trellis 3.2.2 → 3.2.4
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 +10 -0
- package/README.md +4 -0
- package/dist/better-sqlite-backend-CDYOAJDF.js +209 -0
- package/dist/boot-middleware-LBJX4N2S.js +9 -0
- package/dist/boot-middleware-PATBLD52.js +9 -0
- package/dist/bridge-G5DPW6TY.js +2361 -0
- package/dist/bridge-JSSPQPRH.js +2389 -0
- package/dist/bridge-LNXE4HAW.js +2389 -0
- package/dist/bridge-OAAXJWSA.js +2389 -0
- package/dist/bridge-SFS63RHC.js +2367 -0
- package/dist/bridge-U5TOUBVM.js +2389 -0
- package/dist/browser/index.js +9 -9
- package/dist/{chunk-KSU2GW22.js → chunk-276W52FK.js} +8 -0
- package/dist/{chunk-KFQGP6VL.js → chunk-2ESYSVXG.js} +15 -0
- package/dist/{chunk-L5N5PR2S.js → chunk-2WW2X2BR.js} +313 -77
- package/dist/chunk-3XCOAP6G.js +48 -0
- package/dist/chunk-53PDCTJ3.js +1856 -0
- package/dist/{chunk-N6MYZT4O.js → chunk-547FZFKO.js} +1 -1
- package/dist/{chunk-H6JB3PZ3.js → chunk-5KSGGKET.js} +1 -1
- package/dist/{chunk-J2TXUFCZ.js → chunk-6RWGFC3N.js} +134 -20
- package/dist/{chunk-QB5ISE47.js → chunk-7WVOPXJV.js} +3 -3
- package/dist/chunk-CMSFD6OV.js +11801 -0
- package/dist/{chunk-RSWUFTO2.js → chunk-CPUYCCLT.js} +2 -2
- package/dist/{chunk-4HYPLFJD.js → chunk-FA5TFVA5.js} +1 -1
- package/dist/{chunk-4XIVMVHC.js → chunk-G3XIHPSQ.js} +1 -1
- package/dist/{chunk-JHHEXEDM.js → chunk-GCQF75T4.js} +3 -3
- package/dist/{chunk-FKQO5A3H.js → chunk-GHG4H3AS.js} +2 -2
- package/dist/{chunk-GLM4HGN4.js → chunk-GRWQPKYK.js} +1 -1
- package/dist/{chunk-PZ4XYZ4J.js → chunk-GXA73CNC.js} +33 -8
- package/dist/{chunk-6GEZ6DN5.js → chunk-H6VTC5SS.js} +3 -3
- package/dist/{chunk-S3XLFZ27.js → chunk-IHHSOBJS.js} +1 -1
- package/dist/chunk-IJNC25UD.js +2243 -0
- package/dist/{chunk-VDAKEOML.js → chunk-J6OUIION.js} +1 -1
- package/dist/chunk-JAVAYMMS.js +6 -0
- package/dist/{chunk-S6GBJ2ZB.js → chunk-JCQQFLO5.js} +1 -1
- package/dist/{chunk-FWRS4CSC.js → chunk-KQG6ZYXP.js} +3 -3
- package/dist/chunk-KXAISKZT.js +119 -0
- package/dist/chunk-N3R74ZSR.js +7949 -0
- package/dist/{chunk-GU374KWZ.js → chunk-NLFRRGX6.js} +3 -3
- package/dist/{chunk-XMQ7G77X.js → chunk-OB4CMMX6.js} +1 -1
- package/dist/chunk-OKNASCZY.js +182 -0
- package/dist/chunk-ONOPPX5E.js +394 -0
- package/dist/chunk-QMSU2RAH.js +98 -0
- package/dist/{chunk-TCKXSOBP.js → chunk-RARKFVWU.js} +8 -1
- package/dist/{chunk-2W3MHTMG.js → chunk-SJWVDS5M.js} +835 -127
- package/dist/{chunk-SPSPV5BC.js → chunk-SZ3VAB5P.js} +159 -2
- package/dist/chunk-V2ASD6RQ.js +147 -0
- package/dist/{chunk-KQ4A2D2P.js → chunk-V4YCJDYL.js} +58 -38
- package/dist/{chunk-LNUIGRDZ.js → chunk-VWKLKLYB.js} +1 -1
- package/dist/chunk-W5PADCDF.js +1856 -0
- package/dist/{chunk-MLC5BUYO.js → chunk-WMERMSWI.js} +1 -1
- package/dist/{chunk-IZX2PLIB.js → chunk-WXAURJUD.js} +835 -127
- package/dist/chunk-YC5I32PS.js +147 -0
- package/dist/{chunk-VBYUTRXX.js → chunk-YKVB4LUQ.js} +3 -3
- package/dist/{chunk-7ZFRVCUE.js → chunk-YPT6XMS4.js} +48 -64
- package/dist/cli/deploy-cli.d.ts.map +1 -1
- package/dist/{deploy-cli-C35HTITO.js → cli/deploy-cli.js} +45 -6
- package/dist/cli/gateway-deploy-cli.d.ts +19 -0
- package/dist/cli/gateway-deploy-cli.d.ts.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1363 -884
- package/dist/cli/lane.d.ts.map +1 -1
- package/dist/cli/protocol.d.ts +6 -0
- package/dist/cli/protocol.d.ts.map +1 -0
- package/dist/client/index.browser.js +2 -2
- package/dist/client/index.js +11 -11
- package/dist/client/sdk.browser.d.ts +28 -1
- package/dist/client/sdk.browser.d.ts.map +1 -1
- package/dist/client/sdk.browser.js +2 -2
- package/dist/client/sdk.js +2 -2
- package/dist/cms/index.js +1 -1
- package/dist/config-KMY6RRK3.js +19 -0
- package/dist/core/index.js +17 -17
- package/dist/core/kernel/boot-middleware.d.ts +1 -1
- package/dist/core/kernel/boot-middleware.d.ts.map +1 -1
- package/dist/core/kernel/schema-middleware.d.ts +2 -1
- package/dist/core/kernel/schema-middleware.d.ts.map +1 -1
- package/dist/core/kernel/trellis-kernel.d.ts +10 -10
- package/dist/core/kernel/trellis-kernel.d.ts.map +1 -1
- package/dist/core/persist/factory.js +2 -2
- package/dist/core/persist/sqljs-backend.js +2 -2
- package/dist/db/index.js +32 -27
- package/dist/decisions/index.js +4 -4
- package/dist/embeddings/index.js +2 -2
- package/dist/engine.d.ts +24 -6
- package/dist/engine.d.ts.map +1 -1
- package/dist/gateway-deploy-cli-4TU4V3QI.js +312 -0
- package/dist/gateway-deploy-cli-A4ISTDHJ.js +298 -0
- package/dist/gateway-deploy-cli-D3XTKJQJ.js +312 -0
- package/dist/gateway-deploy-cli-ECV3OQCN.js +305 -0
- package/dist/gateway-deploy-cli-JUHKVIJE.js +296 -0
- package/dist/gateway-deploy-cli-NSDW2JLT.js +310 -0
- package/dist/gateway-serve-CM5EAZ52.js +113 -0
- package/dist/import-AJLYHFIA.js +10 -0
- package/dist/index.js +11 -11
- package/dist/launch-explorer-FVX6ZABW.js +95 -0
- package/dist/links/index.js +2 -2
- package/dist/mcp/bridge.d.ts +45 -0
- package/dist/mcp/bridge.d.ts.map +1 -0
- package/dist/mcp/discovery.d.ts +15 -0
- package/dist/mcp/discovery.d.ts.map +1 -0
- package/dist/mcp/gateway-config.d.ts +20 -0
- package/dist/mcp/gateway-config.d.ts.map +1 -0
- package/dist/mcp/gateway-serve.d.ts +19 -0
- package/dist/mcp/gateway-serve.d.ts.map +1 -0
- package/dist/mcp/gateway-serve.js +119 -0
- package/dist/mcp/graph-summary.d.ts +47 -0
- package/dist/mcp/graph-summary.d.ts.map +1 -0
- package/dist/mcp/room-audit.d.ts +14 -0
- package/dist/mcp/room-audit.d.ts.map +1 -0
- package/dist/mcp/room-helpers.d.ts +43 -0
- package/dist/mcp/room-helpers.d.ts.map +1 -0
- package/dist/mcp/room-registry.d.ts +32 -0
- package/dist/mcp/room-registry.d.ts.map +1 -0
- package/dist/mcp/room.d.ts +28 -0
- package/dist/mcp/room.d.ts.map +1 -0
- package/dist/plugins/agent-memory/index.js +1 -1
- package/dist/plugins/idea-garden/index.js +1 -1
- package/dist/plugins/plan-approval/index.js +1 -1
- package/dist/plugins/proactive-watcher/index.js +1 -1
- package/dist/protocol/envelope.d.ts +30 -0
- package/dist/protocol/envelope.d.ts.map +1 -0
- package/dist/protocol/index.d.ts +3 -0
- package/dist/protocol/index.d.ts.map +1 -0
- package/dist/protocol/whereami.d.ts +33 -0
- package/dist/protocol/whereami.d.ts.map +1 -0
- package/dist/query-KHDDIR5G.js +31 -0
- package/dist/react/index.js +3 -3
- package/dist/react/realtime.js +1 -1
- package/dist/react/schema-hooks.js +6 -6
- package/dist/realtime/index.js +3 -3
- package/dist/realtime/relay-server.d.ts.map +1 -1
- package/dist/realtime/room.d.ts.map +1 -1
- package/dist/realtime.bundle.js +2 -0
- package/dist/relay-server-BT6DCJ7F.js +12 -0
- package/dist/relay-server-MPQVGNQU.js +12 -0
- package/dist/relay-server-PAPW2EWC.js +12 -0
- package/dist/remote-manager-6ERQUBSL.js +224 -0
- package/dist/remote-manager-G665WWYY.js +224 -0
- package/dist/remote-manager-HJTEZ4OF.js +224 -0
- package/dist/remote-manager-NYP2Y5UR.js +224 -0
- package/dist/remote-manager-WGLCAMMC.js +224 -0
- package/dist/scaffold/write.d.ts.map +1 -1
- package/dist/schema/index.js +1 -1
- package/dist/server/cors.d.ts +13 -0
- package/dist/server/cors.d.ts.map +1 -0
- package/dist/server/deploy-gateway.d.ts +27 -0
- package/dist/server/deploy-gateway.d.ts.map +1 -0
- package/dist/server/deploy.d.ts +1 -1
- package/dist/server/deploy.d.ts.map +1 -1
- package/dist/server/deploy.js +10 -0
- package/dist/server/discovery-mcp-gateway.d.ts +13 -0
- package/dist/server/discovery-mcp-gateway.d.ts.map +1 -0
- package/dist/server/index.js +44 -37
- package/dist/server/mcp-gateway.d.ts +27 -0
- package/dist/server/mcp-gateway.d.ts.map +1 -0
- package/dist/server/mcp-oauth-metadata.d.ts +31 -0
- package/dist/server/mcp-oauth-metadata.d.ts.map +1 -0
- package/dist/server/node-adapter.d.ts +7 -0
- package/dist/server/node-adapter.d.ts.map +1 -1
- package/dist/server/node-adapter.js +2 -2
- package/dist/server/realtime.d.ts.map +1 -1
- package/dist/server/server.d.ts +8 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/streamable-mcp-gateway.d.ts +12 -0
- package/dist/server/streamable-mcp-gateway.d.ts.map +1 -0
- package/dist/server/usage-meter.d.ts +11 -0
- package/dist/server/usage-meter.d.ts.map +1 -1
- package/dist/server-4VEZHXXS.js +23 -0
- package/dist/{server-ZVWGLLRF.js → server-556BMK4C.js} +1 -1
- package/dist/server-FQT2VYRE.js +23 -0
- package/dist/server-HGZE4ECC.js +23 -0
- package/dist/server-J4JKEAMH.js +23 -0
- package/dist/server-LXPM5TFR.js +23 -0
- package/dist/{server-MB3OPSPI.js → server-POB4NEUX.js} +2 -2
- package/dist/server-VJKAPGPG.js +23 -0
- package/dist/server-YHS3XIIG.js +23 -0
- package/dist/server-ZHTPWPXS.js +23 -0
- package/dist/sprites-NC6D7YZS.js +27 -0
- package/dist/svelte/index.js +3 -3
- package/dist/svelte/schema-hooks.js +4 -4
- package/dist/sync/index.js +4 -4
- package/dist/tenancy-2SZTP4UD.js +16 -0
- package/dist/tenancy-7MTSESMJ.js +16 -0
- package/dist/tenancy-U4E7ZEAG.js +16 -0
- package/dist/vcs/decompose.d.ts.map +1 -1
- package/dist/vcs/index.js +5 -5
- package/dist/vcs/lane-disk-materialize.d.ts +11 -0
- package/dist/vcs/lane-disk-materialize.d.ts.map +1 -0
- package/dist/vcs/lane-worktree.d.ts +21 -0
- package/dist/vcs/lane-worktree.d.ts.map +1 -0
- package/dist/vcs/store.d.ts +28 -0
- package/dist/vcs/store.d.ts.map +1 -0
- package/dist/vcs/types.d.ts +5 -0
- package/dist/vcs/types.d.ts.map +1 -1
- package/dist/vm-config-YZRJ3KUB.js +21 -0
- package/dist/vue/index.js +3 -3
- package/dist/vue/schema-hooks.js +4 -4
- package/package.json +4 -3
- package/dist/chunk-FF36CQHZ.js +0 -61
- package/dist/chunk-GFZCJ4EH.js +0 -108
- package/dist/chunk-KIJITUZB.js +0 -419
- package/dist/chunk-SGMDTWJJ.js +0 -149
- package/dist/chunk-UQISRW6T.js +0 -203
- package/dist/db/trellis.css +0 -1
- package/dist/deploy-LQ7GUGJ5.js +0 -9
- package/dist/deploy-YNVG5E4E.js +0 -9
- package/dist/deploy-cli-24BCHAXY.js +0 -67
- package/dist/sprites-RU3E4XQN.js +0 -15
- package/dist/tenancy-NBLLGCNJ.js +0 -14
|
@@ -0,0 +1,2367 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AjvJsonSchemaValidator,
|
|
3
|
+
CallToolRequestSchema,
|
|
4
|
+
CallToolResultSchema,
|
|
5
|
+
CompleteResultSchema,
|
|
6
|
+
CreateMessageRequestSchema,
|
|
7
|
+
CreateMessageResultSchema,
|
|
8
|
+
CreateMessageResultWithToolsSchema,
|
|
9
|
+
CreateTaskResultSchema,
|
|
10
|
+
ElicitRequestSchema,
|
|
11
|
+
ElicitResultSchema,
|
|
12
|
+
EmptyResultSchema,
|
|
13
|
+
ErrorCode,
|
|
14
|
+
GetPromptResultSchema,
|
|
15
|
+
InitializeResultSchema,
|
|
16
|
+
JSONRPCMessageSchema,
|
|
17
|
+
LATEST_PROTOCOL_VERSION,
|
|
18
|
+
ListChangedOptionsBaseSchema,
|
|
19
|
+
ListPromptsResultSchema,
|
|
20
|
+
ListResourceTemplatesResultSchema,
|
|
21
|
+
ListResourcesResultSchema,
|
|
22
|
+
ListToolsRequestSchema,
|
|
23
|
+
ListToolsResultSchema,
|
|
24
|
+
McpError,
|
|
25
|
+
PromptListChangedNotificationSchema,
|
|
26
|
+
Protocol,
|
|
27
|
+
ReadResourceResultSchema,
|
|
28
|
+
ResourceListChangedNotificationSchema,
|
|
29
|
+
SUPPORTED_PROTOCOL_VERSIONS,
|
|
30
|
+
Server,
|
|
31
|
+
ToolListChangedNotificationSchema,
|
|
32
|
+
assertClientRequestTaskCapability,
|
|
33
|
+
assertToolsCallTaskCapability,
|
|
34
|
+
getObjectShape,
|
|
35
|
+
isInitializedNotification,
|
|
36
|
+
isJSONRPCRequest,
|
|
37
|
+
isJSONRPCResultResponse,
|
|
38
|
+
isZ4Schema,
|
|
39
|
+
mergeCapabilities,
|
|
40
|
+
safeParse
|
|
41
|
+
} from "./chunk-SXYFXZKZ.js";
|
|
42
|
+
import {
|
|
43
|
+
roomMcpPathForUrl
|
|
44
|
+
} from "./chunk-V2ASD6RQ.js";
|
|
45
|
+
import "./chunk-UZRUP7QW.js";
|
|
46
|
+
import {
|
|
47
|
+
readConfig
|
|
48
|
+
} from "./chunk-JA7AIHRK.js";
|
|
49
|
+
import "./chunk-2ESYSVXG.js";
|
|
50
|
+
|
|
51
|
+
// src/mcp/bridge.ts
|
|
52
|
+
import process2 from "node:process";
|
|
53
|
+
|
|
54
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/client.js
|
|
55
|
+
var ExperimentalClientTasks = class {
|
|
56
|
+
constructor(_client) {
|
|
57
|
+
this._client = _client;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Calls a tool and returns an AsyncGenerator that yields response messages.
|
|
61
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
62
|
+
*
|
|
63
|
+
* This method provides streaming access to tool execution, allowing you to
|
|
64
|
+
* observe intermediate task status updates for long-running tool calls.
|
|
65
|
+
* Automatically validates structured output if the tool has an outputSchema.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const stream = client.experimental.tasks.callToolStream({ name: 'myTool', arguments: {} });
|
|
70
|
+
* for await (const message of stream) {
|
|
71
|
+
* switch (message.type) {
|
|
72
|
+
* case 'taskCreated':
|
|
73
|
+
* console.log('Tool execution started:', message.task.taskId);
|
|
74
|
+
* break;
|
|
75
|
+
* case 'taskStatus':
|
|
76
|
+
* console.log('Tool status:', message.task.status);
|
|
77
|
+
* break;
|
|
78
|
+
* case 'result':
|
|
79
|
+
* console.log('Tool result:', message.result);
|
|
80
|
+
* break;
|
|
81
|
+
* case 'error':
|
|
82
|
+
* console.error('Tool error:', message.error);
|
|
83
|
+
* break;
|
|
84
|
+
* }
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* @param params - Tool call parameters (name and arguments)
|
|
89
|
+
* @param resultSchema - Zod schema for validating the result (defaults to CallToolResultSchema)
|
|
90
|
+
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
91
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
92
|
+
*
|
|
93
|
+
* @experimental
|
|
94
|
+
*/
|
|
95
|
+
async *callToolStream(params, resultSchema = CallToolResultSchema, options) {
|
|
96
|
+
const clientInternal = this._client;
|
|
97
|
+
const optionsWithTask = {
|
|
98
|
+
...options,
|
|
99
|
+
// We check if the tool is known to be a task during auto-configuration, but assume
|
|
100
|
+
// the caller knows what they're doing if they pass this explicitly
|
|
101
|
+
task: options?.task ?? (clientInternal.isToolTask(params.name) ? {} : void 0)
|
|
102
|
+
};
|
|
103
|
+
const stream = clientInternal.requestStream({ method: "tools/call", params }, resultSchema, optionsWithTask);
|
|
104
|
+
const validator = clientInternal.getToolOutputValidator(params.name);
|
|
105
|
+
for await (const message of stream) {
|
|
106
|
+
if (message.type === "result" && validator) {
|
|
107
|
+
const result = message.result;
|
|
108
|
+
if (!result.structuredContent && !result.isError) {
|
|
109
|
+
yield {
|
|
110
|
+
type: "error",
|
|
111
|
+
error: new McpError(ErrorCode.InvalidRequest, `Tool ${params.name} has an output schema but did not return structured content`)
|
|
112
|
+
};
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (result.structuredContent) {
|
|
116
|
+
try {
|
|
117
|
+
const validationResult = validator(result.structuredContent);
|
|
118
|
+
if (!validationResult.valid) {
|
|
119
|
+
yield {
|
|
120
|
+
type: "error",
|
|
121
|
+
error: new McpError(ErrorCode.InvalidParams, `Structured content does not match the tool's output schema: ${validationResult.errorMessage}`)
|
|
122
|
+
};
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (error instanceof McpError) {
|
|
127
|
+
yield { type: "error", error };
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
yield {
|
|
131
|
+
type: "error",
|
|
132
|
+
error: new McpError(ErrorCode.InvalidParams, `Failed to validate structured content: ${error instanceof Error ? error.message : String(error)}`)
|
|
133
|
+
};
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
yield message;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Gets the current status of a task.
|
|
143
|
+
*
|
|
144
|
+
* @param taskId - The task identifier
|
|
145
|
+
* @param options - Optional request options
|
|
146
|
+
* @returns The task status
|
|
147
|
+
*
|
|
148
|
+
* @experimental
|
|
149
|
+
*/
|
|
150
|
+
async getTask(taskId, options) {
|
|
151
|
+
return this._client.getTask({ taskId }, options);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Retrieves the result of a completed task.
|
|
155
|
+
*
|
|
156
|
+
* @param taskId - The task identifier
|
|
157
|
+
* @param resultSchema - Zod schema for validating the result
|
|
158
|
+
* @param options - Optional request options
|
|
159
|
+
* @returns The task result
|
|
160
|
+
*
|
|
161
|
+
* @experimental
|
|
162
|
+
*/
|
|
163
|
+
async getTaskResult(taskId, resultSchema, options) {
|
|
164
|
+
return this._client.getTaskResult({ taskId }, resultSchema, options);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Lists tasks with optional pagination.
|
|
168
|
+
*
|
|
169
|
+
* @param cursor - Optional pagination cursor
|
|
170
|
+
* @param options - Optional request options
|
|
171
|
+
* @returns List of tasks with optional next cursor
|
|
172
|
+
*
|
|
173
|
+
* @experimental
|
|
174
|
+
*/
|
|
175
|
+
async listTasks(cursor, options) {
|
|
176
|
+
return this._client.listTasks(cursor ? { cursor } : void 0, options);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Cancels a running task.
|
|
180
|
+
*
|
|
181
|
+
* @param taskId - The task identifier
|
|
182
|
+
* @param options - Optional request options
|
|
183
|
+
*
|
|
184
|
+
* @experimental
|
|
185
|
+
*/
|
|
186
|
+
async cancelTask(taskId, options) {
|
|
187
|
+
return this._client.cancelTask({ taskId }, options);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Sends a request and returns an AsyncGenerator that yields response messages.
|
|
191
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
192
|
+
*
|
|
193
|
+
* This method provides streaming access to request processing, allowing you to
|
|
194
|
+
* observe intermediate task status updates for task-augmented requests.
|
|
195
|
+
*
|
|
196
|
+
* @param request - The request to send
|
|
197
|
+
* @param resultSchema - Zod schema for validating the result
|
|
198
|
+
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
199
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
200
|
+
*
|
|
201
|
+
* @experimental
|
|
202
|
+
*/
|
|
203
|
+
requestStream(request, resultSchema, options) {
|
|
204
|
+
return this._client.requestStream(request, resultSchema, options);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.js
|
|
209
|
+
function applyElicitationDefaults(schema, data) {
|
|
210
|
+
if (!schema || data === null || typeof data !== "object")
|
|
211
|
+
return;
|
|
212
|
+
if (schema.type === "object" && schema.properties && typeof schema.properties === "object") {
|
|
213
|
+
const obj = data;
|
|
214
|
+
const props = schema.properties;
|
|
215
|
+
for (const key of Object.keys(props)) {
|
|
216
|
+
const propSchema = props[key];
|
|
217
|
+
if (obj[key] === void 0 && Object.prototype.hasOwnProperty.call(propSchema, "default")) {
|
|
218
|
+
obj[key] = propSchema.default;
|
|
219
|
+
}
|
|
220
|
+
if (obj[key] !== void 0) {
|
|
221
|
+
applyElicitationDefaults(propSchema, obj[key]);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (Array.isArray(schema.anyOf)) {
|
|
226
|
+
for (const sub of schema.anyOf) {
|
|
227
|
+
if (typeof sub !== "boolean") {
|
|
228
|
+
applyElicitationDefaults(sub, data);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (Array.isArray(schema.oneOf)) {
|
|
233
|
+
for (const sub of schema.oneOf) {
|
|
234
|
+
if (typeof sub !== "boolean") {
|
|
235
|
+
applyElicitationDefaults(sub, data);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function getSupportedElicitationModes(capabilities) {
|
|
241
|
+
if (!capabilities) {
|
|
242
|
+
return { supportsFormMode: false, supportsUrlMode: false };
|
|
243
|
+
}
|
|
244
|
+
const hasFormCapability = capabilities.form !== void 0;
|
|
245
|
+
const hasUrlCapability = capabilities.url !== void 0;
|
|
246
|
+
const supportsFormMode = hasFormCapability || !hasFormCapability && !hasUrlCapability;
|
|
247
|
+
const supportsUrlMode = hasUrlCapability;
|
|
248
|
+
return { supportsFormMode, supportsUrlMode };
|
|
249
|
+
}
|
|
250
|
+
var Client = class extends Protocol {
|
|
251
|
+
/**
|
|
252
|
+
* Initializes this client with the given name and version information.
|
|
253
|
+
*/
|
|
254
|
+
constructor(_clientInfo, options) {
|
|
255
|
+
super(options);
|
|
256
|
+
this._clientInfo = _clientInfo;
|
|
257
|
+
this._cachedToolOutputValidators = /* @__PURE__ */ new Map();
|
|
258
|
+
this._cachedKnownTaskTools = /* @__PURE__ */ new Set();
|
|
259
|
+
this._cachedRequiredTaskTools = /* @__PURE__ */ new Set();
|
|
260
|
+
this._listChangedDebounceTimers = /* @__PURE__ */ new Map();
|
|
261
|
+
this._capabilities = options?.capabilities ?? {};
|
|
262
|
+
this._jsonSchemaValidator = options?.jsonSchemaValidator ?? new AjvJsonSchemaValidator();
|
|
263
|
+
if (options?.listChanged) {
|
|
264
|
+
this._pendingListChangedConfig = options.listChanged;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Set up handlers for list changed notifications based on config and server capabilities.
|
|
269
|
+
* This should only be called after initialization when server capabilities are known.
|
|
270
|
+
* Handlers are silently skipped if the server doesn't advertise the corresponding listChanged capability.
|
|
271
|
+
* @internal
|
|
272
|
+
*/
|
|
273
|
+
_setupListChangedHandlers(config) {
|
|
274
|
+
if (config.tools && this._serverCapabilities?.tools?.listChanged) {
|
|
275
|
+
this._setupListChangedHandler("tools", ToolListChangedNotificationSchema, config.tools, async () => {
|
|
276
|
+
const result = await this.listTools();
|
|
277
|
+
return result.tools;
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
if (config.prompts && this._serverCapabilities?.prompts?.listChanged) {
|
|
281
|
+
this._setupListChangedHandler("prompts", PromptListChangedNotificationSchema, config.prompts, async () => {
|
|
282
|
+
const result = await this.listPrompts();
|
|
283
|
+
return result.prompts;
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
if (config.resources && this._serverCapabilities?.resources?.listChanged) {
|
|
287
|
+
this._setupListChangedHandler("resources", ResourceListChangedNotificationSchema, config.resources, async () => {
|
|
288
|
+
const result = await this.listResources();
|
|
289
|
+
return result.resources;
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Access experimental features.
|
|
295
|
+
*
|
|
296
|
+
* WARNING: These APIs are experimental and may change without notice.
|
|
297
|
+
*
|
|
298
|
+
* @experimental
|
|
299
|
+
*/
|
|
300
|
+
get experimental() {
|
|
301
|
+
if (!this._experimental) {
|
|
302
|
+
this._experimental = {
|
|
303
|
+
tasks: new ExperimentalClientTasks(this)
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
return this._experimental;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Registers new capabilities. This can only be called before connecting to a transport.
|
|
310
|
+
*
|
|
311
|
+
* The new capabilities will be merged with any existing capabilities previously given (e.g., at initialization).
|
|
312
|
+
*/
|
|
313
|
+
registerCapabilities(capabilities) {
|
|
314
|
+
if (this.transport) {
|
|
315
|
+
throw new Error("Cannot register capabilities after connecting to transport");
|
|
316
|
+
}
|
|
317
|
+
this._capabilities = mergeCapabilities(this._capabilities, capabilities);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Override request handler registration to enforce client-side validation for elicitation.
|
|
321
|
+
*/
|
|
322
|
+
setRequestHandler(requestSchema, handler) {
|
|
323
|
+
const shape = getObjectShape(requestSchema);
|
|
324
|
+
const methodSchema = shape?.method;
|
|
325
|
+
if (!methodSchema) {
|
|
326
|
+
throw new Error("Schema is missing a method literal");
|
|
327
|
+
}
|
|
328
|
+
let methodValue;
|
|
329
|
+
if (isZ4Schema(methodSchema)) {
|
|
330
|
+
const v4Schema = methodSchema;
|
|
331
|
+
const v4Def = v4Schema._zod?.def;
|
|
332
|
+
methodValue = v4Def?.value ?? v4Schema.value;
|
|
333
|
+
} else {
|
|
334
|
+
const v3Schema = methodSchema;
|
|
335
|
+
const legacyDef = v3Schema._def;
|
|
336
|
+
methodValue = legacyDef?.value ?? v3Schema.value;
|
|
337
|
+
}
|
|
338
|
+
if (typeof methodValue !== "string") {
|
|
339
|
+
throw new Error("Schema method literal must be a string");
|
|
340
|
+
}
|
|
341
|
+
const method = methodValue;
|
|
342
|
+
if (method === "elicitation/create") {
|
|
343
|
+
const wrappedHandler = async (request, extra) => {
|
|
344
|
+
const validatedRequest = safeParse(ElicitRequestSchema, request);
|
|
345
|
+
if (!validatedRequest.success) {
|
|
346
|
+
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
347
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid elicitation request: ${errorMessage}`);
|
|
348
|
+
}
|
|
349
|
+
const { params } = validatedRequest.data;
|
|
350
|
+
params.mode = params.mode ?? "form";
|
|
351
|
+
const { supportsFormMode, supportsUrlMode } = getSupportedElicitationModes(this._capabilities.elicitation);
|
|
352
|
+
if (params.mode === "form" && !supportsFormMode) {
|
|
353
|
+
throw new McpError(ErrorCode.InvalidParams, "Client does not support form-mode elicitation requests");
|
|
354
|
+
}
|
|
355
|
+
if (params.mode === "url" && !supportsUrlMode) {
|
|
356
|
+
throw new McpError(ErrorCode.InvalidParams, "Client does not support URL-mode elicitation requests");
|
|
357
|
+
}
|
|
358
|
+
const result = await Promise.resolve(handler(request, extra));
|
|
359
|
+
if (params.task) {
|
|
360
|
+
const taskValidationResult = safeParse(CreateTaskResultSchema, result);
|
|
361
|
+
if (!taskValidationResult.success) {
|
|
362
|
+
const errorMessage = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
|
|
363
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
|
|
364
|
+
}
|
|
365
|
+
return taskValidationResult.data;
|
|
366
|
+
}
|
|
367
|
+
const validationResult = safeParse(ElicitResultSchema, result);
|
|
368
|
+
if (!validationResult.success) {
|
|
369
|
+
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
370
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid elicitation result: ${errorMessage}`);
|
|
371
|
+
}
|
|
372
|
+
const validatedResult = validationResult.data;
|
|
373
|
+
const requestedSchema = params.mode === "form" ? params.requestedSchema : void 0;
|
|
374
|
+
if (params.mode === "form" && validatedResult.action === "accept" && validatedResult.content && requestedSchema) {
|
|
375
|
+
if (this._capabilities.elicitation?.form?.applyDefaults) {
|
|
376
|
+
try {
|
|
377
|
+
applyElicitationDefaults(requestedSchema, validatedResult.content);
|
|
378
|
+
} catch {
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return validatedResult;
|
|
383
|
+
};
|
|
384
|
+
return super.setRequestHandler(requestSchema, wrappedHandler);
|
|
385
|
+
}
|
|
386
|
+
if (method === "sampling/createMessage") {
|
|
387
|
+
const wrappedHandler = async (request, extra) => {
|
|
388
|
+
const validatedRequest = safeParse(CreateMessageRequestSchema, request);
|
|
389
|
+
if (!validatedRequest.success) {
|
|
390
|
+
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
391
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid sampling request: ${errorMessage}`);
|
|
392
|
+
}
|
|
393
|
+
const { params } = validatedRequest.data;
|
|
394
|
+
const result = await Promise.resolve(handler(request, extra));
|
|
395
|
+
if (params.task) {
|
|
396
|
+
const taskValidationResult = safeParse(CreateTaskResultSchema, result);
|
|
397
|
+
if (!taskValidationResult.success) {
|
|
398
|
+
const errorMessage = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
|
|
399
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
|
|
400
|
+
}
|
|
401
|
+
return taskValidationResult.data;
|
|
402
|
+
}
|
|
403
|
+
const hasTools = params.tools || params.toolChoice;
|
|
404
|
+
const resultSchema = hasTools ? CreateMessageResultWithToolsSchema : CreateMessageResultSchema;
|
|
405
|
+
const validationResult = safeParse(resultSchema, result);
|
|
406
|
+
if (!validationResult.success) {
|
|
407
|
+
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
408
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid sampling result: ${errorMessage}`);
|
|
409
|
+
}
|
|
410
|
+
return validationResult.data;
|
|
411
|
+
};
|
|
412
|
+
return super.setRequestHandler(requestSchema, wrappedHandler);
|
|
413
|
+
}
|
|
414
|
+
return super.setRequestHandler(requestSchema, handler);
|
|
415
|
+
}
|
|
416
|
+
assertCapability(capability, method) {
|
|
417
|
+
if (!this._serverCapabilities?.[capability]) {
|
|
418
|
+
throw new Error(`Server does not support ${capability} (required for ${method})`);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
async connect(transport, options) {
|
|
422
|
+
await super.connect(transport);
|
|
423
|
+
if (transport.sessionId !== void 0) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
const result = await this.request({
|
|
428
|
+
method: "initialize",
|
|
429
|
+
params: {
|
|
430
|
+
protocolVersion: LATEST_PROTOCOL_VERSION,
|
|
431
|
+
capabilities: this._capabilities,
|
|
432
|
+
clientInfo: this._clientInfo
|
|
433
|
+
}
|
|
434
|
+
}, InitializeResultSchema, options);
|
|
435
|
+
if (result === void 0) {
|
|
436
|
+
throw new Error(`Server sent invalid initialize result: ${result}`);
|
|
437
|
+
}
|
|
438
|
+
if (!SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion)) {
|
|
439
|
+
throw new Error(`Server's protocol version is not supported: ${result.protocolVersion}`);
|
|
440
|
+
}
|
|
441
|
+
this._serverCapabilities = result.capabilities;
|
|
442
|
+
this._serverVersion = result.serverInfo;
|
|
443
|
+
if (transport.setProtocolVersion) {
|
|
444
|
+
transport.setProtocolVersion(result.protocolVersion);
|
|
445
|
+
}
|
|
446
|
+
this._instructions = result.instructions;
|
|
447
|
+
await this.notification({
|
|
448
|
+
method: "notifications/initialized"
|
|
449
|
+
});
|
|
450
|
+
if (this._pendingListChangedConfig) {
|
|
451
|
+
this._setupListChangedHandlers(this._pendingListChangedConfig);
|
|
452
|
+
this._pendingListChangedConfig = void 0;
|
|
453
|
+
}
|
|
454
|
+
} catch (error) {
|
|
455
|
+
void this.close();
|
|
456
|
+
throw error;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* After initialization has completed, this will be populated with the server's reported capabilities.
|
|
461
|
+
*/
|
|
462
|
+
getServerCapabilities() {
|
|
463
|
+
return this._serverCapabilities;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* After initialization has completed, this will be populated with information about the server's name and version.
|
|
467
|
+
*/
|
|
468
|
+
getServerVersion() {
|
|
469
|
+
return this._serverVersion;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* After initialization has completed, this may be populated with information about the server's instructions.
|
|
473
|
+
*/
|
|
474
|
+
getInstructions() {
|
|
475
|
+
return this._instructions;
|
|
476
|
+
}
|
|
477
|
+
assertCapabilityForMethod(method) {
|
|
478
|
+
switch (method) {
|
|
479
|
+
case "logging/setLevel":
|
|
480
|
+
if (!this._serverCapabilities?.logging) {
|
|
481
|
+
throw new Error(`Server does not support logging (required for ${method})`);
|
|
482
|
+
}
|
|
483
|
+
break;
|
|
484
|
+
case "prompts/get":
|
|
485
|
+
case "prompts/list":
|
|
486
|
+
if (!this._serverCapabilities?.prompts) {
|
|
487
|
+
throw new Error(`Server does not support prompts (required for ${method})`);
|
|
488
|
+
}
|
|
489
|
+
break;
|
|
490
|
+
case "resources/list":
|
|
491
|
+
case "resources/templates/list":
|
|
492
|
+
case "resources/read":
|
|
493
|
+
case "resources/subscribe":
|
|
494
|
+
case "resources/unsubscribe":
|
|
495
|
+
if (!this._serverCapabilities?.resources) {
|
|
496
|
+
throw new Error(`Server does not support resources (required for ${method})`);
|
|
497
|
+
}
|
|
498
|
+
if (method === "resources/subscribe" && !this._serverCapabilities.resources.subscribe) {
|
|
499
|
+
throw new Error(`Server does not support resource subscriptions (required for ${method})`);
|
|
500
|
+
}
|
|
501
|
+
break;
|
|
502
|
+
case "tools/call":
|
|
503
|
+
case "tools/list":
|
|
504
|
+
if (!this._serverCapabilities?.tools) {
|
|
505
|
+
throw new Error(`Server does not support tools (required for ${method})`);
|
|
506
|
+
}
|
|
507
|
+
break;
|
|
508
|
+
case "completion/complete":
|
|
509
|
+
if (!this._serverCapabilities?.completions) {
|
|
510
|
+
throw new Error(`Server does not support completions (required for ${method})`);
|
|
511
|
+
}
|
|
512
|
+
break;
|
|
513
|
+
case "initialize":
|
|
514
|
+
break;
|
|
515
|
+
case "ping":
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
assertNotificationCapability(method) {
|
|
520
|
+
switch (method) {
|
|
521
|
+
case "notifications/roots/list_changed":
|
|
522
|
+
if (!this._capabilities.roots?.listChanged) {
|
|
523
|
+
throw new Error(`Client does not support roots list changed notifications (required for ${method})`);
|
|
524
|
+
}
|
|
525
|
+
break;
|
|
526
|
+
case "notifications/initialized":
|
|
527
|
+
break;
|
|
528
|
+
case "notifications/cancelled":
|
|
529
|
+
break;
|
|
530
|
+
case "notifications/progress":
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
assertRequestHandlerCapability(method) {
|
|
535
|
+
if (!this._capabilities) {
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
switch (method) {
|
|
539
|
+
case "sampling/createMessage":
|
|
540
|
+
if (!this._capabilities.sampling) {
|
|
541
|
+
throw new Error(`Client does not support sampling capability (required for ${method})`);
|
|
542
|
+
}
|
|
543
|
+
break;
|
|
544
|
+
case "elicitation/create":
|
|
545
|
+
if (!this._capabilities.elicitation) {
|
|
546
|
+
throw new Error(`Client does not support elicitation capability (required for ${method})`);
|
|
547
|
+
}
|
|
548
|
+
break;
|
|
549
|
+
case "roots/list":
|
|
550
|
+
if (!this._capabilities.roots) {
|
|
551
|
+
throw new Error(`Client does not support roots capability (required for ${method})`);
|
|
552
|
+
}
|
|
553
|
+
break;
|
|
554
|
+
case "tasks/get":
|
|
555
|
+
case "tasks/list":
|
|
556
|
+
case "tasks/result":
|
|
557
|
+
case "tasks/cancel":
|
|
558
|
+
if (!this._capabilities.tasks) {
|
|
559
|
+
throw new Error(`Client does not support tasks capability (required for ${method})`);
|
|
560
|
+
}
|
|
561
|
+
break;
|
|
562
|
+
case "ping":
|
|
563
|
+
break;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
assertTaskCapability(method) {
|
|
567
|
+
assertToolsCallTaskCapability(this._serverCapabilities?.tasks?.requests, method, "Server");
|
|
568
|
+
}
|
|
569
|
+
assertTaskHandlerCapability(method) {
|
|
570
|
+
if (!this._capabilities) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
assertClientRequestTaskCapability(this._capabilities.tasks?.requests, method, "Client");
|
|
574
|
+
}
|
|
575
|
+
async ping(options) {
|
|
576
|
+
return this.request({ method: "ping" }, EmptyResultSchema, options);
|
|
577
|
+
}
|
|
578
|
+
async complete(params, options) {
|
|
579
|
+
return this.request({ method: "completion/complete", params }, CompleteResultSchema, options);
|
|
580
|
+
}
|
|
581
|
+
async setLoggingLevel(level, options) {
|
|
582
|
+
return this.request({ method: "logging/setLevel", params: { level } }, EmptyResultSchema, options);
|
|
583
|
+
}
|
|
584
|
+
async getPrompt(params, options) {
|
|
585
|
+
return this.request({ method: "prompts/get", params }, GetPromptResultSchema, options);
|
|
586
|
+
}
|
|
587
|
+
async listPrompts(params, options) {
|
|
588
|
+
return this.request({ method: "prompts/list", params }, ListPromptsResultSchema, options);
|
|
589
|
+
}
|
|
590
|
+
async listResources(params, options) {
|
|
591
|
+
return this.request({ method: "resources/list", params }, ListResourcesResultSchema, options);
|
|
592
|
+
}
|
|
593
|
+
async listResourceTemplates(params, options) {
|
|
594
|
+
return this.request({ method: "resources/templates/list", params }, ListResourceTemplatesResultSchema, options);
|
|
595
|
+
}
|
|
596
|
+
async readResource(params, options) {
|
|
597
|
+
return this.request({ method: "resources/read", params }, ReadResourceResultSchema, options);
|
|
598
|
+
}
|
|
599
|
+
async subscribeResource(params, options) {
|
|
600
|
+
return this.request({ method: "resources/subscribe", params }, EmptyResultSchema, options);
|
|
601
|
+
}
|
|
602
|
+
async unsubscribeResource(params, options) {
|
|
603
|
+
return this.request({ method: "resources/unsubscribe", params }, EmptyResultSchema, options);
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Calls a tool and waits for the result. Automatically validates structured output if the tool has an outputSchema.
|
|
607
|
+
*
|
|
608
|
+
* For task-based execution with streaming behavior, use client.experimental.tasks.callToolStream() instead.
|
|
609
|
+
*/
|
|
610
|
+
async callTool(params, resultSchema = CallToolResultSchema, options) {
|
|
611
|
+
if (this.isToolTaskRequired(params.name)) {
|
|
612
|
+
throw new McpError(ErrorCode.InvalidRequest, `Tool "${params.name}" requires task-based execution. Use client.experimental.tasks.callToolStream() instead.`);
|
|
613
|
+
}
|
|
614
|
+
const result = await this.request({ method: "tools/call", params }, resultSchema, options);
|
|
615
|
+
const validator = this.getToolOutputValidator(params.name);
|
|
616
|
+
if (validator) {
|
|
617
|
+
if (!result.structuredContent && !result.isError) {
|
|
618
|
+
throw new McpError(ErrorCode.InvalidRequest, `Tool ${params.name} has an output schema but did not return structured content`);
|
|
619
|
+
}
|
|
620
|
+
if (result.structuredContent) {
|
|
621
|
+
try {
|
|
622
|
+
const validationResult = validator(result.structuredContent);
|
|
623
|
+
if (!validationResult.valid) {
|
|
624
|
+
throw new McpError(ErrorCode.InvalidParams, `Structured content does not match the tool's output schema: ${validationResult.errorMessage}`);
|
|
625
|
+
}
|
|
626
|
+
} catch (error) {
|
|
627
|
+
if (error instanceof McpError) {
|
|
628
|
+
throw error;
|
|
629
|
+
}
|
|
630
|
+
throw new McpError(ErrorCode.InvalidParams, `Failed to validate structured content: ${error instanceof Error ? error.message : String(error)}`);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
return result;
|
|
635
|
+
}
|
|
636
|
+
isToolTask(toolName) {
|
|
637
|
+
if (!this._serverCapabilities?.tasks?.requests?.tools?.call) {
|
|
638
|
+
return false;
|
|
639
|
+
}
|
|
640
|
+
return this._cachedKnownTaskTools.has(toolName);
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Check if a tool requires task-based execution.
|
|
644
|
+
* Unlike isToolTask which includes 'optional' tools, this only checks for 'required'.
|
|
645
|
+
*/
|
|
646
|
+
isToolTaskRequired(toolName) {
|
|
647
|
+
return this._cachedRequiredTaskTools.has(toolName);
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Cache validators for tool output schemas.
|
|
651
|
+
* Called after listTools() to pre-compile validators for better performance.
|
|
652
|
+
*/
|
|
653
|
+
cacheToolMetadata(tools) {
|
|
654
|
+
this._cachedToolOutputValidators.clear();
|
|
655
|
+
this._cachedKnownTaskTools.clear();
|
|
656
|
+
this._cachedRequiredTaskTools.clear();
|
|
657
|
+
for (const tool of tools) {
|
|
658
|
+
if (tool.outputSchema) {
|
|
659
|
+
const toolValidator = this._jsonSchemaValidator.getValidator(tool.outputSchema);
|
|
660
|
+
this._cachedToolOutputValidators.set(tool.name, toolValidator);
|
|
661
|
+
}
|
|
662
|
+
const taskSupport = tool.execution?.taskSupport;
|
|
663
|
+
if (taskSupport === "required" || taskSupport === "optional") {
|
|
664
|
+
this._cachedKnownTaskTools.add(tool.name);
|
|
665
|
+
}
|
|
666
|
+
if (taskSupport === "required") {
|
|
667
|
+
this._cachedRequiredTaskTools.add(tool.name);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Get cached validator for a tool
|
|
673
|
+
*/
|
|
674
|
+
getToolOutputValidator(toolName) {
|
|
675
|
+
return this._cachedToolOutputValidators.get(toolName);
|
|
676
|
+
}
|
|
677
|
+
async listTools(params, options) {
|
|
678
|
+
const result = await this.request({ method: "tools/list", params }, ListToolsResultSchema, options);
|
|
679
|
+
this.cacheToolMetadata(result.tools);
|
|
680
|
+
return result;
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Set up a single list changed handler.
|
|
684
|
+
* @internal
|
|
685
|
+
*/
|
|
686
|
+
_setupListChangedHandler(listType, notificationSchema, options, fetcher) {
|
|
687
|
+
const parseResult = ListChangedOptionsBaseSchema.safeParse(options);
|
|
688
|
+
if (!parseResult.success) {
|
|
689
|
+
throw new Error(`Invalid ${listType} listChanged options: ${parseResult.error.message}`);
|
|
690
|
+
}
|
|
691
|
+
if (typeof options.onChanged !== "function") {
|
|
692
|
+
throw new Error(`Invalid ${listType} listChanged options: onChanged must be a function`);
|
|
693
|
+
}
|
|
694
|
+
const { autoRefresh, debounceMs } = parseResult.data;
|
|
695
|
+
const { onChanged } = options;
|
|
696
|
+
const refresh = async () => {
|
|
697
|
+
if (!autoRefresh) {
|
|
698
|
+
onChanged(null, null);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
try {
|
|
702
|
+
const items = await fetcher();
|
|
703
|
+
onChanged(null, items);
|
|
704
|
+
} catch (e) {
|
|
705
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
706
|
+
onChanged(error, null);
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
const handler = () => {
|
|
710
|
+
if (debounceMs) {
|
|
711
|
+
const existingTimer = this._listChangedDebounceTimers.get(listType);
|
|
712
|
+
if (existingTimer) {
|
|
713
|
+
clearTimeout(existingTimer);
|
|
714
|
+
}
|
|
715
|
+
const timer = setTimeout(refresh, debounceMs);
|
|
716
|
+
this._listChangedDebounceTimers.set(listType, timer);
|
|
717
|
+
} else {
|
|
718
|
+
refresh();
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
this.setNotificationHandler(notificationSchema, handler);
|
|
722
|
+
}
|
|
723
|
+
async sendRootsListChanged() {
|
|
724
|
+
return this.notification({ method: "notifications/roots/list_changed" });
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
|
|
728
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/transport.js
|
|
729
|
+
function normalizeHeaders(headers) {
|
|
730
|
+
if (!headers)
|
|
731
|
+
return {};
|
|
732
|
+
if (headers instanceof Headers) {
|
|
733
|
+
return Object.fromEntries(headers.entries());
|
|
734
|
+
}
|
|
735
|
+
if (Array.isArray(headers)) {
|
|
736
|
+
return Object.fromEntries(headers);
|
|
737
|
+
}
|
|
738
|
+
return { ...headers };
|
|
739
|
+
}
|
|
740
|
+
function createFetchWithInit(baseFetch = fetch, baseInit) {
|
|
741
|
+
if (!baseInit) {
|
|
742
|
+
return baseFetch;
|
|
743
|
+
}
|
|
744
|
+
return async (url2, init) => {
|
|
745
|
+
const mergedInit = {
|
|
746
|
+
...baseInit,
|
|
747
|
+
...init,
|
|
748
|
+
// Headers need special handling - merge instead of replace
|
|
749
|
+
headers: init?.headers ? { ...normalizeHeaders(baseInit.headers), ...normalizeHeaders(init.headers) } : baseInit.headers
|
|
750
|
+
};
|
|
751
|
+
return baseFetch(url2, mergedInit);
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// node_modules/.pnpm/pkce-challenge@5.0.1/node_modules/pkce-challenge/dist/index.node.js
|
|
756
|
+
var crypto;
|
|
757
|
+
crypto = globalThis.crypto?.webcrypto ?? // Node.js [18-16] REPL
|
|
758
|
+
globalThis.crypto ?? // Node.js >18
|
|
759
|
+
import("node:crypto").then((m) => m.webcrypto);
|
|
760
|
+
async function getRandomValues(size) {
|
|
761
|
+
return (await crypto).getRandomValues(new Uint8Array(size));
|
|
762
|
+
}
|
|
763
|
+
async function random(size) {
|
|
764
|
+
const mask = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
|
|
765
|
+
const evenDistCutoff = Math.pow(2, 8) - Math.pow(2, 8) % mask.length;
|
|
766
|
+
let result = "";
|
|
767
|
+
while (result.length < size) {
|
|
768
|
+
const randomBytes = await getRandomValues(size - result.length);
|
|
769
|
+
for (const randomByte of randomBytes) {
|
|
770
|
+
if (randomByte < evenDistCutoff) {
|
|
771
|
+
result += mask[randomByte % mask.length];
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
return result;
|
|
776
|
+
}
|
|
777
|
+
async function generateVerifier(length) {
|
|
778
|
+
return await random(length);
|
|
779
|
+
}
|
|
780
|
+
async function generateChallenge(code_verifier) {
|
|
781
|
+
const buffer = await (await crypto).subtle.digest("SHA-256", new TextEncoder().encode(code_verifier));
|
|
782
|
+
return btoa(String.fromCharCode(...new Uint8Array(buffer))).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
|
|
783
|
+
}
|
|
784
|
+
async function pkceChallenge(length) {
|
|
785
|
+
if (!length)
|
|
786
|
+
length = 43;
|
|
787
|
+
if (length < 43 || length > 128) {
|
|
788
|
+
throw `Expected a length between 43 and 128. Received ${length}.`;
|
|
789
|
+
}
|
|
790
|
+
const verifier = await generateVerifier(length);
|
|
791
|
+
const challenge = await generateChallenge(verifier);
|
|
792
|
+
return {
|
|
793
|
+
code_verifier: verifier,
|
|
794
|
+
code_challenge: challenge
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.js
|
|
799
|
+
import * as z from "zod/v4";
|
|
800
|
+
var SafeUrlSchema = z.url().superRefine((val, ctx) => {
|
|
801
|
+
if (!URL.canParse(val)) {
|
|
802
|
+
ctx.addIssue({
|
|
803
|
+
code: z.ZodIssueCode.custom,
|
|
804
|
+
message: "URL must be parseable",
|
|
805
|
+
fatal: true
|
|
806
|
+
});
|
|
807
|
+
return z.NEVER;
|
|
808
|
+
}
|
|
809
|
+
}).refine((url2) => {
|
|
810
|
+
const u = new URL(url2);
|
|
811
|
+
return u.protocol !== "javascript:" && u.protocol !== "data:" && u.protocol !== "vbscript:";
|
|
812
|
+
}, { message: "URL cannot use javascript:, data:, or vbscript: scheme" });
|
|
813
|
+
var OAuthProtectedResourceMetadataSchema = z.looseObject({
|
|
814
|
+
resource: z.string().url(),
|
|
815
|
+
authorization_servers: z.array(SafeUrlSchema).optional(),
|
|
816
|
+
jwks_uri: z.string().url().optional(),
|
|
817
|
+
scopes_supported: z.array(z.string()).optional(),
|
|
818
|
+
bearer_methods_supported: z.array(z.string()).optional(),
|
|
819
|
+
resource_signing_alg_values_supported: z.array(z.string()).optional(),
|
|
820
|
+
resource_name: z.string().optional(),
|
|
821
|
+
resource_documentation: z.string().optional(),
|
|
822
|
+
resource_policy_uri: z.string().url().optional(),
|
|
823
|
+
resource_tos_uri: z.string().url().optional(),
|
|
824
|
+
tls_client_certificate_bound_access_tokens: z.boolean().optional(),
|
|
825
|
+
authorization_details_types_supported: z.array(z.string()).optional(),
|
|
826
|
+
dpop_signing_alg_values_supported: z.array(z.string()).optional(),
|
|
827
|
+
dpop_bound_access_tokens_required: z.boolean().optional()
|
|
828
|
+
});
|
|
829
|
+
var OAuthMetadataSchema = z.looseObject({
|
|
830
|
+
issuer: z.string(),
|
|
831
|
+
authorization_endpoint: SafeUrlSchema,
|
|
832
|
+
token_endpoint: SafeUrlSchema,
|
|
833
|
+
registration_endpoint: SafeUrlSchema.optional(),
|
|
834
|
+
scopes_supported: z.array(z.string()).optional(),
|
|
835
|
+
response_types_supported: z.array(z.string()),
|
|
836
|
+
response_modes_supported: z.array(z.string()).optional(),
|
|
837
|
+
grant_types_supported: z.array(z.string()).optional(),
|
|
838
|
+
token_endpoint_auth_methods_supported: z.array(z.string()).optional(),
|
|
839
|
+
token_endpoint_auth_signing_alg_values_supported: z.array(z.string()).optional(),
|
|
840
|
+
service_documentation: SafeUrlSchema.optional(),
|
|
841
|
+
revocation_endpoint: SafeUrlSchema.optional(),
|
|
842
|
+
revocation_endpoint_auth_methods_supported: z.array(z.string()).optional(),
|
|
843
|
+
revocation_endpoint_auth_signing_alg_values_supported: z.array(z.string()).optional(),
|
|
844
|
+
introspection_endpoint: z.string().optional(),
|
|
845
|
+
introspection_endpoint_auth_methods_supported: z.array(z.string()).optional(),
|
|
846
|
+
introspection_endpoint_auth_signing_alg_values_supported: z.array(z.string()).optional(),
|
|
847
|
+
code_challenge_methods_supported: z.array(z.string()).optional(),
|
|
848
|
+
client_id_metadata_document_supported: z.boolean().optional()
|
|
849
|
+
});
|
|
850
|
+
var OpenIdProviderMetadataSchema = z.looseObject({
|
|
851
|
+
issuer: z.string(),
|
|
852
|
+
authorization_endpoint: SafeUrlSchema,
|
|
853
|
+
token_endpoint: SafeUrlSchema,
|
|
854
|
+
userinfo_endpoint: SafeUrlSchema.optional(),
|
|
855
|
+
jwks_uri: SafeUrlSchema,
|
|
856
|
+
registration_endpoint: SafeUrlSchema.optional(),
|
|
857
|
+
scopes_supported: z.array(z.string()).optional(),
|
|
858
|
+
response_types_supported: z.array(z.string()),
|
|
859
|
+
response_modes_supported: z.array(z.string()).optional(),
|
|
860
|
+
grant_types_supported: z.array(z.string()).optional(),
|
|
861
|
+
acr_values_supported: z.array(z.string()).optional(),
|
|
862
|
+
subject_types_supported: z.array(z.string()),
|
|
863
|
+
id_token_signing_alg_values_supported: z.array(z.string()),
|
|
864
|
+
id_token_encryption_alg_values_supported: z.array(z.string()).optional(),
|
|
865
|
+
id_token_encryption_enc_values_supported: z.array(z.string()).optional(),
|
|
866
|
+
userinfo_signing_alg_values_supported: z.array(z.string()).optional(),
|
|
867
|
+
userinfo_encryption_alg_values_supported: z.array(z.string()).optional(),
|
|
868
|
+
userinfo_encryption_enc_values_supported: z.array(z.string()).optional(),
|
|
869
|
+
request_object_signing_alg_values_supported: z.array(z.string()).optional(),
|
|
870
|
+
request_object_encryption_alg_values_supported: z.array(z.string()).optional(),
|
|
871
|
+
request_object_encryption_enc_values_supported: z.array(z.string()).optional(),
|
|
872
|
+
token_endpoint_auth_methods_supported: z.array(z.string()).optional(),
|
|
873
|
+
token_endpoint_auth_signing_alg_values_supported: z.array(z.string()).optional(),
|
|
874
|
+
display_values_supported: z.array(z.string()).optional(),
|
|
875
|
+
claim_types_supported: z.array(z.string()).optional(),
|
|
876
|
+
claims_supported: z.array(z.string()).optional(),
|
|
877
|
+
service_documentation: z.string().optional(),
|
|
878
|
+
claims_locales_supported: z.array(z.string()).optional(),
|
|
879
|
+
ui_locales_supported: z.array(z.string()).optional(),
|
|
880
|
+
claims_parameter_supported: z.boolean().optional(),
|
|
881
|
+
request_parameter_supported: z.boolean().optional(),
|
|
882
|
+
request_uri_parameter_supported: z.boolean().optional(),
|
|
883
|
+
require_request_uri_registration: z.boolean().optional(),
|
|
884
|
+
op_policy_uri: SafeUrlSchema.optional(),
|
|
885
|
+
op_tos_uri: SafeUrlSchema.optional(),
|
|
886
|
+
client_id_metadata_document_supported: z.boolean().optional()
|
|
887
|
+
});
|
|
888
|
+
var OpenIdProviderDiscoveryMetadataSchema = z.object({
|
|
889
|
+
...OpenIdProviderMetadataSchema.shape,
|
|
890
|
+
...OAuthMetadataSchema.pick({
|
|
891
|
+
code_challenge_methods_supported: true
|
|
892
|
+
}).shape
|
|
893
|
+
});
|
|
894
|
+
var OAuthTokensSchema = z.object({
|
|
895
|
+
access_token: z.string(),
|
|
896
|
+
id_token: z.string().optional(),
|
|
897
|
+
// Optional for OAuth 2.1, but necessary in OpenID Connect
|
|
898
|
+
token_type: z.string(),
|
|
899
|
+
expires_in: z.coerce.number().optional(),
|
|
900
|
+
scope: z.string().optional(),
|
|
901
|
+
refresh_token: z.string().optional()
|
|
902
|
+
}).strip();
|
|
903
|
+
var OAuthErrorResponseSchema = z.object({
|
|
904
|
+
error: z.string(),
|
|
905
|
+
error_description: z.string().optional(),
|
|
906
|
+
error_uri: z.string().optional()
|
|
907
|
+
});
|
|
908
|
+
var OptionalSafeUrlSchema = SafeUrlSchema.optional().or(z.literal("").transform(() => void 0));
|
|
909
|
+
var OAuthClientMetadataSchema = z.object({
|
|
910
|
+
redirect_uris: z.array(SafeUrlSchema),
|
|
911
|
+
token_endpoint_auth_method: z.string().optional(),
|
|
912
|
+
grant_types: z.array(z.string()).optional(),
|
|
913
|
+
response_types: z.array(z.string()).optional(),
|
|
914
|
+
client_name: z.string().optional(),
|
|
915
|
+
client_uri: SafeUrlSchema.optional(),
|
|
916
|
+
logo_uri: OptionalSafeUrlSchema,
|
|
917
|
+
scope: z.string().optional(),
|
|
918
|
+
contacts: z.array(z.string()).optional(),
|
|
919
|
+
tos_uri: OptionalSafeUrlSchema,
|
|
920
|
+
policy_uri: z.string().optional(),
|
|
921
|
+
jwks_uri: SafeUrlSchema.optional(),
|
|
922
|
+
jwks: z.any().optional(),
|
|
923
|
+
software_id: z.string().optional(),
|
|
924
|
+
software_version: z.string().optional(),
|
|
925
|
+
software_statement: z.string().optional()
|
|
926
|
+
}).strip();
|
|
927
|
+
var OAuthClientInformationSchema = z.object({
|
|
928
|
+
client_id: z.string(),
|
|
929
|
+
client_secret: z.string().optional(),
|
|
930
|
+
client_id_issued_at: z.number().optional(),
|
|
931
|
+
client_secret_expires_at: z.number().optional()
|
|
932
|
+
}).strip();
|
|
933
|
+
var OAuthClientInformationFullSchema = OAuthClientMetadataSchema.merge(OAuthClientInformationSchema);
|
|
934
|
+
var OAuthClientRegistrationErrorSchema = z.object({
|
|
935
|
+
error: z.string(),
|
|
936
|
+
error_description: z.string().optional()
|
|
937
|
+
}).strip();
|
|
938
|
+
var OAuthTokenRevocationRequestSchema = z.object({
|
|
939
|
+
token: z.string(),
|
|
940
|
+
token_type_hint: z.string().optional()
|
|
941
|
+
}).strip();
|
|
942
|
+
|
|
943
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth-utils.js
|
|
944
|
+
function resourceUrlFromServerUrl(url2) {
|
|
945
|
+
const resourceURL = typeof url2 === "string" ? new URL(url2) : new URL(url2.href);
|
|
946
|
+
resourceURL.hash = "";
|
|
947
|
+
return resourceURL;
|
|
948
|
+
}
|
|
949
|
+
function checkResourceAllowed({ requestedResource, configuredResource }) {
|
|
950
|
+
const requested = typeof requestedResource === "string" ? new URL(requestedResource) : new URL(requestedResource.href);
|
|
951
|
+
const configured = typeof configuredResource === "string" ? new URL(configuredResource) : new URL(configuredResource.href);
|
|
952
|
+
if (requested.origin !== configured.origin) {
|
|
953
|
+
return false;
|
|
954
|
+
}
|
|
955
|
+
if (requested.pathname.length < configured.pathname.length) {
|
|
956
|
+
return false;
|
|
957
|
+
}
|
|
958
|
+
const requestedPath = requested.pathname.endsWith("/") ? requested.pathname : requested.pathname + "/";
|
|
959
|
+
const configuredPath = configured.pathname.endsWith("/") ? configured.pathname : configured.pathname + "/";
|
|
960
|
+
return requestedPath.startsWith(configuredPath);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/errors.js
|
|
964
|
+
var OAuthError = class extends Error {
|
|
965
|
+
constructor(message, errorUri) {
|
|
966
|
+
super(message);
|
|
967
|
+
this.errorUri = errorUri;
|
|
968
|
+
this.name = this.constructor.name;
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* Converts the error to a standard OAuth error response object
|
|
972
|
+
*/
|
|
973
|
+
toResponseObject() {
|
|
974
|
+
const response = {
|
|
975
|
+
error: this.errorCode,
|
|
976
|
+
error_description: this.message
|
|
977
|
+
};
|
|
978
|
+
if (this.errorUri) {
|
|
979
|
+
response.error_uri = this.errorUri;
|
|
980
|
+
}
|
|
981
|
+
return response;
|
|
982
|
+
}
|
|
983
|
+
get errorCode() {
|
|
984
|
+
return this.constructor.errorCode;
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
var InvalidRequestError = class extends OAuthError {
|
|
988
|
+
};
|
|
989
|
+
InvalidRequestError.errorCode = "invalid_request";
|
|
990
|
+
var InvalidClientError = class extends OAuthError {
|
|
991
|
+
};
|
|
992
|
+
InvalidClientError.errorCode = "invalid_client";
|
|
993
|
+
var InvalidGrantError = class extends OAuthError {
|
|
994
|
+
};
|
|
995
|
+
InvalidGrantError.errorCode = "invalid_grant";
|
|
996
|
+
var UnauthorizedClientError = class extends OAuthError {
|
|
997
|
+
};
|
|
998
|
+
UnauthorizedClientError.errorCode = "unauthorized_client";
|
|
999
|
+
var UnsupportedGrantTypeError = class extends OAuthError {
|
|
1000
|
+
};
|
|
1001
|
+
UnsupportedGrantTypeError.errorCode = "unsupported_grant_type";
|
|
1002
|
+
var InvalidScopeError = class extends OAuthError {
|
|
1003
|
+
};
|
|
1004
|
+
InvalidScopeError.errorCode = "invalid_scope";
|
|
1005
|
+
var AccessDeniedError = class extends OAuthError {
|
|
1006
|
+
};
|
|
1007
|
+
AccessDeniedError.errorCode = "access_denied";
|
|
1008
|
+
var ServerError = class extends OAuthError {
|
|
1009
|
+
};
|
|
1010
|
+
ServerError.errorCode = "server_error";
|
|
1011
|
+
var TemporarilyUnavailableError = class extends OAuthError {
|
|
1012
|
+
};
|
|
1013
|
+
TemporarilyUnavailableError.errorCode = "temporarily_unavailable";
|
|
1014
|
+
var UnsupportedResponseTypeError = class extends OAuthError {
|
|
1015
|
+
};
|
|
1016
|
+
UnsupportedResponseTypeError.errorCode = "unsupported_response_type";
|
|
1017
|
+
var UnsupportedTokenTypeError = class extends OAuthError {
|
|
1018
|
+
};
|
|
1019
|
+
UnsupportedTokenTypeError.errorCode = "unsupported_token_type";
|
|
1020
|
+
var InvalidTokenError = class extends OAuthError {
|
|
1021
|
+
};
|
|
1022
|
+
InvalidTokenError.errorCode = "invalid_token";
|
|
1023
|
+
var MethodNotAllowedError = class extends OAuthError {
|
|
1024
|
+
};
|
|
1025
|
+
MethodNotAllowedError.errorCode = "method_not_allowed";
|
|
1026
|
+
var TooManyRequestsError = class extends OAuthError {
|
|
1027
|
+
};
|
|
1028
|
+
TooManyRequestsError.errorCode = "too_many_requests";
|
|
1029
|
+
var InvalidClientMetadataError = class extends OAuthError {
|
|
1030
|
+
};
|
|
1031
|
+
InvalidClientMetadataError.errorCode = "invalid_client_metadata";
|
|
1032
|
+
var InsufficientScopeError = class extends OAuthError {
|
|
1033
|
+
};
|
|
1034
|
+
InsufficientScopeError.errorCode = "insufficient_scope";
|
|
1035
|
+
var InvalidTargetError = class extends OAuthError {
|
|
1036
|
+
};
|
|
1037
|
+
InvalidTargetError.errorCode = "invalid_target";
|
|
1038
|
+
var OAUTH_ERRORS = {
|
|
1039
|
+
[InvalidRequestError.errorCode]: InvalidRequestError,
|
|
1040
|
+
[InvalidClientError.errorCode]: InvalidClientError,
|
|
1041
|
+
[InvalidGrantError.errorCode]: InvalidGrantError,
|
|
1042
|
+
[UnauthorizedClientError.errorCode]: UnauthorizedClientError,
|
|
1043
|
+
[UnsupportedGrantTypeError.errorCode]: UnsupportedGrantTypeError,
|
|
1044
|
+
[InvalidScopeError.errorCode]: InvalidScopeError,
|
|
1045
|
+
[AccessDeniedError.errorCode]: AccessDeniedError,
|
|
1046
|
+
[ServerError.errorCode]: ServerError,
|
|
1047
|
+
[TemporarilyUnavailableError.errorCode]: TemporarilyUnavailableError,
|
|
1048
|
+
[UnsupportedResponseTypeError.errorCode]: UnsupportedResponseTypeError,
|
|
1049
|
+
[UnsupportedTokenTypeError.errorCode]: UnsupportedTokenTypeError,
|
|
1050
|
+
[InvalidTokenError.errorCode]: InvalidTokenError,
|
|
1051
|
+
[MethodNotAllowedError.errorCode]: MethodNotAllowedError,
|
|
1052
|
+
[TooManyRequestsError.errorCode]: TooManyRequestsError,
|
|
1053
|
+
[InvalidClientMetadataError.errorCode]: InvalidClientMetadataError,
|
|
1054
|
+
[InsufficientScopeError.errorCode]: InsufficientScopeError,
|
|
1055
|
+
[InvalidTargetError.errorCode]: InvalidTargetError
|
|
1056
|
+
};
|
|
1057
|
+
|
|
1058
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js
|
|
1059
|
+
var UnauthorizedError = class extends Error {
|
|
1060
|
+
constructor(message) {
|
|
1061
|
+
super(message ?? "Unauthorized");
|
|
1062
|
+
}
|
|
1063
|
+
};
|
|
1064
|
+
function isClientAuthMethod(method) {
|
|
1065
|
+
return ["client_secret_basic", "client_secret_post", "none"].includes(method);
|
|
1066
|
+
}
|
|
1067
|
+
var AUTHORIZATION_CODE_RESPONSE_TYPE = "code";
|
|
1068
|
+
var AUTHORIZATION_CODE_CHALLENGE_METHOD = "S256";
|
|
1069
|
+
function selectClientAuthMethod(clientInformation, supportedMethods) {
|
|
1070
|
+
const hasClientSecret = clientInformation.client_secret !== void 0;
|
|
1071
|
+
if ("token_endpoint_auth_method" in clientInformation && clientInformation.token_endpoint_auth_method && isClientAuthMethod(clientInformation.token_endpoint_auth_method) && (supportedMethods.length === 0 || supportedMethods.includes(clientInformation.token_endpoint_auth_method))) {
|
|
1072
|
+
return clientInformation.token_endpoint_auth_method;
|
|
1073
|
+
}
|
|
1074
|
+
if (supportedMethods.length === 0) {
|
|
1075
|
+
return hasClientSecret ? "client_secret_basic" : "none";
|
|
1076
|
+
}
|
|
1077
|
+
if (hasClientSecret && supportedMethods.includes("client_secret_basic")) {
|
|
1078
|
+
return "client_secret_basic";
|
|
1079
|
+
}
|
|
1080
|
+
if (hasClientSecret && supportedMethods.includes("client_secret_post")) {
|
|
1081
|
+
return "client_secret_post";
|
|
1082
|
+
}
|
|
1083
|
+
if (supportedMethods.includes("none")) {
|
|
1084
|
+
return "none";
|
|
1085
|
+
}
|
|
1086
|
+
return hasClientSecret ? "client_secret_post" : "none";
|
|
1087
|
+
}
|
|
1088
|
+
function applyClientAuthentication(method, clientInformation, headers, params) {
|
|
1089
|
+
const { client_id, client_secret } = clientInformation;
|
|
1090
|
+
switch (method) {
|
|
1091
|
+
case "client_secret_basic":
|
|
1092
|
+
applyBasicAuth(client_id, client_secret, headers);
|
|
1093
|
+
return;
|
|
1094
|
+
case "client_secret_post":
|
|
1095
|
+
applyPostAuth(client_id, client_secret, params);
|
|
1096
|
+
return;
|
|
1097
|
+
case "none":
|
|
1098
|
+
applyPublicAuth(client_id, params);
|
|
1099
|
+
return;
|
|
1100
|
+
default:
|
|
1101
|
+
throw new Error(`Unsupported client authentication method: ${method}`);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
function applyBasicAuth(clientId, clientSecret, headers) {
|
|
1105
|
+
if (!clientSecret) {
|
|
1106
|
+
throw new Error("client_secret_basic authentication requires a client_secret");
|
|
1107
|
+
}
|
|
1108
|
+
const credentials = btoa(`${clientId}:${clientSecret}`);
|
|
1109
|
+
headers.set("Authorization", `Basic ${credentials}`);
|
|
1110
|
+
}
|
|
1111
|
+
function applyPostAuth(clientId, clientSecret, params) {
|
|
1112
|
+
params.set("client_id", clientId);
|
|
1113
|
+
if (clientSecret) {
|
|
1114
|
+
params.set("client_secret", clientSecret);
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
function applyPublicAuth(clientId, params) {
|
|
1118
|
+
params.set("client_id", clientId);
|
|
1119
|
+
}
|
|
1120
|
+
async function parseErrorResponse(input) {
|
|
1121
|
+
const statusCode = input instanceof Response ? input.status : void 0;
|
|
1122
|
+
const body = input instanceof Response ? await input.text() : input;
|
|
1123
|
+
try {
|
|
1124
|
+
const result = OAuthErrorResponseSchema.parse(JSON.parse(body));
|
|
1125
|
+
const { error, error_description, error_uri } = result;
|
|
1126
|
+
const errorClass = OAUTH_ERRORS[error] || ServerError;
|
|
1127
|
+
return new errorClass(error_description || "", error_uri);
|
|
1128
|
+
} catch (error) {
|
|
1129
|
+
const errorMessage = `${statusCode ? `HTTP ${statusCode}: ` : ""}Invalid OAuth error response: ${error}. Raw body: ${body}`;
|
|
1130
|
+
return new ServerError(errorMessage);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
async function auth(provider, options) {
|
|
1134
|
+
try {
|
|
1135
|
+
return await authInternal(provider, options);
|
|
1136
|
+
} catch (error) {
|
|
1137
|
+
if (error instanceof InvalidClientError || error instanceof UnauthorizedClientError) {
|
|
1138
|
+
await provider.invalidateCredentials?.("all");
|
|
1139
|
+
return await authInternal(provider, options);
|
|
1140
|
+
} else if (error instanceof InvalidGrantError) {
|
|
1141
|
+
await provider.invalidateCredentials?.("tokens");
|
|
1142
|
+
return await authInternal(provider, options);
|
|
1143
|
+
}
|
|
1144
|
+
throw error;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
async function authInternal(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl, fetchFn }) {
|
|
1148
|
+
const cachedState = await provider.discoveryState?.();
|
|
1149
|
+
let resourceMetadata;
|
|
1150
|
+
let authorizationServerUrl;
|
|
1151
|
+
let metadata;
|
|
1152
|
+
let effectiveResourceMetadataUrl = resourceMetadataUrl;
|
|
1153
|
+
if (!effectiveResourceMetadataUrl && cachedState?.resourceMetadataUrl) {
|
|
1154
|
+
effectiveResourceMetadataUrl = new URL(cachedState.resourceMetadataUrl);
|
|
1155
|
+
}
|
|
1156
|
+
if (cachedState?.authorizationServerUrl) {
|
|
1157
|
+
authorizationServerUrl = cachedState.authorizationServerUrl;
|
|
1158
|
+
resourceMetadata = cachedState.resourceMetadata;
|
|
1159
|
+
metadata = cachedState.authorizationServerMetadata ?? await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn });
|
|
1160
|
+
if (!resourceMetadata) {
|
|
1161
|
+
try {
|
|
1162
|
+
resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl }, fetchFn);
|
|
1163
|
+
} catch {
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
if (metadata !== cachedState.authorizationServerMetadata || resourceMetadata !== cachedState.resourceMetadata) {
|
|
1167
|
+
await provider.saveDiscoveryState?.({
|
|
1168
|
+
authorizationServerUrl: String(authorizationServerUrl),
|
|
1169
|
+
resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
|
|
1170
|
+
resourceMetadata,
|
|
1171
|
+
authorizationServerMetadata: metadata
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
} else {
|
|
1175
|
+
const serverInfo = await discoverOAuthServerInfo(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl, fetchFn });
|
|
1176
|
+
authorizationServerUrl = serverInfo.authorizationServerUrl;
|
|
1177
|
+
metadata = serverInfo.authorizationServerMetadata;
|
|
1178
|
+
resourceMetadata = serverInfo.resourceMetadata;
|
|
1179
|
+
await provider.saveDiscoveryState?.({
|
|
1180
|
+
authorizationServerUrl: String(authorizationServerUrl),
|
|
1181
|
+
resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
|
|
1182
|
+
resourceMetadata,
|
|
1183
|
+
authorizationServerMetadata: metadata
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
const resource = await selectResourceURL(serverUrl, provider, resourceMetadata);
|
|
1187
|
+
const resolvedScope = scope || resourceMetadata?.scopes_supported?.join(" ") || provider.clientMetadata.scope;
|
|
1188
|
+
let clientInformation = await Promise.resolve(provider.clientInformation());
|
|
1189
|
+
if (!clientInformation) {
|
|
1190
|
+
if (authorizationCode !== void 0) {
|
|
1191
|
+
throw new Error("Existing OAuth client information is required when exchanging an authorization code");
|
|
1192
|
+
}
|
|
1193
|
+
const supportsUrlBasedClientId = metadata?.client_id_metadata_document_supported === true;
|
|
1194
|
+
const clientMetadataUrl = provider.clientMetadataUrl;
|
|
1195
|
+
if (clientMetadataUrl && !isHttpsUrl(clientMetadataUrl)) {
|
|
1196
|
+
throw new InvalidClientMetadataError(`clientMetadataUrl must be a valid HTTPS URL with a non-root pathname, got: ${clientMetadataUrl}`);
|
|
1197
|
+
}
|
|
1198
|
+
const shouldUseUrlBasedClientId = supportsUrlBasedClientId && clientMetadataUrl;
|
|
1199
|
+
if (shouldUseUrlBasedClientId) {
|
|
1200
|
+
clientInformation = {
|
|
1201
|
+
client_id: clientMetadataUrl
|
|
1202
|
+
};
|
|
1203
|
+
await provider.saveClientInformation?.(clientInformation);
|
|
1204
|
+
} else {
|
|
1205
|
+
if (!provider.saveClientInformation) {
|
|
1206
|
+
throw new Error("OAuth client information must be saveable for dynamic registration");
|
|
1207
|
+
}
|
|
1208
|
+
const fullInformation = await registerClient(authorizationServerUrl, {
|
|
1209
|
+
metadata,
|
|
1210
|
+
clientMetadata: provider.clientMetadata,
|
|
1211
|
+
scope: resolvedScope,
|
|
1212
|
+
fetchFn
|
|
1213
|
+
});
|
|
1214
|
+
await provider.saveClientInformation(fullInformation);
|
|
1215
|
+
clientInformation = fullInformation;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
const nonInteractiveFlow = !provider.redirectUrl;
|
|
1219
|
+
if (authorizationCode !== void 0 || nonInteractiveFlow) {
|
|
1220
|
+
const tokens2 = await fetchToken(provider, authorizationServerUrl, {
|
|
1221
|
+
metadata,
|
|
1222
|
+
resource,
|
|
1223
|
+
authorizationCode,
|
|
1224
|
+
fetchFn
|
|
1225
|
+
});
|
|
1226
|
+
await provider.saveTokens(tokens2);
|
|
1227
|
+
return "AUTHORIZED";
|
|
1228
|
+
}
|
|
1229
|
+
const tokens = await provider.tokens();
|
|
1230
|
+
if (tokens?.refresh_token) {
|
|
1231
|
+
try {
|
|
1232
|
+
const newTokens = await refreshAuthorization(authorizationServerUrl, {
|
|
1233
|
+
metadata,
|
|
1234
|
+
clientInformation,
|
|
1235
|
+
refreshToken: tokens.refresh_token,
|
|
1236
|
+
resource,
|
|
1237
|
+
addClientAuthentication: provider.addClientAuthentication,
|
|
1238
|
+
fetchFn
|
|
1239
|
+
});
|
|
1240
|
+
await provider.saveTokens(newTokens);
|
|
1241
|
+
return "AUTHORIZED";
|
|
1242
|
+
} catch (error) {
|
|
1243
|
+
if (!(error instanceof OAuthError) || error instanceof ServerError) {
|
|
1244
|
+
} else {
|
|
1245
|
+
throw error;
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
const state = provider.state ? await provider.state() : void 0;
|
|
1250
|
+
const { authorizationUrl, codeVerifier } = await startAuthorization(authorizationServerUrl, {
|
|
1251
|
+
metadata,
|
|
1252
|
+
clientInformation,
|
|
1253
|
+
state,
|
|
1254
|
+
redirectUrl: provider.redirectUrl,
|
|
1255
|
+
scope: resolvedScope,
|
|
1256
|
+
resource
|
|
1257
|
+
});
|
|
1258
|
+
await provider.saveCodeVerifier(codeVerifier);
|
|
1259
|
+
await provider.redirectToAuthorization(authorizationUrl);
|
|
1260
|
+
return "REDIRECT";
|
|
1261
|
+
}
|
|
1262
|
+
function isHttpsUrl(value) {
|
|
1263
|
+
if (!value)
|
|
1264
|
+
return false;
|
|
1265
|
+
try {
|
|
1266
|
+
const url2 = new URL(value);
|
|
1267
|
+
return url2.protocol === "https:" && url2.pathname !== "/";
|
|
1268
|
+
} catch {
|
|
1269
|
+
return false;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
async function selectResourceURL(serverUrl, provider, resourceMetadata) {
|
|
1273
|
+
const defaultResource = resourceUrlFromServerUrl(serverUrl);
|
|
1274
|
+
if (provider.validateResourceURL) {
|
|
1275
|
+
return await provider.validateResourceURL(defaultResource, resourceMetadata?.resource);
|
|
1276
|
+
}
|
|
1277
|
+
if (!resourceMetadata) {
|
|
1278
|
+
return void 0;
|
|
1279
|
+
}
|
|
1280
|
+
if (!checkResourceAllowed({ requestedResource: defaultResource, configuredResource: resourceMetadata.resource })) {
|
|
1281
|
+
throw new Error(`Protected resource ${resourceMetadata.resource} does not match expected ${defaultResource} (or origin)`);
|
|
1282
|
+
}
|
|
1283
|
+
return new URL(resourceMetadata.resource);
|
|
1284
|
+
}
|
|
1285
|
+
function extractWWWAuthenticateParams(res) {
|
|
1286
|
+
const authenticateHeader = res.headers.get("WWW-Authenticate");
|
|
1287
|
+
if (!authenticateHeader) {
|
|
1288
|
+
return {};
|
|
1289
|
+
}
|
|
1290
|
+
const [type, scheme] = authenticateHeader.split(" ");
|
|
1291
|
+
if (type.toLowerCase() !== "bearer" || !scheme) {
|
|
1292
|
+
return {};
|
|
1293
|
+
}
|
|
1294
|
+
const resourceMetadataMatch = extractFieldFromWwwAuth(res, "resource_metadata") || void 0;
|
|
1295
|
+
let resourceMetadataUrl;
|
|
1296
|
+
if (resourceMetadataMatch) {
|
|
1297
|
+
try {
|
|
1298
|
+
resourceMetadataUrl = new URL(resourceMetadataMatch);
|
|
1299
|
+
} catch {
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
const scope = extractFieldFromWwwAuth(res, "scope") || void 0;
|
|
1303
|
+
const error = extractFieldFromWwwAuth(res, "error") || void 0;
|
|
1304
|
+
return {
|
|
1305
|
+
resourceMetadataUrl,
|
|
1306
|
+
scope,
|
|
1307
|
+
error
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
function extractFieldFromWwwAuth(response, fieldName) {
|
|
1311
|
+
const wwwAuthHeader = response.headers.get("WWW-Authenticate");
|
|
1312
|
+
if (!wwwAuthHeader) {
|
|
1313
|
+
return null;
|
|
1314
|
+
}
|
|
1315
|
+
const pattern = new RegExp(`${fieldName}=(?:"([^"]+)"|([^\\s,]+))`);
|
|
1316
|
+
const match = wwwAuthHeader.match(pattern);
|
|
1317
|
+
if (match) {
|
|
1318
|
+
return match[1] || match[2];
|
|
1319
|
+
}
|
|
1320
|
+
return null;
|
|
1321
|
+
}
|
|
1322
|
+
async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn = fetch) {
|
|
1323
|
+
const response = await discoverMetadataWithFallback(serverUrl, "oauth-protected-resource", fetchFn, {
|
|
1324
|
+
protocolVersion: opts?.protocolVersion,
|
|
1325
|
+
metadataUrl: opts?.resourceMetadataUrl
|
|
1326
|
+
});
|
|
1327
|
+
if (!response || response.status === 404) {
|
|
1328
|
+
await response?.body?.cancel();
|
|
1329
|
+
throw new Error(`Resource server does not implement OAuth 2.0 Protected Resource Metadata.`);
|
|
1330
|
+
}
|
|
1331
|
+
if (!response.ok) {
|
|
1332
|
+
await response.body?.cancel();
|
|
1333
|
+
throw new Error(`HTTP ${response.status} trying to load well-known OAuth protected resource metadata.`);
|
|
1334
|
+
}
|
|
1335
|
+
return OAuthProtectedResourceMetadataSchema.parse(await response.json());
|
|
1336
|
+
}
|
|
1337
|
+
async function fetchWithCorsRetry(url2, headers, fetchFn = fetch) {
|
|
1338
|
+
try {
|
|
1339
|
+
return await fetchFn(url2, { headers });
|
|
1340
|
+
} catch (error) {
|
|
1341
|
+
if (error instanceof TypeError) {
|
|
1342
|
+
if (headers) {
|
|
1343
|
+
return fetchWithCorsRetry(url2, void 0, fetchFn);
|
|
1344
|
+
} else {
|
|
1345
|
+
return void 0;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
throw error;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
function buildWellKnownPath(wellKnownPrefix, pathname = "", options = {}) {
|
|
1352
|
+
if (pathname.endsWith("/")) {
|
|
1353
|
+
pathname = pathname.slice(0, -1);
|
|
1354
|
+
}
|
|
1355
|
+
return options.prependPathname ? `${pathname}/.well-known/${wellKnownPrefix}` : `/.well-known/${wellKnownPrefix}${pathname}`;
|
|
1356
|
+
}
|
|
1357
|
+
async function tryMetadataDiscovery(url2, protocolVersion, fetchFn = fetch) {
|
|
1358
|
+
const headers = {
|
|
1359
|
+
"MCP-Protocol-Version": protocolVersion
|
|
1360
|
+
};
|
|
1361
|
+
return await fetchWithCorsRetry(url2, headers, fetchFn);
|
|
1362
|
+
}
|
|
1363
|
+
function shouldAttemptFallback(response, pathname) {
|
|
1364
|
+
return !response || response.status >= 400 && response.status < 500 && pathname !== "/";
|
|
1365
|
+
}
|
|
1366
|
+
async function discoverMetadataWithFallback(serverUrl, wellKnownType, fetchFn, opts) {
|
|
1367
|
+
const issuer = new URL(serverUrl);
|
|
1368
|
+
const protocolVersion = opts?.protocolVersion ?? LATEST_PROTOCOL_VERSION;
|
|
1369
|
+
let url2;
|
|
1370
|
+
if (opts?.metadataUrl) {
|
|
1371
|
+
url2 = new URL(opts.metadataUrl);
|
|
1372
|
+
} else {
|
|
1373
|
+
const wellKnownPath = buildWellKnownPath(wellKnownType, issuer.pathname);
|
|
1374
|
+
url2 = new URL(wellKnownPath, opts?.metadataServerUrl ?? issuer);
|
|
1375
|
+
url2.search = issuer.search;
|
|
1376
|
+
}
|
|
1377
|
+
let response = await tryMetadataDiscovery(url2, protocolVersion, fetchFn);
|
|
1378
|
+
if (!opts?.metadataUrl && shouldAttemptFallback(response, issuer.pathname)) {
|
|
1379
|
+
const rootUrl = new URL(`/.well-known/${wellKnownType}`, issuer);
|
|
1380
|
+
response = await tryMetadataDiscovery(rootUrl, protocolVersion, fetchFn);
|
|
1381
|
+
}
|
|
1382
|
+
return response;
|
|
1383
|
+
}
|
|
1384
|
+
function buildDiscoveryUrls(authorizationServerUrl) {
|
|
1385
|
+
const url2 = typeof authorizationServerUrl === "string" ? new URL(authorizationServerUrl) : authorizationServerUrl;
|
|
1386
|
+
const hasPath = url2.pathname !== "/";
|
|
1387
|
+
const urlsToTry = [];
|
|
1388
|
+
if (!hasPath) {
|
|
1389
|
+
urlsToTry.push({
|
|
1390
|
+
url: new URL("/.well-known/oauth-authorization-server", url2.origin),
|
|
1391
|
+
type: "oauth"
|
|
1392
|
+
});
|
|
1393
|
+
urlsToTry.push({
|
|
1394
|
+
url: new URL(`/.well-known/openid-configuration`, url2.origin),
|
|
1395
|
+
type: "oidc"
|
|
1396
|
+
});
|
|
1397
|
+
return urlsToTry;
|
|
1398
|
+
}
|
|
1399
|
+
let pathname = url2.pathname;
|
|
1400
|
+
if (pathname.endsWith("/")) {
|
|
1401
|
+
pathname = pathname.slice(0, -1);
|
|
1402
|
+
}
|
|
1403
|
+
urlsToTry.push({
|
|
1404
|
+
url: new URL(`/.well-known/oauth-authorization-server${pathname}`, url2.origin),
|
|
1405
|
+
type: "oauth"
|
|
1406
|
+
});
|
|
1407
|
+
urlsToTry.push({
|
|
1408
|
+
url: new URL(`/.well-known/openid-configuration${pathname}`, url2.origin),
|
|
1409
|
+
type: "oidc"
|
|
1410
|
+
});
|
|
1411
|
+
urlsToTry.push({
|
|
1412
|
+
url: new URL(`${pathname}/.well-known/openid-configuration`, url2.origin),
|
|
1413
|
+
type: "oidc"
|
|
1414
|
+
});
|
|
1415
|
+
return urlsToTry;
|
|
1416
|
+
}
|
|
1417
|
+
async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn = fetch, protocolVersion = LATEST_PROTOCOL_VERSION } = {}) {
|
|
1418
|
+
const headers = {
|
|
1419
|
+
"MCP-Protocol-Version": protocolVersion,
|
|
1420
|
+
Accept: "application/json"
|
|
1421
|
+
};
|
|
1422
|
+
const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
|
|
1423
|
+
for (const { url: endpointUrl, type } of urlsToTry) {
|
|
1424
|
+
const response = await fetchWithCorsRetry(endpointUrl, headers, fetchFn);
|
|
1425
|
+
if (!response) {
|
|
1426
|
+
continue;
|
|
1427
|
+
}
|
|
1428
|
+
if (!response.ok) {
|
|
1429
|
+
await response.body?.cancel();
|
|
1430
|
+
if (response.status >= 400 && response.status < 500) {
|
|
1431
|
+
continue;
|
|
1432
|
+
}
|
|
1433
|
+
throw new Error(`HTTP ${response.status} trying to load ${type === "oauth" ? "OAuth" : "OpenID provider"} metadata from ${endpointUrl}`);
|
|
1434
|
+
}
|
|
1435
|
+
if (type === "oauth") {
|
|
1436
|
+
return OAuthMetadataSchema.parse(await response.json());
|
|
1437
|
+
} else {
|
|
1438
|
+
return OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
return void 0;
|
|
1442
|
+
}
|
|
1443
|
+
async function discoverOAuthServerInfo(serverUrl, opts) {
|
|
1444
|
+
let resourceMetadata;
|
|
1445
|
+
let authorizationServerUrl;
|
|
1446
|
+
try {
|
|
1447
|
+
resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: opts?.resourceMetadataUrl }, opts?.fetchFn);
|
|
1448
|
+
if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {
|
|
1449
|
+
authorizationServerUrl = resourceMetadata.authorization_servers[0];
|
|
1450
|
+
}
|
|
1451
|
+
} catch {
|
|
1452
|
+
}
|
|
1453
|
+
if (!authorizationServerUrl) {
|
|
1454
|
+
authorizationServerUrl = String(new URL("/", serverUrl));
|
|
1455
|
+
}
|
|
1456
|
+
const authorizationServerMetadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn: opts?.fetchFn });
|
|
1457
|
+
return {
|
|
1458
|
+
authorizationServerUrl,
|
|
1459
|
+
authorizationServerMetadata,
|
|
1460
|
+
resourceMetadata
|
|
1461
|
+
};
|
|
1462
|
+
}
|
|
1463
|
+
async function startAuthorization(authorizationServerUrl, { metadata, clientInformation, redirectUrl, scope, state, resource }) {
|
|
1464
|
+
let authorizationUrl;
|
|
1465
|
+
if (metadata) {
|
|
1466
|
+
authorizationUrl = new URL(metadata.authorization_endpoint);
|
|
1467
|
+
if (!metadata.response_types_supported.includes(AUTHORIZATION_CODE_RESPONSE_TYPE)) {
|
|
1468
|
+
throw new Error(`Incompatible auth server: does not support response type ${AUTHORIZATION_CODE_RESPONSE_TYPE}`);
|
|
1469
|
+
}
|
|
1470
|
+
if (metadata.code_challenge_methods_supported && !metadata.code_challenge_methods_supported.includes(AUTHORIZATION_CODE_CHALLENGE_METHOD)) {
|
|
1471
|
+
throw new Error(`Incompatible auth server: does not support code challenge method ${AUTHORIZATION_CODE_CHALLENGE_METHOD}`);
|
|
1472
|
+
}
|
|
1473
|
+
} else {
|
|
1474
|
+
authorizationUrl = new URL("/authorize", authorizationServerUrl);
|
|
1475
|
+
}
|
|
1476
|
+
const challenge = await pkceChallenge();
|
|
1477
|
+
const codeVerifier = challenge.code_verifier;
|
|
1478
|
+
const codeChallenge = challenge.code_challenge;
|
|
1479
|
+
authorizationUrl.searchParams.set("response_type", AUTHORIZATION_CODE_RESPONSE_TYPE);
|
|
1480
|
+
authorizationUrl.searchParams.set("client_id", clientInformation.client_id);
|
|
1481
|
+
authorizationUrl.searchParams.set("code_challenge", codeChallenge);
|
|
1482
|
+
authorizationUrl.searchParams.set("code_challenge_method", AUTHORIZATION_CODE_CHALLENGE_METHOD);
|
|
1483
|
+
authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl));
|
|
1484
|
+
if (state) {
|
|
1485
|
+
authorizationUrl.searchParams.set("state", state);
|
|
1486
|
+
}
|
|
1487
|
+
if (scope) {
|
|
1488
|
+
authorizationUrl.searchParams.set("scope", scope);
|
|
1489
|
+
}
|
|
1490
|
+
if (scope?.includes("offline_access")) {
|
|
1491
|
+
authorizationUrl.searchParams.append("prompt", "consent");
|
|
1492
|
+
}
|
|
1493
|
+
if (resource) {
|
|
1494
|
+
authorizationUrl.searchParams.set("resource", resource.href);
|
|
1495
|
+
}
|
|
1496
|
+
return { authorizationUrl, codeVerifier };
|
|
1497
|
+
}
|
|
1498
|
+
function prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, redirectUri) {
|
|
1499
|
+
return new URLSearchParams({
|
|
1500
|
+
grant_type: "authorization_code",
|
|
1501
|
+
code: authorizationCode,
|
|
1502
|
+
code_verifier: codeVerifier,
|
|
1503
|
+
redirect_uri: String(redirectUri)
|
|
1504
|
+
});
|
|
1505
|
+
}
|
|
1506
|
+
async function executeTokenRequest(authorizationServerUrl, { metadata, tokenRequestParams, clientInformation, addClientAuthentication, resource, fetchFn }) {
|
|
1507
|
+
const tokenUrl = metadata?.token_endpoint ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl);
|
|
1508
|
+
const headers = new Headers({
|
|
1509
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
1510
|
+
Accept: "application/json"
|
|
1511
|
+
});
|
|
1512
|
+
if (resource) {
|
|
1513
|
+
tokenRequestParams.set("resource", resource.href);
|
|
1514
|
+
}
|
|
1515
|
+
if (addClientAuthentication) {
|
|
1516
|
+
await addClientAuthentication(headers, tokenRequestParams, tokenUrl, metadata);
|
|
1517
|
+
} else if (clientInformation) {
|
|
1518
|
+
const supportedMethods = metadata?.token_endpoint_auth_methods_supported ?? [];
|
|
1519
|
+
const authMethod = selectClientAuthMethod(clientInformation, supportedMethods);
|
|
1520
|
+
applyClientAuthentication(authMethod, clientInformation, headers, tokenRequestParams);
|
|
1521
|
+
}
|
|
1522
|
+
const response = await (fetchFn ?? fetch)(tokenUrl, {
|
|
1523
|
+
method: "POST",
|
|
1524
|
+
headers,
|
|
1525
|
+
body: tokenRequestParams
|
|
1526
|
+
});
|
|
1527
|
+
if (!response.ok) {
|
|
1528
|
+
throw await parseErrorResponse(response);
|
|
1529
|
+
}
|
|
1530
|
+
return OAuthTokensSchema.parse(await response.json());
|
|
1531
|
+
}
|
|
1532
|
+
async function refreshAuthorization(authorizationServerUrl, { metadata, clientInformation, refreshToken, resource, addClientAuthentication, fetchFn }) {
|
|
1533
|
+
const tokenRequestParams = new URLSearchParams({
|
|
1534
|
+
grant_type: "refresh_token",
|
|
1535
|
+
refresh_token: refreshToken
|
|
1536
|
+
});
|
|
1537
|
+
const tokens = await executeTokenRequest(authorizationServerUrl, {
|
|
1538
|
+
metadata,
|
|
1539
|
+
tokenRequestParams,
|
|
1540
|
+
clientInformation,
|
|
1541
|
+
addClientAuthentication,
|
|
1542
|
+
resource,
|
|
1543
|
+
fetchFn
|
|
1544
|
+
});
|
|
1545
|
+
return { refresh_token: refreshToken, ...tokens };
|
|
1546
|
+
}
|
|
1547
|
+
async function fetchToken(provider, authorizationServerUrl, { metadata, resource, authorizationCode, fetchFn } = {}) {
|
|
1548
|
+
const scope = provider.clientMetadata.scope;
|
|
1549
|
+
let tokenRequestParams;
|
|
1550
|
+
if (provider.prepareTokenRequest) {
|
|
1551
|
+
tokenRequestParams = await provider.prepareTokenRequest(scope);
|
|
1552
|
+
}
|
|
1553
|
+
if (!tokenRequestParams) {
|
|
1554
|
+
if (!authorizationCode) {
|
|
1555
|
+
throw new Error("Either provider.prepareTokenRequest() or authorizationCode is required");
|
|
1556
|
+
}
|
|
1557
|
+
if (!provider.redirectUrl) {
|
|
1558
|
+
throw new Error("redirectUrl is required for authorization_code flow");
|
|
1559
|
+
}
|
|
1560
|
+
const codeVerifier = await provider.codeVerifier();
|
|
1561
|
+
tokenRequestParams = prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, provider.redirectUrl);
|
|
1562
|
+
}
|
|
1563
|
+
const clientInformation = await provider.clientInformation();
|
|
1564
|
+
return executeTokenRequest(authorizationServerUrl, {
|
|
1565
|
+
metadata,
|
|
1566
|
+
tokenRequestParams,
|
|
1567
|
+
clientInformation: clientInformation ?? void 0,
|
|
1568
|
+
addClientAuthentication: provider.addClientAuthentication,
|
|
1569
|
+
resource,
|
|
1570
|
+
fetchFn
|
|
1571
|
+
});
|
|
1572
|
+
}
|
|
1573
|
+
async function registerClient(authorizationServerUrl, { metadata, clientMetadata, scope, fetchFn }) {
|
|
1574
|
+
let registrationUrl;
|
|
1575
|
+
if (metadata) {
|
|
1576
|
+
if (!metadata.registration_endpoint) {
|
|
1577
|
+
throw new Error("Incompatible auth server: does not support dynamic client registration");
|
|
1578
|
+
}
|
|
1579
|
+
registrationUrl = new URL(metadata.registration_endpoint);
|
|
1580
|
+
} else {
|
|
1581
|
+
registrationUrl = new URL("/register", authorizationServerUrl);
|
|
1582
|
+
}
|
|
1583
|
+
const response = await (fetchFn ?? fetch)(registrationUrl, {
|
|
1584
|
+
method: "POST",
|
|
1585
|
+
headers: {
|
|
1586
|
+
"Content-Type": "application/json"
|
|
1587
|
+
},
|
|
1588
|
+
body: JSON.stringify({
|
|
1589
|
+
...clientMetadata,
|
|
1590
|
+
...scope !== void 0 ? { scope } : {}
|
|
1591
|
+
})
|
|
1592
|
+
});
|
|
1593
|
+
if (!response.ok) {
|
|
1594
|
+
throw await parseErrorResponse(response);
|
|
1595
|
+
}
|
|
1596
|
+
return OAuthClientInformationFullSchema.parse(await response.json());
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
// node_modules/.pnpm/eventsource-parser@3.1.0/node_modules/eventsource-parser/dist/index.js
|
|
1600
|
+
var ParseError = class extends Error {
|
|
1601
|
+
constructor(message, options) {
|
|
1602
|
+
super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
|
|
1603
|
+
}
|
|
1604
|
+
};
|
|
1605
|
+
var LF = 10;
|
|
1606
|
+
var CR = 13;
|
|
1607
|
+
var SPACE = 32;
|
|
1608
|
+
function noop(_arg) {
|
|
1609
|
+
}
|
|
1610
|
+
function createParser(config) {
|
|
1611
|
+
if (typeof config == "function")
|
|
1612
|
+
throw new TypeError(
|
|
1613
|
+
"`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?"
|
|
1614
|
+
);
|
|
1615
|
+
const { onEvent = noop, onError = noop, onRetry = noop, onComment, maxBufferSize } = config, pendingFragments = [];
|
|
1616
|
+
let pendingFragmentsLength = 0, isFirstChunk = true, id, data = "", dataLines = 0, eventType, terminated = false;
|
|
1617
|
+
function feed(chunk) {
|
|
1618
|
+
if (terminated)
|
|
1619
|
+
throw new Error(
|
|
1620
|
+
"Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing."
|
|
1621
|
+
);
|
|
1622
|
+
if (isFirstChunk && (isFirstChunk = false, chunk.charCodeAt(0) === 239 && chunk.charCodeAt(1) === 187 && chunk.charCodeAt(2) === 191 && (chunk = chunk.slice(3))), pendingFragments.length === 0) {
|
|
1623
|
+
const trailing2 = processLines(chunk);
|
|
1624
|
+
trailing2 !== "" && (pendingFragments.push(trailing2), pendingFragmentsLength = trailing2.length), checkBufferSize();
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
if (chunk.indexOf(`
|
|
1628
|
+
`) === -1 && chunk.indexOf("\r") === -1) {
|
|
1629
|
+
pendingFragments.push(chunk), pendingFragmentsLength += chunk.length, checkBufferSize();
|
|
1630
|
+
return;
|
|
1631
|
+
}
|
|
1632
|
+
pendingFragments.push(chunk);
|
|
1633
|
+
const input = pendingFragments.join("");
|
|
1634
|
+
pendingFragments.length = 0, pendingFragmentsLength = 0;
|
|
1635
|
+
const trailing = processLines(input);
|
|
1636
|
+
trailing !== "" && (pendingFragments.push(trailing), pendingFragmentsLength = trailing.length), checkBufferSize();
|
|
1637
|
+
}
|
|
1638
|
+
function checkBufferSize() {
|
|
1639
|
+
maxBufferSize !== void 0 && (pendingFragmentsLength + data.length <= maxBufferSize || (terminated = true, pendingFragments.length = 0, pendingFragmentsLength = 0, id = void 0, data = "", dataLines = 0, eventType = void 0, onError(
|
|
1640
|
+
new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, {
|
|
1641
|
+
type: "max-buffer-size-exceeded"
|
|
1642
|
+
})
|
|
1643
|
+
)));
|
|
1644
|
+
}
|
|
1645
|
+
function processLines(chunk) {
|
|
1646
|
+
let searchIndex = 0;
|
|
1647
|
+
if (chunk.indexOf("\r") === -1) {
|
|
1648
|
+
let lfIndex = chunk.indexOf(`
|
|
1649
|
+
`, searchIndex);
|
|
1650
|
+
for (; lfIndex !== -1; ) {
|
|
1651
|
+
if (searchIndex === lfIndex) {
|
|
1652
|
+
dataLines > 0 && onEvent({ id, event: eventType, data }), id = void 0, data = "", dataLines = 0, eventType = void 0, searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
1653
|
+
`, searchIndex);
|
|
1654
|
+
continue;
|
|
1655
|
+
}
|
|
1656
|
+
const firstCharCode = chunk.charCodeAt(searchIndex);
|
|
1657
|
+
if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
|
|
1658
|
+
const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5, value = chunk.slice(valueStart, lfIndex);
|
|
1659
|
+
if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
|
|
1660
|
+
onEvent({ id, event: eventType, data: value }), id = void 0, data = "", eventType = void 0, searchIndex = lfIndex + 2, lfIndex = chunk.indexOf(`
|
|
1661
|
+
`, searchIndex);
|
|
1662
|
+
continue;
|
|
1663
|
+
}
|
|
1664
|
+
data = dataLines === 0 ? value : `${data}
|
|
1665
|
+
${value}`, dataLines++;
|
|
1666
|
+
} else isEventPrefix(chunk, searchIndex, firstCharCode) ? eventType = chunk.slice(
|
|
1667
|
+
chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6,
|
|
1668
|
+
lfIndex
|
|
1669
|
+
) || void 0 : parseLine(chunk, searchIndex, lfIndex);
|
|
1670
|
+
searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
1671
|
+
`, searchIndex);
|
|
1672
|
+
}
|
|
1673
|
+
return chunk.slice(searchIndex);
|
|
1674
|
+
}
|
|
1675
|
+
for (; searchIndex < chunk.length; ) {
|
|
1676
|
+
const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
|
|
1677
|
+
`, searchIndex);
|
|
1678
|
+
let lineEnd = -1;
|
|
1679
|
+
if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = crIndex < lfIndex ? crIndex : lfIndex : crIndex !== -1 ? crIndex === chunk.length - 1 ? lineEnd = -1 : lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1)
|
|
1680
|
+
break;
|
|
1681
|
+
parseLine(chunk, searchIndex, lineEnd), searchIndex = lineEnd + 1, chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF && searchIndex++;
|
|
1682
|
+
}
|
|
1683
|
+
return chunk.slice(searchIndex);
|
|
1684
|
+
}
|
|
1685
|
+
function parseLine(chunk, start, end) {
|
|
1686
|
+
if (start === end) {
|
|
1687
|
+
dispatchEvent();
|
|
1688
|
+
return;
|
|
1689
|
+
}
|
|
1690
|
+
const firstCharCode = chunk.charCodeAt(start);
|
|
1691
|
+
if (isDataPrefix(chunk, start, firstCharCode)) {
|
|
1692
|
+
const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5, value2 = chunk.slice(valueStart, end);
|
|
1693
|
+
data = dataLines === 0 ? value2 : `${data}
|
|
1694
|
+
${value2}`, dataLines++;
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
if (isEventPrefix(chunk, start, firstCharCode)) {
|
|
1698
|
+
eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
|
|
1699
|
+
return;
|
|
1700
|
+
}
|
|
1701
|
+
if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
|
|
1702
|
+
const value2 = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
|
|
1703
|
+
id = value2.includes("\0") ? void 0 : value2;
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1706
|
+
if (firstCharCode === 58) {
|
|
1707
|
+
if (onComment) {
|
|
1708
|
+
const line2 = chunk.slice(start, end);
|
|
1709
|
+
onComment(line2.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
|
|
1710
|
+
}
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
const line = chunk.slice(start, end), fieldSeparatorIndex = line.indexOf(":");
|
|
1714
|
+
if (fieldSeparatorIndex === -1) {
|
|
1715
|
+
processField(line, "", line);
|
|
1716
|
+
return;
|
|
1717
|
+
}
|
|
1718
|
+
const field = line.slice(0, fieldSeparatorIndex), offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
|
|
1719
|
+
processField(field, value, line);
|
|
1720
|
+
}
|
|
1721
|
+
function processField(field, value, line) {
|
|
1722
|
+
switch (field) {
|
|
1723
|
+
case "event":
|
|
1724
|
+
eventType = value || void 0;
|
|
1725
|
+
break;
|
|
1726
|
+
case "data":
|
|
1727
|
+
data = dataLines === 0 ? value : `${data}
|
|
1728
|
+
${value}`, dataLines++;
|
|
1729
|
+
break;
|
|
1730
|
+
case "id":
|
|
1731
|
+
id = value.includes("\0") ? void 0 : value;
|
|
1732
|
+
break;
|
|
1733
|
+
case "retry":
|
|
1734
|
+
/^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(
|
|
1735
|
+
new ParseError(`Invalid \`retry\` value: "${value}"`, {
|
|
1736
|
+
type: "invalid-retry",
|
|
1737
|
+
value,
|
|
1738
|
+
line
|
|
1739
|
+
})
|
|
1740
|
+
);
|
|
1741
|
+
break;
|
|
1742
|
+
default:
|
|
1743
|
+
onError(
|
|
1744
|
+
new ParseError(
|
|
1745
|
+
`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`,
|
|
1746
|
+
{ type: "unknown-field", field, value, line }
|
|
1747
|
+
)
|
|
1748
|
+
);
|
|
1749
|
+
break;
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
function dispatchEvent() {
|
|
1753
|
+
dataLines > 0 && onEvent({
|
|
1754
|
+
id,
|
|
1755
|
+
event: eventType,
|
|
1756
|
+
data
|
|
1757
|
+
}), id = void 0, data = "", dataLines = 0, eventType = void 0;
|
|
1758
|
+
}
|
|
1759
|
+
function reset(options = {}) {
|
|
1760
|
+
if (options.consume && pendingFragments.length > 0) {
|
|
1761
|
+
const incompleteLine = pendingFragments.join("");
|
|
1762
|
+
parseLine(incompleteLine, 0, incompleteLine.length);
|
|
1763
|
+
}
|
|
1764
|
+
isFirstChunk = true, id = void 0, data = "", dataLines = 0, eventType = void 0, pendingFragments.length = 0, pendingFragmentsLength = 0, terminated = false;
|
|
1765
|
+
}
|
|
1766
|
+
return { feed, reset };
|
|
1767
|
+
}
|
|
1768
|
+
function isDataPrefix(chunk, i, firstCharCode) {
|
|
1769
|
+
return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;
|
|
1770
|
+
}
|
|
1771
|
+
function isEventPrefix(chunk, i, firstCharCode) {
|
|
1772
|
+
return firstCharCode === 101 && chunk.charCodeAt(i + 1) === 118 && chunk.charCodeAt(i + 2) === 101 && chunk.charCodeAt(i + 3) === 110 && chunk.charCodeAt(i + 4) === 116 && chunk.charCodeAt(i + 5) === 58;
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
// node_modules/.pnpm/eventsource-parser@3.1.0/node_modules/eventsource-parser/dist/stream.js
|
|
1776
|
+
var EventSourceParserStream = class extends TransformStream {
|
|
1777
|
+
constructor({ onError, onRetry, onComment, maxBufferSize } = {}) {
|
|
1778
|
+
let parser;
|
|
1779
|
+
super({
|
|
1780
|
+
start(controller) {
|
|
1781
|
+
parser = createParser({
|
|
1782
|
+
onEvent: (event) => {
|
|
1783
|
+
controller.enqueue(event);
|
|
1784
|
+
},
|
|
1785
|
+
onError(error) {
|
|
1786
|
+
typeof onError == "function" && onError(error), (onError === "terminate" || error.type === "max-buffer-size-exceeded") && controller.error(error);
|
|
1787
|
+
},
|
|
1788
|
+
onRetry,
|
|
1789
|
+
onComment,
|
|
1790
|
+
maxBufferSize
|
|
1791
|
+
});
|
|
1792
|
+
},
|
|
1793
|
+
transform(chunk) {
|
|
1794
|
+
parser.feed(chunk);
|
|
1795
|
+
}
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
};
|
|
1799
|
+
|
|
1800
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js
|
|
1801
|
+
var DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS = {
|
|
1802
|
+
initialReconnectionDelay: 1e3,
|
|
1803
|
+
maxReconnectionDelay: 3e4,
|
|
1804
|
+
reconnectionDelayGrowFactor: 1.5,
|
|
1805
|
+
maxRetries: 2
|
|
1806
|
+
};
|
|
1807
|
+
var StreamableHTTPError = class extends Error {
|
|
1808
|
+
constructor(code, message) {
|
|
1809
|
+
super(`Streamable HTTP error: ${message}`);
|
|
1810
|
+
this.code = code;
|
|
1811
|
+
}
|
|
1812
|
+
};
|
|
1813
|
+
var StreamableHTTPClientTransport = class {
|
|
1814
|
+
constructor(url2, opts) {
|
|
1815
|
+
this._hasCompletedAuthFlow = false;
|
|
1816
|
+
this._url = url2;
|
|
1817
|
+
this._resourceMetadataUrl = void 0;
|
|
1818
|
+
this._scope = void 0;
|
|
1819
|
+
this._requestInit = opts?.requestInit;
|
|
1820
|
+
this._authProvider = opts?.authProvider;
|
|
1821
|
+
this._fetch = opts?.fetch;
|
|
1822
|
+
this._fetchWithInit = createFetchWithInit(opts?.fetch, opts?.requestInit);
|
|
1823
|
+
this._sessionId = opts?.sessionId;
|
|
1824
|
+
this._reconnectionOptions = opts?.reconnectionOptions ?? DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS;
|
|
1825
|
+
}
|
|
1826
|
+
async _authThenStart() {
|
|
1827
|
+
if (!this._authProvider) {
|
|
1828
|
+
throw new UnauthorizedError("No auth provider");
|
|
1829
|
+
}
|
|
1830
|
+
let result;
|
|
1831
|
+
try {
|
|
1832
|
+
result = await auth(this._authProvider, {
|
|
1833
|
+
serverUrl: this._url,
|
|
1834
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
1835
|
+
scope: this._scope,
|
|
1836
|
+
fetchFn: this._fetchWithInit
|
|
1837
|
+
});
|
|
1838
|
+
} catch (error) {
|
|
1839
|
+
this.onerror?.(error);
|
|
1840
|
+
throw error;
|
|
1841
|
+
}
|
|
1842
|
+
if (result !== "AUTHORIZED") {
|
|
1843
|
+
throw new UnauthorizedError();
|
|
1844
|
+
}
|
|
1845
|
+
return await this._startOrAuthSse({ resumptionToken: void 0 });
|
|
1846
|
+
}
|
|
1847
|
+
async _commonHeaders() {
|
|
1848
|
+
const headers = {};
|
|
1849
|
+
if (this._authProvider) {
|
|
1850
|
+
const tokens = await this._authProvider.tokens();
|
|
1851
|
+
if (tokens) {
|
|
1852
|
+
headers["Authorization"] = `Bearer ${tokens.access_token}`;
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
if (this._sessionId) {
|
|
1856
|
+
headers["mcp-session-id"] = this._sessionId;
|
|
1857
|
+
}
|
|
1858
|
+
if (this._protocolVersion) {
|
|
1859
|
+
headers["mcp-protocol-version"] = this._protocolVersion;
|
|
1860
|
+
}
|
|
1861
|
+
const extraHeaders = normalizeHeaders(this._requestInit?.headers);
|
|
1862
|
+
return new Headers({
|
|
1863
|
+
...headers,
|
|
1864
|
+
...extraHeaders
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
async _startOrAuthSse(options) {
|
|
1868
|
+
const { resumptionToken } = options;
|
|
1869
|
+
try {
|
|
1870
|
+
const headers = await this._commonHeaders();
|
|
1871
|
+
headers.set("Accept", "text/event-stream");
|
|
1872
|
+
if (resumptionToken) {
|
|
1873
|
+
headers.set("last-event-id", resumptionToken);
|
|
1874
|
+
}
|
|
1875
|
+
const response = await (this._fetch ?? fetch)(this._url, {
|
|
1876
|
+
method: "GET",
|
|
1877
|
+
headers,
|
|
1878
|
+
signal: this._abortController?.signal
|
|
1879
|
+
});
|
|
1880
|
+
if (!response.ok) {
|
|
1881
|
+
await response.body?.cancel();
|
|
1882
|
+
if (response.status === 401 && this._authProvider) {
|
|
1883
|
+
return await this._authThenStart();
|
|
1884
|
+
}
|
|
1885
|
+
if (response.status === 405) {
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
throw new StreamableHTTPError(response.status, `Failed to open SSE stream: ${response.statusText}`);
|
|
1889
|
+
}
|
|
1890
|
+
this._handleSseStream(response.body, options, true);
|
|
1891
|
+
} catch (error) {
|
|
1892
|
+
this.onerror?.(error);
|
|
1893
|
+
throw error;
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
/**
|
|
1897
|
+
* Calculates the next reconnection delay using backoff algorithm
|
|
1898
|
+
*
|
|
1899
|
+
* @param attempt Current reconnection attempt count for the specific stream
|
|
1900
|
+
* @returns Time to wait in milliseconds before next reconnection attempt
|
|
1901
|
+
*/
|
|
1902
|
+
_getNextReconnectionDelay(attempt) {
|
|
1903
|
+
if (this._serverRetryMs !== void 0) {
|
|
1904
|
+
return this._serverRetryMs;
|
|
1905
|
+
}
|
|
1906
|
+
const initialDelay = this._reconnectionOptions.initialReconnectionDelay;
|
|
1907
|
+
const growFactor = this._reconnectionOptions.reconnectionDelayGrowFactor;
|
|
1908
|
+
const maxDelay = this._reconnectionOptions.maxReconnectionDelay;
|
|
1909
|
+
return Math.min(initialDelay * Math.pow(growFactor, attempt), maxDelay);
|
|
1910
|
+
}
|
|
1911
|
+
/**
|
|
1912
|
+
* Schedule a reconnection attempt using server-provided retry interval or backoff
|
|
1913
|
+
*
|
|
1914
|
+
* @param lastEventId The ID of the last received event for resumability
|
|
1915
|
+
* @param attemptCount Current reconnection attempt count for this specific stream
|
|
1916
|
+
*/
|
|
1917
|
+
_scheduleReconnection(options, attemptCount = 0) {
|
|
1918
|
+
const maxRetries = this._reconnectionOptions.maxRetries;
|
|
1919
|
+
if (attemptCount >= maxRetries) {
|
|
1920
|
+
this.onerror?.(new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
const delay = this._getNextReconnectionDelay(attemptCount);
|
|
1924
|
+
this._reconnectionTimeout = setTimeout(() => {
|
|
1925
|
+
this._startOrAuthSse(options).catch((error) => {
|
|
1926
|
+
this.onerror?.(new Error(`Failed to reconnect SSE stream: ${error instanceof Error ? error.message : String(error)}`));
|
|
1927
|
+
this._scheduleReconnection(options, attemptCount + 1);
|
|
1928
|
+
});
|
|
1929
|
+
}, delay);
|
|
1930
|
+
}
|
|
1931
|
+
_handleSseStream(stream, options, isReconnectable) {
|
|
1932
|
+
if (!stream) {
|
|
1933
|
+
return;
|
|
1934
|
+
}
|
|
1935
|
+
const { onresumptiontoken, replayMessageId } = options;
|
|
1936
|
+
let lastEventId;
|
|
1937
|
+
let hasPrimingEvent = false;
|
|
1938
|
+
let receivedResponse = false;
|
|
1939
|
+
const processStream = async () => {
|
|
1940
|
+
try {
|
|
1941
|
+
const reader = stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream({
|
|
1942
|
+
onRetry: (retryMs) => {
|
|
1943
|
+
this._serverRetryMs = retryMs;
|
|
1944
|
+
}
|
|
1945
|
+
})).getReader();
|
|
1946
|
+
while (true) {
|
|
1947
|
+
const { value: event, done } = await reader.read();
|
|
1948
|
+
if (done) {
|
|
1949
|
+
break;
|
|
1950
|
+
}
|
|
1951
|
+
if (event.id) {
|
|
1952
|
+
lastEventId = event.id;
|
|
1953
|
+
hasPrimingEvent = true;
|
|
1954
|
+
onresumptiontoken?.(event.id);
|
|
1955
|
+
}
|
|
1956
|
+
if (!event.data) {
|
|
1957
|
+
continue;
|
|
1958
|
+
}
|
|
1959
|
+
if (!event.event || event.event === "message") {
|
|
1960
|
+
try {
|
|
1961
|
+
const message = JSONRPCMessageSchema.parse(JSON.parse(event.data));
|
|
1962
|
+
if (isJSONRPCResultResponse(message)) {
|
|
1963
|
+
receivedResponse = true;
|
|
1964
|
+
if (replayMessageId !== void 0) {
|
|
1965
|
+
message.id = replayMessageId;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
this.onmessage?.(message);
|
|
1969
|
+
} catch (error) {
|
|
1970
|
+
this.onerror?.(error);
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
const canResume = isReconnectable || hasPrimingEvent;
|
|
1975
|
+
const needsReconnect = canResume && !receivedResponse;
|
|
1976
|
+
if (needsReconnect && this._abortController && !this._abortController.signal.aborted) {
|
|
1977
|
+
this._scheduleReconnection({
|
|
1978
|
+
resumptionToken: lastEventId,
|
|
1979
|
+
onresumptiontoken,
|
|
1980
|
+
replayMessageId
|
|
1981
|
+
}, 0);
|
|
1982
|
+
}
|
|
1983
|
+
} catch (error) {
|
|
1984
|
+
this.onerror?.(new Error(`SSE stream disconnected: ${error}`));
|
|
1985
|
+
const canResume = isReconnectable || hasPrimingEvent;
|
|
1986
|
+
const needsReconnect = canResume && !receivedResponse;
|
|
1987
|
+
if (needsReconnect && this._abortController && !this._abortController.signal.aborted) {
|
|
1988
|
+
try {
|
|
1989
|
+
this._scheduleReconnection({
|
|
1990
|
+
resumptionToken: lastEventId,
|
|
1991
|
+
onresumptiontoken,
|
|
1992
|
+
replayMessageId
|
|
1993
|
+
}, 0);
|
|
1994
|
+
} catch (error2) {
|
|
1995
|
+
this.onerror?.(new Error(`Failed to reconnect: ${error2 instanceof Error ? error2.message : String(error2)}`));
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
};
|
|
2000
|
+
processStream();
|
|
2001
|
+
}
|
|
2002
|
+
async start() {
|
|
2003
|
+
if (this._abortController) {
|
|
2004
|
+
throw new Error("StreamableHTTPClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
2005
|
+
}
|
|
2006
|
+
this._abortController = new AbortController();
|
|
2007
|
+
}
|
|
2008
|
+
/**
|
|
2009
|
+
* Call this method after the user has finished authorizing via their user agent and is redirected back to the MCP client application. This will exchange the authorization code for an access token, enabling the next connection attempt to successfully auth.
|
|
2010
|
+
*/
|
|
2011
|
+
async finishAuth(authorizationCode) {
|
|
2012
|
+
if (!this._authProvider) {
|
|
2013
|
+
throw new UnauthorizedError("No auth provider");
|
|
2014
|
+
}
|
|
2015
|
+
const result = await auth(this._authProvider, {
|
|
2016
|
+
serverUrl: this._url,
|
|
2017
|
+
authorizationCode,
|
|
2018
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
2019
|
+
scope: this._scope,
|
|
2020
|
+
fetchFn: this._fetchWithInit
|
|
2021
|
+
});
|
|
2022
|
+
if (result !== "AUTHORIZED") {
|
|
2023
|
+
throw new UnauthorizedError("Failed to authorize");
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
async close() {
|
|
2027
|
+
if (this._reconnectionTimeout) {
|
|
2028
|
+
clearTimeout(this._reconnectionTimeout);
|
|
2029
|
+
this._reconnectionTimeout = void 0;
|
|
2030
|
+
}
|
|
2031
|
+
this._abortController?.abort();
|
|
2032
|
+
this.onclose?.();
|
|
2033
|
+
}
|
|
2034
|
+
async send(message, options) {
|
|
2035
|
+
try {
|
|
2036
|
+
const { resumptionToken, onresumptiontoken } = options || {};
|
|
2037
|
+
if (resumptionToken) {
|
|
2038
|
+
this._startOrAuthSse({ resumptionToken, replayMessageId: isJSONRPCRequest(message) ? message.id : void 0 }).catch((err) => this.onerror?.(err));
|
|
2039
|
+
return;
|
|
2040
|
+
}
|
|
2041
|
+
const headers = await this._commonHeaders();
|
|
2042
|
+
headers.set("content-type", "application/json");
|
|
2043
|
+
headers.set("accept", "application/json, text/event-stream");
|
|
2044
|
+
const init = {
|
|
2045
|
+
...this._requestInit,
|
|
2046
|
+
method: "POST",
|
|
2047
|
+
headers,
|
|
2048
|
+
body: JSON.stringify(message),
|
|
2049
|
+
signal: this._abortController?.signal
|
|
2050
|
+
};
|
|
2051
|
+
const response = await (this._fetch ?? fetch)(this._url, init);
|
|
2052
|
+
const sessionId = response.headers.get("mcp-session-id");
|
|
2053
|
+
if (sessionId) {
|
|
2054
|
+
this._sessionId = sessionId;
|
|
2055
|
+
}
|
|
2056
|
+
if (!response.ok) {
|
|
2057
|
+
const text = await response.text().catch(() => null);
|
|
2058
|
+
if (response.status === 401 && this._authProvider) {
|
|
2059
|
+
if (this._hasCompletedAuthFlow) {
|
|
2060
|
+
throw new StreamableHTTPError(401, "Server returned 401 after successful authentication");
|
|
2061
|
+
}
|
|
2062
|
+
const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
|
|
2063
|
+
this._resourceMetadataUrl = resourceMetadataUrl;
|
|
2064
|
+
this._scope = scope;
|
|
2065
|
+
const result = await auth(this._authProvider, {
|
|
2066
|
+
serverUrl: this._url,
|
|
2067
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
2068
|
+
scope: this._scope,
|
|
2069
|
+
fetchFn: this._fetchWithInit
|
|
2070
|
+
});
|
|
2071
|
+
if (result !== "AUTHORIZED") {
|
|
2072
|
+
throw new UnauthorizedError();
|
|
2073
|
+
}
|
|
2074
|
+
this._hasCompletedAuthFlow = true;
|
|
2075
|
+
return this.send(message);
|
|
2076
|
+
}
|
|
2077
|
+
if (response.status === 403 && this._authProvider) {
|
|
2078
|
+
const { resourceMetadataUrl, scope, error } = extractWWWAuthenticateParams(response);
|
|
2079
|
+
if (error === "insufficient_scope") {
|
|
2080
|
+
const wwwAuthHeader = response.headers.get("WWW-Authenticate");
|
|
2081
|
+
if (this._lastUpscopingHeader === wwwAuthHeader) {
|
|
2082
|
+
throw new StreamableHTTPError(403, "Server returned 403 after trying upscoping");
|
|
2083
|
+
}
|
|
2084
|
+
if (scope) {
|
|
2085
|
+
this._scope = scope;
|
|
2086
|
+
}
|
|
2087
|
+
if (resourceMetadataUrl) {
|
|
2088
|
+
this._resourceMetadataUrl = resourceMetadataUrl;
|
|
2089
|
+
}
|
|
2090
|
+
this._lastUpscopingHeader = wwwAuthHeader ?? void 0;
|
|
2091
|
+
const result = await auth(this._authProvider, {
|
|
2092
|
+
serverUrl: this._url,
|
|
2093
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
2094
|
+
scope: this._scope,
|
|
2095
|
+
fetchFn: this._fetch
|
|
2096
|
+
});
|
|
2097
|
+
if (result !== "AUTHORIZED") {
|
|
2098
|
+
throw new UnauthorizedError();
|
|
2099
|
+
}
|
|
2100
|
+
return this.send(message);
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
throw new StreamableHTTPError(response.status, `Error POSTing to endpoint: ${text}`);
|
|
2104
|
+
}
|
|
2105
|
+
this._hasCompletedAuthFlow = false;
|
|
2106
|
+
this._lastUpscopingHeader = void 0;
|
|
2107
|
+
if (response.status === 202) {
|
|
2108
|
+
await response.body?.cancel();
|
|
2109
|
+
if (isInitializedNotification(message)) {
|
|
2110
|
+
this._startOrAuthSse({ resumptionToken: void 0 }).catch((err) => this.onerror?.(err));
|
|
2111
|
+
}
|
|
2112
|
+
return;
|
|
2113
|
+
}
|
|
2114
|
+
const messages = Array.isArray(message) ? message : [message];
|
|
2115
|
+
const hasRequests = messages.filter((msg) => "method" in msg && "id" in msg && msg.id !== void 0).length > 0;
|
|
2116
|
+
const contentType = response.headers.get("content-type");
|
|
2117
|
+
if (hasRequests) {
|
|
2118
|
+
if (contentType?.includes("text/event-stream")) {
|
|
2119
|
+
this._handleSseStream(response.body, { onresumptiontoken }, false);
|
|
2120
|
+
} else if (contentType?.includes("application/json")) {
|
|
2121
|
+
const data = await response.json();
|
|
2122
|
+
const responseMessages = Array.isArray(data) ? data.map((msg) => JSONRPCMessageSchema.parse(msg)) : [JSONRPCMessageSchema.parse(data)];
|
|
2123
|
+
for (const msg of responseMessages) {
|
|
2124
|
+
this.onmessage?.(msg);
|
|
2125
|
+
}
|
|
2126
|
+
} else {
|
|
2127
|
+
await response.body?.cancel();
|
|
2128
|
+
throw new StreamableHTTPError(-1, `Unexpected content type: ${contentType}`);
|
|
2129
|
+
}
|
|
2130
|
+
} else {
|
|
2131
|
+
await response.body?.cancel();
|
|
2132
|
+
}
|
|
2133
|
+
} catch (error) {
|
|
2134
|
+
this.onerror?.(error);
|
|
2135
|
+
throw error;
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
get sessionId() {
|
|
2139
|
+
return this._sessionId;
|
|
2140
|
+
}
|
|
2141
|
+
/**
|
|
2142
|
+
* Terminates the current session by sending a DELETE request to the server.
|
|
2143
|
+
*
|
|
2144
|
+
* Clients that no longer need a particular session
|
|
2145
|
+
* (e.g., because the user is leaving the client application) SHOULD send an
|
|
2146
|
+
* HTTP DELETE to the MCP endpoint with the Mcp-Session-Id header to explicitly
|
|
2147
|
+
* terminate the session.
|
|
2148
|
+
*
|
|
2149
|
+
* The server MAY respond with HTTP 405 Method Not Allowed, indicating that
|
|
2150
|
+
* the server does not allow clients to terminate sessions.
|
|
2151
|
+
*/
|
|
2152
|
+
async terminateSession() {
|
|
2153
|
+
if (!this._sessionId) {
|
|
2154
|
+
return;
|
|
2155
|
+
}
|
|
2156
|
+
try {
|
|
2157
|
+
const headers = await this._commonHeaders();
|
|
2158
|
+
const init = {
|
|
2159
|
+
...this._requestInit,
|
|
2160
|
+
method: "DELETE",
|
|
2161
|
+
headers,
|
|
2162
|
+
signal: this._abortController?.signal
|
|
2163
|
+
};
|
|
2164
|
+
const response = await (this._fetch ?? fetch)(this._url, init);
|
|
2165
|
+
await response.body?.cancel();
|
|
2166
|
+
if (!response.ok && response.status !== 405) {
|
|
2167
|
+
throw new StreamableHTTPError(response.status, `Failed to terminate session: ${response.statusText}`);
|
|
2168
|
+
}
|
|
2169
|
+
this._sessionId = void 0;
|
|
2170
|
+
} catch (error) {
|
|
2171
|
+
this.onerror?.(error);
|
|
2172
|
+
throw error;
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
setProtocolVersion(version) {
|
|
2176
|
+
this._protocolVersion = version;
|
|
2177
|
+
}
|
|
2178
|
+
get protocolVersion() {
|
|
2179
|
+
return this._protocolVersion;
|
|
2180
|
+
}
|
|
2181
|
+
/**
|
|
2182
|
+
* Resume an SSE stream from a previous event ID.
|
|
2183
|
+
* Opens a GET SSE connection with Last-Event-ID header to replay missed events.
|
|
2184
|
+
*
|
|
2185
|
+
* @param lastEventId The event ID to resume from
|
|
2186
|
+
* @param options Optional callback to receive new resumption tokens
|
|
2187
|
+
*/
|
|
2188
|
+
async resumeStream(lastEventId, options) {
|
|
2189
|
+
await this._startOrAuthSse({
|
|
2190
|
+
resumptionToken: lastEventId,
|
|
2191
|
+
onresumptiontoken: options?.onresumptiontoken
|
|
2192
|
+
});
|
|
2193
|
+
}
|
|
2194
|
+
};
|
|
2195
|
+
|
|
2196
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
2197
|
+
import process from "node:process";
|
|
2198
|
+
|
|
2199
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
2200
|
+
var ReadBuffer = class {
|
|
2201
|
+
append(chunk) {
|
|
2202
|
+
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
2203
|
+
}
|
|
2204
|
+
readMessage() {
|
|
2205
|
+
if (!this._buffer) {
|
|
2206
|
+
return null;
|
|
2207
|
+
}
|
|
2208
|
+
const index = this._buffer.indexOf("\n");
|
|
2209
|
+
if (index === -1) {
|
|
2210
|
+
return null;
|
|
2211
|
+
}
|
|
2212
|
+
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
|
|
2213
|
+
this._buffer = this._buffer.subarray(index + 1);
|
|
2214
|
+
return deserializeMessage(line);
|
|
2215
|
+
}
|
|
2216
|
+
clear() {
|
|
2217
|
+
this._buffer = void 0;
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2220
|
+
function deserializeMessage(line) {
|
|
2221
|
+
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
|
2222
|
+
}
|
|
2223
|
+
function serializeMessage(message) {
|
|
2224
|
+
return JSON.stringify(message) + "\n";
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
2228
|
+
var StdioServerTransport = class {
|
|
2229
|
+
constructor(_stdin = process.stdin, _stdout = process.stdout) {
|
|
2230
|
+
this._stdin = _stdin;
|
|
2231
|
+
this._stdout = _stdout;
|
|
2232
|
+
this._readBuffer = new ReadBuffer();
|
|
2233
|
+
this._started = false;
|
|
2234
|
+
this._ondata = (chunk) => {
|
|
2235
|
+
this._readBuffer.append(chunk);
|
|
2236
|
+
this.processReadBuffer();
|
|
2237
|
+
};
|
|
2238
|
+
this._onerror = (error) => {
|
|
2239
|
+
this.onerror?.(error);
|
|
2240
|
+
};
|
|
2241
|
+
}
|
|
2242
|
+
/**
|
|
2243
|
+
* Starts listening for messages on stdin.
|
|
2244
|
+
*/
|
|
2245
|
+
async start() {
|
|
2246
|
+
if (this._started) {
|
|
2247
|
+
throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
|
2248
|
+
}
|
|
2249
|
+
this._started = true;
|
|
2250
|
+
this._stdin.on("data", this._ondata);
|
|
2251
|
+
this._stdin.on("error", this._onerror);
|
|
2252
|
+
}
|
|
2253
|
+
processReadBuffer() {
|
|
2254
|
+
while (true) {
|
|
2255
|
+
try {
|
|
2256
|
+
const message = this._readBuffer.readMessage();
|
|
2257
|
+
if (message === null) {
|
|
2258
|
+
break;
|
|
2259
|
+
}
|
|
2260
|
+
this.onmessage?.(message);
|
|
2261
|
+
} catch (error) {
|
|
2262
|
+
this.onerror?.(error);
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
async close() {
|
|
2267
|
+
this._stdin.off("data", this._ondata);
|
|
2268
|
+
this._stdin.off("error", this._onerror);
|
|
2269
|
+
const remainingDataListeners = this._stdin.listenerCount("data");
|
|
2270
|
+
if (remainingDataListeners === 0) {
|
|
2271
|
+
this._stdin.pause();
|
|
2272
|
+
}
|
|
2273
|
+
this._readBuffer.clear();
|
|
2274
|
+
this.onclose?.();
|
|
2275
|
+
}
|
|
2276
|
+
send(message) {
|
|
2277
|
+
return new Promise((resolve) => {
|
|
2278
|
+
const json = serializeMessage(message);
|
|
2279
|
+
if (this._stdout.write(json)) {
|
|
2280
|
+
resolve();
|
|
2281
|
+
} else {
|
|
2282
|
+
this._stdout.once("drain", resolve);
|
|
2283
|
+
}
|
|
2284
|
+
});
|
|
2285
|
+
}
|
|
2286
|
+
};
|
|
2287
|
+
|
|
2288
|
+
// src/mcp/bridge.ts
|
|
2289
|
+
function resolveRoomMcpUrl(baseUrl) {
|
|
2290
|
+
const trimmed = baseUrl.replace(/\/$/, "");
|
|
2291
|
+
if (trimmed.endsWith("/mcp") || trimmed.endsWith("/trellis/mcp")) {
|
|
2292
|
+
return trimmed;
|
|
2293
|
+
}
|
|
2294
|
+
return `${trimmed}${roomMcpPathForUrl(trimmed)}`;
|
|
2295
|
+
}
|
|
2296
|
+
function resolveBridgeConfig(opts) {
|
|
2297
|
+
const configDir = opts.configDir ?? ".";
|
|
2298
|
+
const fileConfig = readConfig(configDir);
|
|
2299
|
+
const room = opts.room ?? process2.env.TRELLIS_ROOM_URL?.trim() ?? fileConfig?.url ?? (fileConfig?.mode === "local" && fileConfig.port ? `http://localhost:${fileConfig.port}` : void 0);
|
|
2300
|
+
if (!room) {
|
|
2301
|
+
throw new Error(
|
|
2302
|
+
"Room URL required. Pass --room <url> or run from a directory with remote .trellis-db.json"
|
|
2303
|
+
);
|
|
2304
|
+
}
|
|
2305
|
+
const apiKey = opts.apiKey ?? fileConfig?.apiKey;
|
|
2306
|
+
return {
|
|
2307
|
+
url: resolveRoomMcpUrl(room),
|
|
2308
|
+
apiKey
|
|
2309
|
+
};
|
|
2310
|
+
}
|
|
2311
|
+
async function connectRemoteRoomClient(config) {
|
|
2312
|
+
const headers = {};
|
|
2313
|
+
if (config.apiKey) {
|
|
2314
|
+
headers.Authorization = `Bearer ${config.apiKey}`;
|
|
2315
|
+
}
|
|
2316
|
+
const client = new Client({
|
|
2317
|
+
name: "trellis-room-bridge",
|
|
2318
|
+
version: "0.1.0"
|
|
2319
|
+
});
|
|
2320
|
+
const transport = new StreamableHTTPClientTransport(new URL(config.url), {
|
|
2321
|
+
requestInit: Object.keys(headers).length ? { headers } : void 0
|
|
2322
|
+
});
|
|
2323
|
+
await client.connect(transport);
|
|
2324
|
+
return { client, transport };
|
|
2325
|
+
}
|
|
2326
|
+
function createRoomMcpProxyServer(remote) {
|
|
2327
|
+
const server = new Server(
|
|
2328
|
+
{ name: "trellis-room-bridge", version: "0.1.0" },
|
|
2329
|
+
{ capabilities: { tools: {} } }
|
|
2330
|
+
);
|
|
2331
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => remote.listTools());
|
|
2332
|
+
server.setRequestHandler(
|
|
2333
|
+
CallToolRequestSchema,
|
|
2334
|
+
async (request) => remote.callTool(request.params)
|
|
2335
|
+
);
|
|
2336
|
+
return server;
|
|
2337
|
+
}
|
|
2338
|
+
async function runRoomMcpBridge(opts) {
|
|
2339
|
+
const config = resolveBridgeConfig(opts);
|
|
2340
|
+
const { client, transport } = await connectRemoteRoomClient(config);
|
|
2341
|
+
const server = createRoomMcpProxyServer(client);
|
|
2342
|
+
const stdio = new StdioServerTransport();
|
|
2343
|
+
let closing = false;
|
|
2344
|
+
const shutdown = async (code = 0) => {
|
|
2345
|
+
if (closing) return;
|
|
2346
|
+
closing = true;
|
|
2347
|
+
try {
|
|
2348
|
+
await transport.close();
|
|
2349
|
+
} catch {
|
|
2350
|
+
}
|
|
2351
|
+
process2.exit(code);
|
|
2352
|
+
};
|
|
2353
|
+
process2.on("SIGINT", () => void shutdown(0));
|
|
2354
|
+
process2.on("SIGTERM", () => void shutdown(0));
|
|
2355
|
+
process2.stdin.on("end", () => void shutdown(0));
|
|
2356
|
+
if (!opts.quiet) {
|
|
2357
|
+
console.error(`Trellis Room MCP bridge \u2192 ${config.url}`);
|
|
2358
|
+
}
|
|
2359
|
+
await server.connect(stdio);
|
|
2360
|
+
}
|
|
2361
|
+
export {
|
|
2362
|
+
connectRemoteRoomClient,
|
|
2363
|
+
createRoomMcpProxyServer,
|
|
2364
|
+
resolveBridgeConfig,
|
|
2365
|
+
resolveRoomMcpUrl,
|
|
2366
|
+
runRoomMcpBridge
|
|
2367
|
+
};
|