GitShow/modelcontextprotocol/ruby-sdk
modelcontextprotocol

ruby-sdk

The official Ruby SDK for the Model Context Protocol.

by modelcontextprotocol
Star on GitHubForkWebsite

Ruby

858 stars123 forks46 contributorsActive · 11h agoSince 2025v0.22.0

Meet the team

See all 46 on GitHub →
koic
koic496 contributions
atesgoral
atesgoral54 contributions
topherbullock
topherbullock46 contributions
kfischer-okarin
kfischer-okarin13 contributions
Ginja
Ginja12 contributions
dak2
dak210 contributions
sambostock
sambostock8 contributions
tylerrowsell
tylerrowsell6 contributions

Languages

View on GitHub →
Ruby99.7%
Shell0.3%

Commit activity

Last 12 weeks · 173 commits

Full graph →

Community health

5 of 6 standards met

Community profile →
87
✓README✓License✓Contributing✓Code of Conduct○Issue Template✓PR Template

Recent PRs & issues

Active · 8 in progress · Last activity 11h ago
See all on GitHub →
koic
Add Opt-In `ttlMs` / `cacheScope` Cache Hints to List and Read Results per SEP-2549OpenPR

Motivation and Context SEP-2549 (modelcontextprotocol/modelcontextprotocol#2549, merged for the 2026-07-28 spec release) adds a shape with (freshness lifetime in milliseconds, max-age semantics, 0 = do not cache) and ( or , whether shared intermediaries may cache) to , , , , and , complementing the notifications. The field shape follows the Python SDK's implementation (python-sdk#2824, + with / defaults; the TypeScript SDK's earlier -seconds prototype #2070 was superseded by this shape). Because this SDK negotiates protocol versions up to 2025-11-25, where the fields do not exist, emission is opt-in: when neither nor is configured, responses are serialized exactly as before. The fields become REQUIRED in 2026-07-28; a follow-up can auto-emit defaults once that version enters . gains and keywords with validating writers modeled on ( must be nil or a non-negative Integer; must be nil, , or ). A private wraps the five emission points. When the user sets only one of the two values, the other is filled with the spec defaults (, the only universally safe freshness value, and , the spec and Python default). A may return a full hash to override the server-level hints per result; the documented bare-contents return shape keeps working unchanged. The client's / / / structs gain and members populated from the response fields. Resolves #387. How Has This Been Tested? New tests in : with , all four list results carry and the filled default with only , carries with neither configured, list and read results omit both fields (wire-format regression) the hints appear alongside when paginating a returning overrides the server-level value while the missing is filled invalid writer values (, , ) raise New tests in assert all four list result structs expose / , and that both are nil when the server omits the fields. Breaking Changes None. Emission is opt-in, the new constructor keywords default to nil, and the client structs gain additive members. Types of changes [ ] Bug fix (non-breaking change which fixes an issue) [x] New feature (non-breaking change which adds functionality) [ ] Breaking change (fix or feature that would cause existing functionality to change) [x] Documentation update Checklist [x] I have read the MCP Documentation [x] My code follows the repository's style guidelines [x] New and existing tests pass locally [x] I have added appropriate error handling [x] I have added or updated documentation as needed

koic · 49m ago
koic
Recognize multi round-trip `input_required` results per SEP-2322OpenPR

Motivation and Context SEP-2322 (modelcontextprotocol/modelcontextprotocol#2322, merged for the 2026-07-28 spec release) introduces Multi Round-Trip Requests: instead of issuing in-flight server-to-client JSON-RPC requests, a server answers with a result whose is , carrying an map (of , , and request shapes) and an opaque ; the client fulfills the requests and re-issues the original request with and the echoed . The wire contract (the discriminator and the / shape) stayed stable across all three closed TypeScript prototype iterations (typescript-sdk#2062/#2065, the v2-stateless stack, and #2251) and the Python draft (python-sdk#2322), but the server-side suspend/resume mechanism is still unsettled in both SDKs (typescript-sdk#2251 was put on hold on 2026-06-08). This change therefore implements only the stable, additive vocabulary and the client-side recognition, leaving server emission and automatic resumption for a follow-up once the reference design lands: New module with and constants documenting the values. raises the new (exposing , , and the raw ) when any response carries , instead of silently returning a non-final result as if it were the answer. The check lives in the shared request path, so every client method is covered. Servers on stable protocol versions never emit , so default behavior is unchanged. Part of #382. How Has This Been Tested? New tests in : raises for an result and exposes , , and the full raw result returns normally when is and when it is absent (wire-compat regression for stable-protocol servers) also raises for results, proving the recognition covers the shared request path (tests, RuboCop, and conformance baseline) passes. Breaking Changes None for spec-compliant stable servers, which never send . A response that does carry now raises instead of being returned as a final result, which was always a misinterpretation of the draft semantics. Types of changes [ ] Bug fix (non-breaking change which fixes an issue) [x] New feature (non-breaking change which adds functionality) [ ] Breaking change (fix or feature that would cause existing functionality to change) [x] Documentation update Checklist [x] I have read the MCP Documentation [x] My code follows the repository's style guidelines [x] New and existing tests pass locally [x] I have added appropriate error handling [x] I have added or updated documentation as needed

koic · 2d ago
koic
Support `private_key_jwt` Client Authentication for the client_credentials GrantOpenPR

Motivation and Context The MCP extension (SEP-1046, modelcontextprotocol/modelcontextprotocol#1046) specifies two client authentication methods for the grant: and the RECOMMENDED (RFC 7523 Section 2.2 JWT client assertion). The previous commit added the grant with secret-based authentication; this adds the JWT method, which is what the conformance scenario exercises. This mirrors the merged implementations in the TypeScript SDK (, typescript-sdk#1157) and the Python SDK ( / , python-sdk#1663), adapted to this SDK's provider design: New builds the RFC 7523 compact JWS with openssl, keeping the SDK free of a JWT gem dependency (the TypeScript and Python SDKs use jose and PyJWT). Claims follow SEP-1046: and carry the client_id, carries the authorization server's issuer identifier, plus (300-second lifetime, matching both SDKs), , and a unique . ES256 and RS256 are supported; ES256 signatures are converted from OpenSSL's ASN.1 DER form to the raw 64-byte encoding JWS requires (RFC 7518 Section 3.4). accepts with (PEM string or ) and a required (no default, so an algorithm mismatch with the server's fails loudly at construction; both reference SDKs also take the algorithm explicitly). The key stays on the provider and is never written to ; a throwaway assertion is signed at construction to fail fast on an unparseable key or a key/algorithm mismatch. sends and a freshly signed for , using the -validated issuer as the audience, and omits from the body per SEP-1046 (identity travels in the assertion's claims). The conformance client builds a provider when the harness injects , defaulting the algorithm to ES256 like the TypeScript and Python conformance clients, and is removed from . Scope notes: only ES256 and RS256 are supported for now (the TypeScript and Python SDKs accept whatever their JWT libraries support); adding further algorithms is additive. There is also no injection point yet for externally signed assertions (the TypeScript SDK's and the Python SDK's callback cover KMS/HSM-held keys); that is a separate follow-up. How Has This Been Tested? New covers the JWS construction: header and RFC 7523 claims, unpadded base64url segments, ES256 signature round-trip verification (raw -> DER -> ), RS256 verification, PEM and parsed-key input, lifetime override, unique per assertion, and rejection of unsupported algorithms, key/algorithm mismatches (including a P-384 key with ES256), unparseable PEM, and public-only keys. New tests in cover the provider surface: construction, the key and secret never reaching , required / , rejection of a simultaneous , fail-fast on key/algorithm mismatch, and producing a JWT with the expected claims. A new test in runs the full grant against WebMock stubs and asserts the token request carries , the RFC 7523 , an assertion whose / are the client_id and whose is the issuer, the RFC 8707 , and neither nor any secret in the body or headers. passes; the conformance scenario passes 7/7 checks and the baseline check passes with its expected-failure entry removed. Breaking Changes None. becomes optional on only in the signature; it is still required for the secret-based methods, and all existing construction paths behave unchanged. Types of changes [ ] Bug fix (non-breaking change which fixes an issue) [x] New feature (non-breaking change which adds functionality) [ ] Breaking change (fix or feature that would cause existing functionality to change) [ ] Documentation update Checklist [x] I have read the MCP Documentation [x] My code follows the repository's style guidelines [x] New and existing tests pass locally [x] I have added appropriate error handling [x] I have added or updated documentation as needed

koic · 3d ago

Recent fixes

View closed PRs →
koic
Fix an incorrect `result: null` response to an id-bearing notification messageMergedPR

Motivation and Context A JSON-RPC notification carries no id and must not receive any response. When a client erroneously sent a notification-only method such as with an id, the server replied with a successful , which is neither a valid MCP result nor a legal reply to a notification. Such a message is now treated as a request for a method that has no request handler and rejected with Method not found, matching the behavior of the TypeScript and Python SDKs. A well-formed notification that omits the id continues to receive no response. Fixes #434. How Has This Been Tested? Added regression tests covering id-bearing , , and , a batch that mixes an id-bearing notification with other messages, custom methods, and the same case over the HTTP transport. Breaking Changes None for spec-conformant clients, which never put an id on a notification. The only behavioral change is that a malformed id-bearing notification now receives a Method not found error instead of a spurious . Types of changes [x] Bug fix (non-breaking change which fixes an issue) [ ] New feature (non-breaking change which adds functionality) [ ] Breaking change (fix or feature that would cause existing functionality to change) [ ] Documentation update Checklist [x] I have read the MCP Documentation [x] My code follows the repository's style guidelines [x] New and existing tests pass locally [x] I have added appropriate error handling [x] I have added or updated documentation as needed

koic · 11h ago
cclabadmin
Ruby SDK returns `result: null` for an id-bearing `notifications/cancelled` messageClosedIssue

Describe the bug When the Ruby SDK server receives a JSON-RPC message with an and , it returns a successful JSON-RPC response with . A valid MCP notification does not include an and must not receive a response. If this id-bearing message is treated as a request, it should not be completed with a successful response, because MCP result responses use an object-valued . Environment Reproduced with stable release () Also reproduced on current () using a 2026-07-28-style request envelope Transport: stdio To Reproduce 1. Start a Ruby SDK MCP server over stdio. 2. Send a message with a JSON-RPC : 3. Observe the response. Expected behavior The server should not emit a successful JSON-RPC response for this message. A valid notification has no and receives no response. If an id-bearing message for this notification-only method is treated as a request, it should be rejected with a JSON-RPC error rather than completed with . Logs The server returns: The server remains healthy and continues to process subsequent requests. Additional context** In , is dispatched through a special-case handler: can return , for example when there's no session: That value then flows through the normal success-response path in : already exists for handlers that should not emit a JSON-RPC response, so this may be the appropriate sentinel for notification-style handling. This appears related to #398 / #400, which preserved request ids for JSON-RPC envelope error responses in the same area. This issue is different: the response id is preserved, but the message is completed as a successful response with .

cclabadmin · 11h ago
Structured data for AI agents

Repository: modelcontextprotocol/ruby-sdk. Description: The official Ruby SDK for the Model Context Protocol. Stars: 858, Forks: 123. Primary language: Ruby. Languages: Ruby (99.7%), Shell (0.3%). Homepage: https://ruby.sdk.modelcontextprotocol.io Latest release: v0.22.0 (5d ago). Open PRs: 8, open issues: 12. Last activity: 11h ago. Community health: 87%. Top contributors: koic, atesgoral, topherbullock, kfischer-okarin, Ginja, dak2, sambostock, tylerrowsell, andyw8, jcat4 and others.

·@ofershap

Replace github.com with gitshow.dev