@novorb/mcp-core 2.1.1 → 3.0.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/README.md +82 -161
- package/bin/mcp-core-jest.mjs +112 -0
- package/dist/auth.d.ts +57 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +74 -0
- package/dist/auth.js.map +1 -0
- package/dist/bootstrap.d.ts +129 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +206 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/client-input.d.ts +72 -0
- package/dist/client-input.d.ts.map +1 -0
- package/dist/client-input.js +109 -0
- package/dist/client-input.js.map +1 -0
- package/dist/credential-checks.d.ts +80 -0
- package/dist/credential-checks.d.ts.map +1 -0
- package/dist/credential-checks.js +189 -0
- package/dist/credential-checks.js.map +1 -0
- package/dist/credential-health.d.ts +12 -0
- package/dist/credential-health.d.ts.map +1 -0
- package/dist/credential-health.js +12 -0
- package/dist/credential-health.js.map +1 -0
- package/dist/credential-report.d.ts +46 -0
- package/dist/credential-report.d.ts.map +1 -0
- package/dist/credential-report.js +135 -0
- package/dist/credential-report.js.map +1 -0
- package/dist/credential-status-tool.d.ts +20 -0
- package/dist/credential-status-tool.d.ts.map +1 -0
- package/dist/credential-status-tool.js +33 -0
- package/dist/credential-status-tool.js.map +1 -0
- package/dist/credentials.d.ts +288 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +652 -0
- package/dist/credentials.js.map +1 -0
- package/dist/express-peers.d.ts +29 -0
- package/dist/express-peers.d.ts.map +1 -0
- package/dist/express-peers.js +36 -0
- package/dist/express-peers.js.map +1 -0
- package/dist/express.d.ts +74 -0
- package/dist/express.d.ts.map +1 -0
- package/dist/express.js +164 -0
- package/dist/express.js.map +1 -0
- package/dist/http-client.d.ts +278 -43
- package/dist/http-client.d.ts.map +1 -1
- package/dist/http-client.js +620 -182
- package/dist/http-client.js.map +1 -1
- package/dist/index.d.ts +27 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -10
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +28 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +37 -0
- package/dist/limits.js.map +1 -0
- package/dist/list-pagination.d.ts +41 -0
- package/dist/list-pagination.d.ts.map +1 -0
- package/dist/list-pagination.js +104 -0
- package/dist/list-pagination.js.map +1 -0
- package/dist/net.d.ts +112 -0
- package/dist/net.d.ts.map +1 -0
- package/dist/net.js +490 -0
- package/dist/net.js.map +1 -0
- package/dist/notifications.d.ts +78 -0
- package/dist/notifications.d.ts.map +1 -0
- package/dist/notifications.js +173 -0
- package/dist/notifications.js.map +1 -0
- package/dist/pagination.d.ts +236 -5
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +393 -6
- package/dist/pagination.js.map +1 -1
- package/dist/prompts.d.ts +70 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +109 -0
- package/dist/prompts.js.map +1 -0
- package/dist/protocol-errors.d.ts +15 -0
- package/dist/protocol-errors.d.ts.map +1 -0
- package/dist/protocol-errors.js +28 -0
- package/dist/protocol-errors.js.map +1 -0
- package/dist/protocol-logging.d.ts +37 -0
- package/dist/protocol-logging.d.ts.map +1 -0
- package/dist/protocol-logging.js +77 -0
- package/dist/protocol-logging.js.map +1 -0
- package/dist/rate-limiter.d.ts +36 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +79 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/request-state.d.ts +74 -0
- package/dist/request-state.d.ts.map +1 -0
- package/dist/request-state.js +190 -0
- package/dist/request-state.js.map +1 -0
- package/dist/resources.d.ts +181 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +302 -0
- package/dist/resources.js.map +1 -0
- package/dist/result-limits.d.ts +80 -0
- package/dist/result-limits.d.ts.map +1 -0
- package/dist/result-limits.js +248 -0
- package/dist/result-limits.js.map +1 -0
- package/dist/retry.d.ts +79 -23
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +170 -57
- package/dist/retry.js.map +1 -1
- package/dist/sdk/client-stdio.d.ts +6 -0
- package/dist/sdk/client-stdio.d.ts.map +1 -0
- package/dist/sdk/client-stdio.js +6 -0
- package/dist/sdk/client-stdio.js.map +1 -0
- package/dist/sdk/client.d.ts +6 -0
- package/dist/sdk/client.d.ts.map +1 -0
- package/dist/sdk/client.js +6 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/sdk/express.d.ts +3 -0
- package/dist/sdk/express.d.ts.map +1 -0
- package/dist/sdk/express.js +11 -0
- package/dist/sdk/express.js.map +1 -0
- package/dist/sdk/node.d.ts +6 -0
- package/dist/sdk/node.d.ts.map +1 -0
- package/dist/sdk/node.js +6 -0
- package/dist/sdk/node.js.map +1 -0
- package/dist/sdk/server-stdio.d.ts +6 -0
- package/dist/sdk/server-stdio.d.ts.map +1 -0
- package/dist/sdk/server-stdio.js +6 -0
- package/dist/sdk/server-stdio.js.map +1 -0
- package/dist/sdk/server.d.ts +6 -0
- package/dist/sdk/server.d.ts.map +1 -0
- package/dist/sdk/server.js +6 -0
- package/dist/sdk/server.js.map +1 -0
- package/dist/server.d.ts +88 -36
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +98 -44
- package/dist/server.js.map +1 -1
- package/dist/task-request.d.ts +20 -0
- package/dist/task-request.d.ts.map +1 -0
- package/dist/task-request.js +43 -0
- package/dist/task-request.js.map +1 -0
- package/dist/task-store.d.ts +230 -0
- package/dist/task-store.d.ts.map +1 -0
- package/dist/task-store.js +459 -0
- package/dist/task-store.js.map +1 -0
- package/dist/task-tools.d.ts +115 -0
- package/dist/task-tools.d.ts.map +1 -0
- package/dist/task-tools.js +397 -0
- package/dist/task-tools.js.map +1 -0
- package/dist/testing/client.d.ts +25 -0
- package/dist/testing/client.d.ts.map +1 -0
- package/dist/testing/client.js +11 -0
- package/dist/testing/client.js.map +1 -0
- package/dist/testing/in-memory.d.ts +26 -0
- package/dist/testing/in-memory.d.ts.map +1 -0
- package/dist/testing/in-memory.js +41 -0
- package/dist/testing/in-memory.js.map +1 -0
- package/dist/testing/index.d.ts +20 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +20 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/isolated-dirs.d.ts +27 -0
- package/dist/testing/isolated-dirs.d.ts.map +1 -0
- package/dist/testing/isolated-dirs.js +67 -0
- package/dist/testing/isolated-dirs.js.map +1 -0
- package/dist/testing/logs.d.ts +61 -0
- package/dist/testing/logs.d.ts.map +1 -0
- package/dist/testing/logs.js +113 -0
- package/dist/testing/logs.js.map +1 -0
- package/dist/testing/raw-http.d.ts +25 -0
- package/dist/testing/raw-http.d.ts.map +1 -0
- package/dist/testing/raw-http.js +41 -0
- package/dist/testing/raw-http.js.map +1 -0
- package/dist/testing/raw-peer.d.ts +43 -0
- package/dist/testing/raw-peer.d.ts.map +1 -0
- package/dist/testing/raw-peer.js +101 -0
- package/dist/testing/raw-peer.js.map +1 -0
- package/dist/testing/recording-server.d.ts +38 -0
- package/dist/testing/recording-server.d.ts.map +1 -0
- package/dist/testing/recording-server.js +38 -0
- package/dist/testing/recording-server.js.map +1 -0
- package/dist/testing/server-process.d.ts +76 -0
- package/dist/testing/server-process.d.ts.map +1 -0
- package/dist/testing/server-process.js +241 -0
- package/dist/testing/server-process.js.map +1 -0
- package/dist/testing/tools.d.ts +53 -0
- package/dist/testing/tools.d.ts.map +1 -0
- package/dist/testing/tools.js +98 -0
- package/dist/testing/tools.js.map +1 -0
- package/dist/testing/unit.d.ts +52 -0
- package/dist/testing/unit.d.ts.map +1 -0
- package/dist/testing/unit.js +95 -0
- package/dist/testing/unit.js.map +1 -0
- package/dist/tools.d.ts +205 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +370 -0
- package/dist/tools.js.map +1 -0
- package/dist/transport.d.ts +144 -53
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +305 -122
- package/dist/transport.js.map +1 -1
- package/dist/url-path.d.ts +49 -0
- package/dist/url-path.d.ts.map +1 -0
- package/dist/url-path.js +165 -0
- package/dist/url-path.js.map +1 -0
- package/dist/utils/dataStore.d.ts +143 -0
- package/dist/utils/dataStore.d.ts.map +1 -0
- package/dist/utils/dataStore.js +429 -0
- package/dist/utils/dataStore.js.map +1 -0
- package/dist/utils/envLoader.d.ts +129 -0
- package/dist/utils/envLoader.d.ts.map +1 -0
- package/dist/utils/envLoader.js +399 -0
- package/dist/utils/envLoader.js.map +1 -0
- package/dist/utils/logger.d.ts +181 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +664 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/redact.d.ts +50 -0
- package/dist/utils/redact.d.ts.map +1 -0
- package/dist/utils/redact.js +318 -0
- package/dist/utils/redact.js.map +1 -0
- package/docs/api-reference.md +29 -0
- package/docs/building-a-server.md +63 -0
- package/docs/credentials.md +131 -0
- package/docs/data-store.md +37 -0
- package/docs/env.md +38 -0
- package/docs/features.md +28 -0
- package/docs/http-client.md +116 -0
- package/docs/logger.md +100 -0
- package/docs/migrating-to-v3.md +45 -0
- package/docs/outbound-urls.md +104 -0
- package/docs/pagination.md +45 -0
- package/docs/protocol-features.md +62 -0
- package/docs/resources-prompts-tasks.md +95 -0
- package/docs/sdk.md +33 -0
- package/docs/server.md +68 -0
- package/docs/testing-harness.md +139 -0
- package/docs/testing.md +151 -0
- package/docs/tools.md +88 -0
- package/docs/transport.md +85 -0
- package/examples/testing/tools.integration.test.example.ts +312 -0
- package/examples/testing/tools.unit.test.example.ts +149 -0
- package/package.json +140 -18
- package/dist/logger.d.ts +0 -80
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -236
- package/dist/logger.js.map +0 -1
package/dist/tools.js
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @novorb/mcp-core - Tools
|
|
3
|
+
*
|
|
4
|
+
* Register a server's tool definitions on an SDK v2 `McpServer` through `McpServer.registerTool`, so
|
|
5
|
+
* the SDK keeps doing what it does (tools/list from the schemas, input validation, output validation
|
|
6
|
+
* with the era projection, unknown tool = ProtocolError -32602) and mcp-core adds only what it lacks:
|
|
7
|
+
*
|
|
8
|
+
* - one central wrapper per tool: `logToolCall` / `logToolResult` with the duration (shape only,
|
|
9
|
+
* never values);
|
|
10
|
+
* - thrown errors become an `isError` result through `mapError` (default: a safe message, never a
|
|
11
|
+
* stack trace, never a raw error object); a thrown schema error (zod / Standard Schema issues) names
|
|
12
|
+
* the offending fields;
|
|
13
|
+
* - a returned legacy `{ success: false, error }` envelope becomes `isError: true`;
|
|
14
|
+
* - degraded mode: a tool whose `requires` env keys are not configured is still LISTED and answers one
|
|
15
|
+
* uniform error, `<server> is not configured: set <KEYS>`;
|
|
16
|
+
* - `enabled` filters what is registered at all.
|
|
17
|
+
*
|
|
18
|
+
* registerTools(server, [
|
|
19
|
+
* {
|
|
20
|
+
* name: 'lookup',
|
|
21
|
+
* description: 'Look up a value',
|
|
22
|
+
* inputSchema: z.object({ key: z.string() }),
|
|
23
|
+
* annotations: TOOL_ANNOTATIONS.readOnly,
|
|
24
|
+
* requires: ['API_TOKEN'],
|
|
25
|
+
* handler: async ({ key }, ctx) => toolResult(await client.get(key, { signal: ctx.signal })),
|
|
26
|
+
* },
|
|
27
|
+
* ], { env, serverName: 'my-mcp' });
|
|
28
|
+
*/
|
|
29
|
+
import { CLIENT_CAPABILITIES_META_KEY, inputRequired, isInputRequiredResult, ProtocolError, ProtocolErrorCode, } from '@modelcontextprotocol/server';
|
|
30
|
+
import { createClientInput, requestEra } from './client-input.js';
|
|
31
|
+
import { attachCredentialMeta, attachCredentialReport, credentialReportBytes, withCredentialsField, } from './credential-report.js';
|
|
32
|
+
import { CredentialScope, NoUsableCredentialError, processCredentials, runWithCredentialScope, } from './credentials.js';
|
|
33
|
+
import { resolveLimits } from './limits.js';
|
|
34
|
+
import { bindToSurface } from './notifications.js';
|
|
35
|
+
import { InvalidCursorError, invalidCursorResult } from './pagination.js';
|
|
36
|
+
import { runWithRequestContext } from './protocol-logging.js';
|
|
37
|
+
import { RequestStateKeyError } from './request-state.js';
|
|
38
|
+
import { declaresPageArgs, decodeToolCursor, enforceResultLimits, handlerArgs, } from './result-limits.js';
|
|
39
|
+
import { requestStateCodecOf } from './server.js';
|
|
40
|
+
import { InvalidPathSegmentError } from './url-path.js';
|
|
41
|
+
import { getLogger, logToolCall, logToolResult, maskSecretValues } from './utils/logger.js';
|
|
42
|
+
import { redactStringSecrets } from './utils/redact.js';
|
|
43
|
+
/** Identity helper that types a definition's handler arguments from its own input schema. */
|
|
44
|
+
export function defineTool(definition) {
|
|
45
|
+
return definition;
|
|
46
|
+
}
|
|
47
|
+
const LIMIT_KEYS = [
|
|
48
|
+
'MCP_LIST_PAGE_SIZE',
|
|
49
|
+
'MCP_MAX_RESULT_ITEMS',
|
|
50
|
+
'MCP_MAX_RESULT_BYTES',
|
|
51
|
+
'MCP_MAX_TOOL_INPUT_ELEMENTS',
|
|
52
|
+
];
|
|
53
|
+
/** The response-limit keys as read through the loaded env (env file and defaults included). */
|
|
54
|
+
function limitsEnv(env) {
|
|
55
|
+
const out = {};
|
|
56
|
+
for (const key of LIMIT_KEYS)
|
|
57
|
+
out[key] = env.get(key);
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
function isPlainObject(value) {
|
|
61
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A success result: the text block is `opts.text`, the string itself, or pretty JSON; a plain object
|
|
65
|
+
* is also sent as `structuredContent` (the spec requires an object there).
|
|
66
|
+
*/
|
|
67
|
+
export function toolResult(data, opts = {}) {
|
|
68
|
+
const text = opts.text ?? (typeof data === 'string' ? data : (JSON.stringify(data, null, 2) ?? String(data)));
|
|
69
|
+
const result = { content: [{ type: 'text', text }] };
|
|
70
|
+
if (isPlainObject(data))
|
|
71
|
+
result.structuredContent = data;
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Text bound for a client in an error: secret query/userinfo/Basic parameters redacted and every
|
|
76
|
+
* registered secret value masked, exactly as the logger does for its lines.
|
|
77
|
+
*/
|
|
78
|
+
export function maskClientText(text) {
|
|
79
|
+
return maskSecretValues(redactStringSecrets(text));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* An error result (`isError: true`): the message as text, optional details as a second JSON block.
|
|
83
|
+
* Both are passed through `maskClientText`.
|
|
84
|
+
*/
|
|
85
|
+
export function toolError(message, details) {
|
|
86
|
+
const content = [{ type: 'text', text: maskClientText(message) }];
|
|
87
|
+
if (details !== undefined)
|
|
88
|
+
content.push({ type: 'text', text: maskClientText(JSON.stringify(details, null, 2)) });
|
|
89
|
+
return { content, isError: true };
|
|
90
|
+
}
|
|
91
|
+
/** Mask every text block of an error result (whatever produced it). */
|
|
92
|
+
function maskErrorResult(result) {
|
|
93
|
+
if (result.isError !== true)
|
|
94
|
+
return result;
|
|
95
|
+
return {
|
|
96
|
+
...result,
|
|
97
|
+
content: result.content.map((block) => block.type === 'text' ? { ...block, text: maskClientText(block.text) } : block),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function schemaIssues(err) {
|
|
101
|
+
if (!isPlainObject(err) && !(err instanceof Error))
|
|
102
|
+
return undefined;
|
|
103
|
+
const issues = err.issues;
|
|
104
|
+
if (!Array.isArray(issues) || issues.length === 0)
|
|
105
|
+
return undefined;
|
|
106
|
+
if (!issues.every((i) => isPlainObject(i) && typeof i.message === 'string'))
|
|
107
|
+
return undefined;
|
|
108
|
+
return issues;
|
|
109
|
+
}
|
|
110
|
+
function issuePath(issue) {
|
|
111
|
+
const parts = (issue.path ?? []).map((p) => String(typeof p === 'object' && p !== null ? p.key : p));
|
|
112
|
+
return parts.join('.');
|
|
113
|
+
}
|
|
114
|
+
/** "Invalid arguments: a.b: msg; c: msg" for a thrown zod / Standard Schema error. */
|
|
115
|
+
function formatIssues(issues) {
|
|
116
|
+
return `Invalid arguments: ${issues
|
|
117
|
+
.map((i) => {
|
|
118
|
+
const p = issuePath(i);
|
|
119
|
+
return p ? `${p}: ${i.message}` : i.message;
|
|
120
|
+
})
|
|
121
|
+
.join('; ')}`;
|
|
122
|
+
}
|
|
123
|
+
const MAX_ERROR_MESSAGE = 2000;
|
|
124
|
+
/** The default `mapError`: the error message only (secret parameters redacted, bounded), never a stack. */
|
|
125
|
+
export function defaultMapError(err) {
|
|
126
|
+
let message;
|
|
127
|
+
if (err instanceof Error)
|
|
128
|
+
message = err.message || err.name;
|
|
129
|
+
else if (typeof err === 'string')
|
|
130
|
+
message = err;
|
|
131
|
+
else
|
|
132
|
+
message = 'Internal error';
|
|
133
|
+
message = maskClientText(message).replace(/[\r\n]+/g, ' ');
|
|
134
|
+
if (message.length > MAX_ERROR_MESSAGE)
|
|
135
|
+
message = `${message.slice(0, MAX_ERROR_MESSAGE)}...`;
|
|
136
|
+
return { message: message || 'Internal error' };
|
|
137
|
+
}
|
|
138
|
+
function isCallToolResult(value) {
|
|
139
|
+
return isPlainObject(value) && Array.isArray(value.content);
|
|
140
|
+
}
|
|
141
|
+
function isLegacyEnvelope(value) {
|
|
142
|
+
return isPlainObject(value) && typeof value.success === 'boolean';
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Map a handler's return value onto a CallToolResult. An SDK input-required result
|
|
146
|
+
* (`resultType: 'input_required'`) is returned untouched: the SDK owns it (it skips output validation
|
|
147
|
+
* for it and drives the multi-round-trip flow, or the 2025 legacy shim).
|
|
148
|
+
*/
|
|
149
|
+
export function normalizeOutcome(outcome, hasOutputSchema = false) {
|
|
150
|
+
if (isInputRequiredResult(outcome))
|
|
151
|
+
return outcome;
|
|
152
|
+
if (isCallToolResult(outcome))
|
|
153
|
+
return outcome;
|
|
154
|
+
if (isLegacyEnvelope(outcome)) {
|
|
155
|
+
const text = JSON.stringify(outcome, null, 2);
|
|
156
|
+
if (!outcome.success)
|
|
157
|
+
return { content: [{ type: 'text', text }], isError: true };
|
|
158
|
+
const result = { content: [{ type: 'text', text }] };
|
|
159
|
+
if (hasOutputSchema && isPlainObject(outcome.data))
|
|
160
|
+
result.structuredContent = outcome.data;
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
return toolResult(outcome);
|
|
164
|
+
}
|
|
165
|
+
/** The uniform degraded-mode message. */
|
|
166
|
+
export function notConfiguredMessage(serverName, missing) {
|
|
167
|
+
return `${serverName} is not configured: set ${missing.join(', ')}`;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The client's declared capabilities for this request, read the way the SDK's own input-required gate
|
|
171
|
+
* reads them: the request's `_meta` envelope on 2026-07-28 requests, the `initialize`-scoped value on a
|
|
172
|
+
* 2025-era connection (`getClientCapabilities()`, deprecated in favour of the envelope but functional).
|
|
173
|
+
*/
|
|
174
|
+
function clientCapabilitiesOf(server, sdk) {
|
|
175
|
+
if (!sdk)
|
|
176
|
+
return undefined;
|
|
177
|
+
const envelope = sdk.mcpReq.envelope;
|
|
178
|
+
const fromEnvelope = envelope?.[CLIENT_CAPABILITIES_META_KEY];
|
|
179
|
+
return fromEnvelope ?? server.server.getClientCapabilities();
|
|
180
|
+
}
|
|
181
|
+
function contextFor(server, tool, args, sdk, credentials) {
|
|
182
|
+
const cursor = isPlainObject(args) && typeof args.cursor === 'string' && args.cursor !== '' ? args.cursor : undefined;
|
|
183
|
+
const progressToken = sdk?.mcpReq._meta?.progressToken;
|
|
184
|
+
const clientCapabilities = clientCapabilitiesOf(server, sdk);
|
|
185
|
+
const signal = sdk?.mcpReq.signal ?? new AbortController().signal;
|
|
186
|
+
const codec = requestStateCodecOf(server);
|
|
187
|
+
return {
|
|
188
|
+
requestState: () => (codec && sdk ? sdk.mcpReq.requestState() : undefined),
|
|
189
|
+
continueWith: async (state, inputRequests) => {
|
|
190
|
+
if (!codec) {
|
|
191
|
+
throw new RequestStateKeyError('requestState is not configured on this server: set MCP_REQUEST_STATE_KEY and pass requestStateCodec to createMcpServer');
|
|
192
|
+
}
|
|
193
|
+
if (!sdk)
|
|
194
|
+
throw new Error('continueWith needs the SDK request context');
|
|
195
|
+
const requestState = await codec.mint(state, sdk);
|
|
196
|
+
return inputRequired({ ...(inputRequests !== undefined ? { inputRequests } : {}), requestState });
|
|
197
|
+
},
|
|
198
|
+
tool,
|
|
199
|
+
signal,
|
|
200
|
+
authInfo: sdk?.http?.authInfo,
|
|
201
|
+
cursor,
|
|
202
|
+
...(sdk ? { era: requestEra(sdk) } : {}),
|
|
203
|
+
...(clientCapabilities !== undefined ? { clientCapabilities } : {}),
|
|
204
|
+
logger: getLogger(),
|
|
205
|
+
credentials,
|
|
206
|
+
sdk,
|
|
207
|
+
...createClientInput(sdk, clientCapabilities),
|
|
208
|
+
progress: async (progress, total, message) => {
|
|
209
|
+
if (!sdk || progressToken === undefined || signal.aborted)
|
|
210
|
+
return;
|
|
211
|
+
try {
|
|
212
|
+
await sdk.mcpReq.notify({
|
|
213
|
+
method: 'notifications/progress',
|
|
214
|
+
params: {
|
|
215
|
+
progressToken,
|
|
216
|
+
progress,
|
|
217
|
+
...(total !== undefined ? { total } : {}),
|
|
218
|
+
...(message !== undefined ? { message } : {}),
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// A lost progress notification never fails the tool.
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
/** The SDK rethrows exactly this protocol error from its tools/call handler; so must the wrapper. */
|
|
229
|
+
function isRethrownProtocolError(err) {
|
|
230
|
+
return ProtocolError.isInstance(err) && err.code === ProtocolErrorCode.UrlElicitationRequired;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Register `tools` on `server` with `McpServer.registerTool`. Returns the SDK handles by registered
|
|
234
|
+
* name (for `disable()` / `enable()` / `remove()`).
|
|
235
|
+
*/
|
|
236
|
+
export function registerTools(server, tools, opts = {}) {
|
|
237
|
+
const handles = new Map();
|
|
238
|
+
const enabled = opts.enabled ? new Set(opts.enabled) : undefined;
|
|
239
|
+
const mapError = opts.mapError ?? defaultMapError;
|
|
240
|
+
const serverName = opts.serverName ?? 'this server';
|
|
241
|
+
const prefix = opts.prefix ?? '';
|
|
242
|
+
const serverLimits = opts.limits ?? {};
|
|
243
|
+
const registry = opts.credentials ?? processCredentials();
|
|
244
|
+
const valueFor = (key) => opts.env?.get(key);
|
|
245
|
+
for (const tool of tools) {
|
|
246
|
+
if (enabled && !enabled.has(tool.name))
|
|
247
|
+
continue;
|
|
248
|
+
const name = `${prefix}${tool.name}`;
|
|
249
|
+
const requires = tool.requires ?? [];
|
|
250
|
+
if (requires.length > 0 && !opts.env) {
|
|
251
|
+
throw new Error(`registerTools: tool ${name} declares requires but no env was passed`);
|
|
252
|
+
}
|
|
253
|
+
const declared = new Set(opts.env?.schema.map((s) => s.key));
|
|
254
|
+
const undeclared = requires.filter((k) => !declared.has(k));
|
|
255
|
+
if (undeclared.length > 0) {
|
|
256
|
+
throw new Error(`registerTools: tool ${name} requires ${undeclared.join(', ')}, which the env schema does not declare`);
|
|
257
|
+
}
|
|
258
|
+
if (tool.paginated && !declaresPageArgs(tool.inputSchema)) {
|
|
259
|
+
throw new Error(`registerTools: paginated tool ${name} must declare cursor and limit in its input schema`);
|
|
260
|
+
}
|
|
261
|
+
const limits = resolveLimits({
|
|
262
|
+
...(serverLimits.maxItems !== undefined ? { maxResultItems: serverLimits.maxItems } : {}),
|
|
263
|
+
...(serverLimits.maxBytes !== undefined ? { maxResultBytes: serverLimits.maxBytes } : {}),
|
|
264
|
+
...(tool.limits?.maxItems !== undefined ? { maxResultItems: tool.limits.maxItems } : {}),
|
|
265
|
+
...(tool.limits?.maxBytes !== undefined ? { maxResultBytes: tool.limits.maxBytes } : {}),
|
|
266
|
+
}, opts.env ? limitsEnv(opts.env) : process.env);
|
|
267
|
+
const outputSchema = tool.outputSchema !== undefined ? withCredentialsField(tool.outputSchema) : undefined;
|
|
268
|
+
const reportStructured = outputSchema !== undefined && outputSchema !== tool.outputSchema;
|
|
269
|
+
const execute = async (args, sdk, credentials) => {
|
|
270
|
+
const started = Date.now();
|
|
271
|
+
logToolCall(name, args);
|
|
272
|
+
let result;
|
|
273
|
+
let decoded;
|
|
274
|
+
try {
|
|
275
|
+
const missing = requires.filter((k) => !opts.env?.has(k));
|
|
276
|
+
const cursor = isPlainObject(args) && typeof args.cursor === 'string' ? args.cursor : undefined;
|
|
277
|
+
if (cursor !== undefined)
|
|
278
|
+
decoded = decodeToolCursor(name, args, cursor, tool.paginated === true);
|
|
279
|
+
if (missing.length > 0) {
|
|
280
|
+
result = toolError(notConfiguredMessage(serverName, missing));
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
const callArgs = handlerArgs(args, decoded, limits.maxResultItems);
|
|
284
|
+
const outcome = await tool.handler(callArgs, contextFor(server, name, callArgs, sdk, credentials));
|
|
285
|
+
result = normalizeOutcome(outcome, tool.outputSchema !== undefined);
|
|
286
|
+
if (!isInputRequiredResult(result))
|
|
287
|
+
result = maskErrorResult(result);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
if (err instanceof InvalidCursorError) {
|
|
292
|
+
result = invalidCursorResult(err);
|
|
293
|
+
logToolResult(name, { isError: true, durationMs: Date.now() - started });
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
296
|
+
if (isRethrownProtocolError(err)) {
|
|
297
|
+
logToolResult(name, { isError: true, durationMs: Date.now() - started });
|
|
298
|
+
throw err;
|
|
299
|
+
}
|
|
300
|
+
const issues = schemaIssues(err);
|
|
301
|
+
if (err instanceof NoUsableCredentialError) {
|
|
302
|
+
result = toolError(`${serverName} cannot serve ${name}: ${err.message}. Replace or renew the key(s), or wait for a degraded one to recover.`);
|
|
303
|
+
}
|
|
304
|
+
else if (err instanceof InvalidPathSegmentError) {
|
|
305
|
+
// Actionable whatever the server's mapError does; the message names the argument, never the value.
|
|
306
|
+
result = toolError(err.message);
|
|
307
|
+
}
|
|
308
|
+
else if (issues) {
|
|
309
|
+
result = toolError(formatIssues(issues));
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
let mapped;
|
|
313
|
+
try {
|
|
314
|
+
mapped = mapError(err);
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
mapped = { message: 'Internal error' };
|
|
318
|
+
}
|
|
319
|
+
result = toolError(mapped.code ? `${mapped.code}: ${mapped.message}` : mapped.message);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// The report's own bytes count against the byte cap, so the final result stays under it.
|
|
323
|
+
const report = credentials.touchedAny ? credentials.report() : [];
|
|
324
|
+
if (isInputRequiredResult(result)) {
|
|
325
|
+
result = attachCredentialMeta(result, report, maskClientText);
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
const reportBytes = credentialReportBytes(report, reportStructured);
|
|
329
|
+
result = enforceResultLimits({
|
|
330
|
+
tool: name,
|
|
331
|
+
args,
|
|
332
|
+
decoded,
|
|
333
|
+
maxItems: limits.maxResultItems,
|
|
334
|
+
maxBytes: Math.max(1, limits.maxResultBytes - reportBytes),
|
|
335
|
+
...(opts.onOversize ? { onOversize: opts.onOversize } : {}),
|
|
336
|
+
...(sdk?.http?.authInfo ? { authInfo: sdk.http.authInfo } : {}),
|
|
337
|
+
...(tool.envelope ? { envelope: tool.envelope } : {}),
|
|
338
|
+
}, result);
|
|
339
|
+
result = attachCredentialReport(result, report, { structured: reportStructured, mask: maskClientText });
|
|
340
|
+
}
|
|
341
|
+
logToolResult(name, {
|
|
342
|
+
isError: !isInputRequiredResult(result) && result.isError === true,
|
|
343
|
+
durationMs: Date.now() - started,
|
|
344
|
+
});
|
|
345
|
+
return result;
|
|
346
|
+
};
|
|
347
|
+
// The request scope lets the protocol log forwarder find this request's SDK context.
|
|
348
|
+
const run = (args, sdk) => {
|
|
349
|
+
const credentials = new CredentialScope(registry, valueFor);
|
|
350
|
+
const call = () => runWithCredentialScope(credentials, () => execute(args, sdk, credentials));
|
|
351
|
+
return sdk ? runWithRequestContext(sdk, call) : call();
|
|
352
|
+
};
|
|
353
|
+
const config = {
|
|
354
|
+
...(tool.title !== undefined ? { title: tool.title } : {}),
|
|
355
|
+
description: tool.description,
|
|
356
|
+
inputSchema: tool.inputSchema,
|
|
357
|
+
...(outputSchema !== undefined ? { outputSchema } : {}),
|
|
358
|
+
annotations: tool.annotations,
|
|
359
|
+
...(tool.icons !== undefined ? { icons: tool.icons } : {}),
|
|
360
|
+
...(tool.scopeChallenge !== undefined ? { scopeChallenge: tool.scopeChallenge } : {}),
|
|
361
|
+
...(tool._meta !== undefined ? { _meta: tool._meta } : {}),
|
|
362
|
+
};
|
|
363
|
+
const handle = server.registerTool(name, config, (args, ctx) => run(args, ctx));
|
|
364
|
+
if (opts.surface)
|
|
365
|
+
bindToSurface(server, opts.surface, 'tool', name, handle);
|
|
366
|
+
handles.set(name, handle);
|
|
367
|
+
}
|
|
368
|
+
return handles;
|
|
369
|
+
}
|
|
370
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAGL,4BAA4B,EAK5B,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,iBAAiB,GAKlB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAoB,iBAAiB,EAAmB,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACrG,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAuB,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,GAKZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAA2C,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,EAAE,SAAS,EAAe,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACzG,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAiHxD,6FAA6F;AAC7F,MAAM,UAAU,UAAU,CAAmC,UAA6B;IACxF,OAAO,UAA0C,CAAC;AACpD,CAAC;AAkCD,MAAM,UAAU,GAAG;IACjB,oBAAoB;IACpB,sBAAsB;IACtB,sBAAsB;IACtB,6BAA6B;CACrB,CAAC;AAEX,+FAA+F;AAC/F,SAAS,SAAS,CAAC,GAAc;IAC/B,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,KAAK,MAAM,GAAG,IAAI,UAAU;QAAE,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACtD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAa,EAAE,OAA0B,EAAE;IACpE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9G,MAAM,MAAM,GAAmB,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACrE,IAAI,aAAa,CAAC,IAAI,CAAC;QAAE,MAAM,CAAC,iBAAiB,GAAG,IAAI,CAAC;IACzD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,gBAAgB,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,OAAiC;IAC1E,MAAM,OAAO,GAA8B,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7F,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAClH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACpC,CAAC;AAED,uEAAuE;AACvE,SAAS,eAAe,CAAC,MAAsB;IAC7C,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAC3C,OAAO;QACL,GAAG,MAAM;QACT,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACpC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAC/E;KACF,CAAC;AACJ,CAAC;AAOD,SAAS,YAAY,CAAC,GAAY;IAChC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,YAAY,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACrE,MAAM,MAAM,GAAI,GAA4B,CAAC,MAAM,CAAC;IACpD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACpE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9F,OAAO,MAAuB,CAAC;AACjC,CAAC;AAED,SAAS,SAAS,CAAC,KAAkB;IACnC,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrG,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,sFAAsF;AACtF,SAAS,YAAY,CAAC,MAAqB;IACzC,OAAO,sBAAsB,MAAM;SAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QACvB,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC9C,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAClB,CAAC;AAED,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAE/B,2GAA2G;AAC3G,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,IAAI,OAAe,CAAC;IACpB,IAAI,GAAG,YAAY,KAAK;QAAE,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC;SACvD,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,GAAG,CAAC;;QAC3C,OAAO,GAAG,gBAAgB,CAAC;IAChC,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAC3D,IAAI,OAAO,CAAC,MAAM,GAAG,iBAAiB;QAAE,OAAO,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,KAAK,CAAC;IAC9F,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,CAAC;AAClD,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,aAAa,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC;AACpE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAgB,EAAE,eAAe,GAAG,KAAK;IACxE,IAAI,qBAAqB,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IACnD,IAAI,gBAAgB,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IAC9C,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAClF,MAAM,MAAM,GAAmB,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACrE,IAAI,eAAe,IAAI,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;QAC5F,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,oBAAoB,CAAC,UAAkB,EAAE,OAA0B;IACjF,OAAO,GAAG,UAAU,2BAA2B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACtE,CAAC;AAED;;;;GAIG;AACH,SAAS,oBAAoB,CAAC,MAAiB,EAAE,GAA8B;IAC7E,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,QAA+C,CAAC;IAC5E,MAAM,YAAY,GAAG,QAAQ,EAAE,CAAC,4BAA4B,CAAmC,CAAC;IAChG,OAAO,YAAY,IAAI,MAAM,CAAC,MAAM,CAAC,qBAAqB,EAAE,CAAC;AAC/D,CAAC;AAED,SAAS,UAAU,CACjB,MAAiB,EACjB,IAAY,EACZ,IAAa,EACb,GAA8B,EAC9B,WAA4B;IAE5B,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACtH,MAAM,aAAa,GAAG,GAAG,EAAE,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC;IACvD,MAAM,kBAAkB,GAAG,oBAAoB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,GAAG,EAAE,MAAM,CAAC,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC,MAAM,CAAC;IAClE,MAAM,KAAK,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO;QACL,YAAY,EAAE,GAAM,EAAE,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,EAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QAChF,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE;YAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,oBAAoB,CAC5B,wHAAwH,CACzH,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,GAAG;gBAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YACxE,MAAM,YAAY,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAClD,OAAO,aAAa,CAAC,EAAE,GAAG,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC;QACpG,CAAC;QACD,IAAI;QACJ,MAAM;QACN,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ;QAC7B,MAAM;QACN,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxC,GAAG,CAAC,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,MAAM,EAAE,SAAS,EAAE;QACnB,WAAW;QACX,GAAG;QACH,GAAG,iBAAiB,CAAC,GAAG,EAAE,kBAAkB,CAAC;QAC7C,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YAC3C,IAAI,CAAC,GAAG,IAAI,aAAa,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO;gBAAE,OAAO;YAClE,IAAI,CAAC;gBACH,MAAM,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;oBACtB,MAAM,EAAE,wBAAwB;oBAChC,MAAM,EAAE;wBACN,aAAa;wBACb,QAAQ;wBACR,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBACzC,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBAC9C;iBACF,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,qDAAqD;YACvD,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,qGAAqG;AACrG,SAAS,uBAAuB,CAAC,GAAY;IAC3C,OAAO,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,iBAAiB,CAAC,sBAAsB,CAAC;AAChG,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAiB,EACjB,KAAmC,EACnC,OAA6B,EAAE;IAE/B,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,eAAe,CAAC;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,aAAa,CAAC;IACpD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;IACjC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,IAAI,kBAAkB,EAAE,CAAC;IAC1D,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAsB,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IAEzE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QACjD,MAAM,IAAI,GAAG,GAAG,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;QACrC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,0CAA0C,CAAC,CAAC;QACzF,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7D,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5D,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,uBAAuB,IAAI,aAAa,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,yCAAyC,CACvG,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAC1D,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,oDAAoD,CAAC,CAAC;QAC7G,CAAC;QACD,MAAM,MAAM,GAAG,aAAa,CAC1B;YACE,GAAG,CAAC,YAAY,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzF,GAAG,CAAC,YAAY,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzF,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxF,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzF,EACD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAC7C,CAAC;QAEF,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3G,MAAM,gBAAgB,GAAG,YAAY,KAAK,SAAS,IAAI,YAAY,KAAK,IAAI,CAAC,YAAY,CAAC;QAC1F,MAAM,OAAO,GAAG,KAAK,EACnB,IAAa,EACb,GAA8B,EAC9B,WAA4B,EACmB,EAAE;YACjD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACxB,IAAI,MAA4C,CAAC;YACjD,IAAI,OAA+B,CAAC;YACpC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC1D,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;gBAChG,IAAI,MAAM,KAAK,SAAS;oBAAE,OAAO,GAAG,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC;gBAClG,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACvB,MAAM,GAAG,SAAS,CAAC,oBAAoB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;gBAChE,CAAC;qBAAM,CAAC;oBACN,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;oBACnE,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAiB,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;oBAC5G,MAAM,GAAG,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC;oBACpE,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC;wBAAE,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;gBACvE,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;oBACtC,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;oBAClC,aAAa,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;oBACzE,OAAO,MAAM,CAAC;gBAChB,CAAC;gBACD,IAAI,uBAAuB,CAAC,GAAG,CAAC,EAAE,CAAC;oBACjC,aAAa,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;oBACzE,MAAM,GAAG,CAAC;gBACZ,CAAC;gBACD,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;gBACjC,IAAI,GAAG,YAAY,uBAAuB,EAAE,CAAC;oBAC3C,MAAM,GAAG,SAAS,CAChB,GAAG,UAAU,iBAAiB,IAAI,KAAK,GAAG,CAAC,OAAO,uEAAuE,CAC1H,CAAC;gBACJ,CAAC;qBAAM,IAAI,GAAG,YAAY,uBAAuB,EAAE,CAAC;oBAClD,mGAAmG;oBACnG,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAClC,CAAC;qBAAM,IAAI,MAAM,EAAE,CAAC;oBAClB,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;gBAC3C,CAAC;qBAAM,CAAC;oBACN,IAAI,MAAuB,CAAC;oBAC5B,IAAI,CAAC;wBACH,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;oBACzB,CAAC;oBAAC,MAAM,CAAC;wBACP,MAAM,GAAG,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;oBACzC,CAAC;oBACD,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACzF,CAAC;YACH,CAAC;YACD,yFAAyF;YACzF,MAAM,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,IAAI,qBAAqB,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClC,MAAM,GAAG,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;YAChE,CAAC;iBAAM,CAAC;gBACN,MAAM,WAAW,GAAG,qBAAqB,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;gBACpE,MAAM,GAAG,mBAAmB,CAC1B;oBACE,IAAI,EAAE,IAAI;oBACV,IAAI;oBACJ,OAAO;oBACP,QAAQ,EAAE,MAAM,CAAC,cAAc;oBAC/B,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,cAAc,GAAG,WAAW,CAAC;oBAC1D,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC3D,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC/D,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACtD,EACD,MAAM,CACP,CAAC;gBACF,MAAM,GAAG,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,gBAAgB,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;YAC1G,CAAC;YACD,aAAa,CAAC,IAAI,EAAE;gBAClB,OAAO,EAAE,CAAC,qBAAqB,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI;gBAClE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO;aACjC,CAAC,CAAC;YACH,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QACF,qFAAqF;QACrF,MAAM,GAAG,GAAG,CAAC,IAAa,EAAE,GAAmB,EAAiD,EAAE;YAChG,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC5D,MAAM,IAAI,GAAG,GAAkD,EAAE,CAC/D,sBAAsB,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;YAC7E,OAAO,GAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzD,CAAC,CAAC;QAEF,MAAM,MAAM,GAAG;YACb,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,GAAG,CAAC,IAAI,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrF,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3D,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,IAAa,EAAE,GAAkB,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;QACxG,IAAI,IAAI,CAAC,OAAO;YAAE,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAC5E,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/transport.d.ts
CHANGED
|
@@ -1,102 +1,193 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @novorb/mcp-core
|
|
2
|
+
* @novorb/mcp-core - Transport
|
|
3
3
|
*
|
|
4
|
-
* Unified transport for MCP servers. Selects between stdio and
|
|
5
|
-
*
|
|
4
|
+
* Unified transport for MCP servers on SDK v2. Selects between stdio and Streamable HTTP from the
|
|
5
|
+
* MCP_TRANSPORT environment variable; both legs take the SAME server factory.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* - stdio: `serveStdio(factory)` from `@modelcontextprotocol/server/stdio` (one instance per
|
|
8
|
+
* connection; the client's opening message picks the protocol era).
|
|
9
|
+
* - http: `createMcpHandler(factory, { legacy: 'stateless' })` (the SDK default `responseMode: 'auto'`:
|
|
10
|
+
* one JSON body unless the handler emits progress or log notifications first, then SSE) adapted with
|
|
11
|
+
* `toNodeHandler` from `@modelcontextprotocol/node`, behind mcp-core's own `node:http` server that
|
|
12
|
+
* adds `/health`, the fail-closed Bearer gate (the SDK's `verifyBearerToken` over the static key or a
|
|
13
|
+
* pluggable verifier, `req.auth` set for the SDK), Host/Origin allow-lists and the 415/413 guards.
|
|
14
|
+
* Stateless: a fresh instance per request, 2025-era clients served by the SDK's stateless fallback.
|
|
10
15
|
*
|
|
11
16
|
* Usage:
|
|
12
17
|
* import { startMcpServer } from '@novorb/mcp-core/transport';
|
|
18
|
+
* await startMcpServer(() => buildServer());
|
|
13
19
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* '127.0.0.1' for local-only)
|
|
25
|
-
* MCP_API_KEY — Bearer token for HTTP auth. REQUIRED in HTTP mode unless MCP_AUTH_DISABLED.
|
|
26
|
-
* MCP_AUTH_DISABLED — set 'true' to run HTTP WITHOUT auth (only when a gateway/platform fronts it)
|
|
27
|
-
* MCP_MAX_BODY_BYTES — max accepted POST body size (default: 4 MiB)
|
|
28
|
-
* MCP_ALLOWED_HOSTS — comma-separated Host allowlist; setting it enables DNS-rebinding protection
|
|
29
|
-
* MCP_ALLOWED_ORIGINS — comma-separated Origin allowlist (also enables DNS-rebinding protection)
|
|
20
|
+
* Environment variables (an explicit option wins):
|
|
21
|
+
* MCP_TRANSPORT - 'stdio' (default) | 'http'; any other value throws
|
|
22
|
+
* PORT - listen port for HTTP transport (default: 8080)
|
|
23
|
+
* MCP_HTTP_HOST - bind address for HTTP (default: '0.0.0.0'; set '127.0.0.1' for local-only)
|
|
24
|
+
* MCP_API_KEY - Bearer token for HTTP auth. REQUIRED in HTTP mode unless MCP_AUTH_DISABLED or
|
|
25
|
+
* a `verifier` is passed.
|
|
26
|
+
* MCP_AUTH_DISABLED - set 'true' to run HTTP WITHOUT auth (only when a gateway/platform fronts it)
|
|
27
|
+
* MCP_MAX_BODY_BYTES - max accepted POST body size (default: 4 MiB)
|
|
28
|
+
* MCP_ALLOWED_HOSTS - comma-separated Host allowlist; setting it enables DNS-rebinding protection
|
|
29
|
+
* MCP_ALLOWED_ORIGINS - comma-separated Origin allowlist (also enables DNS-rebinding protection)
|
|
30
30
|
*/
|
|
31
|
-
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
32
|
-
|
|
33
|
-
type
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
type
|
|
31
|
+
import { type IncomingMessage, type ServerResponse } from 'node:http';
|
|
32
|
+
import { type AuthInfo, type McpRequestContext, type McpServer, type Server, type ServerEventBus, type ServerNotifier, type VerifyBearerTokenOptions } from '@modelcontextprotocol/server';
|
|
33
|
+
import { type HttpAuthOptions } from './auth.js';
|
|
34
|
+
/**
|
|
35
|
+
* What the SDK hands a factory per serving unit: the protocol `era` ('modern' | 'legacy'), and on HTTP
|
|
36
|
+
* the verified `authInfo` (set by the Bearer gate) and the original `requestInfo`.
|
|
37
|
+
*/
|
|
38
|
+
export type RequestContext = McpRequestContext;
|
|
39
|
+
/**
|
|
40
|
+
* Builds a fresh server instance: once per connection on stdio, once per request on HTTP. Receives the
|
|
41
|
+
* SDK's per-request context; zero-argument factories remain valid.
|
|
42
|
+
*/
|
|
43
|
+
export type ServerFactory = (ctx: RequestContext) => McpServer | Server;
|
|
44
|
+
/** A started transport: resolved once stdio is serving or the HTTP listener is bound. */
|
|
45
|
+
export interface TransportHandle {
|
|
46
|
+
mode: TransportMode;
|
|
47
|
+
/** http only: the bound host. */
|
|
48
|
+
host?: string;
|
|
49
|
+
/** http only: the bound port (the real one when 0 was requested). */
|
|
50
|
+
port?: number;
|
|
51
|
+
/** http only: the `/mcp` endpoint URL. */
|
|
52
|
+
url?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Resolves once the transport has ended for any reason: `close()`, or (stdio) the client closing its
|
|
55
|
+
* end of the pipe (stdin end / close). `runMcpServer` uses it to dispose and exit on a stdio EOF.
|
|
56
|
+
*/
|
|
57
|
+
closed: Promise<void>;
|
|
58
|
+
/** The change-event bus this transport delivers from (`TransportOptions.bus`, else the process bus). */
|
|
59
|
+
bus: ServerEventBus;
|
|
60
|
+
/** Publish list-changed / resource-updated events to every connection of this transport. */
|
|
61
|
+
notify: ServerNotifier;
|
|
62
|
+
/** Close the transport (SDK handler, then the listener / stdio connection). Idempotent. */
|
|
63
|
+
close(): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
/** A server instance (stdio only) or a factory (stdio and HTTP). */
|
|
66
|
+
export type ServerOrFactory = McpServer | Server | ServerFactory;
|
|
39
67
|
export type TransportMode = 'stdio' | 'http';
|
|
40
68
|
export interface TransportOptions {
|
|
41
69
|
/** Transport mode. Defaults to MCP_TRANSPORT env var, falling back to 'stdio'. */
|
|
42
70
|
mode?: TransportMode;
|
|
43
71
|
/** HTTP listen port. Defaults to PORT env var, falling back to 8080. */
|
|
44
72
|
port?: number;
|
|
73
|
+
/** HTTP bind address. Defaults to MCP_HTTP_HOST, falling back to 0.0.0.0. */
|
|
74
|
+
host?: string;
|
|
45
75
|
/**
|
|
46
76
|
* Optional Bearer token for HTTP auth. When set, all /mcp requests must include
|
|
47
77
|
* `Authorization: Bearer <apiKey>`. Defaults to MCP_API_KEY env var.
|
|
48
78
|
* Set to null to EXPLICITLY disable auth (equivalent to MCP_AUTH_DISABLED=true).
|
|
49
79
|
*/
|
|
50
80
|
apiKey?: string | null;
|
|
81
|
+
/**
|
|
82
|
+
* Bearer gate options: a pluggable `verifier` (replaces the static key, for example a JWT verifier),
|
|
83
|
+
* `requiredScopes`, `resourceMetadataUrl`, `expectedResource`, and the API key's `AuthInfo` fields.
|
|
84
|
+
*/
|
|
85
|
+
auth?: HttpAuthOptions;
|
|
86
|
+
/** POST body cap in bytes. Defaults to MCP_MAX_BODY_BYTES, falling back to 4 MiB. */
|
|
87
|
+
maxBodyBytes?: number;
|
|
88
|
+
/** Host allow-list. Defaults to MCP_ALLOWED_HOSTS. */
|
|
89
|
+
allowedHosts?: string[];
|
|
90
|
+
/** Origin allow-list. Defaults to MCP_ALLOWED_ORIGINS. */
|
|
91
|
+
allowedOrigins?: string[];
|
|
92
|
+
/**
|
|
93
|
+
* Install SIGINT/SIGTERM handlers that close the transport (default true). `runMcpServer` passes
|
|
94
|
+
* false and owns the signals itself (close transport, dispose, exit).
|
|
95
|
+
*/
|
|
96
|
+
handleSignals?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* The change-event bus (default: the process bus, `processBus()`). HTTP: the SDK serves
|
|
99
|
+
* `subscriptions/listen` streams from it; stdio: every connection's instance forwards its events.
|
|
100
|
+
*/
|
|
101
|
+
bus?: ServerEventBus;
|
|
51
102
|
}
|
|
103
|
+
/** Default POST body cap (the SDK's own default too). */
|
|
104
|
+
export declare const DEFAULT_MAX_BODY_BYTES: number;
|
|
52
105
|
/**
|
|
53
106
|
* Constant-time comparison of the Authorization header against `Bearer <apiKey>`.
|
|
54
107
|
* Both sides are SHA-256-hashed first so `timingSafeEqual` never throws on a length mismatch and the
|
|
55
|
-
* token length is not itself a timing oracle.
|
|
108
|
+
* token length is not itself a timing oracle. (The transport itself now verifies through the SDK's
|
|
109
|
+
* `verifyBearerToken` with `apiKeyVerifier`, which compares the same way.)
|
|
56
110
|
*/
|
|
57
111
|
export declare function bearerMatches(authHeader: string, apiKey: string): boolean;
|
|
58
112
|
export interface HttpAuthResolution {
|
|
59
113
|
/** Whether the Bearer check is enforced on /mcp requests. */
|
|
60
114
|
authEnabled: boolean;
|
|
61
|
-
/** The resolved key ('' when auth is explicitly disabled). */
|
|
115
|
+
/** The resolved key ('' when auth is explicitly disabled or a verifier replaces it). */
|
|
62
116
|
apiKey: string;
|
|
63
117
|
}
|
|
64
118
|
/**
|
|
65
|
-
* Resolve HTTP auth
|
|
119
|
+
* Resolve HTTP auth - FAIL CLOSED. `apiKey: null` (programmatic) or MCP_AUTH_DISABLED=true are the
|
|
66
120
|
* only ways to run open; a missing/empty MCP_API_KEY is treated as "not configured" (not a valid
|
|
67
|
-
* empty key) and THROWS, so a config typo can't silently downgrade the endpoint to no-auth.
|
|
121
|
+
* empty key) and THROWS, so a config typo can't silently downgrade the endpoint to no-auth. A passed
|
|
122
|
+
* `auth.verifier` always enforces auth (it wins over every "disabled" switch).
|
|
68
123
|
*/
|
|
69
|
-
export declare function resolveHttpAuth(options: Pick<TransportOptions, 'apiKey'>, env?: NodeJS.ProcessEnv): HttpAuthResolution;
|
|
70
|
-
/** Resolved configuration for the HTTP request handler
|
|
124
|
+
export declare function resolveHttpAuth(options: Pick<TransportOptions, 'apiKey' | 'auth'>, env?: NodeJS.ProcessEnv): HttpAuthResolution;
|
|
125
|
+
/** Resolved configuration for the HTTP request handler: everything `startHttp` derives once at boot. */
|
|
71
126
|
export interface RequestHandlerConfig {
|
|
72
|
-
/**
|
|
73
|
-
getServer:
|
|
74
|
-
/** Whether the Bearer check is enforced on /mcp requests. */
|
|
127
|
+
/** Builds a fresh server instance for each request (one instance serves one connection in SDK v2). */
|
|
128
|
+
getServer: ServerFactory;
|
|
129
|
+
/** Whether the Bearer check is enforced on /mcp requests (with the API key, or `auth.verifier`). */
|
|
75
130
|
authEnabled: boolean;
|
|
76
|
-
/** The resolved Bearer key ('' when auth is disabled). */
|
|
131
|
+
/** The resolved Bearer key ('' when auth is disabled or a verifier replaces it). */
|
|
77
132
|
apiKey: string;
|
|
78
|
-
/**
|
|
133
|
+
/** Bearer gate options (verifier, scopes, resource metadata, the API key's AuthInfo fields). */
|
|
134
|
+
auth?: HttpAuthOptions;
|
|
135
|
+
/** Max accepted POST body size in bytes (413 when exceeded). */
|
|
79
136
|
maxBodyBytes: number;
|
|
80
|
-
/** Whether to
|
|
137
|
+
/** Whether to enforce the Host/Origin allow-lists (DNS-rebinding protection). */
|
|
81
138
|
enableDnsRebindingProtection: boolean;
|
|
82
|
-
/** Host allowlist
|
|
139
|
+
/** Host allowlist; `host` or `host:port` entries, matched port-agnostically by hostname. */
|
|
83
140
|
allowedHosts: string[];
|
|
84
|
-
/** Origin allowlist
|
|
141
|
+
/** Origin allowlist; full origins or bare hostnames (matched by hostname), or `<scheme>://*`. */
|
|
85
142
|
allowedOrigins: string[];
|
|
143
|
+
/** The change-event bus `subscriptions/listen` streams subscribe to (default the process bus). */
|
|
144
|
+
bus?: ServerEventBus;
|
|
86
145
|
}
|
|
146
|
+
/** The `(req, res)` listener for `node:http`, plus `close()` to tear down the SDK handler. */
|
|
147
|
+
export type McpRequestHandler = ((req: IncomingMessage, res: ServerResponse) => Promise<void>) & {
|
|
148
|
+
close(): Promise<void>;
|
|
149
|
+
};
|
|
150
|
+
/** `host` or `host:port` -> the bare hostname the SDK's port-agnostic Host validation compares. */
|
|
151
|
+
export declare function toHostname(entry: string): string;
|
|
152
|
+
/**
|
|
153
|
+
* A full origin (`https://app.example.com:443`) -> its hostname; bare hostnames and `<scheme>://*`
|
|
154
|
+
* entries pass unchanged. The SDK honours a lowercase `<scheme>://*` entry (for example
|
|
155
|
+
* `chrome-extension://*`) as "every origin of that scheme", but never `http://*` or `https://*`.
|
|
156
|
+
*/
|
|
157
|
+
export declare function toOriginHostname(entry: string): string;
|
|
158
|
+
/** Split a comma-separated allow-list env value. */
|
|
159
|
+
export declare function parseList(value: string | undefined): string[];
|
|
160
|
+
/** `IncomingMessage` with the `auth` the SDK node adapter forwards as `authInfo`. */
|
|
161
|
+
export type AuthenticatedRequest = IncomingMessage & {
|
|
162
|
+
auth?: AuthInfo;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Run the Bearer gate: answers the SDK challenge (401/403 with `WWW-Authenticate`) and returns false,
|
|
166
|
+
* or sets `req.auth` and returns true. With no gate configured it lets the request through.
|
|
167
|
+
*/
|
|
168
|
+
export declare function runBearerGate(req: AuthenticatedRequest, res: ServerResponse, gate: VerifyBearerTokenOptions | undefined): Promise<boolean>;
|
|
169
|
+
/** The content-type check: the SDK's media-type essence comparison (`application/json`, params allowed). */
|
|
170
|
+
export declare function isJsonRequest(req: IncomingMessage): boolean;
|
|
87
171
|
/**
|
|
88
172
|
* Build the `(req, res)` handler for the HTTP transport. Extracted from `startHttp` so the routing,
|
|
89
|
-
* auth, content-type/size guards, and error handling are unit-testable with mock req/res
|
|
90
|
-
* binding required.
|
|
173
|
+
* auth, content-type/size guards, and error handling are unit-testable with mock req/res, no socket
|
|
174
|
+
* binding required. Order: `/health`, Bearer check, path check, Host/Origin allow-lists, 415, 413,
|
|
175
|
+
* then the SDK handler.
|
|
91
176
|
*/
|
|
92
|
-
export declare function createRequestHandler(cfg: RequestHandlerConfig):
|
|
177
|
+
export declare function createRequestHandler(cfg: RequestHandlerConfig): McpRequestHandler;
|
|
178
|
+
/** The transport mode from the option, else MCP_TRANSPORT, else stdio; anything else throws. */
|
|
179
|
+
export declare function resolveTransportMode(option: TransportMode | undefined, env?: NodeJS.ProcessEnv): "stdio" | "http";
|
|
93
180
|
/**
|
|
94
|
-
* Start an MCP server with the configured transport.
|
|
181
|
+
* Start an MCP server with the configured transport. Resolves with a `TransportHandle` once serving:
|
|
95
182
|
*
|
|
96
|
-
* For stdio:
|
|
97
|
-
*
|
|
98
|
-
*
|
|
183
|
+
* For stdio: serves the process' stdin/stdout. An instance is accepted and wrapped as `() => instance`.
|
|
184
|
+
* With `handleSignals` (default) SIGINT/SIGTERM close the connection and re-raise the signal
|
|
185
|
+
* when no other listener remains. `closed` resolves when the client closes stdin.
|
|
186
|
+
* For http: starts a stateless HTTP server and resolves once the listener is bound (the process stays
|
|
187
|
+
* alive on the listener). With `handleSignals` (default) SIGINT/SIGTERM close it. Requires a
|
|
188
|
+
* factory (a fresh instance per request).
|
|
99
189
|
*/
|
|
100
|
-
export declare function startMcpServer(serverOrFactory: ServerOrFactory, options?: TransportOptions): Promise<
|
|
101
|
-
|
|
190
|
+
export declare function startMcpServer(serverOrFactory: ServerOrFactory, options?: TransportOptions): Promise<TransportHandle>;
|
|
191
|
+
/** A factory whose instances forward the bus's change events (a stdio connection is long-lived). */
|
|
192
|
+
export declare function notifyingFactory(factory: ServerFactory, bus: ServerEventBus): ServerFactory;
|
|
102
193
|
//# sourceMappingURL=transport.d.ts.map
|