@jini-ai/mcp 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +151 -0
- package/README.md +97 -22
- package/dist/agent-install/install.d.ts +20 -4
- package/dist/agent-install/install.js +11 -11
- package/dist/bin/serve.d.ts +25 -13
- package/dist/bin/serve.js +42 -21
- package/dist/client/client.d.ts +28 -8
- package/dist/client/client.js +25 -21
- package/dist/core/config.d.ts +57 -18
- package/dist/core/config.js +76 -48
- package/dist/core/index.d.ts +1 -2
- package/dist/core/index.js +1 -2
- package/dist/core/install-info.d.ts +4 -1
- package/dist/core/install-info.js +5 -5
- package/dist/core/tokens.d.ts +39 -13
- package/dist/core/tokens.js +54 -24
- package/dist/federation/adapter.http.d.ts +67 -0
- package/dist/federation/adapter.http.js +414 -0
- package/dist/federation/approvals/call-confirmation.d.ts +23 -0
- package/dist/federation/approvals/call-confirmation.js +124 -0
- package/dist/federation/approvals/index.d.ts +4 -0
- package/dist/federation/approvals/index.js +4 -0
- package/dist/federation/approvals/ports.d.ts +107 -0
- package/dist/federation/approvals/ports.js +2 -0
- package/dist/federation/approvals/revocation.d.ts +61 -0
- package/dist/federation/approvals/revocation.js +52 -0
- package/dist/federation/bootstrap.d.ts +100 -0
- package/dist/federation/bootstrap.js +182 -0
- package/dist/federation/config.d.ts +68 -0
- package/dist/federation/config.js +40 -0
- package/dist/federation/index.d.ts +14 -0
- package/dist/federation/index.js +14 -0
- package/dist/federation/mcp-protocol.d.ts +115 -0
- package/dist/federation/mcp-protocol.js +151 -0
- package/dist/federation/messages.d.ts +54 -0
- package/dist/federation/messages.js +35 -0
- package/dist/federation/ports.d.ts +287 -0
- package/dist/federation/ports.js +5 -0
- package/dist/federation/presets.d.ts +66 -0
- package/dist/federation/presets.js +30 -0
- package/dist/federation/refusal-notice.d.ts +198 -0
- package/dist/federation/refusal-notice.js +193 -0
- package/dist/federation/registrations.d.ts +171 -0
- package/dist/federation/registrations.js +181 -0
- package/dist/federation/reload.d.ts +112 -0
- package/dist/federation/reload.js +110 -0
- package/dist/federation/stdio/adapter.stdio.d.ts +157 -0
- package/dist/federation/stdio/adapter.stdio.js +526 -0
- package/dist/federation/stdio/default-connect.d.ts +29 -0
- package/dist/federation/stdio/default-connect.js +92 -0
- package/dist/federation/stdio/index.d.ts +4 -0
- package/dist/federation/stdio/index.js +4 -0
- package/dist/federation/stdio/stdio-launch-resolver.d.ts +139 -0
- package/dist/federation/stdio/stdio-launch-resolver.js +227 -0
- package/dist/federation/testing/adapter.memory.d.ts +177 -0
- package/dist/federation/testing/adapter.memory.js +189 -0
- package/dist/federation/testing/index.d.ts +3 -0
- package/dist/federation/testing/index.js +3 -0
- package/dist/federation/testing/tool-approvals.memory.d.ts +27 -0
- package/dist/federation/testing/tool-approvals.memory.js +38 -0
- package/dist/federation/tool-approvals.d.ts +97 -0
- package/dist/federation/tool-approvals.js +42 -0
- package/dist/federation/trust.d.ts +471 -0
- package/dist/federation/trust.js +707 -0
- package/dist/index.d.ts +175 -2
- package/dist/index.js +172 -2
- package/dist/server/daemon-client.d.ts +16 -4
- package/dist/server/daemon-client.js +41 -19
- package/dist/server/ports.d.ts +9 -0
- package/dist/server/ports.js +2 -0
- package/dist/server/resource-protocol.d.ts +14 -4
- package/dist/server/resource-protocol.js +6 -6
- package/dist/server/resources/active-resource.js +3 -3
- package/dist/server/sdk-transport.d.ts +11 -0
- package/dist/server/sdk-transport.js +31 -0
- package/dist/server/tool-protocol.d.ts +31 -9
- package/dist/server/tool-protocol.js +20 -18
- package/dist/server/tool-server.d.ts +60 -43
- package/dist/server/tool-server.js +51 -27
- package/dist/server/tools/component-catalog-tools.js +7 -7
- package/dist/server/tools/delegated-tool.d.ts +7 -4
- package/dist/server/tools/delegated-tool.js +14 -15
- package/dist/server/tools/run-tools.js +15 -15
- package/dist/server/tools/tool-catalog-tools.js +7 -7
- package/dist/tools/ask-choice/index.d.ts +123 -0
- package/dist/tools/ask-choice/index.js +98 -0
- package/dist/tools/ask-choice/pending.d.ts +11 -0
- package/dist/tools/ask-choice/pending.js +34 -0
- package/dist/tools/ask-choice/question.d.ts +16 -0
- package/dist/tools/ask-choice/question.js +60 -0
- package/dist/tools/ask-choice/schema.d.ts +91 -0
- package/dist/tools/ask-choice/schema.js +27 -0
- package/dist/tools/ask-choice/types.d.ts +106 -0
- package/dist/tools/ask-choice/types.js +2 -0
- package/package.json +43 -5
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { RemoteToolDescriptor, RemoteToolResult, McpClientInfo } from "./ports.js";
|
|
2
|
+
/**
|
|
3
|
+
* @file The transport-INDEPENDENT half of host app's minimal MCP client: the JSON-RPC envelope shapes,
|
|
4
|
+
* the handshake constants, and the narrowing of everything a remote server sends back.
|
|
5
|
+
*
|
|
6
|
+
* Why this file exists:
|
|
7
|
+
* `adapter.stdio.ts` and `adapter.http.ts` differ only in how bytes move. Every decision about what
|
|
8
|
+
* a `tools/list` page means, which cursor to follow, how many pages to follow, what a `tools/call`
|
|
9
|
+
* result is allowed to look like, and which fields survive narrowing is identical across both —
|
|
10
|
+
* because it is the PROTOCOL, not the pipe. Duplicating it into the second adapter would have
|
|
11
|
+
* created two copies of this codebase's untrusted-input narrowing that could silently disagree,
|
|
12
|
+
* which is the failure mode the narrowing exists to prevent.
|
|
13
|
+
*
|
|
14
|
+
* Everything here treats its input as HOSTILE. A remote server controls every byte parsed by this
|
|
15
|
+
* file: tool names, descriptions, schemas, annotations, cursors, results. This file's job is to
|
|
16
|
+
* turn that into well-typed values or drop it — never to trust it, and never to throw on it where
|
|
17
|
+
* dropping would do. The trust decisions themselves belong to `trust.ts`; see `ports.ts`'s header
|
|
18
|
+
* for the split.
|
|
19
|
+
*
|
|
20
|
+
* Architectural role:
|
|
21
|
+
* Pure functions and constants. No I/O, no state, no transport knowledge.
|
|
22
|
+
*/
|
|
23
|
+
/** The MCP revision this client negotiates. A server replying with a different one is accepted —
|
|
24
|
+
* MCP's own rule is that the server names the version it will actually speak — but the value is
|
|
25
|
+
* carried on the session so a mismatch is visible in logs rather than silent. */
|
|
26
|
+
export declare const CLIENT_PROTOCOL_VERSION = "2025-06-18";
|
|
27
|
+
/** Bound on `tools/list` cursor-following. A server that returns a fresh `nextCursor` forever would
|
|
28
|
+
* otherwise pin the daemon's boot at 100% CPU; `trust.ts`'s `maxTools` caps what is admitted, but
|
|
29
|
+
* that check runs after this loop, so the loop needs its own bound. */
|
|
30
|
+
export declare const MAX_LIST_TOOLS_PAGES = 20;
|
|
31
|
+
/** One JSON-RPC 2.0 frame as received. Every field optional because a remote may omit any of them,
|
|
32
|
+
* and a missing field must be a narrowing failure rather than a crash. */
|
|
33
|
+
export interface JsonRpcResponse {
|
|
34
|
+
jsonrpc?: string | undefined;
|
|
35
|
+
id?: unknown | undefined;
|
|
36
|
+
result?: unknown | undefined;
|
|
37
|
+
error?: {
|
|
38
|
+
code?: number | undefined;
|
|
39
|
+
message?: string | undefined;
|
|
40
|
+
data?: unknown | undefined;
|
|
41
|
+
} | undefined;
|
|
42
|
+
method?: string | undefined;
|
|
43
|
+
params?: unknown | undefined;
|
|
44
|
+
}
|
|
45
|
+
/** Every failure raised by an MCP client adapter, whatever the transport. Distinct from a plain
|
|
46
|
+
* `Error` so `bootstrap.ts`'s fail-open handler can tell "the protocol went wrong" from "the code
|
|
47
|
+
* went wrong" when it logs. */
|
|
48
|
+
export declare class McpProtocolError extends Error {
|
|
49
|
+
constructor({ message }: {
|
|
50
|
+
message: string;
|
|
51
|
+
}, options?: ErrorOptions);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A `McpProtocolError` specifically caused by the remote's token having expired or been revoked
|
|
55
|
+
* (HTTP 401 today — see `adapter.http.ts`'s `assertOkStatus`; a 403 is a scope/permission refusal,
|
|
56
|
+
* not this). Kept as a distinguishable
|
|
57
|
+
* subtype, rather than a generic `McpProtocolError` a caller would have to pattern-match on message
|
|
58
|
+
* text, so a layer that DOES know what "authorization" means for one connection (an OAuth-backed
|
|
59
|
+
* row, at `assistant/external-mcp-oauth.ts`) can react to it — without this module, which is
|
|
60
|
+
* transport-independent protocol plumbing, knowing anything about OAuth.
|
|
61
|
+
*/
|
|
62
|
+
export declare class McpAuthFailedError extends McpProtocolError {
|
|
63
|
+
}
|
|
64
|
+
/** The server's half of a completed handshake. Untrusted, like everything else it sends — recorded
|
|
65
|
+
* for diagnostics and audit, never acted on. */
|
|
66
|
+
export interface McpServerIdentity {
|
|
67
|
+
readonly protocolVersion: string;
|
|
68
|
+
readonly info: {
|
|
69
|
+
name?: string | undefined;
|
|
70
|
+
version?: string | undefined;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export declare function asRecord({ value }: {
|
|
74
|
+
value: unknown;
|
|
75
|
+
}): Record<string, unknown> | null;
|
|
76
|
+
/** Builds the `initialize` params. One function so both transports negotiate identically — a
|
|
77
|
+
* capability advertised on one and not the other would mean a remote could ask one of host app's two
|
|
78
|
+
* clients for something the other refuses. */
|
|
79
|
+
export declare function buildInitializeParams({ clientInfo }: {
|
|
80
|
+
clientInfo: McpClientInfo;
|
|
81
|
+
}): Record<string, unknown>;
|
|
82
|
+
/** Narrows an `initialize` result into the server's self-reported identity. */
|
|
83
|
+
export declare function parseInitializeResult({ result }: {
|
|
84
|
+
result: unknown;
|
|
85
|
+
}): McpServerIdentity;
|
|
86
|
+
/** Narrows a `tools/call` result. A non-object result is carried through as `content` rather than
|
|
87
|
+
* discarded: a server returning a bare string is out of spec but harmless, and the untrusted
|
|
88
|
+
* envelope (`trust.ts` R7) is where it lands either way. */
|
|
89
|
+
export declare function parseCallToolResult({ result }: {
|
|
90
|
+
result: unknown;
|
|
91
|
+
}): RemoteToolResult;
|
|
92
|
+
/** Narrows one `tools/list` response page into its usable descriptors plus the cursor for the next
|
|
93
|
+
* page (`undefined` when there is none). A malformed entry is dropped rather than thrown on — one
|
|
94
|
+
* bad descriptor must not cost the operator every other tool on the same server; `trust.ts`
|
|
95
|
+
* refuses anything that survives this and still fails its own checks. */
|
|
96
|
+
export declare function parseToolsListPage({ result }: {
|
|
97
|
+
result: unknown;
|
|
98
|
+
}): {
|
|
99
|
+
readonly tools: RemoteToolDescriptor[];
|
|
100
|
+
readonly nextCursor: string | undefined;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Drains a paginated `tools/list` for one session, whatever the transport.
|
|
104
|
+
*
|
|
105
|
+
* @param requestPage - Issues one `tools/list` request and returns its raw result.
|
|
106
|
+
* @throws {McpProtocolError} When the remote keeps producing cursors past
|
|
107
|
+
* {@link MAX_LIST_TOOLS_PAGES}.
|
|
108
|
+
* @complexity O(p) in pages, bounded by {@link MAX_LIST_TOOLS_PAGES}.
|
|
109
|
+
*/
|
|
110
|
+
export declare function drainToolsList({ requestPage }: {
|
|
111
|
+
requestPage: (required: {
|
|
112
|
+
params: Record<string, unknown>;
|
|
113
|
+
}) => Promise<unknown>;
|
|
114
|
+
}): Promise<RemoteToolDescriptor[]>;
|
|
115
|
+
//# sourceMappingURL=mcp-protocol.d.ts.map
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The transport-INDEPENDENT half of host app's minimal MCP client: the JSON-RPC envelope shapes,
|
|
3
|
+
* the handshake constants, and the narrowing of everything a remote server sends back.
|
|
4
|
+
*
|
|
5
|
+
* Why this file exists:
|
|
6
|
+
* `adapter.stdio.ts` and `adapter.http.ts` differ only in how bytes move. Every decision about what
|
|
7
|
+
* a `tools/list` page means, which cursor to follow, how many pages to follow, what a `tools/call`
|
|
8
|
+
* result is allowed to look like, and which fields survive narrowing is identical across both —
|
|
9
|
+
* because it is the PROTOCOL, not the pipe. Duplicating it into the second adapter would have
|
|
10
|
+
* created two copies of this codebase's untrusted-input narrowing that could silently disagree,
|
|
11
|
+
* which is the failure mode the narrowing exists to prevent.
|
|
12
|
+
*
|
|
13
|
+
* Everything here treats its input as HOSTILE. A remote server controls every byte parsed by this
|
|
14
|
+
* file: tool names, descriptions, schemas, annotations, cursors, results. This file's job is to
|
|
15
|
+
* turn that into well-typed values or drop it — never to trust it, and never to throw on it where
|
|
16
|
+
* dropping would do. The trust decisions themselves belong to `trust.ts`; see `ports.ts`'s header
|
|
17
|
+
* for the split.
|
|
18
|
+
*
|
|
19
|
+
* Architectural role:
|
|
20
|
+
* Pure functions and constants. No I/O, no state, no transport knowledge.
|
|
21
|
+
*/
|
|
22
|
+
/** The MCP revision this client negotiates. A server replying with a different one is accepted —
|
|
23
|
+
* MCP's own rule is that the server names the version it will actually speak — but the value is
|
|
24
|
+
* carried on the session so a mismatch is visible in logs rather than silent. */
|
|
25
|
+
export const CLIENT_PROTOCOL_VERSION = "2025-06-18";
|
|
26
|
+
/** Bound on `tools/list` cursor-following. A server that returns a fresh `nextCursor` forever would
|
|
27
|
+
* otherwise pin the daemon's boot at 100% CPU; `trust.ts`'s `maxTools` caps what is admitted, but
|
|
28
|
+
* that check runs after this loop, so the loop needs its own bound. */
|
|
29
|
+
export const MAX_LIST_TOOLS_PAGES = 20;
|
|
30
|
+
/** Every failure raised by an MCP client adapter, whatever the transport. Distinct from a plain
|
|
31
|
+
* `Error` so `bootstrap.ts`'s fail-open handler can tell "the protocol went wrong" from "the code
|
|
32
|
+
* went wrong" when it logs. */
|
|
33
|
+
export class McpProtocolError extends Error {
|
|
34
|
+
constructor({ message }, options = {}) {
|
|
35
|
+
super(message, options);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A `McpProtocolError` specifically caused by the remote's token having expired or been revoked
|
|
40
|
+
* (HTTP 401 today — see `adapter.http.ts`'s `assertOkStatus`; a 403 is a scope/permission refusal,
|
|
41
|
+
* not this). Kept as a distinguishable
|
|
42
|
+
* subtype, rather than a generic `McpProtocolError` a caller would have to pattern-match on message
|
|
43
|
+
* text, so a layer that DOES know what "authorization" means for one connection (an OAuth-backed
|
|
44
|
+
* row, at `assistant/external-mcp-oauth.ts`) can react to it — without this module, which is
|
|
45
|
+
* transport-independent protocol plumbing, knowing anything about OAuth.
|
|
46
|
+
*/
|
|
47
|
+
export class McpAuthFailedError extends McpProtocolError {
|
|
48
|
+
}
|
|
49
|
+
export function asRecord({ value }) {
|
|
50
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
51
|
+
return null;
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
/** Builds the `initialize` params. One function so both transports negotiate identically — a
|
|
55
|
+
* capability advertised on one and not the other would mean a remote could ask one of host app's two
|
|
56
|
+
* clients for something the other refuses. */
|
|
57
|
+
export function buildInitializeParams({ clientInfo }) {
|
|
58
|
+
return { protocolVersion: CLIENT_PROTOCOL_VERSION, capabilities: {}, clientInfo };
|
|
59
|
+
}
|
|
60
|
+
/** Narrows an `initialize` result into the server's self-reported identity. */
|
|
61
|
+
export function parseInitializeResult({ result }) {
|
|
62
|
+
const record = asRecord({ value: result });
|
|
63
|
+
const info = asRecord({ value: record?.serverInfo });
|
|
64
|
+
return {
|
|
65
|
+
protocolVersion: typeof record?.protocolVersion === "string" ? record.protocolVersion : "",
|
|
66
|
+
info: {
|
|
67
|
+
name: typeof info?.name === "string" ? info.name : undefined,
|
|
68
|
+
version: typeof info?.version === "string" ? info.version : undefined,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** Narrows a `tools/call` result. A non-object result is carried through as `content` rather than
|
|
73
|
+
* discarded: a server returning a bare string is out of spec but harmless, and the untrusted
|
|
74
|
+
* envelope (`trust.ts` R7) is where it lands either way. */
|
|
75
|
+
export function parseCallToolResult({ result }) {
|
|
76
|
+
const record = asRecord({ value: result });
|
|
77
|
+
if (!record)
|
|
78
|
+
return { content: result };
|
|
79
|
+
return {
|
|
80
|
+
content: record.content,
|
|
81
|
+
structuredContent: record.structuredContent,
|
|
82
|
+
// The remote's own claim about its own outcome. Surfaced to the model inside the untrusted
|
|
83
|
+
// envelope (`trust.ts` R7); never used to decide anything on this side.
|
|
84
|
+
isError: record.isError === true,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** Narrows one `tools/list` response's `annotations` block. Shape only — the trust decisions all
|
|
88
|
+
* live in `trust.ts`. Split out of {@link asRemoteToolDescriptor} purely to keep that function's
|
|
89
|
+
* complexity under the shop ceiling. */
|
|
90
|
+
function asRemoteToolAnnotations(record) {
|
|
91
|
+
if (!record)
|
|
92
|
+
return undefined;
|
|
93
|
+
return {
|
|
94
|
+
title: typeof record.title === "string" ? record.title : undefined,
|
|
95
|
+
readOnlyHint: typeof record.readOnlyHint === "boolean" ? record.readOnlyHint : undefined,
|
|
96
|
+
destructiveHint: typeof record.destructiveHint === "boolean" ? record.destructiveHint : undefined,
|
|
97
|
+
idempotentHint: typeof record.idempotentHint === "boolean" ? record.idempotentHint : undefined,
|
|
98
|
+
openWorldHint: typeof record.openWorldHint === "boolean" ? record.openWorldHint : undefined,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Narrows one `tools/list` entry, discarding anything without a usable `name`. Shape only — the
|
|
102
|
+
* trust decisions all live in `trust.ts`. */
|
|
103
|
+
function asRemoteToolDescriptor(value) {
|
|
104
|
+
const record = asRecord({ value: value });
|
|
105
|
+
if (!record || typeof record.name !== "string" || record.name.length === 0)
|
|
106
|
+
return null;
|
|
107
|
+
return {
|
|
108
|
+
name: record.name,
|
|
109
|
+
description: typeof record.description === "string" ? record.description : undefined,
|
|
110
|
+
inputSchema: record.inputSchema,
|
|
111
|
+
annotations: asRemoteToolAnnotations(asRecord({ value: record.annotations })),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/** Narrows one `tools/list` response page into its usable descriptors plus the cursor for the next
|
|
115
|
+
* page (`undefined` when there is none). A malformed entry is dropped rather than thrown on — one
|
|
116
|
+
* bad descriptor must not cost the operator every other tool on the same server; `trust.ts`
|
|
117
|
+
* refuses anything that survives this and still fails its own checks. */
|
|
118
|
+
export function parseToolsListPage({ result }) {
|
|
119
|
+
const record = asRecord({ value: result });
|
|
120
|
+
const rawTools = record && Array.isArray(record.tools) ? record.tools : [];
|
|
121
|
+
const tools = [];
|
|
122
|
+
for (const tool of rawTools) {
|
|
123
|
+
const descriptor = asRemoteToolDescriptor(tool);
|
|
124
|
+
if (descriptor)
|
|
125
|
+
tools.push(descriptor);
|
|
126
|
+
}
|
|
127
|
+
const next = record?.nextCursor;
|
|
128
|
+
return { tools, nextCursor: typeof next === "string" && next.length > 0 ? next : undefined };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Drains a paginated `tools/list` for one session, whatever the transport.
|
|
132
|
+
*
|
|
133
|
+
* @param requestPage - Issues one `tools/list` request and returns its raw result.
|
|
134
|
+
* @throws {McpProtocolError} When the remote keeps producing cursors past
|
|
135
|
+
* {@link MAX_LIST_TOOLS_PAGES}.
|
|
136
|
+
* @complexity O(p) in pages, bounded by {@link MAX_LIST_TOOLS_PAGES}.
|
|
137
|
+
*/
|
|
138
|
+
export async function drainToolsList({ requestPage }) {
|
|
139
|
+
const collected = [];
|
|
140
|
+
let cursor;
|
|
141
|
+
for (let page = 0; page < MAX_LIST_TOOLS_PAGES; page += 1) {
|
|
142
|
+
const result = await requestPage({ params: cursor === undefined ? {} : { cursor } });
|
|
143
|
+
const { tools, nextCursor } = parseToolsListPage({ result: result });
|
|
144
|
+
collected.push(...tools);
|
|
145
|
+
if (nextCursor === undefined)
|
|
146
|
+
return collected;
|
|
147
|
+
cursor = nextCursor;
|
|
148
|
+
}
|
|
149
|
+
throw new McpProtocolError({ message: `mcp-federation: the remote server kept returning a tools/list nextCursor past ${MAX_LIST_TOOLS_PAGES} pages — refusing to follow it further` });
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=mcp-protocol.js.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ToolRefusalReason } from "./trust.js";
|
|
2
|
+
import type { FederatedCallConfirmationRequest } from "./ports.js";
|
|
3
|
+
/** Host-owned refusal wording; reason codes and sanitized data remain independent of presentation. */
|
|
4
|
+
export interface FederationRefusalMessages {
|
|
5
|
+
readonly refusalExplanations: Readonly<Record<ToolRefusalReason, string>>;
|
|
6
|
+
readonly unprintableName: string;
|
|
7
|
+
readonly absentExplanation: string;
|
|
8
|
+
readonly inertWriteGrantExplanation: string;
|
|
9
|
+
readonly prefixHeading: string;
|
|
10
|
+
readonly prefixInstruction: string;
|
|
11
|
+
refusalBullet(required: {
|
|
12
|
+
remoteName: string;
|
|
13
|
+
connectionId: string;
|
|
14
|
+
explanation: string;
|
|
15
|
+
}): string;
|
|
16
|
+
omittedRefusals(required: {
|
|
17
|
+
omitted: number;
|
|
18
|
+
total: number;
|
|
19
|
+
}): string;
|
|
20
|
+
}
|
|
21
|
+
/** Shared federation presentation. Hosts replace the complete object, including confirmation and launch copy. */
|
|
22
|
+
export interface FederationMessages extends FederationRefusalMessages {
|
|
23
|
+
authenticationRefused(required: {
|
|
24
|
+
method: string;
|
|
25
|
+
status: number;
|
|
26
|
+
}): string;
|
|
27
|
+
readonly closedByHost: string;
|
|
28
|
+
nativeCollision(required: {
|
|
29
|
+
toolId: string;
|
|
30
|
+
}): string;
|
|
31
|
+
/** Hosts can distinguish uvx/docker/general commands by basename (including Windows suffixes
|
|
32
|
+
* and absolute paths), preserving remediation appropriate to their installed toolchain. */
|
|
33
|
+
launchUnavailable(required: {
|
|
34
|
+
command: string;
|
|
35
|
+
searchedDirs: readonly string[];
|
|
36
|
+
}): string;
|
|
37
|
+
confirmationTitle(required: {
|
|
38
|
+
request: FederatedCallConfirmationRequest;
|
|
39
|
+
}): string;
|
|
40
|
+
confirmationWarning(required: {
|
|
41
|
+
request: FederatedCallConfirmationRequest;
|
|
42
|
+
}): string;
|
|
43
|
+
readonly confirmationDescription: string;
|
|
44
|
+
readonly serviceLabel: string;
|
|
45
|
+
readonly toolLabel: string;
|
|
46
|
+
readonly argumentsLabel: string;
|
|
47
|
+
readonly noArguments: string;
|
|
48
|
+
readonly confirmLabel: string;
|
|
49
|
+
readonly allowChatLabel: string;
|
|
50
|
+
readonly allowAlwaysLabel: string;
|
|
51
|
+
}
|
|
52
|
+
/** Neutral English defaults are explicit host choices, never implicit branding or wire defaults. */
|
|
53
|
+
export declare const defaultFederationMessages: FederationMessages;
|
|
54
|
+
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Neutral English defaults are explicit host choices, never implicit branding or wire defaults. */
|
|
2
|
+
export const defaultFederationMessages = {
|
|
3
|
+
refusalExplanations: {
|
|
4
|
+
"not-in-operator-allowlist": "the administrator has not allowed this tool for this connection. Fix: ask the administrator to allow this tool for this connection.",
|
|
5
|
+
"remote-declares-not-read-only": "the server says this tool makes changes, but the connection has no write grant for it. Fix: ask the administrator to allow this tool and its changes for this connection.",
|
|
6
|
+
"remote-declares-destructive": "the server marks this tool as destructive and the admission policy refused it. Fix: ask the administrator to review the connection's destructive-tool policy.",
|
|
7
|
+
"missing-or-invalid-input-schema": "the server published no usable input schema, so arguments would be guesswork. Fix: ask the administrator to report the missing contract to the server vendor.",
|
|
8
|
+
"invalid-remote-tool-name": "the server advertised a name that cannot be registered (letters, digits, '.', '-' or '_', at most 64 characters). Fix: ask the administrator to report the invalid name to the server vendor.",
|
|
9
|
+
"duplicate-remote-tool-name": "the server advertised the same tool name twice; the repeat cannot overwrite the first definition. Fix: ask the administrator to report the duplicate to the server vendor.",
|
|
10
|
+
"connection-tool-cap-reached": "the connection reached its maximum number of tools. Fix: ask the administrator to limit the connection to the tools that are needed, then restart the assistant.",
|
|
11
|
+
},
|
|
12
|
+
unprintableName: "(an invalid tool name sent by this server)",
|
|
13
|
+
absentExplanation: "the administrator allowed this tool, but the server does not offer that name. Ask the administrator to check the name and the server's enabled features.",
|
|
14
|
+
inertWriteGrantExplanation: "this tool has a write grant but no tool grant, so the write grant cannot take effect. Fix: ask the administrator to allow this tool for this connection.",
|
|
15
|
+
prefixHeading: "EXTERNAL TOOL AVAILABILITY — read this before explaining a missing capability.",
|
|
16
|
+
prefixInstruction: "These tools were withheld when the assistant started. They are absent from `search_tools` and `describe_tool` and cannot be called. Explain the listed reason and fix without inventing another cause. This snapshot stays fixed until the assistant restarts.",
|
|
17
|
+
refusalBullet: ({ remoteName, connectionId, explanation }) => `- '${remoteName}' on external server '${connectionId}': ${explanation}`,
|
|
18
|
+
omittedRefusals: ({ omitted, total }) => `- …and ${omitted} more, for ${total} withheld in total. Ask the administrator for the complete admission report.`,
|
|
19
|
+
authenticationRefused: ({ method, status }) => `mcp-federation: the server refused '${method}' with ${status} — its authorization has expired or been revoked; ask the administrator to reconnect this connection`,
|
|
20
|
+
closedByHost: "closed by the host",
|
|
21
|
+
nativeCollision: ({ toolId }) => `mcp-federation: federated tool id '${toolId}' collides with a natively-registered tool — an external server must never be able to shadow the host's own catalog`,
|
|
22
|
+
launchUnavailable: ({ command }) => `This server's command "${command}" is unavailable. Ask the administrator to install or configure the required executable.`,
|
|
23
|
+
confirmationTitle: ({ request }) => `Run ${request.remoteName} on ${request.connectionLabel}?`,
|
|
24
|
+
confirmationWarning: ({ request }) => {
|
|
25
|
+
const base = request.destructive
|
|
26
|
+
? `${request.connectionLabel} marks this tool as destructive: it can delete or overwrite data, and that may not be undoable.`
|
|
27
|
+
: `This can change things in ${request.connectionLabel}.`;
|
|
28
|
+
return request.writeShapedInputs.length
|
|
29
|
+
? `${base} Its input ${request.writeShapedInputs.join(", ")} looks like it can change data, so the host asks every time.` : base;
|
|
30
|
+
},
|
|
31
|
+
confirmationDescription: "The assistant wants to run this with exactly the values below. Nothing runs until you allow it.",
|
|
32
|
+
serviceLabel: "Service", toolLabel: "Tool", argumentsLabel: "Arguments", noArguments: "(none)",
|
|
33
|
+
confirmLabel: "Allow", allowChatLabel: "Allow for this chat", allowAlwaysLabel: "Always allow",
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
export interface RemoteToolAnnotations {
|
|
2
|
+
readonly title?: string | undefined;
|
|
3
|
+
readonly readOnlyHint?: boolean | undefined;
|
|
4
|
+
readonly destructiveHint?: boolean | undefined;
|
|
5
|
+
readonly idempotentHint?: boolean | undefined;
|
|
6
|
+
readonly openWorldHint?: boolean | undefined;
|
|
7
|
+
}
|
|
8
|
+
/** One entry of a remote server's `tools/list` response. Every field is attacker-controlled. */
|
|
9
|
+
export interface RemoteToolDescriptor {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly description?: string | undefined;
|
|
12
|
+
/** JSON Schema, as published by the remote. `trust.ts` refuses any tool whose schema is not a
|
|
13
|
+
* JSON-Schema object — a schema-less tool is refused for federated tools for the same reason
|
|
14
|
+
* `buildDomainRegistrations` refuses one for native tools. */
|
|
15
|
+
readonly inputSchema?: unknown | undefined;
|
|
16
|
+
readonly annotations?: RemoteToolAnnotations | undefined;
|
|
17
|
+
}
|
|
18
|
+
/** One `tools/call` response. `isError` is the remote's own claim about its own outcome. */
|
|
19
|
+
export interface RemoteToolResult {
|
|
20
|
+
readonly content?: unknown | undefined;
|
|
21
|
+
readonly structuredContent?: unknown | undefined;
|
|
22
|
+
readonly isError?: boolean | undefined;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* An established MCP client session against one remote server.
|
|
26
|
+
*
|
|
27
|
+
* Intentionally three methods and no more: this is the entire surface federation needs. MCP's
|
|
28
|
+
* resources/prompts/sampling/roots are all deliberately out of scope — sampling in particular would
|
|
29
|
+
* let a remote server drive inference on host app's account, which is a far larger grant than "expose
|
|
30
|
+
* some tools" and is not something this pass builds a trust story for.
|
|
31
|
+
*/
|
|
32
|
+
export interface McpSessionPort {
|
|
33
|
+
/** The remote's advertised tool surface, already paginated to completion by the adapter. */
|
|
34
|
+
listTools(): Promise<RemoteToolDescriptor[]>;
|
|
35
|
+
callTool(request: McpToolCallRequiredArgs, options?: McpToolCallOptions): Promise<RemoteToolResult>;
|
|
36
|
+
close(required: Record<string, never>): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The byte-level seam under `adapter.stdio.ts`: a bidirectional stream of newline-delimited
|
|
40
|
+
* JSON-RPC 2.0 messages.
|
|
41
|
+
*
|
|
42
|
+
* Deliberately dumb — it knows about lines, not about MCP. All protocol knowledge (handshake
|
|
43
|
+
* ordering, id correlation, pagination, timeouts) lives in the adapter above it, which is what
|
|
44
|
+
* makes that knowledge testable without a child process.
|
|
45
|
+
*/
|
|
46
|
+
export interface McpStdioChannel {
|
|
47
|
+
/** Writes one JSON-RPC message. Implementations append the framing newline themselves. */
|
|
48
|
+
send({ message }: {
|
|
49
|
+
message: string;
|
|
50
|
+
}): void;
|
|
51
|
+
/** Registers the sink for inbound messages, one complete JSON value per call. */
|
|
52
|
+
onMessage({ listener }: {
|
|
53
|
+
listener: (required: {
|
|
54
|
+
message: string;
|
|
55
|
+
}) => void;
|
|
56
|
+
}): void;
|
|
57
|
+
/** Registers the sink for "this channel is gone" — process exit, stream error, explicit close. */
|
|
58
|
+
onClose({ listener }: {
|
|
59
|
+
listener: (required: {
|
|
60
|
+
reason: string;
|
|
61
|
+
}) => void;
|
|
62
|
+
}): void;
|
|
63
|
+
close(required: Record<string, never>): void;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* One site owner's configured federated connection.
|
|
67
|
+
*
|
|
68
|
+
* `allowedToolNames` is the load-bearing field and has NO safe default at this layer: an empty
|
|
69
|
+
* allowlist yields zero federated tools, which is the correct behaviour for a misconfigured
|
|
70
|
+
* connection. A DEFAULT is a per-vendor judgement and therefore belongs to a vendor preset, not
|
|
71
|
+
* here — an Agent Plugin's `mcp.json` `defaultTools` is the current example, authored from the
|
|
72
|
+
* server's real tool surface, which is what makes it an independent classification rather than a
|
|
73
|
+
* restatement of the remote's own claims.
|
|
74
|
+
*/
|
|
75
|
+
/**
|
|
76
|
+
* Where one connection's config came from — stamped once, at admission, and carried unchanged into
|
|
77
|
+
* every later `tools/call`. `external-mcp-revocation.ts`'s per-call gate is the one consumer: a
|
|
78
|
+
* preset gets only the legacy OAuth `needs_reauth` check (it has no roster row to compare against);
|
|
79
|
+
* a roster connection is re-checked against its CURRENT row every call, keyed by
|
|
80
|
+
* `admissionRevision` — see that file's `rosterRefusalFor`.
|
|
81
|
+
*/
|
|
82
|
+
export type FederatedConnectionOrigin = {
|
|
83
|
+
readonly kind: "preset";
|
|
84
|
+
} | {
|
|
85
|
+
readonly kind: "roster";
|
|
86
|
+
readonly admissionRevision: string;
|
|
87
|
+
};
|
|
88
|
+
export interface FederatedMcpConnectionConfig {
|
|
89
|
+
/** Operator-chosen, stable, `[a-z0-9-]`. Becomes part of every federated tool id, so renaming it
|
|
90
|
+
* renames every tool the model sees — pick once. */
|
|
91
|
+
readonly connectionId: string;
|
|
92
|
+
/** Human-readable, shown to the model as provenance on every federated tool description. */
|
|
93
|
+
readonly label: string;
|
|
94
|
+
/** DEFAULT-DENY allowlist of REMOTE tool names (pre-namespacing). */
|
|
95
|
+
readonly allowedToolNames: readonly string[];
|
|
96
|
+
/** Remote names reviewed in a bundled plugin's mcp.json, independent of admission grants.
|
|
97
|
+
* Remote readOnlyHint:false or destructiveHint:true vetoes each declaration. */
|
|
98
|
+
readonly readOnlyRemoteNames?: ReadonlySet<string> | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* SECOND list of REMOTE tool names (pre-namespacing) the operator has separately declared as
|
|
101
|
+
* writes. Kept for configuration compatibility and admission reports, independently of
|
|
102
|
+
* {@link allowedToolNames}. The allowlist alone gates admission; this list does not grant or
|
|
103
|
+
* refuse calls. Descriptor read-only classification and host permissions remain separate gates.
|
|
104
|
+
*
|
|
105
|
+
* Same "no safe default at this layer" rule as {@link allowedToolNames}: every connection that has
|
|
106
|
+
* never been told to allow a write must resolve to an empty list here, and a vendor preset that
|
|
107
|
+
* wants a non-empty default authors it itself, on purpose, the same way
|
|
108
|
+
* an Agent Plugin's `defaultTools.write` is authored rather than inherited from the remote.
|
|
109
|
+
*
|
|
110
|
+
* Destructive tools may be admitted from the allowlist, but protected actions still require
|
|
111
|
+
* per-call confirmation. Ordinary writes and absent annotations do not require a card. See
|
|
112
|
+
* `trust.ts` R3: hints cannot grant admission, and input names alone are not consent evidence.
|
|
113
|
+
*/
|
|
114
|
+
readonly writeAllowedToolNames: readonly string[];
|
|
115
|
+
/** How long the initialize+list handshake may take before federation is abandoned for this boot. */
|
|
116
|
+
readonly connectTimeoutMs: number;
|
|
117
|
+
/** Per-`tools/call` ceiling. */
|
|
118
|
+
readonly callTimeoutMs: number;
|
|
119
|
+
/** UTF-8 cap on the serialized text payload before wrapping, and separately on the aggregate
|
|
120
|
+
* serialized image array per result. Wrapper text is outside these two budgets. */
|
|
121
|
+
readonly maxResultBytes: number;
|
|
122
|
+
/** Hard cap on how many tools this connection may contribute, whatever the remote advertises. */
|
|
123
|
+
readonly maxTools: number;
|
|
124
|
+
/** Stamped by `bootstrap.ts` (presets, via `withPresetOrigin`) or `external-mcp-store.ts`'s
|
|
125
|
+
* `toResolvedFederatedConnections` (roster rows) — never by anything else. Optional only so a
|
|
126
|
+
* fixture predating this field still type-checks; `external-mcp-revocation.ts`'s gate treats a
|
|
127
|
+
* non-preset call with no origin as `unverifiable` rather than assuming either source. */
|
|
128
|
+
readonly origin?: FederatedConnectionOrigin | undefined;
|
|
129
|
+
}
|
|
130
|
+
/** One federated tool call's identity, as `mcp-federation/registrations.ts`'s handler hands it to
|
|
131
|
+
* `FederationDeps.assertConnectionUsable` — everything `external-mcp-revocation.ts`'s per-call gate
|
|
132
|
+
* needs to re-check an admitted tool against the connection's CURRENT row, without re-deriving any
|
|
133
|
+
* of it from the registry. Keys are required (may be `undefined`) rather than optional, so the
|
|
134
|
+
* shape is safe to build under `exactOptionalPropertyTypes`. */
|
|
135
|
+
export interface FederatedCallTarget {
|
|
136
|
+
/** The remote's own tool name (pre-namespacing) — what the operator's allowlist and write list
|
|
137
|
+
* name. */
|
|
138
|
+
readonly remoteName: string;
|
|
139
|
+
/** Exactly what was recorded at admission (`AdmittedFederatedTool.declaredAnnotations`) — never
|
|
140
|
+
* re-read from the remote on this path. */
|
|
141
|
+
readonly declaredAnnotations: RemoteToolDescriptor["annotations"] | undefined;
|
|
142
|
+
readonly origin: FederatedConnectionOrigin | undefined;
|
|
143
|
+
}
|
|
144
|
+
/** How a locally-launched federated connection is started.
|
|
145
|
+
*
|
|
146
|
+
* See {@link McpHttpLaunchSpec} for the hosted counterpart, and {@link McpLaunchSpec} for why the
|
|
147
|
+
* two are a union rather than one shape with optional halves. */
|
|
148
|
+
export interface McpStdioLaunchSpec {
|
|
149
|
+
readonly command: string;
|
|
150
|
+
readonly args: readonly string[];
|
|
151
|
+
/** Child-process-only environment. Secrets belong here and NOWHERE else — never in `args`, which
|
|
152
|
+
* are world-readable in `/proc/<pid>/cmdline` on Linux and in `ps` output everywhere. */
|
|
153
|
+
readonly env: Readonly<Record<string, string>>;
|
|
154
|
+
readonly cwd?: string | undefined;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* How a HOSTED federated connection is reached: one URL, plus the headers that authenticate to it.
|
|
158
|
+
*
|
|
159
|
+
* `headers` is where an OAuth access token arrives, as `Authorization: Bearer ...`, and it is the
|
|
160
|
+
* hosted analogue of {@link McpStdioLaunchSpec.env}'s "secrets belong here and NOWHERE else" rule —
|
|
161
|
+
* never in `url`, which is logged by proxies, kept in browser history when an operator pastes it,
|
|
162
|
+
* and stored in plaintext on the connection row.
|
|
163
|
+
*
|
|
164
|
+
* Deliberately a plain header bag rather than a token field: this layer should not know that OAuth
|
|
165
|
+
* exists. It is handed headers and sends them. Which credential produced them, whether it can be
|
|
166
|
+
* refreshed, and what to do when it expires are all `assistant/external-mcp-oauth.ts`'s questions,
|
|
167
|
+
* decided before a launch spec is ever built.
|
|
168
|
+
*/
|
|
169
|
+
export interface McpHttpLaunchSpec {
|
|
170
|
+
/** Absolute `https:` URL of the server's MCP endpoint (`http:` only for loopback — enforced at
|
|
171
|
+
* save time by `external-mcp-store.ts`, not here). */
|
|
172
|
+
readonly url: string;
|
|
173
|
+
/** Sent on every request to the endpoint. Carries the bearer token, when there is one. */
|
|
174
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* How a federated connection is reached, whichever transport it uses.
|
|
178
|
+
*
|
|
179
|
+
* A union rather than one struct with optional `command`/`url`, because the two are genuinely
|
|
180
|
+
* exclusive: a spec carrying both is not a degraded configuration to be tolerated, it is a bug, and
|
|
181
|
+
* a union makes that unrepresentable instead of a runtime check somebody has to remember to write.
|
|
182
|
+
*
|
|
183
|
+
* Narrow with {@link isHttpLaunchSpec}.
|
|
184
|
+
*/
|
|
185
|
+
export type McpLaunchSpec = McpStdioLaunchSpec | McpHttpLaunchSpec;
|
|
186
|
+
/** Narrows a {@link McpLaunchSpec} to its hosted arm. */
|
|
187
|
+
export declare function isHttpLaunchSpec(input: {
|
|
188
|
+
spec: McpLaunchSpec;
|
|
189
|
+
}): input is {
|
|
190
|
+
spec: McpHttpLaunchSpec;
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* The byte-level seam under `adapter.http.ts`, and the hosted counterpart to
|
|
194
|
+
* {@link McpStdioChannel}: one request/response exchange against the server's MCP endpoint.
|
|
195
|
+
*
|
|
196
|
+
* Deliberately narrower than `fetch`: a function that takes a body and returns a status, a content
|
|
197
|
+
* type, a couple of named headers, and text. That is everything the Streamable HTTP transport
|
|
198
|
+
* needs, and shrinking the seam is what lets the adapter's real protocol behaviour — handshake
|
|
199
|
+
* ordering, session-id propagation, SSE framing, pagination, error mapping — be tested against a
|
|
200
|
+
* scripted double instead of a live server, exactly as the stdio adapter's channel seam does.
|
|
201
|
+
*/
|
|
202
|
+
export interface McpHttpExchange {
|
|
203
|
+
send(request: McpHttpRequestRequiredArgs, options?: McpHttpRequestOptions): Promise<McpHttpResponse>;
|
|
204
|
+
}
|
|
205
|
+
/** One response from an {@link McpHttpExchange}. */
|
|
206
|
+
export interface McpHttpResponse {
|
|
207
|
+
readonly status: number;
|
|
208
|
+
/** Lowercased `content-type`, value only — parameters such as `; charset=utf-8` may be present
|
|
209
|
+
* and the adapter matches on the prefix. */
|
|
210
|
+
readonly contentType: string;
|
|
211
|
+
/** The server's `Mcp-Session-Id`, when it issued one. */
|
|
212
|
+
readonly sessionId?: string | undefined;
|
|
213
|
+
/** The full body. Bounded by the adapter's own cap before it is parsed. */
|
|
214
|
+
readonly text: string;
|
|
215
|
+
readonly wwwAuthenticate?: string | undefined;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* What a per-call confirmation card (G3, `trust.ts` R3) is asked to show, as
|
|
219
|
+
* `mcp-federation/registrations.ts`'s handler hands it to `FederationDeps.confirmCall`.
|
|
220
|
+
*
|
|
221
|
+
* `arguments` is the exact, already-frozen object that will be sent on Confirm — the handler builds it
|
|
222
|
+
* once, before the card is drawn, and sends that same object afterwards, so the card can never show
|
|
223
|
+
* one thing while the remote receives another.
|
|
224
|
+
*/
|
|
225
|
+
export interface FederatedCallConfirmationRequest {
|
|
226
|
+
/** The namespaced registry id (`mcp__<connection>__<name>`) — the card's clicks are routed back to it. */
|
|
227
|
+
readonly toolId: string;
|
|
228
|
+
readonly remoteName: string;
|
|
229
|
+
readonly connectionId: string;
|
|
230
|
+
/** The operator's label for the connection, e.g. "Supabase" — the "target" the card names. */
|
|
231
|
+
readonly connectionLabel: string;
|
|
232
|
+
readonly arguments: Readonly<Record<string, unknown>>;
|
|
233
|
+
/** The remote declared `destructiveHint: true` — the card carries the stronger, danger-styled warning. */
|
|
234
|
+
readonly destructive: boolean;
|
|
235
|
+
/**
|
|
236
|
+
* The hints recorded when the tool was admitted, and where its connection came from — the tool
|
|
237
|
+
* identity a remembered approval ("Allow for this chat", "Always allow") is pinned to
|
|
238
|
+
* (`assistant/external-mcp-tool-approvals.ts`), so a changed server, name or hints asks again.
|
|
239
|
+
*/
|
|
240
|
+
readonly declaredAnnotations: RemoteToolDescriptor["annotations"] | undefined;
|
|
241
|
+
readonly origin: FederatedConnectionOrigin | undefined;
|
|
242
|
+
/** The description the model reads (`AdmittedFederatedTool.description`) and the input schema, as
|
|
243
|
+
* admitted — also part of that identity, so a drifted description or schema asks again. */
|
|
244
|
+
readonly description: string;
|
|
245
|
+
readonly inputSchema: Readonly<Record<string, unknown>>;
|
|
246
|
+
/**
|
|
247
|
+
* Input names, in the schema or in this call's arguments, that look like writes (`trust.ts`
|
|
248
|
+
* `WRITE_SHAPED_INPUT_WORDS`), sorted. These names describe an already-required protected-action
|
|
249
|
+
* card; names alone do not require one. On such a card, non-empty names disable remembered
|
|
250
|
+
* approval so the person reviews the actual input for that call.
|
|
251
|
+
*/
|
|
252
|
+
readonly writeShapedInputs: readonly string[];
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* The human's answer. Only an explicit Confirm is `{ confirmed: true }`; anything else carries the
|
|
256
|
+
* model-facing result that replaces the call (cancelled, expired, or the run ended).
|
|
257
|
+
*/
|
|
258
|
+
export type FederatedCallConfirmationOutcome = {
|
|
259
|
+
readonly confirmed: true;
|
|
260
|
+
} | {
|
|
261
|
+
readonly confirmed: false;
|
|
262
|
+
readonly result: Readonly<Record<string, unknown>>;
|
|
263
|
+
};
|
|
264
|
+
/** Host identity sent during initialization; there is no product default. */
|
|
265
|
+
export interface McpClientInfo {
|
|
266
|
+
readonly name: string;
|
|
267
|
+
readonly version: string;
|
|
268
|
+
}
|
|
269
|
+
export type RemoteToolDescriptorAnnotations = RemoteToolDescriptor["annotations"];
|
|
270
|
+
/** Required wire payload and optional per-call cancellation. */
|
|
271
|
+
export interface McpToolCallRequiredArgs {
|
|
272
|
+
readonly name: string;
|
|
273
|
+
readonly arguments: Record<string, unknown>;
|
|
274
|
+
}
|
|
275
|
+
export interface McpToolCallOptions {
|
|
276
|
+
readonly signal?: AbortSignal | undefined;
|
|
277
|
+
}
|
|
278
|
+
export interface McpHttpRequestRequiredArgs {
|
|
279
|
+
readonly url: string;
|
|
280
|
+
readonly method: "POST" | "DELETE";
|
|
281
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
282
|
+
}
|
|
283
|
+
export interface McpHttpRequestOptions {
|
|
284
|
+
readonly body?: string | undefined;
|
|
285
|
+
readonly signal?: AbortSignal | undefined;
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=ports.d.ts.map
|