Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `@<ref>`) 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 `@<ref>`) 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`.
Expand Down
60 changes: 54 additions & 6 deletions src/sdk-runner/known-sdks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,44 @@ export const KNOWN_SDKS: Record<string, SdkConfig> = {
},
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.
Expand All @@ -68,6 +95,27 @@ export const KNOWN_SDKS: Record<string, SdkConfig> = {
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'
}
}
};

Expand Down
29 changes: 29 additions & 0 deletions src/sdk-runner/sdk-runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Loading