Commit graph ruby-sdk/README.md
Author SHA1 Message Date
Koichi ITO
a05d941edd
Merge pull request #306 from koic/support_customizing_faraday_client_in_mcp_client_http
Support customizing the Faraday client in `MCP::Client::HTTP`
2026-04-10 13:42:41 +09:00
Koichi ITO
de38804ed7 Auto-set server.transport in Transport#initialize
## Motivation and Context

Transport subclasses (StreamableHTTPTransport, StdioTransport) already
receive the server in their constructor, but users must manually call
`server.transport = transport` after creating a transport instance.
This is boilerplate that can be eliminated by setting the connection
automatically in `Transport#initialize`.

## How Has This Been Tested?

All existing tests pass. Redundant `server.transport = transport` lines
were removed from tests, examples, README.md, and conformance server.

## Breaking Changes

None. Existing code that manually sets `server.transport = transport`
continues to work (idempotent assignment).
2026-04-09 12:08:55 +09:00
Koichi ITO
f7952e8aaf Support customizing the Faraday client in MCP::Client::HTTP
## Motivation and Context

`MCP::Client::HTTP` builds its Faraday connection internally in a private `client` method
with no way to customize the middleware stack or adapter.
Users who need observability (request/response recording, failure logging) or
a different HTTP adapter must override a private method, coupling to an internal API.

This accepts an optional block in `MCP::Client::HTTP.new` that yields the Faraday builder
after default middleware is configured, allowing users to add custom middleware or swap
the HTTP adapter.

## How Has This Been Tested?

Added a test that verifies custom headers set via the block are included in requests.
All existing tests continue to pass.

## Breaking Changes

None. The block argument is optional, so existing code is unaffected.

Resolves #303
2026-04-09 05:08:49 +09:00
Koichi ITO
2822e00b62
Merge pull request #299 from koic/update_rails_controller_example_in_readme
[Doc] Update Rails controller example in README.md
2026-04-07 11:37:51 +09:00
Koichi ITO
0762879abe
Merge pull request #297 from koic/sticky_session_for_multi_server
[Doc] Note sticky session requirement for multi-instance deployments
2026-04-07 11:37:33 +09:00
Koichi ITO
17604beff9 [Doc] Update Rails controller example in README.md
The following two points have been updated:

## 1. Use ActionController::API in README controller example

`ActionController::Base` includes CSRF protection which rejects POST requests
without an authenticity token. MCP clients do not send CSRF tokens,
so the controller example should inherit from `ActionController::API` instead.

## 2. Use `stateless: true` for `StreamableHTTPTransport.new`

The controller creates a new transport per request,
so the session stored on the previous transport is lost.
Without `stateless: true`, the second request with `Mcp-Session-Id`
returns 404 because the new transport has an empty session map.

To share sessions via `Mcp-Session-Id` across requests, there are two approaches.
One is persisting the transport in a class variable. The other is mounting
the transport as a Rack app via https://github.com/modelcontextprotocol/ruby-sdk/pull/263.

Both approaches maintain sessions, so features that depend on `server_context`
within the SDK (Progress, Sampling) work correctly. However, per-request
user-specific context such as `server_context: { user_id: current_user.id }`
cannot be passed since the server is shared across all requests.
2026-04-06 03:22:59 +09:00
Koichi ITO
1b45c4382b [Doc] Note sticky session requirement for multi-instance deployments
## Motivation and Context

PR #290 documented that `StreamableHTTPTransport` requires a single-process server.
However, when running multiple server instances behind a load balancer, requests for
the same session must be routed to the same instance since session state is stored in memory.

This adds a note about using sticky sessions (session affinity) based on the `Mcp-Session-Id` header.

## How Has This Been Tested?

Documentation-only change.

## Breaking Changes

None.
2026-04-06 03:20:46 +09:00
Koichi ITO
3f43b1feac [Doc] Restructure sampling section to lead with tool usage
Sampling is primarily used within tool execution via `server_context.create_sampling_message`,
but the documentation led with the less common direct `Server#create_sampling_message` usage.
This ordering could mislead readers into thinking direct usage is the recommended approach.
2026-04-06 03:17:18 +09:00
Koichi ITO
f9096347bc [Doc] Move stdio before Rails Controller in Usage
For Usage, stdio is easier to try first than a Rails controller.
Moved stdio to the top and placed Rails Controller after it.

Only sections were moved. No content was changed.
2026-04-05 13:29:47 +09:00
Koichi ITO
63f51bbc26 [Doc] Move Usage to the top of the README.md
Users are more likely to want to see Usage first, rather than a feature introduction like Sampling.
Sampling has been moved below Resource Templates so that Usage appears at the top.

Only sections were moved. No content was changed.
2026-04-05 13:29:47 +09:00
Koichi ITO
ee4a7bb4df [Doc] Move Custom methods to the bottom of the README
Custom methods are an advanced feature and may not be appropriate for the top of the README.md.
Move them to the bottom of the page.

Only sections were reorganized with headings. No content was changed.
2026-04-05 13:29:30 +09:00
Koichi ITO
da5f9225ac Support sampling/createMessage per MCP specification
## Motivation and Context

The MCP specification defines `sampling/createMessage` to request LLM completions from the client.
The Ruby SDK did not yet support server-to-client requests,
so the server had no way to ask the client to sample an LLM.
This caused the `tools-call-sampling` conformance test to fail.

This adds `Server#create_sampling_message` to send a `sampling/createMessage` request
to the client via the transport layer. The method validates that the client declared
the `sampling` capability during initialization, and optionally checks the
`sampling.tools` capability when tools or tool_choice parameters are provided.

On the transport side, `Transport#send_request` is introduced as an abstract method,
with implementations in both `StdioTransport` and `StreamableHTTPTransport`.
Each transport assigns a unique request ID, sends the JSON-RPC request to the client,
and blocks until the client responds.

Client capabilities are stored per session via `ServerSession`, so validation is scoped
to the originating client. `ServerSession#create_sampling_message` uses
`build_sampling_params` for capability validation and sends the request directly through
the transport with the session ID, following the same pattern as `notify_progress`.

`Server#create_sampling_message` is the public API for single-client transports
(e.g., StdioTransport).

For multi-client transports (e.g., StreamableHTTPTransport),
`ServerSession#create_sampling_message` must be used to route requests to the correct client.
Tools using `server_context.create_sampling_message` automatically route to the correct session
regardless of transport.

`StreamableHTTPTransport#send_request` requires `session_id` to prevent broadcasting sampling requests
to all connected clients. Missing or invalid session IDs raise explicit errors instead of silently failing.

The `include_context` parameter is soft-deprecated in the MCP specification but is included
for compatibility with existing clients that declare the `sampling.context` capability.
Python and TypeScript SDKs also retain this parameter.

Ref: https://modelcontextprotocol.io/specification/latest/server/utilities/sampling

## How Has This Been Tested?

Added comprehensive tests in `test/mcp/server_sampling_test.rb` covering required and optional parameters,
capability validation, error handling, nil-param omission, per-session capability isolation,
and HTTP init capability scoping.

Added transport tests in `test/mcp/server/transports/stdio_transport_test.rb` and
`test/mcp/server/transports/streamable_http_transport_test.rb` for `send_request` round-trip behavior,
error responses, stateless mode rejection, missing session_id, invalid session_id, and no-active-stream error.

Conformance: `tools-call-sampling` is removed from expected failures. The conformance server's `TestSampling`
tool now calls `server_context.create_sampling_message` instead of returning a stub error.

This aligns the Ruby SDK with the MCP specification and other SDK implementations.

## Breaking Changes

None for end users.
`Transport#send_request` is a new abstract method. `ServerSession#create_sampling_message` is a new method.
2026-04-04 05:55:27 +09:00
Koichi ITO
6f94d64ece
Merge pull request #290 from koic/thread_model_requirement
[Doc] Clarify that `StreamableHTTPTransport` requires a single-process server
2026-04-04 05:51:58 +09:00
Koichi ITO
9ebb42a536 [Doc] Clarify that StreamableHTTPTransport requires a single-process server
## Motivation and Context

`StreamableHTTPTransport` stores session and SSE stream state in memory using
instance variables (`@sessions`, `@mutex`). This design requires all HTTP requests
to be handled within the same process to share state.

Process-based servers like Unicorn fork separate worker processes that do not share memory,
which breaks session management and SSE connections.
This requirement is not obvious from the current documentation.

## How Has This Been Tested?

Documentation-only change.

## Breaking Changes

None.
2026-04-04 02:08:01 +09:00
Koichi ITO
88e1f9a840 Support completion/complete per MCP specification
## Motivation and Context

The MCP specification defines `completion/complete` for providing autocompletion
suggestions for prompt arguments and resource template URIs.
The Ruby SDK previously had only a no-op handler that returned empty results,
with no way for users to define custom completion logic.

This aligns the Ruby SDK with the Python and TypeScript SDKs,
both of which support user-defined completion handlers.

## How Has This Been Tested?

Server tests cover: default handler, custom handler for `ref/prompt` and `ref/resource`,
context argument passing, 100-item truncation, and error responses for nonexistent prompts,
nonexistent resource templates, and invalid ref types.

Client tests cover: request structure, context parameter inclusion,
and fallback when result is missing.

## Breaking Changes

None. The existing default no-op handler behavior is preserved.
The `completion_handler` method is purely additive. The only behavioral change
is that `completion/complete` requests now validate that the referenced prompt
or resource template exists before calling the handler,
returning an `invalid_params` error for unknown references.
2026-04-03 01:35:07 +09:00
Koichi ITO
f0186d08b0
Merge pull request #268 from koic/security__missing_session_expiry_controls
Support session expiry controls for `StreamableHTTPTransport`
2026-03-30 05:46:07 +09:00
Koichi ITO
b89f6e315d Remove Server#notify_progress broadcast API
## Motivation and Context

`Server#notify_progress` broadcasts progress notifications to all connected clients.
Progress notifications are tied to a specific request's `progressToken` and have no
meaningful broadcast use case. Neither the Python SDK nor the TypeScript SDK provides
a server-level progress broadcast capability.

The MCP specification requires that progress notifications only reference tokens
provided in an active request:

> Progress notifications MUST only reference tokens that:
> - Were provided in an active request
> - Are associated with an in-progress operation

Ref: https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/progress

Broadcasting progress to all clients does not comply with this requirement,
since clients that did not originate the request have no matching `progressToken`.

The introduction of `ServerSession` for per-connection state (#275) made
this removal possible: `Progress` and `ServerContext` now use `notification_target:`
(a `ServerSession`) to route notifications to the originating session only.

### Changes

- Removed `Server#notify_progress` entirely. The method is no longer needed as
  `notification_target` in `call_tool_with_args` now passes `session` directly
  (nil when no session is available, in which case `Progress#report` and
  `ServerContext#notify_log_message` are no-ops).
- Removed `ServerContext#notify_progress` as well. Progress notifications should
  only be sent via `server_context.report_progress`, which enforces the correct
  `progressToken` from the originating request.
- Added nil guards to `Progress#report` and `ServerContext#notify_log_message`
  for when no session is available.
- Rewrote progress tests to use `ServerSession#handle` instead of
  `Server#handle`, reflecting that progress notifications are always session-scoped.
- Removed 4 tests that called `server.notify_progress` directly as a public broadcast API.
- Removed `notify_progress` from the README.md notification methods list.
- Removed the "Server-Side: Direct `notify_progress` Usage" section from the README.md.

Progress notifications should be sent via `server_context.report_progress` inside tool handlers,
which automatically scopes them to the originating client session.

## Breaking Changes

Progress notifications are scoped to a specific request via `progressToken` per the MCP specification,
so the broadcast behavior of `Server#notify_progress` was a spec violation.
This is treated as a bug fix and is made without a deprecation period.
This aligns the Ruby SDK with the Python and TypeScript SDKs, neither of which provides
a server-level progress broadcast API.

`Server#notify_progress` and `ServerContext#notify_progress` are no longer available.
Users should use `server_context.report_progress` inside tool handlers instead, which
provides session-scoped delivery with the correct `progressToken`.

This feature was only recently introduced in mcp 0.9.0:
https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.9.0

So an early release should help limit its impact on adoption.
2026-03-29 15:11:28 +09:00
Koichi ITO
49fc501abc Support session expiry controls for StreamableHTTPTransport
## Motivation and Context

The MCP specification recommends expiring session IDs to reduce session hijacking risks:
https://modelcontextprotocol.io/specification/latest/basic/security_best_practices#session-hijacking

Several other SDKs (Go, C#, PHP, Python) already implement session expiry controls, but
the Ruby SDK did not. Sessions persisted indefinitely unless explicitly deleted or
a stream error occurred, leaving abandoned sessions to accumulate in memory.

This adds a `session_idle_timeout:` option to `StreamableHTTPTransport#initialize`. When
set, sessions that receive no HTTP requests for the specified duration (in seconds) are
automatically expired. Expired sessions return 404 on subsequent requests (GET and POST),
matching the MCP specification's behavior for terminated sessions. Each request resets
the idle timer, so actively used sessions are not interrupted.

A background reaper thread periodically cleans up expired sessions to handle orphaned
sessions that receive no further requests. The reaper only starts when
`session_idle_timeout` is configured.

The default is `nil` (no expiry) for backward compatibility, consistent with the Python
SDK's approach. The Python SDK recommends 1800 seconds (30 minutes) for most deployments:
https://github.com/modelcontextprotocol/python-sdk/pull/2022

Resolves #265.

## How Has This Been Tested?

Added tests for session expiry, idle timeout reset, reaper thread lifecycle, input
validation, and default behavior in `streamable_http_transport_test.rb`. All existing
tests continue to pass.

## Breaking Change

None. The default value of `session_idle_timeout` is `nil`, which preserves the existing
behavior of sessions never expiring. The new `last_active_at` field in the internal
session hash is not part of the public API. Existing code that instantiates
`StreamableHTTPTransport.new(server)` or
`StreamableHTTPTransport.new(server, stateless: true)` continues to work without changes.
2026-03-29 12:34:58 +09:00
Koichi ITO
719e5e7fee Introduce ServerSession for per-connection state
## Motivation and Context

The Ruby SDK uses a 1-Server-to-many-sessions model where session-specific state
(`@client`, `@logging_message_notification`) is stored on the shared `Server` instance.
This causes the last client to connect to overwrite state for all sessions,
and requires `session_id` to be threaded through method signatures for session-scoped notifications.

The Python SDK avoids this by creating a `ServerSession` per connection that wraps a shared `Server`.
Each session holds its own state and naturally scopes notifications through its own stream.

### Changes

- Added `MCP::ServerSession` class holding per-session state: client info,
  logging configuration, and a `transport` reference for session-scoped
  notification delivery.
- `StreamableHTTPTransport#handle_initialization` creates a `ServerSession`
  per `initialize` request and stores it in the session hash.
- `handle_regular_request` routes requests through the session's
  `ServerSession` instead of the shared `Server` directly.
- `Server#handle` and `Server#handle_json` accept an optional `session:`
  keyword (`ServerSession` instance).
- `Server#init` stores client info on the session when available.
- `Server#configure_logging_level` stores logging config on the session.
- `ServerContext` and `Progress` accept a `notification_target:` which
  can be either a `ServerSession` (session-scoped) or a `Server` (broadcast).
  No `session_id:` parameter needed.
- `ServerContext#notify_progress` and `#notify_log_message` delegate to
  the `notification_target` without `session_id` threading.
- `StdioTransport` creates a single `ServerSession` on `open`,
  making the session model transparent across both transports.

### Design Decision

This follows the Python SDK's "shared `Server` + per-connection `Session`" pattern.
The `Server` holds configuration (tools, prompts, resources, handlers).
Each `ServerSession` holds per-connection state (client info, logging level, stream writer).
Notifications from `ServerSession` go only to that session's stream.

## How Has This Been Tested?

All existing tests pass. All conformance tests pass. Added tests verifying:

- Session-scoped log notification is sent only to the originating session.
- Session-scoped progress notification is sent only to the originating session.
- Each session stores its own client info independently.
- Each session stores its own logging level independently.
- `StdioTransport#open` creates a `ServerSession` and stores client info on it.

## Breaking Change

None for end users.

The public API (`Server.new`, `define_tool`,`server_context.report_progress`,
`server_context.notify_log_message`, etc.) is unchanged. The following internal API
changes affect only SDK internals:

- `ServerContext.new` now requires `notification_target:` instead of just`progress:`.
- `Progress.new` now takes `notification_target:` instead of `server:`.
- `Server#handle` and `Server#handle_json` accept an optional `session:` keyword.
2026-03-29 08:04:56 +09:00
Koichi ITO
21eef8df9a Add MCP::Client::Stdio transport
## Motivation and Context

The `MCP::Client` currently only supports HTTP transport (`MCP::Client::HTTP`).
To achieve parity with other MCP SDKs (Python, TypeScript, C#) which provide
stdio client transports for spawning and communicating with server subprocesses,
the Ruby SDK needs a stdio client transport.
https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#stdio

This enables building MCP clients that launch server processes and communicate
via stdin/stdout using newline-delimited JSON-RPC 2.0 messages.

## How Has This Been Tested?

Added tests for process spawning, protocol initialization handshake,
notification handling, error handling, and transport close lifecycle.

## Additional context

Enabled the `Lint/IncompatibleIoSelectWithFiberScheduler` cop in `.rubocop.yml`
to detect accidental use of `IO.select` instead of `IO#wait_readable`.
2026-03-19 12:41:27 +09:00
Koichi ITO
a2514a0ef2
Merge pull request #254 from koic/support_progress_notification_per_mcp_spec
Support progress notifications per MCP specification
2026-03-12 12:26:39 +09:00
Koichi ITO
bbe637612b Support progress notifications per MCP specification
## Motivation and Context

The MCP specification defines `notifications/progress` for reporting incremental progress
during long-running tool operations. The Ruby SDK did not yet support this, so tools had no way to
send progress updates to clients. This caused the `tools-call-with-progress` conformance test to fail.

This adds an `MCP::ServerContext` wrapper that provides a `report_progress` method on
`server_context`. Tools call `server_context.report_progress(value, total:, message:)` to send
notifications back to the client. The method is a no-op when no `progressToken` was provided,
so tools can call it unconditionally without checking for a token.

This design is consistent with the TypeScript and Python SDKs, which provide progress
reporting through a context object rather than a separate parameter.

On the client side, `Client#call_tool` now accepts a `progress_token:` parameter that sets
`_meta.progressToken` in the request.

Ref: https://modelcontextprotocol.io/specification/latest/server/utilities/progress

## How Has This Been Tested?

Added comprehensive tests in `test/mcp/server_progress_test.rb` covering `notify_progress`,
tool integration with progress, block-defined tools, `**kwargs` tools, and no-op behavior
without a token.

Added client tests for `progress_token:` parameter inclusion and omission.

Added `test/mcp/server_context_test.rb` test for non-Hash `server_context` preservation
when `_meta` is present.

Conformance: `tools-call-with-progress` removed from expected failures.

## Breaking Change

`server_context` is now always an `MCP::ServerContext` instance when passed to tools,
even if the server has no context configured. Code that checks `server_context ?` to
detect a nil context will need to be updated, as `ServerContext` is always truthy.
`ServerContext` delegates method calls to the underlying context object via
`method_missing`, so `server_context[:key]` and other accessor patterns continue to work.

In practice, this is unlikely to affect users. A tool that declares `server_context:`
is opting in to use the context; if the server has no context configured, that is a
server configuration issue rather than something the tool should handle with a nil check.
2026-03-10 01:49:09 +09:00
Koichi ITO
8a97cebc33
Merge pull request #252 from koic/fix_rails_controller_example_to_return_202_for_notifications
[Doc] Fix Rails controller example to return 202 for notifications
2026-03-08 03:06:19 +09:00
Koichi ITO
7e0a339681 [Doc] Fix Rails controller example to return 202 for notifications
The previous example used `Server#handle_json` directly, which does not control HTTP status codes.
Notifications such as `notifications/initialized` require 202 Accepted per the MCP spec,
but the example always returned 200.

Use `StreamableHTTPTransport#handle_request` instead, which returns the correct HTTP status code
for each request type.

- https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#sending-messages-to-the-server
- https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server

Closes #158
2026-03-06 03:21:25 +09:00
Eric Kreutzer
50cd86c01c
Add automatic _meta parameter extraction support 2026-03-04 10:11:07 -07:00
Koichi ITO
13bbd2937d Support running MCP conformance tests against the Ruby SDK
## Motivation

To assess and track the Ruby SDK's compliance with the MCP
specification, integrate `@modelcontextprotocol/conformance` as the
standard evaluation harness. This makes it possible to measure
conformance objectively, catch regressions early, and produce the kind
of evaluation data needed for SDK tier assessments.

## Scope

Only server conformance is included at this point. Client conformance
requires protocol-level features that MCP::Client does not yet
support (initialize handshake, notifications, ping, etc.).

## Usage

Run conformance tests:

```console
bundle exec rake conformance
```

Start the conformance server in the foreground for iterating on a single
scenario without the per-run startup overhead:

```console
bundle exec rake conformance_server
```

## Default Rake Task (`bundle exec rake`)

It is configured to run in order of lower execution cost: `rubocop`, `test`, and then `conformance`.

## CI

`.github/workflows/conformance.yml` file has been added to run the conformance tests in CI.

## SDK Tier Report

The MCP SDK Tier system (https://modelcontextprotocol.io/community/sdk-tiers)
requires SDK maintainers to self-assess and report results to the SDK Working
Group via https://github.com/modelcontextprotocol/modelcontextprotocol/issues.

To generate a full tier assessment report, use the `/mcp-sdk-tier-audit`
slash command from the https://github.com/modelcontextprotocol/conformance repository with
the conformance server running:

```console
# 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.
2026-03-02 14:50:03 +09:00
Koichi ITO
1a2750d6d7
Merge pull request #222 from koic/update_readme_for_instrumentation_callback
[Doc] Add `tool_arguments` to instrumentation callback documentation
2026-02-09 00:48:46 +09:00
Koichi ITO
0e30dff80b
Merge pull request #225 from sjrct/add-client-resource-templates
Add resource_templates to MCP::Client
2026-02-07 02:58:52 +09:00
Chris Harding
c145fe39df Add resource_templates to MCP::Client
Includes relevant README addition and tests
2026-02-05 16:02:07 -05:00
Mikhail Dubov
2d926ab386 Add client info to instrumentation callback 2026-02-04 12:03:03 +00:00
Koichi ITO
1c449ae549 [Doc] Add tool_arguments to instrumentation callback documentation
Follow-up to #218, which added the `tool_arguments` feature to the instrumentation callback.
This updates README.md to document the new `tool_arguments` key in both instrumentation callback sections,
and removes redundant instrumentation documentation.
2026-01-31 15:47:56 +09:00
dak2
afa2fb4077 Add logging support
A server can send structured logging messages to the client.
https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/logging#logging

Logging was specified in the 2024-11-05 specification, but since it was not supported in ruby-sdk, I implemented it.
https://modelcontextprotocol.io/specification/2024-11-05/server/utilities/logging

I also made it possible to output a simple notification message in the examples.
2026-01-26 22:23:46 +09:00
Adam Jones
685a4913d4
chore: update licensing to Apache 2.0 for new contributions 2026-01-12 22:49:19 +00:00
Koichi ITO
ca934456de
Merge pull request #189 from koic/update_specification_url_to_latest
[Docs] Update specification URL to `latest`
2025-12-31 08:11:20 +09:00
Koichi ITO
149d977031
Merge pull request #187 from koic/fix_incorrect_example_in_readme
[Doc] Fix incorrect examples in README.md
2025-12-22 00:59:04 +09:00
Koichi ITO
67e03d7b3d Allow stable protocol specification version "2025-11-25"
The MCP specification dated 2025-11-25 has been released:

- https://modelcontextprotocol.io/specification/2025-11-25
- https://blog.modelcontextprotocol.io/posts/2025-11-25-first-mcp-anniversary

This PR allows `'2025-11-25'` to be specified for the `:protocol_version` keyword argument
in `MCP::Configuration.new`.
2025-12-20 18:58:28 +09:00
Koichi ITO
baeb75c8d8
Merge pull request #190 from koic/avoid_draft_protocol_version
Default to the latest stable protocol version
2025-12-20 18:55:18 +09:00
Guillaume Briday
2b205581ea
Rename APITool to WeatherTool and add error handling
Updated the APITool class to WeatherTool and modified method parameters. Added section on tool responses with errors.
2025-12-09 20:09:42 +01:00
Koichi ITO
c786a14f61 Default to the latest stable protocol version
When starting an MCP server in Claude Code with `protocol_version` set to `DRAFT-2025-v3`,
it fails with the following error:

```console
2025-12-04T02:58:01.548Z [DEBUG] MCP server "example": Connection failed after 2093ms: Server's protocol version is not supported: DRAFT-2025-v3
2025-12-04T02:58:01.548Z [ERROR] MCP server "example" Connection failed: Server's protocol version is not supported: DRAFT-2025-v3
```

This PR changes the default behavior so that if `protocol_version` is not specified,
it uses the latest stable protocol version instead of the draft version.

This PR also updates the README to note that the latest stable protocol version includes
new features from the draft version.
2025-12-04 14:58:41 +09:00
Koichi ITO
117bb426e5 [Docs] Update specification URL to latest
This PR updates the specification URL to `latest`.
This change avoids the need to update the URL whenever a new protocol version is released.
The `latest` path redirects to the latest protocol version.
2025-11-30 17:42:27 +09:00
Koichi ITO
dacd5f1741 [Doc] Fix incorrect examples in README.md
This PR fixes incorrect examples in README.md. The block variable could be removed if it is unused,
but when presenting an example `:server_context` should still be shown as a keyword argument.

Fixes #185.
2025-11-28 12:29:06 +09:00
Koichi ITO
00392b660d
Merge pull request #181 from jonathanhefner/generate-api-docs
Add API documentation with GitHub Pages deployment
2025-11-27 12:54:46 +09:00
Koichi ITO
d31c3da8f2
Merge pull request #178 from koic/add_elicitation_skeleton
Add Elicitation skeleton
2025-11-25 01:02:30 +09:00
Jonathan Hefner
281c334075 Add API documentation with GitHub Pages deployment
This adds automated deployment of a versioned API documentation landing
page using GitHub Pages. The landing page links to documentation hosted
on RubyDoc.info, the de facto standard documentation site for the Ruby
ecosystem. The landing page will update to reflect new releases.

Changes
-------

1. **Documentation generation script** (see `bin/generate-gh-pages.sh`)

    Copies and commits documentation files to the gh-pages branch. The
    script uses git worktrees to isolate the process from the main
    workspace.

    The script:

    - Creates the gh-pages branch as an orphan branch if it doesn't exist
    - Parses semantic versions from tag names, ignoring arbitrary
      prefixes (e.g., tags `1.2.3`, `v1.2.3`, and `release-1.2.3` all
      create `v1.2.3`)
    - Determines the latest version using semantic version sorting
    - Copies static Jekyll template files from `docs/` to the gh-pages
      root (for the latest version only)
    - Generates `docs/_data/versions.yml` with a list of all versions
      for the Jekyll templates to consume

2. **Jekyll template files** (see `docs/` directory)

    - `docs/_config.yml` - Jekyll configuration
    - `docs/index.md` - Landing page template that links to all versions
      on RubyDoc.info based on generated `docs/_data/versions.yml`
    - `docs/latest/index.html` - Redirect page template that redirects
      to the latest documentation on RubyDoc.info

3. **GitHub Actions workflow** (see `.github/workflows/release.yml`)

    Added a `publish_gh_pages` job that runs after the `publish_gem` job
    on release events. The job invokes the generation script with the
    release tag name, then pushes the updated gh-pages branch to deploy
    the documentation.

4. **CI validation** (see `.github/workflows/ci.yml`)

    Added a `yard` job that runs YARD validation with `--no-output`.
    This ensures YARD can successfully parse the codebase (without
    generating output), catching documentation issues early in CI.

5. **YARD dependencies** (see `Gemfile`)

    Added `yard` and `yard-sorbet` gems as development dependencies to
    support documentation validation in CI.

    YARD documentation is automatically generated and hosted by
    RubyDoc.info when the gem is published to RubyGems.org.

6. **Documentation links** (see `README.md` and `mcp.gemspec`)

    Added links to the published API documentation on RubyDoc.info in
    the README and gemspec metadata.

Documentation URL
-----------------

Custom documentation will be available at:
https://modelcontextprotocol.github.io/ruby-sdk/

RubyDoc.info documentation will be accessible at:
- https://rubydoc.info/gems/mcp (latest version)
- https://rubydoc.info/gems/mcp/1.2.3 (specific versions)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 12:21:38 -06:00
Koichi ITO
11aea51c42
Merge pull request #179 from koic/add_draft_version
Add "Draft" protocol version to supported protocol versions
2025-11-22 01:57:51 +09:00
Koichi ITO
dd458b1fb7 Add Elicitation skeleton
The MCP 2025-06-18 specification includes a feature called Elicitation:
https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation

Like Log Level, an implementation is expected to be provided in the near future.
This PR adds Elicitation as a skeleton implementation for now.
2025-11-21 02:42:20 +09:00
Koichi ITO
bf729baef2 Add "Draft" protocol version to supported protocol versions
For example, the `title` introduced in #109 is not supported in the latest stable protocol version "2025-06-18":
https://modelcontextprotocol.io/specification/2025-06-18

It is supported in the Draft of the next version:
https://modelcontextprotocol.io/specification/draft

In other words, the fact that the Ruby SDK treats "2025-06-18" as the default protocol version while `title` is
only supported in the Draft results in an inconsistency.

Because of this, a new version `"Draft"` has been added to the list of supported versions.
Its value follows the schema below and is defined as `DRAFT-2025-v3`:
14ec41c/schema/draft/schema.ts (L15)

It was also considered to continue using the latest stable version "2025-06-18" as the Ruby SDK default instead of the Draft.
However, in that case, users would need to explicitly specify `MCP::Server.new(protocol_version: 'DRAFT-2025-v3')`,
which adds extra burden. In this PR, Draft is made the default in order to provide the following benefits:

- Users are likely to prefer using the Draft version over the latest stable version
- No need to specify the `protocol_version` option when initializing `MCP::Server`
- Users generally do not need to know the internal development value `DRAFT-2025-v3`

The primary case for specifying `protocol_version` explicitly is when strict adherence to a particular version is required.
However, it seems more practical to prioritize use cases where backward-compatible features, including those from the Draft,
are desirable. This is the rationale behind making the Draft version the default.

In addition, making the Draft version the default protocol version preserves backward compatibility for `MCP::Server`.

NOTE: `DRAFT-2025-v3` is a development code, so its value cannot be set externally.
It is applied either when `protocol_version` is omitted or when `nil` is set explicitly,
such as with `MCP::Configuration.new(protocol_version: nil)`.
This prevents users from creating implementations that depend on development codes like `DRAFT-2025-v3`.
2025-11-11 15:44:36 +09:00
Koichi ITO
b8719ce04f [Doc] Tweak the README for stateless
`stateless` was supported in #101. However, as shown in the official specification below,
the supported transports are stdout and Streamable HTTP, and whether it is stateless is
a detail specific to Streamable HTTP:
https://modelcontextprotocol.io/specification/2025-06-18/basic/transports

This PR updates the documentation to describe `stateless` as part of the Streamable HTTP section.
2025-11-08 12:55:35 +09:00
Hiren Hiranandani
08a84c7320
Introduce stateless mode to allow for HA
- Create failing tests for `stateless` mode
- Implement `stateless` mode by turning of SSE in Streamable HTTP,
  making the interaction a standard HTTP Req/Resp
2025-11-04 15:26:12 -08:00
Koichi ITO
5b737eb9c3 [Docs] Extract release documentation to RELEASE.md
README is generally better kept focused on information that is most valuable to users.
For that reason, release procedures that are not relevant to end users have been moved to
a separate RELEASE.md file.
2025-11-04 11:13:39 +09:00