feat: add ruby-sdk to the known SDKs registry (#457)

Registers modelcontextprotocol/ruby-sdk in KNOWN_SDKS so `tier-check --sdk-path` and `sdk ruby-sdk` manage
the build and per-revision runs themselves, instead of requiring the --conformance-server-url/--client-cmd
fallback for unknown SDKs. This is the registry path the Ruby SDK's SEP-1730 Tier 1 application
(modelcontextprotocol/modelcontextprotocol#3247) was scored through: with the entry in place, reviewers can
reproduce the submission with a single `tier-check --sdk-path <checkout> --requirements 2025-11-25,2026-07-28`,
the same way every other registered SDK is checked.

The entry drives the same fixtures the SDK's own CI runs through `rake conformance`: `conformance/server.rb`
behind the `conformance:server` rake task (PORT from the environment; PORT=3000 matches the registry's port convention)
and `conformance/client.rb`, which reads MCP_CONFORMANCE_SCENARIO from the environment and the server URL from argv,
per the runner's contract. The baseline is `conformance/expected_failures.yml`. One dual-era server serves every revision
from the same /mcp endpoint (stateful dated-spec handshake and the SEP-2575 stateless lifecycle side by side),
so the entry needs no specOverrides.

Testing: `npm test` (525 passing, including a new known-sdks entry test), `npm run check`, and `npm run build` pass.
The entry has already carried four full end-to-end audit runs: the 2026-08-14 and 2026-08-15 tier-check runs against
a local ruby-sdk checkout (`--sdk-path` with `--requirements 2025-11-25,2026-07-28`) each built the SDK, started the
server on PORT=3000, and completed both legs at both revisions, producing the 67/67 server and 50/50 client results
submitted in modelcontextprotocol/modelcontextprotocol#3247. Individually, `sdk ruby-sdk --path <checkout> --mode
server --requirements 2025-11-25` exits 0 with 78/78 checks, and `--mode client --requirements 2025-11-25` exits 0
with every scored scenario passing (failures confined to not_scored extensions).
This commit is contained in:
Koichi ITO 2026-09-07 02:43:45 +09:00 • committed by GitHub
commit c8dab0c3b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 33 additions and 1 deletions

View file

@ -159,6 +159,25 @@ export const KNOWN_SDKS: Record<string, SdkConfig> = {
server: { url: 'http://localhost:3000/stateless' }
}
}
},
// Fixtures live under conformance/ (server.rb + client.rb, the same files
// the SDK's own `rake conformance` CI drives). The client reads
// MCP_CONFORMANCE_SCENARIO from the environment and the server URL from argv.
// One dual-era server serves every revision from the same /mcp endpoint —
// the stateful (dated-spec) handshake and the SEP-2575 stateless lifecycle
// side by side — so no specOverrides are needed. The rake task reads PORT
// from the environment (the SDK's own default is 9292); PORT=3000 matches
// the 3000 convention used above.
'ruby-sdk': {
build: 'bundle install',
client: {
command: 'bundle exec ruby conformance/client.rb'
},
server: {
command: 'PORT=3000 bundle exec rake conformance:server',
url: 'http://localhost:3000/mcp'
},
expectedFailures: 'conformance/expected_failures.yml'
}
};

View file

@ -141,6 +141,19 @@ describe('lookupBuiltinConfig', () => {
expect(rs?.server?.url).toBe('http://localhost:3000/mcp');
});
it('exposes ruby-sdk with the conformance/ fixtures and a baseline', () => {
const rb = lookupBuiltinConfig('ruby-sdk');
expect(rb?.build).toBe('bundle install');
expect(rb?.client?.command).toBe('bundle exec ruby conformance/client.rb');
expect(rb?.server?.command).toBe(
'PORT=3000 bundle exec rake conformance:server'
);
expect(rb?.server?.url).toBe('http://localhost:3000/mcp');
expect(rb?.expectedFailures).toBe('conformance/expected_failures.yml');
// One dual-era server serves every revision, so no per-spec overrides.
expect(rb?.specOverrides).toBeUndefined();
});
it('every built-in entry validates against SdkConfigSchema', () => {
for (const [name, cfg] of Object.entries(KNOWN_SDKS)) {
expect(() => SdkConfigSchema.parse(cfg), name).not.toThrow();