stitchkit 0.41.0 → 0.43.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/README.md +22 -5
- 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/factory.d.ts +29 -2
- package/dist/contract/factory.d.ts.map +1 -1
- package/dist/contract/index.d.ts +2 -2
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/contract/index.js +2 -2
- package/dist/{index-dnkefke9.js → index-310bfer5.js} +1 -1
- package/dist/{index-4e1c0hsw.js → index-esqmem78.js} +101 -67
- package/dist/{index-sc67e454.js → index-gex6gxhe.js} +7 -4
- package/dist/{index-ncqqn1bc.js → index-h2wdcsby.js} +95 -17
- package/dist/{index-xax049k6.js → index-r6czv7yt.js} +58 -22
- 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/audit.d.ts +27 -15
- package/dist/observability/audit.d.ts.map +1 -1
- package/dist/observability/event.d.ts +2 -2
- package/dist/observability/index.d.ts +4 -4
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js +70 -59
- package/dist/react.js +1 -1
- package/dist/server/create.d.ts.map +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/server/logger.d.ts +0 -1
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/types.d.ts +8 -13
- package/dist/server/types.d.ts.map +1 -1
- package/dist/tools/agent.d.ts +1 -1
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/flatten-join.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 +32 -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 +6 -6
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +330 -155
- package/llms-full.txt +524 -131
- package/llms.txt +1 -0
- package/package.json +2 -2
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-h2wdcsby.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";
|
|
@@ -51,6 +51,43 @@ function defineRuntimeTool(definition) {
|
|
|
51
51
|
}
|
|
52
52
|
return definition;
|
|
53
53
|
}
|
|
54
|
+
function createRuntimeToolFactory(config) {
|
|
55
|
+
function parseContext(context) {
|
|
56
|
+
const parsed = config.context.parse(context);
|
|
57
|
+
return { ...parsed, params: undefined, input: context.input };
|
|
58
|
+
}
|
|
59
|
+
function define(definition) {
|
|
60
|
+
if (definition.output !== undefined) {
|
|
61
|
+
const { action: action2, method: method2, meta: meta2, handler: handler2, ...tool2 } = definition;
|
|
62
|
+
const identity2 = {
|
|
63
|
+
serviceName: config.serviceName,
|
|
64
|
+
action: action2,
|
|
65
|
+
method: method2,
|
|
66
|
+
...config.scope !== undefined && { scope: config.scope },
|
|
67
|
+
...(meta2 ?? config.meta) !== undefined && { meta: meta2 ?? config.meta }
|
|
68
|
+
};
|
|
69
|
+
return defineRuntimeTool({
|
|
70
|
+
...tool2,
|
|
71
|
+
identity: identity2,
|
|
72
|
+
handler: (context) => handler2(parseContext(context))
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
const { action, method, meta, handler, ...tool } = definition;
|
|
76
|
+
const identity = {
|
|
77
|
+
serviceName: config.serviceName,
|
|
78
|
+
action,
|
|
79
|
+
method,
|
|
80
|
+
...config.scope !== undefined && { scope: config.scope },
|
|
81
|
+
...(meta ?? config.meta) !== undefined && { meta: meta ?? config.meta }
|
|
82
|
+
};
|
|
83
|
+
return defineRuntimeTool({
|
|
84
|
+
...tool,
|
|
85
|
+
identity,
|
|
86
|
+
handler: (context) => handler(parseContext(context))
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return { define };
|
|
90
|
+
}
|
|
54
91
|
function runtimeToolSupports(definition, transport) {
|
|
55
92
|
if (definition.transports?.length === 0) {
|
|
56
93
|
throw new Error(`Runtime tool "${definition.name}" must expose at least one transport`);
|
|
@@ -70,8 +107,10 @@ function runtimeToolIdentity(definition) {
|
|
|
70
107
|
ui: definition.ui
|
|
71
108
|
};
|
|
72
109
|
}
|
|
73
|
-
function runtimeToolMountable(definition) {
|
|
74
|
-
|
|
110
|
+
function runtimeToolMountable(definition, assertName = true) {
|
|
111
|
+
if (assertName) {
|
|
112
|
+
assertToolName(definition.name, definition.identity.serviceName, definition.identity.action);
|
|
113
|
+
}
|
|
75
114
|
const method = {
|
|
76
115
|
...runtimeToolIdentity(definition),
|
|
77
116
|
inputSchema: definition.input,
|
|
@@ -90,6 +129,55 @@ function runtimeToolMountable(definition) {
|
|
|
90
129
|
};
|
|
91
130
|
}
|
|
92
131
|
|
|
132
|
+
// src/tools/surface.ts
|
|
133
|
+
function duplicateLabel(transport) {
|
|
134
|
+
if (transport === "MCP")
|
|
135
|
+
return "MCP tool name";
|
|
136
|
+
if (transport === "AGENT")
|
|
137
|
+
return "agent tool name";
|
|
138
|
+
return "CLI command";
|
|
139
|
+
}
|
|
140
|
+
function collectToolSurface({
|
|
141
|
+
surface,
|
|
142
|
+
transport,
|
|
143
|
+
assertUniqueNames = true,
|
|
144
|
+
...collectConfig
|
|
145
|
+
}) {
|
|
146
|
+
const entries = [];
|
|
147
|
+
const names = new Set;
|
|
148
|
+
const append = (entry) => {
|
|
149
|
+
if (assertUniqueNames) {
|
|
150
|
+
assertUniqueToolName(entry.mountable.name, names.has(entry.mountable.name), duplicateLabel(transport));
|
|
151
|
+
}
|
|
152
|
+
names.add(entry.mountable.name);
|
|
153
|
+
entries.push(entry);
|
|
154
|
+
};
|
|
155
|
+
for (const service of surface.services ?? []) {
|
|
156
|
+
for (const mountable of collectTools(service, transport, collectConfig)) {
|
|
157
|
+
append({
|
|
158
|
+
kind: "contract",
|
|
159
|
+
service: service.name,
|
|
160
|
+
action: mountable.method.key,
|
|
161
|
+
mountable
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (transport === "CLI")
|
|
166
|
+
return entries;
|
|
167
|
+
for (const definition of surface.runtimeTools ?? []) {
|
|
168
|
+
if (!runtimeToolSupports(definition, transport))
|
|
169
|
+
continue;
|
|
170
|
+
append({
|
|
171
|
+
kind: "runtime",
|
|
172
|
+
service: definition.identity.serviceName,
|
|
173
|
+
action: definition.identity.action,
|
|
174
|
+
mountable: runtimeToolMountable(definition, collectConfig.assertNames),
|
|
175
|
+
definition
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return entries;
|
|
179
|
+
}
|
|
180
|
+
|
|
93
181
|
// src/tools/agent.ts
|
|
94
182
|
function mountAgent(services, config = {}) {
|
|
95
183
|
const serviceList = Array.isArray(services) ? services : [services];
|
|
@@ -104,36 +192,13 @@ function mountAgent(services, config = {}) {
|
|
|
104
192
|
coerceJsonArgs: config.coerceJsonArgs,
|
|
105
193
|
onOutputStrip: config.onOutputStrip
|
|
106
194
|
});
|
|
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");
|
|
195
|
+
for (const entry of collectToolSurface({
|
|
196
|
+
surface: { services: serviceList, runtimeTools: config.runtimeTools },
|
|
197
|
+
transport: "AGENT",
|
|
198
|
+
extend: config.extend,
|
|
199
|
+
flattenUnionInput: config.flattenUnionInput
|
|
200
|
+
})) {
|
|
201
|
+
const { mountable } = entry;
|
|
137
202
|
const inputSchema = jsonSchema(mountable.presentationSchema, {
|
|
138
203
|
validate: async (value) => isRecord(value) ? { success: true, value } : { success: false, error: new Error("Tool arguments must be an object") }
|
|
139
204
|
});
|
|
@@ -148,9 +213,13 @@ function mountAgent(services, config = {}) {
|
|
|
148
213
|
return formatToolError(toolResultFromError(err), mountable.name, config.errorHint);
|
|
149
214
|
}
|
|
150
215
|
};
|
|
151
|
-
|
|
152
|
-
|
|
216
|
+
const presenter = entry.kind === "runtime" ? entry.definition.present?.agent : undefined;
|
|
217
|
+
if (entry.kind === "runtime" && presenter) {
|
|
218
|
+
const { definition } = entry;
|
|
153
219
|
const output = definition.output;
|
|
220
|
+
if (!output) {
|
|
221
|
+
throw new Error(`Runtime tool "${definition.name}" presenter requires an output schema`);
|
|
222
|
+
}
|
|
154
223
|
tools[definition.name] = tool({
|
|
155
224
|
description: definition.description,
|
|
156
225
|
inputSchema,
|
|
@@ -165,10 +234,11 @@ function mountAgent(services, config = {}) {
|
|
|
165
234
|
}
|
|
166
235
|
});
|
|
167
236
|
} else {
|
|
168
|
-
|
|
169
|
-
|
|
237
|
+
const output = entry.kind === "runtime" ? entry.definition.output : undefined;
|
|
238
|
+
tools[mountable.name] = tool({
|
|
239
|
+
description: mountable.method.desc,
|
|
170
240
|
inputSchema,
|
|
171
|
-
...
|
|
241
|
+
...output && { outputSchema: output },
|
|
172
242
|
execute
|
|
173
243
|
});
|
|
174
244
|
}
|
|
@@ -224,34 +294,43 @@ function createToolInvoker(services, config) {
|
|
|
224
294
|
}
|
|
225
295
|
// src/tools/list-names.ts
|
|
226
296
|
var TOOL_TRANSPORTS = ["MCP", "AGENT", "CLI"];
|
|
227
|
-
function listToolNames(
|
|
297
|
+
function listToolNames(surface) {
|
|
228
298
|
const entries = new Map;
|
|
229
|
-
for (const
|
|
230
|
-
for (const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
299
|
+
for (const transport of TOOL_TRANSPORTS) {
|
|
300
|
+
for (const entry of collectToolSurface({
|
|
301
|
+
surface,
|
|
302
|
+
transport,
|
|
303
|
+
assertNames: false,
|
|
304
|
+
assertUniqueNames: false
|
|
305
|
+
})) {
|
|
306
|
+
const id = `${entry.kind}\x00${entry.service}\x00${entry.action}`;
|
|
307
|
+
const existing = entries.get(id);
|
|
308
|
+
if (existing) {
|
|
309
|
+
existing.transports.push(transport);
|
|
310
|
+
} else {
|
|
311
|
+
entries.set(id, {
|
|
312
|
+
kind: entry.kind,
|
|
313
|
+
name: entry.mountable.name,
|
|
314
|
+
service: entry.service,
|
|
315
|
+
method: entry.action,
|
|
316
|
+
transports: [transport]
|
|
317
|
+
});
|
|
244
318
|
}
|
|
245
319
|
}
|
|
246
320
|
}
|
|
247
321
|
return [...entries.values()].sort((a, b) => a.name.localeCompare(b.name) || a.service.localeCompare(b.service));
|
|
248
322
|
}
|
|
249
323
|
// src/tools/manifest.ts
|
|
250
|
-
function buildToolManifest(
|
|
251
|
-
return
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
324
|
+
function buildToolManifest(config) {
|
|
325
|
+
return collectToolSurface({
|
|
326
|
+
surface: config,
|
|
327
|
+
transport: config.transport,
|
|
328
|
+
extend: config.extend,
|
|
329
|
+
flattenUnionInput: config.flattenUnionInput
|
|
330
|
+
}).map(({ mountable }) => ({
|
|
331
|
+
name: mountable.name,
|
|
332
|
+
description: mountable.method.desc,
|
|
333
|
+
inputSchema: mountable.presentationSchema
|
|
255
334
|
}));
|
|
256
335
|
}
|
|
257
336
|
// src/tools/mcp.ts
|
|
@@ -285,63 +364,53 @@ import { z } from "zod";
|
|
|
285
364
|
function isCallToolResult(value) {
|
|
286
365
|
return CallToolResultSchema.safeParse(value).success;
|
|
287
366
|
}
|
|
288
|
-
function
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
367
|
+
function mountPreparedRuntimeMcp(server, tools, config) {
|
|
368
|
+
for (const { definition, descriptor } of tools) {
|
|
369
|
+
const { mountable } = descriptor;
|
|
370
|
+
const toolConfig = {
|
|
371
|
+
description: definition.description,
|
|
372
|
+
inputSchema: z.looseObject({}).meta(presentationMetadata(descriptor.inputSchema))
|
|
373
|
+
};
|
|
374
|
+
if (descriptor.outputSchema)
|
|
375
|
+
toolConfig.outputSchema = descriptor.outputSchema;
|
|
376
|
+
if (definition.annotations)
|
|
377
|
+
toolConfig.annotations = definition.annotations;
|
|
378
|
+
if (definition.ui) {
|
|
379
|
+
toolConfig._meta = {
|
|
380
|
+
ui: definition.ui,
|
|
381
|
+
"ui/resourceUri": definition.ui.resourceUri
|
|
303
382
|
};
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
if (definition.
|
|
309
|
-
|
|
310
|
-
ui: definition.ui,
|
|
311
|
-
"ui/resourceUri": definition.ui.resourceUri
|
|
312
|
-
};
|
|
383
|
+
}
|
|
384
|
+
server.registerTool(definition.name, toolConfig, async (rawArgs) => {
|
|
385
|
+
const args = isRecord(rawArgs) ? rawArgs : {};
|
|
386
|
+
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);
|
|
387
|
+
if (!result.ok || !definition.present?.mcp) {
|
|
388
|
+
return config.formatResult(result, descriptor.outputMode, definition.name);
|
|
313
389
|
}
|
|
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;
|
|
390
|
+
const presented = await definition.present.mcp(result.data);
|
|
391
|
+
if ("structuredContent" in presented || "isError" in presented) {
|
|
337
392
|
return config.formatResult({
|
|
338
393
|
ok: false,
|
|
339
394
|
code: "INTERNAL_SERVER_ERROR",
|
|
340
|
-
details: {
|
|
395
|
+
details: {
|
|
396
|
+
message: "Runtime MCP presenter cannot set framework-owned structuredContent or isError"
|
|
397
|
+
}
|
|
341
398
|
}, "none", definition.name);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
|
|
399
|
+
}
|
|
400
|
+
const structured = config.formatResult(result, descriptor.outputMode, definition.name).structuredContent;
|
|
401
|
+
const response = {
|
|
402
|
+
...presented,
|
|
403
|
+
...structured && { structuredContent: structured }
|
|
404
|
+
};
|
|
405
|
+
if (isCallToolResult(response))
|
|
406
|
+
return response;
|
|
407
|
+
return config.formatResult({
|
|
408
|
+
ok: false,
|
|
409
|
+
code: "INTERNAL_SERVER_ERROR",
|
|
410
|
+
details: { message: "Runtime MCP presenter returned an invalid CallToolResult" }
|
|
411
|
+
}, "none", definition.name);
|
|
412
|
+
});
|
|
413
|
+
}
|
|
345
414
|
}
|
|
346
415
|
|
|
347
416
|
// src/tools/portable-formats.ts
|
|
@@ -629,6 +698,37 @@ function prepareMcpTools(tools, config = {}) {
|
|
|
629
698
|
throwIfFailures(failures);
|
|
630
699
|
return Object.freeze(prepared);
|
|
631
700
|
}
|
|
701
|
+
function prepareMcpServerSurface(surface, config = {}) {
|
|
702
|
+
const contractMountables = [];
|
|
703
|
+
const definitions = [];
|
|
704
|
+
const runtimeMountables = [];
|
|
705
|
+
for (const entry of collectToolSurface({
|
|
706
|
+
surface,
|
|
707
|
+
transport: "MCP",
|
|
708
|
+
extend: config.extend,
|
|
709
|
+
flattenUnionInput: config.flattenUnionInput
|
|
710
|
+
})) {
|
|
711
|
+
if (entry.kind === "contract") {
|
|
712
|
+
contractMountables.push(entry.mountable);
|
|
713
|
+
} else {
|
|
714
|
+
definitions.push(entry.definition);
|
|
715
|
+
runtimeMountables.push(entry.mountable);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
const contractTools = prepareMcpTools(contractMountables, config);
|
|
719
|
+
const runtimeDescriptors = prepareMcpTools(runtimeMountables, {
|
|
720
|
+
schemaValidation: config.schemaValidation,
|
|
721
|
+
logger: config.logger
|
|
722
|
+
});
|
|
723
|
+
const descriptorsByName = new Map(runtimeDescriptors.map((descriptor) => [descriptor.mountable.name, descriptor]));
|
|
724
|
+
const runtimeTools = [];
|
|
725
|
+
for (const definition of definitions) {
|
|
726
|
+
const descriptor = descriptorsByName.get(definition.name);
|
|
727
|
+
if (descriptor)
|
|
728
|
+
runtimeTools.push(Object.freeze({ definition, descriptor }));
|
|
729
|
+
}
|
|
730
|
+
return Object.freeze({ contractTools, runtimeTools: Object.freeze(runtimeTools) });
|
|
731
|
+
}
|
|
632
732
|
function validateMcpSchemas(config) {
|
|
633
733
|
prepareMcpSurface(config.services, {
|
|
634
734
|
extend: config.extend,
|
|
@@ -686,8 +786,22 @@ function mountPreparedMcp(mcpServer, prepared, config = {}) {
|
|
|
686
786
|
}
|
|
687
787
|
}
|
|
688
788
|
function buildMcpServer(config, auth) {
|
|
689
|
-
|
|
690
|
-
|
|
789
|
+
let surface;
|
|
790
|
+
if (config.surfaces) {
|
|
791
|
+
const key = config.selectSurface(auth);
|
|
792
|
+
if (!Object.hasOwn(config.surfaces, key)) {
|
|
793
|
+
throw new Error(`[stitchkit] Unknown MCP surface "${key}"`);
|
|
794
|
+
}
|
|
795
|
+
const selected = config.surfaces[key];
|
|
796
|
+
if (!selected)
|
|
797
|
+
throw new Error(`[stitchkit] Unknown MCP surface "${key}"`);
|
|
798
|
+
surface = selected;
|
|
799
|
+
} else {
|
|
800
|
+
const services = typeof config.services === "function" ? config.services(auth) : config.services;
|
|
801
|
+
const runtimeTools = typeof config.runtimeTools === "function" ? config.runtimeTools(auth) : config.runtimeTools;
|
|
802
|
+
surface = { services, runtimeTools };
|
|
803
|
+
}
|
|
804
|
+
const prepared = prepareMcpServerSurface(surface, {
|
|
691
805
|
extend: config.extend,
|
|
692
806
|
flattenUnionInput: config.flattenUnionInput,
|
|
693
807
|
schemaValidation: config.schemaValidation,
|
|
@@ -698,7 +812,7 @@ function buildMcpServer(config, auth) {
|
|
|
698
812
|
function buildMcpServerFromPrepared(config, auth, prepared) {
|
|
699
813
|
const server = new McpServer(config.serverInfo, config.instructions ? { instructions: config.instructions } : undefined);
|
|
700
814
|
const context = config.context?.(auth);
|
|
701
|
-
mountPreparedMcp(server, prepared, {
|
|
815
|
+
mountPreparedMcp(server, prepared.contractTools, {
|
|
702
816
|
context,
|
|
703
817
|
hooks: config.hooks,
|
|
704
818
|
lifecycle: config.lifecycle,
|
|
@@ -710,23 +824,15 @@ function buildMcpServerFromPrepared(config, auth, prepared) {
|
|
|
710
824
|
errorHint: config.errorHint,
|
|
711
825
|
onOutputStrip: config.onOutputStrip
|
|
712
826
|
});
|
|
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
|
-
}
|
|
827
|
+
mountPreparedRuntimeMcp(server, prepared.runtimeTools, {
|
|
828
|
+
context,
|
|
829
|
+
hooks: config.hooks,
|
|
830
|
+
lifecycle: config.lifecycle,
|
|
831
|
+
coerceJsonArgs: config.coerceJsonArgs,
|
|
832
|
+
onOutputStrip: config.onOutputStrip,
|
|
833
|
+
formatResult: (result, mode, toolName) => formatMcpResult(result, mode, toolName, config.errorHint)
|
|
834
|
+
});
|
|
835
|
+
config.rawTools?.(server, auth);
|
|
730
836
|
for (const resource of config.resources ?? []) {
|
|
731
837
|
mountMcpResource(server, resource);
|
|
732
838
|
}
|
|
@@ -838,13 +944,37 @@ function jsonRpcError(code, message, status, headers) {
|
|
|
838
944
|
}
|
|
839
945
|
function createMcpHandler(config) {
|
|
840
946
|
let buildServer;
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
947
|
+
const preparation = {
|
|
948
|
+
logger: config.logger,
|
|
949
|
+
extend: config.extend,
|
|
950
|
+
flattenUnionInput: config.flattenUnionInput,
|
|
951
|
+
schemaValidation: config.schemaValidation
|
|
952
|
+
};
|
|
953
|
+
if (config.surfaces && config.selectSurface) {
|
|
954
|
+
const selectSurface = config.selectSurface;
|
|
955
|
+
const preparedByKey = new Map;
|
|
956
|
+
const preparedBySurface = new WeakMap;
|
|
957
|
+
for (const key in config.surfaces) {
|
|
958
|
+
if (!Object.hasOwn(config.surfaces, key))
|
|
959
|
+
continue;
|
|
960
|
+
const surface = config.surfaces[key];
|
|
961
|
+
if (!surface)
|
|
962
|
+
continue;
|
|
963
|
+
const existing = preparedBySurface.get(surface);
|
|
964
|
+
const prepared = existing ?? prepareMcpServerSurface(surface, preparation);
|
|
965
|
+
if (!existing)
|
|
966
|
+
preparedBySurface.set(surface, prepared);
|
|
967
|
+
preparedByKey.set(key, prepared);
|
|
968
|
+
}
|
|
969
|
+
buildServer = (auth) => {
|
|
970
|
+
const key = selectSurface(auth);
|
|
971
|
+
const prepared = preparedByKey.get(key);
|
|
972
|
+
if (!prepared)
|
|
973
|
+
throw new Error(`[stitchkit] Unknown MCP surface "${key}"`);
|
|
974
|
+
return buildMcpServerFromPrepared(config, auth, prepared);
|
|
975
|
+
};
|
|
976
|
+
} else if (config.services && typeof config.services !== "function" && typeof config.runtimeTools !== "function") {
|
|
977
|
+
const prepared = prepareMcpServerSurface({ services: config.services, runtimeTools: config.runtimeTools }, preparation);
|
|
848
978
|
buildServer = (auth) => buildMcpServerFromPrepared(config, auth, prepared);
|
|
849
979
|
} else {
|
|
850
980
|
buildServer = (auth) => buildMcpServer(config, auth);
|
|
@@ -1727,27 +1857,71 @@ function createToolkit() {
|
|
|
1727
1857
|
};
|
|
1728
1858
|
}
|
|
1729
1859
|
// src/tools/transports.ts
|
|
1860
|
+
var ALL_TRANSPORTS = ["HTTP", "MCP", "AGENT", "CLI"];
|
|
1730
1861
|
var TOOL_TRANSPORTS2 = ["MCP", "AGENT", "CLI"];
|
|
1731
1862
|
function emptyCounts() {
|
|
1732
1863
|
return { HTTP: 0, MCP: 0, AGENT: 0, CLI: 0 };
|
|
1733
1864
|
}
|
|
1734
|
-
function
|
|
1865
|
+
function contractCounts(service) {
|
|
1866
|
+
const counts = emptyCounts();
|
|
1867
|
+
for (const method of Object.values(service.methods)) {
|
|
1868
|
+
if (!method.expose || method.expose.includes("HTTP"))
|
|
1869
|
+
counts.HTTP += 1;
|
|
1870
|
+
}
|
|
1871
|
+
for (const transport of TOOL_TRANSPORTS2) {
|
|
1872
|
+
counts[transport] = collectToolSurface({
|
|
1873
|
+
surface: { services: [service] },
|
|
1874
|
+
transport,
|
|
1875
|
+
assertNames: false,
|
|
1876
|
+
assertUniqueNames: false
|
|
1877
|
+
}).length;
|
|
1878
|
+
}
|
|
1879
|
+
return counts;
|
|
1880
|
+
}
|
|
1881
|
+
function runtimeCounts(runtimeTools) {
|
|
1882
|
+
const counts = emptyCounts();
|
|
1883
|
+
for (const transport of TOOL_TRANSPORTS2) {
|
|
1884
|
+
counts[transport] = collectToolSurface({
|
|
1885
|
+
surface: { runtimeTools },
|
|
1886
|
+
transport,
|
|
1887
|
+
assertNames: false,
|
|
1888
|
+
assertUniqueNames: false
|
|
1889
|
+
}).length;
|
|
1890
|
+
}
|
|
1891
|
+
return counts;
|
|
1892
|
+
}
|
|
1893
|
+
function addCounts(target, source) {
|
|
1894
|
+
for (const transport of ALL_TRANSPORTS)
|
|
1895
|
+
target[transport] += source[transport];
|
|
1896
|
+
}
|
|
1897
|
+
function summarizeTransports(surface) {
|
|
1735
1898
|
const totals = emptyCounts();
|
|
1736
|
-
const
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1899
|
+
const sources = [];
|
|
1900
|
+
for (const service of surface.services ?? []) {
|
|
1901
|
+
const counts = contractCounts(service);
|
|
1902
|
+
addCounts(totals, counts);
|
|
1903
|
+
sources.push({ kind: "contract", service: service.name, counts });
|
|
1904
|
+
}
|
|
1905
|
+
const runtimeGroups = new Map;
|
|
1906
|
+
for (const definition of surface.runtimeTools ?? []) {
|
|
1907
|
+
const service = definition.identity.serviceName;
|
|
1908
|
+
const group = runtimeGroups.get(service);
|
|
1909
|
+
if (group)
|
|
1910
|
+
group.push(definition);
|
|
1911
|
+
else
|
|
1912
|
+
runtimeGroups.set(service, [definition]);
|
|
1913
|
+
}
|
|
1914
|
+
for (const [service, runtimeTools] of runtimeGroups) {
|
|
1915
|
+
const counts = runtimeCounts(runtimeTools);
|
|
1916
|
+
addCounts(totals, counts);
|
|
1917
|
+
sources.push({ kind: "runtime", service, counts });
|
|
1918
|
+
}
|
|
1919
|
+
return {
|
|
1920
|
+
contractServices: surface.services?.length ?? 0,
|
|
1921
|
+
runtimeTools: surface.runtimeTools?.length ?? 0,
|
|
1922
|
+
totals,
|
|
1923
|
+
sources
|
|
1924
|
+
};
|
|
1751
1925
|
}
|
|
1752
1926
|
// src/tools/view-file.ts
|
|
1753
1927
|
import { readFile, realpath, stat } from "node:fs/promises";
|
|
@@ -1897,6 +2071,7 @@ export {
|
|
|
1897
2071
|
createToolLogger,
|
|
1898
2072
|
createToolInvoker,
|
|
1899
2073
|
createStdioMcpServer,
|
|
2074
|
+
createRuntimeToolFactory,
|
|
1900
2075
|
createMcpHandler,
|
|
1901
2076
|
createCli,
|
|
1902
2077
|
collectTools,
|