Use accessor method in server_context_with_meta instead of ivar

## 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`.
This commit is contained in:
Koichi ITO 2026-03-27 11:47:34 +09:00
commit a2575b24e5
2 changed files with 30 additions and 4 deletions

View file

@ -531,14 +531,14 @@ module MCP
def server_context_with_meta(request)
meta = request[:_meta]
if meta && @server_context.is_a?(Hash)
context = @server_context.dup
if meta && server_context.is_a?(Hash)
context = server_context.dup
context[:_meta] = meta
context
elsif meta && @server_context.nil?
elsif meta && server_context.nil?
{ _meta: meta }
else
@server_context
server_context
end
end
end

View file

@ -1731,5 +1731,31 @@ module MCP
end
end
end
test "server_context_with_meta uses accessor method, not ivar directly" do
subclass = Class.new(Server) do
def server_context
{ custom: "from_accessor" }
end
end
server = subclass.new(name: "test", tools: [])
received_context = nil
server.define_tool(name: "ctx_tool") do |server_context:|
received_context = server_context
Tool::Response.new([{ type: "text", text: "ok" }])
end
request = {
jsonrpc: "2.0",
method: "tools/call",
id: 1,
params: { name: "ctx_tool", arguments: {} },
}
server.handle(request)
assert_equal "from_accessor", received_context[:custom]
end
end
end