@executor-js/plugin-mcp 1.5.14 → 1.5.16

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 (34) hide show
  1. package/dist/{AddMcpSource-BSJDTWMP.js → AddMcpSource-H67EJXJ7.js} +4 -4
  2. package/dist/{EditMcpSource-3S6FUVCR.js → EditMcpSource-AS3ZTP6W.js} +3 -3
  3. package/dist/{McpAccountsPanel-273WNH3T.js → McpAccountsPanel-4F5WE7FH.js} +3 -3
  4. package/dist/api/index.d.ts +4 -4
  5. package/dist/{chunk-ENRA2SPE.js → chunk-2CAKFQPL.js} +114 -40
  6. package/dist/chunk-2CAKFQPL.js.map +1 -0
  7. package/dist/{chunk-3H5Y7JCQ.js → chunk-4V3H3DDH.js} +7 -9
  8. package/dist/chunk-4V3H3DDH.js.map +1 -0
  9. package/dist/{chunk-SJ4LKQVQ.js → chunk-AMC5G2HJ.js} +2 -2
  10. package/dist/{chunk-QEAVWCYB.js → chunk-CLAWPLDI.js} +9 -1
  11. package/dist/chunk-CLAWPLDI.js.map +1 -0
  12. package/dist/client.js +4 -4
  13. package/dist/core.js +3 -5
  14. package/dist/core.js.map +1 -1
  15. package/dist/index.js +3 -3
  16. package/dist/sdk/connection.d.ts +2 -2
  17. package/dist/sdk/errors.d.ts +15 -5
  18. package/dist/sdk/image-content.test.d.ts +1 -0
  19. package/dist/sdk/index.d.ts +1 -1
  20. package/dist/sdk/invoke.d.ts +2 -2
  21. package/dist/sdk/invoke.test.d.ts +1 -0
  22. package/dist/sdk/plugin.d.ts +8 -8
  23. package/dist/testing/index.d.ts +1 -1
  24. package/dist/testing/server.d.ts +3 -0
  25. package/dist/testing.js +55 -0
  26. package/dist/testing.js.map +1 -1
  27. package/package.json +3 -3
  28. package/dist/chunk-3H5Y7JCQ.js.map +0 -1
  29. package/dist/chunk-ENRA2SPE.js.map +0 -1
  30. package/dist/chunk-QEAVWCYB.js.map +0 -1
  31. /package/dist/{AddMcpSource-BSJDTWMP.js.map → AddMcpSource-H67EJXJ7.js.map} +0 -0
  32. /package/dist/{EditMcpSource-3S6FUVCR.js.map → EditMcpSource-AS3ZTP6W.js.map} +0 -0
  33. /package/dist/{McpAccountsPanel-273WNH3T.js.map → McpAccountsPanel-4F5WE7FH.js.map} +0 -0
  34. /package/dist/{chunk-SJ4LKQVQ.js.map → chunk-AMC5G2HJ.js.map} +0 -0
@@ -11,11 +11,21 @@ declare const McpToolDiscoveryError_base: Schema.Class<McpToolDiscoveryError, Sc
11
11
  }>, import("effect/Cause").YieldableError>;
12
12
  export declare class McpToolDiscoveryError extends McpToolDiscoveryError_base {
13
13
  }
14
- declare const McpInvocationError_base: Schema.Class<McpInvocationError, Schema.TaggedStruct<"McpInvocationError", {
15
- readonly toolName: Schema.String;
16
- readonly message: Schema.String;
17
- }>, import("effect/Cause").YieldableError>;
18
- export declare class McpInvocationError extends McpInvocationError_base {
14
+ declare const McpInvocationError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
15
+ readonly _tag: "McpInvocationError";
16
+ } & Readonly<A>;
17
+ export declare class McpInvocationError extends McpInvocationError_base<{
18
+ readonly toolName: string;
19
+ readonly message: string;
20
+ readonly status?: number;
21
+ }> {
22
+ }
23
+ declare const McpOAuthReauthorizationRequired_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
24
+ readonly _tag: "McpOAuthReauthorizationRequired";
25
+ } & Readonly<A>;
26
+ export declare class McpOAuthReauthorizationRequired extends McpOAuthReauthorizationRequired_base<{
27
+ readonly message: string;
28
+ }> {
19
29
  }
20
30
  declare const McpOAuthError_base: Schema.Class<McpOAuthError, Schema.TaggedStruct<"McpOAuthError", {
21
31
  readonly message: Schema.String;
@@ -0,0 +1 @@
1
+ export {};
@@ -2,5 +2,5 @@ export { mcpPlugin, userFacingProbeMessage, type McpPluginExtension, type McpPlu
2
2
  export { McpAuthMethod, McpAuthMethodInput, McpAuthShorthand, McpIntegrationConfig, McpRemoteIntegrationConfig, McpStdioIntegrationConfig, McpRemoteTransport, McpTransport, McpToolAnnotations, McpToolBinding, parseMcpIntegrationConfig, } from "./types";
3
3
  export { migrateMcpAuthConfig } from "./migrate-config";
4
4
  export { variable, type ApiKeyAuthTemplate } from "@executor-js/sdk/http-auth";
5
- export { McpConnectionError, McpToolDiscoveryError, McpInvocationError, McpOAuthError, } from "./errors";
5
+ export { McpConnectionError, McpToolDiscoveryError, McpOAuthError } from "./errors";
6
6
  export { deriveMcpNamespace, joinToolPath, extractManifestFromListToolsResult } from "./manifest";
@@ -1,6 +1,6 @@
1
1
  import { Effect } from "effect";
2
2
  import { type Elicit } from "@executor-js/sdk";
3
- import { McpConnectionError, McpInvocationError } from "./errors";
3
+ import { McpConnectionError, McpInvocationError, McpOAuthReauthorizationRequired } from "./errors";
4
4
  import type { McpConnector } from "./connection";
5
5
  export interface InvokeMcpToolInput {
6
6
  readonly toolId: string;
@@ -12,4 +12,4 @@ export interface InvokeMcpToolInput {
12
12
  readonly connector: McpConnector;
13
13
  readonly elicit: Elicit;
14
14
  }
15
- export declare const invokeMcpTool: (input: InvokeMcpToolInput) => Effect.Effect<unknown, McpConnectionError | McpInvocationError>;
15
+ export declare const invokeMcpTool: (input: InvokeMcpToolInput) => Effect.Effect<unknown, McpConnectionError | McpInvocationError | McpOAuthReauthorizationRequired>;
@@ -0,0 +1 @@
1
+ export {};
@@ -156,12 +156,12 @@ export type McpStdioServerInput = typeof McpStdioServerInputSchema.Type;
156
156
  export type McpServerInput = typeof McpAddServerInputSchema.Type;
157
157
  export type McpProbeResult = typeof McpProbeEndpointOutputSchema.Type;
158
158
  export type McpProbeEndpointInput = typeof McpProbeEndpointInputSchema.Type;
159
- /** Translate a non-MCP probe outcome into a message a user can act on.
159
+ /** Translate a hard-stop probe outcome into a message a user can act on.
160
+ * Auth-required shapes are routed to the auth editor upstream, so they never
161
+ * reach here; the only outcomes are an unreachable endpoint or a non-MCP one.
160
162
  * Exported for tests. */
161
163
  export declare const userFacingProbeMessage: (shape: Extract<McpShapeProbeResult, {
162
- kind: "not-mcp";
163
- } | {
164
- kind: "unreachable";
164
+ readonly kind: "unreachable" | "not-mcp";
165
165
  }>) => string;
166
166
  export declare const describeMcpAuthMethods: (record: IntegrationRecord) => readonly AuthMethodDescriptor[];
167
167
  export declare const describeMcpIntegrationDisplay: (record: IntegrationRecord) => {
@@ -191,8 +191,8 @@ export declare const mcpPlugin: import("@executor-js/sdk").ConfiguredPlugin<"mcp
191
191
  } | {
192
192
  connected: false;
193
193
  requiresAuthentication: true;
194
- requiresOAuth: true;
195
- supportsDynamicRegistration: boolean;
194
+ requiresOAuth: false;
195
+ supportsDynamicRegistration: false;
196
196
  name: string;
197
197
  slug: string;
198
198
  toolCount: null;
@@ -201,8 +201,8 @@ export declare const mcpPlugin: import("@executor-js/sdk").ConfiguredPlugin<"mcp
201
201
  } | {
202
202
  connected: false;
203
203
  requiresAuthentication: true;
204
- requiresOAuth: false;
205
- supportsDynamicRegistration: false;
204
+ requiresOAuth: true;
205
+ supportsDynamicRegistration: boolean;
206
206
  name: string;
207
207
  slug: string;
208
208
  toolCount: null;
@@ -1 +1 @@
1
- export { McpTestServerError, McpTestServerLayer, makeAnnotationsMcpServer, makeEchoMcpServer, makeElicitationMcpServer, makeGreetingMcpServer, serveMcpServer, serveMcpServerWithOAuth, type McpTestRequest, type McpTestServer, type McpTestServerOptions, } from "./server";
1
+ export { McpTestServerError, McpTestServerLayer, TEST_IMAGE_MIME_TYPE, TEST_IMAGE_PNG_BASE64, makeAnnotationsMcpServer, makeEchoMcpServer, makeElicitationMcpServer, makeGreetingMcpServer, makeImageMcpServer, serveMcpServer, serveMcpServerWithOAuth, type McpTestRequest, type McpTestServer, type McpTestServerOptions, } from "./server";
@@ -63,6 +63,9 @@ export declare const makeGreetingMcpServer: (options?: {
63
63
  readonly toolDescription?: string;
64
64
  readonly text?: string;
65
65
  }) => McpServer;
66
+ export declare const TEST_IMAGE_MIME_TYPE = "image/png";
67
+ export declare const TEST_IMAGE_PNG_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAFgwJ/l8N1wwAAAABJRU5ErkJggg==";
68
+ export declare const makeImageMcpServer: () => McpServer;
66
69
  export declare const makeEchoMcpServer: (options?: {
67
70
  readonly name?: string;
68
71
  readonly version?: string;
package/dist/testing.js CHANGED
@@ -191,6 +191,58 @@ var makeGreetingMcpServer = (options = {}) => {
191
191
  );
192
192
  return server;
193
193
  };
194
+ var TEST_IMAGE_MIME_TYPE = "image/png";
195
+ var TEST_IMAGE_PNG_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAFgwJ/l8N1wwAAAABJRU5ErkJggg==";
196
+ var testImageMetadata = () => ({
197
+ name: "mcp-image-fixture.png",
198
+ mimeType: TEST_IMAGE_MIME_TYPE,
199
+ byteLength: Buffer.from(TEST_IMAGE_PNG_BASE64, "base64").byteLength
200
+ });
201
+ var makeImageMcpServer = () => {
202
+ const server = new McpServer(
203
+ { name: "image-test-server", version: "1.0.0" },
204
+ { capabilities: {} }
205
+ );
206
+ server.registerTool(
207
+ "image_fixture",
208
+ {
209
+ description: "Returns a deterministic PNG as MCP image content",
210
+ inputSchema: {}
211
+ },
212
+ async () => ({
213
+ content: [
214
+ {
215
+ type: "image",
216
+ data: TEST_IMAGE_PNG_BASE64,
217
+ mimeType: TEST_IMAGE_MIME_TYPE
218
+ }
219
+ ],
220
+ structuredContent: testImageMetadata()
221
+ })
222
+ );
223
+ server.registerTool(
224
+ "image_fixture_with_metadata",
225
+ {
226
+ description: "Returns text metadata followed by MCP image content",
227
+ inputSchema: {}
228
+ },
229
+ async () => ({
230
+ content: [
231
+ {
232
+ type: "text",
233
+ text: "Deterministic image fixture: mcp-image-fixture.png (image/png, 70 bytes)"
234
+ },
235
+ {
236
+ type: "image",
237
+ data: TEST_IMAGE_PNG_BASE64,
238
+ mimeType: TEST_IMAGE_MIME_TYPE
239
+ }
240
+ ],
241
+ structuredContent: testImageMetadata()
242
+ })
243
+ );
244
+ return server;
245
+ };
194
246
  var makeEchoMcpServer = (options = {}) => {
195
247
  const inputName = options.inputName ?? "value";
196
248
  const server = new McpServer(
@@ -320,10 +372,13 @@ var makeAnnotationsMcpServer = () => {
320
372
  export {
321
373
  McpTestServerError,
322
374
  McpTestServerLayer,
375
+ TEST_IMAGE_MIME_TYPE,
376
+ TEST_IMAGE_PNG_BASE64,
323
377
  makeAnnotationsMcpServer,
324
378
  makeEchoMcpServer,
325
379
  makeElicitationMcpServer,
326
380
  makeGreetingMcpServer,
381
+ makeImageMcpServer,
327
382
  serveMcpServer,
328
383
  serveMcpServerWithOAuth
329
384
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/testing/server.ts"],"sourcesContent":["import { Context, Data, Effect, Layer, Ref, Scope } from \"effect\";\nimport * as http from \"node:http\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { OAuthTestServer } from \"@executor-js/sdk/testing\";\nimport z from \"zod\";\n\nexport type McpTestServer = {\n readonly url: string;\n readonly endpoint: string;\n /** Number of MCP sessions created (each connect = 1 session) */\n readonly sessionCount: () => number;\n readonly requests: Effect.Effect<readonly McpTestRequest[]>;\n readonly clearRequests: Effect.Effect<void>;\n};\n\nexport type McpTestRequest = {\n readonly method: string;\n readonly url: string;\n readonly authorization: string | undefined;\n readonly sessionId: string | undefined;\n};\n\nexport type McpTestServerOptions = {\n readonly path?: string;\n readonly auth?: {\n readonly validateAuthorization: (authorization: string | undefined) => Effect.Effect<boolean>;\n readonly authorizationServerUrls?: readonly string[];\n readonly scopes?: readonly string[];\n readonly wwwAuthenticate?: string;\n };\n};\n\nexport class McpTestServerError extends Data.TaggedError(\"McpTestServerError\")<{\n readonly cause: unknown;\n}> {}\n\nconst writeJson = (\n response: http.ServerResponse,\n status: number,\n body: Readonly<Record<string, unknown>>,\n headers: Readonly<Record<string, string>> = {},\n) => {\n response.writeHead(status, {\n \"content-type\": \"application/json\",\n ...headers,\n });\n response.end(JSON.stringify(body));\n};\n\nconst writeText = (response: http.ServerResponse, status: number, body: string) => {\n response.writeHead(status, { \"content-type\": \"text/plain; charset=utf-8\" });\n response.end(body);\n};\n\nconst isMcpPath = (url: string, path: string): boolean => {\n const parsed = new URL(url, \"http://executor.test\");\n return parsed.pathname === path;\n};\n\nconst protectedResourcePath = \"/.well-known/oauth-protected-resource\";\n\nexport const serveMcpServer = (factory: () => McpServer, options: McpTestServerOptions = {}) =>\n Effect.acquireRelease(\n Effect.gen(function* () {\n const transports = new Map<string, StreamableHTTPServerTransport>();\n const requests = yield* Ref.make<readonly McpTestRequest[]>([]);\n const path = options.path ?? \"/\";\n let sessions = 0;\n\n const handleMcpRequest = (\n request: http.IncomingMessage,\n response: http.ServerResponse,\n ): Effect.Effect<void> =>\n Effect.gen(function* () {\n const requestUrl = request.url ?? \"/\";\n const sessionId = Array.isArray(request.headers[\"mcp-session-id\"])\n ? request.headers[\"mcp-session-id\"][0]\n : request.headers[\"mcp-session-id\"];\n const authorization = Array.isArray(request.headers.authorization)\n ? request.headers.authorization[0]\n : request.headers.authorization;\n const origin = request.headers.host\n ? `http://${request.headers.host}`\n : \"http://127.0.0.1\";\n\n yield* Ref.update(requests, (all) => [\n ...all,\n {\n method: request.method ?? \"GET\",\n url: requestUrl,\n authorization,\n sessionId,\n },\n ]);\n\n if (\n options.auth?.authorizationServerUrls &&\n requestUrl.startsWith(protectedResourcePath)\n ) {\n const resourcePath = requestUrl.slice(protectedResourcePath.length);\n writeJson(response, 200, {\n resource: `${origin}${resourcePath}`,\n authorization_servers: options.auth.authorizationServerUrls,\n bearer_methods_supported: [\"header\"],\n scopes_supported: options.auth.scopes ?? [\"read\"],\n });\n return;\n }\n\n if (!isMcpPath(requestUrl, path)) {\n writeJson(response, 404, { error: \"not_found\" });\n return;\n }\n\n if (options.auth) {\n const accepted = yield* options.auth.validateAuthorization(authorization);\n if (!accepted) {\n writeJson(\n response,\n 401,\n { error: \"invalid_token\" },\n {\n \"www-authenticate\":\n options.auth.wwwAuthenticate ??\n `Bearer resource_metadata=\"${origin}${protectedResourcePath}${path}\", error=\"invalid_token\"`,\n },\n );\n return;\n }\n }\n\n const existingTransport = sessionId ? transports.get(sessionId) : undefined;\n if (sessionId && !existingTransport) {\n writeText(response, 404, \"Session not found\");\n return;\n }\n\n if (existingTransport) {\n yield* Effect.tryPromise({\n try: () => existingTransport.handleRequest(request, response),\n catch: (cause) => new McpTestServerError({ cause }),\n });\n return;\n }\n\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => crypto.randomUUID(),\n onsessioninitialized: (sid) => {\n transports.set(sid, transport);\n },\n });\n sessions += 1;\n\n const mcpServer = factory();\n yield* Effect.tryPromise({\n try: () => mcpServer.connect(transport),\n catch: (cause) => new McpTestServerError({ cause }),\n });\n yield* Effect.tryPromise({\n try: () => transport.handleRequest(request, response),\n catch: (cause) => new McpTestServerError({ cause }),\n });\n }).pipe(\n Effect.catch(() =>\n Effect.sync(() => {\n if (!response.headersSent) {\n writeJson(response, 500, { error: \"mcp_test_server_failed\" });\n } else if (!response.writableEnded) {\n response.end();\n }\n }),\n ),\n );\n\n const nodeServer = http.createServer((request, response) => {\n void Effect.runPromise(handleMcpRequest(request, response));\n });\n\n const port = yield* Effect.callback<number, McpTestServerError>((resume) => {\n const onError = (cause: Error) => {\n nodeServer.off(\"error\", onError);\n resume(Effect.fail(new McpTestServerError({ cause })));\n };\n nodeServer.once(\"error\", onError);\n nodeServer.listen(0, () => {\n nodeServer.off(\"error\", onError);\n const address = nodeServer.address();\n if (typeof address === \"object\" && address) {\n resume(Effect.succeed(address.port));\n return;\n }\n resume(Effect.fail(new McpTestServerError({ cause: address })));\n });\n });\n\n const baseUrl = `http://127.0.0.1:${port}`;\n const endpoint = path === \"/\" ? baseUrl : new URL(path, baseUrl).toString();\n return {\n url: endpoint,\n endpoint,\n sessionCount: () => sessions,\n requests: Ref.get(requests),\n clearRequests: Ref.set(requests, []),\n close: Effect.gen(function* () {\n for (const transport of transports.values()) {\n yield* Effect.tryPromise({\n try: () => transport.close(),\n catch: (cause) => new McpTestServerError({ cause }),\n }).pipe(Effect.ignore);\n }\n yield* Effect.sync(() => {\n nodeServer.close();\n nodeServer.closeAllConnections?.();\n });\n }),\n };\n }),\n (server) => server.close,\n ).pipe(Effect.map(({ close: _close, ...server }) => server));\n\nexport const serveMcpServerWithOAuth = (\n factory: () => McpServer,\n options: Omit<McpTestServerOptions, \"auth\"> & {\n readonly scopes?: readonly string[];\n readonly wwwAuthenticate?: string;\n } = {},\n) =>\n Effect.gen(function* () {\n const oauth = yield* OAuthTestServer;\n return yield* serveMcpServer(factory, {\n path: options.path,\n auth: {\n validateAuthorization: oauth.acceptsAuthorizationHeader,\n authorizationServerUrls: [oauth.issuerUrl],\n scopes: options.scopes ?? [\"read\"],\n wwwAuthenticate: options.wwwAuthenticate,\n },\n });\n });\n\nexport class McpTestServerLayer extends Context.Service<McpTestServerLayer, McpTestServer>()(\n \"@executor-js/plugin-mcp/testing/McpTestServer\",\n) {\n static readonly layer = (\n factory: () => McpServer,\n options?: McpTestServerOptions,\n ): Layer.Layer<McpTestServerLayer, McpTestServerError, Scope.Scope> =>\n Layer.effect(McpTestServerLayer, serveMcpServer(factory, options));\n\n static readonly layerWithOAuth = (\n factory: () => McpServer,\n options?: Omit<McpTestServerOptions, \"auth\"> & {\n readonly scopes?: readonly string[];\n readonly wwwAuthenticate?: string;\n },\n ): Layer.Layer<McpTestServerLayer, McpTestServerError, Scope.Scope | OAuthTestServer> =>\n Layer.effect(McpTestServerLayer, serveMcpServerWithOAuth(factory, options));\n}\n\nexport const makeGreetingMcpServer = (\n options: {\n readonly name?: string;\n readonly version?: string;\n readonly toolName?: string;\n readonly toolDescription?: string;\n readonly text?: string;\n } = {},\n) => {\n const server = new McpServer(\n {\n name: options.name ?? \"executor-test-mcp\",\n version: options.version ?? \"1.0.0\",\n },\n { capabilities: {} },\n );\n\n server.registerTool(\n options.toolName ?? \"simple_echo\",\n {\n description: options.toolDescription ?? \"Echoes from the executor MCP test server\",\n inputSchema: {},\n },\n async () => ({\n content: [{ type: \"text\" as const, text: options.text ?? \"mcp-ok\" }],\n }),\n );\n\n return server;\n};\n\nexport const makeEchoMcpServer = (\n options: {\n readonly name?: string;\n readonly version?: string;\n readonly toolName?: string;\n readonly toolDescription?: string;\n readonly inputName?: \"name\" | \"value\" | \"marker\";\n readonly text?: (value: string) => string;\n } = {},\n) => {\n const inputName = options.inputName ?? \"value\";\n const server = new McpServer(\n {\n name: options.name ?? \"executor-echo-mcp\",\n version: options.version ?? \"1.0.0\",\n },\n { capabilities: {} },\n );\n\n server.registerTool(\n options.toolName ?? \"echo\",\n {\n description: options.toolDescription ?? \"Echoes a string value\",\n inputSchema: { [inputName]: z.string() },\n },\n async (input) => ({\n content: [\n {\n type: \"text\" as const,\n text: options.text ? options.text(input[inputName]) : input[inputName],\n },\n ],\n }),\n );\n\n return server;\n};\n\nexport const makeElicitationMcpServer = () => {\n const server = new McpServer(\n { name: \"elicitation-test-server\", version: \"1.0.0\" },\n { capabilities: {} },\n );\n\n server.registerTool(\n \"gated_echo\",\n {\n description: \"Asks for approval before echoing a value\",\n inputSchema: { value: z.string() },\n },\n async ({ value }: { value: string }) => {\n const response = await server.server.elicitInput({\n mode: \"form\",\n message: `Approve echo for \"${value}\"?`,\n requestedSchema: {\n type: \"object\",\n properties: {\n approved: { type: \"boolean\", title: \"Approve\" },\n },\n required: [\"approved\"],\n },\n });\n\n if (response.action !== \"accept\" || !response.content || response.content.approved !== true) {\n return {\n content: [{ type: \"text\" as const, text: `denied:${value}` }],\n };\n }\n\n return {\n content: [{ type: \"text\" as const, text: `approved:${value}` }],\n };\n },\n );\n\n server.registerTool(\n \"simple_echo\",\n {\n description: \"Echoes a value without elicitation\",\n inputSchema: { value: z.string() },\n },\n async ({ value }: { value: string }) => ({\n content: [{ type: \"text\" as const, text: value }],\n }),\n );\n\n server.registerTool(\n \"structured_echo\",\n {\n description: \"Returns text plus structured data\",\n inputSchema: { value: z.string() },\n outputSchema: {\n value: z.string(),\n upper: z.string(),\n },\n },\n async ({ value }: { value: string }) => ({\n content: [{ type: \"text\" as const, text: value }],\n structuredContent: { value, upper: value.toUpperCase() },\n _meta: { trace: \"kept\" },\n }),\n );\n\n return server;\n};\n\nexport const makeAnnotationsMcpServer = () => {\n const server = new McpServer(\n { name: \"annotations-test-server\", version: \"1.0.0\" },\n { capabilities: {} },\n );\n\n server.registerTool(\n \"delete\",\n {\n description: \"A destructive tool\",\n inputSchema: { id: z.string() },\n annotations: { destructiveHint: true },\n },\n async () => ({ content: [] }),\n );\n\n server.registerTool(\n \"delete_titled\",\n {\n description: \"A destructive tool with a title annotation\",\n inputSchema: { id: z.string() },\n annotations: { destructiveHint: true, title: \"Delete dataset\" },\n },\n async () => ({ content: [] }),\n );\n\n server.registerTool(\n \"list\",\n {\n description: \"A read-only tool\",\n inputSchema: {},\n annotations: { readOnlyHint: true },\n },\n async () => ({ content: [] }),\n );\n\n server.registerTool(\n \"ping\",\n { description: \"An unannotated tool\", inputSchema: {} },\n async () => ({ content: [] }),\n );\n\n return server;\n};\n"],"mappings":";AAAA,SAAS,SAAS,MAAM,QAAQ,OAAO,WAAkB;AACzD,YAAY,UAAU;AACtB,SAAS,iBAAiB;AAC1B,SAAS,qCAAqC;AAC9C,SAAS,uBAAuB;AAChC,OAAO,OAAO;AA4BP,IAAM,qBAAN,cAAiC,KAAK,YAAY,oBAAoB,EAE1E;AAAC;AAEJ,IAAM,YAAY,CAChB,UACA,QACA,MACA,UAA4C,CAAC,MAC1C;AACH,WAAS,UAAU,QAAQ;AAAA,IACzB,gBAAgB;AAAA,IAChB,GAAG;AAAA,EACL,CAAC;AACD,WAAS,IAAI,KAAK,UAAU,IAAI,CAAC;AACnC;AAEA,IAAM,YAAY,CAAC,UAA+B,QAAgB,SAAiB;AACjF,WAAS,UAAU,QAAQ,EAAE,gBAAgB,4BAA4B,CAAC;AAC1E,WAAS,IAAI,IAAI;AACnB;AAEA,IAAM,YAAY,CAAC,KAAa,SAA0B;AACxD,QAAM,SAAS,IAAI,IAAI,KAAK,sBAAsB;AAClD,SAAO,OAAO,aAAa;AAC7B;AAEA,IAAM,wBAAwB;AAEvB,IAAM,iBAAiB,CAAC,SAA0B,UAAgC,CAAC,MACxF,OAAO;AAAA,EACL,OAAO,IAAI,aAAa;AACtB,UAAM,aAAa,oBAAI,IAA2C;AAClE,UAAM,WAAW,OAAO,IAAI,KAAgC,CAAC,CAAC;AAC9D,UAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAI,WAAW;AAEf,UAAM,mBAAmB,CACvB,SACA,aAEA,OAAO,IAAI,aAAa;AACtB,YAAM,aAAa,QAAQ,OAAO;AAClC,YAAM,YAAY,MAAM,QAAQ,QAAQ,QAAQ,gBAAgB,CAAC,IAC7D,QAAQ,QAAQ,gBAAgB,EAAE,CAAC,IACnC,QAAQ,QAAQ,gBAAgB;AACpC,YAAM,gBAAgB,MAAM,QAAQ,QAAQ,QAAQ,aAAa,IAC7D,QAAQ,QAAQ,cAAc,CAAC,IAC/B,QAAQ,QAAQ;AACpB,YAAM,SAAS,QAAQ,QAAQ,OAC3B,UAAU,QAAQ,QAAQ,IAAI,KAC9B;AAEJ,aAAO,IAAI,OAAO,UAAU,CAAC,QAAQ;AAAA,QACnC,GAAG;AAAA,QACH;AAAA,UACE,QAAQ,QAAQ,UAAU;AAAA,UAC1B,KAAK;AAAA,UACL;AAAA,UACA;AAAA,QACF;AAAA,MACF,CAAC;AAED,UACE,QAAQ,MAAM,2BACd,WAAW,WAAW,qBAAqB,GAC3C;AACA,cAAM,eAAe,WAAW,MAAM,sBAAsB,MAAM;AAClE,kBAAU,UAAU,KAAK;AAAA,UACvB,UAAU,GAAG,MAAM,GAAG,YAAY;AAAA,UAClC,uBAAuB,QAAQ,KAAK;AAAA,UACpC,0BAA0B,CAAC,QAAQ;AAAA,UACnC,kBAAkB,QAAQ,KAAK,UAAU,CAAC,MAAM;AAAA,QAClD,CAAC;AACD;AAAA,MACF;AAEA,UAAI,CAAC,UAAU,YAAY,IAAI,GAAG;AAChC,kBAAU,UAAU,KAAK,EAAE,OAAO,YAAY,CAAC;AAC/C;AAAA,MACF;AAEA,UAAI,QAAQ,MAAM;AAChB,cAAM,WAAW,OAAO,QAAQ,KAAK,sBAAsB,aAAa;AACxE,YAAI,CAAC,UAAU;AACb;AAAA,YACE;AAAA,YACA;AAAA,YACA,EAAE,OAAO,gBAAgB;AAAA,YACzB;AAAA,cACE,oBACE,QAAQ,KAAK,mBACb,6BAA6B,MAAM,GAAG,qBAAqB,GAAG,IAAI;AAAA,YACtE;AAAA,UACF;AACA;AAAA,QACF;AAAA,MACF;AAEA,YAAM,oBAAoB,YAAY,WAAW,IAAI,SAAS,IAAI;AAClE,UAAI,aAAa,CAAC,mBAAmB;AACnC,kBAAU,UAAU,KAAK,mBAAmB;AAC5C;AAAA,MACF;AAEA,UAAI,mBAAmB;AACrB,eAAO,OAAO,WAAW;AAAA,UACvB,KAAK,MAAM,kBAAkB,cAAc,SAAS,QAAQ;AAAA,UAC5D,OAAO,CAAC,UAAU,IAAI,mBAAmB,EAAE,MAAM,CAAC;AAAA,QACpD,CAAC;AACD;AAAA,MACF;AAEA,YAAM,YAAY,IAAI,8BAA8B;AAAA,QAClD,oBAAoB,MAAM,OAAO,WAAW;AAAA,QAC5C,sBAAsB,CAAC,QAAQ;AAC7B,qBAAW,IAAI,KAAK,SAAS;AAAA,QAC/B;AAAA,MACF,CAAC;AACD,kBAAY;AAEZ,YAAM,YAAY,QAAQ;AAC1B,aAAO,OAAO,WAAW;AAAA,QACvB,KAAK,MAAM,UAAU,QAAQ,SAAS;AAAA,QACtC,OAAO,CAAC,UAAU,IAAI,mBAAmB,EAAE,MAAM,CAAC;AAAA,MACpD,CAAC;AACD,aAAO,OAAO,WAAW;AAAA,QACvB,KAAK,MAAM,UAAU,cAAc,SAAS,QAAQ;AAAA,QACpD,OAAO,CAAC,UAAU,IAAI,mBAAmB,EAAE,MAAM,CAAC;AAAA,MACpD,CAAC;AAAA,IACH,CAAC,EAAE;AAAA,MACD,OAAO;AAAA,QAAM,MACX,OAAO,KAAK,MAAM;AAChB,cAAI,CAAC,SAAS,aAAa;AACzB,sBAAU,UAAU,KAAK,EAAE,OAAO,yBAAyB,CAAC;AAAA,UAC9D,WAAW,CAAC,SAAS,eAAe;AAClC,qBAAS,IAAI;AAAA,UACf;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEF,UAAM,aAAkB,kBAAa,CAAC,SAAS,aAAa;AAC1D,WAAK,OAAO,WAAW,iBAAiB,SAAS,QAAQ,CAAC;AAAA,IAC5D,CAAC;AAED,UAAM,OAAO,OAAO,OAAO,SAAqC,CAAC,WAAW;AAC1E,YAAM,UAAU,CAAC,UAAiB;AAChC,mBAAW,IAAI,SAAS,OAAO;AAC/B,eAAO,OAAO,KAAK,IAAI,mBAAmB,EAAE,MAAM,CAAC,CAAC,CAAC;AAAA,MACvD;AACA,iBAAW,KAAK,SAAS,OAAO;AAChC,iBAAW,OAAO,GAAG,MAAM;AACzB,mBAAW,IAAI,SAAS,OAAO;AAC/B,cAAM,UAAU,WAAW,QAAQ;AACnC,YAAI,OAAO,YAAY,YAAY,SAAS;AAC1C,iBAAO,OAAO,QAAQ,QAAQ,IAAI,CAAC;AACnC;AAAA,QACF;AACA,eAAO,OAAO,KAAK,IAAI,mBAAmB,EAAE,OAAO,QAAQ,CAAC,CAAC,CAAC;AAAA,MAChE,CAAC;AAAA,IACH,CAAC;AAED,UAAM,UAAU,oBAAoB,IAAI;AACxC,UAAM,WAAW,SAAS,MAAM,UAAU,IAAI,IAAI,MAAM,OAAO,EAAE,SAAS;AAC1E,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA,cAAc,MAAM;AAAA,MACpB,UAAU,IAAI,IAAI,QAAQ;AAAA,MAC1B,eAAe,IAAI,IAAI,UAAU,CAAC,CAAC;AAAA,MACnC,OAAO,OAAO,IAAI,aAAa;AAC7B,mBAAW,aAAa,WAAW,OAAO,GAAG;AAC3C,iBAAO,OAAO,WAAW;AAAA,YACvB,KAAK,MAAM,UAAU,MAAM;AAAA,YAC3B,OAAO,CAAC,UAAU,IAAI,mBAAmB,EAAE,MAAM,CAAC;AAAA,UACpD,CAAC,EAAE,KAAK,OAAO,MAAM;AAAA,QACvB;AACA,eAAO,OAAO,KAAK,MAAM;AACvB,qBAAW,MAAM;AACjB,qBAAW,sBAAsB;AAAA,QACnC,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAAA,EACD,CAAC,WAAW,OAAO;AACrB,EAAE,KAAK,OAAO,IAAI,CAAC,EAAE,OAAO,QAAQ,GAAG,OAAO,MAAM,MAAM,CAAC;AAEtD,IAAM,0BAA0B,CACrC,SACA,UAGI,CAAC,MAEL,OAAO,IAAI,aAAa;AACtB,QAAM,QAAQ,OAAO;AACrB,SAAO,OAAO,eAAe,SAAS;AAAA,IACpC,MAAM,QAAQ;AAAA,IACd,MAAM;AAAA,MACJ,uBAAuB,MAAM;AAAA,MAC7B,yBAAyB,CAAC,MAAM,SAAS;AAAA,MACzC,QAAQ,QAAQ,UAAU,CAAC,MAAM;AAAA,MACjC,iBAAiB,QAAQ;AAAA,IAC3B;AAAA,EACF,CAAC;AACH,CAAC;AAEI,IAAM,qBAAN,MAAM,4BAA2B,QAAQ,QAA2C;AAAA,EACzF;AACF,EAAE;AAAA,EACA,OAAgB,QAAQ,CACtB,SACA,YAEA,MAAM,OAAO,qBAAoB,eAAe,SAAS,OAAO,CAAC;AAAA,EAEnE,OAAgB,iBAAiB,CAC/B,SACA,YAKA,MAAM,OAAO,qBAAoB,wBAAwB,SAAS,OAAO,CAAC;AAC9E;AAEO,IAAM,wBAAwB,CACnC,UAMI,CAAC,MACF;AACH,QAAM,SAAS,IAAI;AAAA,IACjB;AAAA,MACE,MAAM,QAAQ,QAAQ;AAAA,MACtB,SAAS,QAAQ,WAAW;AAAA,IAC9B;AAAA,IACA,EAAE,cAAc,CAAC,EAAE;AAAA,EACrB;AAEA,SAAO;AAAA,IACL,QAAQ,YAAY;AAAA,IACpB;AAAA,MACE,aAAa,QAAQ,mBAAmB;AAAA,MACxC,aAAa,CAAC;AAAA,IAChB;AAAA,IACA,aAAa;AAAA,MACX,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,QAAQ,QAAQ,SAAS,CAAC;AAAA,IACrE;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,oBAAoB,CAC/B,UAOI,CAAC,MACF;AACH,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,SAAS,IAAI;AAAA,IACjB;AAAA,MACE,MAAM,QAAQ,QAAQ;AAAA,MACtB,SAAS,QAAQ,WAAW;AAAA,IAC9B;AAAA,IACA,EAAE,cAAc,CAAC,EAAE;AAAA,EACrB;AAEA,SAAO;AAAA,IACL,QAAQ,YAAY;AAAA,IACpB;AAAA,MACE,aAAa,QAAQ,mBAAmB;AAAA,MACxC,aAAa,EAAE,CAAC,SAAS,GAAG,EAAE,OAAO,EAAE;AAAA,IACzC;AAAA,IACA,OAAO,WAAW;AAAA,MAChB,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,QAAQ,OAAO,QAAQ,KAAK,MAAM,SAAS,CAAC,IAAI,MAAM,SAAS;AAAA,QACvE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,2BAA2B,MAAM;AAC5C,QAAM,SAAS,IAAI;AAAA,IACjB,EAAE,MAAM,2BAA2B,SAAS,QAAQ;AAAA,IACpD,EAAE,cAAc,CAAC,EAAE;AAAA,EACrB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE;AAAA,IACnC;AAAA,IACA,OAAO,EAAE,MAAM,MAAyB;AACtC,YAAM,WAAW,MAAM,OAAO,OAAO,YAAY;AAAA,QAC/C,MAAM;AAAA,QACN,SAAS,qBAAqB,KAAK;AAAA,QACnC,iBAAiB;AAAA,UACf,MAAM;AAAA,UACN,YAAY;AAAA,YACV,UAAU,EAAE,MAAM,WAAW,OAAO,UAAU;AAAA,UAChD;AAAA,UACA,UAAU,CAAC,UAAU;AAAA,QACvB;AAAA,MACF,CAAC;AAED,UAAI,SAAS,WAAW,YAAY,CAAC,SAAS,WAAW,SAAS,QAAQ,aAAa,MAAM;AAC3F,eAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,UAAU,KAAK,GAAG,CAAC;AAAA,QAC9D;AAAA,MACF;AAEA,aAAO;AAAA,QACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,KAAK,GAAG,CAAC;AAAA,MAChE;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE;AAAA,IACnC;AAAA,IACA,OAAO,EAAE,MAAM,OAA0B;AAAA,MACvC,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,MAAM,CAAC;AAAA,IAClD;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE;AAAA,MACjC,cAAc;AAAA,QACZ,OAAO,EAAE,OAAO;AAAA,QAChB,OAAO,EAAE,OAAO;AAAA,MAClB;AAAA,IACF;AAAA,IACA,OAAO,EAAE,MAAM,OAA0B;AAAA,MACvC,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,MAAM,CAAC;AAAA,MAChD,mBAAmB,EAAE,OAAO,OAAO,MAAM,YAAY,EAAE;AAAA,MACvD,OAAO,EAAE,OAAO,OAAO;AAAA,IACzB;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,2BAA2B,MAAM;AAC5C,QAAM,SAAS,IAAI;AAAA,IACjB,EAAE,MAAM,2BAA2B,SAAS,QAAQ;AAAA,IACpD,EAAE,cAAc,CAAC,EAAE;AAAA,EACrB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE;AAAA,MAC9B,aAAa,EAAE,iBAAiB,KAAK;AAAA,IACvC;AAAA,IACA,aAAa,EAAE,SAAS,CAAC,EAAE;AAAA,EAC7B;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE;AAAA,MAC9B,aAAa,EAAE,iBAAiB,MAAM,OAAO,iBAAiB;AAAA,IAChE;AAAA,IACA,aAAa,EAAE,SAAS,CAAC,EAAE;AAAA,EAC7B;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,CAAC;AAAA,MACd,aAAa,EAAE,cAAc,KAAK;AAAA,IACpC;AAAA,IACA,aAAa,EAAE,SAAS,CAAC,EAAE;AAAA,EAC7B;AAEA,SAAO;AAAA,IACL;AAAA,IACA,EAAE,aAAa,uBAAuB,aAAa,CAAC,EAAE;AAAA,IACtD,aAAa,EAAE,SAAS,CAAC,EAAE;AAAA,EAC7B;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/testing/server.ts"],"sourcesContent":["import { Context, Data, Effect, Layer, Ref, Scope } from \"effect\";\nimport * as http from \"node:http\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { OAuthTestServer } from \"@executor-js/sdk/testing\";\nimport z from \"zod\";\n\nexport type McpTestServer = {\n readonly url: string;\n readonly endpoint: string;\n /** Number of MCP sessions created (each connect = 1 session) */\n readonly sessionCount: () => number;\n readonly requests: Effect.Effect<readonly McpTestRequest[]>;\n readonly clearRequests: Effect.Effect<void>;\n};\n\nexport type McpTestRequest = {\n readonly method: string;\n readonly url: string;\n readonly authorization: string | undefined;\n readonly sessionId: string | undefined;\n};\n\nexport type McpTestServerOptions = {\n readonly path?: string;\n readonly auth?: {\n readonly validateAuthorization: (authorization: string | undefined) => Effect.Effect<boolean>;\n readonly authorizationServerUrls?: readonly string[];\n readonly scopes?: readonly string[];\n readonly wwwAuthenticate?: string;\n };\n};\n\nexport class McpTestServerError extends Data.TaggedError(\"McpTestServerError\")<{\n readonly cause: unknown;\n}> {}\n\nconst writeJson = (\n response: http.ServerResponse,\n status: number,\n body: Readonly<Record<string, unknown>>,\n headers: Readonly<Record<string, string>> = {},\n) => {\n response.writeHead(status, {\n \"content-type\": \"application/json\",\n ...headers,\n });\n response.end(JSON.stringify(body));\n};\n\nconst writeText = (response: http.ServerResponse, status: number, body: string) => {\n response.writeHead(status, { \"content-type\": \"text/plain; charset=utf-8\" });\n response.end(body);\n};\n\nconst isMcpPath = (url: string, path: string): boolean => {\n const parsed = new URL(url, \"http://executor.test\");\n return parsed.pathname === path;\n};\n\nconst protectedResourcePath = \"/.well-known/oauth-protected-resource\";\n\nexport const serveMcpServer = (factory: () => McpServer, options: McpTestServerOptions = {}) =>\n Effect.acquireRelease(\n Effect.gen(function* () {\n const transports = new Map<string, StreamableHTTPServerTransport>();\n const requests = yield* Ref.make<readonly McpTestRequest[]>([]);\n const path = options.path ?? \"/\";\n let sessions = 0;\n\n const handleMcpRequest = (\n request: http.IncomingMessage,\n response: http.ServerResponse,\n ): Effect.Effect<void> =>\n Effect.gen(function* () {\n const requestUrl = request.url ?? \"/\";\n const sessionId = Array.isArray(request.headers[\"mcp-session-id\"])\n ? request.headers[\"mcp-session-id\"][0]\n : request.headers[\"mcp-session-id\"];\n const authorization = Array.isArray(request.headers.authorization)\n ? request.headers.authorization[0]\n : request.headers.authorization;\n const origin = request.headers.host\n ? `http://${request.headers.host}`\n : \"http://127.0.0.1\";\n\n yield* Ref.update(requests, (all) => [\n ...all,\n {\n method: request.method ?? \"GET\",\n url: requestUrl,\n authorization,\n sessionId,\n },\n ]);\n\n if (\n options.auth?.authorizationServerUrls &&\n requestUrl.startsWith(protectedResourcePath)\n ) {\n const resourcePath = requestUrl.slice(protectedResourcePath.length);\n writeJson(response, 200, {\n resource: `${origin}${resourcePath}`,\n authorization_servers: options.auth.authorizationServerUrls,\n bearer_methods_supported: [\"header\"],\n scopes_supported: options.auth.scopes ?? [\"read\"],\n });\n return;\n }\n\n if (!isMcpPath(requestUrl, path)) {\n writeJson(response, 404, { error: \"not_found\" });\n return;\n }\n\n if (options.auth) {\n const accepted = yield* options.auth.validateAuthorization(authorization);\n if (!accepted) {\n writeJson(\n response,\n 401,\n { error: \"invalid_token\" },\n {\n \"www-authenticate\":\n options.auth.wwwAuthenticate ??\n `Bearer resource_metadata=\"${origin}${protectedResourcePath}${path}\", error=\"invalid_token\"`,\n },\n );\n return;\n }\n }\n\n const existingTransport = sessionId ? transports.get(sessionId) : undefined;\n if (sessionId && !existingTransport) {\n writeText(response, 404, \"Session not found\");\n return;\n }\n\n if (existingTransport) {\n yield* Effect.tryPromise({\n try: () => existingTransport.handleRequest(request, response),\n catch: (cause) => new McpTestServerError({ cause }),\n });\n return;\n }\n\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => crypto.randomUUID(),\n onsessioninitialized: (sid) => {\n transports.set(sid, transport);\n },\n });\n sessions += 1;\n\n const mcpServer = factory();\n yield* Effect.tryPromise({\n try: () => mcpServer.connect(transport),\n catch: (cause) => new McpTestServerError({ cause }),\n });\n yield* Effect.tryPromise({\n try: () => transport.handleRequest(request, response),\n catch: (cause) => new McpTestServerError({ cause }),\n });\n }).pipe(\n Effect.catch(() =>\n Effect.sync(() => {\n if (!response.headersSent) {\n writeJson(response, 500, { error: \"mcp_test_server_failed\" });\n } else if (!response.writableEnded) {\n response.end();\n }\n }),\n ),\n );\n\n const nodeServer = http.createServer((request, response) => {\n void Effect.runPromise(handleMcpRequest(request, response));\n });\n\n const port = yield* Effect.callback<number, McpTestServerError>((resume) => {\n const onError = (cause: Error) => {\n nodeServer.off(\"error\", onError);\n resume(Effect.fail(new McpTestServerError({ cause })));\n };\n nodeServer.once(\"error\", onError);\n nodeServer.listen(0, () => {\n nodeServer.off(\"error\", onError);\n const address = nodeServer.address();\n if (typeof address === \"object\" && address) {\n resume(Effect.succeed(address.port));\n return;\n }\n resume(Effect.fail(new McpTestServerError({ cause: address })));\n });\n });\n\n const baseUrl = `http://127.0.0.1:${port}`;\n const endpoint = path === \"/\" ? baseUrl : new URL(path, baseUrl).toString();\n return {\n url: endpoint,\n endpoint,\n sessionCount: () => sessions,\n requests: Ref.get(requests),\n clearRequests: Ref.set(requests, []),\n close: Effect.gen(function* () {\n for (const transport of transports.values()) {\n yield* Effect.tryPromise({\n try: () => transport.close(),\n catch: (cause) => new McpTestServerError({ cause }),\n }).pipe(Effect.ignore);\n }\n yield* Effect.sync(() => {\n nodeServer.close();\n nodeServer.closeAllConnections?.();\n });\n }),\n };\n }),\n (server) => server.close,\n ).pipe(Effect.map(({ close: _close, ...server }) => server));\n\nexport const serveMcpServerWithOAuth = (\n factory: () => McpServer,\n options: Omit<McpTestServerOptions, \"auth\"> & {\n readonly scopes?: readonly string[];\n readonly wwwAuthenticate?: string;\n } = {},\n) =>\n Effect.gen(function* () {\n const oauth = yield* OAuthTestServer;\n return yield* serveMcpServer(factory, {\n path: options.path,\n auth: {\n validateAuthorization: oauth.acceptsAuthorizationHeader,\n authorizationServerUrls: [oauth.issuerUrl],\n scopes: options.scopes ?? [\"read\"],\n wwwAuthenticate: options.wwwAuthenticate,\n },\n });\n });\n\nexport class McpTestServerLayer extends Context.Service<McpTestServerLayer, McpTestServer>()(\n \"@executor-js/plugin-mcp/testing/McpTestServer\",\n) {\n static readonly layer = (\n factory: () => McpServer,\n options?: McpTestServerOptions,\n ): Layer.Layer<McpTestServerLayer, McpTestServerError, Scope.Scope> =>\n Layer.effect(McpTestServerLayer, serveMcpServer(factory, options));\n\n static readonly layerWithOAuth = (\n factory: () => McpServer,\n options?: Omit<McpTestServerOptions, \"auth\"> & {\n readonly scopes?: readonly string[];\n readonly wwwAuthenticate?: string;\n },\n ): Layer.Layer<McpTestServerLayer, McpTestServerError, Scope.Scope | OAuthTestServer> =>\n Layer.effect(McpTestServerLayer, serveMcpServerWithOAuth(factory, options));\n}\n\nexport const makeGreetingMcpServer = (\n options: {\n readonly name?: string;\n readonly version?: string;\n readonly toolName?: string;\n readonly toolDescription?: string;\n readonly text?: string;\n } = {},\n) => {\n const server = new McpServer(\n {\n name: options.name ?? \"executor-test-mcp\",\n version: options.version ?? \"1.0.0\",\n },\n { capabilities: {} },\n );\n\n server.registerTool(\n options.toolName ?? \"simple_echo\",\n {\n description: options.toolDescription ?? \"Echoes from the executor MCP test server\",\n inputSchema: {},\n },\n async () => ({\n content: [{ type: \"text\" as const, text: options.text ?? \"mcp-ok\" }],\n }),\n );\n\n return server;\n};\n\nexport const TEST_IMAGE_MIME_TYPE = \"image/png\";\nexport const TEST_IMAGE_PNG_BASE64 =\n \"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAFgwJ/l8N1wwAAAABJRU5ErkJggg==\";\n\nconst testImageMetadata = () => ({\n name: \"mcp-image-fixture.png\",\n mimeType: TEST_IMAGE_MIME_TYPE,\n byteLength: Buffer.from(TEST_IMAGE_PNG_BASE64, \"base64\").byteLength,\n});\n\nexport const makeImageMcpServer = () => {\n const server = new McpServer(\n { name: \"image-test-server\", version: \"1.0.0\" },\n { capabilities: {} },\n );\n\n server.registerTool(\n \"image_fixture\",\n {\n description: \"Returns a deterministic PNG as MCP image content\",\n inputSchema: {},\n },\n async () => ({\n content: [\n {\n type: \"image\" as const,\n data: TEST_IMAGE_PNG_BASE64,\n mimeType: TEST_IMAGE_MIME_TYPE,\n },\n ],\n structuredContent: testImageMetadata(),\n }),\n );\n\n server.registerTool(\n \"image_fixture_with_metadata\",\n {\n description: \"Returns text metadata followed by MCP image content\",\n inputSchema: {},\n },\n async () => ({\n content: [\n {\n type: \"text\" as const,\n text: \"Deterministic image fixture: mcp-image-fixture.png (image/png, 70 bytes)\",\n },\n {\n type: \"image\" as const,\n data: TEST_IMAGE_PNG_BASE64,\n mimeType: TEST_IMAGE_MIME_TYPE,\n },\n ],\n structuredContent: testImageMetadata(),\n }),\n );\n\n return server;\n};\n\nexport const makeEchoMcpServer = (\n options: {\n readonly name?: string;\n readonly version?: string;\n readonly toolName?: string;\n readonly toolDescription?: string;\n readonly inputName?: \"name\" | \"value\" | \"marker\";\n readonly text?: (value: string) => string;\n } = {},\n) => {\n const inputName = options.inputName ?? \"value\";\n const server = new McpServer(\n {\n name: options.name ?? \"executor-echo-mcp\",\n version: options.version ?? \"1.0.0\",\n },\n { capabilities: {} },\n );\n\n server.registerTool(\n options.toolName ?? \"echo\",\n {\n description: options.toolDescription ?? \"Echoes a string value\",\n inputSchema: { [inputName]: z.string() },\n },\n async (input) => ({\n content: [\n {\n type: \"text\" as const,\n text: options.text ? options.text(input[inputName]) : input[inputName],\n },\n ],\n }),\n );\n\n return server;\n};\n\nexport const makeElicitationMcpServer = () => {\n const server = new McpServer(\n { name: \"elicitation-test-server\", version: \"1.0.0\" },\n { capabilities: {} },\n );\n\n server.registerTool(\n \"gated_echo\",\n {\n description: \"Asks for approval before echoing a value\",\n inputSchema: { value: z.string() },\n },\n async ({ value }: { value: string }) => {\n const response = await server.server.elicitInput({\n mode: \"form\",\n message: `Approve echo for \"${value}\"?`,\n requestedSchema: {\n type: \"object\",\n properties: {\n approved: { type: \"boolean\", title: \"Approve\" },\n },\n required: [\"approved\"],\n },\n });\n\n if (response.action !== \"accept\" || !response.content || response.content.approved !== true) {\n return {\n content: [{ type: \"text\" as const, text: `denied:${value}` }],\n };\n }\n\n return {\n content: [{ type: \"text\" as const, text: `approved:${value}` }],\n };\n },\n );\n\n server.registerTool(\n \"simple_echo\",\n {\n description: \"Echoes a value without elicitation\",\n inputSchema: { value: z.string() },\n },\n async ({ value }: { value: string }) => ({\n content: [{ type: \"text\" as const, text: value }],\n }),\n );\n\n server.registerTool(\n \"structured_echo\",\n {\n description: \"Returns text plus structured data\",\n inputSchema: { value: z.string() },\n outputSchema: {\n value: z.string(),\n upper: z.string(),\n },\n },\n async ({ value }: { value: string }) => ({\n content: [{ type: \"text\" as const, text: value }],\n structuredContent: { value, upper: value.toUpperCase() },\n _meta: { trace: \"kept\" },\n }),\n );\n\n return server;\n};\n\nexport const makeAnnotationsMcpServer = () => {\n const server = new McpServer(\n { name: \"annotations-test-server\", version: \"1.0.0\" },\n { capabilities: {} },\n );\n\n server.registerTool(\n \"delete\",\n {\n description: \"A destructive tool\",\n inputSchema: { id: z.string() },\n annotations: { destructiveHint: true },\n },\n async () => ({ content: [] }),\n );\n\n server.registerTool(\n \"delete_titled\",\n {\n description: \"A destructive tool with a title annotation\",\n inputSchema: { id: z.string() },\n annotations: { destructiveHint: true, title: \"Delete dataset\" },\n },\n async () => ({ content: [] }),\n );\n\n server.registerTool(\n \"list\",\n {\n description: \"A read-only tool\",\n inputSchema: {},\n annotations: { readOnlyHint: true },\n },\n async () => ({ content: [] }),\n );\n\n server.registerTool(\n \"ping\",\n { description: \"An unannotated tool\", inputSchema: {} },\n async () => ({ content: [] }),\n );\n\n return server;\n};\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@executor-js/plugin-mcp",
3
- "version": "1.5.14",
3
+ "version": "1.5.16",
4
4
  "homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/plugins/mcp",
5
5
  "bugs": {
6
6
  "url": "https://github.com/RhysSullivan/executor/issues"
@@ -54,8 +54,8 @@
54
54
  "dependencies": {
55
55
  "@cfworker/json-schema": "^4.1.1",
56
56
  "@effect/platform-node": "4.0.0-beta.59",
57
- "@executor-js/config": "1.5.14",
58
- "@executor-js/sdk": "1.5.14",
57
+ "@executor-js/config": "1.5.16",
58
+ "@executor-js/sdk": "1.5.16",
59
59
  "@modelcontextprotocol/sdk": "^1.29.0",
60
60
  "zod": "4.3.6"
61
61
  },
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/sdk/errors.ts","../src/sdk/types.ts"],"sourcesContent":["// MCP plugin tagged errors. Each carries an `HttpApiSchema` annotation so\n// it can be `.addError(...)` directly on the API group — handlers return\n// these and HttpApi encodes them as 4xx responses with a typed body. No\n// per-handler sanitisation step.\n\nimport { Schema } from \"effect\";\n\nexport class McpConnectionError extends Schema.TaggedErrorClass<McpConnectionError>()(\n \"McpConnectionError\",\n {\n transport: Schema.String,\n message: Schema.String,\n },\n { httpApiStatus: 400 },\n) {}\n\nexport class McpToolDiscoveryError extends Schema.TaggedErrorClass<McpToolDiscoveryError>()(\n \"McpToolDiscoveryError\",\n {\n stage: Schema.Literals([\"connect\", \"list_tools\"]),\n message: Schema.String,\n },\n { httpApiStatus: 400 },\n) {}\n\nexport class McpInvocationError extends Schema.TaggedErrorClass<McpInvocationError>()(\n \"McpInvocationError\",\n {\n toolName: Schema.String,\n message: Schema.String,\n },\n { httpApiStatus: 400 },\n) {}\n\nexport class McpOAuthError extends Schema.TaggedErrorClass<McpOAuthError>()(\n \"McpOAuthError\",\n {\n message: Schema.String,\n },\n { httpApiStatus: 400 },\n) {}\n","import { Effect, Option, Schema } from \"effect\";\nimport {\n ApiKeyAuthMethod,\n ApiKeyAuthTemplate,\n NoneAuthMethod,\n apiKeyMethodFromAuthTemplate,\n isApiKeyAuthTemplate,\n normalizeAuthMethodSlugs,\n} from \"@executor-js/sdk/http-auth\";\n\n// ---------------------------------------------------------------------------\n// MCP plugin v2 data model.\n//\n// An MCP integration is one server. Its `config` blob (opaque to core, stored\n// on the integration row) carries everything needed to dial the server plus\n// the declared auth methods describing how a connection's resolved credential\n// values are applied to the request. A connection IS the credential: at\n// execute time core resolves the connection's values through its provider\n// (refreshing OAuth tokens), and the plugin renders them onto the request per\n// the method the connection binds (D11).\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// Transport / remote transport\n// ---------------------------------------------------------------------------\n\nexport const McpRemoteTransport = Schema.Literals([\"streamable-http\", \"sse\", \"auto\"]);\nexport type McpRemoteTransport = typeof McpRemoteTransport.Type;\n\n/** All transport types (used in the connector layer) */\nexport const McpTransport = Schema.Literals([\"streamable-http\", \"sse\", \"stdio\", \"auto\"]);\nexport type McpTransport = typeof McpTransport.Type;\n\n// ---------------------------------------------------------------------------\n// Auth methods — the shared placements vocabulary (`@executor-js/sdk/http-auth`)\n// plus MCP's own oauth variant. An integration declares zero or more methods,\n// each with a stable `slug` a connection binds against (`connection.template`),\n// mirroring the OpenAPI/GraphQL `authenticationTemplate` arrays.\n//\n// none — no credential (open server)\n// apikey — render the connection's values through the method's header/query\n// placements (one credential input per distinct placement\n// `variable`; servers like ui.sh authenticate via a `?token=`\n// query placement, and a method may mix carriers — e.g. a bearer\n// header plus a team-id query param)\n// oauth2 — the value is an OAuth access token, applied as a Bearer header\n// via the MCP SDK's OAuthClientProvider. MCP oauth carries no\n// stored endpoints: metadata is discovered live at connect time.\n// ---------------------------------------------------------------------------\n\nexport const McpOAuthMethod = Schema.Struct({\n slug: Schema.String,\n kind: Schema.Literal(\"oauth2\"),\n});\nexport type McpOAuthMethod = typeof McpOAuthMethod.Type;\n\nexport const McpAuthMethod = Schema.Union([NoneAuthMethod, ApiKeyAuthMethod, McpOAuthMethod]);\nexport type McpAuthMethod = typeof McpAuthMethod.Type;\n\n/** Single-method `auth` shorthand on `addServer` — agent convenience for the\n * common cases. Normalized into `authenticationTemplate` at the boundary;\n * never stored. */\nexport const McpAuthShorthand = Schema.Union([\n Schema.Struct({ kind: Schema.Literal(\"none\") }),\n Schema.Struct({\n kind: Schema.Literal(\"header\"),\n headerName: Schema.String,\n prefix: Schema.optional(Schema.String),\n }),\n Schema.Struct({ kind: Schema.Literal(\"oauth2\") }),\n]);\nexport type McpAuthShorthand = typeof McpAuthShorthand.Type;\n\n/** Expand the `auth` shorthand into a declared method. Slugs match what the\n * shorthand has always produced (`none` / `header` / `oauth2`) so existing\n * connections bound to them keep matching. */\nexport const mcpAuthMethodFromShorthand = (auth: McpAuthShorthand): McpAuthMethod => {\n if (auth.kind === \"header\") {\n return {\n slug: \"header\",\n kind: \"apikey\",\n placements: [\n {\n carrier: \"header\",\n name: auth.headerName,\n ...(auth.prefix !== undefined ? { prefix: auth.prefix } : {}),\n },\n ],\n };\n }\n return { slug: auth.kind, kind: auth.kind };\n};\n\n/** Input variant of `McpAuthMethod` — callers (UI, agents) may omit the slug;\n * `normalizeMcpAuthMethods` backfills it. */\nexport const McpAuthMethodInput = Schema.Union([\n Schema.Struct({ slug: Schema.optional(Schema.String), kind: Schema.Literal(\"none\") }),\n Schema.Struct({ slug: Schema.optional(Schema.String), kind: Schema.Literal(\"oauth2\") }),\n // Credential methods are authored request-shaped — the ONE apikey input\n // dialect: `{ type: \"apiKey\", headers: { Authorization: [\"Bearer \",\n // variable(\"token\")] }, queryParams: { … } }`. Stored configs and the\n // catalog read as canonical placements; `apiKeyAuthTemplateFromMethod`\n // serializes them back for read-modify-write flows.\n ApiKeyAuthTemplate,\n]);\nexport type McpAuthMethodInput = typeof McpAuthMethodInput.Type;\n\n/** The expansion target: input arms with the dialect resolved to canonical\n * placements (slug still optional — backfill is a separate pass). */\nexport type McpCanonicalAuthMethodInput =\n | Exclude<McpAuthMethodInput, ApiKeyAuthTemplate>\n | (Omit<ApiKeyAuthMethod, \"slug\"> & { readonly slug?: string });\n\n/** The default slug for a slug-less input method. Carrier-derived for the\n * single-placement apikey cases (`header` / `query`) — the slugs those\n * methods have always had — so the shorthand, UI, and migration paths all\n * converge on the same names. */\nconst defaultMcpAuthSlug = (method: McpCanonicalAuthMethodInput): string => {\n if (method.kind !== \"apikey\") return method.kind;\n if (method.placements.length === 1) {\n return method.placements[0]!.carrier === \"header\" ? \"header\" : \"query\";\n }\n return \"apikey\";\n};\n\n/** Expand request-shaped dialect entries into canonical placements; canonical\n * entries pass through. Slug backfill is the caller's concern\n * (`normalizeMcpAuthMethods` for declare flows, `mergeAuthTemplates` for the\n * custom-method merge). */\nexport const expandMcpAuthMethodInputs = (\n methods: readonly McpAuthMethodInput[],\n): readonly McpCanonicalAuthMethodInput[] =>\n methods.map(\n (method): McpCanonicalAuthMethodInput =>\n isApiKeyAuthTemplate(method)\n ? (apiKeyMethodFromAuthTemplate(method) as McpCanonicalAuthMethodInput)\n : (method as McpCanonicalAuthMethodInput),\n );\n\n/** Assign each method a stable slug: a caller-provided one wins, otherwise a\n * kind/carrier-derived default, suffixed `_2`, `_3`, … on collision. The\n * request-shaped dialect is expanded to canonical placements first. */\nexport const normalizeMcpAuthMethods = (\n methods: readonly McpAuthMethodInput[],\n): readonly McpAuthMethod[] =>\n normalizeAuthMethodSlugs(\n expandMcpAuthMethodInputs(methods),\n defaultMcpAuthSlug,\n ) as readonly McpAuthMethod[];\n\n// ---------------------------------------------------------------------------\n// Integration config — the opaque blob stored on the integration row. A\n// discriminated union on transport.\n// ---------------------------------------------------------------------------\n\nconst StringMap = Schema.Record(Schema.String, Schema.String);\n\nexport const McpRemoteIntegrationConfig = Schema.Struct({\n transport: Schema.Literal(\"remote\"),\n /** The MCP server endpoint URL */\n endpoint: Schema.String,\n /** Transport preference for this remote server */\n remoteTransport: McpRemoteTransport.pipe(\n Schema.optionalKey,\n Schema.withConstructorDefault(Effect.succeed(\"auto\" as const)),\n ),\n /** Static query params appended to the endpoint URL (non-credential) */\n queryParams: Schema.optional(StringMap),\n /** Static headers sent on every request (non-credential) */\n headers: Schema.optional(StringMap),\n /** Declared auth methods — how a connection's values are rendered onto\n * requests. A connection's `template` picks one by slug. */\n authenticationTemplate: Schema.Array(McpAuthMethod),\n});\nexport type McpRemoteIntegrationConfig = typeof McpRemoteIntegrationConfig.Type;\n\nexport const McpStdioIntegrationConfig = Schema.Struct({\n transport: Schema.Literal(\"stdio\"),\n /** The command to run */\n command: Schema.String,\n /** Arguments to the command */\n args: Schema.optional(Schema.Array(Schema.String)),\n /** Environment variables */\n env: Schema.optional(StringMap),\n /** Working directory */\n cwd: Schema.optional(Schema.String),\n});\nexport type McpStdioIntegrationConfig = typeof McpStdioIntegrationConfig.Type;\n\nexport const McpIntegrationConfig = Schema.Union([\n McpRemoteIntegrationConfig,\n McpStdioIntegrationConfig,\n]);\nexport type McpIntegrationConfig = typeof McpIntegrationConfig.Type;\n\nconst decodeIntegrationConfig = Schema.decodeUnknownOption(McpIntegrationConfig);\n\n/** Parse an opaque integration `config` blob into a typed MCP config, or null\n * if it isn't this plugin's (canonical) shape. Pre-canonical stored shapes\n * are rewritten by the one-off config migration (`migrate-config.ts`), not\n * decoded here — runtime code knows only the canonical model. */\nexport const parseMcpIntegrationConfig = (config: unknown): McpIntegrationConfig | null =>\n Option.getOrNull(decodeIntegrationConfig(config));\n\n// ---------------------------------------------------------------------------\n// Tool annotations — upstream MCP ToolAnnotations we honour (destructiveHint\n// drives requiresApproval).\n// ---------------------------------------------------------------------------\n\nexport const McpToolAnnotations = Schema.Struct({\n title: Schema.optional(Schema.String),\n readOnlyHint: Schema.optional(Schema.Boolean),\n destructiveHint: Schema.optional(Schema.Boolean),\n idempotentHint: Schema.optional(Schema.Boolean),\n openWorldHint: Schema.optional(Schema.Boolean),\n});\nexport type McpToolAnnotations = typeof McpToolAnnotations.Type;\n\n// ---------------------------------------------------------------------------\n// Tool binding — maps a persisted (sanitized) tool name back to its real MCP\n// tool name and upstream annotations, persisted per-connection so invokeTool\n// can dial the server with the correct name.\n// ---------------------------------------------------------------------------\n\nexport const McpToolBinding = Schema.Struct({\n /** Sanitized, address-safe tool name (the `<tool>` address segment). */\n toolId: Schema.String,\n /** The real MCP tool name as advertised by the server. */\n toolName: Schema.String,\n description: Schema.NullOr(Schema.String),\n inputSchema: Schema.optional(Schema.Unknown),\n outputSchema: Schema.optional(Schema.Unknown),\n annotations: Schema.optional(McpToolAnnotations),\n});\nexport type McpToolBinding = typeof McpToolBinding.Type;\n"],"mappings":"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","names":["Schema"]}