Skip to content

Run a scenario across every SDK: sdk-matrix workflow, script and toolchain image - #496

Draft
pcarleton wants to merge 10 commits into
mainfrom
paulc/sdk-matrix
Draft

Run a scenario across every SDK: sdk-matrix workflow, script and toolchain image#496
pcarleton wants to merge 10 commits into
mainfrom
paulc/sdk-matrix

Conversation

@pcarleton

@pcarleton pcarleton commented Sep 7, 2026

Copy link
Copy Markdown
Member

What

A way to run one conformance selection (a scenario list, a suite, or a requirement set) across every SDK in KNOWN_SDKS and get back a single SDK x check table, from any of three places:

  1. .github/workflows/sdk-matrix.yml (primary): workflow_dispatch with sdks, mode, scenario|suite|requirements, ref, pr, pr_comment, plus a weekly schedule. One job per SDK on ubuntu-latest with that SDK's toolchain (setup-node + corepack, setup-uv, setup-go, rust-toolchain, setup-dotnet at the version csharp-sdk's global.json pins, setup-ruby, setup-java), then a report job that merges the legs into the run summary and an optional comment job that upserts one sticky comment on the conformance PR.
  2. scripts/sdk-matrix-docker.sh + docker/sdk-matrix/Dockerfile: the same run locally with every toolchain in one image and a cache volume, for people who do not want six toolchains on their laptop.
  3. scripts/sdk-matrix.mjs (npm run sdk-matrix): the plain script both of the above call. It is thin orchestration over the existing conformance sdk command (no new way to clone, build or run an SDK), never lets one SDK's failure stop the others, and writes matrix.json (sdk x scenario x check, plus build/exec errors verbatim) and matrix.md. The report reads each SDK's own expected-failures baseline (the file conformance sdk already passes) and leads with a Regressions section: failing checks that baseline does not excuse, stale baseline entries, and SDKs that could not run. That is the "would this change turn an SDK's CI red" answer; baselined failures are shown separately.
gh workflow run sdk-matrix.yml -R modelcontextprotocol/conformance \
  -f sdks=all -f mode=client \
  -f scenario=auth/metadata-var2,auth/metadata-default \
  -f pr=488 -f pr_comment=true

Why

Reviewing a check change means answering "what does this do to each SDK". Today that takes whichever toolchains the reviewer happens to have installed, and the rest get predicted by reading SDK code. For #488 three of eight SDKs were checked that way. The harness already knows how to clone, build and drive every SDK (conformance sdk), so the missing piece was fan-out, aggregation and a place to run it that has all the toolchains. Hosted runners are that place; the container is the offline equivalent.

Security model of the workflow

Same split as traceability.yml. plan and run execute code from the ref under test and third-party SDK code with contents: read, persist-credentials: false, no secrets, no token in the environment of the step that builds and runs SDKs, and no actions caches. report checks out only the dispatching branch and runs no SDK code. comment is the only job with pull-requests: write; it checks nothing out and posts the rendered table read from the artifact, with all SDK-produced text escaped as data. The workflow is dispatch/schedule only, so it always runs as defined on a branch of this repository; a fork PR's harness code only ever runs in the unprivileged jobs, and plan flags fork PRs.

Testing

  • scripts/sdk-matrix.test.ts: aggregation and rendering against canned result directories, log classification (build failure, missing toolchain, server never ready, checkout failure), merge of artifact-style directories, markdown escaping, and a cross-check that the KNOWN_SDKS source parse matches the module's keys.
  • Ran the container path locally for --mode client --scenario auth/metadata-var2,auth/metadata-default and --mode server --scenario tools-list across all SDKs.
  • Exercised the workflow from this branch (a temporary push trigger, since reverted, registered it so workflow_dispatch --ref works): a targeted run for the feat(client/auth): check the resource parameter matches the PRM-published identifier #488 scenarios, a pr=488 dispatch (resolves to the merge commit), and a full sdks=all mode=both run, which covers 44 client and 31 server scenarios per SDK in about 3 minutes wall time. The full report from that last run is in its run summary: https://github.com/modelcontextprotocol/conformance/actions/runs/34057591441
  • plan can only dispatch by name once the workflow has run at least once in the repo, which it now has; after merge the documented command works as-is.

Docs

README section "Running a Scenario Across All SDKs" (workflow trigger, docker wrapper, plain script), and a line in AGENTS.md / CONTRIBUTING.md asking authors to attach the matrix when a change adds a check to an existing scenario or changes a check's severity.

uv sync --all-packages fails on a case-sensitive filesystem for the v1.x
branch: examples/clients/simple-chatbot declares README.md but ships
README.MD, so hatchling refuses to build it. Sync the two conformance
packages one at a time, which is what the SDK's own v1.x conformance CI
does and what the python-sdk entry already does for main.
Fans one scenario list, suite or requirement set out over KNOWN_SDKS by
invoking the existing 'conformance sdk' command per SDK, so cloning,
building and running stay in one place. One SDK failing to build never
stops the others: each invocation's log is classified (checkout, build,
server start, ran) and the toolchain error is carried into the report.

Writes matrix.json (sdk x scenario x check, plus errors verbatim and
per-SDK toolchain versions) and matrix.md (SDK overview, scenario
summary, per-check tables, failure messages), and prints the markdown.
--merge re-renders from saved matrix.json files, which is how CI
combines per-SDK legs; --ref tests another conformance ref or PR;
--harness-dir drives an already-built checkout. All SDK-produced text
is escaped before it reaches the markdown.

npm run sdk-matrix is the entry point; results default to
sdk-matrix-results/ (ignored).
One job per SDK on ubuntu-latest with that SDK's toolchain (setup-node
and corepack, setup-uv, setup-go, rust-toolchain, setup-dotnet at the
band csharp-sdk's global.json pins, setup-ruby, setup-java), running
scripts/sdk-matrix.mjs for that leg against the requested conformance
ref or PR, then a report job that merges the legs into the run summary
and an optional job that upserts one sticky comment on the PR.

Same trust split as traceability.yml: the jobs that build and run SDK
code (and code from the ref under test) are read-only, keep no git
credentials, hold no token in the SDK step's environment and use no
actions caches; the report job only checks out the dispatching branch;
the comment job holds the single write permission, checks nothing out
and posts the table as data.
…ocally

docker/sdk-matrix installs Node + corepack, uv, Go, rustup, the .NET
SDK, Ruby + Bundler and a JDK from their public sources on ubuntu 24.04.
scripts/sdk-matrix-docker.sh builds it on first use and runs
scripts/sdk-matrix.mjs against the bind-mounted checkout with SDK
clones, builds and package caches on a named volume, so reruns are fast.

Registries default to each ecosystem's public one; mirror configuration
can be forwarded per run with explicit flags (--npmrc, --cargo-config,
--pip-conf, --uv-config, --nuget-config, --gemrc, --env NAME). The
wrapper never mounts SSH keys, git credentials or tokens, publishes no
ports, and handles rootless Docker by running as container uid 0 (the
invoking host user).
README section covering the workflow trigger, the docker wrapper and
the plain script; AGENTS.md and CONTRIBUTING.md ask authors to attach
the matrix when a change adds a check to an existing scenario or
changes a check's severity.
…this branch

workflow_dispatch is only accepted once the workflow exists on the
default branch. Revert before merge.
Scenarios in the same area emit the same check ids (every auth/* flow
shares ~19), so per-scenario tables repeated themselves. Union the ids
across scenarios into a single table, show the worst status per cell, and
break out only the checks whose outcome differs between scenarios.
…aseline

The question the matrix exists to answer is whether a harness change turns
an existing SDK's CI red. Read the baseline file 'conformance sdk' already
passes as --expected-failures, and lead the report with a Regressions
section: failing checks that baseline does not excuse, baseline entries
that now pass (stale, which also fails that SDK's CI), and SDKs that could
not be built or run. Baselined failures stay visible but are marked
separately in the summary cells, the SDK x check table and the message
list. --strict now means 'would turn some SDK's CI red'.
@pkg-pr-new

pkg-pr-new Bot commented Sep 7, 2026

Copy link
Copy Markdown

Open in StackBlitz

npx https://pkg.pr.new/@modelcontextprotocol/conformance@496

commit: 48e92be

Comment on lines +216 to +220
- uses: ruby/setup-ruby@v1
if: contains(matrix.spec, 'ruby-sdk')
with:
ruby-version: '4.0' # what ruby-sdk's own conformance CI runs
- uses: actions/setup-java@v5
Comment on lines +226 to +230
- name: Build the harness under test
working-directory: under-test
run: npm ci && npm run build

- name: Run the matrix leg for this SDK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants