diff --git a/README.md b/README.md index e4cd70fe..8fa48afc 100644 --- a/README.md +++ b/README.md @@ -281,13 +281,14 @@ npm start -- sdk typescript-sdk --mode client --spec-version draft Build/run commands for each official SDK are looked up by name from [`src/sdk-runner/known-sdks.ts`](src/sdk-runner/known-sdks.ts) — no config file is required in the SDK repo. Resolution order is **CLI flag > built-in entry**, so any field can be overridden on the command line for refs that diverge from the built-in. -An SDK can have more than one entry when its layout differs across major versions — e.g. `typescript-sdk` (v2, the `main` monorepo) and `typescript-sdk-v1` (the published npm v1.x line). An entry may set `defaultRef` (the branch used when you don't pass `@`) and `repo` (the real clone target when the entry name is an alias). Overriding for a one-off ref: +An SDK can have more than one entry when its layout differs across major versions — e.g. `typescript-sdk` (v2, the `main` monorepo) and `typescript-sdk-v1` (the published npm v1.x line). An entry may set `defaultRef` (the branch used when you don't pass `@`) and `repo` (the real clone target when the entry name is an alias). Overriding built-in fields for a one-off run: ```bash -npm start -- sdk owner/go-sdk@some-branch \ - --mode client \ - --build-cmd 'go build -tags mcp_go_client_oauth -o ./.conformance-client ./conformance/everything-client' \ - --client-cmd './.conformance-client' +# e.g. a 2026-07-28 run against go-sdk's server — the built-in server command +# pins -stateless=false (what the dated-spec suites need), so override it to +# get the SEP-2575 stateless lifecycle: +npm start -- sdk go-sdk --mode server --suite all --spec-version 2026-07-28 \ + --server-cmd './.conformance-server -http=localhost:3000' ``` To add a new SDK to the matrix, add an entry to `KNOWN_SDKS`. diff --git a/src/sdk-runner/known-sdks.ts b/src/sdk-runner/known-sdks.ts index 8a6b30fd..0e02c291 100644 --- a/src/sdk-runner/known-sdks.ts +++ b/src/sdk-runner/known-sdks.ts @@ -38,17 +38,44 @@ export const KNOWN_SDKS: Record = { }, expectedFailures: 'test/conformance/conformance-baseline.yml' }, + // Fixtures live under conformance/ (everything-client + everything-server, + // mirroring scripts/{client,server}-conformance.sh). The server's -stateless + // flag defaults to true; -stateless=false pins the stateful transport, which + // the dated-spec (`active` suite) scenarios need — for a 2026-07-28 / + // SEP-2575 run, override with --server-cmd './.conformance-server -http=localhost:3000' + // to get the stateless lifecycle. 'go-sdk': { - build: 'go build -o ./.conformance-server ./examples/server/conformance', - // Upstream go-sdk has no client conformance fixture yet (see go-sdk#859). + build: + 'go build -o ./.conformance-server ./conformance/everything-server && go build -o ./.conformance-client ./conformance/everything-client', + client: { + command: './.conformance-client' + }, server: { - command: './.conformance-server -http=:3000', + command: './.conformance-server -http=localhost:3000 -stateless=false', url: 'http://localhost:3000' - } + }, + expectedFailures: 'conformance/baseline.yml' + }, + // main — targets the 2026-07-28 revision. Same uv workspace layout as v1.x + // (client fixture in .github/actions/conformance/, mcp-everything-server + // workspace package). Two baselines exist upstream: expected-failures.yml + // covers runs at the latest dated spec (the default here), and + // expected-failures.2026-07-28.yml covers --spec-version 2026-07-28 runs — + // pass the latter via --expected-failures when targeting the new revision. + 'python-sdk': { + build: 'uv sync --frozen --all-extras --all-packages', + client: { + command: 'uv run --frozen python .github/actions/conformance/client.py' + }, + server: { + command: 'uv run --frozen mcp-everything-server --port 3000', + url: 'http://localhost:3000/mcp' + }, + expectedFailures: '.github/actions/conformance/expected-failures.yml' }, // v1.x — the stable, published line of the python-sdk, analogous to - // typescript-sdk-v1 (v2/main is mid-refactor and noisy). Clones the - // python-sdk repo, defaulting to the `v1.x` branch, and targets the latest + // typescript-sdk-v1. Clones the python-sdk repo, defaulting to the `v1.x` + // branch, and targets the latest // dated spec so draft-only scenarios/checks are excluded by default. uv // workspace: the `mcp` (client) and `mcp-everything-server` (server) packages // are both members, so one `uv sync --all-packages` covers both modes. @@ -68,6 +95,27 @@ export const KNOWN_SDKS: Record = { url: 'http://localhost:3000/mcp' }, expectedFailures: '.github/actions/conformance/expected-failures.yml' + }, + // Fixtures live in tests/ModelContextProtocol.ConformanceClient and + // tests/ModelContextProtocol.ConformanceServer (requires the .NET 10 SDK, + // per global.json); build output goes to the repo-level artifacts/ tree + // (UseArtifactsOutput), not per-project bin/. The client binary takes the scenario as its first + // argument rather than reading MCP_CONFORMANCE_SCENARIO, so the command + // bridges the env var into argv ($1 is the server URL the harness appends). + // The server serves the stateful lifecycle at / and the SEP-2575 stateless + // lifecycle at /stateless from the same port — for a 2026-07-28 run, + // override with --server-url http://localhost:3000/stateless. + 'csharp-sdk': { + build: + 'dotnet build tests/ModelContextProtocol.ConformanceClient -c Release -f net10.0 && dotnet build tests/ModelContextProtocol.ConformanceServer -c Release -f net10.0', + client: { + command: `bash -c 'exec dotnet artifacts/bin/ModelContextProtocol.ConformanceClient/Release/net10.0/ModelContextProtocol.ConformanceClient.dll "$MCP_CONFORMANCE_SCENARIO" "$1"' conformance-client` + }, + server: { + command: + 'dotnet artifacts/bin/ModelContextProtocol.ConformanceServer/Release/net10.0/ModelContextProtocol.ConformanceServer.dll --urls http://localhost:3000', + url: 'http://localhost:3000' + } } }; diff --git a/src/sdk-runner/sdk-runner.test.ts b/src/sdk-runner/sdk-runner.test.ts index 6c6353e5..f7363fa3 100644 --- a/src/sdk-runner/sdk-runner.test.ts +++ b/src/sdk-runner/sdk-runner.test.ts @@ -104,6 +104,35 @@ describe('lookupBuiltinConfig', () => { expect(lookupBuiltinConfig('typescript-sdk')?.specVersion).toBeUndefined(); }); + it('go-sdk exposes both fixtures from conformance/ and a baseline', () => { + const go = lookupBuiltinConfig('go-sdk'); + expect(go?.build).toContain('./conformance/everything-server'); + expect(go?.build).toContain('./conformance/everything-client'); + expect(go?.client?.command).toBe('./.conformance-client'); + expect(go?.server?.url).toBe('http://localhost:3000'); + expect(go?.expectedFailures).toBe('conformance/baseline.yml'); + }); + + it('exposes python-sdk (main) with both commands and no ref/spec pin', () => { + const py = lookupBuiltinConfig('python-sdk'); + expect(py?.repo).toBeUndefined(); + expect(py?.defaultRef).toBeUndefined(); + expect(py?.specVersion).toBeUndefined(); + expect(py?.client?.command).toContain('client.py'); + expect(py?.server?.command).toContain('mcp-everything-server'); + expect(py?.server?.url).toBe('http://localhost:3000/mcp'); + }); + + it('exposes csharp-sdk with dotnet fixtures and the scenario-argv bridge', () => { + const cs = lookupBuiltinConfig('csharp-sdk'); + expect(cs?.build).toContain('ModelContextProtocol.ConformanceClient'); + expect(cs?.build).toContain('ModelContextProtocol.ConformanceServer'); + // The C# client takes the scenario as argv[0]; the command bridges the + // MCP_CONFORMANCE_SCENARIO env var into it. + expect(cs?.client?.command).toContain('$MCP_CONFORMANCE_SCENARIO'); + expect(cs?.server?.url).toBe('http://localhost:3000'); + }); + it('every built-in entry validates against SdkConfigSchema', () => { for (const [name, cfg] of Object.entries(KNOWN_SDKS)) { expect(() => SdkConfigSchema.parse(cfg), name).not.toThrow();