@orkestrel/mcp 0.0.11 → 0.0.12
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.
|
@@ -677,6 +677,27 @@ export declare interface HTTPTransportOptions<TState = unknown> extends HTTPHand
|
|
|
677
677
|
readonly path?: string;
|
|
678
678
|
}
|
|
679
679
|
|
|
680
|
+
/**
|
|
681
|
+
* Infer the first required MCP HTTP header that is missing or mismatched.
|
|
682
|
+
*
|
|
683
|
+
* @remarks
|
|
684
|
+
* A modern request derives its protocol, method, and tools/call-only name expectations from
|
|
685
|
+
* the JSON-RPC body. A legacy request body requires a protocol header after initialization,
|
|
686
|
+
* while a supplied legacy session version additionally diagnoses a header that disagrees with
|
|
687
|
+
* the active session. Messages name the expected value but never echo the client-supplied one.
|
|
688
|
+
*
|
|
689
|
+
* @param request - The HTTP request carrying the headers
|
|
690
|
+
* @param reference - The parsed request body, or the active legacy session version
|
|
691
|
+
* @returns The first header issue, or `undefined` when the applicable headers agree
|
|
692
|
+
*
|
|
693
|
+
* @example
|
|
694
|
+
* ```ts
|
|
695
|
+
* const issue = inferHeaderIssue(request, rpcRequest)
|
|
696
|
+
* issue?.header // 'Mcp-Method' when that field is absent or mismatched
|
|
697
|
+
* ```
|
|
698
|
+
*/
|
|
699
|
+
export declare function inferHeaderIssue(request: Request, reference: JSONRPCRequest | MCPVersion): MCPHeaderIssue | undefined;
|
|
700
|
+
|
|
680
701
|
/**
|
|
681
702
|
* Infer the legacy revision an `initialize` request negotiates.
|
|
682
703
|
*
|
|
@@ -718,21 +739,6 @@ export declare interface LineExtraction {
|
|
|
718
739
|
readonly remainder: string;
|
|
719
740
|
}
|
|
720
741
|
|
|
721
|
-
/**
|
|
722
|
-
* Whether a modern HTTP request's required standard headers match its JSON-RPC body.
|
|
723
|
-
*
|
|
724
|
-
* @remarks
|
|
725
|
-
* Requires `MCP-Protocol-Version` to equal the reserved `_meta` version and `Mcp-Method`
|
|
726
|
-
* to equal `method`. `Mcp-Name` is required only for `tools/call`, where it must equal
|
|
727
|
-
* `params.name`; discovery and listing requests need no name because none is derivable.
|
|
728
|
-
* Legacy requests return `false` because this predicate models the modern contract only.
|
|
729
|
-
*
|
|
730
|
-
* @param request - The HTTP request carrying the headers
|
|
731
|
-
* @param message - The parsed JSON-RPC request body
|
|
732
|
-
* @returns `true` only when every method-applicable modern header matches
|
|
733
|
-
*/
|
|
734
|
-
export declare function matchesModernHeaders(request: Request, message: JSONRPCRequest): boolean;
|
|
735
|
-
|
|
736
742
|
/** The modern Streamable-HTTP request header carrying the JSON-RPC method name. */
|
|
737
743
|
export declare const MCP_METHOD_HEADER = "mcp-method";
|
|
738
744
|
|
|
@@ -788,6 +794,21 @@ export declare const MCP_WEBSOCKET_SUBPROTOCOL = "mcp";
|
|
|
788
794
|
*/
|
|
789
795
|
export declare type MCPCallerHandler<TState = unknown> = (request: Request, context: RouteContext<string, TState> | undefined) => unknown;
|
|
790
796
|
|
|
797
|
+
/**
|
|
798
|
+
* One required MCP HTTP header that is absent or disagrees with its server-derived value.
|
|
799
|
+
*
|
|
800
|
+
* @remarks
|
|
801
|
+
* - `header` — the canonical HTTP field name safe to show to an integrator.
|
|
802
|
+
* - `reason` — whether the field is absent or carries a mismatched value.
|
|
803
|
+
* - `message` — the refusal message naming the expected body, session, or server value without
|
|
804
|
+
* echoing the client-supplied header value.
|
|
805
|
+
*/
|
|
806
|
+
export declare interface MCPHeaderIssue {
|
|
807
|
+
readonly header: 'MCP-Protocol-Version' | 'Mcp-Method' | 'Mcp-Name';
|
|
808
|
+
readonly reason: 'missing' | 'mismatched';
|
|
809
|
+
readonly message: string;
|
|
810
|
+
}
|
|
811
|
+
|
|
791
812
|
/**
|
|
792
813
|
* Shared SSE keepalive options for held-open HTTP responses.
|
|
793
814
|
*
|
|
@@ -677,6 +677,27 @@ export declare interface HTTPTransportOptions<TState = unknown> extends HTTPHand
|
|
|
677
677
|
readonly path?: string;
|
|
678
678
|
}
|
|
679
679
|
|
|
680
|
+
/**
|
|
681
|
+
* Infer the first required MCP HTTP header that is missing or mismatched.
|
|
682
|
+
*
|
|
683
|
+
* @remarks
|
|
684
|
+
* A modern request derives its protocol, method, and tools/call-only name expectations from
|
|
685
|
+
* the JSON-RPC body. A legacy request body requires a protocol header after initialization,
|
|
686
|
+
* while a supplied legacy session version additionally diagnoses a header that disagrees with
|
|
687
|
+
* the active session. Messages name the expected value but never echo the client-supplied one.
|
|
688
|
+
*
|
|
689
|
+
* @param request - The HTTP request carrying the headers
|
|
690
|
+
* @param reference - The parsed request body, or the active legacy session version
|
|
691
|
+
* @returns The first header issue, or `undefined` when the applicable headers agree
|
|
692
|
+
*
|
|
693
|
+
* @example
|
|
694
|
+
* ```ts
|
|
695
|
+
* const issue = inferHeaderIssue(request, rpcRequest)
|
|
696
|
+
* issue?.header // 'Mcp-Method' when that field is absent or mismatched
|
|
697
|
+
* ```
|
|
698
|
+
*/
|
|
699
|
+
export declare function inferHeaderIssue(request: Request, reference: JSONRPCRequest | MCPVersion): MCPHeaderIssue | undefined;
|
|
700
|
+
|
|
680
701
|
/**
|
|
681
702
|
* Infer the legacy revision an `initialize` request negotiates.
|
|
682
703
|
*
|
|
@@ -718,21 +739,6 @@ export declare interface LineExtraction {
|
|
|
718
739
|
readonly remainder: string;
|
|
719
740
|
}
|
|
720
741
|
|
|
721
|
-
/**
|
|
722
|
-
* Whether a modern HTTP request's required standard headers match its JSON-RPC body.
|
|
723
|
-
*
|
|
724
|
-
* @remarks
|
|
725
|
-
* Requires `MCP-Protocol-Version` to equal the reserved `_meta` version and `Mcp-Method`
|
|
726
|
-
* to equal `method`. `Mcp-Name` is required only for `tools/call`, where it must equal
|
|
727
|
-
* `params.name`; discovery and listing requests need no name because none is derivable.
|
|
728
|
-
* Legacy requests return `false` because this predicate models the modern contract only.
|
|
729
|
-
*
|
|
730
|
-
* @param request - The HTTP request carrying the headers
|
|
731
|
-
* @param message - The parsed JSON-RPC request body
|
|
732
|
-
* @returns `true` only when every method-applicable modern header matches
|
|
733
|
-
*/
|
|
734
|
-
export declare function matchesModernHeaders(request: Request, message: JSONRPCRequest): boolean;
|
|
735
|
-
|
|
736
742
|
/** The modern Streamable-HTTP request header carrying the JSON-RPC method name. */
|
|
737
743
|
export declare const MCP_METHOD_HEADER = "mcp-method";
|
|
738
744
|
|
|
@@ -788,6 +794,21 @@ export declare const MCP_WEBSOCKET_SUBPROTOCOL = "mcp";
|
|
|
788
794
|
*/
|
|
789
795
|
export declare type MCPCallerHandler<TState = unknown> = (request: Request, context: RouteContext<string, TState> | undefined) => unknown;
|
|
790
796
|
|
|
797
|
+
/**
|
|
798
|
+
* One required MCP HTTP header that is absent or disagrees with its server-derived value.
|
|
799
|
+
*
|
|
800
|
+
* @remarks
|
|
801
|
+
* - `header` — the canonical HTTP field name safe to show to an integrator.
|
|
802
|
+
* - `reason` — whether the field is absent or carries a mismatched value.
|
|
803
|
+
* - `message` — the refusal message naming the expected body, session, or server value without
|
|
804
|
+
* echoing the client-supplied header value.
|
|
805
|
+
*/
|
|
806
|
+
export declare interface MCPHeaderIssue {
|
|
807
|
+
readonly header: 'MCP-Protocol-Version' | 'Mcp-Method' | 'Mcp-Name';
|
|
808
|
+
readonly reason: 'missing' | 'mismatched';
|
|
809
|
+
readonly message: string;
|
|
810
|
+
}
|
|
811
|
+
|
|
791
812
|
/**
|
|
792
813
|
* Shared SSE keepalive options for held-open HTTP responses.
|
|
793
814
|
*
|
package/dist/src/server/index.js
CHANGED
|
@@ -144,27 +144,6 @@ function allowsOrigin(request, options) {
|
|
|
144
144
|
return options?.origins?.includes(parsed.origin) ?? false;
|
|
145
145
|
}
|
|
146
146
|
/**
|
|
147
|
-
* Whether a modern HTTP request's required standard headers match its JSON-RPC body.
|
|
148
|
-
*
|
|
149
|
-
* @remarks
|
|
150
|
-
* Requires `MCP-Protocol-Version` to equal the reserved `_meta` version and `Mcp-Method`
|
|
151
|
-
* to equal `method`. `Mcp-Name` is required only for `tools/call`, where it must equal
|
|
152
|
-
* `params.name`; discovery and listing requests need no name because none is derivable.
|
|
153
|
-
* Legacy requests return `false` because this predicate models the modern contract only.
|
|
154
|
-
*
|
|
155
|
-
* @param request - The HTTP request carrying the headers
|
|
156
|
-
* @param message - The parsed JSON-RPC request body
|
|
157
|
-
* @returns `true` only when every method-applicable modern header matches
|
|
158
|
-
*/
|
|
159
|
-
function matchesModernHeaders(request, message) {
|
|
160
|
-
if (!isModernRequest(message)) return false;
|
|
161
|
-
const version = (isRecord(message.params?.["_meta"]) ? message.params["_meta"] : void 0)?.[MCP_META_VERSION];
|
|
162
|
-
if (!isString(version) || request.headers.get("mcp-protocol-version") !== version || request.headers.get("mcp-method") !== message.method) return false;
|
|
163
|
-
if (message.method !== "tools/call") return true;
|
|
164
|
-
const name = message.params?.["name"];
|
|
165
|
-
return isString(name) && request.headers.get("mcp-name") === name;
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
147
|
* Read the request's `mcp-session-id` header — the session id a stateful transport
|
|
169
148
|
* validates, or `undefined` when absent.
|
|
170
149
|
*
|
|
@@ -418,6 +397,87 @@ function bridgeMessageTransport(transport) {
|
|
|
418
397
|
//#endregion
|
|
419
398
|
//#region src/server/inferers.ts
|
|
420
399
|
/**
|
|
400
|
+
* Infer the first required MCP HTTP header that is missing or mismatched.
|
|
401
|
+
*
|
|
402
|
+
* @remarks
|
|
403
|
+
* A modern request derives its protocol, method, and tools/call-only name expectations from
|
|
404
|
+
* the JSON-RPC body. A legacy request body requires a protocol header after initialization,
|
|
405
|
+
* while a supplied legacy session version additionally diagnoses a header that disagrees with
|
|
406
|
+
* the active session. Messages name the expected value but never echo the client-supplied one.
|
|
407
|
+
*
|
|
408
|
+
* @param request - The HTTP request carrying the headers
|
|
409
|
+
* @param reference - The parsed request body, or the active legacy session version
|
|
410
|
+
* @returns The first header issue, or `undefined` when the applicable headers agree
|
|
411
|
+
*
|
|
412
|
+
* @example
|
|
413
|
+
* ```ts
|
|
414
|
+
* const issue = inferHeaderIssue(request, rpcRequest)
|
|
415
|
+
* issue?.header // 'Mcp-Method' when that field is absent or mismatched
|
|
416
|
+
* ```
|
|
417
|
+
*/
|
|
418
|
+
function inferHeaderIssue(request, reference) {
|
|
419
|
+
const protocol = request.headers.get(MCP_PROTOCOL_VERSION_HEADER);
|
|
420
|
+
if (isString(reference)) {
|
|
421
|
+
if (protocol === null) return {
|
|
422
|
+
header: "MCP-Protocol-Version",
|
|
423
|
+
reason: "missing",
|
|
424
|
+
message: `Required MCP-Protocol-Version header is missing; the active session uses '${reference}'.`
|
|
425
|
+
};
|
|
426
|
+
if (protocol !== reference) return {
|
|
427
|
+
header: "MCP-Protocol-Version",
|
|
428
|
+
reason: "mismatched",
|
|
429
|
+
message: `MCP-Protocol-Version header does not match the active session version '${reference}'.`
|
|
430
|
+
};
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
if (!isModernRequest(reference)) {
|
|
434
|
+
if (isInitializeRequest(reference) || protocol !== null) return void 0;
|
|
435
|
+
return {
|
|
436
|
+
header: "MCP-Protocol-Version",
|
|
437
|
+
reason: "missing",
|
|
438
|
+
message: `Required MCP-Protocol-Version header is missing; this server offers '${MCP_PROTOCOL_VERSION}'.`
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
const message = reference;
|
|
442
|
+
const version = (isRecord(message.params?.["_meta"]) ? message.params["_meta"] : void 0)?.[MCP_META_VERSION];
|
|
443
|
+
if (!isString(version)) return void 0;
|
|
444
|
+
if (protocol === null) return {
|
|
445
|
+
header: "MCP-Protocol-Version",
|
|
446
|
+
reason: "missing",
|
|
447
|
+
message: `Required MCP-Protocol-Version header is missing; the request body version is '${version}'.`
|
|
448
|
+
};
|
|
449
|
+
if (protocol !== version) return {
|
|
450
|
+
header: "MCP-Protocol-Version",
|
|
451
|
+
reason: "mismatched",
|
|
452
|
+
message: `MCP-Protocol-Version header does not match the request body version '${version}'.`
|
|
453
|
+
};
|
|
454
|
+
const method = request.headers.get(MCP_METHOD_HEADER);
|
|
455
|
+
if (method === null) return {
|
|
456
|
+
header: "Mcp-Method",
|
|
457
|
+
reason: "missing",
|
|
458
|
+
message: `Required Mcp-Method header is missing; the request body method is '${message.method}'.`
|
|
459
|
+
};
|
|
460
|
+
if (method !== message.method) return {
|
|
461
|
+
header: "Mcp-Method",
|
|
462
|
+
reason: "mismatched",
|
|
463
|
+
message: `Mcp-Method header does not match the request body method '${message.method}'.`
|
|
464
|
+
};
|
|
465
|
+
if (message.method !== "tools/call") return void 0;
|
|
466
|
+
const name = message.params?.["name"];
|
|
467
|
+
if (!isString(name)) return void 0;
|
|
468
|
+
const header = request.headers.get(MCP_NAME_HEADER);
|
|
469
|
+
if (header === null) return {
|
|
470
|
+
header: "Mcp-Name",
|
|
471
|
+
reason: "missing",
|
|
472
|
+
message: `Required Mcp-Name header is missing; the request body tool name is '${name}'.`
|
|
473
|
+
};
|
|
474
|
+
if (header !== name) return {
|
|
475
|
+
header: "Mcp-Name",
|
|
476
|
+
reason: "mismatched",
|
|
477
|
+
message: `Mcp-Name header does not match the request body tool name '${name}'.`
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
421
481
|
* Infer the legacy revision an `initialize` request negotiates.
|
|
422
482
|
*
|
|
423
483
|
* @remarks
|
|
@@ -589,9 +649,10 @@ function createMCPPostHandler(mcp, options) {
|
|
|
589
649
|
const protocol = request.headers.get(MCP_PROTOCOL_VERSION_HEADER);
|
|
590
650
|
if (era === "modern") {
|
|
591
651
|
if (parseRequestContext(rpcRequest) === void 0) return Response.json(buildJSONRPCError(id, JSONRPC_INVALID_PARAMS, "Invalid params: malformed modern request metadata"), { status: 400 });
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
652
|
+
}
|
|
653
|
+
const issue = inferHeaderIssue(request, rpcRequest);
|
|
654
|
+
if (issue !== void 0) return Response.json(buildJSONRPCError(id, MCP_HEADER_MISMATCH, issue.message), { status: 400 });
|
|
655
|
+
if (era === "legacy") {
|
|
595
656
|
if (protocol !== null && !isMCPVersion(protocol)) return Response.json(buildJSONRPCError(id, MCP_UNSUPPORTED_VERSION, `Unsupported MCP protocol version '${protocol}'`, {
|
|
596
657
|
supported: SUPPORTED_PROTOCOL_VERSIONS,
|
|
597
658
|
requested: protocol
|
|
@@ -1690,11 +1751,11 @@ function createMCPSession(options) {
|
|
|
1690
1751
|
if (!Reflect.set(context.state, "session", entry.session)) throw new Error("MCP session state is not writable");
|
|
1691
1752
|
const headers = new Headers(request.headers);
|
|
1692
1753
|
if (parsed === void 0 || !isInitializeRequest(parsed)) {
|
|
1693
|
-
const
|
|
1694
|
-
if (
|
|
1695
|
-
else if (
|
|
1754
|
+
const issue = inferHeaderIssue(request, entry.version);
|
|
1755
|
+
if (issue?.reason === "missing") headers.set(MCP_PROTOCOL_VERSION_HEADER, entry.version);
|
|
1756
|
+
else if (issue !== void 0) {
|
|
1696
1757
|
const requestId = parsed !== void 0 && "method" in parsed ? parsed.id ?? null : null;
|
|
1697
|
-
return Response.json(buildJSONRPCError(requestId, MCP_HEADER_MISMATCH,
|
|
1758
|
+
return Response.json(buildJSONRPCError(requestId, MCP_HEADER_MISMATCH, issue.message), { status: 400 });
|
|
1698
1759
|
}
|
|
1699
1760
|
}
|
|
1700
1761
|
const response = await next(new Request(context.url, {
|
|
@@ -1712,6 +1773,6 @@ function createMCPSession(options) {
|
|
|
1712
1773
|
};
|
|
1713
1774
|
}
|
|
1714
1775
|
//#endregion
|
|
1715
|
-
export { DEFAULT_MCP_KEEPALIVE_INTERVAL, DEFAULT_MCP_PATH, DEFAULT_MCP_SESSION_CAPACITY, DEFAULT_MCP_SESSION_TTL, HTTPClientTransport, MCPSession, MCP_METHOD_HEADER, MCP_NAME_HEADER, MCP_PROTOCOL_VERSION_HEADER, MCP_SESSION_HEADER, MCP_WEBSOCKET_SUBPROTOCOL, SSE_BUFFERING_DISABLED, SSE_BUFFERING_HEADER, SSE_KEEPALIVE_COMMENT, StdioClientTransport, StdioServerTransport, WebSocketClientTransport, WebSocketServerTransport, acceptsEventStream, allowsOrigin, bridgeMessageTransport, createHTTPClientTransport, createMCPPostHandler, createMCPRoutes, createMCPSession, createReadableStream, createStdioClientTransport, createStdioServer, createWebSocketClientTransport, createWebSocketServer, decodeEvent, dispatchLines, extractLines, inferLegacyVersion, inferStatus,
|
|
1776
|
+
export { DEFAULT_MCP_KEEPALIVE_INTERVAL, DEFAULT_MCP_PATH, DEFAULT_MCP_SESSION_CAPACITY, DEFAULT_MCP_SESSION_TTL, HTTPClientTransport, MCPSession, MCP_METHOD_HEADER, MCP_NAME_HEADER, MCP_PROTOCOL_VERSION_HEADER, MCP_SESSION_HEADER, MCP_WEBSOCKET_SUBPROTOCOL, SSE_BUFFERING_DISABLED, SSE_BUFFERING_HEADER, SSE_KEEPALIVE_COMMENT, StdioClientTransport, StdioServerTransport, WebSocketClientTransport, WebSocketServerTransport, acceptsEventStream, allowsOrigin, bridgeMessageTransport, createHTTPClientTransport, createMCPPostHandler, createMCPRoutes, createMCPSession, createReadableStream, createStdioClientTransport, createStdioServer, createWebSocketClientTransport, createWebSocketServer, decodeEvent, dispatchLines, extractLines, inferHeaderIssue, inferLegacyVersion, inferStatus, readEventStream, readLastEventId, readSessionHeader, rejectUnknownSession, upgradeRequestPath };
|
|
1716
1777
|
|
|
1717
1778
|
//# sourceMappingURL=index.js.map
|