| Filename | Latest commit message | Latest commit date |
|---|---|---|
## Motivation and Context The MCP authorization specification (2025-11-25 scope-selection-strategy) and RFC 6750 Section 3.1 describe OAuth 2.0 step-up authentication: the client already holds a valid access token, but the server returns a 403 with `WWW-Authenticate: Bearer error="insufficient_scope", scope="..."` to demand a higher-privileged scope for a specific operation. The client is expected to run a fresh authorization request with the escalated scope and retry. Until now the Ruby SDK only ran the OAuth flow on 401 responses. A 403 surfaced unchanged as a `RequestHandlerError` and the operation that needed the escalated scope failed permanently, even with a valid token in storage. This lined up with the `auth/scope-step-up` conformance scenario being listed in `conformance/expected_failures.yml`. The change adds: - `MCP::Client::HTTP#send_request` recognises a 403 carrying an `insufficient_scope` Bearer challenge as a step-up signal, re-runs a full authorization request with the scope from the challenge, and retries the original request. Retries are capped at one per `send_request` call so a server that repeatedly demands more scope cannot loop the transport. - `run_step_up_flow!` deliberately bypasses the refresh-token path that `run_oauth_flow!` uses on 401. Refreshing would re-issue the same scope set the existing token already has and the server already rejected. Only a fresh `authorization_code` grant with the escalated scope can succeed. - A plain 403 with no `insufficient_scope` challenge continues to surface as `RequestHandlerError` with `error_type: :forbidden`. - `conformance/client.rb` invokes a tool for the `auth/scope-step-up` scenario; the scenario's authorization middleware only requires the escalated scope on `tools/call`, so the previous `tools/list`-only client could never trigger the second authorization. - `auth/scope-step-up` is removed from `conformance/expected_failures.yml`. Resolves #383. ## How Has This Been Tested? New `HTTPOAuthTest` cases cover: the 403 insufficient_scope path re-authorizes with the escalated scope from the challenge and retries the original request with the new bearer token; a plain 403 without the `insufficient_scope` challenge is surfaced as `error_type: :forbidden` with no OAuth side effects; repeated `insufficient_scope` responses retry at most once and then surface the 403; a provider with a saved `refresh_token` still goes through the full authorization request rather than exchanging the refresh token, because the existing scope set is precisely what was rejected. Conformance: `auth/scope-step-up` now passes 22/22 with no warnings. `bundle exec rake test`, `bundle exec rake rubocop`, and `bundle exec rake conformance` are all green. ## Breaking Changes None. Behaviour on 401 is unchanged. A 403 without the `insufficient_scope` Bearer challenge still raises the same `RequestHandlerError` as before. The new retry only fires when both the WWW-Authenticate header signals step-up and the transport was constructed with an OAuth provider. |
||
| .. | ||
| client.rb | ||
| client_runner.rb | ||
| expected_failures.yml | ||
| README.md | ||
| server.rb | ||
| server_runner.rb | ||
MCP Conformance Tests
Validates the Ruby SDK's conformance to the MCP specification using @modelcontextprotocol/conformance.
Prerequisites
- Node.js (for
npx) bundle installcompleted
Running the Tests
Run all scenarios
bundle exec rake conformance
Runs both server and client conformance tests in sequence. Server conformance starts the
conformance server and tests it. Client conformance spawns test servers for each scenario
and invokes conformance/client.rb against them. Scenarios listed in expected_failures.yml
are allowed to fail without affecting the exit code.
Environment variables
| Variable | Description | Default |
|---|---|---|
PORT |
Server port (server conformance only) | 9292 |
SCENARIO |
Run a single scenario by name | (all) |
SPEC_VERSION |
Filter scenarios by spec version | (all) |
VERBOSE |
Show raw JSON output when set | (off) |
# Run a single server scenario
bundle exec rake conformance SCENARIO=ping
# Use a different port with verbose output
bundle exec rake conformance PORT=3000 VERBOSE=1
# Start the server on a specific port
bundle exec rake conformance_server PORT=3000
Start the server and test separately
# Terminal 1: start the server
bundle exec rake conformance_server
# Terminal 2: run all scenarios
npx @modelcontextprotocol/conformance server --url http://localhost:9292/mcp
# Terminal 2: run a single scenario
npx @modelcontextprotocol/conformance server --url http://localhost:9292/mcp --scenario ping
Keeps the server alive between test runs, which avoids the startup overhead when iterating on a single scenario. Stop the server with Ctrl+C when done.
List available scenarios
bundle exec rake conformance_list
Prints all scenario names that can be passed to SCENARIO.
SDK Tier Report
The MCP SDK Tier system requires SDK maintainers to self-assess and report results to the SDK Working Group via modelcontextprotocol/modelcontextprotocol issues.
To generate a full tier assessment report, use the /mcp-sdk-tier-audit slash command from
the modelcontextprotocol/conformance
repository with the conformance server running:
# Terminal 1 (this repository): start the conformance server
bundle exec rake conformance_server
# Terminal 2 (conformance repository): run the tier audit skill as a slash command in Claude Code
/mcp-sdk-tier-audit /path/to/modelcontextprotocol/ruby-sdk http://localhost:9292/mcp
The skill evaluates conformance pass rate, issue label taxonomy, triage metrics, documentation coverage, and policy compliance, then produces a markdown report suitable for tier advancement submissions.
File Structure
conformance/
server.rb # Conformance server (Rack + Puma, default port 9292)
server_runner.rb # Starts the server, runs npx conformance server, exits with result code
client.rb # Conformance client (invoked by npx conformance client)
client_runner.rb # Runs npx conformance client, exits with result code
expected_failures.yml # Baseline of known-failing scenarios (server and client)
README.md # This file
Known Limitations
Known-failing scenarios are registered in conformance/expected_failures.yml. They are allowed to
fail without affecting the exit code and are tracked to catch regressions.
These are shown in the output of bundle exec rake conformance.