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.
This refactoring extracts common schema validation logic into a base Schema
class, eliminating ~100 lines of duplicate code between InputSchema and
OutputSchema. It also adds support for the JSON Schema `additionalProperties`
keyword to allow fine-grained control over extra properties in tool arguments.
Previously `additionalParameters` could be set only on OutputSchema.
Key changes:
- Created MCP::Tool::Schema base class consolidating:
- Schema validation against JSON Schema Draft 4 metaschema
- Deep key transformation (string to symbol conversion)
- $ref disallowance checking
- Common validation methods
- Refactored InputSchema to inherit from Schema:
- Simplified constructor to accept full schema hash
- Changed required fields storage from symbols to strings
- Removed ~40 lines of duplicated validation logic
- Refactored OutputSchema to inherit from Schema:
- Removed ~54 lines of duplicated validation logic
- Now shares all common functionality with InputSchema
- Updated Tool.input_schema setter:
- Simplified to pass full hash directly to InputSchema
- Added additionalProperties support:
- By default, tools now allow additional properties (JSON Schema default)
- Can explicitly set `additionalProperties: false` to disallow extras
- Added comprehensive test coverage for both behaviors
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.
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`.
- Create failing tests for `stateless` mode
- Implement `stateless` mode by turning of SSE in Streamable HTTP,
making the interaction a standard HTTP Req/Resp
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
Follow-up to https://github.com/modelcontextprotocol/ruby-sdk/pull/147.
According to the specification schema, `content` is not optional and therefore cannot be omitted:
```typescript
interface CallToolResult {
_meta?: { [key: string]: unknown };
content: ContentBlock[];
isError?: boolean;
structuredContent?: { [key: string]: unknown };
[key: string]: unknown;
}
```
https://modelcontextprotocol.io/specification/2025-06-18/schema#calltoolresult
Instead of `nil`, an empty array is set as the default value.
There may be a better value for `content`, but at the very least it should not be missing.
* 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>
I noticed through the existing tests that `MCP::Configuration#protocol_version=`
allows setting an arbitrary protocol version.
Since the official MCP Ruby SDK is an implementation of the MCP specification,
it should not support arbitrary protocol versions. This change adds validation
to the setter, consistent with `Configuration#initialize`.
The same validation has also been added to `MCP::Configuration#validate_tool_call_arguments=`.
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`.
This commit implements optional JSON Schema validation for tool outputs according to the MCP specification:
- Add MCP::Tool::OutputSchema class mirroring InputSchema functionality
- Support output_schema in class definitions, Tool.define, and OutputSchema objects
- Include validate_result method for runtime validation
- Update MCP::Client::Tool to track output schemas
- Add comprehensive test coverage with 249 passing tests
- Update README with dedicated Tool Output Schemas section
- Follow MCP spec requirements for server/client validation