@executor-js/plugin-mcp 0.0.1-beta.6 → 0.0.2

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 (40) hide show
  1. package/README.md +19 -15
  2. package/dist/api/group.d.ts +114 -147
  3. package/dist/api/handlers.d.ts +2 -2
  4. package/dist/api/handlers.test.d.ts +1 -0
  5. package/dist/chunk-DJANY5EU.js +1325 -0
  6. package/dist/chunk-DJANY5EU.js.map +1 -0
  7. package/dist/core.js +8 -52
  8. package/dist/core.js.map +1 -1
  9. package/dist/index.js +2 -5
  10. package/dist/index.js.map +1 -1
  11. package/dist/promise.d.ts +2 -6
  12. package/dist/react/AddMcpSource.d.ts +2 -0
  13. package/dist/react/McpSignInButton.d.ts +3 -0
  14. package/dist/react/atoms.d.ts +153 -0
  15. package/dist/react/client.d.ts +437 -3
  16. package/dist/react/index.d.ts +3 -2
  17. package/dist/react/source-plugin.d.ts +13 -1
  18. package/dist/sdk/binding-store.d.ts +74 -18
  19. package/dist/sdk/connection-pool.test.d.ts +1 -0
  20. package/dist/sdk/connection.d.ts +3 -1
  21. package/dist/sdk/cross-user-isolation.test.d.ts +1 -0
  22. package/dist/sdk/errors.d.ts +15 -23
  23. package/dist/sdk/index.d.ts +3 -3
  24. package/dist/sdk/invoke.d.ts +18 -17
  25. package/dist/sdk/manifest.d.ts +1 -0
  26. package/dist/sdk/per-user-auth-isolation.test.d.ts +1 -0
  27. package/dist/sdk/plugin.d.ts +109 -43
  28. package/dist/sdk/probe-shape.d.ts +39 -0
  29. package/dist/sdk/probe-shape.test.d.ts +1 -0
  30. package/dist/sdk/stdio-connector.d.ts +8 -0
  31. package/dist/sdk/stored-source.d.ts +31 -105
  32. package/dist/sdk/types.d.ts +77 -93
  33. package/dist/stdio-connector-KNHLETKM.js +12 -0
  34. package/dist/stdio-connector-KNHLETKM.js.map +1 -0
  35. package/package.json +11 -21
  36. package/dist/chunk-NJ4CITCV.js +0 -1203
  37. package/dist/chunk-NJ4CITCV.js.map +0 -1
  38. package/dist/react/McpSourceSummary.d.ts +0 -3
  39. package/dist/sdk/config-file-store.d.ts +0 -10
  40. package/dist/sdk/oauth.d.ts +0 -36
@@ -1,1203 +0,0 @@
1
- // src/sdk/binding-store.ts
2
- import { Effect, Schema as Schema2 } from "effect";
3
- import { makeInMemoryScopedKv, scopeKv } from "@executor-js/sdk";
4
-
5
- // src/sdk/types.ts
6
- import { Schema } from "effect";
7
- var McpRemoteTransport = Schema.Literal("streamable-http", "sse", "auto");
8
- var McpTransport = Schema.Literal("streamable-http", "sse", "stdio", "auto");
9
- var McpConnectionAuth = Schema.Union(
10
- Schema.Struct({ kind: Schema.Literal("none") }),
11
- Schema.Struct({
12
- kind: Schema.Literal("header"),
13
- headerName: Schema.String,
14
- secretId: Schema.String,
15
- prefix: Schema.optional(Schema.String)
16
- }),
17
- Schema.Struct({
18
- kind: Schema.Literal("oauth2"),
19
- accessTokenSecretId: Schema.String,
20
- refreshTokenSecretId: Schema.NullOr(Schema.String),
21
- tokenType: Schema.optionalWith(Schema.String, { default: () => "Bearer" }),
22
- expiresAt: Schema.NullOr(Schema.Number),
23
- scope: Schema.NullOr(Schema.String)
24
- })
25
- );
26
- var StringMap = Schema.Record({ key: Schema.String, value: Schema.String });
27
- var McpRemoteSourceData = Schema.Struct({
28
- transport: Schema.Literal("remote"),
29
- /** The MCP server endpoint URL */
30
- endpoint: Schema.String,
31
- /** Transport preference for this remote source */
32
- remoteTransport: Schema.optionalWith(McpRemoteTransport, { default: () => "auto" }),
33
- /** Extra query params appended to the endpoint URL */
34
- queryParams: Schema.optional(StringMap),
35
- /** Extra headers sent on every request */
36
- headers: Schema.optional(StringMap),
37
- /** Auth configuration */
38
- auth: McpConnectionAuth
39
- });
40
- var McpStdioSourceData = Schema.Struct({
41
- transport: Schema.Literal("stdio"),
42
- /** The command to run */
43
- command: Schema.String,
44
- /** Arguments to the command */
45
- args: Schema.optional(Schema.Array(Schema.String)),
46
- /** Environment variables */
47
- env: Schema.optional(StringMap),
48
- /** Working directory */
49
- cwd: Schema.optional(Schema.String)
50
- });
51
- var McpStoredSourceData = Schema.Union(McpRemoteSourceData, McpStdioSourceData);
52
- var McpToolBinding = class extends Schema.Class("McpToolBinding")({
53
- toolId: Schema.String,
54
- toolName: Schema.String,
55
- description: Schema.NullOr(Schema.String),
56
- inputSchema: Schema.optional(Schema.Unknown),
57
- outputSchema: Schema.optional(Schema.Unknown)
58
- }) {
59
- };
60
-
61
- // src/sdk/binding-store.ts
62
- var StoredBindingEntry = Schema2.Struct({
63
- namespace: Schema2.String,
64
- binding: McpToolBinding,
65
- sourceData: Schema2.Unknown
66
- });
67
- var encodeBindingEntry = Schema2.encodeSync(Schema2.parseJson(StoredBindingEntry));
68
- var decodeBindingEntry = Schema2.decodeUnknownSync(Schema2.parseJson(StoredBindingEntry));
69
- var makeStore = (bindings, sources) => ({
70
- // ---- Bindings ----
71
- get: (toolId) => Effect.gen(function* () {
72
- const raw = yield* bindings.get(toolId);
73
- if (!raw) return null;
74
- const entry = decodeBindingEntry(raw);
75
- return {
76
- binding: entry.binding,
77
- sourceData: entry.sourceData
78
- };
79
- }),
80
- put: (toolId, namespace, binding, sourceData) => bindings.set([{ key: toolId, value: encodeBindingEntry({ namespace, binding, sourceData }) }]),
81
- remove: (toolId) => bindings.delete([toolId]).pipe(Effect.asVoid),
82
- listByNamespace: (namespace) => Effect.gen(function* () {
83
- const entries = yield* bindings.list();
84
- const ids = [];
85
- for (const e of entries) {
86
- const entry = decodeBindingEntry(e.value);
87
- if (entry.namespace === namespace) ids.push(e.key);
88
- }
89
- return ids;
90
- }),
91
- removeByNamespace: (namespace) => Effect.gen(function* () {
92
- const entries = yield* bindings.list();
93
- const ids = [];
94
- for (const e of entries) {
95
- const entry = decodeBindingEntry(e.value);
96
- if (entry.namespace === namespace) ids.push(e.key);
97
- }
98
- if (ids.length > 0) yield* bindings.delete(ids);
99
- return ids;
100
- }),
101
- // ---- Sources (meta + config combined) ----
102
- putSource: (source) => sources.set([{ key: source.namespace, value: JSON.stringify(source) }]),
103
- removeSource: (namespace) => sources.delete([namespace]).pipe(Effect.asVoid),
104
- listSources: () => Effect.gen(function* () {
105
- const entries = yield* sources.list();
106
- return entries.map((e) => JSON.parse(e.value));
107
- }),
108
- getSource: (namespace) => Effect.gen(function* () {
109
- const raw = yield* sources.get(namespace);
110
- if (!raw) return null;
111
- return JSON.parse(raw);
112
- }),
113
- getSourceConfig: (namespace) => Effect.gen(function* () {
114
- const raw = yield* sources.get(namespace);
115
- if (!raw) return null;
116
- const source = JSON.parse(raw);
117
- return source.config;
118
- })
119
- });
120
- var makeKvBindingStore = (kv, namespace) => makeStore(scopeKv(kv, `${namespace}.bindings`), scopeKv(kv, `${namespace}.sources`));
121
- var makeInMemoryBindingStore = () => makeStore(makeInMemoryScopedKv(), makeInMemoryScopedKv());
122
-
123
- // src/sdk/plugin.ts
124
- import { Effect as Effect6, Exit, ScopedCache, Duration, Scope } from "effect";
125
- import {
126
- Source,
127
- SourceDetectionResult,
128
- definePlugin,
129
- ToolId,
130
- SecretId
131
- } from "@executor-js/sdk";
132
-
133
- // src/sdk/connection.ts
134
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
135
- import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
136
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
137
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
138
- import { Effect as Effect2 } from "effect";
139
-
140
- // src/sdk/errors.ts
141
- import { Schema as Schema3 } from "effect";
142
- var McpConnectionError = class extends Schema3.TaggedError()(
143
- "McpConnectionError",
144
- {
145
- transport: Schema3.String,
146
- message: Schema3.String
147
- }
148
- ) {
149
- };
150
- var McpToolDiscoveryError = class extends Schema3.TaggedError()(
151
- "McpToolDiscoveryError",
152
- {
153
- stage: Schema3.Literal("connect", "list_tools"),
154
- message: Schema3.String
155
- }
156
- ) {
157
- };
158
- var McpInvocationError = class extends Schema3.TaggedError()(
159
- "McpInvocationError",
160
- {
161
- toolName: Schema3.String,
162
- message: Schema3.String
163
- }
164
- ) {
165
- };
166
- var McpOAuthError = class extends Schema3.TaggedError()("McpOAuthError", {
167
- message: Schema3.String
168
- }) {
169
- };
170
-
171
- // src/sdk/connection.ts
172
- var buildEndpointUrl = (endpoint, queryParams) => {
173
- const url = new URL(endpoint);
174
- for (const [key, value] of Object.entries(queryParams)) {
175
- url.searchParams.set(key, value);
176
- }
177
- return url;
178
- };
179
- var createClient = () => new Client(
180
- { name: "executor-mcp", version: "0.1.0" },
181
- { capabilities: { elicitation: { form: {}, url: {} } } }
182
- );
183
- var connectionFromClient = (client) => ({
184
- client,
185
- close: () => client.close()
186
- });
187
- var connectClient = (input) => Effect2.gen(function* () {
188
- const client = createClient();
189
- const transportInstance = input.createTransport();
190
- yield* Effect2.tryPromise({
191
- try: () => client.connect(transportInstance),
192
- catch: (cause) => new McpConnectionError({
193
- transport: input.transport,
194
- message: `Failed connecting via ${input.transport}: ${cause instanceof Error ? cause.message : String(cause)}`
195
- })
196
- });
197
- return connectionFromClient(client);
198
- });
199
- var createMcpConnector = (input) => {
200
- if (input.transport === "stdio") {
201
- const command = input.command.trim();
202
- if (!command) {
203
- return new McpConnectionError({
204
- transport: "stdio",
205
- message: "MCP stdio transport requires a command"
206
- });
207
- }
208
- return connectClient({
209
- transport: "stdio",
210
- createTransport: () => new StdioClientTransport({
211
- command,
212
- args: input.args ? [...input.args] : void 0,
213
- env: input.env ? { ...process.env, ...input.env } : void 0,
214
- cwd: input.cwd?.trim().length ? input.cwd.trim() : void 0
215
- })
216
- });
217
- }
218
- const headers = input.headers ?? {};
219
- const remoteTransport = input.remoteTransport ?? "auto";
220
- const requestInit = Object.keys(headers).length > 0 ? { headers } : void 0;
221
- const endpoint = buildEndpointUrl(input.endpoint, input.queryParams ?? {});
222
- const connectStreamableHttp = connectClient({
223
- transport: "streamable-http",
224
- createTransport: () => new StreamableHTTPClientTransport(endpoint, {
225
- requestInit,
226
- authProvider: input.authProvider
227
- })
228
- });
229
- const connectSse = connectClient({
230
- transport: "sse",
231
- createTransport: () => new SSEClientTransport(endpoint, {
232
- requestInit,
233
- authProvider: input.authProvider
234
- })
235
- });
236
- if (remoteTransport === "streamable-http") return connectStreamableHttp;
237
- if (remoteTransport === "sse") return connectSse;
238
- return connectStreamableHttp.pipe(Effect2.catchAll(() => connectSse));
239
- };
240
-
241
- // src/sdk/oauth.ts
242
- import {
243
- auth
244
- } from "@modelcontextprotocol/sdk/client/auth.js";
245
- import { Effect as Effect3 } from "effect";
246
- var toJsonObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
247
- var CLIENT_METADATA = {
248
- grant_types: ["authorization_code", "refresh_token"],
249
- response_types: ["code"],
250
- token_endpoint_auth_method: "none",
251
- client_name: "Executor"
252
- };
253
- var extractDiscoveryState = (discoveryState, clientInformation) => ({
254
- resourceMetadataUrl: discoveryState?.resourceMetadataUrl ?? null,
255
- authorizationServerUrl: discoveryState?.authorizationServerUrl ?? null,
256
- resourceMetadata: toJsonObject(discoveryState?.resourceMetadata),
257
- authorizationServerMetadata: toJsonObject(discoveryState?.authorizationServerMetadata),
258
- clientInformation: toJsonObject(clientInformation)
259
- });
260
- var callAuth = (provider, opts) => Effect3.tryPromise({
261
- try: () => auth(provider, opts),
262
- catch: (cause) => new McpOAuthError({
263
- message: cause instanceof Error ? cause.message : String(cause)
264
- })
265
- });
266
- var startMcpOAuthAuthorization = (input) => Effect3.gen(function* () {
267
- let authorizationUrl;
268
- let codeVerifier;
269
- let discoveryState;
270
- let clientInformation;
271
- const provider = {
272
- get redirectUrl() {
273
- return input.redirectUrl;
274
- },
275
- get clientMetadata() {
276
- return { ...CLIENT_METADATA, redirect_uris: [input.redirectUrl] };
277
- },
278
- state: () => input.state,
279
- clientInformation: () => clientInformation,
280
- saveClientInformation: (ci) => {
281
- clientInformation = ci;
282
- },
283
- tokens: () => void 0,
284
- saveTokens: () => void 0,
285
- redirectToAuthorization: (url) => {
286
- authorizationUrl = url;
287
- },
288
- saveCodeVerifier: (cv) => {
289
- codeVerifier = cv;
290
- },
291
- codeVerifier: () => {
292
- if (!codeVerifier) throw new Error("Code verifier not captured");
293
- return codeVerifier;
294
- },
295
- saveDiscoveryState: (s) => {
296
- discoveryState = s;
297
- },
298
- discoveryState: () => discoveryState
299
- };
300
- const result = yield* callAuth(provider, { serverUrl: input.endpoint });
301
- if (result !== "REDIRECT" || !authorizationUrl || !codeVerifier) {
302
- return yield* new McpOAuthError({
303
- message: "OAuth flow did not produce an authorization redirect"
304
- });
305
- }
306
- return {
307
- authorizationUrl: authorizationUrl.toString(),
308
- codeVerifier,
309
- ...extractDiscoveryState(discoveryState, clientInformation)
310
- };
311
- });
312
- var exchangeMcpOAuthCode = (input) => Effect3.gen(function* () {
313
- const { session } = input;
314
- let tokens;
315
- let discoveryState = {
316
- authorizationServerUrl: session.authorizationServerUrl ?? new URL("/", session.endpoint).toString(),
317
- resourceMetadataUrl: session.resourceMetadataUrl ?? void 0,
318
- resourceMetadata: session.resourceMetadata,
319
- authorizationServerMetadata: session.authorizationServerMetadata
320
- };
321
- let clientInformation = session.clientInformation;
322
- const provider = {
323
- get redirectUrl() {
324
- return session.redirectUrl;
325
- },
326
- get clientMetadata() {
327
- return { ...CLIENT_METADATA, redirect_uris: [session.redirectUrl] };
328
- },
329
- clientInformation: () => clientInformation,
330
- saveClientInformation: (ci) => {
331
- clientInformation = ci;
332
- },
333
- tokens: () => void 0,
334
- saveTokens: (t) => {
335
- tokens = t;
336
- },
337
- redirectToAuthorization: () => {
338
- throw new Error("Unexpected redirect during code exchange");
339
- },
340
- saveCodeVerifier: () => void 0,
341
- codeVerifier: () => session.codeVerifier,
342
- saveDiscoveryState: (s) => {
343
- discoveryState = s;
344
- },
345
- discoveryState: () => discoveryState
346
- };
347
- const result = yield* callAuth(provider, {
348
- serverUrl: session.endpoint,
349
- authorizationCode: input.code
350
- });
351
- if (result !== "AUTHORIZED" || !tokens) {
352
- return yield* new McpOAuthError({
353
- message: "OAuth exchange did not produce tokens"
354
- });
355
- }
356
- return {
357
- tokens,
358
- ...extractDiscoveryState(discoveryState, clientInformation)
359
- };
360
- });
361
-
362
- // src/sdk/discover.ts
363
- import { Effect as Effect4 } from "effect";
364
-
365
- // src/sdk/manifest.ts
366
- import { Schema as Schema4 } from "effect";
367
- var ListedTool = Schema4.Struct({
368
- name: Schema4.String,
369
- description: Schema4.optional(Schema4.NullOr(Schema4.String)),
370
- inputSchema: Schema4.optional(Schema4.Unknown),
371
- parameters: Schema4.optional(Schema4.Unknown),
372
- outputSchema: Schema4.optional(Schema4.Unknown)
373
- });
374
- var ListToolsResult = Schema4.Struct({
375
- tools: Schema4.Array(ListedTool)
376
- });
377
- var ServerInfo = Schema4.Struct({
378
- name: Schema4.optional(Schema4.String),
379
- version: Schema4.optional(Schema4.String)
380
- });
381
- var decodeListToolsResult = Schema4.decodeUnknownOption(ListToolsResult);
382
- var decodeServerInfo = Schema4.decodeUnknownOption(ServerInfo);
383
- var sanitize = (value) => {
384
- const s = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
385
- return s || "tool";
386
- };
387
- var uniqueId = (value, seen) => {
388
- const base = sanitize(value);
389
- const n = (seen.get(base) ?? 0) + 1;
390
- seen.set(base, n);
391
- return n === 1 ? base : `${base}_${n}`;
392
- };
393
- var joinToolPath = (namespace, toolId) => namespace?.trim() ? `${namespace}.${toolId}` : toolId;
394
- var extractManifestFromListToolsResult = (listToolsResult, metadata) => {
395
- const seen = /* @__PURE__ */ new Map();
396
- const listed = decodeListToolsResult(listToolsResult).pipe(
397
- (opt) => opt._tag === "Some" ? opt.value.tools : []
398
- );
399
- const server = decodeServerInfo(metadata?.serverInfo).pipe(
400
- (opt) => opt._tag === "Some" ? { name: opt.value.name ?? null, version: opt.value.version ?? null } : null
401
- );
402
- const tools = listed.flatMap((tool) => {
403
- const toolName = tool.name.trim();
404
- if (!toolName) return [];
405
- return [
406
- {
407
- toolId: uniqueId(toolName, seen),
408
- toolName,
409
- description: tool.description ?? null,
410
- inputSchema: tool.inputSchema ?? tool.parameters,
411
- outputSchema: tool.outputSchema
412
- }
413
- ];
414
- });
415
- return { server, tools };
416
- };
417
- var slugify = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
418
- var hostnameOf = (url) => {
419
- try {
420
- return new URL(url).hostname;
421
- } catch {
422
- return null;
423
- }
424
- };
425
- var basenameOf = (path) => path.trim().split(/[\\/]/).pop() ?? path.trim();
426
- var deriveMcpNamespace = (input) => {
427
- if (input.name?.trim()) return slugify(input.name) || "mcp";
428
- const fromEndpoint = input.endpoint?.trim() ? hostnameOf(input.endpoint) : null;
429
- if (fromEndpoint) return slugify(fromEndpoint) || "mcp";
430
- if (input.command?.trim()) return slugify(basenameOf(input.command)) || "mcp";
431
- return "mcp";
432
- };
433
-
434
- // src/sdk/discover.ts
435
- var discoverTools = (connector) => Effect4.gen(function* () {
436
- const connection = yield* connector.pipe(
437
- Effect4.mapError(
438
- (err) => new McpToolDiscoveryError({
439
- stage: "connect",
440
- message: `Failed connecting to MCP server: ${err.message}`
441
- })
442
- )
443
- );
444
- const listResult = yield* Effect4.tryPromise({
445
- try: () => connection.client.listTools(),
446
- catch: (cause) => new McpToolDiscoveryError({
447
- stage: "list_tools",
448
- message: `Failed listing MCP tools: ${cause instanceof Error ? cause.message : String(cause)}`
449
- })
450
- });
451
- const manifest = extractManifestFromListToolsResult(listResult, {
452
- serverInfo: connection.client.getServerVersion?.()
453
- });
454
- yield* Effect4.promise(() => connection.close().catch(() => {
455
- }));
456
- return manifest;
457
- });
458
-
459
- // src/sdk/invoke.ts
460
- import { Effect as Effect5, Schema as Schema5 } from "effect";
461
- import { ElicitRequestSchema } from "@modelcontextprotocol/sdk/types.js";
462
- import {
463
- ToolInvocationResult,
464
- ToolInvocationError,
465
- ToolAnnotations,
466
- ElicitationResponse,
467
- FormElicitation,
468
- UrlElicitation
469
- } from "@executor-js/sdk";
470
- var asRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
471
- var makeOAuthProvider = (accessToken, tokenType, refreshToken) => ({
472
- get redirectUrl() {
473
- return "http://localhost/oauth/callback";
474
- },
475
- get clientMetadata() {
476
- return {
477
- redirect_uris: ["http://localhost/oauth/callback"],
478
- grant_types: ["authorization_code", "refresh_token"],
479
- response_types: ["code"],
480
- token_endpoint_auth_method: "none",
481
- client_name: "Executor"
482
- };
483
- },
484
- clientInformation: () => void 0,
485
- saveClientInformation: () => {
486
- },
487
- tokens: async () => ({
488
- access_token: accessToken,
489
- token_type: tokenType,
490
- ...refreshToken ? { refresh_token: refreshToken } : {}
491
- }),
492
- saveTokens: async () => {
493
- },
494
- redirectToAuthorization: async () => {
495
- throw new Error("MCP OAuth re-authorization required");
496
- },
497
- saveCodeVerifier: () => {
498
- },
499
- codeVerifier: () => {
500
- throw new Error("No active PKCE verifier");
501
- },
502
- saveDiscoveryState: () => {
503
- },
504
- discoveryState: () => void 0
505
- });
506
- var McpElicitParams = Schema5.Union(
507
- Schema5.Struct({
508
- mode: Schema5.Literal("url"),
509
- message: Schema5.String,
510
- url: Schema5.String,
511
- elicitationId: Schema5.optional(Schema5.String),
512
- id: Schema5.optional(Schema5.String)
513
- }),
514
- Schema5.Struct({
515
- mode: Schema5.optional(Schema5.Literal("form")),
516
- message: Schema5.String,
517
- requestedSchema: Schema5.Record({ key: Schema5.String, value: Schema5.Unknown })
518
- })
519
- );
520
- var decodeElicitParams = Schema5.decodeUnknownSync(McpElicitParams);
521
- var toElicitationRequest = (params) => params.mode === "url" ? new UrlElicitation({
522
- message: params.message,
523
- url: params.url,
524
- elicitationId: params.elicitationId ?? params.id ?? ""
525
- }) : new FormElicitation({
526
- message: params.message,
527
- requestedSchema: params.requestedSchema
528
- });
529
- var installElicitationHandler = (client, toolId, args, handler) => {
530
- client.setRequestHandler(ElicitRequestSchema, async (request) => {
531
- const params = decodeElicitParams(request.params);
532
- const response = await Effect5.runPromise(
533
- handler({ toolId, args, request: toElicitationRequest(params) })
534
- );
535
- return {
536
- action: response.action,
537
- ...response.action === "accept" && response.content ? { content: response.content } : {}
538
- };
539
- });
540
- };
541
- var resolveConnectorInput = (sourceData, secrets, scopeId) => {
542
- if (sourceData.transport === "stdio") {
543
- return Effect5.succeed({
544
- transport: "stdio",
545
- command: sourceData.command,
546
- args: sourceData.args,
547
- env: sourceData.env,
548
- cwd: sourceData.cwd
549
- });
550
- }
551
- return Effect5.gen(function* () {
552
- const headers = { ...sourceData.headers };
553
- let authProvider;
554
- const auth2 = sourceData.auth;
555
- if (auth2.kind === "header") {
556
- const secretValue = yield* secrets.resolve(auth2.secretId, scopeId).pipe(
557
- Effect5.mapError(
558
- () => new ToolInvocationError({
559
- toolId: "",
560
- message: `Failed to resolve secret "${auth2.secretId}" for MCP auth`,
561
- cause: void 0
562
- })
563
- )
564
- );
565
- headers[auth2.headerName] = auth2.prefix ? `${auth2.prefix}${secretValue}` : secretValue;
566
- } else if (auth2.kind === "oauth2") {
567
- const accessToken = yield* secrets.resolve(auth2.accessTokenSecretId, scopeId).pipe(
568
- Effect5.mapError(
569
- () => new ToolInvocationError({
570
- toolId: "",
571
- message: "Failed to resolve OAuth access token for MCP auth",
572
- cause: void 0
573
- })
574
- )
575
- );
576
- let refreshToken;
577
- if (auth2.refreshTokenSecretId) {
578
- refreshToken = yield* secrets.resolve(auth2.refreshTokenSecretId, scopeId).pipe(
579
- Effect5.option,
580
- Effect5.map((o) => o._tag === "Some" ? o.value : void 0)
581
- );
582
- }
583
- authProvider = makeOAuthProvider(accessToken, auth2.tokenType ?? "Bearer", refreshToken);
584
- }
585
- return {
586
- transport: "remote",
587
- endpoint: sourceData.endpoint,
588
- remoteTransport: sourceData.remoteTransport,
589
- queryParams: sourceData.queryParams,
590
- headers: Object.keys(headers).length > 0 ? headers : void 0,
591
- authProvider
592
- };
593
- });
594
- };
595
- var connectionCacheKey = (sourceData) => sourceData.transport === "stdio" ? `stdio:${sourceData.command}` : `remote:${sourceData.endpoint}`;
596
- var resolveElicitationHandler = (options) => options.onElicitation === "accept-all" ? () => Effect5.succeed(new ElicitationResponse({ action: "accept" })) : options.onElicitation;
597
- var useMcpConnection = (connection, toolId, toolName, args, handler) => Effect5.gen(function* () {
598
- installElicitationHandler(connection.client, toolId, args, handler);
599
- return yield* Effect5.tryPromise({
600
- try: () => connection.client.callTool({ name: toolName, arguments: args }),
601
- catch: (cause) => new ToolInvocationError({
602
- toolId,
603
- message: `MCP tool call failed for ${toolName}: ${cause instanceof Error ? cause.message : String(cause)}`,
604
- cause
605
- })
606
- });
607
- }).pipe(Effect5.withSpan(`mcp.callTool.${toolName}`));
608
- var makeMcpInvoker = (opts) => {
609
- const { connectionCache, pendingConnectors } = opts;
610
- return {
611
- resolveAnnotations: () => Effect5.succeed(new ToolAnnotations({ requiresApproval: false })),
612
- invoke: (toolId, args, options) => Effect5.gen(function* () {
613
- const entry = yield* opts.bindingStore.get(toolId);
614
- if (!entry) {
615
- return yield* new ToolInvocationError({
616
- toolId,
617
- message: `No MCP binding found for tool "${toolId}"`,
618
- cause: void 0
619
- });
620
- }
621
- const { binding, sourceData } = entry;
622
- const cacheKey = connectionCacheKey(sourceData);
623
- const connector = resolveConnectorInput(sourceData, opts.secrets, opts.scopeId).pipe(
624
- Effect5.flatMap((ci) => createMcpConnector(ci)),
625
- Effect5.mapError(
626
- (err) => new McpConnectionError({
627
- transport: "auto",
628
- message: err instanceof Error ? err.message : String(err)
629
- })
630
- )
631
- );
632
- pendingConnectors.set(cacheKey, connector);
633
- const connection = yield* connectionCache.get(cacheKey).pipe(
634
- Effect5.mapError(
635
- (err) => new ToolInvocationError({
636
- toolId,
637
- message: `Failed connecting to MCP server: ${err instanceof Error ? err.message : String(err)}`,
638
- cause: err
639
- })
640
- )
641
- );
642
- const elicitationHandler = resolveElicitationHandler(options);
643
- return yield* useMcpConnection(
644
- connection,
645
- toolId,
646
- binding.toolName,
647
- asRecord(args),
648
- elicitationHandler
649
- ).pipe(
650
- // On failure, invalidate the cached connection and retry once
651
- Effect5.catchAll(
652
- () => Effect5.gen(function* () {
653
- yield* connectionCache.invalidate(cacheKey);
654
- pendingConnectors.set(cacheKey, connector);
655
- const freshConnection = yield* connectionCache.get(cacheKey).pipe(
656
- Effect5.mapError(
657
- (retryErr) => new ToolInvocationError({
658
- toolId,
659
- message: `Failed reconnecting: ${retryErr instanceof Error ? retryErr.message : String(retryErr)}`,
660
- cause: retryErr
661
- })
662
- )
663
- );
664
- return yield* useMcpConnection(
665
- freshConnection,
666
- toolId,
667
- binding.toolName,
668
- asRecord(args),
669
- elicitationHandler
670
- );
671
- })
672
- )
673
- );
674
- }).pipe(
675
- Effect5.scoped,
676
- Effect5.map((callResult) => {
677
- const resultRecord = asRecord(callResult);
678
- const isError = resultRecord.isError === true;
679
- return new ToolInvocationResult({
680
- data: isError ? null : callResult ?? null,
681
- error: isError ? callResult : null
682
- });
683
- }),
684
- Effect5.catchAll((err) => {
685
- if (typeof err === "object" && err !== null && "_tag" in err && err._tag === "ToolInvocationError") {
686
- return Effect5.fail(err);
687
- }
688
- return Effect5.fail(
689
- new ToolInvocationError({
690
- toolId,
691
- message: `MCP invocation failed: ${err instanceof Error ? err.message : String(err)}`,
692
- cause: err
693
- })
694
- );
695
- })
696
- ),
697
- closeConnections: () => Effect5.sync(() => {
698
- pendingConnectors.clear();
699
- }).pipe(Effect5.flatMap(() => connectionCache.invalidateAll))
700
- };
701
- };
702
-
703
- // src/sdk/plugin.ts
704
- var toRegistration = (entry, namespace) => ({
705
- id: ToolId.make(joinToolPath(namespace, entry.toolId)),
706
- pluginKey: "mcp",
707
- sourceId: namespace,
708
- name: entry.toolName,
709
- description: entry.description ?? `MCP tool: ${entry.toolName}`,
710
- inputSchema: entry.inputSchema,
711
- outputSchema: entry.outputSchema
712
- });
713
- var toBinding = (entry) => new McpToolBinding({
714
- toolId: entry.toolId,
715
- toolName: entry.toolName,
716
- description: entry.description,
717
- inputSchema: entry.inputSchema,
718
- outputSchema: entry.outputSchema
719
- });
720
- var toStoredSourceData = (config) => {
721
- if (config.transport === "stdio") {
722
- return {
723
- transport: "stdio",
724
- command: config.command,
725
- args: config.args,
726
- env: config.env,
727
- cwd: config.cwd
728
- };
729
- }
730
- return {
731
- transport: "remote",
732
- endpoint: config.endpoint,
733
- remoteTransport: config.remoteTransport ?? "auto",
734
- queryParams: config.queryParams,
735
- headers: config.headers,
736
- auth: config.auth ?? { kind: "none" }
737
- };
738
- };
739
- var normalizeNamespace = (config) => config.namespace ?? deriveMcpNamespace({
740
- name: config.name,
741
- endpoint: config.transport === "remote" ? config.endpoint : void 0,
742
- command: config.transport === "stdio" ? config.command : void 0
743
- });
744
- var makeOAuthProvider2 = (accessToken, tokenType, refreshToken) => ({
745
- get redirectUrl() {
746
- return "http://localhost/oauth/callback";
747
- },
748
- get clientMetadata() {
749
- return {
750
- redirect_uris: ["http://localhost/oauth/callback"],
751
- grant_types: ["authorization_code", "refresh_token"],
752
- response_types: ["code"],
753
- token_endpoint_auth_method: "none",
754
- client_name: "Executor"
755
- };
756
- },
757
- clientInformation: () => void 0,
758
- saveClientInformation: () => {
759
- },
760
- tokens: async () => ({
761
- access_token: accessToken,
762
- token_type: tokenType,
763
- ...refreshToken ? { refresh_token: refreshToken } : {}
764
- }),
765
- saveTokens: async () => {
766
- },
767
- redirectToAuthorization: async () => {
768
- throw new Error("MCP OAuth re-authorization required");
769
- },
770
- saveCodeVerifier: () => {
771
- },
772
- codeVerifier: () => {
773
- throw new Error("No active PKCE verifier");
774
- },
775
- saveDiscoveryState: () => {
776
- },
777
- discoveryState: () => void 0
778
- });
779
- var remoteConnectionError = (message) => new McpConnectionError({ transport: "remote", message });
780
- var mcpOAuthError = (message) => new McpOAuthError({ message });
781
- var mcpDiscoveryError = (message) => new McpToolDiscoveryError({ stage: "list_tools", message });
782
- var mcpPlugin = (options) => {
783
- const bindingStore = options?.bindingStore ?? makeInMemoryBindingStore();
784
- const addedSources = /* @__PURE__ */ new Map();
785
- const oauthSessions = /* @__PURE__ */ new Map();
786
- return definePlugin({
787
- key: "mcp",
788
- init: (ctx) => Effect6.gen(function* () {
789
- const cacheScope = yield* Scope.make();
790
- const pendingConnectors = /* @__PURE__ */ new Map();
791
- const connectionCache = yield* ScopedCache.make({
792
- lookup: (key) => Effect6.acquireRelease(
793
- Effect6.suspend(() => {
794
- const connector = pendingConnectors.get(key);
795
- if (!connector) {
796
- return Effect6.fail(
797
- new McpConnectionError({
798
- transport: "auto",
799
- message: `No pending connector for key: ${key}`
800
- })
801
- );
802
- }
803
- return connector;
804
- }),
805
- (connection) => Effect6.promise(() => connection.close().catch(() => {
806
- }))
807
- ),
808
- capacity: 64,
809
- timeToLive: Duration.minutes(5)
810
- }).pipe(Scope.extend(cacheScope));
811
- const invoker = makeMcpInvoker({
812
- bindingStore,
813
- secrets: ctx.secrets,
814
- scopeId: ctx.scope.id,
815
- connectionCache,
816
- pendingConnectors
817
- });
818
- yield* ctx.tools.registerInvoker("mcp", invoker);
819
- const savedSources = yield* bindingStore.listSources();
820
- for (const s of savedSources) {
821
- const isRemote = s.config.transport === "remote";
822
- addedSources.set(
823
- s.namespace,
824
- new Source({
825
- id: s.namespace,
826
- name: s.name,
827
- kind: "mcp",
828
- canEdit: isRemote
829
- })
830
- );
831
- }
832
- const resolveConnectorInput2 = (sd) => {
833
- if (sd.transport === "stdio") {
834
- return Effect6.succeed({
835
- transport: "stdio",
836
- command: sd.command,
837
- args: sd.args,
838
- env: sd.env,
839
- cwd: sd.cwd
840
- });
841
- }
842
- return Effect6.gen(function* () {
843
- const headers = {
844
- ...sd.headers
845
- };
846
- let authProvider;
847
- const auth2 = sd.auth;
848
- if (auth2.kind === "header") {
849
- const val = yield* ctx.secrets.resolve(SecretId.make(auth2.secretId), ctx.scope.id).pipe(
850
- Effect6.mapError(
851
- () => remoteConnectionError(`Failed to resolve secret "${auth2.secretId}"`)
852
- )
853
- );
854
- headers[auth2.headerName] = auth2.prefix ? `${auth2.prefix}${val}` : val;
855
- } else if (auth2.kind === "oauth2") {
856
- const accessToken = yield* ctx.secrets.resolve(SecretId.make(auth2.accessTokenSecretId), ctx.scope.id).pipe(
857
- Effect6.mapError(
858
- () => remoteConnectionError("Failed to resolve OAuth access token")
859
- )
860
- );
861
- let refreshToken;
862
- if (auth2.refreshTokenSecretId) {
863
- refreshToken = yield* ctx.secrets.resolve(SecretId.make(auth2.refreshTokenSecretId), ctx.scope.id).pipe(
864
- Effect6.option,
865
- Effect6.map((o) => o._tag === "Some" ? o.value : void 0)
866
- );
867
- }
868
- authProvider = makeOAuthProvider2(
869
- accessToken,
870
- auth2.tokenType ?? "Bearer",
871
- refreshToken
872
- );
873
- }
874
- return {
875
- transport: "remote",
876
- endpoint: sd.endpoint,
877
- remoteTransport: sd.remoteTransport,
878
- queryParams: sd.queryParams,
879
- headers: Object.keys(headers).length > 0 ? headers : void 0,
880
- authProvider
881
- };
882
- });
883
- };
884
- yield* ctx.sources.addManager({
885
- kind: "mcp",
886
- list: () => Effect6.sync(() => [...addedSources.values()]),
887
- remove: (sourceId) => Effect6.gen(function* () {
888
- yield* bindingStore.removeByNamespace(sourceId);
889
- yield* bindingStore.removeSource(sourceId);
890
- yield* ctx.tools.unregisterBySource(sourceId);
891
- addedSources.delete(sourceId);
892
- }),
893
- detect: (url) => Effect6.gen(function* () {
894
- const trimmed = url.trim();
895
- if (!trimmed) return null;
896
- const parsed = yield* Effect6.try(() => new URL(trimmed)).pipe(Effect6.option);
897
- if (parsed._tag === "None") return null;
898
- const name = parsed.value.hostname || "mcp";
899
- const namespace = deriveMcpNamespace({ endpoint: trimmed });
900
- const connector = createMcpConnector({
901
- transport: "remote",
902
- endpoint: trimmed
903
- });
904
- const connected = yield* discoverTools(connector).pipe(
905
- Effect6.map(() => true),
906
- Effect6.catchAll(() => Effect6.succeed(false))
907
- );
908
- if (connected) {
909
- return new SourceDetectionResult({
910
- kind: "mcp",
911
- confidence: "high",
912
- endpoint: trimmed,
913
- name,
914
- namespace
915
- });
916
- }
917
- const hasOAuth = yield* startMcpOAuthAuthorization({
918
- endpoint: trimmed,
919
- redirectUrl: "http://127.0.0.1/executor/discovery/oauth/probe",
920
- state: "probe"
921
- }).pipe(
922
- Effect6.map(() => true),
923
- Effect6.catchAll(() => Effect6.succeed(false))
924
- );
925
- if (hasOAuth) {
926
- return new SourceDetectionResult({
927
- kind: "mcp",
928
- confidence: "high",
929
- endpoint: trimmed,
930
- name,
931
- namespace
932
- });
933
- }
934
- return null;
935
- }),
936
- refresh: (sourceId) => Effect6.gen(function* () {
937
- const sd = yield* bindingStore.getSourceConfig(sourceId);
938
- if (!sd || !addedSources.has(sourceId)) return;
939
- const ci = yield* resolveConnectorInput2(sd).pipe(
940
- Effect6.catchAll(() => Effect6.succeed(null))
941
- );
942
- if (!ci) return;
943
- const manifest = yield* discoverTools(createMcpConnector(ci)).pipe(
944
- Effect6.catchAll(() => Effect6.succeed(null))
945
- );
946
- if (!manifest) return;
947
- const oldIds = yield* bindingStore.removeByNamespace(sourceId);
948
- if (oldIds.length > 0) yield* ctx.tools.unregister(oldIds);
949
- yield* Effect6.forEach(
950
- manifest.tools,
951
- (e) => bindingStore.put(
952
- ToolId.make(joinToolPath(sourceId, e.toolId)),
953
- sourceId,
954
- toBinding(e),
955
- sd
956
- ),
957
- { discard: true }
958
- );
959
- yield* ctx.tools.register(manifest.tools.map((e) => toRegistration(e, sourceId)));
960
- })
961
- });
962
- const probeEndpoint = (endpoint) => Effect6.gen(function* () {
963
- const trimmed = endpoint.trim();
964
- if (!trimmed) return yield* remoteConnectionError("Endpoint URL is required");
965
- const name = yield* Effect6.try(() => new URL(trimmed).hostname).pipe(
966
- Effect6.orElseSucceed(() => "mcp")
967
- );
968
- const namespace = deriveMcpNamespace({ endpoint: trimmed });
969
- const connector = createMcpConnector({
970
- transport: "remote",
971
- endpoint: trimmed
972
- });
973
- const result = yield* discoverTools(connector).pipe(
974
- Effect6.map((m) => ({ ok: true, manifest: m })),
975
- Effect6.catchAll(() => Effect6.succeed({ ok: false, manifest: null }))
976
- );
977
- if (result.ok && result.manifest) {
978
- return {
979
- connected: true,
980
- requiresOAuth: false,
981
- name: result.manifest.server?.name ?? name,
982
- namespace,
983
- toolCount: result.manifest.tools.length,
984
- serverName: result.manifest.server?.name ?? null
985
- };
986
- }
987
- const hasOAuth = yield* startMcpOAuthAuthorization({
988
- endpoint: trimmed,
989
- redirectUrl: "http://127.0.0.1/executor/discovery/oauth/probe",
990
- state: "probe"
991
- }).pipe(
992
- Effect6.map(() => true),
993
- Effect6.catchAll(() => Effect6.succeed(false))
994
- );
995
- if (hasOAuth) {
996
- return {
997
- connected: false,
998
- requiresOAuth: true,
999
- name,
1000
- namespace,
1001
- toolCount: null,
1002
- serverName: null
1003
- };
1004
- }
1005
- return yield* remoteConnectionError(
1006
- "Could not connect to MCP endpoint and no OAuth was detected"
1007
- );
1008
- });
1009
- const addSource = (config) => Effect6.gen(function* () {
1010
- const namespace = normalizeNamespace(config);
1011
- const sd = toStoredSourceData(config);
1012
- const ci = yield* resolveConnectorInput2(sd);
1013
- const connector = createMcpConnector(ci);
1014
- const manifest = yield* discoverTools(connector).pipe(
1015
- Effect6.mapError((err) => mcpDiscoveryError(`MCP discovery failed: ${err.message}`))
1016
- );
1017
- const registrations = manifest.tools.map((e) => toRegistration(e, namespace));
1018
- yield* Effect6.forEach(
1019
- manifest.tools,
1020
- (e) => bindingStore.put(
1021
- ToolId.make(joinToolPath(namespace, e.toolId)),
1022
- namespace,
1023
- toBinding(e),
1024
- sd
1025
- ),
1026
- { discard: true }
1027
- );
1028
- yield* ctx.tools.register(registrations);
1029
- const sourceName = manifest.server?.name ?? config.name ?? namespace;
1030
- yield* bindingStore.putSource({
1031
- namespace,
1032
- name: sourceName,
1033
- config: sd
1034
- });
1035
- addedSources.set(
1036
- namespace,
1037
- new Source({
1038
- id: namespace,
1039
- name: sourceName,
1040
- kind: "mcp",
1041
- canEdit: config.transport === "remote"
1042
- })
1043
- );
1044
- return { toolCount: registrations.length, namespace };
1045
- });
1046
- const removeSource = (namespace) => Effect6.gen(function* () {
1047
- const ids = yield* bindingStore.removeByNamespace(namespace);
1048
- if (ids.length > 0) yield* ctx.tools.unregister(ids);
1049
- yield* bindingStore.removeSource(namespace);
1050
- addedSources.delete(namespace);
1051
- });
1052
- const refreshSource = (namespace) => Effect6.gen(function* () {
1053
- const sd = yield* bindingStore.getSourceConfig(namespace);
1054
- if (!sd)
1055
- return yield* remoteConnectionError(`No stored config for MCP source "${namespace}"`);
1056
- const ci = yield* resolveConnectorInput2(sd);
1057
- const manifest = yield* discoverTools(createMcpConnector(ci)).pipe(
1058
- Effect6.mapError((err) => mcpDiscoveryError(`MCP refresh failed: ${err.message}`))
1059
- );
1060
- const oldIds = yield* bindingStore.removeByNamespace(namespace);
1061
- if (oldIds.length > 0) yield* ctx.tools.unregister(oldIds);
1062
- yield* Effect6.forEach(
1063
- manifest.tools,
1064
- (e) => bindingStore.put(
1065
- ToolId.make(joinToolPath(namespace, e.toolId)),
1066
- namespace,
1067
- toBinding(e),
1068
- sd
1069
- ),
1070
- { discard: true }
1071
- );
1072
- yield* ctx.tools.register(manifest.tools.map((e) => toRegistration(e, namespace)));
1073
- return { toolCount: manifest.tools.length };
1074
- });
1075
- const startOAuth = (input) => Effect6.gen(function* () {
1076
- const endpoint = input.endpoint.trim();
1077
- if (!endpoint) return yield* mcpOAuthError("MCP OAuth requires an endpoint");
1078
- let fullEndpoint = endpoint;
1079
- if (input.queryParams && Object.keys(input.queryParams).length > 0) {
1080
- const u = new URL(endpoint);
1081
- for (const [k, v] of Object.entries(input.queryParams)) u.searchParams.set(k, v);
1082
- fullEndpoint = u.toString();
1083
- }
1084
- const sessionId = `mcp_oauth_${crypto.randomUUID()}`;
1085
- const started = yield* startMcpOAuthAuthorization({
1086
- endpoint: fullEndpoint,
1087
- redirectUrl: input.redirectUrl,
1088
- state: sessionId
1089
- }).pipe(Effect6.mapError((e) => mcpOAuthError(`OAuth start failed: ${e.message}`)));
1090
- oauthSessions.set(sessionId, {
1091
- endpoint: fullEndpoint,
1092
- redirectUrl: input.redirectUrl,
1093
- codeVerifier: started.codeVerifier,
1094
- resourceMetadataUrl: started.resourceMetadataUrl,
1095
- authorizationServerUrl: started.authorizationServerUrl,
1096
- resourceMetadata: started.resourceMetadata,
1097
- authorizationServerMetadata: started.authorizationServerMetadata,
1098
- clientInformation: started.clientInformation
1099
- });
1100
- return {
1101
- sessionId,
1102
- authorizationUrl: started.authorizationUrl
1103
- };
1104
- });
1105
- const completeOAuth = (input) => Effect6.gen(function* () {
1106
- if (input.error) return yield* mcpOAuthError(`OAuth error: ${input.error}`);
1107
- if (!input.code) return yield* mcpOAuthError("Missing OAuth authorization code");
1108
- const session = oauthSessions.get(input.state);
1109
- if (!session) return yield* mcpOAuthError(`OAuth session not found: ${input.state}`);
1110
- const exchanged = yield* exchangeMcpOAuthCode({
1111
- session,
1112
- code: input.code
1113
- }).pipe(Effect6.mapError((e) => mcpOAuthError(`OAuth exchange failed: ${e.message}`)));
1114
- const accessTokenRef = yield* ctx.secrets.set({
1115
- id: SecretId.make(`mcp-oauth-access-${input.state}`),
1116
- scopeId: ctx.scope.id,
1117
- name: "MCP OAuth Access Token",
1118
- value: exchanged.tokens.access_token,
1119
- purpose: "oauth_access_token"
1120
- }).pipe(
1121
- Effect6.mapError((e) => mcpOAuthError(`Failed to store access token: ${String(e)}`))
1122
- );
1123
- let refreshTokenSecretId = null;
1124
- if (exchanged.tokens.refresh_token) {
1125
- const ref = yield* ctx.secrets.set({
1126
- id: SecretId.make(`mcp-oauth-refresh-${input.state}`),
1127
- scopeId: ctx.scope.id,
1128
- name: "MCP OAuth Refresh Token",
1129
- value: exchanged.tokens.refresh_token,
1130
- purpose: "oauth_refresh_token"
1131
- }).pipe(
1132
- Effect6.mapError(
1133
- (e) => mcpOAuthError(`Failed to store refresh token: ${String(e)}`)
1134
- )
1135
- );
1136
- refreshTokenSecretId = ref.id;
1137
- }
1138
- oauthSessions.delete(input.state);
1139
- const expiresAt = typeof exchanged.tokens.expires_in === "number" ? Date.now() + exchanged.tokens.expires_in * 1e3 : null;
1140
- return {
1141
- accessTokenSecretId: accessTokenRef.id,
1142
- refreshTokenSecretId,
1143
- tokenType: exchanged.tokens.token_type ?? "Bearer",
1144
- expiresAt,
1145
- scope: exchanged.tokens.scope ?? null
1146
- };
1147
- });
1148
- const updateSource = (namespace, input) => Effect6.gen(function* () {
1149
- const existingConfig = yield* bindingStore.getSourceConfig(namespace);
1150
- if (!existingConfig || existingConfig.transport !== "remote") return;
1151
- const remote = existingConfig;
1152
- const updatedConfig = {
1153
- ...remote,
1154
- ...input.endpoint !== void 0 ? { endpoint: input.endpoint } : {},
1155
- ...input.headers !== void 0 ? { headers: input.headers } : {},
1156
- ...input.auth !== void 0 ? { auth: input.auth } : {},
1157
- ...input.queryParams !== void 0 ? { queryParams: input.queryParams } : {}
1158
- };
1159
- const sources = yield* bindingStore.listSources();
1160
- const existingMeta = sources.find((s) => s.namespace === namespace);
1161
- yield* bindingStore.putSource({
1162
- namespace,
1163
- name: existingMeta?.name ?? namespace,
1164
- config: updatedConfig
1165
- });
1166
- const toolIds = yield* bindingStore.listByNamespace(namespace);
1167
- for (const toolId of toolIds) {
1168
- const entry = yield* bindingStore.get(toolId);
1169
- if (entry) {
1170
- yield* bindingStore.put(toolId, namespace, entry.binding, updatedConfig);
1171
- }
1172
- }
1173
- });
1174
- const getSource = (namespace) => bindingStore.getSource(namespace);
1175
- return {
1176
- extension: {
1177
- probeEndpoint,
1178
- addSource,
1179
- removeSource,
1180
- refreshSource,
1181
- startOAuth,
1182
- completeOAuth,
1183
- getSource,
1184
- updateSource
1185
- },
1186
- close: () => Effect6.gen(function* () {
1187
- yield* invoker.closeConnections();
1188
- yield* Scope.close(cacheScope, Exit.void);
1189
- for (const sourceId of addedSources.keys()) {
1190
- yield* ctx.tools.unregisterBySource(sourceId);
1191
- }
1192
- addedSources.clear();
1193
- })
1194
- };
1195
- })
1196
- });
1197
- };
1198
-
1199
- export {
1200
- makeKvBindingStore,
1201
- mcpPlugin
1202
- };
1203
- //# sourceMappingURL=chunk-NJ4CITCV.js.map