@executor-js/plugin-mcp 0.0.1-beta.6 → 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.
- package/dist/api/group.d.ts +25 -27
- package/dist/api/handlers.test.d.ts +1 -0
- package/dist/{chunk-NJ4CITCV.js → chunk-X3JTTDWJ.js} +270 -218
- package/dist/chunk-X3JTTDWJ.js.map +1 -0
- package/dist/core.js +1 -1
- package/dist/index.js +1 -1
- package/dist/sdk/binding-store.d.ts +9 -7
- package/dist/sdk/oauth.d.ts +21 -17
- package/dist/sdk/plugin.d.ts +1 -0
- package/package.json +7 -7
- package/dist/chunk-NJ4CITCV.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/sdk/binding-store.ts
|
|
2
|
-
import { Effect, Schema as
|
|
2
|
+
import { Effect as Effect2, Schema as Schema5 } from "effect";
|
|
3
3
|
import { makeInMemoryScopedKv, scopeKv } from "@executor-js/sdk";
|
|
4
4
|
|
|
5
5
|
// src/sdk/types.ts
|
|
@@ -58,191 +58,58 @@ var McpToolBinding = class extends Schema.Class("McpToolBinding")({
|
|
|
58
58
|
}) {
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
-
// src/sdk/
|
|
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";
|
|
61
|
+
// src/sdk/oauth.ts
|
|
125
62
|
import {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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";
|
|
63
|
+
auth
|
|
64
|
+
} from "@modelcontextprotocol/sdk/client/auth.js";
|
|
65
|
+
import { Effect, Schema as Schema3 } from "effect";
|
|
139
66
|
|
|
140
67
|
// src/sdk/errors.ts
|
|
141
|
-
import { Schema as
|
|
142
|
-
var McpConnectionError = class extends
|
|
68
|
+
import { Schema as Schema2 } from "effect";
|
|
69
|
+
var McpConnectionError = class extends Schema2.TaggedError()(
|
|
143
70
|
"McpConnectionError",
|
|
144
71
|
{
|
|
145
|
-
transport:
|
|
146
|
-
message:
|
|
72
|
+
transport: Schema2.String,
|
|
73
|
+
message: Schema2.String
|
|
147
74
|
}
|
|
148
75
|
) {
|
|
149
76
|
};
|
|
150
|
-
var McpToolDiscoveryError = class extends
|
|
77
|
+
var McpToolDiscoveryError = class extends Schema2.TaggedError()(
|
|
151
78
|
"McpToolDiscoveryError",
|
|
152
79
|
{
|
|
153
|
-
stage:
|
|
154
|
-
message:
|
|
80
|
+
stage: Schema2.Literal("connect", "list_tools"),
|
|
81
|
+
message: Schema2.String
|
|
155
82
|
}
|
|
156
83
|
) {
|
|
157
84
|
};
|
|
158
|
-
var McpInvocationError = class extends
|
|
85
|
+
var McpInvocationError = class extends Schema2.TaggedError()(
|
|
159
86
|
"McpInvocationError",
|
|
160
87
|
{
|
|
161
|
-
toolName:
|
|
162
|
-
message:
|
|
88
|
+
toolName: Schema2.String,
|
|
89
|
+
message: Schema2.String
|
|
163
90
|
}
|
|
164
91
|
) {
|
|
165
92
|
};
|
|
166
|
-
var McpOAuthError = class extends
|
|
167
|
-
message:
|
|
93
|
+
var McpOAuthError = class extends Schema2.TaggedError()("McpOAuthError", {
|
|
94
|
+
message: Schema2.String
|
|
168
95
|
}) {
|
|
169
96
|
};
|
|
170
97
|
|
|
171
|
-
// src/sdk/
|
|
172
|
-
var
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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()
|
|
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)
|
|
186
106
|
});
|
|
187
|
-
var
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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);
|
|
107
|
+
var McpOAuthSession = Schema3.Struct({
|
|
108
|
+
...McpOAuthDiscoveryState.fields,
|
|
109
|
+
endpoint: Schema3.String,
|
|
110
|
+
redirectUrl: Schema3.String,
|
|
111
|
+
codeVerifier: Schema3.String
|
|
198
112
|
});
|
|
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
113
|
var toJsonObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
247
114
|
var CLIENT_METADATA = {
|
|
248
115
|
grant_types: ["authorization_code", "refresh_token"],
|
|
@@ -257,13 +124,13 @@ var extractDiscoveryState = (discoveryState, clientInformation) => ({
|
|
|
257
124
|
authorizationServerMetadata: toJsonObject(discoveryState?.authorizationServerMetadata),
|
|
258
125
|
clientInformation: toJsonObject(clientInformation)
|
|
259
126
|
});
|
|
260
|
-
var callAuth = (provider, opts) =>
|
|
127
|
+
var callAuth = (provider, opts) => Effect.tryPromise({
|
|
261
128
|
try: () => auth(provider, opts),
|
|
262
129
|
catch: (cause) => new McpOAuthError({
|
|
263
130
|
message: cause instanceof Error ? cause.message : String(cause)
|
|
264
131
|
})
|
|
265
132
|
});
|
|
266
|
-
var startMcpOAuthAuthorization = (input) =>
|
|
133
|
+
var startMcpOAuthAuthorization = (input) => Effect.gen(function* () {
|
|
267
134
|
let authorizationUrl;
|
|
268
135
|
let codeVerifier;
|
|
269
136
|
let discoveryState;
|
|
@@ -309,7 +176,7 @@ var startMcpOAuthAuthorization = (input) => Effect3.gen(function* () {
|
|
|
309
176
|
...extractDiscoveryState(discoveryState, clientInformation)
|
|
310
177
|
};
|
|
311
178
|
});
|
|
312
|
-
var exchangeMcpOAuthCode = (input) =>
|
|
179
|
+
var exchangeMcpOAuthCode = (input) => Effect.gen(function* () {
|
|
313
180
|
const { session } = input;
|
|
314
181
|
let tokens;
|
|
315
182
|
let discoveryState = {
|
|
@@ -359,27 +226,215 @@ var exchangeMcpOAuthCode = (input) => Effect3.gen(function* () {
|
|
|
359
226
|
};
|
|
360
227
|
});
|
|
361
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
|
+
|
|
362
417
|
// src/sdk/discover.ts
|
|
363
418
|
import { Effect as Effect4 } from "effect";
|
|
364
419
|
|
|
365
420
|
// src/sdk/manifest.ts
|
|
366
|
-
import { Schema as
|
|
367
|
-
var ListedTool =
|
|
368
|
-
name:
|
|
369
|
-
description:
|
|
370
|
-
inputSchema:
|
|
371
|
-
parameters:
|
|
372
|
-
outputSchema:
|
|
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)
|
|
373
428
|
});
|
|
374
|
-
var ListToolsResult =
|
|
375
|
-
tools:
|
|
429
|
+
var ListToolsResult = Schema6.Struct({
|
|
430
|
+
tools: Schema6.Array(ListedTool)
|
|
376
431
|
});
|
|
377
|
-
var ServerInfo =
|
|
378
|
-
name:
|
|
379
|
-
version:
|
|
432
|
+
var ServerInfo = Schema6.Struct({
|
|
433
|
+
name: Schema6.optional(Schema6.String),
|
|
434
|
+
version: Schema6.optional(Schema6.String)
|
|
380
435
|
});
|
|
381
|
-
var decodeListToolsResult =
|
|
382
|
-
var decodeServerInfo =
|
|
436
|
+
var decodeListToolsResult = Schema6.decodeUnknownOption(ListToolsResult);
|
|
437
|
+
var decodeServerInfo = Schema6.decodeUnknownOption(ServerInfo);
|
|
383
438
|
var sanitize = (value) => {
|
|
384
439
|
const s = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
385
440
|
return s || "tool";
|
|
@@ -457,7 +512,7 @@ var discoverTools = (connector) => Effect4.gen(function* () {
|
|
|
457
512
|
});
|
|
458
513
|
|
|
459
514
|
// src/sdk/invoke.ts
|
|
460
|
-
import { Effect as Effect5, Schema as
|
|
515
|
+
import { Effect as Effect5, Schema as Schema7 } from "effect";
|
|
461
516
|
import { ElicitRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
462
517
|
import {
|
|
463
518
|
ToolInvocationResult,
|
|
@@ -503,21 +558,21 @@ var makeOAuthProvider = (accessToken, tokenType, refreshToken) => ({
|
|
|
503
558
|
},
|
|
504
559
|
discoveryState: () => void 0
|
|
505
560
|
});
|
|
506
|
-
var McpElicitParams =
|
|
507
|
-
|
|
508
|
-
mode:
|
|
509
|
-
message:
|
|
510
|
-
url:
|
|
511
|
-
elicitationId:
|
|
512
|
-
id:
|
|
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)
|
|
513
568
|
}),
|
|
514
|
-
|
|
515
|
-
mode:
|
|
516
|
-
message:
|
|
517
|
-
requestedSchema:
|
|
569
|
+
Schema7.Struct({
|
|
570
|
+
mode: Schema7.optional(Schema7.Literal("form")),
|
|
571
|
+
message: Schema7.String,
|
|
572
|
+
requestedSchema: Schema7.Record({ key: Schema7.String, value: Schema7.Unknown })
|
|
518
573
|
})
|
|
519
574
|
);
|
|
520
|
-
var decodeElicitParams =
|
|
575
|
+
var decodeElicitParams = Schema7.decodeUnknownSync(McpElicitParams);
|
|
521
576
|
var toElicitationRequest = (params) => params.mode === "url" ? new UrlElicitation({
|
|
522
577
|
message: params.message,
|
|
523
578
|
url: params.url,
|
|
@@ -618,7 +673,15 @@ var makeMcpInvoker = (opts) => {
|
|
|
618
673
|
cause: void 0
|
|
619
674
|
});
|
|
620
675
|
}
|
|
621
|
-
const
|
|
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;
|
|
622
685
|
const cacheKey = connectionCacheKey(sourceData);
|
|
623
686
|
const connector = resolveConnectorInput(sourceData, opts.secrets, opts.scopeId).pipe(
|
|
624
687
|
Effect5.flatMap((ci) => createMcpConnector(ci)),
|
|
@@ -782,7 +845,6 @@ var mcpDiscoveryError = (message) => new McpToolDiscoveryError({ stage: "list_to
|
|
|
782
845
|
var mcpPlugin = (options) => {
|
|
783
846
|
const bindingStore = options?.bindingStore ?? makeInMemoryBindingStore();
|
|
784
847
|
const addedSources = /* @__PURE__ */ new Map();
|
|
785
|
-
const oauthSessions = /* @__PURE__ */ new Map();
|
|
786
848
|
return definePlugin({
|
|
787
849
|
key: "mcp",
|
|
788
850
|
init: (ctx) => Effect6.gen(function* () {
|
|
@@ -825,6 +887,7 @@ var mcpPlugin = (options) => {
|
|
|
825
887
|
id: s.namespace,
|
|
826
888
|
name: s.name,
|
|
827
889
|
kind: "mcp",
|
|
890
|
+
url: s.config.transport === "remote" ? s.config.endpoint : void 0,
|
|
828
891
|
canEdit: isRemote
|
|
829
892
|
})
|
|
830
893
|
);
|
|
@@ -951,8 +1014,7 @@ var mcpPlugin = (options) => {
|
|
|
951
1014
|
(e) => bindingStore.put(
|
|
952
1015
|
ToolId.make(joinToolPath(sourceId, e.toolId)),
|
|
953
1016
|
sourceId,
|
|
954
|
-
toBinding(e)
|
|
955
|
-
sd
|
|
1017
|
+
toBinding(e)
|
|
956
1018
|
),
|
|
957
1019
|
{ discard: true }
|
|
958
1020
|
);
|
|
@@ -1020,8 +1082,7 @@ var mcpPlugin = (options) => {
|
|
|
1020
1082
|
(e) => bindingStore.put(
|
|
1021
1083
|
ToolId.make(joinToolPath(namespace, e.toolId)),
|
|
1022
1084
|
namespace,
|
|
1023
|
-
toBinding(e)
|
|
1024
|
-
sd
|
|
1085
|
+
toBinding(e)
|
|
1025
1086
|
),
|
|
1026
1087
|
{ discard: true }
|
|
1027
1088
|
);
|
|
@@ -1038,6 +1099,7 @@ var mcpPlugin = (options) => {
|
|
|
1038
1099
|
id: namespace,
|
|
1039
1100
|
name: sourceName,
|
|
1040
1101
|
kind: "mcp",
|
|
1102
|
+
url: sd.transport === "remote" ? sd.endpoint : void 0,
|
|
1041
1103
|
canEdit: config.transport === "remote"
|
|
1042
1104
|
})
|
|
1043
1105
|
);
|
|
@@ -1064,8 +1126,7 @@ var mcpPlugin = (options) => {
|
|
|
1064
1126
|
(e) => bindingStore.put(
|
|
1065
1127
|
ToolId.make(joinToolPath(namespace, e.toolId)),
|
|
1066
1128
|
namespace,
|
|
1067
|
-
toBinding(e)
|
|
1068
|
-
sd
|
|
1129
|
+
toBinding(e)
|
|
1069
1130
|
),
|
|
1070
1131
|
{ discard: true }
|
|
1071
1132
|
);
|
|
@@ -1087,7 +1148,7 @@ var mcpPlugin = (options) => {
|
|
|
1087
1148
|
redirectUrl: input.redirectUrl,
|
|
1088
1149
|
state: sessionId
|
|
1089
1150
|
}).pipe(Effect6.mapError((e) => mcpOAuthError(`OAuth start failed: ${e.message}`)));
|
|
1090
|
-
|
|
1151
|
+
yield* bindingStore.putOAuthSession(sessionId, {
|
|
1091
1152
|
endpoint: fullEndpoint,
|
|
1092
1153
|
redirectUrl: input.redirectUrl,
|
|
1093
1154
|
codeVerifier: started.codeVerifier,
|
|
@@ -1105,7 +1166,7 @@ var mcpPlugin = (options) => {
|
|
|
1105
1166
|
const completeOAuth = (input) => Effect6.gen(function* () {
|
|
1106
1167
|
if (input.error) return yield* mcpOAuthError(`OAuth error: ${input.error}`);
|
|
1107
1168
|
if (!input.code) return yield* mcpOAuthError("Missing OAuth authorization code");
|
|
1108
|
-
const session =
|
|
1169
|
+
const session = yield* bindingStore.getOAuthSession(input.state);
|
|
1109
1170
|
if (!session) return yield* mcpOAuthError(`OAuth session not found: ${input.state}`);
|
|
1110
1171
|
const exchanged = yield* exchangeMcpOAuthCode({
|
|
1111
1172
|
session,
|
|
@@ -1135,7 +1196,7 @@ var mcpPlugin = (options) => {
|
|
|
1135
1196
|
);
|
|
1136
1197
|
refreshTokenSecretId = ref.id;
|
|
1137
1198
|
}
|
|
1138
|
-
|
|
1199
|
+
yield* bindingStore.deleteOAuthSession(input.state);
|
|
1139
1200
|
const expiresAt = typeof exchanged.tokens.expires_in === "number" ? Date.now() + exchanged.tokens.expires_in * 1e3 : null;
|
|
1140
1201
|
return {
|
|
1141
1202
|
accessTokenSecretId: accessTokenRef.id,
|
|
@@ -1146,9 +1207,9 @@ var mcpPlugin = (options) => {
|
|
|
1146
1207
|
};
|
|
1147
1208
|
});
|
|
1148
1209
|
const updateSource = (namespace, input) => Effect6.gen(function* () {
|
|
1149
|
-
const
|
|
1150
|
-
if (!
|
|
1151
|
-
const remote =
|
|
1210
|
+
const existing = yield* bindingStore.getSource(namespace);
|
|
1211
|
+
if (!existing || existing.config.transport !== "remote") return;
|
|
1212
|
+
const remote = existing.config;
|
|
1152
1213
|
const updatedConfig = {
|
|
1153
1214
|
...remote,
|
|
1154
1215
|
...input.endpoint !== void 0 ? { endpoint: input.endpoint } : {},
|
|
@@ -1156,20 +1217,11 @@ var mcpPlugin = (options) => {
|
|
|
1156
1217
|
...input.auth !== void 0 ? { auth: input.auth } : {},
|
|
1157
1218
|
...input.queryParams !== void 0 ? { queryParams: input.queryParams } : {}
|
|
1158
1219
|
};
|
|
1159
|
-
const sources = yield* bindingStore.listSources();
|
|
1160
|
-
const existingMeta = sources.find((s) => s.namespace === namespace);
|
|
1161
1220
|
yield* bindingStore.putSource({
|
|
1162
1221
|
namespace,
|
|
1163
|
-
name:
|
|
1222
|
+
name: input.name?.trim() || existing.name,
|
|
1164
1223
|
config: updatedConfig
|
|
1165
1224
|
});
|
|
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
1225
|
});
|
|
1174
1226
|
const getSource = (namespace) => bindingStore.getSource(namespace);
|
|
1175
1227
|
return {
|
|
@@ -1200,4 +1252,4 @@ export {
|
|
|
1200
1252
|
makeKvBindingStore,
|
|
1201
1253
|
mcpPlugin
|
|
1202
1254
|
};
|
|
1203
|
-
//# sourceMappingURL=chunk-
|
|
1255
|
+
//# sourceMappingURL=chunk-X3JTTDWJ.js.map
|