Add instructions support to MCP::Server

The response of the `init` method can include `instructions`.
https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle

`instructions` appear to be supported starting from the 2025-03-26 specification.

- https://modelcontextprotocol.io/specification/2025-03-26/basic/lifecycle (supports `instructions`)
- https://modelcontextprotocol.io/specification/2024-11-05/basic/lifecycle (does not support `instructions`)

If `instructions` is used with an unsupported protocol version, an `ArgumentError` will be raised.

As additional context, the TypeScript SDK also treats `instructions` as optional.
https://github.com/modelcontextprotocol/typescript-sdk/blob/1.16.0/src/types.ts#L356-L361
This commit is contained in:
Koichi ITO 2025-07-23 01:47:22 +09:00
commit f6f064ab71
3 changed files with 41 additions and 3 deletions

View file

@ -155,11 +155,11 @@ You can use the `Server#handle_json` method to handle requests.
```ruby
class ApplicationController < ActionController::Base
def index
server = MCP::Server.new(
name: "my_server",
version: "1.0.0",
instructions: "Use the tools of this server as a last resort",
tools: [SomeTool, AnotherTool],
prompts: [MyPrompt],
server_context: { user_id: current_user.id },

View file

@ -31,11 +31,12 @@ module MCP
include Instrumentation
attr_accessor :name, :version, :tools, :prompts, :resources, :server_context, :configuration, :capabilities, :transport
attr_accessor :name, :version, :instructions, :tools, :prompts, :resources, :server_context, :configuration, :capabilities, :transport
def initialize(
name: "model_context_protocol",
version: DEFAULT_VERSION,
instructions: nil,
tools: [],
prompts: [],
resources: [],
@ -47,6 +48,7 @@ module MCP
)
@name = name
@version = version
@instructions = instructions
@tools = tools.to_h { |t| [t.name_value, t] }
@prompts = prompts.to_h { |p| [p.name_value, p] }
@resources = resources
@ -54,6 +56,12 @@ module MCP
@resource_index = index_resources_by_uri(resources)
@server_context = server_context
@configuration = MCP.configuration.merge(configuration)
if @configuration.protocol_version == "2024-11-05" && @instructions
message = "`instructions` supported by protocol version 2025-03-26 or higher"
raise ArgumentError, message
end
@capabilities = capabilities || default_capabilities
@handlers = {
@ -218,7 +226,8 @@ module MCP
protocolVersion: configuration.protocol_version,
capabilities: capabilities,
serverInfo: server_info,
}
instructions: instructions,
}.compact
end
def list_tools(request)

View file

@ -64,6 +64,7 @@ module MCP
@server = Server.new(
name: @server_name,
version: "1.2.3",
instructions: "Optional instructions for the client",
tools: [@tool, @tool_that_raises],
prompts: [@prompt],
resources: [@resource],
@ -135,6 +136,7 @@ module MCP
name: @server_name,
version: "1.2.3",
},
instructions: "Optional instructions for the client",
},
}
@ -750,6 +752,33 @@ module MCP
assert_equal Server::DEFAULT_VERSION, response[:result][:serverInfo][:version]
end
test "server uses instructions when not configured" do
server = Server.new(name: "test_server")
request = {
jsonrpc: "2.0",
method: "initialize",
id: 1,
}
response = server.handle(request)
refute response[:result].key?(:instructions)
end
test "server uses instructions when configured with protocol version 2025-03-26" do
configuration = Configuration.new(protocol_version: "2025-03-26")
server = Server.new(name: "test_server", instructions: "The server instructions.", configuration: configuration)
assert_equal("The server instructions.", server.instructions)
end
test "raises error if instructions are used with protocol version 2024-11-05" do
configuration = Configuration.new(protocol_version: "2024-11-05")
exception = assert_raises(ArgumentError) do
Server.new(name: "test_server", instructions: "The server instructions.", configuration: configuration)
end
assert_equal("`instructions` supported by protocol version 2025-03-26 or higher", exception.message)
end
test "#define_tool adds a tool to the server" do
@server.define_tool(
name: "defined_tool",