Expose the user-defined server_context in instrumentation data

APM integrations need to tag a span with the subject of the request, but the
user-defined `server_context` hash passed to `Server.new` never reaches
`around_request` or `instrumentation_callback`. The exception reporter's
`server_context` argument is a different value — it describes where a failure
occurred (`{ request: ... }`, `{ notification: ... }`), not who made the call —
so there is currently no way to read the request subject from a hook.

Add `Configuration#instrument_server_context`, off by default. When enabled,
`instrument_call` puts the host's `server_context` into the instrumentation data
before invoking `around_request`, so it is readable both before and after
`request_handler.call`.

The flag is opt-in rather than unconditional because the hash is
application-supplied and may hold values a tracing backend should not receive.
Hosts that do not expose a `server_context` reader are unaffected.

`instrument_call` reads it through `self.server_context`: the existing
`server_context:` keyword shadows the reader, and the value wanted here is the
user-defined hash, not the reporter context.

Follows the same shape as the earlier additions of `tool_arguments` (#218) and
`client` (#221) to this hash.
This commit is contained in:
seunghan Kim 2026-08-08 08:33:07 +09:00
commit 14e02da475

View file

@ -346,7 +346,8 @@ server = MCP::Server.new(
```
This hash is then passed as the `server_context` keyword argument to tool and prompt calls.
Note that exception and instrumentation callbacks do not receive this user-defined hash.
Note that the exception reporter does not receive this user-defined hash, and instrumentation
callbacks omit it unless you opt in with `instrument_server_context`.
See the relevant sections below for the arguments they receive.
#### Request-specific `_meta` Parameter
@ -460,10 +461,31 @@ around_request = ->(data, &request_handler) { request_handler.call }
**`data` availability by timing:**
- Before `request_handler.call`: `method`
- Before `request_handler.call`: `method`, and `server_context` when `instrument_server_context` is enabled
- After `request_handler.call`: `tool_name`, `tool_arguments`, `prompt_name`, `resource_uri`, `error`, `client`
- Not available inside `around_request`: `duration` (added after `around_request` returns)
**Exposing the user-defined `server_context` (opt in):**
`data` omits the user-defined `server_context` by default, because that hash is
application-supplied and may hold values a tracing backend should not receive.
Enable it when you need to tag spans with the request's subject:
```ruby
MCP.configure do |config|
config.instrument_server_context = true
config.around_request = ->(data, &request_handler) {
Sentry.set_user(id: data.dig(:server_context, :user_id))
request_handler.call
}
end
```
`data[:server_context]` is the hash passed to `Server.new` — `nil` when the host
set none. It is not the exception reporter's context argument, which describes
where a failure occurred rather than who made the request.
> [!NOTE]
> `tool_name`, `prompt_name` and `resource_uri` may only be populated for the corresponding request methods
> (`tools/call`, `prompts/get`, `resources/read`), and may not be set depending on how the request is handled
@ -515,6 +537,8 @@ It receives a hash with the following possible keys:
- `error`: (String, optional) Error code if a lookup failed
- `duration`: (Float) Duration of the call in seconds
- `client`: (Hash, optional) Client information with `name` and `version` keys, from the initialize request
- `server_context`: (Any, optional) The user-defined hash passed to `Server.new`, present only when
`instrument_server_context` is enabled
**Signature:**