import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'; import type { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js'; /** * Who is running this local server — learned from the MCP handshake. * * The agent that spawned this process (Claude Code, Cursor, Codex, …) is * the thing a person sees on the deployment's Audit log and the thing they * revoke; "hexis-mcp on " told them neither which agent it was nor * let two agents on one machine be told apart. The very first message an MCP * client sends is `initialize`, and it carries `clientInfo` — the client's * own name and version. That is the identity a browser sign-in registers * under, and what keys the stored credential, so each agent signs in once * and gets its own row. A client that names itself to nobody gets a GUESS * from the process tree instead (parent-process.ts), marked as such; only * when that fails too does the sign-in say "Unknown agent". * * The catch is ordering: the sign-in has to happen BEFORE the handshake is * answered (the deployment's agent instructions ride the `initialize` * result and need the credential), yet the identity arrives IN the * handshake. So the transport is started early, the `initialize` request is * held (with anything that follows it), the sign-in runs with the identity * in hand, and the held messages are replayed to the server once it exists. * From the client's side this is the same wait a first keyless run always * was — the response to `initialize` arrives once the person has signed in. */ export interface AgentIdentity { /** `clientInfo.name` as the client sent it, e.g. `claude-code` — or, when guessed, the program that spawned this server. */ name: string; version?: string; /** * True when the client named itself to nobody and the name is the parent * program's (see parent-process.ts). Said on stderr at sign-in, so a wrong * guess can be traced to its source. */ guessed?: boolean; } /** "Claude Code", "Cursor" — the agent as a person names it. */ export declare function agentDisplayName(agent: AgentIdentity): string; /** * The agent's part of a stored-credential file name: lowercase, one hyphen * per run of anything else, bounded — a file name, not a display name. */ export declare function agentStoreKey(agent: AgentIdentity): string; /** * What a browser sign-in registers this server as with the deployment — the * name the Audit log then shows for the connection. With an agent known or * guessed: "Claude Code · local server on LAPTOP-1". With none at all: the * truth, "Unknown agent · local server on LAPTOP-1". It used to say * "hexis-mcp on LAPTOP-1", which read as if the local server itself were the * agent — the one thing the Audit log must never suggest. */ export declare function registrationName(agent: AgentIdentity | null, host: string): string; /** * The one stderr line that says who this server is signing in as and where * that came from — so a wrong name on the Audit log can be traced in the * client's server log, instead of being a mystery for a week. */ export declare function identityLine(agent: AgentIdentity | null, host: string, version: string): string; /** The agent an `initialize` request names, or null for any other message or a nameless client. */ export declare function agentFromInitialize(message: JSONRPCMessage): AgentIdentity | null; export interface HeldHandshake { /** Who sent `initialize`; null when the first message was not one, named no client, or the client hung up first. */ agent: AgentIdentity | null; /** The transport to hand the server: already started, replaying what was held once the server listens. */ transport: Transport; } export interface HoldOptions { /** * Resolves when the client has let go — stdin's `end`/`close` for the * stdio transport, which fires `onclose` only from its own `close()` and * never on EOF. Without it a client that spawns the server and dies before * saying anything would leave the hold waiting forever. */ hangUp?: Promise; } /** * Start `inner`, wait for the client's first message, and hand back a * transport the server can `connect()` as if nothing had happened. * * Every message that arrives before the server exists is kept, in order, * and delivered on the wrapper's `start()` — which the SDK calls only after * it has installed its own `onmessage`, so nothing is delivered into the * void. A client that hangs up before saying anything resolves with no * agent; the caller's let-go handling sees the closed stdin and leaves. */ export declare function holdInitialize(inner: Transport, options?: HoldOptions): Promise; //# sourceMappingURL=handshake.d.ts.map