stitchkit 0.41.0 → 0.42.0
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/cli.js +2 -2
- package/dist/contract/errors-factory.d.ts +88 -15
- package/dist/contract/errors-factory.d.ts.map +1 -1
- package/dist/contract/errors.d.ts +4 -4
- package/dist/contract/errors.d.ts.map +1 -1
- package/dist/contract/index.d.ts +1 -1
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/contract/index.js +2 -2
- package/dist/{index-xax049k6.js → index-11x5dts2.js} +44 -13
- package/dist/{index-4e1c0hsw.js → index-181aebw8.js} +1 -1
- package/dist/{index-dnkefke9.js → index-310bfer5.js} +1 -1
- package/dist/{index-sc67e454.js → index-gex6gxhe.js} +7 -4
- package/dist/{index-ncqqn1bc.js → index-p9vkwns1.js} +2 -2
- package/dist/{index-809wc1tt.js → index-s4qsmgwe.js} +4 -1
- package/dist/index.js +2 -2
- package/dist/internal/typed.d.ts +8 -0
- package/dist/internal/typed.d.ts.map +1 -1
- package/dist/node.js +2 -2
- package/dist/observability/index.js +1 -1
- package/dist/react.js +1 -1
- package/dist/server/error-hook.d.ts +8 -4
- package/dist/server/error-hook.d.ts.map +1 -1
- package/dist/server/index.js +7 -6
- package/dist/tools/agent.d.ts +1 -1
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/list-names.d.ts +8 -6
- package/dist/tools/list-names.d.ts.map +1 -1
- package/dist/tools/manifest.d.ts +13 -5
- package/dist/tools/manifest.d.ts.map +1 -1
- package/dist/tools/mcp-handler.d.ts +5 -4
- package/dist/tools/mcp-handler.d.ts.map +1 -1
- package/dist/tools/mcp-stdio.d.ts +3 -2
- package/dist/tools/mcp-stdio.d.ts.map +1 -1
- package/dist/tools/mcp.d.ts +49 -9
- package/dist/tools/mcp.d.ts.map +1 -1
- package/dist/tools/native-mcp.d.ts +4 -18
- package/dist/tools/native-mcp.d.ts.map +1 -1
- package/dist/tools/runtime-tool.d.ts +1 -1
- package/dist/tools/runtime-tool.d.ts.map +1 -1
- package/dist/tools/surface.d.ts +37 -0
- package/dist/tools/surface.d.ts.map +1 -0
- package/dist/tools/toolkit.d.ts +4 -4
- package/dist/tools/toolkit.d.ts.map +1 -1
- package/dist/tools/transports.d.ts +11 -9
- package/dist/tools/transports.d.ts.map +1 -1
- package/dist/tools/view-file.d.ts +3 -3
- package/dist/tools.d.ts +5 -5
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +292 -155
- package/llms-full.txt +264 -47
- package/package.json +1 -1
package/dist/tools.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
inputIsQuery,
|
|
3
3
|
signJwt,
|
|
4
4
|
verifyPkce
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-310bfer5.js";
|
|
6
6
|
import {
|
|
7
7
|
DEFAULT_CORS_ALLOW_HEADERS
|
|
8
8
|
} from "./index-6jypn22c.js";
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
toolErrorFromResult,
|
|
26
26
|
toolResultFromError,
|
|
27
27
|
writeDownload
|
|
28
|
-
} from "./index-
|
|
28
|
+
} from "./index-p9vkwns1.js";
|
|
29
29
|
import {
|
|
30
30
|
toJsonSchema
|
|
31
31
|
} from "./index-frfyw9fa.js";
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
mergeMeta,
|
|
40
40
|
parseTrailingWildcard,
|
|
41
41
|
typedEntries
|
|
42
|
-
} from "./index-
|
|
42
|
+
} from "./index-gex6gxhe.js";
|
|
43
43
|
|
|
44
44
|
// src/tools/agent.ts
|
|
45
45
|
import { jsonSchema, tool } from "ai";
|
|
@@ -70,8 +70,10 @@ function runtimeToolIdentity(definition) {
|
|
|
70
70
|
ui: definition.ui
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
|
-
function runtimeToolMountable(definition) {
|
|
74
|
-
|
|
73
|
+
function runtimeToolMountable(definition, assertName = true) {
|
|
74
|
+
if (assertName) {
|
|
75
|
+
assertToolName(definition.name, definition.identity.serviceName, definition.identity.action);
|
|
76
|
+
}
|
|
75
77
|
const method = {
|
|
76
78
|
...runtimeToolIdentity(definition),
|
|
77
79
|
inputSchema: definition.input,
|
|
@@ -90,6 +92,55 @@ function runtimeToolMountable(definition) {
|
|
|
90
92
|
};
|
|
91
93
|
}
|
|
92
94
|
|
|
95
|
+
// src/tools/surface.ts
|
|
96
|
+
function duplicateLabel(transport) {
|
|
97
|
+
if (transport === "MCP")
|
|
98
|
+
return "MCP tool name";
|
|
99
|
+
if (transport === "AGENT")
|
|
100
|
+
return "agent tool name";
|
|
101
|
+
return "CLI command";
|
|
102
|
+
}
|
|
103
|
+
function collectToolSurface({
|
|
104
|
+
surface,
|
|
105
|
+
transport,
|
|
106
|
+
assertUniqueNames = true,
|
|
107
|
+
...collectConfig
|
|
108
|
+
}) {
|
|
109
|
+
const entries = [];
|
|
110
|
+
const names = new Set;
|
|
111
|
+
const append = (entry) => {
|
|
112
|
+
if (assertUniqueNames) {
|
|
113
|
+
assertUniqueToolName(entry.mountable.name, names.has(entry.mountable.name), duplicateLabel(transport));
|
|
114
|
+
}
|
|
115
|
+
names.add(entry.mountable.name);
|
|
116
|
+
entries.push(entry);
|
|
117
|
+
};
|
|
118
|
+
for (const service of surface.services ?? []) {
|
|
119
|
+
for (const mountable of collectTools(service, transport, collectConfig)) {
|
|
120
|
+
append({
|
|
121
|
+
kind: "contract",
|
|
122
|
+
service: service.name,
|
|
123
|
+
action: mountable.method.key,
|
|
124
|
+
mountable
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (transport === "CLI")
|
|
129
|
+
return entries;
|
|
130
|
+
for (const definition of surface.runtimeTools ?? []) {
|
|
131
|
+
if (!runtimeToolSupports(definition, transport))
|
|
132
|
+
continue;
|
|
133
|
+
append({
|
|
134
|
+
kind: "runtime",
|
|
135
|
+
service: definition.identity.serviceName,
|
|
136
|
+
action: definition.identity.action,
|
|
137
|
+
mountable: runtimeToolMountable(definition, collectConfig.assertNames),
|
|
138
|
+
definition
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return entries;
|
|
142
|
+
}
|
|
143
|
+
|
|
93
144
|
// src/tools/agent.ts
|
|
94
145
|
function mountAgent(services, config = {}) {
|
|
95
146
|
const serviceList = Array.isArray(services) ? services : [services];
|
|
@@ -104,36 +155,13 @@ function mountAgent(services, config = {}) {
|
|
|
104
155
|
coerceJsonArgs: config.coerceJsonArgs,
|
|
105
156
|
onOutputStrip: config.onOutputStrip
|
|
106
157
|
});
|
|
107
|
-
for (const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
description: mountable.method.desc,
|
|
115
|
-
inputSchema: jsonSchema(mountable.presentationSchema, {
|
|
116
|
-
validate: async (value) => isRecord(value) ? { success: true, value } : { success: false, error: new Error("Tool arguments must be an object") }
|
|
117
|
-
}),
|
|
118
|
-
execute: async (rawArgs) => {
|
|
119
|
-
const args = isRecord(rawArgs) ? rawArgs : {};
|
|
120
|
-
try {
|
|
121
|
-
const result = await runTool(mountable, args);
|
|
122
|
-
if (result.ok)
|
|
123
|
-
return result.data;
|
|
124
|
-
return formatToolError(result, mountable.name, config.errorHint);
|
|
125
|
-
} catch (err) {
|
|
126
|
-
return formatToolError(toolResultFromError(err), mountable.name, config.errorHint);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
for (const definition of config.runtimeTools ?? []) {
|
|
133
|
-
if (!runtimeToolSupports(definition, "AGENT"))
|
|
134
|
-
continue;
|
|
135
|
-
const mountable = runtimeToolMountable(definition);
|
|
136
|
-
assertUniqueToolName(definition.name, Object.hasOwn(tools, definition.name), "agent tool name");
|
|
158
|
+
for (const entry of collectToolSurface({
|
|
159
|
+
surface: { services: serviceList, runtimeTools: config.runtimeTools },
|
|
160
|
+
transport: "AGENT",
|
|
161
|
+
extend: config.extend,
|
|
162
|
+
flattenUnionInput: config.flattenUnionInput
|
|
163
|
+
})) {
|
|
164
|
+
const { mountable } = entry;
|
|
137
165
|
const inputSchema = jsonSchema(mountable.presentationSchema, {
|
|
138
166
|
validate: async (value) => isRecord(value) ? { success: true, value } : { success: false, error: new Error("Tool arguments must be an object") }
|
|
139
167
|
});
|
|
@@ -148,9 +176,13 @@ function mountAgent(services, config = {}) {
|
|
|
148
176
|
return formatToolError(toolResultFromError(err), mountable.name, config.errorHint);
|
|
149
177
|
}
|
|
150
178
|
};
|
|
151
|
-
|
|
152
|
-
|
|
179
|
+
const presenter = entry.kind === "runtime" ? entry.definition.present?.agent : undefined;
|
|
180
|
+
if (entry.kind === "runtime" && presenter) {
|
|
181
|
+
const { definition } = entry;
|
|
153
182
|
const output = definition.output;
|
|
183
|
+
if (!output) {
|
|
184
|
+
throw new Error(`Runtime tool "${definition.name}" presenter requires an output schema`);
|
|
185
|
+
}
|
|
154
186
|
tools[definition.name] = tool({
|
|
155
187
|
description: definition.description,
|
|
156
188
|
inputSchema,
|
|
@@ -165,10 +197,11 @@ function mountAgent(services, config = {}) {
|
|
|
165
197
|
}
|
|
166
198
|
});
|
|
167
199
|
} else {
|
|
168
|
-
|
|
169
|
-
|
|
200
|
+
const output = entry.kind === "runtime" ? entry.definition.output : undefined;
|
|
201
|
+
tools[mountable.name] = tool({
|
|
202
|
+
description: mountable.method.desc,
|
|
170
203
|
inputSchema,
|
|
171
|
-
...
|
|
204
|
+
...output && { outputSchema: output },
|
|
172
205
|
execute
|
|
173
206
|
});
|
|
174
207
|
}
|
|
@@ -224,34 +257,43 @@ function createToolInvoker(services, config) {
|
|
|
224
257
|
}
|
|
225
258
|
// src/tools/list-names.ts
|
|
226
259
|
var TOOL_TRANSPORTS = ["MCP", "AGENT", "CLI"];
|
|
227
|
-
function listToolNames(
|
|
260
|
+
function listToolNames(surface) {
|
|
228
261
|
const entries = new Map;
|
|
229
|
-
for (const
|
|
230
|
-
for (const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
262
|
+
for (const transport of TOOL_TRANSPORTS) {
|
|
263
|
+
for (const entry of collectToolSurface({
|
|
264
|
+
surface,
|
|
265
|
+
transport,
|
|
266
|
+
assertNames: false,
|
|
267
|
+
assertUniqueNames: false
|
|
268
|
+
})) {
|
|
269
|
+
const id = `${entry.kind}\x00${entry.service}\x00${entry.action}`;
|
|
270
|
+
const existing = entries.get(id);
|
|
271
|
+
if (existing) {
|
|
272
|
+
existing.transports.push(transport);
|
|
273
|
+
} else {
|
|
274
|
+
entries.set(id, {
|
|
275
|
+
kind: entry.kind,
|
|
276
|
+
name: entry.mountable.name,
|
|
277
|
+
service: entry.service,
|
|
278
|
+
method: entry.action,
|
|
279
|
+
transports: [transport]
|
|
280
|
+
});
|
|
244
281
|
}
|
|
245
282
|
}
|
|
246
283
|
}
|
|
247
284
|
return [...entries.values()].sort((a, b) => a.name.localeCompare(b.name) || a.service.localeCompare(b.service));
|
|
248
285
|
}
|
|
249
286
|
// src/tools/manifest.ts
|
|
250
|
-
function buildToolManifest(
|
|
251
|
-
return
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
287
|
+
function buildToolManifest(config) {
|
|
288
|
+
return collectToolSurface({
|
|
289
|
+
surface: config,
|
|
290
|
+
transport: config.transport,
|
|
291
|
+
extend: config.extend,
|
|
292
|
+
flattenUnionInput: config.flattenUnionInput
|
|
293
|
+
}).map(({ mountable }) => ({
|
|
294
|
+
name: mountable.name,
|
|
295
|
+
description: mountable.method.desc,
|
|
296
|
+
inputSchema: mountable.presentationSchema
|
|
255
297
|
}));
|
|
256
298
|
}
|
|
257
299
|
// src/tools/mcp.ts
|
|
@@ -285,63 +327,53 @@ import { z } from "zod";
|
|
|
285
327
|
function isCallToolResult(value) {
|
|
286
328
|
return CallToolResultSchema.safeParse(value).success;
|
|
287
329
|
}
|
|
288
|
-
function
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
330
|
+
function mountPreparedRuntimeMcp(server, tools, config) {
|
|
331
|
+
for (const { definition, descriptor } of tools) {
|
|
332
|
+
const { mountable } = descriptor;
|
|
333
|
+
const toolConfig = {
|
|
334
|
+
description: definition.description,
|
|
335
|
+
inputSchema: z.looseObject({}).meta(presentationMetadata(descriptor.inputSchema))
|
|
336
|
+
};
|
|
337
|
+
if (descriptor.outputSchema)
|
|
338
|
+
toolConfig.outputSchema = descriptor.outputSchema;
|
|
339
|
+
if (definition.annotations)
|
|
340
|
+
toolConfig.annotations = definition.annotations;
|
|
341
|
+
if (definition.ui) {
|
|
342
|
+
toolConfig._meta = {
|
|
343
|
+
ui: definition.ui,
|
|
344
|
+
"ui/resourceUri": definition.ui.resourceUri
|
|
303
345
|
};
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
if (definition.
|
|
309
|
-
|
|
310
|
-
ui: definition.ui,
|
|
311
|
-
"ui/resourceUri": definition.ui.resourceUri
|
|
312
|
-
};
|
|
346
|
+
}
|
|
347
|
+
server.registerTool(definition.name, toolConfig, async (rawArgs) => {
|
|
348
|
+
const args = isRecord(rawArgs) ? rawArgs : {};
|
|
349
|
+
const result = await executeToolMethod(mountable.method, definition.name, args, { ...config.context, source: "mcp" }, config.hooks, config.lifecycle, config.coerceJsonArgs ?? true, config.onOutputStrip ? (paths) => config.onOutputStrip?.(definition.name, paths) : undefined);
|
|
350
|
+
if (!result.ok || !definition.present?.mcp) {
|
|
351
|
+
return config.formatResult(result, descriptor.outputMode, definition.name);
|
|
313
352
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const result = await executeToolMethod(mountable.method, definition.name, args, { ...config.context, source: "mcp" }, config.hooks, config.lifecycle, config.coerceJsonArgs ?? true, config.onOutputStrip ? (paths) => config.onOutputStrip?.(definition.name, paths) : undefined);
|
|
317
|
-
if (!result.ok || !definition.present?.mcp) {
|
|
318
|
-
return config.formatResult(result, prepared.outputMode, definition.name);
|
|
319
|
-
}
|
|
320
|
-
const presented = await definition.present.mcp(result.data);
|
|
321
|
-
if ("structuredContent" in presented || "isError" in presented) {
|
|
322
|
-
return config.formatResult({
|
|
323
|
-
ok: false,
|
|
324
|
-
code: "INTERNAL_SERVER_ERROR",
|
|
325
|
-
details: {
|
|
326
|
-
message: "Runtime MCP presenter cannot set framework-owned structuredContent or isError"
|
|
327
|
-
}
|
|
328
|
-
}, "none", definition.name);
|
|
329
|
-
}
|
|
330
|
-
const structured = config.formatResult(result, prepared.outputMode, definition.name).structuredContent;
|
|
331
|
-
const response = {
|
|
332
|
-
...presented,
|
|
333
|
-
...structured && { structuredContent: structured }
|
|
334
|
-
};
|
|
335
|
-
if (isCallToolResult(response))
|
|
336
|
-
return response;
|
|
353
|
+
const presented = await definition.present.mcp(result.data);
|
|
354
|
+
if ("structuredContent" in presented || "isError" in presented) {
|
|
337
355
|
return config.formatResult({
|
|
338
356
|
ok: false,
|
|
339
357
|
code: "INTERNAL_SERVER_ERROR",
|
|
340
|
-
details: {
|
|
358
|
+
details: {
|
|
359
|
+
message: "Runtime MCP presenter cannot set framework-owned structuredContent or isError"
|
|
360
|
+
}
|
|
341
361
|
}, "none", definition.name);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
|
|
362
|
+
}
|
|
363
|
+
const structured = config.formatResult(result, descriptor.outputMode, definition.name).structuredContent;
|
|
364
|
+
const response = {
|
|
365
|
+
...presented,
|
|
366
|
+
...structured && { structuredContent: structured }
|
|
367
|
+
};
|
|
368
|
+
if (isCallToolResult(response))
|
|
369
|
+
return response;
|
|
370
|
+
return config.formatResult({
|
|
371
|
+
ok: false,
|
|
372
|
+
code: "INTERNAL_SERVER_ERROR",
|
|
373
|
+
details: { message: "Runtime MCP presenter returned an invalid CallToolResult" }
|
|
374
|
+
}, "none", definition.name);
|
|
375
|
+
});
|
|
376
|
+
}
|
|
345
377
|
}
|
|
346
378
|
|
|
347
379
|
// src/tools/portable-formats.ts
|
|
@@ -629,6 +661,37 @@ function prepareMcpTools(tools, config = {}) {
|
|
|
629
661
|
throwIfFailures(failures);
|
|
630
662
|
return Object.freeze(prepared);
|
|
631
663
|
}
|
|
664
|
+
function prepareMcpServerSurface(surface, config = {}) {
|
|
665
|
+
const contractMountables = [];
|
|
666
|
+
const definitions = [];
|
|
667
|
+
const runtimeMountables = [];
|
|
668
|
+
for (const entry of collectToolSurface({
|
|
669
|
+
surface,
|
|
670
|
+
transport: "MCP",
|
|
671
|
+
extend: config.extend,
|
|
672
|
+
flattenUnionInput: config.flattenUnionInput
|
|
673
|
+
})) {
|
|
674
|
+
if (entry.kind === "contract") {
|
|
675
|
+
contractMountables.push(entry.mountable);
|
|
676
|
+
} else {
|
|
677
|
+
definitions.push(entry.definition);
|
|
678
|
+
runtimeMountables.push(entry.mountable);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
const contractTools = prepareMcpTools(contractMountables, config);
|
|
682
|
+
const runtimeDescriptors = prepareMcpTools(runtimeMountables, {
|
|
683
|
+
schemaValidation: config.schemaValidation,
|
|
684
|
+
logger: config.logger
|
|
685
|
+
});
|
|
686
|
+
const descriptorsByName = new Map(runtimeDescriptors.map((descriptor) => [descriptor.mountable.name, descriptor]));
|
|
687
|
+
const runtimeTools = [];
|
|
688
|
+
for (const definition of definitions) {
|
|
689
|
+
const descriptor = descriptorsByName.get(definition.name);
|
|
690
|
+
if (descriptor)
|
|
691
|
+
runtimeTools.push(Object.freeze({ definition, descriptor }));
|
|
692
|
+
}
|
|
693
|
+
return Object.freeze({ contractTools, runtimeTools: Object.freeze(runtimeTools) });
|
|
694
|
+
}
|
|
632
695
|
function validateMcpSchemas(config) {
|
|
633
696
|
prepareMcpSurface(config.services, {
|
|
634
697
|
extend: config.extend,
|
|
@@ -686,8 +749,22 @@ function mountPreparedMcp(mcpServer, prepared, config = {}) {
|
|
|
686
749
|
}
|
|
687
750
|
}
|
|
688
751
|
function buildMcpServer(config, auth) {
|
|
689
|
-
|
|
690
|
-
|
|
752
|
+
let surface;
|
|
753
|
+
if (config.surfaces) {
|
|
754
|
+
const key = config.selectSurface(auth);
|
|
755
|
+
if (!Object.hasOwn(config.surfaces, key)) {
|
|
756
|
+
throw new Error(`[stitchkit] Unknown MCP surface "${key}"`);
|
|
757
|
+
}
|
|
758
|
+
const selected = config.surfaces[key];
|
|
759
|
+
if (!selected)
|
|
760
|
+
throw new Error(`[stitchkit] Unknown MCP surface "${key}"`);
|
|
761
|
+
surface = selected;
|
|
762
|
+
} else {
|
|
763
|
+
const services = typeof config.services === "function" ? config.services(auth) : config.services;
|
|
764
|
+
const runtimeTools = typeof config.runtimeTools === "function" ? config.runtimeTools(auth) : config.runtimeTools;
|
|
765
|
+
surface = { services, runtimeTools };
|
|
766
|
+
}
|
|
767
|
+
const prepared = prepareMcpServerSurface(surface, {
|
|
691
768
|
extend: config.extend,
|
|
692
769
|
flattenUnionInput: config.flattenUnionInput,
|
|
693
770
|
schemaValidation: config.schemaValidation,
|
|
@@ -698,7 +775,7 @@ function buildMcpServer(config, auth) {
|
|
|
698
775
|
function buildMcpServerFromPrepared(config, auth, prepared) {
|
|
699
776
|
const server = new McpServer(config.serverInfo, config.instructions ? { instructions: config.instructions } : undefined);
|
|
700
777
|
const context = config.context?.(auth);
|
|
701
|
-
mountPreparedMcp(server, prepared, {
|
|
778
|
+
mountPreparedMcp(server, prepared.contractTools, {
|
|
702
779
|
context,
|
|
703
780
|
hooks: config.hooks,
|
|
704
781
|
lifecycle: config.lifecycle,
|
|
@@ -710,23 +787,15 @@ function buildMcpServerFromPrepared(config, auth, prepared) {
|
|
|
710
787
|
errorHint: config.errorHint,
|
|
711
788
|
onOutputStrip: config.onOutputStrip
|
|
712
789
|
});
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
prepare: (tool2) => prepareMcpTools([tool2], {
|
|
723
|
-
schemaValidation: config.schemaValidation,
|
|
724
|
-
logger: config.logger
|
|
725
|
-
}),
|
|
726
|
-
formatResult: (result, mode, toolName) => formatMcpResult(result, mode, toolName, config.errorHint)
|
|
727
|
-
});
|
|
728
|
-
config.nativeTools(registrar, auth);
|
|
729
|
-
}
|
|
790
|
+
mountPreparedRuntimeMcp(server, prepared.runtimeTools, {
|
|
791
|
+
context,
|
|
792
|
+
hooks: config.hooks,
|
|
793
|
+
lifecycle: config.lifecycle,
|
|
794
|
+
coerceJsonArgs: config.coerceJsonArgs,
|
|
795
|
+
onOutputStrip: config.onOutputStrip,
|
|
796
|
+
formatResult: (result, mode, toolName) => formatMcpResult(result, mode, toolName, config.errorHint)
|
|
797
|
+
});
|
|
798
|
+
config.rawTools?.(server, auth);
|
|
730
799
|
for (const resource of config.resources ?? []) {
|
|
731
800
|
mountMcpResource(server, resource);
|
|
732
801
|
}
|
|
@@ -838,13 +907,37 @@ function jsonRpcError(code, message, status, headers) {
|
|
|
838
907
|
}
|
|
839
908
|
function createMcpHandler(config) {
|
|
840
909
|
let buildServer;
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
910
|
+
const preparation = {
|
|
911
|
+
logger: config.logger,
|
|
912
|
+
extend: config.extend,
|
|
913
|
+
flattenUnionInput: config.flattenUnionInput,
|
|
914
|
+
schemaValidation: config.schemaValidation
|
|
915
|
+
};
|
|
916
|
+
if (config.surfaces && config.selectSurface) {
|
|
917
|
+
const selectSurface = config.selectSurface;
|
|
918
|
+
const preparedByKey = new Map;
|
|
919
|
+
const preparedBySurface = new WeakMap;
|
|
920
|
+
for (const key in config.surfaces) {
|
|
921
|
+
if (!Object.hasOwn(config.surfaces, key))
|
|
922
|
+
continue;
|
|
923
|
+
const surface = config.surfaces[key];
|
|
924
|
+
if (!surface)
|
|
925
|
+
continue;
|
|
926
|
+
const existing = preparedBySurface.get(surface);
|
|
927
|
+
const prepared = existing ?? prepareMcpServerSurface(surface, preparation);
|
|
928
|
+
if (!existing)
|
|
929
|
+
preparedBySurface.set(surface, prepared);
|
|
930
|
+
preparedByKey.set(key, prepared);
|
|
931
|
+
}
|
|
932
|
+
buildServer = (auth) => {
|
|
933
|
+
const key = selectSurface(auth);
|
|
934
|
+
const prepared = preparedByKey.get(key);
|
|
935
|
+
if (!prepared)
|
|
936
|
+
throw new Error(`[stitchkit] Unknown MCP surface "${key}"`);
|
|
937
|
+
return buildMcpServerFromPrepared(config, auth, prepared);
|
|
938
|
+
};
|
|
939
|
+
} else if (config.services && typeof config.services !== "function" && typeof config.runtimeTools !== "function") {
|
|
940
|
+
const prepared = prepareMcpServerSurface({ services: config.services, runtimeTools: config.runtimeTools }, preparation);
|
|
848
941
|
buildServer = (auth) => buildMcpServerFromPrepared(config, auth, prepared);
|
|
849
942
|
} else {
|
|
850
943
|
buildServer = (auth) => buildMcpServer(config, auth);
|
|
@@ -1727,27 +1820,71 @@ function createToolkit() {
|
|
|
1727
1820
|
};
|
|
1728
1821
|
}
|
|
1729
1822
|
// src/tools/transports.ts
|
|
1823
|
+
var ALL_TRANSPORTS = ["HTTP", "MCP", "AGENT", "CLI"];
|
|
1730
1824
|
var TOOL_TRANSPORTS2 = ["MCP", "AGENT", "CLI"];
|
|
1731
1825
|
function emptyCounts() {
|
|
1732
1826
|
return { HTTP: 0, MCP: 0, AGENT: 0, CLI: 0 };
|
|
1733
1827
|
}
|
|
1734
|
-
function
|
|
1828
|
+
function contractCounts(service) {
|
|
1829
|
+
const counts = emptyCounts();
|
|
1830
|
+
for (const method of Object.values(service.methods)) {
|
|
1831
|
+
if (!method.expose || method.expose.includes("HTTP"))
|
|
1832
|
+
counts.HTTP += 1;
|
|
1833
|
+
}
|
|
1834
|
+
for (const transport of TOOL_TRANSPORTS2) {
|
|
1835
|
+
counts[transport] = collectToolSurface({
|
|
1836
|
+
surface: { services: [service] },
|
|
1837
|
+
transport,
|
|
1838
|
+
assertNames: false,
|
|
1839
|
+
assertUniqueNames: false
|
|
1840
|
+
}).length;
|
|
1841
|
+
}
|
|
1842
|
+
return counts;
|
|
1843
|
+
}
|
|
1844
|
+
function runtimeCounts(runtimeTools) {
|
|
1845
|
+
const counts = emptyCounts();
|
|
1846
|
+
for (const transport of TOOL_TRANSPORTS2) {
|
|
1847
|
+
counts[transport] = collectToolSurface({
|
|
1848
|
+
surface: { runtimeTools },
|
|
1849
|
+
transport,
|
|
1850
|
+
assertNames: false,
|
|
1851
|
+
assertUniqueNames: false
|
|
1852
|
+
}).length;
|
|
1853
|
+
}
|
|
1854
|
+
return counts;
|
|
1855
|
+
}
|
|
1856
|
+
function addCounts(target, source) {
|
|
1857
|
+
for (const transport of ALL_TRANSPORTS)
|
|
1858
|
+
target[transport] += source[transport];
|
|
1859
|
+
}
|
|
1860
|
+
function summarizeTransports(surface) {
|
|
1735
1861
|
const totals = emptyCounts();
|
|
1736
|
-
const
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1862
|
+
const sources = [];
|
|
1863
|
+
for (const service of surface.services ?? []) {
|
|
1864
|
+
const counts = contractCounts(service);
|
|
1865
|
+
addCounts(totals, counts);
|
|
1866
|
+
sources.push({ kind: "contract", service: service.name, counts });
|
|
1867
|
+
}
|
|
1868
|
+
const runtimeGroups = new Map;
|
|
1869
|
+
for (const definition of surface.runtimeTools ?? []) {
|
|
1870
|
+
const service = definition.identity.serviceName;
|
|
1871
|
+
const group = runtimeGroups.get(service);
|
|
1872
|
+
if (group)
|
|
1873
|
+
group.push(definition);
|
|
1874
|
+
else
|
|
1875
|
+
runtimeGroups.set(service, [definition]);
|
|
1876
|
+
}
|
|
1877
|
+
for (const [service, runtimeTools] of runtimeGroups) {
|
|
1878
|
+
const counts = runtimeCounts(runtimeTools);
|
|
1879
|
+
addCounts(totals, counts);
|
|
1880
|
+
sources.push({ kind: "runtime", service, counts });
|
|
1881
|
+
}
|
|
1882
|
+
return {
|
|
1883
|
+
contractServices: surface.services?.length ?? 0,
|
|
1884
|
+
runtimeTools: surface.runtimeTools?.length ?? 0,
|
|
1885
|
+
totals,
|
|
1886
|
+
sources
|
|
1887
|
+
};
|
|
1751
1888
|
}
|
|
1752
1889
|
// src/tools/view-file.ts
|
|
1753
1890
|
import { readFile, realpath, stat } from "node:fs/promises";
|