@phake/mcp 0.0.1

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.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +187 -0
  3. package/dist/adapters/http-node/http/app.d.ts +5 -0
  4. package/dist/adapters/http-node/http/auth-app.d.ts +5 -0
  5. package/dist/adapters/http-node/http/middlewares/auth.d.ts +39 -0
  6. package/dist/adapters/http-node/http/middlewares/cors.d.ts +8 -0
  7. package/dist/adapters/http-node/http/routes/health.d.ts +5 -0
  8. package/dist/adapters/http-node/http/routes/mcp.d.ts +11 -0
  9. package/dist/adapters/http-node/middleware.security.d.ts +6 -0
  10. package/dist/adapters/http-node/routes.discovery.d.ts +6 -0
  11. package/dist/adapters/http-node/routes.oauth.d.ts +7 -0
  12. package/dist/adapters/http-worker/index.d.ts +48 -0
  13. package/dist/adapters/http-worker/mcp.handler.d.ts +24 -0
  14. package/dist/adapters/http-worker/routes.discovery.d.ts +7 -0
  15. package/dist/adapters/http-worker/routes.oauth.d.ts +8 -0
  16. package/dist/adapters/http-worker/security.d.ts +7 -0
  17. package/dist/index-1zyem3xr.js +14893 -0
  18. package/dist/index-4f4xvtt9.js +19552 -0
  19. package/dist/index-sbqy8kgq.js +3478 -0
  20. package/dist/index.d.ts +27 -0
  21. package/dist/index.js +1083 -0
  22. package/dist/mcp-server.d.ts +18 -0
  23. package/dist/runtime/node/capabilities.d.ts +2 -0
  24. package/dist/runtime/node/context.d.ts +29 -0
  25. package/dist/runtime/node/index.d.ts +5 -0
  26. package/dist/runtime/node/index.js +27 -0
  27. package/dist/runtime/node/mcp.d.ts +28 -0
  28. package/dist/runtime/node/storage/file.d.ts +44 -0
  29. package/dist/runtime/node/storage/sqlite.d.ts +213 -0
  30. package/dist/runtime/worker/index.d.ts +1 -0
  31. package/dist/runtime/worker/index.js +12 -0
  32. package/dist/shared/auth/index.d.ts +1 -0
  33. package/dist/shared/auth/strategy.d.ts +71 -0
  34. package/dist/shared/config/env.d.ts +52 -0
  35. package/dist/shared/config/index.d.ts +2 -0
  36. package/dist/shared/config/metadata.d.ts +5 -0
  37. package/dist/shared/crypto/aes-gcm.d.ts +37 -0
  38. package/dist/shared/crypto/index.d.ts +1 -0
  39. package/dist/shared/http/cors.d.ts +20 -0
  40. package/dist/shared/http/index.d.ts +2 -0
  41. package/dist/shared/http/response.d.ts +52 -0
  42. package/dist/shared/mcp/dispatcher.d.ts +81 -0
  43. package/dist/shared/mcp/index.d.ts +3 -0
  44. package/dist/shared/mcp/security.d.ts +23 -0
  45. package/dist/shared/mcp/server-internals.d.ts +79 -0
  46. package/dist/shared/oauth/cimd.d.ts +43 -0
  47. package/dist/shared/oauth/discovery-handlers.d.ts +14 -0
  48. package/dist/shared/oauth/discovery.d.ts +26 -0
  49. package/dist/shared/oauth/endpoints.d.ts +11 -0
  50. package/dist/shared/oauth/flow.d.ts +31 -0
  51. package/dist/shared/oauth/index.d.ts +9 -0
  52. package/dist/shared/oauth/input-parsers.d.ts +43 -0
  53. package/dist/shared/oauth/refresh.d.ts +61 -0
  54. package/dist/shared/oauth/ssrf.d.ts +31 -0
  55. package/dist/shared/oauth/types.d.ts +78 -0
  56. package/dist/shared/schemas/prompts.d.ts +1 -0
  57. package/dist/shared/services/http-client.d.ts +16 -0
  58. package/dist/shared/services/index.d.ts +1 -0
  59. package/dist/shared/storage/index.d.ts +4 -0
  60. package/dist/shared/storage/interface.d.ts +99 -0
  61. package/dist/shared/storage/kv.d.ts +68 -0
  62. package/dist/shared/storage/memory.d.ts +91 -0
  63. package/dist/shared/storage/singleton.d.ts +4 -0
  64. package/dist/shared/tools/echo.d.ts +16 -0
  65. package/dist/shared/tools/health.d.ts +13 -0
  66. package/dist/shared/tools/index.d.ts +4 -0
  67. package/dist/shared/tools/registry.d.ts +64 -0
  68. package/dist/shared/tools/types.d.ts +161 -0
  69. package/dist/shared/types/auth.d.ts +35 -0
  70. package/dist/shared/types/context.d.ts +79 -0
  71. package/dist/shared/types/index.d.ts +8 -0
  72. package/dist/shared/types/provider.d.ts +28 -0
  73. package/dist/shared/utils/base64.d.ts +12 -0
  74. package/dist/shared/utils/cancellation.d.ts +13 -0
  75. package/dist/shared/utils/elicitation.d.ts +247 -0
  76. package/dist/shared/utils/formatting.d.ts +106 -0
  77. package/dist/shared/utils/index.d.ts +11 -0
  78. package/dist/shared/utils/limits.d.ts +6 -0
  79. package/dist/shared/utils/logger.d.ts +20 -0
  80. package/dist/shared/utils/pagination.d.ts +11 -0
  81. package/dist/shared/utils/progress.d.ts +56 -0
  82. package/dist/shared/utils/roots.d.ts +62 -0
  83. package/dist/shared/utils/sampling.d.ts +155 -0
  84. package/dist/shared/utils/security.d.ts +6 -0
  85. package/package.json +55 -0
package/dist/index.js ADDED
@@ -0,0 +1,1083 @@
1
+ // @bun
2
+ import {
3
+ FileTokenStore,
4
+ JSON_RPC_METHOD_NOT_FOUND,
5
+ SqliteSessionStore,
6
+ buildServer,
7
+ getLowLevelServer,
8
+ getServerWithInternals,
9
+ isJsonRpcError,
10
+ sessions
11
+ } from "./index-1zyem3xr.js";
12
+ import {
13
+ ClientMetadataSchema,
14
+ JsonRpcErrorCode,
15
+ KvSessionStore,
16
+ KvTokenStore,
17
+ LATEST_PROTOCOL_VERSION,
18
+ SUPPORTED_PROTOCOL_VERSIONS,
19
+ assertSsrfSafe,
20
+ buildAuthorizationServerMetadata,
21
+ buildCorsHeaders,
22
+ buildFlowOptions,
23
+ buildOAuthConfig,
24
+ buildProtectedResourceMetadata,
25
+ buildProviderConfig,
26
+ buildProviderRefreshConfig,
27
+ buildTokenInput,
28
+ buildUnauthorizedChallenge,
29
+ checkSsrfSafe,
30
+ corsPreflightResponse,
31
+ createDiscoveryHandlers,
32
+ createWorkerRouter,
33
+ dispatchMcpMethod,
34
+ ensureFreshToken,
35
+ fetchClientMetadata,
36
+ generateOpaqueToken,
37
+ getLogLevel,
38
+ getSessionStore,
39
+ getTokenStore,
40
+ handleAuthorize,
41
+ handleMcpNotification,
42
+ handleProviderCallback,
43
+ handleRegister,
44
+ handleRevoke,
45
+ handleToken,
46
+ initializeStorage,
47
+ initializeWorkerStorage,
48
+ isClientIdUrl,
49
+ isSsrfSafe,
50
+ isTokenExpiredOrExpiring,
51
+ nodeDiscoveryStrategy,
52
+ parseAuthorizeInput,
53
+ parseCallbackInput,
54
+ parseTokenInput,
55
+ refreshProviderToken,
56
+ shimProcessEnv,
57
+ validateOrigin,
58
+ validateProtocolVersion,
59
+ validateRedirectUri,
60
+ withCors,
61
+ workerDiscoveryStrategy
62
+ } from "./index-sbqy8kgq.js";
63
+ import {
64
+ CancellationError,
65
+ CancellationToken,
66
+ MAX_SESSIONS_PER_API_KEY,
67
+ MemorySessionStore,
68
+ MemoryTokenStore,
69
+ assertProviderToken,
70
+ authContextStorage,
71
+ base64Decode,
72
+ base64Encode,
73
+ base64UrlDecode,
74
+ base64UrlDecodeJson,
75
+ base64UrlDecodeString,
76
+ base64UrlEncode,
77
+ base64UrlEncodeJson,
78
+ base64UrlEncodeString,
79
+ buildCapabilities,
80
+ contextRegistry,
81
+ createCancellationToken,
82
+ createEncryptor,
83
+ decrypt,
84
+ defineTool,
85
+ echoInputSchema,
86
+ echoTool,
87
+ encrypt,
88
+ executeSharedTool,
89
+ exports_external,
90
+ generateKey,
91
+ getCurrentAuthContext,
92
+ getSharedTool,
93
+ getSharedToolNames,
94
+ healthInputSchema,
95
+ healthTool,
96
+ logger,
97
+ registerTools,
98
+ sharedLogger,
99
+ sharedTools,
100
+ startContextCleanup,
101
+ stopContextCleanup,
102
+ toProviderInfo,
103
+ toProviderTokens,
104
+ withCancellation
105
+ } from "./index-4f4xvtt9.js";
106
+ // src/shared/config/env.ts
107
+ function parseBoolean(value) {
108
+ return String(value || "false").toLowerCase() === "true";
109
+ }
110
+ function parseNumber(value, defaultValue) {
111
+ const num = Number(value);
112
+ return Number.isFinite(num) ? num : defaultValue;
113
+ }
114
+ function parseStringArray(value) {
115
+ return String(value || "").split(",").map((s) => s.trim()).filter(Boolean);
116
+ }
117
+ function parseAuthStrategy(env) {
118
+ const explicit = env.AUTH_STRATEGY?.toLowerCase();
119
+ if (explicit && ["oauth", "bearer", "api_key", "custom", "none"].includes(explicit)) {
120
+ return explicit;
121
+ }
122
+ if (parseBoolean(env.AUTH_ENABLED)) {
123
+ return "oauth";
124
+ }
125
+ if (env.API_KEY) {
126
+ return "api_key";
127
+ }
128
+ if (env.BEARER_TOKEN) {
129
+ return "bearer";
130
+ }
131
+ return "none";
132
+ }
133
+ function parseConfig(env) {
134
+ const authStrategy = parseAuthStrategy(env);
135
+ return {
136
+ HOST: String(env.HOST || "127.0.0.1"),
137
+ PORT: parseNumber(env.PORT, 3000),
138
+ NODE_ENV: env.NODE_ENV || "development",
139
+ MCP_TITLE: String(env.MCP_TITLE || "MCP Server Template"),
140
+ MCP_INSTRUCTIONS: String(env.MCP_INSTRUCTIONS || "Use these tools responsibly. Prefer minimal scopes and small page sizes."),
141
+ MCP_VERSION: String(env.MCP_VERSION || "0.1.0"),
142
+ MCP_PROTOCOL_VERSION: String(env.MCP_PROTOCOL_VERSION || "2025-06-18"),
143
+ MCP_ACCEPT_HEADERS: parseStringArray(env.MCP_ACCEPT_HEADERS),
144
+ AUTH_STRATEGY: authStrategy,
145
+ AUTH_ENABLED: authStrategy === "oauth" || parseBoolean(env.AUTH_ENABLED),
146
+ AUTH_REQUIRE_RS: parseBoolean(env.AUTH_REQUIRE_RS),
147
+ AUTH_ALLOW_DIRECT_BEARER: parseBoolean(env.AUTH_ALLOW_DIRECT_BEARER),
148
+ AUTH_RESOURCE_URI: env.AUTH_RESOURCE_URI,
149
+ AUTH_DISCOVERY_URL: env.AUTH_DISCOVERY_URL,
150
+ API_KEY: env.API_KEY,
151
+ API_KEY_HEADER: String(env.API_KEY_HEADER || "x-api-key"),
152
+ BEARER_TOKEN: env.BEARER_TOKEN,
153
+ CUSTOM_HEADERS: env.CUSTOM_HEADERS,
154
+ OAUTH_CLIENT_ID: env.OAUTH_CLIENT_ID,
155
+ OAUTH_CLIENT_SECRET: env.OAUTH_CLIENT_SECRET,
156
+ OAUTH_SCOPES: String(env.OAUTH_SCOPES || ""),
157
+ OAUTH_AUTHORIZATION_URL: env.OAUTH_AUTHORIZATION_URL,
158
+ OAUTH_TOKEN_URL: env.OAUTH_TOKEN_URL,
159
+ OAUTH_REVOCATION_URL: env.OAUTH_REVOCATION_URL,
160
+ OAUTH_REDIRECT_URI: String(env.OAUTH_REDIRECT_URI || "http://localhost:3000/callback"),
161
+ OAUTH_REDIRECT_ALLOWLIST: parseStringArray(env.OAUTH_REDIRECT_ALLOWLIST),
162
+ OAUTH_REDIRECT_ALLOW_ALL: parseBoolean(env.OAUTH_REDIRECT_ALLOW_ALL),
163
+ OAUTH_EXTRA_AUTH_PARAMS: env.OAUTH_EXTRA_AUTH_PARAMS,
164
+ CIMD_ENABLED: parseBoolean(env.CIMD_ENABLED ?? "true"),
165
+ CIMD_FETCH_TIMEOUT_MS: parseNumber(env.CIMD_FETCH_TIMEOUT_MS, 5000),
166
+ CIMD_MAX_RESPONSE_BYTES: parseNumber(env.CIMD_MAX_RESPONSE_BYTES, 65536),
167
+ CIMD_ALLOWED_DOMAINS: parseStringArray(env.CIMD_ALLOWED_DOMAINS),
168
+ PROVIDER_CLIENT_ID: env.PROVIDER_CLIENT_ID?.trim(),
169
+ PROVIDER_CLIENT_SECRET: env.PROVIDER_CLIENT_SECRET?.trim(),
170
+ PROVIDER_API_URL: env.PROVIDER_API_URL,
171
+ PROVIDER_ACCOUNTS_URL: env.PROVIDER_ACCOUNTS_URL,
172
+ BASE_URL: env.BASE_URL,
173
+ RS_TOKENS_FILE: env.RS_TOKENS_FILE,
174
+ RS_TOKENS_ENC_KEY: env.RS_TOKENS_ENC_KEY,
175
+ RPS_LIMIT: parseNumber(env.RPS_LIMIT, 10),
176
+ CONCURRENCY_LIMIT: parseNumber(env.CONCURRENCY_LIMIT, 5),
177
+ LOG_LEVEL: env.LOG_LEVEL || "info"
178
+ };
179
+ }
180
+
181
+ // src/mcp-server.ts
182
+ function createMCPServer(options) {
183
+ if (options.adapter === "worker") {
184
+ return createWorkerServer(options.tools);
185
+ }
186
+ throw new Error(`Adapter '${options.adapter}' not supported yet`);
187
+ }
188
+ function createWorkerServer(tools) {
189
+ return {
190
+ async fetch(request, env) {
191
+ shimProcessEnv(env);
192
+ const config = parseConfig(env);
193
+ const storage = initializeWorkerStorage(env, config);
194
+ if (!storage) {
195
+ return withCors(new Response("Server misconfigured: Storage unavailable", {
196
+ status: 503
197
+ }));
198
+ }
199
+ const router = createWorkerRouter({
200
+ tokenStore: storage.tokenStore,
201
+ sessionStore: storage.sessionStore,
202
+ config,
203
+ tools
204
+ });
205
+ return router.fetch(request);
206
+ }
207
+ };
208
+ }
209
+ // src/shared/auth/strategy.ts
210
+ function parseCustomHeaders(value) {
211
+ if (!value)
212
+ return {};
213
+ const headers = {};
214
+ const pairs = value.split(",");
215
+ for (const pair of pairs) {
216
+ const colonIndex = pair.indexOf(":");
217
+ if (colonIndex === -1)
218
+ continue;
219
+ const key = pair.slice(0, colonIndex).trim();
220
+ const val = pair.slice(colonIndex + 1).trim();
221
+ if (key && val) {
222
+ headers[key] = val;
223
+ }
224
+ }
225
+ return headers;
226
+ }
227
+ function parseAuthStrategy2(env) {
228
+ const strategy = env.AUTH_STRATEGY?.toLowerCase();
229
+ switch (strategy) {
230
+ case "api_key":
231
+ return {
232
+ type: "api_key",
233
+ headerName: env.API_KEY_HEADER || "x-api-key",
234
+ value: env.API_KEY
235
+ };
236
+ case "bearer":
237
+ return {
238
+ type: "bearer",
239
+ value: env.BEARER_TOKEN
240
+ };
241
+ case "custom":
242
+ return {
243
+ type: "custom",
244
+ customHeaders: parseCustomHeaders(env.CUSTOM_HEADERS)
245
+ };
246
+ case "none":
247
+ return { type: "none" };
248
+ default:
249
+ return { type: "oauth" };
250
+ }
251
+ }
252
+ function buildAuthHeaders(strategyConfig) {
253
+ const headers = {};
254
+ switch (strategyConfig.type) {
255
+ case "api_key":
256
+ if (strategyConfig.value && strategyConfig.headerName) {
257
+ headers[strategyConfig.headerName] = strategyConfig.value;
258
+ }
259
+ break;
260
+ case "bearer":
261
+ if (strategyConfig.value) {
262
+ headers.Authorization = `Bearer ${strategyConfig.value}`;
263
+ }
264
+ break;
265
+ case "custom":
266
+ if (strategyConfig.customHeaders) {
267
+ Object.assign(headers, strategyConfig.customHeaders);
268
+ }
269
+ break;
270
+ case "oauth":
271
+ case "none":
272
+ break;
273
+ }
274
+ return headers;
275
+ }
276
+ function resolveStaticAuth(strategyConfig) {
277
+ const headers = buildAuthHeaders(strategyConfig);
278
+ return {
279
+ strategy: strategyConfig.type,
280
+ headers,
281
+ accessToken: strategyConfig.type === "bearer" ? strategyConfig.value : undefined
282
+ };
283
+ }
284
+ function mergeAuthHeaders(incoming, strategy) {
285
+ return {
286
+ ...incoming,
287
+ ...strategy
288
+ };
289
+ }
290
+ function isOAuthStrategy(config) {
291
+ return config.type === "oauth";
292
+ }
293
+ function requiresAuth(config) {
294
+ return config.type !== "none";
295
+ }
296
+ function validateAuthConfig(config) {
297
+ const errors = [];
298
+ switch (config.type) {
299
+ case "api_key":
300
+ if (!config.value) {
301
+ errors.push("API_KEY is required when AUTH_STRATEGY=api_key");
302
+ }
303
+ break;
304
+ case "bearer":
305
+ if (!config.value) {
306
+ errors.push("BEARER_TOKEN is required when AUTH_STRATEGY=bearer");
307
+ }
308
+ break;
309
+ case "custom":
310
+ if (!config.customHeaders || Object.keys(config.customHeaders).length === 0) {
311
+ errors.push("CUSTOM_HEADERS is required when AUTH_STRATEGY=custom");
312
+ }
313
+ break;
314
+ }
315
+ return errors;
316
+ }
317
+ // src/shared/utils/limits.ts
318
+ var makeTokenBucket = (capacity, refillPerSec) => {
319
+ let tokens = capacity;
320
+ let last = Date.now();
321
+ const refillLoop = () => {
322
+ const now = Date.now();
323
+ const delta = (now - last) / 1000;
324
+ last = now;
325
+ tokens = Math.min(capacity, tokens + delta * refillPerSec);
326
+ };
327
+ return {
328
+ take(n = 1) {
329
+ refillLoop();
330
+ if (tokens >= n) {
331
+ tokens -= n;
332
+ return true;
333
+ }
334
+ return false;
335
+ },
336
+ refill(n = capacity) {
337
+ tokens = Math.min(capacity, tokens + n);
338
+ }
339
+ };
340
+ };
341
+ var makeConcurrencyGate = (max) => {
342
+ let active = 0;
343
+ const queue = [];
344
+ return async (fn) => {
345
+ if (active >= max) {
346
+ await new Promise((resolve) => queue.push(resolve));
347
+ }
348
+ active++;
349
+ try {
350
+ return await fn();
351
+ } finally {
352
+ active--;
353
+ const next = queue.shift();
354
+ if (next)
355
+ next();
356
+ }
357
+ };
358
+ };
359
+
360
+ // src/shared/services/http-client.ts
361
+ var DEFAULT_RPS = 10;
362
+ var DEFAULT_CONCURRENCY = 5;
363
+ function createHttpClient(options = {}) {
364
+ const {
365
+ baseHeaders = {},
366
+ timeout = 30000,
367
+ retries = 3,
368
+ retryDelay = 1000,
369
+ rateLimit = { rps: DEFAULT_RPS, burst: DEFAULT_RPS * 2 },
370
+ concurrency = DEFAULT_CONCURRENCY
371
+ } = options;
372
+ const rateLimiter = makeTokenBucket(rateLimit.burst, rateLimit.rps);
373
+ const concurrencyGate = makeConcurrencyGate(concurrency);
374
+ return async (input, init) => {
375
+ return concurrencyGate(async () => {
376
+ if (!rateLimiter.take()) {
377
+ logger.warning("http_client", {
378
+ message: "Rate limit exceeded, request rejected"
379
+ });
380
+ throw new Error("Rate limit exceeded");
381
+ }
382
+ const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input?.url ?? String(input);
383
+ const method = init?.method || "GET";
384
+ logger.debug("http_client", {
385
+ message: "HTTP request starting",
386
+ url,
387
+ method
388
+ });
389
+ for (let attempt = 1;attempt <= retries; attempt++) {
390
+ try {
391
+ const controller = new AbortController;
392
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
393
+ const response = await fetch(url, {
394
+ ...init,
395
+ headers: {
396
+ ...baseHeaders,
397
+ ...init?.headers
398
+ },
399
+ signal: controller.signal
400
+ });
401
+ clearTimeout(timeoutId);
402
+ if (response.ok || attempt === retries) {
403
+ logger.info("http_client", {
404
+ message: "HTTP request completed",
405
+ url,
406
+ method,
407
+ status: response.status,
408
+ attempt
409
+ });
410
+ return response;
411
+ }
412
+ logger.warning("http_client", {
413
+ message: "HTTP request failed, retrying",
414
+ url,
415
+ method,
416
+ status: response.status,
417
+ attempt
418
+ });
419
+ const delay = retryDelay * 2 ** (attempt - 1) + Math.random() * 1000;
420
+ await new Promise((resolve) => setTimeout(resolve, delay));
421
+ } catch (error) {
422
+ if (attempt === retries) {
423
+ logger.error("http_client", {
424
+ message: "HTTP request failed after all retries",
425
+ url,
426
+ method,
427
+ error: error.message,
428
+ attempts: retries
429
+ });
430
+ throw error;
431
+ }
432
+ logger.warning("http_client", {
433
+ message: "HTTP request error, retrying",
434
+ url,
435
+ method,
436
+ error: error.message,
437
+ attempt
438
+ });
439
+ const delay = retryDelay * 2 ** (attempt - 1) + Math.random() * 1000;
440
+ await new Promise((resolve) => setTimeout(resolve, delay));
441
+ }
442
+ }
443
+ throw new Error("Unexpected end of retry loop");
444
+ });
445
+ };
446
+ }
447
+ // src/shared/utils/elicitation.ts
448
+ function getLowLevelServer2(server) {
449
+ return server.server;
450
+ }
451
+ var ElicitResultSchema = exports_external.object({
452
+ action: exports_external.enum(["accept", "decline", "cancel"]),
453
+ content: exports_external.record(exports_external.string(), exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean(), exports_external.array(exports_external.string())])).optional()
454
+ });
455
+ function validateElicitationSchema(schema) {
456
+ if (schema.type !== "object") {
457
+ throw new Error('Elicitation schema must have type: "object" at root');
458
+ }
459
+ if (!schema.properties || typeof schema.properties !== "object") {
460
+ throw new Error('Elicitation schema must have a "properties" object');
461
+ }
462
+ for (const [fieldName, fieldSchema] of Object.entries(schema.properties)) {
463
+ if ("properties" in fieldSchema) {
464
+ throw new Error(`Nested objects not allowed in elicitation schema (field: "${fieldName}"). ` + "Only primitive types (string, number, integer, boolean) and enums are supported.");
465
+ }
466
+ if (fieldSchema.type === "array" && "items" in fieldSchema) {
467
+ const items = fieldSchema.items;
468
+ if (items.type === "object" || "properties" in items) {
469
+ throw new Error(`Array of objects not allowed in elicitation schema (field: "${fieldName}"). ` + "Only arrays with string enum items are supported for multi-select.");
470
+ }
471
+ }
472
+ const allowedTypes = ["boolean", "string", "number", "integer", "array"];
473
+ if (!allowedTypes.includes(fieldSchema.type)) {
474
+ throw new Error(`Invalid field type "${fieldSchema.type}" in elicitation schema (field: "${fieldName}"). ` + `Allowed types: ${allowedTypes.join(", ")}`);
475
+ }
476
+ }
477
+ }
478
+ function clientSupportsFormElicitation(server) {
479
+ try {
480
+ const lowLevel = getLowLevelServer2(server);
481
+ const clientCapabilities = lowLevel.getClientCapabilities?.() ?? {};
482
+ return Boolean(clientCapabilities.elicitation);
483
+ } catch {
484
+ return false;
485
+ }
486
+ }
487
+ function clientSupportsUrlElicitation(server) {
488
+ try {
489
+ const lowLevel = getLowLevelServer2(server);
490
+ const clientCapabilities = lowLevel.getClientCapabilities?.() ?? {};
491
+ return Boolean(clientCapabilities.elicitation?.url);
492
+ } catch {
493
+ return false;
494
+ }
495
+ }
496
+ async function elicitForm(server, request) {
497
+ if (!clientSupportsFormElicitation(server)) {
498
+ logger.warning("elicitation", {
499
+ message: "Client does not support form elicitation"
500
+ });
501
+ throw new Error("Client does not support form elicitation");
502
+ }
503
+ validateElicitationSchema(request.requestedSchema);
504
+ logger.debug("elicitation", {
505
+ message: "Requesting form elicitation",
506
+ fieldCount: Object.keys(request.requestedSchema.properties).length
507
+ });
508
+ try {
509
+ const lowLevel = getLowLevelServer2(server);
510
+ const response = await lowLevel.elicitInput({
511
+ mode: "form",
512
+ message: request.message,
513
+ requestedSchema: request.requestedSchema
514
+ });
515
+ logger.info("elicitation", {
516
+ message: "Form elicitation completed",
517
+ action: response.action
518
+ });
519
+ return response;
520
+ } catch (error) {
521
+ logger.error("elicitation", {
522
+ message: "Form elicitation failed",
523
+ error: error.message
524
+ });
525
+ throw error;
526
+ }
527
+ }
528
+ async function elicitUrl(server, request) {
529
+ if (!clientSupportsUrlElicitation(server)) {
530
+ logger.warning("elicitation", {
531
+ message: "Client does not support URL elicitation"
532
+ });
533
+ throw new Error("Client does not support URL elicitation");
534
+ }
535
+ logger.debug("elicitation", {
536
+ message: "Requesting URL elicitation",
537
+ elicitationId: request.elicitationId,
538
+ url: request.url
539
+ });
540
+ try {
541
+ const lowLevel = getLowLevelServer2(server);
542
+ const response = await lowLevel.elicitInput({
543
+ mode: "url",
544
+ message: request.message,
545
+ elicitationId: request.elicitationId,
546
+ url: request.url
547
+ });
548
+ logger.info("elicitation", {
549
+ message: "URL elicitation completed",
550
+ action: response.action,
551
+ elicitationId: request.elicitationId
552
+ });
553
+ return response;
554
+ } catch (error) {
555
+ logger.error("elicitation", {
556
+ message: "URL elicitation failed",
557
+ error: error.message,
558
+ elicitationId: request.elicitationId
559
+ });
560
+ throw error;
561
+ }
562
+ }
563
+ async function notifyElicitationComplete(server, elicitationId) {
564
+ if (!clientSupportsUrlElicitation(server)) {
565
+ throw new Error("Client does not support URL elicitation notifications");
566
+ }
567
+ logger.debug("elicitation", {
568
+ message: "Sending elicitation complete notification",
569
+ elicitationId
570
+ });
571
+ try {
572
+ const lowLevel = getLowLevelServer2(server);
573
+ const notifyComplete = lowLevel.createElicitationCompletionNotifier(elicitationId);
574
+ await notifyComplete();
575
+ logger.info("elicitation", {
576
+ message: "Elicitation complete notification sent",
577
+ elicitationId
578
+ });
579
+ } catch (error) {
580
+ logger.error("elicitation", {
581
+ message: "Failed to send elicitation complete notification",
582
+ error: error.message,
583
+ elicitationId
584
+ });
585
+ throw error;
586
+ }
587
+ }
588
+ async function confirm(server, message, options) {
589
+ const result = await elicitForm(server, {
590
+ message,
591
+ requestedSchema: {
592
+ type: "object",
593
+ properties: {
594
+ confirmed: {
595
+ type: "boolean",
596
+ title: options?.confirmLabel ?? "Confirm",
597
+ default: false
598
+ }
599
+ }
600
+ }
601
+ });
602
+ return result.action === "accept" && result.content?.confirmed === true;
603
+ }
604
+ async function promptText(server, message, options) {
605
+ const result = await elicitForm(server, {
606
+ message,
607
+ requestedSchema: {
608
+ type: "object",
609
+ properties: {
610
+ value: {
611
+ type: "string",
612
+ title: options?.title ?? "Value",
613
+ description: options?.description,
614
+ default: options?.defaultValue,
615
+ minLength: options?.minLength,
616
+ maxLength: options?.maxLength
617
+ }
618
+ },
619
+ ...options?.required && { required: ["value"] }
620
+ }
621
+ });
622
+ if (result.action === "accept") {
623
+ return result.content?.value;
624
+ }
625
+ return;
626
+ }
627
+ async function promptSelect(server, message, options, config) {
628
+ const result = await elicitForm(server, {
629
+ message,
630
+ requestedSchema: {
631
+ type: "object",
632
+ properties: {
633
+ selection: {
634
+ type: "string",
635
+ title: config?.title ?? "Selection",
636
+ oneOf: options.map((opt) => ({ const: opt.value, title: opt.label })),
637
+ default: config?.defaultValue
638
+ }
639
+ },
640
+ ...config?.required && { required: ["selection"] }
641
+ }
642
+ });
643
+ if (result.action === "accept") {
644
+ return result.content?.selection;
645
+ }
646
+ return;
647
+ }
648
+ // src/shared/utils/formatting.ts
649
+ function summarizeList(items, formatPreview, options = {}) {
650
+ const {
651
+ title = "List",
652
+ maxPreview = 100,
653
+ detailsFormatter,
654
+ maxDetails = 5
655
+ } = options;
656
+ if (items.length === 0) {
657
+ return `## ${title} (0 items)
658
+
659
+ No items found.`;
660
+ }
661
+ const parts = [];
662
+ const previewItems = items.slice(0, maxPreview);
663
+ const hasMore = items.length > maxPreview;
664
+ parts.push(`## ${title} (${items.length} items)`);
665
+ parts.push("");
666
+ parts.push(...previewItems.map(formatPreview));
667
+ if (hasMore) {
668
+ parts.push(`... and ${items.length - maxPreview} more`);
669
+ }
670
+ if (detailsFormatter && items.length > 0) {
671
+ parts.push("");
672
+ parts.push("## Details");
673
+ parts.push("");
674
+ const detailItems = items.slice(0, maxDetails);
675
+ parts.push(...detailItems.map(detailsFormatter));
676
+ if (items.length > maxDetails) {
677
+ parts.push("");
678
+ parts.push(`_Showing ${maxDetails} of ${items.length} items. Use pagination to see more._`);
679
+ }
680
+ }
681
+ return parts.join(`
682
+ `);
683
+ }
684
+ function summarizeBatch(results, options) {
685
+ const { operationName, successFormatter, errorFormatter } = options;
686
+ const successes = results.filter((r) => r.success);
687
+ const failures = results.filter((r) => !r.success);
688
+ const parts = [];
689
+ parts.push(`## ${operationName} Results`);
690
+ parts.push("");
691
+ parts.push(`**Summary**: ${successes.length} succeeded, ${failures.length} failed (${results.length} total)`);
692
+ if (successes.length > 0) {
693
+ parts.push("");
694
+ parts.push("### Successful Operations");
695
+ parts.push("");
696
+ parts.push(...successes.map(successFormatter));
697
+ }
698
+ if (failures.length > 0) {
699
+ parts.push("");
700
+ parts.push("### Failed Operations");
701
+ parts.push("");
702
+ parts.push(...failures.map(errorFormatter));
703
+ }
704
+ return parts.join(`
705
+ `);
706
+ }
707
+ function formatFieldChange(fieldName, before, after) {
708
+ const formatValue = (value) => {
709
+ if (value === null || value === undefined)
710
+ return "\u2014";
711
+ if (typeof value === "boolean")
712
+ return value ? "true" : "false";
713
+ return String(value);
714
+ };
715
+ return `${fieldName}: ${formatValue(before)} \u2192 ${formatValue(after)}`;
716
+ }
717
+ function createSection(content, options = {}) {
718
+ const { tag, indent = 0 } = options;
719
+ const indentation = " ".repeat(indent);
720
+ if (!tag) {
721
+ return content.split(`
722
+ `).map((line) => indentation + line).join(`
723
+ `);
724
+ }
725
+ const lines = [];
726
+ lines.push(`${indentation}<ove tag="${tag}">`);
727
+ lines.push(...content.split(`
728
+ `).map((line) => indentation + (line ? ` ${line}` : line)));
729
+ lines.push(`${indentation}</ove>`);
730
+ return lines.join(`
731
+ `);
732
+ }
733
+ function truncate(text, maxLength = 100) {
734
+ if (text.length <= maxLength)
735
+ return text;
736
+ return `${text.slice(0, maxLength - 3)}...`;
737
+ }
738
+ function formatKeyValueList(pairs) {
739
+ return Object.entries(pairs).filter(([_key, value]) => value !== null && value !== undefined).map(([key, value]) => {
740
+ const capitalizedKey = key.charAt(0).toUpperCase() + key.slice(1);
741
+ return `- **${capitalizedKey}**: ${value}`;
742
+ }).join(`
743
+ `);
744
+ }
745
+ // src/shared/utils/pagination.ts
746
+ function createCursor(offset) {
747
+ return base64Encode(JSON.stringify({ offset }));
748
+ }
749
+ function parseCursor(cursor) {
750
+ if (!cursor)
751
+ return 0;
752
+ try {
753
+ const decoded = base64Decode(cursor);
754
+ const parsed = JSON.parse(decoded);
755
+ return typeof parsed.offset === "number" ? parsed.offset : 0;
756
+ } catch {
757
+ return 0;
758
+ }
759
+ }
760
+ function paginateArray(items, cursor, limit = 50) {
761
+ const offset = parseCursor(cursor);
762
+ const startIndex = Math.max(0, offset);
763
+ const endIndex = startIndex + limit;
764
+ const data = items.slice(startIndex, endIndex);
765
+ const nextCursor = endIndex < items.length ? createCursor(endIndex) : undefined;
766
+ return { data, nextCursor };
767
+ }
768
+ // src/shared/utils/progress.ts
769
+ class ProgressReporter {
770
+ server;
771
+ progressToken;
772
+ completed = false;
773
+ constructor(server, progressToken) {
774
+ this.server = server;
775
+ this.progressToken = progressToken;
776
+ }
777
+ async report(progress, total, message) {
778
+ if (this.completed) {
779
+ logger.warning("progress", {
780
+ message: "Attempted to send progress after completion - notification will be ignored",
781
+ progressToken: this.progressToken
782
+ });
783
+ return;
784
+ }
785
+ try {
786
+ const lowLevel = getLowLevelServer(this.server);
787
+ await lowLevel.notification?.({
788
+ method: "notifications/progress",
789
+ params: {
790
+ progressToken: this.progressToken,
791
+ progress,
792
+ total,
793
+ ...message ? { message } : {}
794
+ }
795
+ });
796
+ } catch (error) {
797
+ logger.warning("progress", {
798
+ message: "Failed to send progress notification",
799
+ error: error.message,
800
+ progressToken: this.progressToken
801
+ });
802
+ }
803
+ }
804
+ async complete(message) {
805
+ await this.report(1, 1, message ?? "Complete");
806
+ this.completed = true;
807
+ }
808
+ }
809
+ function createProgressReporter(server, progressToken) {
810
+ if (!progressToken) {
811
+ return null;
812
+ }
813
+ return new ProgressReporter(server, progressToken);
814
+ }
815
+ // src/shared/utils/roots.ts
816
+ async function requestRoots(server) {
817
+ logger.debug("roots", {
818
+ message: "Requesting roots from client"
819
+ });
820
+ try {
821
+ const lowLevel = getLowLevelServer(server);
822
+ if (!lowLevel.request) {
823
+ throw new Error("Roots not supported: Server does not support client requests");
824
+ }
825
+ const clientCapabilities = lowLevel.getClientCapabilities?.() ?? {};
826
+ if (!clientCapabilities.roots) {
827
+ throw new Error("Client does not support roots capability. " + 'Client must declare "roots" capability to list filesystem roots.');
828
+ }
829
+ const response = await lowLevel.request({
830
+ method: "roots/list"
831
+ });
832
+ logger.info("roots", {
833
+ message: "Received roots from client",
834
+ rootCount: response.roots.length
835
+ });
836
+ return response.roots;
837
+ } catch (error) {
838
+ logger.error("roots", {
839
+ message: "Roots request failed",
840
+ error: error.message
841
+ });
842
+ if (isJsonRpcError(error, JSON_RPC_METHOD_NOT_FOUND)) {
843
+ throw new Error('Roots not supported by client. Client must declare "roots" capability.');
844
+ }
845
+ throw error;
846
+ }
847
+ }
848
+ function clientSupportsRoots(server) {
849
+ try {
850
+ const lowLevel = getLowLevelServer(server);
851
+ const clientCapabilities = lowLevel.getClientCapabilities?.() ?? {};
852
+ return Boolean(clientCapabilities.roots);
853
+ } catch {
854
+ return false;
855
+ }
856
+ }
857
+ function clientSupportsRootsListChanged(server) {
858
+ try {
859
+ const lowLevel = getLowLevelServer(server);
860
+ const clientCapabilities = lowLevel.getClientCapabilities?.() ?? {};
861
+ const roots = clientCapabilities.roots;
862
+ return Boolean(roots?.listChanged);
863
+ } catch {
864
+ return false;
865
+ }
866
+ }
867
+ // src/shared/utils/sampling.ts
868
+ function getLowLevelServer3(server) {
869
+ return server.server;
870
+ }
871
+ async function requestSampling(server, request) {
872
+ logger.debug("sampling", {
873
+ message: "Requesting LLM sampling from client",
874
+ messageCount: request.messages.length,
875
+ modelHints: request.modelPreferences?.hints?.map((h) => h.name),
876
+ hasTools: !!request.tools,
877
+ hasToolChoice: !!request.toolChoice
878
+ });
879
+ try {
880
+ const lowLevel = getLowLevelServer3(server);
881
+ const params = {
882
+ messages: request.messages,
883
+ maxTokens: request.maxTokens,
884
+ modelPreferences: request.modelPreferences,
885
+ systemPrompt: request.systemPrompt,
886
+ temperature: request.temperature,
887
+ stopSequences: request.stopSequences,
888
+ metadata: request.metadata,
889
+ ...request.tools && { tools: request.tools },
890
+ ...request.toolChoice && { toolChoice: request.toolChoice }
891
+ };
892
+ const response = await lowLevel.createMessage(params);
893
+ logger.info("sampling", {
894
+ message: "Received LLM response from client",
895
+ model: response.model,
896
+ stopReason: response.stopReason
897
+ });
898
+ return response;
899
+ } catch (error) {
900
+ logger.error("sampling", {
901
+ message: "Sampling request failed",
902
+ error: error.message
903
+ });
904
+ throw error;
905
+ }
906
+ }
907
+ function clientSupportsSampling(server) {
908
+ try {
909
+ const lowLevel = getLowLevelServer3(server);
910
+ const clientCapabilities = lowLevel.getClientCapabilities?.() ?? {};
911
+ return Boolean(clientCapabilities.sampling);
912
+ } catch {
913
+ return false;
914
+ }
915
+ }
916
+ function clientSupportsSamplingTools(server) {
917
+ try {
918
+ const lowLevel = getLowLevelServer3(server);
919
+ const clientCapabilities = lowLevel.getClientCapabilities?.() ?? {};
920
+ const sampling = clientCapabilities.sampling;
921
+ return Boolean(sampling?.tools);
922
+ } catch {
923
+ return false;
924
+ }
925
+ }
926
+ async function requestTextCompletion(server, prompt, maxTokens, options) {
927
+ const response = await requestSampling(server, {
928
+ messages: [
929
+ {
930
+ role: "user",
931
+ content: {
932
+ type: "text",
933
+ text: prompt
934
+ }
935
+ }
936
+ ],
937
+ maxTokens,
938
+ ...options
939
+ });
940
+ if (response.content.type !== "text") {
941
+ throw new Error(`Expected text response but got ${response.content.type}`);
942
+ }
943
+ return response.content.text;
944
+ }
945
+ export {
946
+ workerDiscoveryStrategy,
947
+ withCors,
948
+ withCancellation,
949
+ validateRedirectUri,
950
+ validateProtocolVersion,
951
+ validateOrigin,
952
+ validateElicitationSchema,
953
+ validateAuthConfig,
954
+ truncate,
955
+ toProviderTokens,
956
+ toProviderInfo,
957
+ summarizeList,
958
+ summarizeBatch,
959
+ stopContextCleanup,
960
+ startContextCleanup,
961
+ shimProcessEnv,
962
+ sharedTools,
963
+ sharedLogger,
964
+ sessions,
965
+ resolveStaticAuth,
966
+ requiresAuth,
967
+ requestTextCompletion,
968
+ requestSampling,
969
+ requestRoots,
970
+ registerTools,
971
+ refreshProviderToken,
972
+ promptText,
973
+ promptSelect,
974
+ parseTokenInput,
975
+ parseCursor,
976
+ parseConfig,
977
+ parseCallbackInput,
978
+ parseAuthorizeInput,
979
+ parseAuthStrategy2 as parseAuthStrategy,
980
+ paginateArray,
981
+ notifyElicitationComplete,
982
+ nodeDiscoveryStrategy,
983
+ mergeAuthHeaders,
984
+ makeTokenBucket,
985
+ makeConcurrencyGate,
986
+ logger,
987
+ isTokenExpiredOrExpiring,
988
+ isSsrfSafe,
989
+ isOAuthStrategy,
990
+ isJsonRpcError,
991
+ isClientIdUrl,
992
+ initializeWorkerStorage,
993
+ initializeStorage,
994
+ healthTool,
995
+ healthInputSchema,
996
+ handleToken,
997
+ handleRevoke,
998
+ handleRegister,
999
+ handleProviderCallback,
1000
+ handleMcpNotification,
1001
+ handleAuthorize,
1002
+ getTokenStore,
1003
+ getSharedToolNames,
1004
+ getSharedTool,
1005
+ getSessionStore,
1006
+ getServerWithInternals,
1007
+ getLowLevelServer,
1008
+ getLogLevel,
1009
+ getCurrentAuthContext,
1010
+ generateOpaqueToken,
1011
+ generateKey,
1012
+ formatKeyValueList,
1013
+ formatFieldChange,
1014
+ fetchClientMetadata,
1015
+ executeSharedTool,
1016
+ ensureFreshToken,
1017
+ encrypt,
1018
+ elicitUrl,
1019
+ elicitForm,
1020
+ echoTool,
1021
+ echoInputSchema,
1022
+ dispatchMcpMethod,
1023
+ defineTool,
1024
+ decrypt,
1025
+ createWorkerRouter,
1026
+ createSection,
1027
+ createProgressReporter,
1028
+ createMCPServer,
1029
+ createHttpClient,
1030
+ createEncryptor,
1031
+ createDiscoveryHandlers,
1032
+ createCursor,
1033
+ createCancellationToken,
1034
+ corsPreflightResponse,
1035
+ contextRegistry,
1036
+ confirm,
1037
+ clientSupportsUrlElicitation,
1038
+ clientSupportsSamplingTools,
1039
+ clientSupportsSampling,
1040
+ clientSupportsRootsListChanged,
1041
+ clientSupportsRoots,
1042
+ clientSupportsFormElicitation,
1043
+ checkSsrfSafe,
1044
+ buildUnauthorizedChallenge,
1045
+ buildTokenInput,
1046
+ buildServer,
1047
+ buildProviderRefreshConfig,
1048
+ buildProviderConfig,
1049
+ buildProtectedResourceMetadata,
1050
+ buildOAuthConfig,
1051
+ buildFlowOptions,
1052
+ buildCorsHeaders,
1053
+ buildCapabilities,
1054
+ buildAuthorizationServerMetadata,
1055
+ buildAuthHeaders,
1056
+ base64UrlEncodeString,
1057
+ base64UrlEncodeJson,
1058
+ base64UrlEncode,
1059
+ base64UrlDecodeString,
1060
+ base64UrlDecodeJson,
1061
+ base64UrlDecode,
1062
+ base64Encode,
1063
+ base64Decode,
1064
+ authContextStorage,
1065
+ assertSsrfSafe,
1066
+ assertProviderToken,
1067
+ SqliteSessionStore,
1068
+ SUPPORTED_PROTOCOL_VERSIONS,
1069
+ ProgressReporter,
1070
+ MemoryTokenStore,
1071
+ MemorySessionStore,
1072
+ MAX_SESSIONS_PER_API_KEY,
1073
+ LATEST_PROTOCOL_VERSION,
1074
+ KvTokenStore,
1075
+ KvSessionStore,
1076
+ JsonRpcErrorCode,
1077
+ JSON_RPC_METHOD_NOT_FOUND,
1078
+ FileTokenStore,
1079
+ ElicitResultSchema,
1080
+ ClientMetadataSchema,
1081
+ CancellationToken,
1082
+ CancellationError
1083
+ };