## Motivation and Context
`server_context_with_meta` reads `@server_context` (the instance variable)
directly instead of calling the `server_context` accessor method.
This prevents subclasses from overriding `server_context`. Ffor example,
to provide thread-local context in multi-threaded servers like Puma.
Fixes#271.
## How Has This Been Tested?
Added a regression test and passed.
## Breaking Changes
None. This restores the expected behavior of `attr_accessor :server_context`.
## Motivation and Context
`lib/mcp.rb` currently declares all `require_relative` statements in one place.
As a result, Server and Client are both loaded, the stdio and Streamable HTTP
transports are both loaded, and Tool, Prompt, and Resource are all loaded,
regardless of which components are actually used.
These components are selected by the user depending on their use case,
so loading everything upfront is unnecessary.
Using `autoload` for selected constants defers loading until the constant
is actually referenced, so only the subsystems required by the user are loaded.
## How Has This Been Tested?
All existing tests pass unchanged.
## Breaking Change
None. This change only defers loading of unused components.
## 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.
The no-op handlers for `completion/complete`, `resources/subscribe`,
and `resources/unsubscribe` returned `nil`.
When a client accesses the expected response structure (e.g., `result[:completion][:values]`),
a `nil` result raises `NoMethodError`.
The MCP spec requires specific response structures even for no-op handlers.
Returning spec-compliant defaults ensures that clients receive valid responses without
requiring servers to explicitly override each handler.
`completion/complete` now returns `{ completion: { values: [], hasMore: false } }`.
ref: https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/completion
`resources/subscribe` and `resources/unsubscribe` now return `{}` (empty result).
ref: https://modelcontextprotocol.io/specification/2025-11-25/server/resources#subscriptions
Include the tool arguments in instrumentation callback data when
tools/call is invoked. This allows consumers to track which arguments
were passed to each tool call for analytics and debugging purposes.
Previously, the `icons` parameter was always included in responses (as an empty array)
even when not configured. This differs from the response representation in MCP Ruby SDK 0.4.0.
Since `icons` is optional, it should be omitted from responses when unused to reduce
unnecessary context window usage.
https://modelcontextprotocol.io/specification/2025-11-25/schema#implementation
This fix applies to `Tool#to_h`, `Prompt#to_h`, `Resource#to_h`, `ResourceTemplate#to_h`,
and `Server#server_info`.
It doesn't seem critical, but if there are no other issues, it would be good to cut 0.5.1 bugfix release soon.
## Summary
Unlike applications, libraries provide value by remaining usable for a broad range of users,
even when that means supporting older Ruby versions beyond Ruby's own EOL timeline.
I maintain RuboCop, a Ruby linter. Because linters need to work across the ecosystem,
they often need to keep compatibility with older Ruby versions to some extent.
The trade-off is that the MCP Ruby SDK must remain compatible with Ruby 2.7.
However, given the ecosystem impact, supporting Ruby 2.7 is still worthwhile.
For example, bundled gems such as `csv` (Ruby >= 2.5), `bigdecimal` (Ruby >= 2.5), `json` (Ruby >= 2.7),
and `language_server-protocol` (Ruby >= 2.5) tend to keep compatibility with older Ruby versions.
Unlike dropping support, which imposes restrictions on users,
this change broadens compatibility and does not introduce breaking changes.
## Development Note
`rubocop-shopify` (2.18) supports Ruby 3.1+, and this PR does not change that.
Since RuboCop can configure the runtime Ruby version and the target Ruby version for analysis independently,
CI continues to run RuboCop on Ruby 4.0, while analyzing code with `TargetRubyVersion: 2.7`.
When setting `TargetRubyVersion: 2.7`, several RuboCop offenses were resolved.
Additionally, Sorbet-related libraries support Ruby 3.0+. Since these are not dependencies of the MCP Ruby SDK itself,
they are versioned and tested in the development Gemfile.
Claude Code sometimes only shows `Error: MCP error -32603: Internal error`
when an unexpected exception occurs during a tool call.
This change broadens the exception handling scope so the server can surface
the exception message more often, making failures easier to diagnose.
This raises an exception when duplicate tool names are registered,
instead of silently overwriting tools. Tool names are required to be
unique within a server, so this behavior aligns with the MCP specification.
> Tool names SHOULD be unique within a server.
https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names
Validation for tool names could be made more strictly spec-compliant in a separate effort.
Fixes#197
This PR adds support for the optional `websiteUrl` parameter in `serverInfo`.
This parameter has been supported since the 2025-11-25 MCP specification.
This PR also implements part of https://github.com/modelcontextprotocol/ruby-sdk/issues/127.
Consolidates four identical constructions of error `Tool::Response` in
`handle_call_tool_request` into a single private `error_tool_response` method,
reducing duplication and improving maintainability. No behavior change.
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`.
Tool execution errors now return successful responses with isError: true
instead of JSON-RPC protocol errors, per the MCP specification.
This allows clients to distinguish between protocol-level errors and
tool execution errors, providing better error context.
Fixes#159
* Add support for _meta field on tool schema
* use `meta` naming for `_meta` field on tool schema
* apply suggestions to fix `_meta` tests
Co-authored-by: Ateş Göral <ates@magnetiq.com>
* Update lib/mcp/tool.rb
Co-authored-by: Ateş Göral <ates@magnetiq.com>
* Update lib/mcp/tool.rb
Co-authored-by: Ateş Göral <ates@magnetiq.com>
---------
Co-authored-by: Topher Bullock <topherbullock@users.noreply.github.com>
Co-authored-by: Ateş Göral <ates@magnetiq.com>
There are some unused block variables. This change removes block parameters
that consist solely of unused block parameters.
Where `Hash#values` suffices instead of ignoring unused variables,
replace such code with `Hash#values`.
Since the optional `title` becomes `title: null` when not provided, the following error occurs.
This occurs with Claude Code 1.0.100.
```console
[DEBUG] MCP server "example": Connection failed after 1591ms: [
{
"code": "invalid_type",
"expected": "string",
"received": "null",
"path": [
"serverInfo",
"title"
],
"message": "Expected string, received null"
}
]
```
By adding `compact`, the `title` key will be removed if the optional `title` keyword argument is not specified.