| Filename | Latest commit message | Latest commit date |
|---|---|---|
## Motivation and Context The MCP authorization specification and SEP-1046 allow confidential clients to obtain tokens through the OAuth 2.1 `client_credentials` grant: a machine-to-machine flow with no user, no browser redirect, and no authorization code. The Ruby SDK previously supported only the interactive authorization-code flow, so it could not authenticate against a server that requires `client_credentials`. This makes the `auth/client-credentials-basic` conformance scenario pass and is removed from the expected failures list. Following the TypeScript SDK (`ClientCredentialsProvider`) and the Python SDK (`ClientCredentialsOAuthProvider`), the grant gets its own provider class rather than overloading the authorization-code provider. The change adds: - `MCP::Client::OAuth::ClientCredentialsProvider`, a dedicated provider for the grant. `client_id` and `client_secret` are mandatory (the grant is for confidential clients), `token_endpoint_auth_method` is `client_secret_basic` (default) or `client_secret_post` -- `none` is rejected because an unauthenticated `client_credentials` request is meaningless. It has no redirect arguments, so a credentials-only client never supplies the redirect URI / handlers that grant has no use for. - `MCP::Client::OAuth::StorageBackedProvider`, an internal module that shares the token / client-information persistence between the two provider classes so `Flow` can treat any provider uniformly. - `Provider#authorization_flow` (`:authorization_code`) and `ClientCredentialsProvider#authorization_flow` (`:client_credentials`). `Flow#run!` dispatches on this rather than inspecting `client_metadata[:grant_types]`, which is protocol metadata for the authorization server, not an SDK control signal. - `run_client_credentials!` shares the same PRM / AS metadata discovery and Communication Security checks as the interactive flow, then exchanges `grant_type=client_credentials` at the token endpoint via the existing `post_to_token_endpoint` (which already applies `client_secret_basic`). There is no PKCE, redirect, or `offline_access` augmentation, because the grant does not issue a refresh token (OAuth 2.1 Section 4.3.3). - `conformance/client.rb` builds a `ClientCredentialsProvider` for the `auth/client-credentials-*` scenarios, reusing the harness-injected `client_id` / `client_secret`. ## How Has This Been Tested? New `ClientCredentialsProvider` tests cover: credentials are stored as client information; `authorization_flow` is `:client_credentials`; `client_secret_post` is accepted; missing `client_id` / `client_secret` and `token_endpoint_auth_method: "none"` are rejected; and the token helpers delegate to storage. New `Flow` tests cover: a `client_credentials` provider exchanges `grant_type=client_credentials` with HTTP Basic auth, saves the token, and never contacts the authorization or registration endpoint; the requested scope is taken from PRM `scopes_supported`; and a standard `Provider` runs the authorization-code grant regardless of what its `client_metadata[:grant_types]` lists. A `Provider` test asserts `authorization_flow` is `:authorization_code`. Conformance: `auth/client-credentials-basic` now passes 7/7 with no failures. ## Breaking Changes None. `ClientCredentialsProvider` is a new class; the existing `Provider` keeps its required `redirect_uri` / `redirect_handler` / `callback_handler` arguments and its behaviour is unchanged. Existing interactive clients are unaffected. |
||
| .. | ||
| 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.