@executor-js/plugin-mcp 1.4.29 → 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-2DOCEPYN.js → chunk-H5PLTEMB.js} +632 -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-2DOCEPYN.js.map +0 -1
- package/dist/chunk-4ORPFRLI.js.map +0 -1
- package/dist/chunk-M6REVU6O.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
|
}
|
|
@@ -975,8 +747,117 @@ var probeMcpEndpointShape = (endpoint, options = {}) => Effect5.gen(function* ()
|
|
|
975
747
|
|
|
976
748
|
// src/sdk/plugin.ts
|
|
977
749
|
import {
|
|
978
|
-
|
|
750
|
+
headerToConfigValue
|
|
979
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
|
+
);
|
|
980
861
|
var toStoredSourceData = (config, remoteCredentials) => {
|
|
981
862
|
if (config.transport === "stdio") {
|
|
982
863
|
return {
|
|
@@ -1010,6 +891,22 @@ var toBinding = (entry) => McpToolBinding.make({
|
|
|
1010
891
|
annotations: entry.annotations
|
|
1011
892
|
});
|
|
1012
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
|
+
};
|
|
1013
910
|
var urlMatchesToken = (url, token) => {
|
|
1014
911
|
const re = new RegExp(`(?:^|[^a-z0-9])${token}(?:$|[^a-z0-9])`, "i");
|
|
1015
912
|
return re.test(url.hostname) || re.test(url.pathname);
|
|
@@ -1032,26 +929,6 @@ var userFacingProbeMessage = (shape) => {
|
|
|
1032
929
|
};
|
|
1033
930
|
var scopeRanks = (ctx) => new Map(ctx.scopes.map((scope, index) => [String(scope.id), index]));
|
|
1034
931
|
var scopeRank = (ranks, scopeId) => ranks.get(scopeId) ?? Infinity;
|
|
1035
|
-
var coreBindingToMcpBinding = (binding) => McpSourceBindingRef.make({
|
|
1036
|
-
sourceId: binding.sourceId,
|
|
1037
|
-
sourceScopeId: binding.sourceScopeId,
|
|
1038
|
-
scopeId: binding.scopeId,
|
|
1039
|
-
slot: binding.slotKey,
|
|
1040
|
-
value: binding.value,
|
|
1041
|
-
createdAt: binding.createdAt,
|
|
1042
|
-
updatedAt: binding.updatedAt
|
|
1043
|
-
});
|
|
1044
|
-
var listMcpSourceBindings = (ctx, sourceId, sourceScope) => Effect6.gen(function* () {
|
|
1045
|
-
const ranks = scopeRanks(ctx);
|
|
1046
|
-
const sourceSourceRank = scopeRank(ranks, sourceScope);
|
|
1047
|
-
if (sourceSourceRank === Infinity) return [];
|
|
1048
|
-
const bindings = yield* ctx.credentialBindings.listForSource({
|
|
1049
|
-
pluginId: MCP_PLUGIN_ID,
|
|
1050
|
-
sourceId,
|
|
1051
|
-
sourceScope: ScopeId.make(sourceScope)
|
|
1052
|
-
});
|
|
1053
|
-
return bindings.filter((binding) => scopeRank(ranks, binding.scopeId) <= sourceSourceRank).map(coreBindingToMcpBinding);
|
|
1054
|
-
});
|
|
1055
932
|
var resolveMcpSourceBinding = (ctx, sourceId, sourceScope, slot) => Effect6.gen(function* () {
|
|
1056
933
|
const ranks = scopeRanks(ctx);
|
|
1057
934
|
const sourceSourceRank = scopeRank(ranks, sourceScope);
|
|
@@ -1064,7 +941,7 @@ var resolveMcpSourceBinding = (ctx, sourceId, sourceScope, slot) => Effect6.gen(
|
|
|
1064
941
|
const binding = bindings.filter(
|
|
1065
942
|
(candidate) => candidate.slotKey === slot && scopeRank(ranks, candidate.scopeId) <= sourceSourceRank
|
|
1066
943
|
).sort((a, b) => scopeRank(ranks, a.scopeId) - scopeRank(ranks, b.scopeId))[0];
|
|
1067
|
-
return binding
|
|
944
|
+
return binding ?? null;
|
|
1068
945
|
});
|
|
1069
946
|
var validateMcpBindingTarget = (ctx, input) => Effect6.gen(function* () {
|
|
1070
947
|
const ranks = scopeRanks(ctx);
|
|
@@ -1090,108 +967,64 @@ var validateMcpBindingTarget = (ctx, input) => Effect6.gen(function* () {
|
|
|
1090
967
|
});
|
|
1091
968
|
}
|
|
1092
969
|
});
|
|
1093
|
-
var
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
return Effect6.fail(
|
|
1097
|
-
new McpConnectionError({
|
|
1098
|
-
transport: "remote",
|
|
1099
|
-
message: "credentialTargetScope is required when adding direct MCP credentials"
|
|
1100
|
-
})
|
|
1101
|
-
);
|
|
1102
|
-
};
|
|
1103
|
-
var targetScopeForBinding = (fallbackTargetScope, binding) => {
|
|
1104
|
-
const targetScope = binding.targetScope ?? fallbackTargetScope;
|
|
1105
|
-
if (targetScope) return Effect6.succeed(targetScope);
|
|
1106
|
-
return Effect6.fail(
|
|
1107
|
-
new McpConnectionError({
|
|
1108
|
-
transport: "remote",
|
|
1109
|
-
message: "credentialTargetScope is required when adding direct MCP credentials"
|
|
1110
|
-
})
|
|
1111
|
-
);
|
|
1112
|
-
};
|
|
1113
|
-
var canonicalizeCredentialMap = (values, slotForName) => {
|
|
1114
|
-
const nextValues = {};
|
|
1115
|
-
const bindings = [];
|
|
970
|
+
var canonicalizeCredentialMap = compileHttpNamedCredentialMap;
|
|
971
|
+
var canonicalizeConfiguredValueMap = (values, slotForName) => {
|
|
972
|
+
const next = {};
|
|
1116
973
|
for (const [name, value] of Object.entries(values ?? {})) {
|
|
1117
974
|
if (typeof value === "string") {
|
|
1118
|
-
|
|
1119
|
-
continue;
|
|
1120
|
-
}
|
|
1121
|
-
if ("kind" in value) {
|
|
1122
|
-
nextValues[name] = value;
|
|
975
|
+
next[name] = value;
|
|
1123
976
|
continue;
|
|
1124
977
|
}
|
|
1125
|
-
|
|
1126
|
-
nextValues[name] = ConfiguredCredentialBinding2.make({
|
|
978
|
+
next[name] = {
|
|
1127
979
|
kind: "binding",
|
|
1128
|
-
slot,
|
|
980
|
+
slot: slotForName(name),
|
|
1129
981
|
prefix: value.prefix
|
|
1130
|
-
}
|
|
1131
|
-
bindings.push({
|
|
1132
|
-
slot,
|
|
1133
|
-
targetScope: "targetScope" in value ? value.targetScope : void 0,
|
|
1134
|
-
value: {
|
|
1135
|
-
kind: "secret",
|
|
1136
|
-
secretId: SecretId.make(value.secretId),
|
|
1137
|
-
..."secretScopeId" in value && value.secretScopeId ? { secretScopeId: value.secretScopeId } : {}
|
|
1138
|
-
}
|
|
1139
|
-
});
|
|
982
|
+
};
|
|
1140
983
|
}
|
|
1141
|
-
return
|
|
984
|
+
return next;
|
|
1142
985
|
};
|
|
1143
|
-
var
|
|
1144
|
-
if (!
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
auth: {
|
|
1149
|
-
kind: "header",
|
|
1150
|
-
headerName: auth.headerName,
|
|
1151
|
-
secretSlot: MCP_HEADER_AUTH_SLOT,
|
|
1152
|
-
prefix: auth.prefix
|
|
1153
|
-
},
|
|
1154
|
-
bindings: [
|
|
1155
|
-
{
|
|
1156
|
-
slot: MCP_HEADER_AUTH_SLOT,
|
|
1157
|
-
targetScope: auth.targetScope,
|
|
1158
|
-
value: {
|
|
1159
|
-
kind: "secret",
|
|
1160
|
-
secretId: SecretId.make(auth.secretId),
|
|
1161
|
-
...auth.secretScopeId ? { secretScopeId: auth.secretScopeId } : {}
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
]
|
|
1165
|
-
};
|
|
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;
|
|
1166
991
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
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({
|
|
1170
1006
|
slot: MCP_OAUTH_CONNECTION_SLOT,
|
|
1171
|
-
value:
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
}
|
|
1176
|
-
];
|
|
1177
|
-
if (auth.clientIdSecretId) {
|
|
1007
|
+
value: httpCredentialInputToBindingValue(oauth.connection)
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
if (oauth.clientId) {
|
|
1178
1011
|
bindings.push({
|
|
1179
1012
|
slot: MCP_OAUTH_CLIENT_ID_SLOT,
|
|
1180
|
-
value:
|
|
1013
|
+
value: httpCredentialInputToBindingValue(oauth.clientId)
|
|
1181
1014
|
});
|
|
1182
1015
|
}
|
|
1183
|
-
if (
|
|
1016
|
+
if (oauth.clientSecret) {
|
|
1184
1017
|
bindings.push({
|
|
1185
1018
|
slot: MCP_OAUTH_CLIENT_SECRET_SLOT,
|
|
1186
|
-
value:
|
|
1019
|
+
value: httpCredentialInputToBindingValue(oauth.clientSecret)
|
|
1187
1020
|
});
|
|
1188
1021
|
}
|
|
1189
1022
|
return {
|
|
1190
1023
|
auth: {
|
|
1191
1024
|
kind: "oauth2",
|
|
1192
1025
|
connectionSlot: MCP_OAUTH_CONNECTION_SLOT,
|
|
1193
|
-
...
|
|
1194
|
-
...
|
|
1026
|
+
...oauth.clientId ? { clientIdSlot: MCP_OAUTH_CLIENT_ID_SLOT } : {},
|
|
1027
|
+
...oauth.clientSecret ? { clientSecretSlot: MCP_OAUTH_CLIENT_SECRET_SLOT } : {}
|
|
1195
1028
|
},
|
|
1196
1029
|
bindings
|
|
1197
1030
|
};
|
|
@@ -1230,21 +1063,32 @@ var resolveSecretBackedMap = (values, ctx) => resolveSharedSecretBackedMap({
|
|
|
1230
1063
|
transport: "remote",
|
|
1231
1064
|
message: `Failed to resolve secret "${value.secretId}"`
|
|
1232
1065
|
}),
|
|
1233
|
-
onError: (err, _name, value) =>
|
|
1066
|
+
onError: (err, _name, value) => Predicate3.isTagged("SecretOwnedByConnectionError")(err) ? new McpConnectionError({
|
|
1234
1067
|
transport: "remote",
|
|
1235
1068
|
message: `Failed to resolve secret "${value.secretId}"`
|
|
1236
1069
|
}) : err
|
|
1237
1070
|
}).pipe(
|
|
1238
1071
|
Effect6.mapError(
|
|
1239
|
-
(err) =>
|
|
1072
|
+
(err) => Predicate3.isTagged("SecretOwnedByConnectionError")(err) ? new McpConnectionError({ transport: "remote", message: "Failed to resolve secret" }) : err
|
|
1240
1073
|
)
|
|
1241
1074
|
);
|
|
1242
|
-
var
|
|
1075
|
+
var credentialInputMapToConfigValues = (values) => {
|
|
1243
1076
|
if (!values) return void 0;
|
|
1244
|
-
const
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
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;
|
|
1248
1092
|
};
|
|
1249
1093
|
var resolveMcpBindingValueMap = (ctx, values, params) => Effect6.gen(function* () {
|
|
1250
1094
|
if (!values) return void 0;
|
|
@@ -1292,49 +1136,58 @@ var resolveMcpBindingValueMap = (ctx, values, params) => Effect6.gen(function* (
|
|
|
1292
1136
|
}
|
|
1293
1137
|
return Object.keys(resolved).length > 0 ? resolved : void 0;
|
|
1294
1138
|
});
|
|
1295
|
-
var
|
|
1296
|
-
|
|
1139
|
+
var resolveInitialMcpCredentialValueMap = (ctx, values, bindings, targetScope, missingLabel) => Effect6.gen(function* () {
|
|
1140
|
+
const bySlot = new Map(bindings.map((binding) => [binding.slot, binding.value]));
|
|
1297
1141
|
const resolved = {};
|
|
1298
1142
|
for (const [name, value] of Object.entries(values)) {
|
|
1299
1143
|
if (typeof value === "string") {
|
|
1300
1144
|
resolved[name] = value;
|
|
1301
1145
|
continue;
|
|
1302
1146
|
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
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
|
+
)
|
|
1312
1159
|
);
|
|
1313
|
-
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;
|
|
1314
1167
|
continue;
|
|
1315
1168
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
Effect6.catchTag(
|
|
1319
|
-
"SecretOwnedByConnectionError",
|
|
1320
|
-
() => Effect6.fail(
|
|
1321
|
-
new McpConnectionError({
|
|
1322
|
-
transport: "remote",
|
|
1323
|
-
message: `Failed to resolve secret for ${params.missingLabel} "${name}"`
|
|
1324
|
-
})
|
|
1325
|
-
)
|
|
1326
|
-
)
|
|
1327
|
-
);
|
|
1328
|
-
if (secret === null) {
|
|
1329
|
-
return yield* new McpConnectionError({
|
|
1330
|
-
transport: "remote",
|
|
1331
|
-
message: `Missing secret "${value.secretId}" for ${params.missingLabel} "${name}"`
|
|
1332
|
-
});
|
|
1169
|
+
if (binding?.kind === "text") {
|
|
1170
|
+
resolved[name] = value.prefix ? `${value.prefix}${binding.text}` : binding.text;
|
|
1333
1171
|
}
|
|
1334
|
-
resolved[name] = value.prefix ? `${value.prefix}${secret}` : secret;
|
|
1335
1172
|
}
|
|
1336
1173
|
return Object.keys(resolved).length > 0 ? resolved : void 0;
|
|
1337
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
|
+
});
|
|
1338
1191
|
var resolveMcpHeaderAuth = (ctx, sourceId, sourceScope, auth) => Effect6.gen(function* () {
|
|
1339
1192
|
if (auth.kind !== "header") return {};
|
|
1340
1193
|
const binding = yield* resolveMcpSourceBinding(ctx, sourceId, sourceScope, auth.secretSlot);
|
|
@@ -1388,60 +1241,6 @@ var resolveMcpStoredOauthProvider = (ctx, sourceId, sourceScope, auth) => Effect
|
|
|
1388
1241
|
);
|
|
1389
1242
|
return makeOAuthProvider(accessToken);
|
|
1390
1243
|
});
|
|
1391
|
-
var resolveMcpInputAuth = (ctx, sourceId, sourceScope, targetScope, auth) => Effect6.gen(function* () {
|
|
1392
|
-
if (!auth || auth.kind === "none") return { headers: {} };
|
|
1393
|
-
if (auth.kind === "header") {
|
|
1394
|
-
if ("secretSlot" in auth) {
|
|
1395
|
-
const headers = yield* resolveMcpHeaderAuth(ctx, sourceId, sourceScope, auth);
|
|
1396
|
-
return { headers };
|
|
1397
|
-
}
|
|
1398
|
-
const secretScope = auth.secretScopeId ?? auth.targetScope ?? targetScope ?? sourceScope;
|
|
1399
|
-
const secret = yield* ctx.secrets.getAtScope(SecretId.make(auth.secretId), secretScope).pipe(
|
|
1400
|
-
Effect6.catchTag(
|
|
1401
|
-
"SecretOwnedByConnectionError",
|
|
1402
|
-
() => Effect6.fail(
|
|
1403
|
-
new McpConnectionError({
|
|
1404
|
-
transport: "remote",
|
|
1405
|
-
message: `Failed to resolve secret "${auth.secretId}"`
|
|
1406
|
-
})
|
|
1407
|
-
)
|
|
1408
|
-
)
|
|
1409
|
-
);
|
|
1410
|
-
if (secret === null) {
|
|
1411
|
-
return yield* new McpConnectionError({
|
|
1412
|
-
transport: "remote",
|
|
1413
|
-
message: `Failed to resolve secret "${auth.secretId}"`
|
|
1414
|
-
});
|
|
1415
|
-
}
|
|
1416
|
-
return {
|
|
1417
|
-
headers: { [auth.headerName]: auth.prefix ? `${auth.prefix}${secret}` : secret }
|
|
1418
|
-
};
|
|
1419
|
-
}
|
|
1420
|
-
const connection = "connectionId" in auth ? { id: ConnectionId.make(auth.connectionId), scope: targetScope ?? sourceScope } : yield* Effect6.gen(function* () {
|
|
1421
|
-
const binding = yield* resolveMcpSourceBinding(
|
|
1422
|
-
ctx,
|
|
1423
|
-
sourceId,
|
|
1424
|
-
sourceScope,
|
|
1425
|
-
auth.connectionSlot
|
|
1426
|
-
);
|
|
1427
|
-
return binding?.value.kind === "connection" ? { id: binding.value.connectionId, scope: binding.scopeId } : null;
|
|
1428
|
-
});
|
|
1429
|
-
if (connection === null) {
|
|
1430
|
-
return yield* new McpConnectionError({
|
|
1431
|
-
transport: "remote",
|
|
1432
|
-
message: `Missing OAuth connection binding for MCP source "${sourceId}"`
|
|
1433
|
-
});
|
|
1434
|
-
}
|
|
1435
|
-
const accessToken = yield* ctx.connections.accessTokenAtScope(connection.id, connection.scope).pipe(
|
|
1436
|
-
Effect6.mapError(
|
|
1437
|
-
({ message }) => new McpConnectionError({
|
|
1438
|
-
transport: "remote",
|
|
1439
|
-
message: `Failed to resolve OAuth connection "${connection.id}": ${message}`
|
|
1440
|
-
})
|
|
1441
|
-
)
|
|
1442
|
-
);
|
|
1443
|
-
return { headers: {}, authProvider: makeOAuthProvider(accessToken) };
|
|
1444
|
-
});
|
|
1445
1244
|
var resolveConnectorInput = (sourceId, sourceScope, sd, ctx, allowStdio) => {
|
|
1446
1245
|
if (sd.transport === "stdio") {
|
|
1447
1246
|
if (!allowStdio) {
|
|
@@ -1519,23 +1318,16 @@ var makeRuntime = () => Effect6.gen(function* () {
|
|
|
1519
1318
|
}).pipe(Scope.provide(cacheScope));
|
|
1520
1319
|
return { connectionCache, pendingConnectors, cacheScope };
|
|
1521
1320
|
});
|
|
1522
|
-
var secretRef = (id) => `${SECRET_REF_PREFIX}${id}`;
|
|
1523
1321
|
var authToConfig = (auth) => {
|
|
1524
1322
|
if (!auth) return void 0;
|
|
1525
|
-
if (
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
return
|
|
1529
|
-
kind: "header",
|
|
1530
|
-
headerName: auth.headerName,
|
|
1531
|
-
secret: secretRef(auth.secretId),
|
|
1532
|
-
prefix: auth.prefix
|
|
1533
|
-
};
|
|
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;
|
|
1534
1327
|
}
|
|
1535
|
-
if (!("connectionId" in auth)) return void 0;
|
|
1536
1328
|
return {
|
|
1537
1329
|
kind: "oauth2",
|
|
1538
|
-
connectionId:
|
|
1330
|
+
connectionId: connection.connectionId
|
|
1539
1331
|
};
|
|
1540
1332
|
};
|
|
1541
1333
|
var toCredentialInput = (bySlot, configured) => {
|
|
@@ -1544,7 +1336,9 @@ var toCredentialInput = (bySlot, configured) => {
|
|
|
1544
1336
|
if (!value) return void 0;
|
|
1545
1337
|
if (value.kind === "secret") {
|
|
1546
1338
|
return {
|
|
1339
|
+
kind: "secret",
|
|
1547
1340
|
secretId: value.secretId,
|
|
1341
|
+
...value.secretScopeId ? { secretScope: value.secretScopeId } : {},
|
|
1548
1342
|
...configured.prefix ? { prefix: configured.prefix } : {}
|
|
1549
1343
|
};
|
|
1550
1344
|
}
|
|
@@ -1566,15 +1360,15 @@ var toAuthInput = (bySlot, auth) => {
|
|
|
1566
1360
|
const value = bySlot.get(auth.secretSlot);
|
|
1567
1361
|
if (value?.kind !== "secret") return void 0;
|
|
1568
1362
|
return {
|
|
1569
|
-
kind: "
|
|
1570
|
-
headerName: auth.headerName,
|
|
1571
|
-
secretId: value.secretId,
|
|
1572
|
-
prefix: auth.prefix
|
|
1363
|
+
kind: "none"
|
|
1573
1364
|
};
|
|
1574
1365
|
}
|
|
1575
1366
|
const connection = bySlot.get(auth.connectionSlot);
|
|
1576
|
-
|
|
1577
|
-
|
|
1367
|
+
return {
|
|
1368
|
+
oauth2: {
|
|
1369
|
+
...connection?.kind === "connection" ? { connection: { kind: "connection", connectionId: connection.connectionId } } : {}
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1578
1372
|
};
|
|
1579
1373
|
var inputFormFromStored = (bindings, stored, scope, sourceName, namespace) => {
|
|
1580
1374
|
if (stored.transport === "stdio") {
|
|
@@ -1622,8 +1416,8 @@ var toMcpConfigEntry = (namespace, sourceName, config) => {
|
|
|
1622
1416
|
name: sourceName,
|
|
1623
1417
|
endpoint: config.endpoint,
|
|
1624
1418
|
remoteTransport: config.remoteTransport,
|
|
1625
|
-
queryParams:
|
|
1626
|
-
headers:
|
|
1419
|
+
queryParams: credentialInputMapToConfigValues(config.queryParams),
|
|
1420
|
+
headers: credentialInputMapToConfigValues(config.headers),
|
|
1627
1421
|
namespace,
|
|
1628
1422
|
auth: authToConfig(config.auth)
|
|
1629
1423
|
};
|
|
@@ -1642,6 +1436,13 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
1642
1436
|
return {
|
|
1643
1437
|
id: "mcp",
|
|
1644
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
|
+
})),
|
|
1645
1446
|
// Surfaced to the client bundle via the Vite plugin (see
|
|
1646
1447
|
// `@executor-js/vite-plugin`). The MCP `./client` factory reads
|
|
1647
1448
|
// `allowStdio` and gates the stdio tab + presets in AddMcpSource —
|
|
@@ -1734,72 +1535,72 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
1734
1535
|
const addSource = (config) => Effect6.gen(function* () {
|
|
1735
1536
|
const namespace = normalizeNamespace(config);
|
|
1736
1537
|
const canonicalRemote = config.transport === "remote" ? {
|
|
1737
|
-
headers:
|
|
1738
|
-
queryParams:
|
|
1739
|
-
|
|
1538
|
+
headers: canonicalizeConfiguredValueMap(config.headers, mcpHeaderSlot),
|
|
1539
|
+
queryParams: canonicalizeConfiguredValueMap(
|
|
1540
|
+
config.queryParams,
|
|
1541
|
+
mcpQueryParamSlot
|
|
1542
|
+
)
|
|
1740
1543
|
} : null;
|
|
1741
|
-
const
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
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) {
|
|
1751
1562
|
yield* validateMcpBindingTarget(ctx, {
|
|
1752
1563
|
sourceId: namespace,
|
|
1753
1564
|
sourceScope: config.scope,
|
|
1754
|
-
targetScope:
|
|
1565
|
+
targetScope: initialRemote.scope
|
|
1755
1566
|
});
|
|
1756
1567
|
}
|
|
1757
|
-
const
|
|
1758
|
-
const
|
|
1759
|
-
|
|
1760
|
-
canonicalRemote
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
)
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
};
|
|
1794
|
-
return {
|
|
1795
|
-
transport: "remote",
|
|
1796
|
-
endpoint: config.endpoint,
|
|
1797
|
-
remoteTransport: config.remoteTransport ?? "auto",
|
|
1798
|
-
queryParams: resolvedQueryParams,
|
|
1799
|
-
headers: Object.keys(headers).length > 0 ? headers : void 0,
|
|
1800
|
-
authProvider: resolvedAuth.authProvider
|
|
1801
|
-
};
|
|
1802
|
-
}) : 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(
|
|
1803
1604
|
Effect6.result,
|
|
1804
1605
|
Effect6.withSpan("mcp.plugin.resolve_connector", {
|
|
1805
1606
|
attributes: {
|
|
@@ -1859,21 +1660,22 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
1859
1660
|
outputSchema: e.outputSchema
|
|
1860
1661
|
}))
|
|
1861
1662
|
});
|
|
1862
|
-
if (
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
)
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
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) => ({
|
|
1873
1675
|
slotKey: binding.slot,
|
|
1874
1676
|
value: binding.value
|
|
1875
|
-
})
|
|
1876
|
-
}
|
|
1677
|
+
}))
|
|
1678
|
+
});
|
|
1877
1679
|
}
|
|
1878
1680
|
})
|
|
1879
1681
|
).pipe(
|
|
@@ -1996,8 +1798,25 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
1996
1798
|
attributes: { "mcp.source.namespace": namespace }
|
|
1997
1799
|
})
|
|
1998
1800
|
);
|
|
1999
|
-
const
|
|
2000
|
-
|
|
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);
|
|
2001
1820
|
if (!existing || existing.config.transport !== "remote") return;
|
|
2002
1821
|
const canonicalHeaders = input.headers !== void 0 ? canonicalizeCredentialMap(input.headers, mcpHeaderSlot) : null;
|
|
2003
1822
|
const canonicalQueryParams = input.queryParams !== void 0 ? canonicalizeCredentialMap(input.queryParams, mcpQueryParamSlot) : null;
|
|
@@ -2007,46 +1826,40 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
2007
1826
|
...canonicalQueryParams?.bindings ?? [],
|
|
2008
1827
|
...canonicalAuth?.bindings ?? []
|
|
2009
1828
|
];
|
|
2010
|
-
|
|
2011
|
-
input.credentialTargetScope,
|
|
2012
|
-
directBindings
|
|
2013
|
-
);
|
|
2014
|
-
if (targetScope) {
|
|
1829
|
+
if (directBindings.length > 0) {
|
|
2015
1830
|
yield* validateMcpBindingTarget(ctx, {
|
|
2016
|
-
sourceId
|
|
2017
|
-
sourceScope
|
|
1831
|
+
sourceId,
|
|
1832
|
+
sourceScope,
|
|
2018
1833
|
targetScope
|
|
2019
1834
|
});
|
|
2020
1835
|
}
|
|
2021
|
-
const remote = existing.config;
|
|
2022
1836
|
const updatedConfig = {
|
|
2023
|
-
...
|
|
1837
|
+
...existing.config,
|
|
2024
1838
|
...input.endpoint !== void 0 ? { endpoint: input.endpoint } : {},
|
|
2025
1839
|
...canonicalHeaders ? { headers: canonicalHeaders.values } : {},
|
|
2026
1840
|
...canonicalAuth ? { auth: canonicalAuth.auth } : {},
|
|
2027
1841
|
...canonicalQueryParams ? { queryParams: canonicalQueryParams.values } : {}
|
|
2028
1842
|
};
|
|
2029
|
-
const sourceName = input.name?.trim() || existing.name;
|
|
2030
1843
|
const affectedPrefixes = [
|
|
2031
1844
|
...input.headers !== void 0 ? ["header:"] : [],
|
|
2032
1845
|
...input.queryParams !== void 0 ? ["query_param:"] : [],
|
|
2033
1846
|
...input.auth !== void 0 ? ["auth:"] : []
|
|
2034
1847
|
];
|
|
2035
|
-
const
|
|
1848
|
+
const sourceName = input.name?.trim() || existing.name;
|
|
2036
1849
|
yield* ctx.transaction(
|
|
2037
1850
|
Effect6.gen(function* () {
|
|
2038
1851
|
yield* ctx.storage.putSource({
|
|
2039
|
-
namespace,
|
|
2040
|
-
scope,
|
|
1852
|
+
namespace: sourceId,
|
|
1853
|
+
scope: sourceScope,
|
|
2041
1854
|
name: sourceName,
|
|
2042
1855
|
config: updatedConfig
|
|
2043
1856
|
});
|
|
2044
1857
|
if (affectedPrefixes.length > 0 || directBindings.length > 0) {
|
|
2045
1858
|
yield* ctx.credentialBindings.replaceForSource({
|
|
2046
|
-
targetScope: ScopeId.make(
|
|
1859
|
+
targetScope: ScopeId.make(targetScope),
|
|
2047
1860
|
pluginId: MCP_PLUGIN_ID,
|
|
2048
|
-
sourceId
|
|
2049
|
-
sourceScope: ScopeId.make(
|
|
1861
|
+
sourceId,
|
|
1862
|
+
sourceScope: ScopeId.make(sourceScope),
|
|
2050
1863
|
slotPrefixes: affectedPrefixes,
|
|
2051
1864
|
bindings: directBindings.map((binding) => ({
|
|
2052
1865
|
slotKey: binding.slot,
|
|
@@ -2056,71 +1869,168 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
2056
1869
|
}
|
|
2057
1870
|
})
|
|
2058
1871
|
);
|
|
2059
|
-
if (configFile) {
|
|
1872
|
+
if (options?.configFile) {
|
|
2060
1873
|
const bindings = yield* ctx.credentialBindings.listForSource({
|
|
2061
1874
|
pluginId: MCP_PLUGIN_ID,
|
|
2062
|
-
sourceId
|
|
2063
|
-
sourceScope: ScopeId.make(
|
|
1875
|
+
sourceId,
|
|
1876
|
+
sourceScope: ScopeId.make(sourceScope)
|
|
2064
1877
|
});
|
|
2065
1878
|
const inputForm = inputFormFromStored(
|
|
2066
1879
|
bindings,
|
|
2067
1880
|
updatedConfig,
|
|
2068
|
-
|
|
1881
|
+
sourceScope,
|
|
2069
1882
|
sourceName,
|
|
2070
|
-
|
|
1883
|
+
sourceId
|
|
2071
1884
|
);
|
|
2072
|
-
yield* configFile.upsertSource(toMcpConfigEntry(
|
|
1885
|
+
yield* options.configFile.upsertSource(toMcpConfigEntry(sourceId, sourceName, inputForm)).pipe(Effect6.withSpan("mcp.plugin.config_file.upsert"));
|
|
2073
1886
|
}
|
|
2074
|
-
})
|
|
2075
|
-
Effect6.withSpan("mcp.plugin.update_source", {
|
|
2076
|
-
attributes: { "mcp.source.namespace": namespace }
|
|
2077
|
-
})
|
|
2078
|
-
);
|
|
2079
|
-
const getSource = (namespace, scope) => ctx.storage.getSource(namespace, scope).pipe(
|
|
2080
|
-
Effect6.withSpan("mcp.plugin.get_source", {
|
|
2081
|
-
attributes: { "mcp.source.namespace": namespace }
|
|
2082
|
-
})
|
|
2083
|
-
);
|
|
2084
|
-
return {
|
|
2085
|
-
probeEndpoint,
|
|
2086
|
-
addSource,
|
|
2087
|
-
removeSource,
|
|
2088
|
-
refreshSource,
|
|
2089
|
-
getSource,
|
|
2090
|
-
updateSource,
|
|
2091
|
-
listSourceBindings: (sourceId, sourceScope) => listMcpSourceBindings(ctx, sourceId, sourceScope),
|
|
2092
|
-
setSourceBinding: (input) => Effect6.gen(function* () {
|
|
2093
|
-
yield* validateMcpBindingTarget(ctx, {
|
|
2094
|
-
sourceId: input.sourceId,
|
|
2095
|
-
sourceScope: input.sourceScope,
|
|
2096
|
-
targetScope: input.scope
|
|
2097
|
-
});
|
|
2098
|
-
const binding = yield* ctx.credentialBindings.set({
|
|
2099
|
-
targetScope: input.scope,
|
|
2100
|
-
pluginId: MCP_PLUGIN_ID,
|
|
2101
|
-
sourceId: input.sourceId,
|
|
2102
|
-
sourceScope: input.sourceScope,
|
|
2103
|
-
slotKey: input.slot,
|
|
2104
|
-
value: input.value
|
|
2105
|
-
});
|
|
2106
|
-
return coreBindingToMcpBinding(binding);
|
|
2107
|
-
}),
|
|
2108
|
-
removeSourceBinding: (sourceId, sourceScope, slot, scope) => Effect6.gen(function* () {
|
|
2109
|
-
yield* validateMcpBindingTarget(ctx, {
|
|
2110
|
-
sourceId,
|
|
2111
|
-
sourceScope,
|
|
2112
|
-
targetScope: scope
|
|
2113
|
-
});
|
|
2114
|
-
yield* ctx.credentialBindings.remove({
|
|
2115
|
-
targetScope: ScopeId.make(scope),
|
|
2116
|
-
pluginId: MCP_PLUGIN_ID,
|
|
2117
|
-
sourceId,
|
|
2118
|
-
sourceScope: ScopeId.make(sourceScope),
|
|
2119
|
-
slotKey: slot
|
|
2120
|
-
});
|
|
2121
|
-
})
|
|
2122
|
-
};
|
|
1887
|
+
})
|
|
2123
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
|
+
],
|
|
2124
2034
|
invokeTool: ({ ctx, toolRow, args, elicit }) => Effect6.gen(function* () {
|
|
2125
2035
|
const runtime = yield* ensureRuntime();
|
|
2126
2036
|
const toolScope = toolRow.scope_id;
|
|
@@ -2146,7 +2056,7 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
2146
2056
|
message: `No MCP source config for namespace "${entry.namespace}"`
|
|
2147
2057
|
});
|
|
2148
2058
|
}
|
|
2149
|
-
|
|
2059
|
+
const raw = yield* invokeMcpTool({
|
|
2150
2060
|
toolId: toolRow.id,
|
|
2151
2061
|
toolName: entry.binding.toolName,
|
|
2152
2062
|
args,
|
|
@@ -2181,6 +2091,15 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
2181
2091
|
pendingConnectors: runtime.pendingConnectors,
|
|
2182
2092
|
elicit
|
|
2183
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);
|
|
2184
2103
|
}).pipe(
|
|
2185
2104
|
Effect6.withSpan("mcp.plugin.invoke_tool", {
|
|
2186
2105
|
attributes: {
|
|
@@ -2247,8 +2166,8 @@ var mcpPlugin = definePlugin((options) => {
|
|
|
2247
2166
|
// Honor upstream destructiveHint from MCP ToolAnnotations.
|
|
2248
2167
|
// Bindings are fetched per scope so shadowed sources (e.g. an org-level
|
|
2249
2168
|
// source overridden per-user) each resolve against their own scope's
|
|
2250
|
-
// row rather than collapsing onto whichever row
|
|
2251
|
-
//
|
|
2169
|
+
// row rather than collapsing onto whichever visible row would otherwise
|
|
2170
|
+
// win first.
|
|
2252
2171
|
resolveAnnotations: ({ ctx, sourceId, toolRows }) => Effect6.gen(function* () {
|
|
2253
2172
|
const scopes = new Set(toolRows.map((row) => row.scope_id));
|
|
2254
2173
|
const entries = yield* Effect6.forEach(
|
|
@@ -2315,4 +2234,4 @@ export {
|
|
|
2315
2234
|
makeMcpStore,
|
|
2316
2235
|
mcpPlugin
|
|
2317
2236
|
};
|
|
2318
|
-
//# sourceMappingURL=chunk-
|
|
2237
|
+
//# sourceMappingURL=chunk-H5PLTEMB.js.map
|