@executor-js/plugin-mcp 1.4.28 → 1.4.30
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/{AddMcpSource-TLAL463B.js → AddMcpSource-3HUBFR3K.js} +68 -141
- package/dist/AddMcpSource-3HUBFR3K.js.map +1 -0
- package/dist/{EditMcpSource-FAWEECNU.js → EditMcpSource-UVGSSC2R.js} +106 -83
- package/dist/EditMcpSource-UVGSSC2R.js.map +1 -0
- package/dist/McpSourceSummary-UWVCAJOU.js +171 -0
- package/dist/McpSourceSummary-UWVCAJOU.js.map +1 -0
- package/dist/api/group.d.ts +92 -180
- package/dist/api/index.d.ts +97 -382
- package/dist/{chunk-4ORPFRLI.js → chunk-2A4H3UVR.js} +21 -80
- package/dist/chunk-2A4H3UVR.js.map +1 -0
- package/dist/{chunk-M6REVU6O.js → chunk-3TGDWTNE.js} +14 -40
- package/dist/chunk-3TGDWTNE.js.map +1 -0
- package/dist/{chunk-NQT7NAGE.js → chunk-H5PLTEMB.js} +673 -713
- package/dist/chunk-H5PLTEMB.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/{chunk-SKSXXFOA.js → chunk-TW44CBXJ.js} +12 -1
- package/dist/chunk-TW44CBXJ.js.map +1 -0
- package/dist/client.js +5 -4
- package/dist/client.js.map +1 -1
- package/dist/core.js +4 -6
- package/dist/index.js +4 -2
- package/dist/promise.d.ts +1 -1
- package/dist/react/atoms.d.ts +198 -236
- package/dist/react/client.d.ts +91 -179
- package/dist/sdk/binding-store.d.ts +3 -163
- package/dist/sdk/index.d.ts +2 -2
- package/dist/sdk/plugin.d.ts +172 -225
- package/dist/sdk/presets.d.ts +1 -0
- package/dist/sdk/testing-fixtures.test.d.ts +1 -0
- package/dist/sdk/types.d.ts +58 -83
- package/dist/{stdio-connector-AA5S6UUJ.js → stdio-connector-MDW6PW36.js} +3 -1
- package/dist/{stdio-connector-AA5S6UUJ.js.map → stdio-connector-MDW6PW36.js.map} +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/server.d.ts +70 -4
- package/dist/testing.js +14085 -30
- package/dist/testing.js.map +1 -1
- package/package.json +3 -4
- package/dist/AddMcpSource-TLAL463B.js.map +0 -1
- package/dist/EditMcpSource-FAWEECNU.js.map +0 -1
- package/dist/McpSourceSummary-257JNETP.js +0 -85
- package/dist/McpSourceSummary-257JNETP.js.map +0 -1
- package/dist/chunk-4ORPFRLI.js.map +0 -1
- package/dist/chunk-M6REVU6O.js.map +0 -1
- package/dist/chunk-NQT7NAGE.js.map +0 -1
- package/dist/chunk-SKSXXFOA.js.map +0 -1
|
@@ -1,94 +1,30 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
mcpPresets
|
|
3
|
+
} from "./chunk-TW44CBXJ.js";
|
|
4
|
+
import {
|
|
3
5
|
MCP_OAUTH_CLIENT_ID_SLOT,
|
|
4
6
|
MCP_OAUTH_CLIENT_SECRET_SLOT,
|
|
5
7
|
MCP_OAUTH_CONNECTION_SLOT,
|
|
8
|
+
McpConfiguredValueInput,
|
|
9
|
+
McpConnectionAuthInput,
|
|
6
10
|
McpConnectionError,
|
|
11
|
+
McpCredentialInput,
|
|
7
12
|
McpInvocationError,
|
|
8
|
-
|
|
13
|
+
McpRemoteTransport,
|
|
9
14
|
McpStoredSourceData,
|
|
10
15
|
McpToolAnnotations,
|
|
11
16
|
McpToolBinding,
|
|
12
17
|
McpToolDiscoveryError,
|
|
18
|
+
SecretBackedValue,
|
|
13
19
|
mcpHeaderSlot,
|
|
14
20
|
mcpQueryParamSlot
|
|
15
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-3TGDWTNE.js";
|
|
16
22
|
|
|
17
23
|
// src/sdk/binding-store.ts
|
|
18
|
-
import { Effect, Option, Schema } from "effect";
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} from "@executor-js/sdk/core";
|
|
23
|
-
var mcpSchema = defineSchema({
|
|
24
|
-
mcp_source: {
|
|
25
|
-
fields: {
|
|
26
|
-
id: { type: "string", required: true },
|
|
27
|
-
scope_id: { type: "string", required: true, index: true },
|
|
28
|
-
name: { type: "string", required: true },
|
|
29
|
-
// Plugin-private structural data minus the ref-bearing fields
|
|
30
|
-
// (auth, headers, queryParams). For remote sources: transport,
|
|
31
|
-
// endpoint, remoteTransport. For stdio: transport, command,
|
|
32
|
-
// args, env, cwd.
|
|
33
|
-
config: { type: "json", required: true },
|
|
34
|
-
// Flattened McpConnectionAuth. The stored source only names slots;
|
|
35
|
-
// concrete per-user/per-workspace values live in core credential_binding.
|
|
36
|
-
auth_kind: {
|
|
37
|
-
type: ["none", "header", "oauth2"],
|
|
38
|
-
required: true,
|
|
39
|
-
defaultValue: "none"
|
|
40
|
-
},
|
|
41
|
-
// Header-auth fields.
|
|
42
|
-
auth_header_name: { type: "string", required: false },
|
|
43
|
-
auth_header_slot: { type: "string", required: false },
|
|
44
|
-
auth_header_prefix: { type: "string", required: false },
|
|
45
|
-
// OAuth2 auth fields.
|
|
46
|
-
auth_connection_slot: { type: "string", required: false },
|
|
47
|
-
auth_client_id_slot: {
|
|
48
|
-
type: "string",
|
|
49
|
-
required: false
|
|
50
|
-
},
|
|
51
|
-
auth_client_secret_slot: {
|
|
52
|
-
type: "string",
|
|
53
|
-
required: false
|
|
54
|
-
},
|
|
55
|
-
created_at: { type: "date", required: true }
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
mcp_source_header: {
|
|
59
|
-
fields: {
|
|
60
|
-
id: { type: "string", required: true },
|
|
61
|
-
scope_id: { type: "string", required: true, index: true },
|
|
62
|
-
source_id: { type: "string", required: true, index: true },
|
|
63
|
-
name: { type: "string", required: true },
|
|
64
|
-
kind: { type: ["text", "binding"], required: true },
|
|
65
|
-
text_value: { type: "string", required: false },
|
|
66
|
-
slot_key: { type: "string", required: false },
|
|
67
|
-
prefix: { type: "string", required: false }
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
mcp_source_query_param: {
|
|
71
|
-
fields: {
|
|
72
|
-
id: { type: "string", required: true },
|
|
73
|
-
scope_id: { type: "string", required: true, index: true },
|
|
74
|
-
source_id: { type: "string", required: true, index: true },
|
|
75
|
-
name: { type: "string", required: true },
|
|
76
|
-
kind: { type: ["text", "binding"], required: true },
|
|
77
|
-
text_value: { type: "string", required: false },
|
|
78
|
-
slot_key: { type: "string", required: false },
|
|
79
|
-
prefix: { type: "string", required: false }
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
mcp_binding: {
|
|
83
|
-
fields: {
|
|
84
|
-
id: { type: "string", required: true },
|
|
85
|
-
scope_id: { type: "string", required: true, index: true },
|
|
86
|
-
source_id: { type: "string", required: true, index: true },
|
|
87
|
-
binding: { type: "json", required: true },
|
|
88
|
-
created_at: { type: "date", required: true }
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
});
|
|
24
|
+
import { Effect, Option, Predicate, Schema } from "effect";
|
|
25
|
+
var mcpSchema = {};
|
|
26
|
+
var SOURCE_COLLECTION = "source";
|
|
27
|
+
var BINDING_COLLECTION = "binding";
|
|
92
28
|
var decodeSourceData = Schema.decodeUnknownSync(McpStoredSourceData);
|
|
93
29
|
var encodeSourceData = Schema.encodeSync(McpStoredSourceData);
|
|
94
30
|
var decodeBinding = Schema.decodeUnknownSync(McpToolBinding);
|
|
@@ -98,279 +34,109 @@ var coerceJson = (value) => {
|
|
|
98
34
|
if (typeof value !== "string") return value;
|
|
99
35
|
return Option.getOrElse(decodeJson(value), () => value);
|
|
100
36
|
};
|
|
101
|
-
var
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
37
|
+
var sourceData = (source) => ({
|
|
38
|
+
namespace: source.namespace,
|
|
39
|
+
scope: source.scope,
|
|
40
|
+
name: source.name,
|
|
41
|
+
config: encodeSourceData(source.config)
|
|
42
|
+
});
|
|
43
|
+
var bindingData = (namespace, entry) => ({
|
|
44
|
+
namespace,
|
|
45
|
+
toolId: entry.toolId,
|
|
46
|
+
binding: encodeBinding(entry.binding)
|
|
47
|
+
});
|
|
48
|
+
var rowToSource = (row) => {
|
|
49
|
+
const raw = coerceJson(row.data);
|
|
50
|
+
if (!raw || typeof raw !== "object") return null;
|
|
51
|
+
const record = raw;
|
|
52
|
+
if (typeof record.namespace !== "string" || typeof record.scope !== "string" || typeof record.name !== "string") {
|
|
53
|
+
return null;
|
|
117
54
|
}
|
|
118
|
-
return {
|
|
55
|
+
return {
|
|
56
|
+
namespace: record.namespace,
|
|
57
|
+
scope: record.scope,
|
|
58
|
+
name: record.name,
|
|
59
|
+
config: decodeSourceData(coerceJson(record.config))
|
|
60
|
+
};
|
|
119
61
|
};
|
|
120
|
-
var
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
if (kind === "oauth2" && typeof row.auth_connection_slot === "string") {
|
|
132
|
-
const cid = row.auth_client_id_slot;
|
|
133
|
-
const csec = row.auth_client_secret_slot;
|
|
134
|
-
return {
|
|
135
|
-
kind: "oauth2",
|
|
136
|
-
connectionSlot: row.auth_connection_slot,
|
|
137
|
-
...cid ? { clientIdSlot: cid } : {},
|
|
138
|
-
...csec ? { clientSecretSlot: csec } : {}
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
return { kind: "none" };
|
|
62
|
+
var rowToBinding = (row) => {
|
|
63
|
+
const raw = coerceJson(row.data);
|
|
64
|
+
if (!raw || typeof raw !== "object") return null;
|
|
65
|
+
const record = raw;
|
|
66
|
+
if (typeof record.toolId !== "string" || typeof record.namespace !== "string") return null;
|
|
67
|
+
return {
|
|
68
|
+
toolId: record.toolId,
|
|
69
|
+
namespace: record.namespace,
|
|
70
|
+
binding: decodeBinding(coerceJson(record.binding))
|
|
71
|
+
};
|
|
142
72
|
};
|
|
143
|
-
var
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
73
|
+
var makeMcpStore = ({ pluginStorage }) => {
|
|
74
|
+
const listBindingRowsForSourceScope = (namespace, scope) => pluginStorage.list({
|
|
75
|
+
collection: BINDING_COLLECTION,
|
|
76
|
+
keyPrefix: `${namespace}.`
|
|
77
|
+
}).pipe(
|
|
78
|
+
Effect.map(
|
|
79
|
+
(rows) => rows.filter((row) => {
|
|
80
|
+
if (String(row.scopeId) !== scope) return false;
|
|
81
|
+
return rowToBinding(row)?.namespace === namespace;
|
|
82
|
+
})
|
|
83
|
+
)
|
|
84
|
+
);
|
|
85
|
+
const removeBindingsForSourceScope = (namespace, scope) => Effect.gen(function* () {
|
|
86
|
+
const rows = yield* listBindingRowsForSourceScope(namespace, scope);
|
|
87
|
+
for (const row of rows) {
|
|
88
|
+
yield* pluginStorage.remove({
|
|
89
|
+
scope,
|
|
90
|
+
collection: BINDING_COLLECTION,
|
|
91
|
+
key: row.key
|
|
92
|
+
});
|
|
156
93
|
}
|
|
157
|
-
return {
|
|
158
|
-
id,
|
|
159
|
-
scope_id: scope,
|
|
160
|
-
source_id: sourceId,
|
|
161
|
-
name,
|
|
162
|
-
kind: "binding",
|
|
163
|
-
slot_key: value.slot,
|
|
164
|
-
prefix: value.prefix
|
|
165
|
-
};
|
|
166
94
|
});
|
|
167
|
-
};
|
|
168
|
-
var rowsToValueMap = (rows) => {
|
|
169
|
-
const out = {};
|
|
170
|
-
for (const row of rows) {
|
|
171
|
-
if (typeof row.name !== "string") continue;
|
|
172
|
-
const name = row.name;
|
|
173
|
-
if (row.kind === "binding" && typeof row.slot_key === "string") {
|
|
174
|
-
const prefix = row.prefix;
|
|
175
|
-
out[name] = prefix ? ConfiguredCredentialBinding.make({ kind: "binding", slot: row.slot_key, prefix }) : ConfiguredCredentialBinding.make({ kind: "binding", slot: row.slot_key });
|
|
176
|
-
} else if (row.kind === "text" && typeof row.text_value === "string") {
|
|
177
|
-
out[name] = row.text_value;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return out;
|
|
181
|
-
};
|
|
182
|
-
var makeMcpStore = ({ adapter: db }) => {
|
|
183
95
|
return {
|
|
184
|
-
listBindingsBySource: (namespace, scope) =>
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}));
|
|
196
|
-
}),
|
|
197
|
-
getBinding: (toolId, scope) => Effect.gen(function* () {
|
|
198
|
-
const row = yield* db.findOne({
|
|
199
|
-
model: "mcp_binding",
|
|
200
|
-
where: [
|
|
201
|
-
{ field: "id", value: toolId },
|
|
202
|
-
{ field: "scope_id", value: scope }
|
|
203
|
-
]
|
|
204
|
-
});
|
|
205
|
-
if (!row) return null;
|
|
206
|
-
const binding = decodeBinding(coerceJson(row.binding));
|
|
207
|
-
return { binding, namespace: row.source_id };
|
|
208
|
-
}),
|
|
96
|
+
listBindingsBySource: (namespace, scope) => listBindingRowsForSourceScope(namespace, scope).pipe(
|
|
97
|
+
Effect.map(
|
|
98
|
+
(rows) => rows.map(rowToBinding).filter(Predicate.isNotNull).map((row) => ({ toolId: row.toolId, binding: row.binding }))
|
|
99
|
+
)
|
|
100
|
+
),
|
|
101
|
+
getBinding: (toolId, scope) => pluginStorage.getAtScope({ scope, collection: BINDING_COLLECTION, key: toolId }).pipe(
|
|
102
|
+
Effect.map((row) => {
|
|
103
|
+
const binding = row ? rowToBinding(row) : null;
|
|
104
|
+
return binding ? { binding: binding.binding, namespace: binding.namespace } : null;
|
|
105
|
+
})
|
|
106
|
+
),
|
|
209
107
|
putBindings: (namespace, scope, entries) => Effect.gen(function* () {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
scope_id: scope,
|
|
217
|
-
source_id: namespace,
|
|
218
|
-
binding: encodeBinding(e.binding),
|
|
219
|
-
created_at: now
|
|
220
|
-
})),
|
|
221
|
-
forceAllowId: true
|
|
222
|
-
});
|
|
223
|
-
}),
|
|
224
|
-
removeBindingsByNamespace: (namespace, scope) => db.deleteMany({
|
|
225
|
-
model: "mcp_binding",
|
|
226
|
-
where: [
|
|
227
|
-
{ field: "source_id", value: namespace },
|
|
228
|
-
{ field: "scope_id", value: scope }
|
|
229
|
-
]
|
|
230
|
-
}).pipe(Effect.asVoid),
|
|
231
|
-
getSource: (namespace, scope) => Effect.gen(function* () {
|
|
232
|
-
const row = yield* db.findOne({
|
|
233
|
-
model: "mcp_source",
|
|
234
|
-
where: [
|
|
235
|
-
{ field: "id", value: namespace },
|
|
236
|
-
{ field: "scope_id", value: scope }
|
|
237
|
-
]
|
|
238
|
-
});
|
|
239
|
-
if (!row) return null;
|
|
240
|
-
return {
|
|
241
|
-
namespace: row.id,
|
|
242
|
-
scope: row.scope_id,
|
|
243
|
-
name: row.name,
|
|
244
|
-
config: yield* hydrateSourceData(row, namespace, scope)
|
|
245
|
-
};
|
|
246
|
-
}),
|
|
247
|
-
getSourceConfig: (namespace, scope) => Effect.gen(function* () {
|
|
248
|
-
const row = yield* db.findOne({
|
|
249
|
-
model: "mcp_source",
|
|
250
|
-
where: [
|
|
251
|
-
{ field: "id", value: namespace },
|
|
252
|
-
{ field: "scope_id", value: scope }
|
|
253
|
-
]
|
|
254
|
-
});
|
|
255
|
-
if (!row) return null;
|
|
256
|
-
return yield* hydrateSourceData(row, namespace, scope);
|
|
257
|
-
}),
|
|
258
|
-
putSource: (source) => Effect.gen(function* () {
|
|
259
|
-
const now = /* @__PURE__ */ new Date();
|
|
260
|
-
yield* db.delete({
|
|
261
|
-
model: "mcp_source",
|
|
262
|
-
where: [
|
|
263
|
-
{ field: "id", value: source.namespace },
|
|
264
|
-
{ field: "scope_id", value: source.scope }
|
|
265
|
-
]
|
|
266
|
-
});
|
|
267
|
-
yield* deleteSourceChildren(source.namespace, source.scope);
|
|
268
|
-
const auth = source.config.transport === "remote" ? source.config.auth : { kind: "none" };
|
|
269
|
-
const authCols = authToColumns(auth);
|
|
270
|
-
const headers = source.config.transport === "remote" ? source.config.headers : void 0;
|
|
271
|
-
const queryParams = source.config.transport === "remote" ? source.config.queryParams : void 0;
|
|
272
|
-
const encodedConfig = stripExtractedFields(
|
|
273
|
-
encodeSourceData(source.config)
|
|
274
|
-
);
|
|
275
|
-
yield* db.create({
|
|
276
|
-
model: "mcp_source",
|
|
277
|
-
data: {
|
|
278
|
-
id: source.namespace,
|
|
279
|
-
scope_id: source.scope,
|
|
280
|
-
name: source.name,
|
|
281
|
-
config: encodedConfig,
|
|
282
|
-
created_at: now,
|
|
283
|
-
...authCols
|
|
284
|
-
},
|
|
285
|
-
forceAllowId: true
|
|
286
|
-
});
|
|
287
|
-
const headerRows = valueMapToRows(source.namespace, source.scope, headers);
|
|
288
|
-
if (headerRows.length > 0) {
|
|
289
|
-
yield* db.createMany({
|
|
290
|
-
model: "mcp_source_header",
|
|
291
|
-
data: headerRows,
|
|
292
|
-
forceAllowId: true
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
const paramRows = valueMapToRows(source.namespace, source.scope, queryParams);
|
|
296
|
-
if (paramRows.length > 0) {
|
|
297
|
-
yield* db.createMany({
|
|
298
|
-
model: "mcp_source_query_param",
|
|
299
|
-
data: paramRows,
|
|
300
|
-
forceAllowId: true
|
|
108
|
+
for (const entry of entries) {
|
|
109
|
+
yield* pluginStorage.put({
|
|
110
|
+
scope,
|
|
111
|
+
collection: BINDING_COLLECTION,
|
|
112
|
+
key: entry.toolId,
|
|
113
|
+
data: bindingData(namespace, entry)
|
|
301
114
|
});
|
|
302
115
|
}
|
|
303
116
|
}),
|
|
117
|
+
removeBindingsByNamespace: (namespace, scope) => removeBindingsForSourceScope(namespace, scope),
|
|
118
|
+
getSource: (namespace, scope) => pluginStorage.getAtScope({ scope, collection: SOURCE_COLLECTION, key: namespace }).pipe(Effect.map((row) => row ? rowToSource(row) : null)),
|
|
119
|
+
getSourceConfig: (namespace, scope) => pluginStorage.getAtScope({ scope, collection: SOURCE_COLLECTION, key: namespace }).pipe(
|
|
120
|
+
Effect.map((row) => {
|
|
121
|
+
const source = row ? rowToSource(row) : null;
|
|
122
|
+
return source?.config ?? null;
|
|
123
|
+
})
|
|
124
|
+
),
|
|
125
|
+
putSource: (source) => pluginStorage.put({
|
|
126
|
+
scope: source.scope,
|
|
127
|
+
collection: SOURCE_COLLECTION,
|
|
128
|
+
key: source.namespace,
|
|
129
|
+
data: sourceData(source)
|
|
130
|
+
}).pipe(Effect.asVoid),
|
|
304
131
|
removeSource: (namespace, scope) => Effect.gen(function* () {
|
|
305
|
-
yield*
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
]
|
|
311
|
-
});
|
|
312
|
-
yield* deleteSourceChildren(namespace, scope);
|
|
313
|
-
yield* db.delete({
|
|
314
|
-
model: "mcp_source",
|
|
315
|
-
where: [
|
|
316
|
-
{ field: "id", value: namespace },
|
|
317
|
-
{ field: "scope_id", value: scope }
|
|
318
|
-
]
|
|
132
|
+
yield* removeBindingsForSourceScope(namespace, scope);
|
|
133
|
+
yield* pluginStorage.remove({
|
|
134
|
+
scope,
|
|
135
|
+
collection: SOURCE_COLLECTION,
|
|
136
|
+
key: namespace
|
|
319
137
|
});
|
|
320
138
|
})
|
|
321
139
|
};
|
|
322
|
-
function deleteSourceChildren(namespace, scope) {
|
|
323
|
-
return Effect.gen(function* () {
|
|
324
|
-
for (const model of ["mcp_source_header", "mcp_source_query_param"]) {
|
|
325
|
-
yield* db.deleteMany({
|
|
326
|
-
model,
|
|
327
|
-
where: [
|
|
328
|
-
{ field: "source_id", value: namespace },
|
|
329
|
-
{ field: "scope_id", value: scope }
|
|
330
|
-
]
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
function hydrateSourceData(row, namespace, scope) {
|
|
336
|
-
return Effect.gen(function* () {
|
|
337
|
-
const partial = coerceJson(row.config);
|
|
338
|
-
if (partial.transport !== "remote") {
|
|
339
|
-
return decodeSourceData(partial);
|
|
340
|
-
}
|
|
341
|
-
const headerRows = yield* db.findMany({
|
|
342
|
-
model: "mcp_source_header",
|
|
343
|
-
where: [
|
|
344
|
-
{ field: "source_id", value: namespace },
|
|
345
|
-
{ field: "scope_id", value: scope }
|
|
346
|
-
]
|
|
347
|
-
});
|
|
348
|
-
const paramRows = yield* db.findMany({
|
|
349
|
-
model: "mcp_source_query_param",
|
|
350
|
-
where: [
|
|
351
|
-
{ field: "source_id", value: namespace },
|
|
352
|
-
{ field: "scope_id", value: scope }
|
|
353
|
-
]
|
|
354
|
-
});
|
|
355
|
-
const headers = rowsToValueMap(headerRows);
|
|
356
|
-
const queryParams = rowsToValueMap(paramRows);
|
|
357
|
-
const reassembled = {
|
|
358
|
-
...partial,
|
|
359
|
-
...Object.keys(headers).length > 0 ? { headers } : {},
|
|
360
|
-
...Object.keys(queryParams).length > 0 ? { queryParams } : {},
|
|
361
|
-
auth: columnsToAuth(row)
|
|
362
|
-
};
|
|
363
|
-
return decodeSourceData(reassembled);
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
};
|
|
367
|
-
var stripExtractedFields = (encoded) => {
|
|
368
|
-
if (encoded.transport !== "remote") return encoded;
|
|
369
|
-
const { auth, headers, queryParams, ...rest } = encoded;
|
|
370
|
-
void auth;
|
|
371
|
-
void headers;
|
|
372
|
-
void queryParams;
|
|
373
|
-
return rest;
|
|
374
140
|
};
|
|
375
141
|
|
|
376
142
|
// src/sdk/plugin.ts
|
|
@@ -380,21 +146,27 @@ import {
|
|
|
380
146
|
Exit as Exit2,
|
|
381
147
|
Match,
|
|
382
148
|
Option as Option5,
|
|
383
|
-
Predicate as
|
|
149
|
+
Predicate as Predicate3,
|
|
384
150
|
Result,
|
|
385
151
|
Scope,
|
|
152
|
+
Schema as Schema5,
|
|
386
153
|
ScopedCache as ScopedCache2
|
|
387
154
|
} from "effect";
|
|
388
155
|
import {
|
|
389
|
-
ConfiguredCredentialBinding as ConfiguredCredentialBinding2,
|
|
390
|
-
ConnectionId,
|
|
391
156
|
ScopeId,
|
|
392
|
-
SecretId,
|
|
393
157
|
SourceDetectionResult,
|
|
158
|
+
ToolResult,
|
|
159
|
+
defaultSourceInstallScopeId,
|
|
394
160
|
definePlugin,
|
|
161
|
+
tool,
|
|
395
162
|
resolveSecretBackedMap as resolveSharedSecretBackedMap,
|
|
396
163
|
StorageError
|
|
397
164
|
} from "@executor-js/sdk/core";
|
|
165
|
+
import {
|
|
166
|
+
compileHttpNamedCredentialMap,
|
|
167
|
+
OAuth2SourceConfig,
|
|
168
|
+
httpCredentialInputToBindingValue
|
|
169
|
+
} from "@executor-js/sdk/http-source";
|
|
398
170
|
|
|
399
171
|
// src/sdk/connection.ts
|
|
400
172
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -449,7 +221,7 @@ var createMcpConnector = (input) => {
|
|
|
449
221
|
}
|
|
450
222
|
return Effect2.gen(function* () {
|
|
451
223
|
const { createStdioTransport } = yield* Effect2.tryPromise({
|
|
452
|
-
try: () => import("./stdio-connector-
|
|
224
|
+
try: () => import("./stdio-connector-MDW6PW36.js"),
|
|
453
225
|
catch: () => new McpConnectionError({
|
|
454
226
|
transport: "stdio",
|
|
455
227
|
message: "Failed to load stdio transport module"
|
|
@@ -537,17 +309,17 @@ var extractManifestFromListToolsResult = (listToolsResult, metadata) => {
|
|
|
537
309
|
),
|
|
538
310
|
Option2.getOrNull
|
|
539
311
|
);
|
|
540
|
-
const tools = listed.flatMap((
|
|
541
|
-
const toolName =
|
|
312
|
+
const tools = listed.flatMap((tool2) => {
|
|
313
|
+
const toolName = tool2.name.trim();
|
|
542
314
|
if (!toolName) return [];
|
|
543
315
|
return [
|
|
544
316
|
{
|
|
545
317
|
toolId: uniqueId(toolName, seen),
|
|
546
318
|
toolName,
|
|
547
|
-
description:
|
|
548
|
-
inputSchema:
|
|
549
|
-
outputSchema:
|
|
550
|
-
annotations:
|
|
319
|
+
description: tool2.description ?? null,
|
|
320
|
+
inputSchema: tool2.inputSchema ?? tool2.parameters,
|
|
321
|
+
outputSchema: tool2.outputSchema,
|
|
322
|
+
annotations: tool2.annotations
|
|
551
323
|
}
|
|
552
324
|
];
|
|
553
325
|
});
|
|
@@ -608,7 +380,7 @@ var closeConnection = (connection) => Effect3.ignore(
|
|
|
608
380
|
);
|
|
609
381
|
|
|
610
382
|
// src/sdk/invoke.ts
|
|
611
|
-
import { Cause, Effect as Effect4, Exit, Option as Option3, Predicate, Schema as Schema3, ScopedCache } from "effect";
|
|
383
|
+
import { Cause, Effect as Effect4, Exit, Option as Option3, Predicate as Predicate2, Schema as Schema3, ScopedCache } from "effect";
|
|
612
384
|
import { ElicitRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
613
385
|
import {
|
|
614
386
|
FormElicitation,
|
|
@@ -691,8 +463,8 @@ var installElicitationHandler = (client, elicit) => {
|
|
|
691
463
|
const failure = exit.cause.reasons.find(Cause.isFailReason);
|
|
692
464
|
if (failure) {
|
|
693
465
|
const err = failure.error;
|
|
694
|
-
if (
|
|
695
|
-
const action =
|
|
466
|
+
if (Predicate2.isTagged(err, "ElicitationDeclinedError")) {
|
|
467
|
+
const action = Predicate2.hasProperty(err, "action") && err.action === "cancel" ? "cancel" : "decline";
|
|
696
468
|
return { action };
|
|
697
469
|
}
|
|
698
470
|
}
|
|
@@ -808,6 +580,41 @@ var isOAuthErrorBody = (body) => {
|
|
|
808
580
|
if (Array.isArray(obj.errors)) return false;
|
|
809
581
|
return typeof obj.error === "string";
|
|
810
582
|
};
|
|
583
|
+
var ProtectedResourceMetadata = Schema4.Struct({
|
|
584
|
+
resource: Schema4.String,
|
|
585
|
+
authorization_servers: Schema4.Array(Schema4.String)
|
|
586
|
+
});
|
|
587
|
+
var decodeProtectedResourceMetadata = Schema4.decodeUnknownOption(
|
|
588
|
+
Schema4.fromJsonString(ProtectedResourceMetadata)
|
|
589
|
+
);
|
|
590
|
+
var protectedResourceMetadataUrl = (endpoint) => {
|
|
591
|
+
const path = endpoint.pathname === "/" ? "" : endpoint.pathname;
|
|
592
|
+
return `${endpoint.origin}/.well-known/oauth-protected-resource${path}`;
|
|
593
|
+
};
|
|
594
|
+
var resourceMatchesEndpoint = (resource, endpoint) => {
|
|
595
|
+
if (!URL.canParse(resource)) return false;
|
|
596
|
+
const parsed = new URL(resource);
|
|
597
|
+
if (parsed.origin !== endpoint.origin) return false;
|
|
598
|
+
const resourcePath = parsed.pathname.replace(/\/+$/, "");
|
|
599
|
+
const endpointPath = endpoint.pathname.replace(/\/+$/, "");
|
|
600
|
+
return endpointPath === resourcePath || endpointPath.startsWith(`${resourcePath}/`);
|
|
601
|
+
};
|
|
602
|
+
var probeProtectedResourceMetadata = (client, endpoint, timeoutMs) => Effect5.gen(function* () {
|
|
603
|
+
const response = yield* client.execute(
|
|
604
|
+
HttpClientRequest.get(protectedResourceMetadataUrl(endpoint)).pipe(
|
|
605
|
+
HttpClientRequest.setHeader("accept", "application/json")
|
|
606
|
+
)
|
|
607
|
+
).pipe(Effect5.timeout(Duration.millis(timeoutMs)));
|
|
608
|
+
if (response.status < 200 || response.status >= 300) return false;
|
|
609
|
+
const body = yield* response.text.pipe(
|
|
610
|
+
Effect5.timeout(Duration.millis(timeoutMs)),
|
|
611
|
+
Effect5.catch(() => Effect5.succeed(""))
|
|
612
|
+
);
|
|
613
|
+
const metadata = decodeProtectedResourceMetadata(body);
|
|
614
|
+
if (Option4.isNone(metadata)) return false;
|
|
615
|
+
if (metadata.value.authorization_servers.length === 0) return false;
|
|
616
|
+
return resourceMatchesEndpoint(metadata.value.resource, endpoint);
|
|
617
|
+
}).pipe(Effect5.catch(() => Effect5.succeed(false)));
|
|
811
618
|
var ErrorMessageShape = Schema4.Struct({ message: Schema4.String });
|
|
812
619
|
var decodeErrorMessageShape = Schema4.decodeUnknownOption(ErrorMessageShape);
|
|
813
620
|
var reasonFromBoundaryCause = (cause) => {
|
|
@@ -836,6 +643,9 @@ var probeMcpEndpointShape = (endpoint, options = {}) => Effect5.gen(function* ()
|
|
|
836
643
|
if (response.status === 401) {
|
|
837
644
|
const wwwAuth = readHeader(response.headers, "www-authenticate");
|
|
838
645
|
if (!wwwAuth || !/^\s*bearer\b/i.test(wwwAuth)) {
|
|
646
|
+
if (yield* probeProtectedResourceMetadata(client, url, timeoutMs)) {
|
|
647
|
+
return { kind: "mcp", requiresAuth: true };
|
|
648
|
+
}
|
|
839
649
|
return {
|
|
840
650
|
kind: "not-mcp",
|
|
841
651
|
category: "auth-required",
|
|
@@ -851,6 +661,9 @@ var probeMcpEndpointShape = (endpoint, options = {}) => Effect5.gen(function* ()
|
|
|
851
661
|
if (isSse) return { kind: "mcp", requiresAuth: true };
|
|
852
662
|
const body = yield* readBody(response);
|
|
853
663
|
if (!isJsonRpcEnvelope(body) && !isOAuthErrorBody(body)) {
|
|
664
|
+
if (yield* probeProtectedResourceMetadata(client, url, timeoutMs)) {
|
|
665
|
+
return { kind: "mcp", requiresAuth: true };
|
|
666
|
+
}
|
|
854
667
|
return {
|
|
855
668
|
kind: "not-mcp",
|
|
856
669
|
category: "auth-required",
|
|
@@ -934,8 +747,117 @@ var probeMcpEndpointShape = (endpoint, options = {}) => Effect5.gen(function* ()
|
|
|
934
747
|
|
|
935
748
|
// src/sdk/plugin.ts
|
|
936
749
|
import {
|
|
937
|
-
|
|
750
|
+
headerToConfigValue
|
|
938
751
|
} from "@executor-js/config";
|
|
752
|
+
var McpConfigureSourcePayloadSchema = Schema5.Struct({
|
|
753
|
+
name: Schema5.optional(Schema5.String),
|
|
754
|
+
endpoint: Schema5.optional(Schema5.String),
|
|
755
|
+
headers: Schema5.optional(Schema5.Record(Schema5.String, McpCredentialInput)),
|
|
756
|
+
queryParams: Schema5.optional(Schema5.Record(Schema5.String, McpCredentialInput)),
|
|
757
|
+
auth: Schema5.optional(McpConnectionAuthInput)
|
|
758
|
+
});
|
|
759
|
+
var McpConfigureSourceInputSchema = Schema5.Struct({
|
|
760
|
+
scope: Schema5.String,
|
|
761
|
+
...McpConfigureSourcePayloadSchema.fields
|
|
762
|
+
});
|
|
763
|
+
var McpInitialCredentialsInputSchema = Schema5.Struct({
|
|
764
|
+
scope: Schema5.String,
|
|
765
|
+
headers: Schema5.optional(Schema5.Record(Schema5.String, McpCredentialInput)),
|
|
766
|
+
queryParams: Schema5.optional(Schema5.Record(Schema5.String, McpCredentialInput)),
|
|
767
|
+
auth: Schema5.optional(McpConnectionAuthInput)
|
|
768
|
+
});
|
|
769
|
+
var McpRemoteAddSourceInputSchema = Schema5.Struct({
|
|
770
|
+
transport: Schema5.Literal("remote"),
|
|
771
|
+
name: Schema5.String,
|
|
772
|
+
endpoint: Schema5.String,
|
|
773
|
+
remoteTransport: Schema5.optional(McpRemoteTransport),
|
|
774
|
+
queryParams: Schema5.optional(Schema5.Record(Schema5.String, McpConfiguredValueInput)),
|
|
775
|
+
headers: Schema5.optional(Schema5.Record(Schema5.String, McpConfiguredValueInput)),
|
|
776
|
+
namespace: Schema5.optional(Schema5.String),
|
|
777
|
+
oauth2: Schema5.optional(OAuth2SourceConfig),
|
|
778
|
+
credentials: Schema5.optional(McpInitialCredentialsInputSchema)
|
|
779
|
+
});
|
|
780
|
+
var McpStdioAddSourceInputSchema = Schema5.Struct({
|
|
781
|
+
transport: Schema5.Literal("stdio"),
|
|
782
|
+
name: Schema5.String,
|
|
783
|
+
command: Schema5.String,
|
|
784
|
+
args: Schema5.optional(Schema5.Array(Schema5.String)),
|
|
785
|
+
env: Schema5.optional(Schema5.Record(Schema5.String, Schema5.String)),
|
|
786
|
+
cwd: Schema5.optional(Schema5.String),
|
|
787
|
+
namespace: Schema5.optional(Schema5.String)
|
|
788
|
+
});
|
|
789
|
+
var McpAddSourceInputSchema = Schema5.Union([
|
|
790
|
+
McpRemoteAddSourceInputSchema,
|
|
791
|
+
McpStdioAddSourceInputSchema
|
|
792
|
+
]);
|
|
793
|
+
var McpAddSourceOutputSchema = Schema5.Struct({
|
|
794
|
+
namespace: Schema5.String,
|
|
795
|
+
source: Schema5.Struct({
|
|
796
|
+
id: Schema5.String,
|
|
797
|
+
scope: Schema5.String
|
|
798
|
+
}),
|
|
799
|
+
toolCount: Schema5.Number,
|
|
800
|
+
discovery: Schema5.optional(
|
|
801
|
+
Schema5.Struct({
|
|
802
|
+
status: Schema5.Literals(["ok", "failed"]),
|
|
803
|
+
message: Schema5.optional(Schema5.String),
|
|
804
|
+
stage: Schema5.optional(Schema5.String)
|
|
805
|
+
})
|
|
806
|
+
)
|
|
807
|
+
});
|
|
808
|
+
var McpProbeEndpointInputSchema = Schema5.Struct({
|
|
809
|
+
endpoint: Schema5.String,
|
|
810
|
+
headers: Schema5.optional(Schema5.Record(Schema5.String, SecretBackedValue)),
|
|
811
|
+
queryParams: Schema5.optional(Schema5.Record(Schema5.String, SecretBackedValue))
|
|
812
|
+
});
|
|
813
|
+
var McpProbeEndpointOutputSchema = Schema5.Struct({
|
|
814
|
+
connected: Schema5.Boolean,
|
|
815
|
+
requiresOAuth: Schema5.Boolean,
|
|
816
|
+
supportsDynamicRegistration: Schema5.Boolean,
|
|
817
|
+
name: Schema5.String,
|
|
818
|
+
namespace: Schema5.String,
|
|
819
|
+
toolCount: Schema5.NullOr(Schema5.Number),
|
|
820
|
+
serverName: Schema5.NullOr(Schema5.String)
|
|
821
|
+
});
|
|
822
|
+
var McpGetSourceInputSchema = Schema5.Struct({
|
|
823
|
+
namespace: Schema5.String,
|
|
824
|
+
scope: Schema5.String
|
|
825
|
+
});
|
|
826
|
+
var McpGetSourceOutputSchema = Schema5.Struct({
|
|
827
|
+
source: Schema5.NullOr(Schema5.Unknown)
|
|
828
|
+
});
|
|
829
|
+
var McpStaticConfigureSourceInputSchema = Schema5.Struct({
|
|
830
|
+
source: Schema5.Struct({
|
|
831
|
+
id: Schema5.String,
|
|
832
|
+
scope: Schema5.String
|
|
833
|
+
}),
|
|
834
|
+
scope: Schema5.String,
|
|
835
|
+
...McpConfigureSourcePayloadSchema.fields
|
|
836
|
+
});
|
|
837
|
+
var McpStaticConfigureSourceOutputSchema = Schema5.Struct({
|
|
838
|
+
configured: Schema5.Boolean
|
|
839
|
+
});
|
|
840
|
+
var schemaToStaticToolSchema = (schema) => Schema5.toStandardSchemaV1(Schema5.toStandardJSONSchemaV1(schema));
|
|
841
|
+
var mcpToolFailure = (code, message, details) => ToolResult.fail({
|
|
842
|
+
code,
|
|
843
|
+
message,
|
|
844
|
+
...details === void 0 ? {} : { details }
|
|
845
|
+
});
|
|
846
|
+
var McpAddSourceInputStandardSchema = schemaToStaticToolSchema(McpAddSourceInputSchema);
|
|
847
|
+
var McpAddSourceOutputStandardSchema = schemaToStaticToolSchema(McpAddSourceOutputSchema);
|
|
848
|
+
var McpProbeEndpointInputStandardSchema = schemaToStaticToolSchema(McpProbeEndpointInputSchema);
|
|
849
|
+
var McpProbeEndpointOutputStandardSchema = schemaToStaticToolSchema(McpProbeEndpointOutputSchema);
|
|
850
|
+
var McpGetSourceInputStandardSchema = schemaToStaticToolSchema(McpGetSourceInputSchema);
|
|
851
|
+
var McpGetSourceOutputStandardSchema = schemaToStaticToolSchema(McpGetSourceOutputSchema);
|
|
852
|
+
var McpStaticConfigureSourceInputStandardSchema = schemaToStaticToolSchema(
|
|
853
|
+
McpStaticConfigureSourceInputSchema
|
|
854
|
+
);
|
|
855
|
+
var McpStaticConfigureSourceOutputStandardSchema = schemaToStaticToolSchema(
|
|
856
|
+
McpStaticConfigureSourceOutputSchema
|
|
857
|
+
);
|
|
858
|
+
var resolveStaticScopeInput = (ctx, value) => String(
|
|
859
|
+
ctx.scopes.find((scope) => scope.name === value || String(scope.id) === value)?.id ?? value
|
|
860
|
+
);
|
|
939
861
|
var toStoredSourceData = (config, remoteCredentials) => {
|
|
940
862
|
if (config.transport === "stdio") {
|
|
941
863
|
return {
|
|
@@ -969,6 +891,22 @@ var toBinding = (entry) => McpToolBinding.make({
|
|
|
969
891
|
annotations: entry.annotations
|
|
970
892
|
});
|
|
971
893
|
var MCP_PLUGIN_ID = "mcp";
|
|
894
|
+
var McpTextContent = Schema5.Struct({ type: Schema5.Literal("text"), text: Schema5.String });
|
|
895
|
+
var McpToolCallEnvelope = Schema5.Struct({
|
|
896
|
+
isError: Schema5.optional(Schema5.Boolean),
|
|
897
|
+
content: Schema5.optional(Schema5.Array(Schema5.Unknown))
|
|
898
|
+
});
|
|
899
|
+
var decodeMcpTextContent = Schema5.decodeUnknownOption(McpTextContent);
|
|
900
|
+
var decodeMcpToolCallEnvelope = Schema5.decodeUnknownOption(McpToolCallEnvelope);
|
|
901
|
+
var extractMcpErrorMessage = (content) => {
|
|
902
|
+
if (Array.isArray(content)) {
|
|
903
|
+
for (const item of content) {
|
|
904
|
+
const decoded = Option5.getOrUndefined(decodeMcpTextContent(item));
|
|
905
|
+
if (decoded !== void 0 && decoded.text.length > 0) return decoded.text;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
return "MCP tool returned an error";
|
|
909
|
+
};
|
|
972
910
|
var urlMatchesToken = (url, token) => {
|
|
973
911
|
const re = new RegExp(`(?:^|[^a-z0-9])${token}(?:$|[^a-z0-9])`, "i");
|
|
974
912
|
return re.test(url.hostname) || re.test(url.pathname);
|
|
@@ -991,26 +929,6 @@ var userFacingProbeMessage = (shape) => {
|
|
|
991
929
|
};
|
|
992
930
|
var scopeRanks = (ctx) => new Map(ctx.scopes.map((scope, index) => [String(scope.id), index]));
|
|
993
931
|
var scopeRank = (ranks, scopeId) => ranks.get(scopeId) ?? Infinity;
|
|
994
|
-
var coreBindingToMcpBinding = (binding) => McpSourceBindingRef.make({
|
|
995
|
-
sourceId: binding.sourceId,
|
|
996
|
-
sourceScopeId: binding.sourceScopeId,
|
|
997
|
-
scopeId: binding.scopeId,
|
|
998
|
-
slot: binding.slotKey,
|
|
999
|
-
value: binding.value,
|
|
1000
|
-
createdAt: binding.createdAt,
|
|
1001
|
-
updatedAt: binding.updatedAt
|
|
1002
|
-
});
|
|
1003
|
-
var listMcpSourceBindings = (ctx, sourceId, sourceScope) => Effect6.gen(function* () {
|
|
1004
|
-
const ranks = scopeRanks(ctx);
|
|
1005
|
-
const sourceSourceRank = scopeRank(ranks, sourceScope);
|
|
1006
|
-
if (sourceSourceRank === Infinity) return [];
|
|
1007
|
-
const bindings = yield* ctx.credentialBindings.listForSource({
|
|
1008
|
-
pluginId: MCP_PLUGIN_ID,
|
|
1009
|
-
sourceId,
|
|
1010
|
-
sourceScope: ScopeId.make(sourceScope)
|
|
1011
|
-
});
|
|
1012
|
-
return bindings.filter((binding) => scopeRank(ranks, binding.scopeId) <= sourceSourceRank).map(coreBindingToMcpBinding);
|
|
1013
|
-
});
|
|
1014
932
|
var resolveMcpSourceBinding = (ctx, sourceId, sourceScope, slot) => Effect6.gen(function* () {
|
|
1015
933
|
const ranks = scopeRanks(ctx);
|
|
1016
934
|
const sourceSourceRank = scopeRank(ranks, sourceScope);
|
|
@@ -1023,7 +941,7 @@ var resolveMcpSourceBinding = (ctx, sourceId, sourceScope, slot) => Effect6.gen(
|
|
|
1023
941
|
const binding = bindings.filter(
|
|
1024
942
|
(candidate) => candidate.slotKey === slot && scopeRank(ranks, candidate.scopeId) <= sourceSourceRank
|
|
1025
943
|
).sort((a, b) => scopeRank(ranks, a.scopeId) - scopeRank(ranks, b.scopeId))[0];
|
|
1026
|
-
return binding
|
|
944
|
+
return binding ?? null;
|
|
1027
945
|
});
|
|
1028
946
|
var validateMcpBindingTarget = (ctx, input) => Effect6.gen(function* () {
|
|
1029
947
|
const ranks = scopeRanks(ctx);
|
|
@@ -1049,108 +967,64 @@ var validateMcpBindingTarget = (ctx, input) => Effect6.gen(function* () {
|
|
|
1049
967
|
});
|
|
1050
968
|
}
|
|
1051
969
|
});
|
|
1052
|
-
var
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
return Effect6.fail(
|
|
1056
|
-
new McpConnectionError({
|
|
1057
|
-
transport: "remote",
|
|
1058
|
-
message: "credentialTargetScope is required when adding direct MCP credentials"
|
|
1059
|
-
})
|
|
1060
|
-
);
|
|
1061
|
-
};
|
|
1062
|
-
var targetScopeForBinding = (fallbackTargetScope, binding) => {
|
|
1063
|
-
const targetScope = binding.targetScope ?? fallbackTargetScope;
|
|
1064
|
-
if (targetScope) return Effect6.succeed(targetScope);
|
|
1065
|
-
return Effect6.fail(
|
|
1066
|
-
new McpConnectionError({
|
|
1067
|
-
transport: "remote",
|
|
1068
|
-
message: "credentialTargetScope is required when adding direct MCP credentials"
|
|
1069
|
-
})
|
|
1070
|
-
);
|
|
1071
|
-
};
|
|
1072
|
-
var canonicalizeCredentialMap = (values, slotForName) => {
|
|
1073
|
-
const nextValues = {};
|
|
1074
|
-
const bindings = [];
|
|
970
|
+
var canonicalizeCredentialMap = compileHttpNamedCredentialMap;
|
|
971
|
+
var canonicalizeConfiguredValueMap = (values, slotForName) => {
|
|
972
|
+
const next = {};
|
|
1075
973
|
for (const [name, value] of Object.entries(values ?? {})) {
|
|
1076
974
|
if (typeof value === "string") {
|
|
1077
|
-
|
|
975
|
+
next[name] = value;
|
|
1078
976
|
continue;
|
|
1079
977
|
}
|
|
1080
|
-
|
|
1081
|
-
nextValues[name] = value;
|
|
1082
|
-
continue;
|
|
1083
|
-
}
|
|
1084
|
-
const slot = slotForName(name);
|
|
1085
|
-
nextValues[name] = ConfiguredCredentialBinding2.make({
|
|
978
|
+
next[name] = {
|
|
1086
979
|
kind: "binding",
|
|
1087
|
-
slot,
|
|
980
|
+
slot: slotForName(name),
|
|
1088
981
|
prefix: value.prefix
|
|
1089
|
-
}
|
|
1090
|
-
bindings.push({
|
|
1091
|
-
slot,
|
|
1092
|
-
targetScope: "targetScope" in value ? value.targetScope : void 0,
|
|
1093
|
-
value: {
|
|
1094
|
-
kind: "secret",
|
|
1095
|
-
secretId: SecretId.make(value.secretId),
|
|
1096
|
-
..."secretScopeId" in value && value.secretScopeId ? { secretScopeId: value.secretScopeId } : {}
|
|
1097
|
-
}
|
|
1098
|
-
});
|
|
982
|
+
};
|
|
1099
983
|
}
|
|
1100
|
-
return
|
|
984
|
+
return next;
|
|
1101
985
|
};
|
|
1102
|
-
var
|
|
1103
|
-
if (!
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
auth: {
|
|
1108
|
-
kind: "header",
|
|
1109
|
-
headerName: auth.headerName,
|
|
1110
|
-
secretSlot: MCP_HEADER_AUTH_SLOT,
|
|
1111
|
-
prefix: auth.prefix
|
|
1112
|
-
},
|
|
1113
|
-
bindings: [
|
|
1114
|
-
{
|
|
1115
|
-
slot: MCP_HEADER_AUTH_SLOT,
|
|
1116
|
-
targetScope: auth.targetScope,
|
|
1117
|
-
value: {
|
|
1118
|
-
kind: "secret",
|
|
1119
|
-
secretId: SecretId.make(auth.secretId),
|
|
1120
|
-
...auth.secretScopeId ? { secretScopeId: auth.secretScopeId } : {}
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
]
|
|
1124
|
-
};
|
|
986
|
+
var resolveConfiguredValueMap = (values) => {
|
|
987
|
+
if (!values) return void 0;
|
|
988
|
+
const resolved = {};
|
|
989
|
+
for (const [name, value] of Object.entries(values)) {
|
|
990
|
+
if (typeof value === "string") resolved[name] = value;
|
|
1125
991
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
992
|
+
return Object.keys(resolved).length > 0 ? resolved : void 0;
|
|
993
|
+
};
|
|
994
|
+
var authFromOAuth2Source = (oauth2) => oauth2 ? {
|
|
995
|
+
kind: "oauth2",
|
|
996
|
+
connectionSlot: oauth2.connectionSlot,
|
|
997
|
+
clientIdSlot: oauth2.clientIdSlot,
|
|
998
|
+
...oauth2.clientSecretSlot ? { clientSecretSlot: oauth2.clientSecretSlot } : {}
|
|
999
|
+
} : { kind: "none" };
|
|
1000
|
+
var canonicalizeAuth = (auth) => {
|
|
1001
|
+
if (!auth || "kind" in auth || !auth.oauth2) return { auth: { kind: "none" }, bindings: [] };
|
|
1002
|
+
const oauth = auth.oauth2;
|
|
1003
|
+
const bindings = [];
|
|
1004
|
+
if (oauth.connection) {
|
|
1005
|
+
bindings.push({
|
|
1129
1006
|
slot: MCP_OAUTH_CONNECTION_SLOT,
|
|
1130
|
-
value:
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
}
|
|
1135
|
-
];
|
|
1136
|
-
if (auth.clientIdSecretId) {
|
|
1007
|
+
value: httpCredentialInputToBindingValue(oauth.connection)
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
if (oauth.clientId) {
|
|
1137
1011
|
bindings.push({
|
|
1138
1012
|
slot: MCP_OAUTH_CLIENT_ID_SLOT,
|
|
1139
|
-
value:
|
|
1013
|
+
value: httpCredentialInputToBindingValue(oauth.clientId)
|
|
1140
1014
|
});
|
|
1141
1015
|
}
|
|
1142
|
-
if (
|
|
1016
|
+
if (oauth.clientSecret) {
|
|
1143
1017
|
bindings.push({
|
|
1144
1018
|
slot: MCP_OAUTH_CLIENT_SECRET_SLOT,
|
|
1145
|
-
value:
|
|
1019
|
+
value: httpCredentialInputToBindingValue(oauth.clientSecret)
|
|
1146
1020
|
});
|
|
1147
1021
|
}
|
|
1148
1022
|
return {
|
|
1149
1023
|
auth: {
|
|
1150
1024
|
kind: "oauth2",
|
|
1151
1025
|
connectionSlot: MCP_OAUTH_CONNECTION_SLOT,
|
|
1152
|
-
...
|
|
1153
|
-
...
|
|
1026
|
+
...oauth.clientId ? { clientIdSlot: MCP_OAUTH_CLIENT_ID_SLOT } : {},
|
|
1027
|
+
...oauth.clientSecret ? { clientSecretSlot: MCP_OAUTH_CLIENT_SECRET_SLOT } : {}
|
|
1154
1028
|
},
|
|
1155
1029
|
bindings
|
|
1156
1030
|
};
|
|
@@ -1189,21 +1063,32 @@ var resolveSecretBackedMap = (values, ctx) => resolveSharedSecretBackedMap({
|
|
|
1189
1063
|
transport: "remote",
|
|
1190
1064
|
message: `Failed to resolve secret "${value.secretId}"`
|
|
1191
1065
|
}),
|
|
1192
|
-
onError: (err, _name, value) =>
|
|
1066
|
+
onError: (err, _name, value) => Predicate3.isTagged("SecretOwnedByConnectionError")(err) ? new McpConnectionError({
|
|
1193
1067
|
transport: "remote",
|
|
1194
1068
|
message: `Failed to resolve secret "${value.secretId}"`
|
|
1195
1069
|
}) : err
|
|
1196
1070
|
}).pipe(
|
|
1197
1071
|
Effect6.mapError(
|
|
1198
|
-
(err) =>
|
|
1072
|
+
(err) => Predicate3.isTagged("SecretOwnedByConnectionError")(err) ? new McpConnectionError({ transport: "remote", message: "Failed to resolve secret" }) : err
|
|
1199
1073
|
)
|
|
1200
1074
|
);
|
|
1201
|
-
var
|
|
1075
|
+
var credentialInputMapToConfigValues = (values) => {
|
|
1202
1076
|
if (!values) return void 0;
|
|
1203
|
-
const
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1077
|
+
const out = {};
|
|
1078
|
+
for (const [name, value] of Object.entries(values)) {
|
|
1079
|
+
if (typeof value === "string") {
|
|
1080
|
+
out[name] = value;
|
|
1081
|
+
continue;
|
|
1082
|
+
}
|
|
1083
|
+
if (value.kind === "secret" && "secretId" in value) {
|
|
1084
|
+
out[name] = headerToConfigValue({ secretId: value.secretId, prefix: value.prefix });
|
|
1085
|
+
continue;
|
|
1086
|
+
}
|
|
1087
|
+
if (value.kind === "text") {
|
|
1088
|
+
out[name] = value.prefix ? `${value.prefix}${value.text}` : value.text;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
1207
1092
|
};
|
|
1208
1093
|
var resolveMcpBindingValueMap = (ctx, values, params) => Effect6.gen(function* () {
|
|
1209
1094
|
if (!values) return void 0;
|
|
@@ -1251,49 +1136,58 @@ var resolveMcpBindingValueMap = (ctx, values, params) => Effect6.gen(function* (
|
|
|
1251
1136
|
}
|
|
1252
1137
|
return Object.keys(resolved).length > 0 ? resolved : void 0;
|
|
1253
1138
|
});
|
|
1254
|
-
var
|
|
1255
|
-
|
|
1139
|
+
var resolveInitialMcpCredentialValueMap = (ctx, values, bindings, targetScope, missingLabel) => Effect6.gen(function* () {
|
|
1140
|
+
const bySlot = new Map(bindings.map((binding) => [binding.slot, binding.value]));
|
|
1256
1141
|
const resolved = {};
|
|
1257
1142
|
for (const [name, value] of Object.entries(values)) {
|
|
1258
1143
|
if (typeof value === "string") {
|
|
1259
1144
|
resolved[name] = value;
|
|
1260
1145
|
continue;
|
|
1261
1146
|
}
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1147
|
+
const binding = bySlot.get(value.slot);
|
|
1148
|
+
if (binding?.kind === "secret") {
|
|
1149
|
+
const secret = yield* ctx.secrets.getAtScope(binding.secretId, binding.secretScopeId ?? ScopeId.make(targetScope)).pipe(
|
|
1150
|
+
Effect6.catchTag(
|
|
1151
|
+
"SecretOwnedByConnectionError",
|
|
1152
|
+
() => Effect6.fail(
|
|
1153
|
+
new McpConnectionError({
|
|
1154
|
+
transport: "remote",
|
|
1155
|
+
message: `Failed to resolve secret for ${missingLabel} "${name}"`
|
|
1156
|
+
})
|
|
1157
|
+
)
|
|
1158
|
+
)
|
|
1271
1159
|
);
|
|
1272
|
-
if (
|
|
1160
|
+
if (secret === null) {
|
|
1161
|
+
return yield* new McpConnectionError({
|
|
1162
|
+
transport: "remote",
|
|
1163
|
+
message: `Missing secret "${binding.secretId}" for ${missingLabel} "${name}"`
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
resolved[name] = value.prefix ? `${value.prefix}${secret}` : secret;
|
|
1273
1167
|
continue;
|
|
1274
1168
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
Effect6.catchTag(
|
|
1278
|
-
"SecretOwnedByConnectionError",
|
|
1279
|
-
() => Effect6.fail(
|
|
1280
|
-
new McpConnectionError({
|
|
1281
|
-
transport: "remote",
|
|
1282
|
-
message: `Failed to resolve secret for ${params.missingLabel} "${name}"`
|
|
1283
|
-
})
|
|
1284
|
-
)
|
|
1285
|
-
)
|
|
1286
|
-
);
|
|
1287
|
-
if (secret === null) {
|
|
1288
|
-
return yield* new McpConnectionError({
|
|
1289
|
-
transport: "remote",
|
|
1290
|
-
message: `Missing secret "${value.secretId}" for ${params.missingLabel} "${name}"`
|
|
1291
|
-
});
|
|
1169
|
+
if (binding?.kind === "text") {
|
|
1170
|
+
resolved[name] = value.prefix ? `${value.prefix}${binding.text}` : binding.text;
|
|
1292
1171
|
}
|
|
1293
|
-
resolved[name] = value.prefix ? `${value.prefix}${secret}` : secret;
|
|
1294
1172
|
}
|
|
1295
1173
|
return Object.keys(resolved).length > 0 ? resolved : void 0;
|
|
1296
1174
|
});
|
|
1175
|
+
var resolveInitialMcpOauthProvider = (ctx, bindings, targetScope) => Effect6.gen(function* () {
|
|
1176
|
+
const connection = bindings.find(
|
|
1177
|
+
(binding) => binding.slot === MCP_OAUTH_CONNECTION_SLOT && binding.value.kind === "connection"
|
|
1178
|
+
);
|
|
1179
|
+
if (!connection || connection.value.kind !== "connection") return void 0;
|
|
1180
|
+
const connectionId = connection.value.connectionId;
|
|
1181
|
+
const accessToken = yield* ctx.connections.accessTokenAtScope(connectionId, ScopeId.make(targetScope)).pipe(
|
|
1182
|
+
Effect6.mapError(
|
|
1183
|
+
({ message }) => new McpConnectionError({
|
|
1184
|
+
transport: "remote",
|
|
1185
|
+
message: `Failed to resolve OAuth connection "${connectionId}": ${message}`
|
|
1186
|
+
})
|
|
1187
|
+
)
|
|
1188
|
+
);
|
|
1189
|
+
return makeOAuthProvider(accessToken);
|
|
1190
|
+
});
|
|
1297
1191
|
var resolveMcpHeaderAuth = (ctx, sourceId, sourceScope, auth) => Effect6.gen(function* () {
|
|
1298
1192
|
if (auth.kind !== "header") return {};
|
|
1299
1193
|
const binding = yield* resolveMcpSourceBinding(ctx, sourceId, sourceScope, auth.secretSlot);
|
|
@@ -1347,60 +1241,6 @@ var resolveMcpStoredOauthProvider = (ctx, sourceId, sourceScope, auth) => Effect
|
|
|
1347
1241
|
);
|
|
1348
1242
|
return makeOAuthProvider(accessToken);
|
|
1349
1243
|
});
|
|
1350
|
-
var resolveMcpInputAuth = (ctx, sourceId, sourceScope, targetScope, auth) => Effect6.gen(function* () {
|
|
1351
|
-
if (!auth || auth.kind === "none") return { headers: {} };
|
|
1352
|
-
if (auth.kind === "header") {
|
|
1353
|
-
if ("secretSlot" in auth) {
|
|
1354
|
-
const headers = yield* resolveMcpHeaderAuth(ctx, sourceId, sourceScope, auth);
|
|
1355
|
-
return { headers };
|
|
1356
|
-
}
|
|
1357
|
-
const secretScope = auth.secretScopeId ?? auth.targetScope ?? targetScope ?? sourceScope;
|
|
1358
|
-
const secret = yield* ctx.secrets.getAtScope(SecretId.make(auth.secretId), secretScope).pipe(
|
|
1359
|
-
Effect6.catchTag(
|
|
1360
|
-
"SecretOwnedByConnectionError",
|
|
1361
|
-
() => Effect6.fail(
|
|
1362
|
-
new McpConnectionError({
|
|
1363
|
-
transport: "remote",
|
|
1364
|
-
message: `Failed to resolve secret "${auth.secretId}"`
|
|
1365
|
-
})
|
|
1366
|
-
)
|
|
1367
|
-
)
|
|
1368
|
-
);
|
|
1369
|
-
if (secret === null) {
|
|
1370
|
-
return yield* new McpConnectionError({
|
|
1371
|
-
transport: "remote",
|
|
1372
|
-
message: `Failed to resolve secret "${auth.secretId}"`
|
|
1373
|
-
});
|
|
1374
|
-
}
|
|
1375
|
-
return {
|
|
1376
|
-
headers: { [auth.headerName]: auth.prefix ? `${auth.prefix}${secret}` : secret }
|
|
1377
|
-
};
|
|
1378
|
-
}
|
|
1379
|
-
const connection = "connectionId" in auth ? { id: ConnectionId.make(auth.connectionId), scope: targetScope ?? sourceScope } : yield* Effect6.gen(function* () {
|
|
1380
|
-
const binding = yield* resolveMcpSourceBinding(
|
|
1381
|
-
ctx,
|
|
1382
|
-
sourceId,
|
|
1383
|
-
sourceScope,
|
|
1384
|
-
auth.connectionSlot
|
|
1385
|
-
);
|
|
1386
|
-
return binding?.value.kind === "connection" ? { id: binding.value.connectionId, scope: binding.scopeId } : null;
|
|
1387
|
-
});
|
|
1388
|
-
if (connection === null) {
|
|
1389
|
-
return yield* new McpConnectionError({
|
|
1390
|
-
transport: "remote",
|
|
1391
|
-
message: `Missing OAuth connection binding for MCP source "${sourceId}"`
|
|
1392
|
-
});
|
|
1393
|
-
}
|
|
1394
|
-
const accessToken = yield* ctx.connections.accessTokenAtScope(connection.id, connection.scope).pipe(
|
|
1395
|
-
Effect6.mapError(
|
|
1396
|
-
({ message }) => new McpConnectionError({
|
|
1397
|
-
transport: "remote",
|
|
1398
|
-
message: `Failed to resolve OAuth connection "${connection.id}": ${message}`
|
|
1399
|
-
})
|
|
1400
|
-
)
|
|
1401
|
-
);
|
|
1402
|
-
return { headers: {}, authProvider: makeOAuthProvider(accessToken) };
|
|
1403
|
-
});
|
|
1404
1244
|
var resolveConnectorInput = (sourceId, sourceScope, sd, ctx, allowStdio) => {
|
|
1405
1245
|
if (sd.transport === "stdio") {
|
|
1406
1246
|
if (!allowStdio) {
|
|
@@ -1478,23 +1318,16 @@ var makeRuntime = () => Effect6.gen(function* () {
|
|
|
1478
1318
|
}).pipe(Scope.provide(cacheScope));
|
|
1479
1319
|
return { connectionCache, pendingConnectors, cacheScope };
|
|
1480
1320
|
});
|
|
1481
|
-
var secretRef = (id) => `${SECRET_REF_PREFIX}${id}`;
|
|
1482
1321
|
var authToConfig = (auth) => {
|
|
1483
1322
|
if (!auth) return void 0;
|
|
1484
|
-
if (
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
return
|
|
1488
|
-
kind: "header",
|
|
1489
|
-
headerName: auth.headerName,
|
|
1490
|
-
secret: secretRef(auth.secretId),
|
|
1491
|
-
prefix: auth.prefix
|
|
1492
|
-
};
|
|
1323
|
+
if ("kind" in auth) return { kind: "none" };
|
|
1324
|
+
const connection = auth.oauth2?.connection;
|
|
1325
|
+
if (!connection || typeof connection === "string" || connection.kind !== "connection") {
|
|
1326
|
+
return void 0;
|
|
1493
1327
|
}
|
|
1494
|
-
if (!("connectionId" in auth)) return void 0;
|
|
1495
1328
|
return {
|
|
1496
1329
|
kind: "oauth2",
|
|
1497
|
-
connectionId:
|
|
1330
|
+
connectionId: connection.connectionId
|
|
1498
1331
|
};
|
|
1499
1332
|
};
|
|
1500
1333
|
var toCredentialInput = (bySlot, configured) => {
|
|
@@ -1503,7 +1336,9 @@ var toCredentialInput = (bySlot, configured) => {
|
|
|
1503
1336
|
if (!value) return void 0;
|
|
1504
1337
|
if (value.kind === "secret") {
|
|
1505
1338
|
return {
|
|
1339
|
+
kind: "secret",
|
|
1506
1340
|
secretId: value.secretId,
|
|
1341
|
+
...value.secretScopeId ? { secretScope: value.secretScopeId } : {},
|
|
1507
1342
|
...configured.prefix ? { prefix: configured.prefix } : {}
|
|
1508
1343
|
};
|
|
1509
1344
|
}
|
|
@@ -1525,15 +1360,15 @@ var toAuthInput = (bySlot, auth) => {
|
|
|
1525
1360
|
const value = bySlot.get(auth.secretSlot);
|
|
1526
1361
|
if (value?.kind !== "secret") return void 0;
|
|
1527
1362
|
return {
|
|
1528
|
-
kind: "
|
|
1529
|
-
headerName: auth.headerName,
|
|
1530
|
-
secretId: value.secretId,
|
|
1531
|
-
prefix: auth.prefix
|
|
1363
|
+
kind: "none"
|
|
1532
1364
|
};
|
|
1533
1365
|
}
|
|
1534
1366
|
const connection = bySlot.get(auth.connectionSlot);
|
|
1535
|
-
|
|
1536
|
-
|
|
1367
|
+
return {
|
|
1368
|
+
oauth2: {
|
|
1369
|
+
...connection?.kind === "connection" ? { connection: { kind: "connection", connectionId: connection.connectionId } } : {}
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1537
1372
|
};
|
|
1538
1373
|
var inputFormFromStored = (bindings, stored, scope, sourceName, namespace) => {
|
|
1539
1374
|
if (stored.transport === "stdio") {
|
|
@@ -1581,8 +1416,8 @@ var toMcpConfigEntry = (namespace, sourceName, config) => {
|
|
|
1581
1416
|
name: sourceName,
|
|
1582
1417
|
endpoint: config.endpoint,
|
|
1583
1418
|
remoteTransport: config.remoteTransport,
|
|
1584
|
-
queryParams:
|
|
1585
|
-
headers:
|
|
1419
|
+
queryParams: credentialInputMapToConfigValues(config.queryParams),
|
|
1420
|
+
headers: credentialInputMapToConfigValues(config.headers),
|
|
1586
1421
|
namespace,
|
|
1587
1422
|
auth: authToConfig(config.auth)
|
|
1588
1423
|
};
|
|
@@ -1601,6 +1436,13 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
1601
1436
|
return {
|
|
1602
1437
|
id: "mcp",
|
|
1603
1438
|
packageName: "@executor-js/plugin-mcp",
|
|
1439
|
+
sourcePresets: allowStdio ? mcpPresets.map((preset) => ({
|
|
1440
|
+
...preset,
|
|
1441
|
+
transport: "transport" in preset ? preset.transport : "remote"
|
|
1442
|
+
})) : mcpPresets.filter((preset) => !("transport" in preset && preset.transport === "stdio")).map((preset) => ({
|
|
1443
|
+
...preset,
|
|
1444
|
+
transport: "remote"
|
|
1445
|
+
})),
|
|
1604
1446
|
// Surfaced to the client bundle via the Vite plugin (see
|
|
1605
1447
|
// `@executor-js/vite-plugin`). The MCP `./client` factory reads
|
|
1606
1448
|
// `allowStdio` and gates the stdio tab + presets in AddMcpSource —
|
|
@@ -1693,72 +1535,72 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
1693
1535
|
const addSource = (config) => Effect6.gen(function* () {
|
|
1694
1536
|
const namespace = normalizeNamespace(config);
|
|
1695
1537
|
const canonicalRemote = config.transport === "remote" ? {
|
|
1696
|
-
headers:
|
|
1697
|
-
queryParams:
|
|
1698
|
-
|
|
1538
|
+
headers: canonicalizeConfiguredValueMap(config.headers, mcpHeaderSlot),
|
|
1539
|
+
queryParams: canonicalizeConfiguredValueMap(
|
|
1540
|
+
config.queryParams,
|
|
1541
|
+
mcpQueryParamSlot
|
|
1542
|
+
)
|
|
1699
1543
|
} : null;
|
|
1700
|
-
const
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1544
|
+
const initialRemote = config.transport === "remote" && config.credentials ? {
|
|
1545
|
+
scope: config.credentials.scope,
|
|
1546
|
+
headers: config.credentials.headers !== void 0 ? canonicalizeCredentialMap(config.credentials.headers, mcpHeaderSlot) : null,
|
|
1547
|
+
queryParams: config.credentials.queryParams !== void 0 ? canonicalizeCredentialMap(config.credentials.queryParams, mcpQueryParamSlot) : null,
|
|
1548
|
+
auth: config.credentials.auth !== void 0 ? canonicalizeAuth(config.credentials.auth) : null
|
|
1549
|
+
} : null;
|
|
1550
|
+
const remoteAuth = config.transport === "remote" ? config.oauth2 ? authFromOAuth2Source(config.oauth2) : initialRemote?.auth?.auth ?? { kind: "none" } : null;
|
|
1551
|
+
const remoteCredentials = canonicalRemote && remoteAuth ? {
|
|
1552
|
+
headers: canonicalRemote.headers,
|
|
1553
|
+
queryParams: canonicalRemote.queryParams,
|
|
1554
|
+
auth: remoteAuth
|
|
1555
|
+
} : void 0;
|
|
1556
|
+
const initialBindings = [
|
|
1557
|
+
...initialRemote?.headers?.bindings ?? [],
|
|
1558
|
+
...initialRemote?.queryParams?.bindings ?? [],
|
|
1559
|
+
...initialRemote?.auth?.bindings ?? []
|
|
1560
|
+
];
|
|
1561
|
+
if (initialRemote && initialBindings.length > 0) {
|
|
1710
1562
|
yield* validateMcpBindingTarget(ctx, {
|
|
1711
1563
|
sourceId: namespace,
|
|
1712
1564
|
sourceScope: config.scope,
|
|
1713
|
-
targetScope:
|
|
1565
|
+
targetScope: initialRemote.scope
|
|
1714
1566
|
});
|
|
1715
1567
|
}
|
|
1716
|
-
const
|
|
1717
|
-
const
|
|
1718
|
-
|
|
1719
|
-
canonicalRemote
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
)
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
};
|
|
1753
|
-
return {
|
|
1754
|
-
transport: "remote",
|
|
1755
|
-
endpoint: config.endpoint,
|
|
1756
|
-
remoteTransport: config.remoteTransport ?? "auto",
|
|
1757
|
-
queryParams: resolvedQueryParams,
|
|
1758
|
-
headers: Object.keys(headers).length > 0 ? headers : void 0,
|
|
1759
|
-
authProvider: resolvedAuth.authProvider
|
|
1760
|
-
};
|
|
1761
|
-
}) : resolveConnectorInput(namespace, config.scope, sd, ctx, allowStdio)).pipe(
|
|
1568
|
+
const sd = toStoredSourceData(config, remoteCredentials);
|
|
1569
|
+
const initialQueryParams = initialRemote?.queryParams && (yield* resolveInitialMcpCredentialValueMap(
|
|
1570
|
+
ctx,
|
|
1571
|
+
canonicalRemote?.queryParams ?? initialRemote.queryParams.values,
|
|
1572
|
+
initialRemote.queryParams.bindings,
|
|
1573
|
+
initialRemote.scope,
|
|
1574
|
+
"query parameter"
|
|
1575
|
+
));
|
|
1576
|
+
const initialHeaders = initialRemote?.headers && (yield* resolveInitialMcpCredentialValueMap(
|
|
1577
|
+
ctx,
|
|
1578
|
+
canonicalRemote?.headers ?? initialRemote.headers.values,
|
|
1579
|
+
initialRemote.headers.bindings,
|
|
1580
|
+
initialRemote.scope,
|
|
1581
|
+
"header"
|
|
1582
|
+
));
|
|
1583
|
+
const remoteQueryParams = {
|
|
1584
|
+
...config.transport === "remote" ? resolveConfiguredValueMap(config.queryParams) ?? {} : {},
|
|
1585
|
+
...initialQueryParams || {}
|
|
1586
|
+
};
|
|
1587
|
+
const remoteHeaders = {
|
|
1588
|
+
...config.transport === "remote" ? resolveConfiguredValueMap(config.headers) ?? {} : {},
|
|
1589
|
+
...initialHeaders || {}
|
|
1590
|
+
};
|
|
1591
|
+
const initialAuthProvider = initialRemote?.auth !== null && initialRemote?.auth !== void 0 ? yield* resolveInitialMcpOauthProvider(
|
|
1592
|
+
ctx,
|
|
1593
|
+
initialRemote.auth.bindings,
|
|
1594
|
+
initialRemote.scope
|
|
1595
|
+
) : void 0;
|
|
1596
|
+
const resolved = config.transport === "remote" ? Result.succeed({
|
|
1597
|
+
transport: "remote",
|
|
1598
|
+
endpoint: config.endpoint,
|
|
1599
|
+
remoteTransport: config.remoteTransport ?? "auto",
|
|
1600
|
+
queryParams: Object.keys(remoteQueryParams).length > 0 ? remoteQueryParams : void 0,
|
|
1601
|
+
headers: Object.keys(remoteHeaders).length > 0 ? remoteHeaders : void 0,
|
|
1602
|
+
authProvider: initialAuthProvider
|
|
1603
|
+
}) : yield* resolveConnectorInput(namespace, config.scope, sd, ctx, allowStdio).pipe(
|
|
1762
1604
|
Effect6.result,
|
|
1763
1605
|
Effect6.withSpan("mcp.plugin.resolve_connector", {
|
|
1764
1606
|
attributes: {
|
|
@@ -1818,21 +1660,22 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
1818
1660
|
outputSchema: e.outputSchema
|
|
1819
1661
|
}))
|
|
1820
1662
|
});
|
|
1821
|
-
if (
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
)
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1663
|
+
if (initialRemote && initialBindings.length > 0) {
|
|
1664
|
+
yield* ctx.credentialBindings.replaceForSource({
|
|
1665
|
+
targetScope: ScopeId.make(initialRemote.scope),
|
|
1666
|
+
pluginId: MCP_PLUGIN_ID,
|
|
1667
|
+
sourceId: namespace,
|
|
1668
|
+
sourceScope: ScopeId.make(config.scope),
|
|
1669
|
+
slotPrefixes: [
|
|
1670
|
+
...initialRemote.headers !== null ? ["header:"] : [],
|
|
1671
|
+
...initialRemote.queryParams !== null ? ["query_param:"] : [],
|
|
1672
|
+
...initialRemote.auth !== null ? ["auth:"] : []
|
|
1673
|
+
],
|
|
1674
|
+
bindings: initialBindings.map((binding) => ({
|
|
1832
1675
|
slotKey: binding.slot,
|
|
1833
1676
|
value: binding.value
|
|
1834
|
-
})
|
|
1835
|
-
}
|
|
1677
|
+
}))
|
|
1678
|
+
});
|
|
1836
1679
|
}
|
|
1837
1680
|
})
|
|
1838
1681
|
).pipe(
|
|
@@ -1955,8 +1798,25 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
1955
1798
|
attributes: { "mcp.source.namespace": namespace }
|
|
1956
1799
|
})
|
|
1957
1800
|
);
|
|
1958
|
-
const
|
|
1959
|
-
|
|
1801
|
+
const getSource = (namespace, scope) => ctx.storage.getSource(namespace, scope).pipe(
|
|
1802
|
+
Effect6.withSpan("mcp.plugin.get_source", {
|
|
1803
|
+
attributes: { "mcp.source.namespace": namespace }
|
|
1804
|
+
})
|
|
1805
|
+
);
|
|
1806
|
+
return {
|
|
1807
|
+
probeEndpoint,
|
|
1808
|
+
addSource,
|
|
1809
|
+
removeSource,
|
|
1810
|
+
refreshSource,
|
|
1811
|
+
getSource
|
|
1812
|
+
};
|
|
1813
|
+
},
|
|
1814
|
+
sourceConfigure: {
|
|
1815
|
+
type: "mcp",
|
|
1816
|
+
schema: McpConfigureSourcePayloadSchema,
|
|
1817
|
+
configure: ({ ctx, sourceId, sourceScope, targetScope, config }) => Effect6.gen(function* () {
|
|
1818
|
+
const input = config;
|
|
1819
|
+
const existing = yield* ctx.storage.getSource(sourceId, sourceScope);
|
|
1960
1820
|
if (!existing || existing.config.transport !== "remote") return;
|
|
1961
1821
|
const canonicalHeaders = input.headers !== void 0 ? canonicalizeCredentialMap(input.headers, mcpHeaderSlot) : null;
|
|
1962
1822
|
const canonicalQueryParams = input.queryParams !== void 0 ? canonicalizeCredentialMap(input.queryParams, mcpQueryParamSlot) : null;
|
|
@@ -1966,46 +1826,40 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
1966
1826
|
...canonicalQueryParams?.bindings ?? [],
|
|
1967
1827
|
...canonicalAuth?.bindings ?? []
|
|
1968
1828
|
];
|
|
1969
|
-
|
|
1970
|
-
input.credentialTargetScope,
|
|
1971
|
-
directBindings
|
|
1972
|
-
);
|
|
1973
|
-
if (targetScope) {
|
|
1829
|
+
if (directBindings.length > 0) {
|
|
1974
1830
|
yield* validateMcpBindingTarget(ctx, {
|
|
1975
|
-
sourceId
|
|
1976
|
-
sourceScope
|
|
1831
|
+
sourceId,
|
|
1832
|
+
sourceScope,
|
|
1977
1833
|
targetScope
|
|
1978
1834
|
});
|
|
1979
1835
|
}
|
|
1980
|
-
const remote = existing.config;
|
|
1981
1836
|
const updatedConfig = {
|
|
1982
|
-
...
|
|
1837
|
+
...existing.config,
|
|
1983
1838
|
...input.endpoint !== void 0 ? { endpoint: input.endpoint } : {},
|
|
1984
1839
|
...canonicalHeaders ? { headers: canonicalHeaders.values } : {},
|
|
1985
1840
|
...canonicalAuth ? { auth: canonicalAuth.auth } : {},
|
|
1986
1841
|
...canonicalQueryParams ? { queryParams: canonicalQueryParams.values } : {}
|
|
1987
1842
|
};
|
|
1988
|
-
const sourceName = input.name?.trim() || existing.name;
|
|
1989
1843
|
const affectedPrefixes = [
|
|
1990
1844
|
...input.headers !== void 0 ? ["header:"] : [],
|
|
1991
1845
|
...input.queryParams !== void 0 ? ["query_param:"] : [],
|
|
1992
1846
|
...input.auth !== void 0 ? ["auth:"] : []
|
|
1993
1847
|
];
|
|
1994
|
-
const
|
|
1848
|
+
const sourceName = input.name?.trim() || existing.name;
|
|
1995
1849
|
yield* ctx.transaction(
|
|
1996
1850
|
Effect6.gen(function* () {
|
|
1997
1851
|
yield* ctx.storage.putSource({
|
|
1998
|
-
namespace,
|
|
1999
|
-
scope,
|
|
1852
|
+
namespace: sourceId,
|
|
1853
|
+
scope: sourceScope,
|
|
2000
1854
|
name: sourceName,
|
|
2001
1855
|
config: updatedConfig
|
|
2002
1856
|
});
|
|
2003
1857
|
if (affectedPrefixes.length > 0 || directBindings.length > 0) {
|
|
2004
1858
|
yield* ctx.credentialBindings.replaceForSource({
|
|
2005
|
-
targetScope: ScopeId.make(
|
|
1859
|
+
targetScope: ScopeId.make(targetScope),
|
|
2006
1860
|
pluginId: MCP_PLUGIN_ID,
|
|
2007
|
-
sourceId
|
|
2008
|
-
sourceScope: ScopeId.make(
|
|
1861
|
+
sourceId,
|
|
1862
|
+
sourceScope: ScopeId.make(sourceScope),
|
|
2009
1863
|
slotPrefixes: affectedPrefixes,
|
|
2010
1864
|
bindings: directBindings.map((binding) => ({
|
|
2011
1865
|
slotKey: binding.slot,
|
|
@@ -2015,71 +1869,168 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
2015
1869
|
}
|
|
2016
1870
|
})
|
|
2017
1871
|
);
|
|
2018
|
-
if (configFile) {
|
|
1872
|
+
if (options?.configFile) {
|
|
2019
1873
|
const bindings = yield* ctx.credentialBindings.listForSource({
|
|
2020
1874
|
pluginId: MCP_PLUGIN_ID,
|
|
2021
|
-
sourceId
|
|
2022
|
-
sourceScope: ScopeId.make(
|
|
1875
|
+
sourceId,
|
|
1876
|
+
sourceScope: ScopeId.make(sourceScope)
|
|
2023
1877
|
});
|
|
2024
1878
|
const inputForm = inputFormFromStored(
|
|
2025
1879
|
bindings,
|
|
2026
1880
|
updatedConfig,
|
|
2027
|
-
|
|
1881
|
+
sourceScope,
|
|
2028
1882
|
sourceName,
|
|
2029
|
-
|
|
1883
|
+
sourceId
|
|
2030
1884
|
);
|
|
2031
|
-
yield* configFile.upsertSource(toMcpConfigEntry(
|
|
1885
|
+
yield* options.configFile.upsertSource(toMcpConfigEntry(sourceId, sourceName, inputForm)).pipe(Effect6.withSpan("mcp.plugin.config_file.upsert"));
|
|
2032
1886
|
}
|
|
2033
|
-
})
|
|
2034
|
-
Effect6.withSpan("mcp.plugin.update_source", {
|
|
2035
|
-
attributes: { "mcp.source.namespace": namespace }
|
|
2036
|
-
})
|
|
2037
|
-
);
|
|
2038
|
-
const getSource = (namespace, scope) => ctx.storage.getSource(namespace, scope).pipe(
|
|
2039
|
-
Effect6.withSpan("mcp.plugin.get_source", {
|
|
2040
|
-
attributes: { "mcp.source.namespace": namespace }
|
|
2041
|
-
})
|
|
2042
|
-
);
|
|
2043
|
-
return {
|
|
2044
|
-
probeEndpoint,
|
|
2045
|
-
addSource,
|
|
2046
|
-
removeSource,
|
|
2047
|
-
refreshSource,
|
|
2048
|
-
getSource,
|
|
2049
|
-
updateSource,
|
|
2050
|
-
listSourceBindings: (sourceId, sourceScope) => listMcpSourceBindings(ctx, sourceId, sourceScope),
|
|
2051
|
-
setSourceBinding: (input) => Effect6.gen(function* () {
|
|
2052
|
-
yield* validateMcpBindingTarget(ctx, {
|
|
2053
|
-
sourceId: input.sourceId,
|
|
2054
|
-
sourceScope: input.sourceScope,
|
|
2055
|
-
targetScope: input.scope
|
|
2056
|
-
});
|
|
2057
|
-
const binding = yield* ctx.credentialBindings.set({
|
|
2058
|
-
targetScope: input.scope,
|
|
2059
|
-
pluginId: MCP_PLUGIN_ID,
|
|
2060
|
-
sourceId: input.sourceId,
|
|
2061
|
-
sourceScope: input.sourceScope,
|
|
2062
|
-
slotKey: input.slot,
|
|
2063
|
-
value: input.value
|
|
2064
|
-
});
|
|
2065
|
-
return coreBindingToMcpBinding(binding);
|
|
2066
|
-
}),
|
|
2067
|
-
removeSourceBinding: (sourceId, sourceScope, slot, scope) => Effect6.gen(function* () {
|
|
2068
|
-
yield* validateMcpBindingTarget(ctx, {
|
|
2069
|
-
sourceId,
|
|
2070
|
-
sourceScope,
|
|
2071
|
-
targetScope: scope
|
|
2072
|
-
});
|
|
2073
|
-
yield* ctx.credentialBindings.remove({
|
|
2074
|
-
targetScope: ScopeId.make(scope),
|
|
2075
|
-
pluginId: MCP_PLUGIN_ID,
|
|
2076
|
-
sourceId,
|
|
2077
|
-
sourceScope: ScopeId.make(sourceScope),
|
|
2078
|
-
slotKey: slot
|
|
2079
|
-
});
|
|
2080
|
-
})
|
|
2081
|
-
};
|
|
1887
|
+
})
|
|
2082
1888
|
},
|
|
1889
|
+
staticSources: (self) => [
|
|
1890
|
+
{
|
|
1891
|
+
id: "mcp",
|
|
1892
|
+
kind: "executor",
|
|
1893
|
+
name: "MCP",
|
|
1894
|
+
tools: [
|
|
1895
|
+
tool({
|
|
1896
|
+
name: "probeEndpoint",
|
|
1897
|
+
description: "Probe a remote MCP endpoint before adding it. If the result requires OAuth, call `executor.coreTools.oauth.probe` and `executor.coreTools.oauth.start` with `credentialScope` set to the user's chosen personal or organization credential scope first, then pass the resulting connection through `addSource` credentials or `mcp.configureSource`.",
|
|
1898
|
+
inputSchema: McpProbeEndpointInputStandardSchema,
|
|
1899
|
+
outputSchema: McpProbeEndpointOutputStandardSchema,
|
|
1900
|
+
execute: (input) => self.probeEndpoint(input).pipe(
|
|
1901
|
+
Effect6.map(ToolResult.ok),
|
|
1902
|
+
Effect6.catchTag(
|
|
1903
|
+
"McpConnectionError",
|
|
1904
|
+
({ message, transport }) => Effect6.succeed(mcpToolFailure("mcp_connection_failed", message, { transport }))
|
|
1905
|
+
)
|
|
1906
|
+
)
|
|
1907
|
+
}),
|
|
1908
|
+
tool({
|
|
1909
|
+
name: "getSource",
|
|
1910
|
+
description: "Inspect an existing MCP source, including transport, endpoint/command, auth mode, configured headers/query params, and credential slots. Use this before repairing an existing source with `mcp.configureSource`, `secrets.create`, or `oauth.start`.",
|
|
1911
|
+
inputSchema: McpGetSourceInputStandardSchema,
|
|
1912
|
+
outputSchema: McpGetSourceOutputStandardSchema,
|
|
1913
|
+
execute: (input, { ctx }) => {
|
|
1914
|
+
const args = input;
|
|
1915
|
+
return Effect6.map(
|
|
1916
|
+
self.getSource(args.namespace, resolveStaticScopeInput(ctx, args.scope)),
|
|
1917
|
+
(source) => ToolResult.ok({ source })
|
|
1918
|
+
);
|
|
1919
|
+
}
|
|
1920
|
+
}),
|
|
1921
|
+
tool({
|
|
1922
|
+
name: "addSource",
|
|
1923
|
+
description: "Add an MCP source and register its tools. Executor chooses the source install scope (local scope locally, organization scope in cloud) and returns it as `source`. For remote OAuth-protected servers, first use `probeEndpoint` and the core OAuth browser handoff (`oauth.probe`, `oauth.start` with the user's chosen `credentialScope`), then bind the completed connection with `mcp.configureSource` if needed. For header/API-key auth, first call `secrets.create` at the user's chosen credential scope so the value is entered in the browser, then pass the secret reference in `credentials`. Remote sources are still saved if discovery fails; inspect the returned `discovery` field and use `sources.refresh` after credentials or network access are fixed.",
|
|
1924
|
+
annotations: {
|
|
1925
|
+
requiresApproval: true,
|
|
1926
|
+
approvalDescription: "Add an MCP source"
|
|
1927
|
+
},
|
|
1928
|
+
inputSchema: McpAddSourceInputStandardSchema,
|
|
1929
|
+
outputSchema: McpAddSourceOutputStandardSchema,
|
|
1930
|
+
execute: (rawInput, { ctx }) => {
|
|
1931
|
+
const input = rawInput;
|
|
1932
|
+
const sourceScope = defaultSourceInstallScopeId(ctx.scopes);
|
|
1933
|
+
if (sourceScope === null) {
|
|
1934
|
+
return Effect6.succeed(
|
|
1935
|
+
mcpToolFailure(
|
|
1936
|
+
"source_scope_unavailable",
|
|
1937
|
+
"Cannot add an MCP source because this executor has no source install scope."
|
|
1938
|
+
)
|
|
1939
|
+
);
|
|
1940
|
+
}
|
|
1941
|
+
const normalizedInput = {
|
|
1942
|
+
...input,
|
|
1943
|
+
scope: sourceScope
|
|
1944
|
+
};
|
|
1945
|
+
const added = self.addSource(normalizedInput).pipe(
|
|
1946
|
+
Effect6.map(
|
|
1947
|
+
(result) => ToolResult.ok({
|
|
1948
|
+
...result,
|
|
1949
|
+
source: { id: result.namespace, scope: sourceScope },
|
|
1950
|
+
discovery: { status: "ok" }
|
|
1951
|
+
})
|
|
1952
|
+
)
|
|
1953
|
+
);
|
|
1954
|
+
if (normalizedInput.transport !== "remote") return added;
|
|
1955
|
+
const savedWithDiscoveryFailure = (failure) => Effect6.succeed(
|
|
1956
|
+
ToolResult.ok({
|
|
1957
|
+
namespace: normalizedInput.namespace ?? deriveMcpNamespace({
|
|
1958
|
+
name: normalizedInput.name,
|
|
1959
|
+
endpoint: normalizedInput.endpoint
|
|
1960
|
+
}),
|
|
1961
|
+
source: {
|
|
1962
|
+
id: normalizedInput.namespace ?? deriveMcpNamespace({
|
|
1963
|
+
name: normalizedInput.name,
|
|
1964
|
+
endpoint: normalizedInput.endpoint
|
|
1965
|
+
}),
|
|
1966
|
+
scope: sourceScope
|
|
1967
|
+
},
|
|
1968
|
+
toolCount: 0,
|
|
1969
|
+
discovery: {
|
|
1970
|
+
status: "failed",
|
|
1971
|
+
message: failure.message,
|
|
1972
|
+
...failure.stage ? { stage: failure.stage } : {}
|
|
1973
|
+
}
|
|
1974
|
+
})
|
|
1975
|
+
);
|
|
1976
|
+
return added.pipe(
|
|
1977
|
+
Effect6.catchTags({
|
|
1978
|
+
McpToolDiscoveryError: savedWithDiscoveryFailure,
|
|
1979
|
+
McpConnectionError: ({ message }) => Effect6.succeed(
|
|
1980
|
+
ToolResult.ok({
|
|
1981
|
+
namespace: normalizedInput.namespace ?? deriveMcpNamespace({
|
|
1982
|
+
name: normalizedInput.name,
|
|
1983
|
+
endpoint: normalizedInput.endpoint
|
|
1984
|
+
}),
|
|
1985
|
+
source: {
|
|
1986
|
+
id: normalizedInput.namespace ?? deriveMcpNamespace({
|
|
1987
|
+
name: normalizedInput.name,
|
|
1988
|
+
endpoint: normalizedInput.endpoint
|
|
1989
|
+
}),
|
|
1990
|
+
scope: sourceScope
|
|
1991
|
+
},
|
|
1992
|
+
toolCount: 0,
|
|
1993
|
+
discovery: {
|
|
1994
|
+
status: "failed",
|
|
1995
|
+
message
|
|
1996
|
+
}
|
|
1997
|
+
})
|
|
1998
|
+
)
|
|
1999
|
+
})
|
|
2000
|
+
);
|
|
2001
|
+
}
|
|
2002
|
+
}),
|
|
2003
|
+
tool({
|
|
2004
|
+
name: "configureSource",
|
|
2005
|
+
description: 'Configure an existing remote MCP source with concrete fields. Use `source` returned by `mcp.addSource` or `sources.list`. The top-level `scope` is the credential target scope for bindings; in cloud, choose the user or organization credential scope deliberately. Pass secret refs as `{kind:"secret", secretId}` and OAuth connections as `{kind:"connection", connectionId}`.',
|
|
2006
|
+
annotations: {
|
|
2007
|
+
requiresApproval: true,
|
|
2008
|
+
approvalDescription: "Configure an MCP source"
|
|
2009
|
+
},
|
|
2010
|
+
inputSchema: McpStaticConfigureSourceInputStandardSchema,
|
|
2011
|
+
outputSchema: McpStaticConfigureSourceOutputStandardSchema,
|
|
2012
|
+
execute: (rawInput, { ctx }) => Effect6.gen(function* () {
|
|
2013
|
+
const { source, ...config } = rawInput;
|
|
2014
|
+
const sourceScope = resolveStaticScopeInput(ctx, source.scope);
|
|
2015
|
+
const targetScope = resolveStaticScopeInput(ctx, config.scope);
|
|
2016
|
+
yield* ctx.core.sources.configure({
|
|
2017
|
+
source: { id: source.id, scope: sourceScope },
|
|
2018
|
+
scope: targetScope,
|
|
2019
|
+
type: "mcp",
|
|
2020
|
+
config: {
|
|
2021
|
+
...config.name !== void 0 ? { name: config.name } : {},
|
|
2022
|
+
...config.endpoint !== void 0 ? { endpoint: config.endpoint } : {},
|
|
2023
|
+
...config.headers !== void 0 ? { headers: config.headers } : {},
|
|
2024
|
+
...config.queryParams !== void 0 ? { queryParams: config.queryParams } : {},
|
|
2025
|
+
...config.auth !== void 0 ? { auth: config.auth } : {}
|
|
2026
|
+
}
|
|
2027
|
+
});
|
|
2028
|
+
return ToolResult.ok({ configured: true });
|
|
2029
|
+
})
|
|
2030
|
+
})
|
|
2031
|
+
]
|
|
2032
|
+
}
|
|
2033
|
+
],
|
|
2083
2034
|
invokeTool: ({ ctx, toolRow, args, elicit }) => Effect6.gen(function* () {
|
|
2084
2035
|
const runtime = yield* ensureRuntime();
|
|
2085
2036
|
const toolScope = toolRow.scope_id;
|
|
@@ -2105,7 +2056,7 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
2105
2056
|
message: `No MCP source config for namespace "${entry.namespace}"`
|
|
2106
2057
|
});
|
|
2107
2058
|
}
|
|
2108
|
-
|
|
2059
|
+
const raw = yield* invokeMcpTool({
|
|
2109
2060
|
toolId: toolRow.id,
|
|
2110
2061
|
toolName: entry.binding.toolName,
|
|
2111
2062
|
args,
|
|
@@ -2140,6 +2091,15 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
2140
2091
|
pendingConnectors: runtime.pendingConnectors,
|
|
2141
2092
|
elicit
|
|
2142
2093
|
});
|
|
2094
|
+
const envelope = Option5.getOrUndefined(decodeMcpToolCallEnvelope(raw));
|
|
2095
|
+
if (envelope?.isError === true) {
|
|
2096
|
+
return ToolResult.fail({
|
|
2097
|
+
code: "mcp_tool_error",
|
|
2098
|
+
message: extractMcpErrorMessage(envelope.content),
|
|
2099
|
+
details: { content: envelope.content }
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2102
|
+
return ToolResult.ok(raw);
|
|
2143
2103
|
}).pipe(
|
|
2144
2104
|
Effect6.withSpan("mcp.plugin.invoke_tool", {
|
|
2145
2105
|
attributes: {
|
|
@@ -2206,8 +2166,8 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
2206
2166
|
// Honor upstream destructiveHint from MCP ToolAnnotations.
|
|
2207
2167
|
// Bindings are fetched per scope so shadowed sources (e.g. an org-level
|
|
2208
2168
|
// source overridden per-user) each resolve against their own scope's
|
|
2209
|
-
// row rather than collapsing onto whichever row
|
|
2210
|
-
//
|
|
2169
|
+
// row rather than collapsing onto whichever visible row would otherwise
|
|
2170
|
+
// win first.
|
|
2211
2171
|
resolveAnnotations: ({ ctx, sourceId, toolRows }) => Effect6.gen(function* () {
|
|
2212
2172
|
const scopes = new Set(toolRows.map((row) => row.scope_id));
|
|
2213
2173
|
const entries = yield* Effect6.forEach(
|
|
@@ -2274,4 +2234,4 @@ export {
|
|
|
2274
2234
|
makeMcpStore,
|
|
2275
2235
|
mcpPlugin
|
|
2276
2236
|
};
|
|
2277
|
-
//# sourceMappingURL=chunk-
|
|
2237
|
+
//# sourceMappingURL=chunk-H5PLTEMB.js.map
|