Skip to content

Commit 430ff37

Browse files
committed
Run every referee scenario in the server conformance leg
## Motivation and Context The server conformance leg ran the referee's default `active` suite, which leaves out the extension-tagged scenarios, while the client leg has selected every scenario with `--suite all`. The Skills server implementation therefore never met the referee's `sep-2640-skills-*` server scenarios, although the conformance server already serves the `conformance/skills` directory for them, and the `all` suite's other additions (stateless server, SSE polling, caching, standard header validation, `input-required` results) were not run either. The server leg now selects `--suite all` the way the client leg does, with a requirement set or a single scenario still replacing the selection. Of the 34 scenarios this adds, 23 pass. The rest reach three areas the SDK does not implement and are listed in `expected_failures.yml` the way the TypeScript and Python SDKs list theirs: the Tasks extension (SEP-2663); the server side of SEP-2243 custom headers, where the server does not bind `Mcp-Param-*` headers to `x-mcp-header` tool parameters and the conformance server exposes no such tool, so the referee reports the scenario's checks as untestable; and SEP-1699 resumability, where a POST SSE stream carries no priming event or `retry` field, which the referee reports as warnings that its baseline counts as failures. `tasks-status-notifications` is left out of the baseline because the referee runs no check in it, and the baseline check would flag an entry for a passing scenario as stale. ## How Has This Been Tested? test/conformance/server_runner_test.rb, and `bundle exec rake conformance:test`: the server leg runs 65 scenarios, the 11 baselined failures reported as expected and the three `sep-2640-skills-*` scenarios passing, where it ran 31 before the change. `REQUIREMENTS=2026-07-28` still runs the frozen set without a suite. ## Breaking Changes None.
1 parent 51db52a commit 430ff37

5 files changed

Lines changed: 61 additions & 10 deletions

File tree

‎.github/workflows/conformance.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
- run: bundle exec rake conformance:test
3030

3131
# Frozen requirement sets for SEP-1730 tier scoring: each spec revision's scenarios run at
32-
# that revision's own wire version, unlike the moving active suite above.
32+
# that revision's own wire version, unlike the moving full suite above.
3333
requirements-conformance:
3434
runs-on: ubuntu-latest
3535
continue-on-error: true

‎conformance/README.md‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ Validates the Ruby SDK's conformance to the MCP specification using [`@modelcont
1515
bundle exec rake conformance:test
1616
```
1717

18-
Runs both server and client conformance tests in sequence. Server conformance starts the
19-
conformance server and tests it. Client conformance spawns test servers for each scenario
20-
and invokes `conformance/client.rb` against them. Scenarios listed in `expected_failures.yml`
21-
are allowed to fail without affecting the exit code.
18+
Runs both server and client conformance tests in sequence. Server conformance starts the conformance server and tests it.
19+
Client conformance spawns test servers for each scenario and invokes `conformance/client.rb` against them.
20+
Both legs select every scenario the referee ships (`--suite all`), the extension-tagged ones included,
21+
so the Skills server and client implementations are checked. Scenarios listed in `expected_failures.yml`,
22+
which cover the areas the SDK does not implement, are allowed to fail without affecting the exit code;
23+
the referee flags an entry as stale once its scenario passes.
2224

2325
### Environment variables
2426

@@ -55,7 +57,7 @@ bundle exec rake conformance:server PORT=3000
5557
bundle exec rake conformance:server
5658

5759
# Terminal 2: run all scenarios
58-
npx @modelcontextprotocol/conformance@alpha server --url http://localhost:9292/mcp
60+
npx @modelcontextprotocol/conformance@alpha server --url http://localhost:9292/mcp --suite all
5961

6062
# Terminal 2: run a single scenario
6163
npx @modelcontextprotocol/conformance@alpha server --url http://localhost:9292/mcp --scenario ping

‎conformance/expected_failures.yml‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,23 @@
1-
server: []
1+
server:
2+
# SEP-1699 resumability: the server sends no priming event or `retry` field on a POST SSE stream and replays
3+
# nothing on `Last-Event-ID`; the referee warns about both, and the baseline counts a warning as a failure.
4+
- server-sse-polling
5+
# SEP-2243 custom headers: the server does not bind `Mcp-Param-*` headers to `x-mcp-header` tool parameters
6+
# (the client side sends them), so the conformance server exposes no such tool and the referee reports
7+
# the scenario's checks as untestable.
8+
- http-custom-header-server-validation
9+
# SEP-2663 (io.modelcontextprotocol/tasks): the server does not implement the tasks extension.
10+
# `tasks-status-notifications` is intentionally absent: the referee runs no check in it, and a baseline entry
11+
# for a scenario with no failing check is flagged stale.
12+
- tasks-lifecycle
13+
- tasks-capability-negotiation
14+
- tasks-wire-fields
15+
- tasks-request-state-removal
16+
- tasks-mrtr-input
17+
- tasks-request-headers
18+
- tasks-dispatch-and-envelope
19+
- tasks-required-task-error
20+
- tasks-mrtr-composition
221
client:
322
# Unimplemented authorization extensions.
423
- auth/dpop

‎conformance/server_runner.rb‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,17 @@ def build_command
3333
expected_failures_yml = File.expand_path("expected_failures.yml", __dir__)
3434

3535
npx_command = ["npx", "--yes", "@modelcontextprotocol/conformance@alpha", "server", "--url", "http://localhost:#{@port}/mcp"]
36-
npx_command += ["--scenario", @scenario] if @scenario
36+
# A requirement set already fixes which scenarios run, so it replaces the suite selection.
37+
# The referee's default `active` suite leaves out the extension-tagged scenarios (Skills, Tasks), which `all` selects,
38+
# as the client leg does; the areas the SDK does not implement are listed in expected_failures.yml.
39+
npx_command += if @requirements
40+
["--requirements", @requirements]
41+
elsif @scenario
42+
["--scenario", @scenario]
43+
else
44+
["--suite", "all"]
45+
end
3746
npx_command += ["--spec-version", @spec_version] if @spec_version
38-
npx_command += ["--requirements", @requirements] if @requirements
3947
npx_command += ["--verbose"] if @verbose
4048
npx_command += ["--expected-failures", expected_failures_yml]
4149
npx_command

‎test/conformance/server_runner_test.rb‎

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module Conformance
77
class ServerRunnerTest < ActiveSupport::TestCase
88
EXPECTED_FAILURES_YML = File.expand_path("../../conformance/expected_failures.yml", __dir__)
99

10-
test "build_command runs the active suite by default" do
10+
test "build_command runs the full suite by default" do
1111
command = ServerRunner.new.send(:build_command)
1212

1313
assert_equal(
@@ -18,6 +18,28 @@ class ServerRunnerTest < ActiveSupport::TestCase
1818
"server",
1919
"--url",
2020
"http://localhost:#{Server::DEFAULT_PORT}/mcp",
21+
"--suite",
22+
"all",
23+
"--expected-failures",
24+
EXPECTED_FAILURES_YML,
25+
],
26+
command,
27+
)
28+
end
29+
30+
test "build_command keeps the single scenario selection" do
31+
command = ServerRunner.new(scenario: "ping").send(:build_command)
32+
33+
assert_equal(
34+
[
35+
"npx",
36+
"--yes",
37+
"@modelcontextprotocol/conformance@alpha",
38+
"server",
39+
"--url",
40+
"http://localhost:#{Server::DEFAULT_PORT}/mcp",
41+
"--scenario",
42+
"ping",
2143
"--expected-failures",
2244
EXPECTED_FAILURES_YML,
2345
],

0 commit comments

Comments
 (0)