import type { CompatibleRequestHandlerExtra, McpEvent, MCPRequestLike, MCPServerLike } from '../types'; /** * Client identity — who is calling, and which spec revision they speak. * * Where it lives depends on the revision the *request* declares, so this is a * fallback chain and never a branch: one server serves both eras, request by * request. * * 1. `ctx.mcpReq.envelope` — MCP SDK v2 lifts the reserved * `io.modelcontextprotocol/*` keys out of `_meta` before dispatch, so by * the time a handler runs they are here and `params._meta` is empty. * 2. `request.params._meta` — where 2026-07-28 puts them on the wire, and * where they still are on any server that does not lift them. * 3. the `MCP-Protocol-Version` request header, which 2025-11-25 requires a * client to send on every request after `initialize` — the only per-request * carrier a legacy-era request has, and therefore the only one that * survives a per-request server instance. * 4. the server's own accessors — `getClientVersion()` from a legacy * `initialize` handshake, `getNegotiatedProtocolVersion()` on v2. * * The 2026-07-28 revision removed the `initialize` handshake and the * `Mcp-Session-Id` header (SEP-2575 / SEP-2567), so client name/version and the * protocol version no longer arrive once per connection — they travel with * every request. The key strings are mirrored here rather than imported, * because no `@modelcontextprotocol/*` package is a dependency of this one. */ export declare const META_CLIENT_INFO_KEY = "io.modelcontextprotocol/clientInfo"; export declare const META_PROTOCOL_VERSION_KEY = "io.modelcontextprotocol/protocolVersion"; /** Required on every post-`initialize` request by 2025-11-25 (and sent by modern clients too). */ export declare const PROTOCOL_VERSION_HEADER = "mcp-protocol-version"; export interface MetaClientInfo { clientName?: string; clientVersion?: string; protocolVersion?: string; } /** Everything a request can be asked about who is calling. */ export interface ClientIdentitySources { request: MCPRequestLike; extra?: CompatibleRequestHandlerExtra; /** * Typed `unknown` on purpose: every accessor on it is reached through a * structural probe, never a declared type, because the two SDK majors expose * different ones. Call sites pass a real `MCPServerLike`; the shape checks * here are what decide whether it can answer. */ server?: unknown; } /** * Reads the client name/version and protocol version a modern client puts in * `params._meta`. Returns `undefined` when the request carries none (e.g. a * legacy client, which sends this on `initialize` instead). Never throws. */ export declare function readMetaClientInfo(request: MCPRequestLike): MetaClientInfo | undefined; /** * Reads the same keys from MCP SDK v2's request envelope. v2 strips the reserved * `io.modelcontextprotocol/*` keys from `_meta` while parsing, so on exactly the * traffic this matters for, `readMetaClientInfo` finds nothing and this finds * everything. */ export declare function readEnvelopeClientInfo(extra: CompatibleRequestHandlerExtra | undefined): MetaClientInfo | undefined; /** * Reads the protocol version off the request headers. * * This is what closes the gap on **2025-11-25 traffic served by a per-request * server**: that era carries identity at the handshake, and the instance * handling a later `tools/call` never saw it. The header rides every request, so * it survives where the handshake does not. Carries no client name — that still * depends on the replayed session token. */ export declare function readHeaderProtocolVersion(extra: CompatibleRequestHandlerExtra | undefined): MetaClientInfo | undefined; /** * Asks the server itself. `getClientVersion()` answers on any server that * handled an `initialize` (and v2 hosts such as `createMcpHandler` backfill it * from the envelope); `getNegotiatedProtocolVersion()` exists on v2 only, which * is why it is a link in the chain rather than a branch. Never throws — a * server that dislikes being asked must not fail the tool call. */ export declare function readServerClientIdentity(server: unknown): MetaClientInfo | undefined; /** * Resolves client identity through the whole chain, field by field: the first * source that answers a field wins, and a source that answers nothing simply * does not participate. Field-by-field rather than source-by-source because a * request may carry its protocol version in the envelope while the client's * name is only known to the server from a handshake. * * The first three links are **per request**, so they cannot describe anyone but * the caller. Only the last — the server's own accessors — is connection-scoped, * and on a server that multiplexes several clients through one connection it * answers for whichever client completed the handshake. That is the best answer * available on that connection, and it is the same scope `capture.ts` has always * fallen back to (`eventInput.clientName ?? sessionInfo.clientName`), so the * chain neither introduces that sharing nor widens it. Ordering it last is what * keeps it a fallback: any request that identifies itself wins outright. */ export declare function resolveClientIdentity({ request, extra, server }: ClientIdentitySources): MetaClientInfo | undefined; /** * Stamps whatever the chain resolved onto the event being built for *this* * request, so it carries `$mcp_client_name`, `$mcp_client_version` and * `$mcp_protocol_version` even when there was no `initialize` to learn them * from (the modern stateless case). * * Writing to the event — a per-request object — rather than the server-wide * `sessionInfo` keeps identity correct when one instrumented server multiplexes * concurrent requests from different clients (which the stateless spec allows): * a sibling request can't clobber this event's attribution between now and when * it's captured. Only fields actually resolved are set, so a request that * carries nothing leaves the event's existing values untouched. */ export declare function stampClientIdentity(event: McpEvent, request: MCPRequestLike, extra?: CompatibleRequestHandlerExtra, server?: MCPServerLike): void; //# sourceMappingURL=client-identity.d.ts.map