@executor-js/plugin-mcp 0.0.1-beta.5 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,6 @@
1
1
  // src/sdk/binding-store.ts
2
- import { Effect, Schema as Schema2 } from "effect";
3
- import {
4
- makeInMemoryScopedKv,
5
- scopeKv
6
- } from "@executor-js/sdk/core";
2
+ import { Effect as Effect2, Schema as Schema5 } from "effect";
3
+ import { makeInMemoryScopedKv, scopeKv } from "@executor-js/sdk";
7
4
 
8
5
  // src/sdk/types.ts
9
6
  import { Schema } from "effect";
@@ -51,13 +48,8 @@ var McpStdioSourceData = Schema.Struct({
51
48
  /** Working directory */
52
49
  cwd: Schema.optional(Schema.String)
53
50
  });
54
- var McpStoredSourceData = Schema.Union(
55
- McpRemoteSourceData,
56
- McpStdioSourceData
57
- );
58
- var McpToolBinding = class extends Schema.Class(
59
- "McpToolBinding"
60
- )({
51
+ var McpStoredSourceData = Schema.Union(McpRemoteSourceData, McpStdioSourceData);
52
+ var McpToolBinding = class extends Schema.Class("McpToolBinding")({
61
53
  toolId: Schema.String,
62
54
  toolName: Schema.String,
63
55
  description: Schema.NullOr(Schema.String),
@@ -66,207 +58,58 @@ var McpToolBinding = class extends Schema.Class(
66
58
  }) {
67
59
  };
68
60
 
69
- // src/sdk/binding-store.ts
70
- var StoredBindingEntry = Schema2.Struct({
71
- namespace: Schema2.String,
72
- binding: McpToolBinding,
73
- sourceData: Schema2.Unknown
74
- });
75
- var encodeBindingEntry = Schema2.encodeSync(
76
- Schema2.parseJson(StoredBindingEntry)
77
- );
78
- var decodeBindingEntry = Schema2.decodeUnknownSync(
79
- Schema2.parseJson(StoredBindingEntry)
80
- );
81
- var makeStore = (bindings, sources) => ({
82
- // ---- Bindings ----
83
- get: (toolId) => Effect.gen(function* () {
84
- const raw = yield* bindings.get(toolId);
85
- if (!raw) return null;
86
- const entry = decodeBindingEntry(raw);
87
- return {
88
- binding: entry.binding,
89
- sourceData: entry.sourceData
90
- };
91
- }),
92
- put: (toolId, namespace, binding, sourceData) => bindings.set(
93
- toolId,
94
- encodeBindingEntry({ namespace, binding, sourceData })
95
- ),
96
- remove: (toolId) => bindings.delete(toolId).pipe(Effect.asVoid),
97
- listByNamespace: (namespace) => Effect.gen(function* () {
98
- const entries = yield* bindings.list();
99
- const ids = [];
100
- for (const e of entries) {
101
- const entry = decodeBindingEntry(e.value);
102
- if (entry.namespace === namespace) ids.push(e.key);
103
- }
104
- return ids;
105
- }),
106
- removeByNamespace: (namespace) => Effect.gen(function* () {
107
- const entries = yield* bindings.list();
108
- const ids = [];
109
- for (const e of entries) {
110
- const entry = decodeBindingEntry(e.value);
111
- if (entry.namespace === namespace) {
112
- ids.push(e.key);
113
- yield* bindings.delete(e.key);
114
- }
115
- }
116
- return ids;
117
- }),
118
- // ---- Sources (meta + config combined) ----
119
- putSource: (source) => sources.set(source.namespace, JSON.stringify(source)),
120
- removeSource: (namespace) => sources.delete(namespace).pipe(Effect.asVoid),
121
- listSources: () => Effect.gen(function* () {
122
- const entries = yield* sources.list();
123
- return entries.map((e) => JSON.parse(e.value));
124
- }),
125
- getSourceConfig: (namespace) => Effect.gen(function* () {
126
- const raw = yield* sources.get(namespace);
127
- if (!raw) return null;
128
- const source = JSON.parse(raw);
129
- return source.config;
130
- })
131
- });
132
- var makeKvBindingStore = (kv, namespace) => makeStore(
133
- scopeKv(kv, `${namespace}.bindings`),
134
- scopeKv(kv, `${namespace}.sources`)
135
- );
136
- var makeInMemoryBindingStore = () => makeStore(
137
- makeInMemoryScopedKv(),
138
- makeInMemoryScopedKv()
139
- );
140
-
141
- // src/sdk/plugin.ts
142
- import { Effect as Effect6, Exit, ScopedCache, Duration, Scope } from "effect";
61
+ // src/sdk/oauth.ts
143
62
  import {
144
- Source,
145
- SourceDetectionResult,
146
- definePlugin,
147
- ToolId,
148
- SecretId
149
- } from "@executor-js/sdk/core";
150
-
151
- // src/sdk/connection.ts
152
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
153
- import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
154
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
155
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
156
- import { Effect as Effect2 } from "effect";
63
+ auth
64
+ } from "@modelcontextprotocol/sdk/client/auth.js";
65
+ import { Effect, Schema as Schema3 } from "effect";
157
66
 
158
67
  // src/sdk/errors.ts
159
- import { Schema as Schema3 } from "effect";
160
- var McpConnectionError = class extends Schema3.TaggedError()(
68
+ import { Schema as Schema2 } from "effect";
69
+ var McpConnectionError = class extends Schema2.TaggedError()(
161
70
  "McpConnectionError",
162
71
  {
163
- transport: Schema3.String,
164
- message: Schema3.String
72
+ transport: Schema2.String,
73
+ message: Schema2.String
165
74
  }
166
75
  ) {
167
76
  };
168
- var McpToolDiscoveryError = class extends Schema3.TaggedError()(
77
+ var McpToolDiscoveryError = class extends Schema2.TaggedError()(
169
78
  "McpToolDiscoveryError",
170
79
  {
171
- stage: Schema3.Literal("connect", "list_tools"),
172
- message: Schema3.String
80
+ stage: Schema2.Literal("connect", "list_tools"),
81
+ message: Schema2.String
173
82
  }
174
83
  ) {
175
84
  };
176
- var McpInvocationError = class extends Schema3.TaggedError()(
85
+ var McpInvocationError = class extends Schema2.TaggedError()(
177
86
  "McpInvocationError",
178
87
  {
179
- toolName: Schema3.String,
180
- message: Schema3.String
88
+ toolName: Schema2.String,
89
+ message: Schema2.String
181
90
  }
182
91
  ) {
183
92
  };
184
- var McpOAuthError = class extends Schema3.TaggedError()(
185
- "McpOAuthError",
186
- {
187
- message: Schema3.String
188
- }
189
- ) {
93
+ var McpOAuthError = class extends Schema2.TaggedError()("McpOAuthError", {
94
+ message: Schema2.String
95
+ }) {
190
96
  };
191
97
 
192
- // src/sdk/connection.ts
193
- var buildEndpointUrl = (endpoint, queryParams) => {
194
- const url = new URL(endpoint);
195
- for (const [key, value] of Object.entries(queryParams)) {
196
- url.searchParams.set(key, value);
197
- }
198
- return url;
199
- };
200
- var createClient = () => new Client(
201
- { name: "executor-mcp", version: "0.1.0" },
202
- { capabilities: { elicitation: { form: {}, url: {} } } }
203
- );
204
- var connectionFromClient = (client) => ({
205
- client,
206
- close: () => client.close()
98
+ // src/sdk/oauth.ts
99
+ var JsonObject = Schema3.Record({ key: Schema3.String, value: Schema3.Unknown });
100
+ var McpOAuthDiscoveryState = Schema3.Struct({
101
+ resourceMetadataUrl: Schema3.NullOr(Schema3.String),
102
+ authorizationServerUrl: Schema3.NullOr(Schema3.String),
103
+ resourceMetadata: Schema3.NullOr(JsonObject),
104
+ authorizationServerMetadata: Schema3.NullOr(JsonObject),
105
+ clientInformation: Schema3.NullOr(JsonObject)
207
106
  });
208
- var connectClient = (input) => Effect2.gen(function* () {
209
- const client = createClient();
210
- const transportInstance = input.createTransport();
211
- yield* Effect2.tryPromise({
212
- try: () => client.connect(transportInstance),
213
- catch: (cause) => new McpConnectionError({
214
- transport: input.transport,
215
- message: `Failed connecting via ${input.transport}: ${cause instanceof Error ? cause.message : String(cause)}`
216
- })
217
- });
218
- return connectionFromClient(client);
107
+ var McpOAuthSession = Schema3.Struct({
108
+ ...McpOAuthDiscoveryState.fields,
109
+ endpoint: Schema3.String,
110
+ redirectUrl: Schema3.String,
111
+ codeVerifier: Schema3.String
219
112
  });
220
- var createMcpConnector = (input) => {
221
- if (input.transport === "stdio") {
222
- const command = input.command.trim();
223
- if (!command) {
224
- return new McpConnectionError({
225
- transport: "stdio",
226
- message: "MCP stdio transport requires a command"
227
- });
228
- }
229
- return connectClient({
230
- transport: "stdio",
231
- createTransport: () => new StdioClientTransport({
232
- command,
233
- args: input.args ? [...input.args] : void 0,
234
- env: input.env ? { ...process.env, ...input.env } : void 0,
235
- cwd: input.cwd?.trim().length ? input.cwd.trim() : void 0
236
- })
237
- });
238
- }
239
- const headers = input.headers ?? {};
240
- const remoteTransport = input.remoteTransport ?? "auto";
241
- const requestInit = Object.keys(headers).length > 0 ? { headers } : void 0;
242
- const endpoint = buildEndpointUrl(
243
- input.endpoint,
244
- input.queryParams ?? {}
245
- );
246
- const connectStreamableHttp = connectClient({
247
- transport: "streamable-http",
248
- createTransport: () => new StreamableHTTPClientTransport(endpoint, {
249
- requestInit,
250
- authProvider: input.authProvider
251
- })
252
- });
253
- const connectSse = connectClient({
254
- transport: "sse",
255
- createTransport: () => new SSEClientTransport(endpoint, {
256
- requestInit,
257
- authProvider: input.authProvider
258
- })
259
- });
260
- if (remoteTransport === "streamable-http") return connectStreamableHttp;
261
- if (remoteTransport === "sse") return connectSse;
262
- return connectStreamableHttp.pipe(Effect2.catchAll(() => connectSse));
263
- };
264
-
265
- // src/sdk/oauth.ts
266
- import {
267
- auth
268
- } from "@modelcontextprotocol/sdk/client/auth.js";
269
- import { Effect as Effect3 } from "effect";
270
113
  var toJsonObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
271
114
  var CLIENT_METADATA = {
272
115
  grant_types: ["authorization_code", "refresh_token"],
@@ -281,13 +124,13 @@ var extractDiscoveryState = (discoveryState, clientInformation) => ({
281
124
  authorizationServerMetadata: toJsonObject(discoveryState?.authorizationServerMetadata),
282
125
  clientInformation: toJsonObject(clientInformation)
283
126
  });
284
- var callAuth = (provider, opts) => Effect3.tryPromise({
127
+ var callAuth = (provider, opts) => Effect.tryPromise({
285
128
  try: () => auth(provider, opts),
286
129
  catch: (cause) => new McpOAuthError({
287
130
  message: cause instanceof Error ? cause.message : String(cause)
288
131
  })
289
132
  });
290
- var startMcpOAuthAuthorization = (input) => Effect3.gen(function* () {
133
+ var startMcpOAuthAuthorization = (input) => Effect.gen(function* () {
291
134
  let authorizationUrl;
292
135
  let codeVerifier;
293
136
  let discoveryState;
@@ -333,7 +176,7 @@ var startMcpOAuthAuthorization = (input) => Effect3.gen(function* () {
333
176
  ...extractDiscoveryState(discoveryState, clientInformation)
334
177
  };
335
178
  });
336
- var exchangeMcpOAuthCode = (input) => Effect3.gen(function* () {
179
+ var exchangeMcpOAuthCode = (input) => Effect.gen(function* () {
337
180
  const { session } = input;
338
181
  let tokens;
339
182
  let discoveryState = {
@@ -383,27 +226,215 @@ var exchangeMcpOAuthCode = (input) => Effect3.gen(function* () {
383
226
  };
384
227
  });
385
228
 
229
+ // src/sdk/stored-source.ts
230
+ import { Schema as Schema4 } from "effect";
231
+ var McpStoredSourceSchema = class extends Schema4.Class("McpStoredSource")({
232
+ namespace: Schema4.String,
233
+ name: Schema4.String,
234
+ config: McpStoredSourceData
235
+ }) {
236
+ };
237
+
238
+ // src/sdk/binding-store.ts
239
+ var MCP_OAUTH_SESSION_TTL_MS = 15 * 60 * 1e3;
240
+ var StoredOAuthSession = Schema5.Struct({
241
+ session: McpOAuthSession,
242
+ expiresAt: Schema5.Number
243
+ });
244
+ var encodeOAuthSession = Schema5.encodeSync(Schema5.parseJson(StoredOAuthSession));
245
+ var decodeOAuthSession = Schema5.decodeUnknownSync(Schema5.parseJson(StoredOAuthSession));
246
+ var encodeSource = Schema5.encodeSync(Schema5.parseJson(McpStoredSourceSchema));
247
+ var decodeSource = Schema5.decodeUnknownSync(Schema5.parseJson(McpStoredSourceSchema));
248
+ var StoredBindingEntry = Schema5.Struct({
249
+ namespace: Schema5.String,
250
+ binding: McpToolBinding
251
+ });
252
+ var encodeBindingEntry = Schema5.encodeSync(Schema5.parseJson(StoredBindingEntry));
253
+ var decodeBindingEntry = Schema5.decodeUnknownSync(Schema5.parseJson(StoredBindingEntry));
254
+ var makeStore = (bindings, sources, oauthSessions) => ({
255
+ // ---- Bindings ----
256
+ get: (toolId) => Effect2.gen(function* () {
257
+ const raw = yield* bindings.get(toolId);
258
+ if (!raw) return null;
259
+ const entry = decodeBindingEntry(raw);
260
+ return {
261
+ binding: entry.binding,
262
+ namespace: entry.namespace
263
+ };
264
+ }),
265
+ put: (toolId, namespace, binding) => bindings.set([{ key: toolId, value: encodeBindingEntry({ namespace, binding }) }]),
266
+ remove: (toolId) => bindings.delete([toolId]).pipe(Effect2.asVoid),
267
+ listByNamespace: (namespace) => Effect2.gen(function* () {
268
+ const entries = yield* bindings.list();
269
+ const ids = [];
270
+ for (const e of entries) {
271
+ const entry = decodeBindingEntry(e.value);
272
+ if (entry.namespace === namespace) ids.push(e.key);
273
+ }
274
+ return ids;
275
+ }),
276
+ removeByNamespace: (namespace) => Effect2.gen(function* () {
277
+ const entries = yield* bindings.list();
278
+ const ids = [];
279
+ for (const e of entries) {
280
+ const entry = decodeBindingEntry(e.value);
281
+ if (entry.namespace === namespace) ids.push(e.key);
282
+ }
283
+ if (ids.length > 0) yield* bindings.delete(ids);
284
+ return ids;
285
+ }),
286
+ // ---- Sources (meta + config combined) ----
287
+ putSource: (source) => sources.set([{ key: source.namespace, value: encodeSource(source) }]),
288
+ removeSource: (namespace) => sources.delete([namespace]).pipe(Effect2.asVoid),
289
+ listSources: () => Effect2.gen(function* () {
290
+ const entries = yield* sources.list();
291
+ return entries.map((e) => decodeSource(e.value));
292
+ }),
293
+ getSource: (namespace) => Effect2.gen(function* () {
294
+ const raw = yield* sources.get(namespace);
295
+ if (!raw) return null;
296
+ return decodeSource(raw);
297
+ }),
298
+ getSourceConfig: (namespace) => Effect2.gen(function* () {
299
+ const raw = yield* sources.get(namespace);
300
+ if (!raw) return null;
301
+ return decodeSource(raw).config;
302
+ }),
303
+ // ---- Pending OAuth sessions (short-lived, between startOAuth and completeOAuth) ----
304
+ putOAuthSession: (sessionId, session) => oauthSessions.set([
305
+ {
306
+ key: sessionId,
307
+ value: encodeOAuthSession({
308
+ session,
309
+ expiresAt: Date.now() + MCP_OAUTH_SESSION_TTL_MS
310
+ })
311
+ }
312
+ ]),
313
+ getOAuthSession: (sessionId) => Effect2.gen(function* () {
314
+ const raw = yield* oauthSessions.get(sessionId);
315
+ if (!raw) return null;
316
+ const entry = decodeOAuthSession(raw);
317
+ if (entry.expiresAt < Date.now()) {
318
+ yield* oauthSessions.delete([sessionId]);
319
+ return null;
320
+ }
321
+ return entry.session;
322
+ }),
323
+ deleteOAuthSession: (sessionId) => oauthSessions.delete([sessionId]).pipe(Effect2.asVoid)
324
+ });
325
+ var makeKvBindingStore = (kv, namespace) => makeStore(
326
+ scopeKv(kv, `${namespace}.bindings`),
327
+ scopeKv(kv, `${namespace}.sources`),
328
+ scopeKv(kv, `${namespace}.oauth-sessions`)
329
+ );
330
+ var makeInMemoryBindingStore = () => makeStore(makeInMemoryScopedKv(), makeInMemoryScopedKv(), makeInMemoryScopedKv());
331
+
332
+ // src/sdk/plugin.ts
333
+ import { Effect as Effect6, Exit, ScopedCache, Duration, Scope } from "effect";
334
+ import {
335
+ Source,
336
+ SourceDetectionResult,
337
+ definePlugin,
338
+ ToolId,
339
+ SecretId
340
+ } from "@executor-js/sdk";
341
+
342
+ // src/sdk/connection.ts
343
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
344
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
345
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
346
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
347
+ import { Effect as Effect3 } from "effect";
348
+ var buildEndpointUrl = (endpoint, queryParams) => {
349
+ const url = new URL(endpoint);
350
+ for (const [key, value] of Object.entries(queryParams)) {
351
+ url.searchParams.set(key, value);
352
+ }
353
+ return url;
354
+ };
355
+ var createClient = () => new Client(
356
+ { name: "executor-mcp", version: "0.1.0" },
357
+ { capabilities: { elicitation: { form: {}, url: {} } } }
358
+ );
359
+ var connectionFromClient = (client) => ({
360
+ client,
361
+ close: () => client.close()
362
+ });
363
+ var connectClient = (input) => Effect3.gen(function* () {
364
+ const client = createClient();
365
+ const transportInstance = input.createTransport();
366
+ yield* Effect3.tryPromise({
367
+ try: () => client.connect(transportInstance),
368
+ catch: (cause) => new McpConnectionError({
369
+ transport: input.transport,
370
+ message: `Failed connecting via ${input.transport}: ${cause instanceof Error ? cause.message : String(cause)}`
371
+ })
372
+ });
373
+ return connectionFromClient(client);
374
+ });
375
+ var createMcpConnector = (input) => {
376
+ if (input.transport === "stdio") {
377
+ const command = input.command.trim();
378
+ if (!command) {
379
+ return new McpConnectionError({
380
+ transport: "stdio",
381
+ message: "MCP stdio transport requires a command"
382
+ });
383
+ }
384
+ return connectClient({
385
+ transport: "stdio",
386
+ createTransport: () => new StdioClientTransport({
387
+ command,
388
+ args: input.args ? [...input.args] : void 0,
389
+ env: input.env ? { ...process.env, ...input.env } : void 0,
390
+ cwd: input.cwd?.trim().length ? input.cwd.trim() : void 0
391
+ })
392
+ });
393
+ }
394
+ const headers = input.headers ?? {};
395
+ const remoteTransport = input.remoteTransport ?? "auto";
396
+ const requestInit = Object.keys(headers).length > 0 ? { headers } : void 0;
397
+ const endpoint = buildEndpointUrl(input.endpoint, input.queryParams ?? {});
398
+ const connectStreamableHttp = connectClient({
399
+ transport: "streamable-http",
400
+ createTransport: () => new StreamableHTTPClientTransport(endpoint, {
401
+ requestInit,
402
+ authProvider: input.authProvider
403
+ })
404
+ });
405
+ const connectSse = connectClient({
406
+ transport: "sse",
407
+ createTransport: () => new SSEClientTransport(endpoint, {
408
+ requestInit,
409
+ authProvider: input.authProvider
410
+ })
411
+ });
412
+ if (remoteTransport === "streamable-http") return connectStreamableHttp;
413
+ if (remoteTransport === "sse") return connectSse;
414
+ return connectStreamableHttp.pipe(Effect3.catchAll(() => connectSse));
415
+ };
416
+
386
417
  // src/sdk/discover.ts
387
418
  import { Effect as Effect4 } from "effect";
388
419
 
389
420
  // src/sdk/manifest.ts
390
- import { Schema as Schema4 } from "effect";
391
- var ListedTool = Schema4.Struct({
392
- name: Schema4.String,
393
- description: Schema4.optional(Schema4.NullOr(Schema4.String)),
394
- inputSchema: Schema4.optional(Schema4.Unknown),
395
- parameters: Schema4.optional(Schema4.Unknown),
396
- outputSchema: Schema4.optional(Schema4.Unknown)
421
+ import { Schema as Schema6 } from "effect";
422
+ var ListedTool = Schema6.Struct({
423
+ name: Schema6.String,
424
+ description: Schema6.optional(Schema6.NullOr(Schema6.String)),
425
+ inputSchema: Schema6.optional(Schema6.Unknown),
426
+ parameters: Schema6.optional(Schema6.Unknown),
427
+ outputSchema: Schema6.optional(Schema6.Unknown)
397
428
  });
398
- var ListToolsResult = Schema4.Struct({
399
- tools: Schema4.Array(ListedTool)
429
+ var ListToolsResult = Schema6.Struct({
430
+ tools: Schema6.Array(ListedTool)
400
431
  });
401
- var ServerInfo = Schema4.Struct({
402
- name: Schema4.optional(Schema4.String),
403
- version: Schema4.optional(Schema4.String)
432
+ var ServerInfo = Schema6.Struct({
433
+ name: Schema6.optional(Schema6.String),
434
+ version: Schema6.optional(Schema6.String)
404
435
  });
405
- var decodeListToolsResult = Schema4.decodeUnknownOption(ListToolsResult);
406
- var decodeServerInfo = Schema4.decodeUnknownOption(ServerInfo);
436
+ var decodeListToolsResult = Schema6.decodeUnknownOption(ListToolsResult);
437
+ var decodeServerInfo = Schema6.decodeUnknownOption(ServerInfo);
407
438
  var sanitize = (value) => {
408
439
  const s = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
409
440
  return s || "tool";
@@ -481,7 +512,7 @@ var discoverTools = (connector) => Effect4.gen(function* () {
481
512
  });
482
513
 
483
514
  // src/sdk/invoke.ts
484
- import { Effect as Effect5, Schema as Schema5 } from "effect";
515
+ import { Effect as Effect5, Schema as Schema7 } from "effect";
485
516
  import { ElicitRequestSchema } from "@modelcontextprotocol/sdk/types.js";
486
517
  import {
487
518
  ToolInvocationResult,
@@ -490,7 +521,7 @@ import {
490
521
  ElicitationResponse,
491
522
  FormElicitation,
492
523
  UrlElicitation
493
- } from "@executor-js/sdk/core";
524
+ } from "@executor-js/sdk";
494
525
  var asRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
495
526
  var makeOAuthProvider = (accessToken, tokenType, refreshToken) => ({
496
527
  get redirectUrl() {
@@ -527,21 +558,21 @@ var makeOAuthProvider = (accessToken, tokenType, refreshToken) => ({
527
558
  },
528
559
  discoveryState: () => void 0
529
560
  });
530
- var McpElicitParams = Schema5.Union(
531
- Schema5.Struct({
532
- mode: Schema5.Literal("url"),
533
- message: Schema5.String,
534
- url: Schema5.String,
535
- elicitationId: Schema5.optional(Schema5.String),
536
- id: Schema5.optional(Schema5.String)
561
+ var McpElicitParams = Schema7.Union(
562
+ Schema7.Struct({
563
+ mode: Schema7.Literal("url"),
564
+ message: Schema7.String,
565
+ url: Schema7.String,
566
+ elicitationId: Schema7.optional(Schema7.String),
567
+ id: Schema7.optional(Schema7.String)
537
568
  }),
538
- Schema5.Struct({
539
- mode: Schema5.optional(Schema5.Literal("form")),
540
- message: Schema5.String,
541
- requestedSchema: Schema5.Record({ key: Schema5.String, value: Schema5.Unknown })
569
+ Schema7.Struct({
570
+ mode: Schema7.optional(Schema7.Literal("form")),
571
+ message: Schema7.String,
572
+ requestedSchema: Schema7.Record({ key: Schema7.String, value: Schema7.Unknown })
542
573
  })
543
574
  );
544
- var decodeElicitParams = Schema5.decodeUnknownSync(McpElicitParams);
575
+ var decodeElicitParams = Schema7.decodeUnknownSync(McpElicitParams);
545
576
  var toElicitationRequest = (params) => params.mode === "url" ? new UrlElicitation({
546
577
  message: params.message,
547
578
  url: params.url,
@@ -551,19 +582,16 @@ var toElicitationRequest = (params) => params.mode === "url" ? new UrlElicitatio
551
582
  requestedSchema: params.requestedSchema
552
583
  });
553
584
  var installElicitationHandler = (client, toolId, args, handler) => {
554
- client.setRequestHandler(
555
- ElicitRequestSchema,
556
- async (request) => {
557
- const params = decodeElicitParams(request.params);
558
- const response = await Effect5.runPromise(
559
- handler({ toolId, args, request: toElicitationRequest(params) })
560
- );
561
- return {
562
- action: response.action,
563
- ...response.action === "accept" && response.content ? { content: response.content } : {}
564
- };
565
- }
566
- );
585
+ client.setRequestHandler(ElicitRequestSchema, async (request) => {
586
+ const params = decodeElicitParams(request.params);
587
+ const response = await Effect5.runPromise(
588
+ handler({ toolId, args, request: toElicitationRequest(params) })
589
+ );
590
+ return {
591
+ action: response.action,
592
+ ...response.action === "accept" && response.content ? { content: response.content } : {}
593
+ };
594
+ });
567
595
  };
568
596
  var resolveConnectorInput = (sourceData, secrets, scopeId) => {
569
597
  if (sourceData.transport === "stdio") {
@@ -576,7 +604,7 @@ var resolveConnectorInput = (sourceData, secrets, scopeId) => {
576
604
  });
577
605
  }
578
606
  return Effect5.gen(function* () {
579
- const headers = { ...sourceData.headers ?? {} };
607
+ const headers = { ...sourceData.headers };
580
608
  let authProvider;
581
609
  const auth2 = sourceData.auth;
582
610
  if (auth2.kind === "header") {
@@ -607,11 +635,7 @@ var resolveConnectorInput = (sourceData, secrets, scopeId) => {
607
635
  Effect5.map((o) => o._tag === "Some" ? o.value : void 0)
608
636
  );
609
637
  }
610
- authProvider = makeOAuthProvider(
611
- accessToken,
612
- auth2.tokenType ?? "Bearer",
613
- refreshToken
614
- );
638
+ authProvider = makeOAuthProvider(accessToken, auth2.tokenType ?? "Bearer", refreshToken);
615
639
  }
616
640
  return {
617
641
  transport: "remote",
@@ -639,9 +663,7 @@ var useMcpConnection = (connection, toolId, toolName, args, handler) => Effect5.
639
663
  var makeMcpInvoker = (opts) => {
640
664
  const { connectionCache, pendingConnectors } = opts;
641
665
  return {
642
- resolveAnnotations: () => Effect5.succeed(
643
- new ToolAnnotations({ requiresApproval: false })
644
- ),
666
+ resolveAnnotations: () => Effect5.succeed(new ToolAnnotations({ requiresApproval: false })),
645
667
  invoke: (toolId, args, options) => Effect5.gen(function* () {
646
668
  const entry = yield* opts.bindingStore.get(toolId);
647
669
  if (!entry) {
@@ -651,13 +673,17 @@ var makeMcpInvoker = (opts) => {
651
673
  cause: void 0
652
674
  });
653
675
  }
654
- const { binding, sourceData } = entry;
676
+ const sourceData = yield* opts.bindingStore.getSourceConfig(entry.namespace);
677
+ if (!sourceData) {
678
+ return yield* new ToolInvocationError({
679
+ toolId,
680
+ message: `No MCP source config found for namespace "${entry.namespace}"`,
681
+ cause: void 0
682
+ });
683
+ }
684
+ const { binding } = entry;
655
685
  const cacheKey = connectionCacheKey(sourceData);
656
- const connector = resolveConnectorInput(
657
- sourceData,
658
- opts.secrets,
659
- opts.scopeId
660
- ).pipe(
686
+ const connector = resolveConnectorInput(sourceData, opts.secrets, opts.scopeId).pipe(
661
687
  Effect5.flatMap((ci) => createMcpConnector(ci)),
662
688
  Effect5.mapError(
663
689
  (err) => new McpConnectionError({
@@ -686,7 +712,7 @@ var makeMcpInvoker = (opts) => {
686
712
  ).pipe(
687
713
  // On failure, invalidate the cached connection and retry once
688
714
  Effect5.catchAll(
689
- (err) => Effect5.gen(function* () {
715
+ () => Effect5.gen(function* () {
690
716
  yield* connectionCache.invalidate(cacheKey);
691
717
  pendingConnectors.set(cacheKey, connector);
692
718
  const freshConnection = yield* connectionCache.get(cacheKey).pipe(
@@ -733,9 +759,7 @@ var makeMcpInvoker = (opts) => {
733
759
  ),
734
760
  closeConnections: () => Effect5.sync(() => {
735
761
  pendingConnectors.clear();
736
- }).pipe(
737
- Effect5.flatMap(() => connectionCache.invalidateAll)
738
- )
762
+ }).pipe(Effect5.flatMap(() => connectionCache.invalidateAll))
739
763
  };
740
764
  };
741
765
 
@@ -821,7 +845,6 @@ var mcpDiscoveryError = (message) => new McpToolDiscoveryError({ stage: "list_to
821
845
  var mcpPlugin = (options) => {
822
846
  const bindingStore = options?.bindingStore ?? makeInMemoryBindingStore();
823
847
  const addedSources = /* @__PURE__ */ new Map();
824
- const oauthSessions = /* @__PURE__ */ new Map();
825
848
  return definePlugin({
826
849
  key: "mcp",
827
850
  init: (ctx) => Effect6.gen(function* () {
@@ -857,9 +880,16 @@ var mcpPlugin = (options) => {
857
880
  yield* ctx.tools.registerInvoker("mcp", invoker);
858
881
  const savedSources = yield* bindingStore.listSources();
859
882
  for (const s of savedSources) {
883
+ const isRemote = s.config.transport === "remote";
860
884
  addedSources.set(
861
885
  s.namespace,
862
- new Source({ id: s.namespace, name: s.name, kind: "mcp" })
886
+ new Source({
887
+ id: s.namespace,
888
+ name: s.name,
889
+ kind: "mcp",
890
+ url: s.config.transport === "remote" ? s.config.endpoint : void 0,
891
+ canEdit: isRemote
892
+ })
863
893
  );
864
894
  }
865
895
  const resolveConnectorInput2 = (sd) => {
@@ -874,30 +904,26 @@ var mcpPlugin = (options) => {
874
904
  }
875
905
  return Effect6.gen(function* () {
876
906
  const headers = {
877
- ...sd.headers ?? {}
907
+ ...sd.headers
878
908
  };
879
909
  let authProvider;
880
910
  const auth2 = sd.auth;
881
911
  if (auth2.kind === "header") {
882
- const val = yield* ctx.secrets.resolve(auth2.secretId, ctx.scope.id).pipe(
912
+ const val = yield* ctx.secrets.resolve(SecretId.make(auth2.secretId), ctx.scope.id).pipe(
883
913
  Effect6.mapError(
884
- () => remoteConnectionError(
885
- `Failed to resolve secret "${auth2.secretId}"`
886
- )
914
+ () => remoteConnectionError(`Failed to resolve secret "${auth2.secretId}"`)
887
915
  )
888
916
  );
889
917
  headers[auth2.headerName] = auth2.prefix ? `${auth2.prefix}${val}` : val;
890
918
  } else if (auth2.kind === "oauth2") {
891
- const accessToken = yield* ctx.secrets.resolve(auth2.accessTokenSecretId, ctx.scope.id).pipe(
919
+ const accessToken = yield* ctx.secrets.resolve(SecretId.make(auth2.accessTokenSecretId), ctx.scope.id).pipe(
892
920
  Effect6.mapError(
893
- () => remoteConnectionError(
894
- "Failed to resolve OAuth access token"
895
- )
921
+ () => remoteConnectionError("Failed to resolve OAuth access token")
896
922
  )
897
923
  );
898
924
  let refreshToken;
899
925
  if (auth2.refreshTokenSecretId) {
900
- refreshToken = yield* ctx.secrets.resolve(auth2.refreshTokenSecretId, ctx.scope.id).pipe(
926
+ refreshToken = yield* ctx.secrets.resolve(SecretId.make(auth2.refreshTokenSecretId), ctx.scope.id).pipe(
901
927
  Effect6.option,
902
928
  Effect6.map((o) => o._tag === "Some" ? o.value : void 0)
903
929
  );
@@ -930,9 +956,7 @@ var mcpPlugin = (options) => {
930
956
  detect: (url) => Effect6.gen(function* () {
931
957
  const trimmed = url.trim();
932
958
  if (!trimmed) return null;
933
- const parsed = yield* Effect6.try(() => new URL(trimmed)).pipe(
934
- Effect6.option
935
- );
959
+ const parsed = yield* Effect6.try(() => new URL(trimmed)).pipe(Effect6.option);
936
960
  if (parsed._tag === "None") return null;
937
961
  const name = parsed.value.hostname || "mcp";
938
962
  const namespace = deriveMcpNamespace({ endpoint: trimmed });
@@ -979,9 +1003,9 @@ var mcpPlugin = (options) => {
979
1003
  Effect6.catchAll(() => Effect6.succeed(null))
980
1004
  );
981
1005
  if (!ci) return;
982
- const manifest = yield* discoverTools(
983
- createMcpConnector(ci)
984
- ).pipe(Effect6.catchAll(() => Effect6.succeed(null)));
1006
+ const manifest = yield* discoverTools(createMcpConnector(ci)).pipe(
1007
+ Effect6.catchAll(() => Effect6.succeed(null))
1008
+ );
985
1009
  if (!manifest) return;
986
1010
  const oldIds = yield* bindingStore.removeByNamespace(sourceId);
987
1011
  if (oldIds.length > 0) yield* ctx.tools.unregister(oldIds);
@@ -990,20 +1014,16 @@ var mcpPlugin = (options) => {
990
1014
  (e) => bindingStore.put(
991
1015
  ToolId.make(joinToolPath(sourceId, e.toolId)),
992
1016
  sourceId,
993
- toBinding(e),
994
- sd
1017
+ toBinding(e)
995
1018
  ),
996
1019
  { discard: true }
997
1020
  );
998
- yield* ctx.tools.register(
999
- manifest.tools.map((e) => toRegistration(e, sourceId))
1000
- );
1021
+ yield* ctx.tools.register(manifest.tools.map((e) => toRegistration(e, sourceId)));
1001
1022
  })
1002
1023
  });
1003
1024
  const probeEndpoint = (endpoint) => Effect6.gen(function* () {
1004
1025
  const trimmed = endpoint.trim();
1005
- if (!trimmed)
1006
- return yield* remoteConnectionError("Endpoint URL is required");
1026
+ if (!trimmed) return yield* remoteConnectionError("Endpoint URL is required");
1007
1027
  const name = yield* Effect6.try(() => new URL(trimmed).hostname).pipe(
1008
1028
  Effect6.orElseSucceed(() => "mcp")
1009
1029
  );
@@ -1014,9 +1034,7 @@ var mcpPlugin = (options) => {
1014
1034
  });
1015
1035
  const result = yield* discoverTools(connector).pipe(
1016
1036
  Effect6.map((m) => ({ ok: true, manifest: m })),
1017
- Effect6.catchAll(
1018
- () => Effect6.succeed({ ok: false, manifest: null })
1019
- )
1037
+ Effect6.catchAll(() => Effect6.succeed({ ok: false, manifest: null }))
1020
1038
  );
1021
1039
  if (result.ok && result.manifest) {
1022
1040
  return {
@@ -1056,20 +1074,15 @@ var mcpPlugin = (options) => {
1056
1074
  const ci = yield* resolveConnectorInput2(sd);
1057
1075
  const connector = createMcpConnector(ci);
1058
1076
  const manifest = yield* discoverTools(connector).pipe(
1059
- Effect6.mapError(
1060
- (err) => mcpDiscoveryError(`MCP discovery failed: ${err.message}`)
1061
- )
1062
- );
1063
- const registrations = manifest.tools.map(
1064
- (e) => toRegistration(e, namespace)
1077
+ Effect6.mapError((err) => mcpDiscoveryError(`MCP discovery failed: ${err.message}`))
1065
1078
  );
1079
+ const registrations = manifest.tools.map((e) => toRegistration(e, namespace));
1066
1080
  yield* Effect6.forEach(
1067
1081
  manifest.tools,
1068
1082
  (e) => bindingStore.put(
1069
1083
  ToolId.make(joinToolPath(namespace, e.toolId)),
1070
1084
  namespace,
1071
- toBinding(e),
1072
- sd
1085
+ toBinding(e)
1073
1086
  ),
1074
1087
  { discard: true }
1075
1088
  );
@@ -1085,7 +1098,9 @@ var mcpPlugin = (options) => {
1085
1098
  new Source({
1086
1099
  id: namespace,
1087
1100
  name: sourceName,
1088
- kind: "mcp"
1101
+ kind: "mcp",
1102
+ url: sd.transport === "remote" ? sd.endpoint : void 0,
1103
+ canEdit: config.transport === "remote"
1089
1104
  })
1090
1105
  );
1091
1106
  return { toolCount: registrations.length, namespace };
@@ -1099,16 +1114,10 @@ var mcpPlugin = (options) => {
1099
1114
  const refreshSource = (namespace) => Effect6.gen(function* () {
1100
1115
  const sd = yield* bindingStore.getSourceConfig(namespace);
1101
1116
  if (!sd)
1102
- return yield* remoteConnectionError(
1103
- `No stored config for MCP source "${namespace}"`
1104
- );
1117
+ return yield* remoteConnectionError(`No stored config for MCP source "${namespace}"`);
1105
1118
  const ci = yield* resolveConnectorInput2(sd);
1106
- const manifest = yield* discoverTools(
1107
- createMcpConnector(ci)
1108
- ).pipe(
1109
- Effect6.mapError(
1110
- (err) => mcpDiscoveryError(`MCP refresh failed: ${err.message}`)
1111
- )
1119
+ const manifest = yield* discoverTools(createMcpConnector(ci)).pipe(
1120
+ Effect6.mapError((err) => mcpDiscoveryError(`MCP refresh failed: ${err.message}`))
1112
1121
  );
1113
1122
  const oldIds = yield* bindingStore.removeByNamespace(namespace);
1114
1123
  if (oldIds.length > 0) yield* ctx.tools.unregister(oldIds);
@@ -1117,25 +1126,20 @@ var mcpPlugin = (options) => {
1117
1126
  (e) => bindingStore.put(
1118
1127
  ToolId.make(joinToolPath(namespace, e.toolId)),
1119
1128
  namespace,
1120
- toBinding(e),
1121
- sd
1129
+ toBinding(e)
1122
1130
  ),
1123
1131
  { discard: true }
1124
1132
  );
1125
- yield* ctx.tools.register(
1126
- manifest.tools.map((e) => toRegistration(e, namespace))
1127
- );
1133
+ yield* ctx.tools.register(manifest.tools.map((e) => toRegistration(e, namespace)));
1128
1134
  return { toolCount: manifest.tools.length };
1129
1135
  });
1130
1136
  const startOAuth = (input) => Effect6.gen(function* () {
1131
1137
  const endpoint = input.endpoint.trim();
1132
- if (!endpoint)
1133
- return yield* mcpOAuthError("MCP OAuth requires an endpoint");
1138
+ if (!endpoint) return yield* mcpOAuthError("MCP OAuth requires an endpoint");
1134
1139
  let fullEndpoint = endpoint;
1135
1140
  if (input.queryParams && Object.keys(input.queryParams).length > 0) {
1136
1141
  const u = new URL(endpoint);
1137
- for (const [k, v] of Object.entries(input.queryParams))
1138
- u.searchParams.set(k, v);
1142
+ for (const [k, v] of Object.entries(input.queryParams)) u.searchParams.set(k, v);
1139
1143
  fullEndpoint = u.toString();
1140
1144
  }
1141
1145
  const sessionId = `mcp_oauth_${crypto.randomUUID()}`;
@@ -1143,12 +1147,8 @@ var mcpPlugin = (options) => {
1143
1147
  endpoint: fullEndpoint,
1144
1148
  redirectUrl: input.redirectUrl,
1145
1149
  state: sessionId
1146
- }).pipe(
1147
- Effect6.mapError(
1148
- (e) => mcpOAuthError(`OAuth start failed: ${e.message}`)
1149
- )
1150
- );
1151
- oauthSessions.set(sessionId, {
1150
+ }).pipe(Effect6.mapError((e) => mcpOAuthError(`OAuth start failed: ${e.message}`)));
1151
+ yield* bindingStore.putOAuthSession(sessionId, {
1152
1152
  endpoint: fullEndpoint,
1153
1153
  redirectUrl: input.redirectUrl,
1154
1154
  codeVerifier: started.codeVerifier,
@@ -1164,56 +1164,39 @@ var mcpPlugin = (options) => {
1164
1164
  };
1165
1165
  });
1166
1166
  const completeOAuth = (input) => Effect6.gen(function* () {
1167
- if (input.error)
1168
- return yield* mcpOAuthError(`OAuth error: ${input.error}`);
1169
- if (!input.code)
1170
- return yield* mcpOAuthError("Missing OAuth authorization code");
1171
- const session = oauthSessions.get(input.state);
1172
- if (!session)
1173
- return yield* mcpOAuthError(`OAuth session not found: ${input.state}`);
1167
+ if (input.error) return yield* mcpOAuthError(`OAuth error: ${input.error}`);
1168
+ if (!input.code) return yield* mcpOAuthError("Missing OAuth authorization code");
1169
+ const session = yield* bindingStore.getOAuthSession(input.state);
1170
+ if (!session) return yield* mcpOAuthError(`OAuth session not found: ${input.state}`);
1174
1171
  const exchanged = yield* exchangeMcpOAuthCode({
1175
1172
  session,
1176
1173
  code: input.code
1177
- }).pipe(
1178
- Effect6.mapError(
1179
- (e) => mcpOAuthError(`OAuth exchange failed: ${e.message}`)
1180
- )
1181
- );
1174
+ }).pipe(Effect6.mapError((e) => mcpOAuthError(`OAuth exchange failed: ${e.message}`)));
1182
1175
  const accessTokenRef = yield* ctx.secrets.set({
1183
- id: SecretId.make(
1184
- `mcp-oauth-access-${input.state}`
1185
- ),
1176
+ id: SecretId.make(`mcp-oauth-access-${input.state}`),
1186
1177
  scopeId: ctx.scope.id,
1187
1178
  name: "MCP OAuth Access Token",
1188
1179
  value: exchanged.tokens.access_token,
1189
1180
  purpose: "oauth_access_token"
1190
1181
  }).pipe(
1191
- Effect6.mapError(
1192
- (e) => mcpOAuthError(
1193
- `Failed to store access token: ${String(e)}`
1194
- )
1195
- )
1182
+ Effect6.mapError((e) => mcpOAuthError(`Failed to store access token: ${String(e)}`))
1196
1183
  );
1197
1184
  let refreshTokenSecretId = null;
1198
1185
  if (exchanged.tokens.refresh_token) {
1199
1186
  const ref = yield* ctx.secrets.set({
1200
- id: SecretId.make(
1201
- `mcp-oauth-refresh-${input.state}`
1202
- ),
1187
+ id: SecretId.make(`mcp-oauth-refresh-${input.state}`),
1203
1188
  scopeId: ctx.scope.id,
1204
1189
  name: "MCP OAuth Refresh Token",
1205
1190
  value: exchanged.tokens.refresh_token,
1206
1191
  purpose: "oauth_refresh_token"
1207
1192
  }).pipe(
1208
1193
  Effect6.mapError(
1209
- (e) => mcpOAuthError(
1210
- `Failed to store refresh token: ${String(e)}`
1211
- )
1194
+ (e) => mcpOAuthError(`Failed to store refresh token: ${String(e)}`)
1212
1195
  )
1213
1196
  );
1214
1197
  refreshTokenSecretId = ref.id;
1215
1198
  }
1216
- oauthSessions.delete(input.state);
1199
+ yield* bindingStore.deleteOAuthSession(input.state);
1217
1200
  const expiresAt = typeof exchanged.tokens.expires_in === "number" ? Date.now() + exchanged.tokens.expires_in * 1e3 : null;
1218
1201
  return {
1219
1202
  accessTokenSecretId: accessTokenRef.id,
@@ -1223,6 +1206,24 @@ var mcpPlugin = (options) => {
1223
1206
  scope: exchanged.tokens.scope ?? null
1224
1207
  };
1225
1208
  });
1209
+ const updateSource = (namespace, input) => Effect6.gen(function* () {
1210
+ const existing = yield* bindingStore.getSource(namespace);
1211
+ if (!existing || existing.config.transport !== "remote") return;
1212
+ const remote = existing.config;
1213
+ const updatedConfig = {
1214
+ ...remote,
1215
+ ...input.endpoint !== void 0 ? { endpoint: input.endpoint } : {},
1216
+ ...input.headers !== void 0 ? { headers: input.headers } : {},
1217
+ ...input.auth !== void 0 ? { auth: input.auth } : {},
1218
+ ...input.queryParams !== void 0 ? { queryParams: input.queryParams } : {}
1219
+ };
1220
+ yield* bindingStore.putSource({
1221
+ namespace,
1222
+ name: input.name?.trim() || existing.name,
1223
+ config: updatedConfig
1224
+ });
1225
+ });
1226
+ const getSource = (namespace) => bindingStore.getSource(namespace);
1226
1227
  return {
1227
1228
  extension: {
1228
1229
  probeEndpoint,
@@ -1230,7 +1231,9 @@ var mcpPlugin = (options) => {
1230
1231
  removeSource,
1231
1232
  refreshSource,
1232
1233
  startOAuth,
1233
- completeOAuth
1234
+ completeOAuth,
1235
+ getSource,
1236
+ updateSource
1234
1237
  },
1235
1238
  close: () => Effect6.gen(function* () {
1236
1239
  yield* invoker.closeConnections();
@@ -1249,4 +1252,4 @@ export {
1249
1252
  makeKvBindingStore,
1250
1253
  mcpPlugin
1251
1254
  };
1252
- //# sourceMappingURL=chunk-DR65PT4S.js.map
1255
+ //# sourceMappingURL=chunk-X3JTTDWJ.js.map