@frontmcp/sdk 0.3.0 → 0.4.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/LICENSE +201 -0
- package/README.md +192 -164
- package/package.json +7 -4
- package/src/__test-utils__/fixtures/hook.fixtures.d.ts +46 -0
- package/src/__test-utils__/fixtures/hook.fixtures.js +114 -0
- package/src/__test-utils__/fixtures/hook.fixtures.js.map +1 -0
- package/src/__test-utils__/fixtures/index.d.ts +7 -0
- package/src/__test-utils__/fixtures/index.js +11 -0
- package/src/__test-utils__/fixtures/index.js.map +1 -0
- package/src/__test-utils__/fixtures/plugin.fixtures.d.ts +46 -0
- package/src/__test-utils__/fixtures/plugin.fixtures.js +127 -0
- package/src/__test-utils__/fixtures/plugin.fixtures.js.map +1 -0
- package/src/__test-utils__/fixtures/provider.fixtures.d.ts +69 -0
- package/src/__test-utils__/fixtures/provider.fixtures.js +131 -0
- package/src/__test-utils__/fixtures/provider.fixtures.js.map +1 -0
- package/src/__test-utils__/fixtures/scope.fixtures.d.ts +14 -0
- package/src/__test-utils__/fixtures/scope.fixtures.js +59 -0
- package/src/__test-utils__/fixtures/scope.fixtures.js.map +1 -0
- package/src/__test-utils__/fixtures/tool.fixtures.d.ts +36 -0
- package/src/__test-utils__/fixtures/tool.fixtures.js +91 -0
- package/src/__test-utils__/fixtures/tool.fixtures.js.map +1 -0
- package/src/__test-utils__/helpers/assertion.helpers.d.ts +45 -0
- package/src/__test-utils__/helpers/assertion.helpers.js +153 -0
- package/src/__test-utils__/helpers/assertion.helpers.js.map +1 -0
- package/src/__test-utils__/helpers/async.helpers.d.ts +48 -0
- package/src/__test-utils__/helpers/async.helpers.js +112 -0
- package/src/__test-utils__/helpers/async.helpers.js.map +1 -0
- package/src/__test-utils__/helpers/index.d.ts +6 -0
- package/src/__test-utils__/helpers/index.js +10 -0
- package/src/__test-utils__/helpers/index.js.map +1 -0
- package/src/__test-utils__/helpers/setup.helpers.d.ts +54 -0
- package/src/__test-utils__/helpers/setup.helpers.js +106 -0
- package/src/__test-utils__/helpers/setup.helpers.js.map +1 -0
- package/src/__test-utils__/index.d.ts +9 -0
- package/src/__test-utils__/index.js +14 -0
- package/src/__test-utils__/index.js.map +1 -0
- package/src/__test-utils__/mocks/flow-instance.mock.d.ts +50 -0
- package/src/__test-utils__/mocks/flow-instance.mock.js +72 -0
- package/src/__test-utils__/mocks/flow-instance.mock.js.map +1 -0
- package/src/__test-utils__/mocks/hook-registry.mock.d.ts +25 -0
- package/src/__test-utils__/mocks/hook-registry.mock.js +65 -0
- package/src/__test-utils__/mocks/hook-registry.mock.js.map +1 -0
- package/src/__test-utils__/mocks/index.d.ts +8 -0
- package/src/__test-utils__/mocks/index.js +12 -0
- package/src/__test-utils__/mocks/index.js.map +1 -0
- package/src/__test-utils__/mocks/plugin-registry.mock.d.ts +43 -0
- package/src/__test-utils__/mocks/plugin-registry.mock.js +70 -0
- package/src/__test-utils__/mocks/plugin-registry.mock.js.map +1 -0
- package/src/__test-utils__/mocks/provider-registry.mock.d.ts +39 -0
- package/src/__test-utils__/mocks/provider-registry.mock.js +72 -0
- package/src/__test-utils__/mocks/provider-registry.mock.js.map +1 -0
- package/src/__test-utils__/mocks/tool-registry.mock.d.ts +43 -0
- package/src/__test-utils__/mocks/tool-registry.mock.js +79 -0
- package/src/__test-utils__/mocks/tool-registry.mock.js.map +1 -0
- package/src/app/app.utils.js.map +1 -1
- package/src/app/instances/app.local.instance.js +8 -11
- package/src/app/instances/app.local.instance.js.map +1 -1
- package/src/auth/auth.registry.d.ts +2 -2
- package/src/auth/auth.registry.js +3 -3
- package/src/auth/auth.registry.js.map +1 -1
- package/src/auth/flows/oauth.authorize.flow.d.ts +8 -8
- package/src/auth/flows/oauth.register.flow.d.ts +4 -4
- package/src/auth/flows/oauth.token.flow.d.ts +4 -4
- package/src/auth/flows/well-known.jwks.flow.d.ts +12 -12
- package/src/auth/flows/well-known.oauth-authorization-server.flow.d.ts +8 -8
- package/src/auth/flows/well-known.prm.flow.d.ts +4 -4
- package/src/auth/instances/instance.local-primary-auth.d.ts +3 -2
- package/src/auth/instances/instance.local-primary-auth.js +4 -2
- package/src/auth/instances/instance.local-primary-auth.js.map +1 -1
- package/src/auth/instances/instance.remote-primary-auth.d.ts +3 -2
- package/src/auth/instances/instance.remote-primary-auth.js +3 -1
- package/src/auth/instances/instance.remote-primary-auth.js.map +1 -1
- package/src/auth/jwks/jwks.service.js +0 -1
- package/src/auth/jwks/jwks.service.js.map +1 -1
- package/src/common/decorators/tool.decorator.d.ts +97 -36
- package/src/common/decorators/tool.decorator.js +0 -1
- package/src/common/decorators/tool.decorator.js.map +1 -1
- package/src/common/entries/scope.entry.d.ts +1 -0
- package/src/common/entries/scope.entry.js +6 -0
- package/src/common/entries/scope.entry.js.map +1 -1
- package/src/common/entries/tool.entry.d.ts +54 -11
- package/src/common/entries/tool.entry.js +19 -0
- package/src/common/entries/tool.entry.js.map +1 -1
- package/src/common/interfaces/internal/registry.interface.d.ts +10 -2
- package/src/common/interfaces/internal/registry.interface.js.map +1 -1
- package/src/common/interfaces/plugin.interface.d.ts +1 -1
- package/src/common/interfaces/plugin.interface.js.map +1 -1
- package/src/common/interfaces/tool.interface.d.ts +12 -7
- package/src/common/interfaces/tool.interface.js +1 -1
- package/src/common/interfaces/tool.interface.js.map +1 -1
- package/src/common/metadata/front-mcp.metadata.d.ts +145 -145
- package/src/common/metadata/hook.metadata.d.ts +4 -2
- package/src/common/metadata/hook.metadata.js.map +1 -1
- package/src/common/metadata/prompt.metadata.d.ts +28 -28
- package/src/common/metadata/prompt.metadata.js.map +1 -1
- package/src/common/metadata/resource.metadata.d.ts +54 -54
- package/src/common/metadata/tool.metadata.d.ts +190 -7
- package/src/common/metadata/tool.metadata.js +41 -6
- package/src/common/metadata/tool.metadata.js.map +1 -1
- package/src/common/records/scope.record.d.ts +2 -2
- package/src/common/records/scope.record.js.map +1 -1
- package/src/common/schemas/http-output.schema.d.ts +106 -106
- package/src/common/tokens/tool.tokens.js.map +1 -1
- package/src/common/types/options/logging.options.d.ts +1 -2
- package/src/common/types/options/logging.options.js +1 -9
- package/src/common/types/options/logging.options.js.map +1 -1
- package/src/common/types/options/server-info.options.d.ts +19 -19
- package/src/errors/error-handler.d.ts +65 -0
- package/src/errors/error-handler.js +107 -0
- package/src/errors/error-handler.js.map +1 -0
- package/src/errors/index.d.ts +2 -0
- package/src/errors/index.js +26 -0
- package/src/errors/index.js.map +1 -0
- package/src/errors/mcp.error.d.ts +156 -0
- package/src/errors/mcp.error.js +243 -0
- package/src/errors/mcp.error.js.map +1 -0
- package/src/flows/flow.instance.js +7 -6
- package/src/flows/flow.instance.js.map +1 -1
- package/src/flows/flow.registry.js +1 -1
- package/src/flows/flow.registry.js.map +1 -1
- package/src/front-mcp/front-mcp.providers.d.ts +20 -20
- package/src/hooks/hook.registry.d.ts +5 -3
- package/src/hooks/hook.registry.js +13 -1
- package/src/hooks/hook.registry.js.map +1 -1
- package/src/plugin/plugin.registry.d.ts +7 -2
- package/src/plugin/plugin.registry.js +23 -11
- package/src/plugin/plugin.registry.js.map +1 -1
- package/src/prompt/prompt.registry.js +1 -0
- package/src/prompt/prompt.registry.js.map +1 -1
- package/src/resource/resource.registry.js +1 -0
- package/src/resource/resource.registry.js.map +1 -1
- package/src/scope/scope.instance.js +8 -2
- package/src/scope/scope.instance.js.map +1 -1
- package/src/scope/scope.registry.js +3 -2
- package/src/scope/scope.registry.js.map +1 -1
- package/src/scope/scope.utils.js +6 -4
- package/src/scope/scope.utils.js.map +1 -1
- package/src/store/adapters/store.memory.adapter.js +3 -1
- package/src/store/adapters/store.memory.adapter.js.map +1 -1
- package/src/tool/flows/call-tool.flow.d.ts +1012 -676
- package/src/tool/flows/call-tool.flow.js +94 -61
- package/src/tool/flows/call-tool.flow.js.map +1 -1
- package/src/tool/flows/tools-list.flow.d.ts +347 -590
- package/src/tool/flows/tools-list.flow.js +76 -49
- package/src/tool/flows/tools-list.flow.js.map +1 -1
- package/src/tool/tool.instance.d.ts +27 -8
- package/src/tool/tool.instance.js +40 -5
- package/src/tool/tool.instance.js.map +1 -1
- package/src/tool/tool.registry.js +19 -21
- package/src/tool/tool.registry.js.map +1 -1
- package/src/tool/tool.utils.d.ts +3 -2
- package/src/tool/tool.utils.js +377 -14
- package/src/tool/tool.utils.js.map +1 -1
- package/src/transport/adapters/transport.sse.adapter.js +2 -1
- package/src/transport/adapters/transport.sse.adapter.js.map +1 -1
- package/src/transport/adapters/transport.streamable-http.adapter.js.map +1 -1
- package/src/transport/flows/handle.sse.flow.js +6 -13
- package/src/transport/flows/handle.sse.flow.js.map +1 -1
- package/src/transport/flows/handle.streamable-http.flow.js +1 -0
- package/src/transport/flows/handle.streamable-http.flow.js.map +1 -1
- package/src/transport/mcp-handlers/call-tool-request.handler.d.ts +1 -1
- package/src/transport/mcp-handlers/call-tool-request.handler.js +10 -5
- package/src/transport/mcp-handlers/call-tool-request.handler.js.map +1 -1
- package/src/transport/mcp-handlers/index.d.ts +151 -268
- package/src/transport/mcp-handlers/list-tools-request.handler.d.ts +124 -216
- package/src/transport/transport.local.js +1 -0
- package/src/transport/transport.local.js.map +1 -1
- package/src/utils/string.utils.js +1 -1
- package/src/utils/string.utils.js.map +1 -1
|
@@ -7,6 +7,7 @@ require("reflect-metadata");
|
|
|
7
7
|
const zod_1 = require("zod");
|
|
8
8
|
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
9
9
|
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
10
|
+
const errors_1 = require("../../errors");
|
|
10
11
|
const inputSchema = zod_1.z.object({
|
|
11
12
|
request: types_js_1.ListToolsRequestSchema,
|
|
12
13
|
ctx: zod_1.z.any(),
|
|
@@ -40,10 +41,19 @@ let ToolsListFlow = class ToolsListFlow extends common_1.FlowBase {
|
|
|
40
41
|
}
|
|
41
42
|
async parseInput() {
|
|
42
43
|
this.logger.verbose('parseInput:start');
|
|
43
|
-
|
|
44
|
+
let method;
|
|
45
|
+
let params;
|
|
46
|
+
try {
|
|
47
|
+
const inputData = inputSchema.parse(this.rawInput);
|
|
48
|
+
method = inputData.request.method;
|
|
49
|
+
params = inputData.request.params;
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
throw new errors_1.InvalidInputError('Invalid request format', e instanceof zod_1.z.ZodError ? e.errors : undefined);
|
|
53
|
+
}
|
|
44
54
|
if (method !== 'tools/list') {
|
|
45
55
|
this.logger.warn(`parseInput: invalid method "${method}"`);
|
|
46
|
-
throw new
|
|
56
|
+
throw new errors_1.InvalidMethodError(method, 'tools/list');
|
|
47
57
|
}
|
|
48
58
|
const cursor = params?.cursor;
|
|
49
59
|
if (cursor)
|
|
@@ -53,63 +63,80 @@ let ToolsListFlow = class ToolsListFlow extends common_1.FlowBase {
|
|
|
53
63
|
}
|
|
54
64
|
async findTools() {
|
|
55
65
|
this.logger.info('findTools:start');
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
try {
|
|
67
|
+
const apps = this.scope.apps.getApps();
|
|
68
|
+
this.logger.info(`findTools: discovered ${apps.length} app(s)`);
|
|
69
|
+
const tools = [];
|
|
70
|
+
const scopeTools = this.scope.tools.getTools();
|
|
71
|
+
this.logger.verbose(`findTools: scope tools=${scopeTools.length}`);
|
|
72
|
+
for (const tool of scopeTools) {
|
|
73
|
+
tools.push({ appName: tool.owner.id, tool });
|
|
74
|
+
}
|
|
75
|
+
this.logger.info(`findTools: total tools collected=${tools.length}`);
|
|
76
|
+
if (tools.length === 0) {
|
|
77
|
+
this.logger.warn('findTools: no tools found across apps');
|
|
78
|
+
}
|
|
79
|
+
this.state.set('tools', tools);
|
|
80
|
+
this.logger.verbose('findTools:done');
|
|
63
81
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
82
|
+
catch (error) {
|
|
83
|
+
this.logger.error('findTools: failed to collect tools', error);
|
|
84
|
+
throw error;
|
|
67
85
|
}
|
|
68
|
-
this.state.set('tools', tools);
|
|
69
|
-
this.logger.verbose('findTools:done');
|
|
70
86
|
}
|
|
71
87
|
async resolveConflicts() {
|
|
72
88
|
this.logger.verbose('resolveConflicts:start');
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
89
|
+
try {
|
|
90
|
+
const found = this.state.required.tools;
|
|
91
|
+
const counts = new Map();
|
|
92
|
+
for (const { tool } of found) {
|
|
93
|
+
const baseName = tool.metadata.id ?? tool.metadata.name;
|
|
94
|
+
counts.set(baseName, (counts.get(baseName) ?? 0) + 1);
|
|
95
|
+
}
|
|
96
|
+
const conflicts = new Set([...counts.entries()].filter(([, n]) => n > 1).map(([k]) => k));
|
|
97
|
+
if (conflicts.size > 0) {
|
|
98
|
+
const preview = this.sample(Array.from(conflicts)).join(', ');
|
|
99
|
+
const extra = conflicts.size > 5 ? `, +${conflicts.size - 5} more` : '';
|
|
100
|
+
this.logger.warn(`resolveConflicts: ${conflicts.size} name conflict(s) detected: ${preview}${extra}`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
this.logger.info('resolveConflicts: no name conflicts detected');
|
|
104
|
+
}
|
|
105
|
+
const resolved = found.map(({ appName, tool }) => {
|
|
106
|
+
const baseName = tool.metadata.id ?? tool.metadata.name;
|
|
107
|
+
const finalName = conflicts.has(baseName) ? `${appName}:${baseName}` : baseName;
|
|
108
|
+
return { appName, tool, finalName };
|
|
109
|
+
});
|
|
110
|
+
this.state.set('resolvedTools', resolved);
|
|
111
|
+
this.logger.verbose('resolveConflicts:done');
|
|
84
112
|
}
|
|
85
|
-
|
|
86
|
-
this.logger.
|
|
113
|
+
catch (error) {
|
|
114
|
+
this.logger.error('resolveConflicts: failed to resolve conflicts', error);
|
|
115
|
+
throw error;
|
|
87
116
|
}
|
|
88
|
-
const resolved = found.map(({ appName, tool }) => {
|
|
89
|
-
const baseName = tool.metadata.id ?? tool.metadata.name;
|
|
90
|
-
const finalName = conflicts.has(baseName) ? `${appName}:${baseName}` : baseName;
|
|
91
|
-
return { appName, tool, finalName };
|
|
92
|
-
});
|
|
93
|
-
this.state.set('resolvedTools', resolved);
|
|
94
|
-
this.logger.verbose('resolveConflicts:done');
|
|
95
117
|
}
|
|
96
118
|
async parseTools() {
|
|
97
119
|
this.logger.verbose('parseTools:start');
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
(0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object(tool.metadata.inputSchema)),
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
120
|
+
try {
|
|
121
|
+
const resolved = this.state.required.resolvedTools;
|
|
122
|
+
const tools = resolved.map(({ finalName, tool }) => ({
|
|
123
|
+
name: finalName,
|
|
124
|
+
title: tool.metadata.name,
|
|
125
|
+
description: tool.metadata.description,
|
|
126
|
+
annotations: tool.metadata.annotations,
|
|
127
|
+
inputSchema: tool.metadata.rawInputSchema ?? (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object(tool.metadata.inputSchema)),
|
|
128
|
+
}));
|
|
129
|
+
const preview = this.sample(tools.map((t) => t.name)).join(', ');
|
|
130
|
+
const extra = tools.length > 5 ? `, +${tools.length - 5} more` : '';
|
|
131
|
+
this.logger.info(`parseTools: prepared ${tools.length} tool descriptor(s): ${preview}${extra}`);
|
|
132
|
+
this.respond({ tools });
|
|
133
|
+
this.logger.info('parseTools: response sent');
|
|
134
|
+
this.logger.verbose('parseTools:done');
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
this.logger.error('parseTools: failed to parse tools', error);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
113
140
|
}
|
|
114
141
|
};
|
|
115
142
|
tslib_1.__decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools-list.flow.js","sourceRoot":"","sources":["../../../../src/tool/flows/tools-list.flow.ts"],"names":[],"mappings":"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","sourcesContent":["// tools/flows/list-tools.flow.ts\nimport {Flow, FlowBase, FlowHooksOf, FlowPlan, FlowRunOptions, ToolEntry} from '../../common';\nimport 'reflect-metadata';\nimport {z} from 'zod';\nimport {ListToolsRequestSchema, ListToolsResultSchema} from '@modelcontextprotocol/sdk/types.js';\nimport {zodToJsonSchema} from 'zod-to-json-schema';\n\nconst inputSchema = z.object({\n request: ListToolsRequestSchema,\n ctx: z.any(),\n});\n\nconst outputSchema = ListToolsResultSchema;\n\nconst stateSchema = z.object({\n cursor: z.string().optional(),\n tools: z.array(\n z.object({\n appName: z.string(),\n tool: z.instanceof(ToolEntry),\n })\n ),\n resolvedTools: z.array(\n z.object({\n appName: z.string(),\n tool: z.instanceof(ToolEntry),\n finalName: z.string(),\n })\n ),\n});\n\ntype ResponseToolItem = z.infer<typeof outputSchema>['tools'][number];\n\n// TODO: add support for pagination\n// TODO: add support for session based tools\nconst plan = {\n pre: ['parseInput'],\n execute: ['findTools', 'resolveConflicts'],\n post: ['parseTools'],\n} as const satisfies FlowPlan<string>;\n\ndeclare global {\n interface ExtendFlows {\n 'tools:list-tools': FlowRunOptions<\n ToolsListFlow,\n typeof plan,\n typeof inputSchema,\n typeof outputSchema,\n typeof stateSchema\n >;\n }\n}\n\nconst name = 'tools:list-tools' as const;\nconst {Stage} = FlowHooksOf('tools:list-tools');\n\n@Flow({\n name,\n plan,\n inputSchema,\n outputSchema,\n access: 'authorized',\n})\nexport default class ToolsListFlow extends FlowBase<typeof name> {\n logger = this.scopeLogger.child('ToolsListFlow');\n\n private sample<T>(arr: T[], n = 5): T[] {\n return arr.slice(0, n);\n }\n\n @Stage('parseInput')\n async parseInput() {\n this.logger.verbose('parseInput:start');\n const {\n request: {method, params},\n } = inputSchema.parse(this.rawInput);\n\n if (method !== 'tools/list') {\n this.logger.warn(`parseInput: invalid method \"${method}\"`);\n throw new Error('Invalid method');\n }\n\n const cursor = params?.cursor;\n if (cursor) this.logger.verbose(`parseInput: cursor=${cursor}`);\n this.state.set('cursor', cursor);\n this.logger.verbose('parseInput:done');\n }\n\n @Stage('findTools')\n async findTools() {\n this.logger.info('findTools:start');\n const apps = this.scope.apps.getApps();\n this.logger.info(`findTools: discovered ${apps.length} app(s)`);\n\n const tools: Array<{ appName: string; tool: ToolEntry }> = [];\n\n const scopeTools = this.scope.tools.getTools();\n this.logger.verbose(`findTools: scope tools=${scopeTools.length}`);\n\n for (const tool of scopeTools) {\n tools.push({appName: tool.owner.id, tool});\n }\n this.logger.info(`findTools: total tools collected=${tools.length}`);\n if (tools.length === 0) {\n this.logger.warn('findTools: no tools found across apps');\n }\n\n this.state.set('tools', tools);\n this.logger.verbose('findTools:done');\n }\n\n @Stage('resolveConflicts')\n async resolveConflicts() {\n this.logger.verbose('resolveConflicts:start');\n const found = this.state.required.tools;\n\n const counts = new Map<string, number>();\n for (const {tool} of found) {\n const baseName = tool.metadata.id ?? tool.metadata.name;\n counts.set(baseName, (counts.get(baseName) ?? 0) + 1);\n }\n\n const conflicts = new Set<string>(\n [...counts.entries()].filter(([, n]) => n > 1).map(([k]) => k)\n );\n\n if (conflicts.size > 0) {\n const preview = this.sample(Array.from(conflicts)).join(', ');\n const extra = conflicts.size > 5 ? `, +${conflicts.size - 5} more` : '';\n this.logger.warn(`resolveConflicts: ${conflicts.size} name conflict(s) detected: ${preview}${extra}`);\n } else {\n this.logger.info('resolveConflicts: no name conflicts detected');\n }\n\n const resolved = found.map(({appName, tool}) => {\n const baseName = tool.metadata.id ?? tool.metadata.name;\n const finalName = conflicts.has(baseName) ? `${appName}:${baseName}` : baseName;\n return {appName, tool, finalName};\n });\n\n this.state.set('resolvedTools', resolved);\n this.logger.verbose('resolveConflicts:done');\n }\n\n @Stage('parseTools')\n async parseTools() {\n this.logger.verbose('parseTools:start');\n const resolved = this.state.required.resolvedTools;\n\n const tools: ResponseToolItem[] = resolved.map(({finalName, tool}) => ({\n name: finalName,\n title: tool.metadata.name,\n description: tool.metadata.description,\n annotations: tool.metadata.annotations,\n inputSchema:\n (tool.metadata as any).rawInputSchema ??\n (zodToJsonSchema(z.object(tool.metadata.inputSchema) as any) as any),\n }));\n\n const preview = this.sample(tools.map(t => t.name)).join(', ');\n const extra = tools.length > 5 ? `, +${tools.length - 5} more` : '';\n this.logger.info(`parseTools: prepared ${tools.length} tool descriptor(s): ${preview}${extra}`);\n\n this.respond({tools});\n this.logger.info('parseTools: response sent');\n this.logger.verbose('parseTools:done');\n\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tools-list.flow.js","sourceRoot":"","sources":["../../../../src/tool/flows/tools-list.flow.ts"],"names":[],"mappings":";;;AAAA,iCAAiC;AACjC,yCAAgG;AAChG,4BAA0B;AAC1B,6BAAwB;AACxB,iEAAmG;AACnG,2DAAqD;AACrD,yCAAqE;AAErE,MAAM,WAAW,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3B,OAAO,EAAE,iCAAsB;IAC/B,GAAG,EAAE,OAAC,CAAC,GAAG,EAAE;CACb,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,gCAAqB,CAAC;AAE3C,MAAM,WAAW,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3B,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,KAAK,EAAE,OAAC,CAAC,KAAK,CACZ,OAAC,CAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;QACnB,IAAI,EAAE,OAAC,CAAC,UAAU,CAAC,kBAAS,CAAC;KAC9B,CAAC,CACH;IACD,aAAa,EAAE,OAAC,CAAC,KAAK,CACpB,OAAC,CAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;QACnB,IAAI,EAAE,OAAC,CAAC,UAAU,CAAC,kBAAS,CAAC;QAC7B,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE;KACtB,CAAC,CACH;CACF,CAAC,CAAC;AAIH,mCAAmC;AACnC,4CAA4C;AAC5C,MAAM,IAAI,GAAG;IACX,GAAG,EAAE,CAAC,YAAY,CAAC;IACnB,OAAO,EAAE,CAAC,WAAW,EAAE,kBAAkB,CAAC;IAC1C,IAAI,EAAE,CAAC,YAAY,CAAC;CACe,CAAC;AActC,MAAM,IAAI,GAAG,kBAA2B,CAAC;AACzC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAA,oBAAW,EAAC,kBAAkB,CAAC,CAAC;AASnC,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,iBAAqB;IAC9D,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAEzC,MAAM,CAAI,GAAQ,EAAE,CAAC,GAAG,CAAC;QAC/B,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACzB,CAAC;IAGK,AAAN,KAAK,CAAC,UAAU;QACd,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAExC,IAAI,MAAe,CAAC;QACpB,IAAI,MAAW,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;YAClC,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;QACpC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,0BAAiB,CAAC,wBAAwB,EAAE,CAAC,YAAY,OAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACxG,CAAC;QAED,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;YAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,+BAA+B,MAAM,GAAG,CAAC,CAAC;YAC3D,MAAM,IAAI,2BAAkB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC;QAC9B,IAAI,MAAM;YAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzC,CAAC;IAGK,AAAN,KAAK,CAAC,SAAS;QACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAEpC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACvC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,IAAI,CAAC,MAAM,SAAS,CAAC,CAAC;YAEhE,MAAM,KAAK,GAAgD,EAAE,CAAC;YAE9D,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC/C,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,0BAA0B,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;YAEnE,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;gBAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/C,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oCAAoC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YACrE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;YAC5D,CAAC;YAED,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;YAC/D,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAGK,AAAN,KAAK,CAAC,gBAAgB;QACpB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;QAE9C,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;YAExC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;YACzC,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC;gBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACxD,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACxD,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAElG,IAAI,SAAS,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9D,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,SAAS,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,SAAS,CAAC,IAAI,+BAA+B,OAAO,GAAG,KAAK,EAAE,CAAC,CAAC;YACxG,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;YACnE,CAAC;YAED,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;gBAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACxD,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;gBAChF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;YACtC,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+CAA+C,EAAE,KAAK,CAAC,CAAC;YAC1E,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAGK,AAAN,KAAK,CAAC,UAAU;QACd,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAExC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC;YAEnD,MAAM,KAAK,GAAuB,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;gBACvE,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;gBACzB,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW;gBACtC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW;gBACtC,WAAW,EACR,IAAI,CAAC,QAAgB,CAAC,cAAc,IAAK,IAAA,oCAAe,EAAC,OAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAQ,CAAS;aAChH,CAAC,CAAC,CAAC;YAEJ,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjE,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wBAAwB,KAAK,CAAC,MAAM,wBAAwB,OAAO,GAAG,KAAK,EAAE,CAAC,CAAC;YAEhG,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;YAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;YAC9D,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF,CAAA;AAvHO;IADL,KAAK,CAAC,YAAY,CAAC;;;;+CAuBnB;AAGK;IADL,KAAK,CAAC,WAAW,CAAC;;;;8CA4BlB;AAGK;IADL,KAAK,CAAC,kBAAkB,CAAC;;;;qDAmCzB;AAGK;IADL,KAAK,CAAC,YAAY,CAAC;;;;+CA2BnB;AA9HkB,aAAa;IAPjC,IAAA,aAAI,EAAC;QACJ,IAAI;QACJ,IAAI;QACJ,WAAW;QACX,YAAY;QACZ,MAAM,EAAE,YAAY;KACrB,CAAC;GACmB,aAAa,CA+HjC;kBA/HoB,aAAa","sourcesContent":["// tools/flows/list-tools.flow.ts\nimport { Flow, FlowBase, FlowHooksOf, FlowPlan, FlowRunOptions, ToolEntry } from '../../common';\nimport 'reflect-metadata';\nimport { z } from 'zod';\nimport { ListToolsRequestSchema, ListToolsResultSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport { InvalidMethodError, InvalidInputError } from '../../errors';\n\nconst inputSchema = z.object({\n request: ListToolsRequestSchema,\n ctx: z.any(),\n});\n\nconst outputSchema = ListToolsResultSchema;\n\nconst stateSchema = z.object({\n cursor: z.string().optional(),\n tools: z.array(\n z.object({\n appName: z.string(),\n tool: z.instanceof(ToolEntry),\n }),\n ),\n resolvedTools: z.array(\n z.object({\n appName: z.string(),\n tool: z.instanceof(ToolEntry),\n finalName: z.string(),\n }),\n ),\n});\n\ntype ResponseToolItem = z.infer<typeof outputSchema>['tools'][number];\n\n// TODO: add support for pagination\n// TODO: add support for session based tools\nconst plan = {\n pre: ['parseInput'],\n execute: ['findTools', 'resolveConflicts'],\n post: ['parseTools'],\n} as const satisfies FlowPlan<string>;\n\ndeclare global {\n interface ExtendFlows {\n 'tools:list-tools': FlowRunOptions<\n ToolsListFlow,\n typeof plan,\n typeof inputSchema,\n typeof outputSchema,\n typeof stateSchema\n >;\n }\n}\n\nconst name = 'tools:list-tools' as const;\nconst { Stage } = FlowHooksOf('tools:list-tools');\n\n@Flow({\n name,\n plan,\n inputSchema,\n outputSchema,\n access: 'authorized',\n})\nexport default class ToolsListFlow extends FlowBase<typeof name> {\n logger = this.scopeLogger.child('ToolsListFlow');\n\n private sample<T>(arr: T[], n = 5): T[] {\n return arr.slice(0, n);\n }\n\n @Stage('parseInput')\n async parseInput() {\n this.logger.verbose('parseInput:start');\n\n let method!: string;\n let params: any;\n try {\n const inputData = inputSchema.parse(this.rawInput);\n method = inputData.request.method;\n params = inputData.request.params;\n } catch (e) {\n throw new InvalidInputError('Invalid request format', e instanceof z.ZodError ? e.errors : undefined);\n }\n\n if (method !== 'tools/list') {\n this.logger.warn(`parseInput: invalid method \"${method}\"`);\n throw new InvalidMethodError(method, 'tools/list');\n }\n\n const cursor = params?.cursor;\n if (cursor) this.logger.verbose(`parseInput: cursor=${cursor}`);\n this.state.set('cursor', cursor);\n this.logger.verbose('parseInput:done');\n }\n\n @Stage('findTools')\n async findTools() {\n this.logger.info('findTools:start');\n\n try {\n const apps = this.scope.apps.getApps();\n this.logger.info(`findTools: discovered ${apps.length} app(s)`);\n\n const tools: Array<{ appName: string; tool: ToolEntry }> = [];\n\n const scopeTools = this.scope.tools.getTools();\n this.logger.verbose(`findTools: scope tools=${scopeTools.length}`);\n\n for (const tool of scopeTools) {\n tools.push({ appName: tool.owner.id, tool });\n }\n\n this.logger.info(`findTools: total tools collected=${tools.length}`);\n if (tools.length === 0) {\n this.logger.warn('findTools: no tools found across apps');\n }\n\n this.state.set('tools', tools);\n this.logger.verbose('findTools:done');\n } catch (error) {\n this.logger.error('findTools: failed to collect tools', error);\n throw error;\n }\n }\n\n @Stage('resolveConflicts')\n async resolveConflicts() {\n this.logger.verbose('resolveConflicts:start');\n\n try {\n const found = this.state.required.tools;\n\n const counts = new Map<string, number>();\n for (const { tool } of found) {\n const baseName = tool.metadata.id ?? tool.metadata.name;\n counts.set(baseName, (counts.get(baseName) ?? 0) + 1);\n }\n\n const conflicts = new Set<string>([...counts.entries()].filter(([, n]) => n > 1).map(([k]) => k));\n\n if (conflicts.size > 0) {\n const preview = this.sample(Array.from(conflicts)).join(', ');\n const extra = conflicts.size > 5 ? `, +${conflicts.size - 5} more` : '';\n this.logger.warn(`resolveConflicts: ${conflicts.size} name conflict(s) detected: ${preview}${extra}`);\n } else {\n this.logger.info('resolveConflicts: no name conflicts detected');\n }\n\n const resolved = found.map(({ appName, tool }) => {\n const baseName = tool.metadata.id ?? tool.metadata.name;\n const finalName = conflicts.has(baseName) ? `${appName}:${baseName}` : baseName;\n return { appName, tool, finalName };\n });\n\n this.state.set('resolvedTools', resolved);\n this.logger.verbose('resolveConflicts:done');\n } catch (error) {\n this.logger.error('resolveConflicts: failed to resolve conflicts', error);\n throw error;\n }\n }\n\n @Stage('parseTools')\n async parseTools() {\n this.logger.verbose('parseTools:start');\n\n try {\n const resolved = this.state.required.resolvedTools;\n\n const tools: ResponseToolItem[] = resolved.map(({ finalName, tool }) => ({\n name: finalName,\n title: tool.metadata.name,\n description: tool.metadata.description,\n annotations: tool.metadata.annotations,\n inputSchema:\n (tool.metadata as any).rawInputSchema ?? (zodToJsonSchema(z.object(tool.metadata.inputSchema) as any) as any),\n }));\n\n const preview = this.sample(tools.map((t) => t.name)).join(', ');\n const extra = tools.length > 5 ? `, +${tools.length - 5} more` : '';\n this.logger.info(`parseTools: prepared ${tools.length} tool descriptor(s): ${preview}${extra}`);\n\n this.respond({ tools });\n this.logger.info('parseTools: response sent');\n this.logger.verbose('parseTools:done');\n } catch (error) {\n this.logger.error('parseTools: failed to parse tools', error);\n throw error;\n }\n }\n}\n"]}
|
|
@@ -1,15 +1,34 @@
|
|
|
1
|
-
import { EntryOwnerRef, ToolCallArgs, ToolCallExtra, ToolContext, ToolEntry, ToolRecord } from '../common';
|
|
1
|
+
import { EntryOwnerRef, ToolCallArgs, ToolCallExtra, ToolContext, ToolEntry, ToolInputType, ToolOutputType, ToolRecord, ParsedToolResult, ToolInputOf, ToolOutputOf, SafeTransformResult } from '../common';
|
|
2
2
|
import ProviderRegistry from '../provider/provider.registry';
|
|
3
|
-
import { z } from
|
|
4
|
-
import HookRegistry from
|
|
5
|
-
import { Scope } from
|
|
6
|
-
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import HookRegistry from '../hooks/hook.registry';
|
|
5
|
+
import { Scope } from '../scope';
|
|
6
|
+
import type { CallToolRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
export declare class ToolInstance<InSchema extends ToolInputType = ToolInputType, OutSchema extends ToolOutputType = ToolOutputType, In = ToolInputOf<{
|
|
8
|
+
inputSchema: InSchema;
|
|
9
|
+
}>, Out = ToolOutputOf<{
|
|
10
|
+
outputSchema: OutSchema;
|
|
11
|
+
}>> extends ToolEntry<InSchema, OutSchema, In, Out> {
|
|
7
12
|
private readonly providers;
|
|
8
|
-
readonly name: string;
|
|
9
13
|
readonly scope: Scope;
|
|
10
14
|
readonly hooks: HookRegistry;
|
|
11
15
|
constructor(record: ToolRecord, providers: ProviderRegistry, owner: EntryOwnerRef);
|
|
12
16
|
protected initialize(): Promise<void>;
|
|
13
|
-
getMetadata(): import("../common").ToolMetadata<z.ZodRawShape,
|
|
14
|
-
|
|
17
|
+
getMetadata(): import("../common").ToolMetadata<z.ZodRawShape, ToolOutputType>;
|
|
18
|
+
getOutputSchema(): OutSchema | undefined;
|
|
19
|
+
create(input: ToolCallArgs, ctx: ToolCallExtra): ToolContext<InSchema, OutSchema, In, Out>;
|
|
20
|
+
parseInput(input: CallToolRequest['params']): CallToolRequest['params']['arguments'];
|
|
21
|
+
/**
|
|
22
|
+
* Turn the raw tool function result into an MCP-compliant CallToolResult:
|
|
23
|
+
* - `content`: list of ContentBlocks (text / image / audio / resource / resource_link)
|
|
24
|
+
* - `structuredContent`: sanitized JSON when outputSchema is "json-like"
|
|
25
|
+
*
|
|
26
|
+
* Rules:
|
|
27
|
+
* - If outputSchema is a JS array → multiple content items, each with its own type.
|
|
28
|
+
* - Primitive → stringifies into a TextContent block.
|
|
29
|
+
* - image/audio/resource/resource_link → passed through as-is.
|
|
30
|
+
* - JSON / structured → JSON.stringify for text, and full sanitized JSON in structuredContent.
|
|
31
|
+
*/
|
|
32
|
+
parseOutput(raw: Out | Partial<Out> | any): ParsedToolResult;
|
|
33
|
+
safeParseOutput(raw: Out | Partial<Out> | any): SafeTransformResult<ParsedToolResult>;
|
|
15
34
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// file: libs/sdk/src/tool/tool.instance.ts
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
exports.ToolInstance = void 0;
|
|
4
5
|
const common_1 = require("../common");
|
|
5
6
|
const zod_1 = require("zod");
|
|
6
7
|
const hooks_utils_1 = require("../hooks/hooks.utils");
|
|
8
|
+
const tool_utils_1 = require("./tool.utils");
|
|
7
9
|
class ToolInstance extends common_1.ToolEntry {
|
|
8
10
|
providers;
|
|
9
|
-
name;
|
|
10
11
|
scope;
|
|
11
12
|
hooks;
|
|
12
13
|
constructor(record, providers, owner) {
|
|
@@ -14,17 +15,20 @@ class ToolInstance extends common_1.ToolEntry {
|
|
|
14
15
|
this.owner = owner;
|
|
15
16
|
this.providers = providers;
|
|
16
17
|
this.name = record.metadata.id || record.metadata.name;
|
|
18
|
+
this.fullName = this.owner.id + ':' + this.name;
|
|
17
19
|
this.scope = this.providers.getActiveScope();
|
|
18
20
|
this.hooks = this.scope.providers.getHooksRegistry();
|
|
19
21
|
const schema = record.metadata.inputSchema;
|
|
20
|
-
|
|
22
|
+
// Support both Zod objects and raw ZodRawShape
|
|
23
|
+
this.inputSchema = schema instanceof zod_1.z.ZodObject ? schema.shape : schema ?? {};
|
|
24
|
+
// Whatever JSON schema representation you’re storing for inputs
|
|
21
25
|
this.rawInputSchema = record.metadata.rawInputSchema;
|
|
22
|
-
|
|
26
|
+
// IMPORTANT: keep the *raw* outputSchema (string literal, zod, raw shape, or array)
|
|
27
|
+
this.outputSchema = record.metadata.outputSchema;
|
|
23
28
|
this.ready = this.initialize();
|
|
24
29
|
}
|
|
25
30
|
async initialize() {
|
|
26
|
-
const hooks = (0, hooks_utils_1.normalizeHooksFromCls)(this.record.provide)
|
|
27
|
-
.filter(hook => hook.metadata.flow === 'tools:call-tool' || hook.metadata.flow === 'tools:list-tools');
|
|
31
|
+
const hooks = (0, hooks_utils_1.normalizeHooksFromCls)(this.record.provide).filter((hook) => hook.metadata.flow === 'tools:call-tool' || hook.metadata.flow === 'tools:list-tools');
|
|
28
32
|
if (hooks.length > 0) {
|
|
29
33
|
await this.hooks.registerHooks(true, ...hooks);
|
|
30
34
|
}
|
|
@@ -33,6 +37,9 @@ class ToolInstance extends common_1.ToolEntry {
|
|
|
33
37
|
getMetadata() {
|
|
34
38
|
return this.record.metadata;
|
|
35
39
|
}
|
|
40
|
+
getOutputSchema() {
|
|
41
|
+
return this.outputSchema;
|
|
42
|
+
}
|
|
36
43
|
create(input, ctx) {
|
|
37
44
|
const metadata = this.metadata;
|
|
38
45
|
const providers = this.providers;
|
|
@@ -53,6 +60,34 @@ class ToolInstance extends common_1.ToolEntry {
|
|
|
53
60
|
return new FunctionToolContext(this.record, toolCtorArgs);
|
|
54
61
|
}
|
|
55
62
|
}
|
|
63
|
+
parseInput(input) {
|
|
64
|
+
const inputSchema = zod_1.z.object(this.inputSchema);
|
|
65
|
+
return inputSchema.parse(input.arguments);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Turn the raw tool function result into an MCP-compliant CallToolResult:
|
|
69
|
+
* - `content`: list of ContentBlocks (text / image / audio / resource / resource_link)
|
|
70
|
+
* - `structuredContent`: sanitized JSON when outputSchema is "json-like"
|
|
71
|
+
*
|
|
72
|
+
* Rules:
|
|
73
|
+
* - If outputSchema is a JS array → multiple content items, each with its own type.
|
|
74
|
+
* - Primitive → stringifies into a TextContent block.
|
|
75
|
+
* - image/audio/resource/resource_link → passed through as-is.
|
|
76
|
+
* - JSON / structured → JSON.stringify for text, and full sanitized JSON in structuredContent.
|
|
77
|
+
*/
|
|
78
|
+
parseOutput(raw) {
|
|
79
|
+
const descriptor = this.outputSchema;
|
|
80
|
+
return (0, tool_utils_1.buildParsedToolResult)(descriptor, raw);
|
|
81
|
+
}
|
|
82
|
+
safeParseOutput(raw) {
|
|
83
|
+
const descriptor = this.outputSchema;
|
|
84
|
+
try {
|
|
85
|
+
return { success: true, data: (0, tool_utils_1.buildParsedToolResult)(descriptor, raw) };
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
return { success: false, error };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
56
91
|
}
|
|
57
92
|
exports.ToolInstance = ToolInstance;
|
|
58
93
|
class FunctionToolContext extends common_1.ToolContext {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.instance.js","sourceRoot":"","sources":["../../../src/tool/tool.instance.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tool.instance.js","sourceRoot":"","sources":["../../../src/tool/tool.instance.ts"],"names":[],"mappings":"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","sourcesContent":["// file: libs/sdk/src/tool/tool.instance.ts\n\nimport {\n EntryOwnerRef,\n ToolCallArgs,\n ToolCallExtra,\n ToolContext,\n ToolCtorArgs,\n ToolEntry,\n ToolFunctionTokenRecord,\n ToolInputType,\n ToolKind,\n ToolOutputType,\n ToolRecord,\n ParsedToolResult,\n ToolInputOf,\n ToolOutputOf,\n SafeTransformResult,\n} from '../common';\nimport ProviderRegistry from '../provider/provider.registry';\nimport { z } from 'zod';\nimport HookRegistry from '../hooks/hook.registry';\nimport { Scope } from '../scope';\nimport { normalizeHooksFromCls } from '../hooks/hooks.utils';\nimport type { CallToolRequest } from '@modelcontextprotocol/sdk/types.js';\nimport { buildParsedToolResult } from './tool.utils';\n\nexport class ToolInstance<\n InSchema extends ToolInputType = ToolInputType,\n OutSchema extends ToolOutputType = ToolOutputType,\n In = ToolInputOf<{ inputSchema: InSchema }>,\n Out = ToolOutputOf<{ outputSchema: OutSchema }>,\n> extends ToolEntry<InSchema, OutSchema, In, Out> {\n private readonly providers: ProviderRegistry;\n readonly scope: Scope;\n readonly hooks: HookRegistry;\n\n constructor(record: ToolRecord, providers: ProviderRegistry, owner: EntryOwnerRef) {\n super(record);\n this.owner = owner;\n this.providers = providers;\n this.name = record.metadata.id || record.metadata.name;\n this.fullName = this.owner.id + ':' + this.name;\n this.scope = this.providers.getActiveScope();\n this.hooks = this.scope.providers.getHooksRegistry();\n\n const schema: any = record.metadata.inputSchema;\n // Support both Zod objects and raw ZodRawShape\n this.inputSchema = schema instanceof z.ZodObject ? schema.shape : schema ?? {};\n\n // Whatever JSON schema representation you’re storing for inputs\n this.rawInputSchema = record.metadata.rawInputSchema;\n\n // IMPORTANT: keep the *raw* outputSchema (string literal, zod, raw shape, or array)\n this.outputSchema = record.metadata.outputSchema as OutSchema;\n\n this.ready = this.initialize();\n }\n\n protected async initialize() {\n const hooks = normalizeHooksFromCls(this.record.provide).filter(\n (hook) => hook.metadata.flow === 'tools:call-tool' || hook.metadata.flow === 'tools:list-tools',\n );\n if (hooks.length > 0) {\n await this.hooks.registerHooks(true, ...hooks);\n }\n return Promise.resolve();\n }\n\n getMetadata() {\n return this.record.metadata;\n }\n\n override getOutputSchema() {\n return this.outputSchema;\n }\n\n override create(input: ToolCallArgs, ctx: ToolCallExtra): ToolContext<InSchema, OutSchema, In, Out> {\n const metadata = this.metadata;\n const providers = this.providers;\n const scope = this.providers.getActiveScope();\n const logger = scope.logger;\n const authInfo = ctx.authInfo;\n\n const toolCtorArgs: ToolCtorArgs<In> = {\n metadata,\n input: input as In,\n providers,\n logger,\n authInfo,\n };\n switch (this.record.kind) {\n case ToolKind.CLASS_TOKEN:\n return new this.record.provide(toolCtorArgs) as ToolContext<InSchema, OutSchema, In, Out>;\n case ToolKind.FUNCTION:\n return new FunctionToolContext<InSchema, OutSchema, In, Out>(this.record, toolCtorArgs);\n }\n }\n\n override parseInput(input: CallToolRequest['params']): CallToolRequest['params']['arguments'] {\n const inputSchema = z.object(this.inputSchema);\n return inputSchema.parse(input.arguments);\n }\n /**\n * Turn the raw tool function result into an MCP-compliant CallToolResult:\n * - `content`: list of ContentBlocks (text / image / audio / resource / resource_link)\n * - `structuredContent`: sanitized JSON when outputSchema is \"json-like\"\n *\n * Rules:\n * - If outputSchema is a JS array → multiple content items, each with its own type.\n * - Primitive → stringifies into a TextContent block.\n * - image/audio/resource/resource_link → passed through as-is.\n * - JSON / structured → JSON.stringify for text, and full sanitized JSON in structuredContent.\n */\n override parseOutput(raw: Out | Partial<Out> | any): ParsedToolResult {\n const descriptor = this.outputSchema as any;\n\n return buildParsedToolResult(descriptor, raw);\n }\n\n override safeParseOutput(raw: Out | Partial<Out> | any): SafeTransformResult<ParsedToolResult> {\n const descriptor = this.outputSchema as any;\n try {\n return { success: true, data: buildParsedToolResult(descriptor, raw) };\n } catch (error: any) {\n return { success: false, error };\n }\n }\n}\n\nclass FunctionToolContext<\n InSchema extends ToolInputType,\n OutSchema extends ToolOutputType,\n In = ToolInputOf<{ inputSchema: InSchema }>,\n Out = ToolOutputOf<{ outputSchema: OutSchema }>,\n> extends ToolContext<InSchema, OutSchema, In, Out> {\n constructor(private readonly record: ToolFunctionTokenRecord, args: ToolCtorArgs<In>) {\n super(args);\n }\n\n execute(input: In): Promise<Out> {\n return this.record.provide(input, this);\n }\n}\n"]}
|
|
@@ -74,17 +74,21 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
|
|
|
74
74
|
this.localRows.push(row);
|
|
75
75
|
}
|
|
76
76
|
const childAppRegistries = this.providers.getRegistries('AppRegistry');
|
|
77
|
-
childAppRegistries.forEach(appRegistry => {
|
|
77
|
+
childAppRegistries.forEach((appRegistry) => {
|
|
78
78
|
const apps = appRegistry.getApps();
|
|
79
79
|
for (const app of apps) {
|
|
80
80
|
const appToolsRegistries = app.providers.getRegistries('ToolRegistry');
|
|
81
|
-
appToolsRegistries
|
|
81
|
+
appToolsRegistries
|
|
82
|
+
.filter((t) => t.owner.kind === 'app')
|
|
83
|
+
.forEach((appToolRegistry) => {
|
|
82
84
|
this.adoptFromChild(appToolRegistry, appToolRegistry.owner);
|
|
83
85
|
});
|
|
84
86
|
}
|
|
85
87
|
});
|
|
86
88
|
const childToolRegistries = this.providers.getRegistries('ToolRegistry');
|
|
87
|
-
childToolRegistries
|
|
89
|
+
childToolRegistries
|
|
90
|
+
.filter((t) => t != this)
|
|
91
|
+
.forEach((toolRegistry) => {
|
|
88
92
|
this.adoptFromChild(toolRegistry, toolRegistry.owner);
|
|
89
93
|
});
|
|
90
94
|
// Build effective indexes from (locals + already adopted children)
|
|
@@ -107,12 +111,12 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
|
|
|
107
111
|
return;
|
|
108
112
|
const childRows = child.listAllIndexed(); // includes child's lineage
|
|
109
113
|
const prepend = this.owner ? [this.owner] : [];
|
|
110
|
-
const adoptedRows = childRows.map(r => this.relineage(r, prepend));
|
|
114
|
+
const adoptedRows = childRows.map((r) => this.relineage(r, prepend));
|
|
111
115
|
this.adopted.set(child, adoptedRows);
|
|
112
116
|
this.children.add(child);
|
|
113
117
|
// keep live if child changes
|
|
114
118
|
child.subscribe({ immediate: false }, () => {
|
|
115
|
-
const latest = child.listAllIndexed().map(r => this.relineage(r, prepend));
|
|
119
|
+
const latest = child.listAllIndexed().map((r) => this.relineage(r, prepend));
|
|
116
120
|
this.adopted.set(child, latest);
|
|
117
121
|
this.reindex();
|
|
118
122
|
this.bump('reset');
|
|
@@ -161,11 +165,11 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
|
|
|
161
165
|
}
|
|
162
166
|
/** List all instances (locals + adopted). */
|
|
163
167
|
listAllInstances() {
|
|
164
|
-
return this.listAllIndexed().map(r => r.instance);
|
|
168
|
+
return this.listAllIndexed().map((r) => r.instance);
|
|
165
169
|
}
|
|
166
170
|
/** List instances by owner path (e.g. "app:Portal/plugin:Okta") */
|
|
167
171
|
listByOwner(ownerPath) {
|
|
168
|
-
return (this.byOwner.get(ownerPath) ?? []).map(r => r.instance);
|
|
172
|
+
return (this.byOwner.get(ownerPath) ?? []).map((r) => r.instance);
|
|
169
173
|
}
|
|
170
174
|
/* -------------------- Conflict-aware exported names -------------------- */
|
|
171
175
|
/**
|
|
@@ -177,7 +181,7 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
|
|
|
177
181
|
*/
|
|
178
182
|
exportResolvedNames(opts) {
|
|
179
183
|
const cfg = { ...tool_types_1.DEFAULT_EXPORT_OPTS, ...(opts ?? {}) };
|
|
180
|
-
const rows = this.listAllIndexed().map(r => {
|
|
184
|
+
const rows = this.listAllIndexed().map((r) => {
|
|
181
185
|
const base = (0, tool_utils_1.normalizeSegment)(r.baseName, cfg.case);
|
|
182
186
|
const isLocal = r.source === this;
|
|
183
187
|
const provider = (0, tool_utils_1.normalizeProviderId)(this.providerIdOf(r.instance), cfg.case);
|
|
@@ -198,8 +202,8 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
|
|
|
198
202
|
out.set((0, tool_utils_1.ensureMaxLen)(base, cfg.maxLen), g.row.instance);
|
|
199
203
|
continue;
|
|
200
204
|
}
|
|
201
|
-
const locals = group.filter(g => g.isLocal);
|
|
202
|
-
const children = group.filter(g => !g.isLocal);
|
|
205
|
+
const locals = group.filter((g) => g.isLocal);
|
|
206
|
+
const children = group.filter((g) => !g.isLocal);
|
|
203
207
|
if (cfg.prefixChildrenOnConflict && locals.length > 0) {
|
|
204
208
|
// Locals
|
|
205
209
|
if (locals.length === 1) {
|
|
@@ -215,9 +219,7 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
|
|
|
215
219
|
}
|
|
216
220
|
// Children
|
|
217
221
|
for (const c of children) {
|
|
218
|
-
const pre = cfg.prefixSource === 'provider'
|
|
219
|
-
? (c.provider ?? c.ownerPath)
|
|
220
|
-
: c.ownerPath;
|
|
222
|
+
const pre = cfg.prefixSource === 'provider' ? c.provider ?? c.ownerPath : c.ownerPath;
|
|
221
223
|
const name = (0, tool_utils_1.ensureMaxLen)(`${pre}${(0, tool_utils_1.sepFor)(cfg.case)}${base}`, cfg.maxLen);
|
|
222
224
|
out.set(disambiguate(name, out, cfg), c.row.instance);
|
|
223
225
|
}
|
|
@@ -225,17 +227,13 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
|
|
|
225
227
|
else {
|
|
226
228
|
// Prefix everyone by source
|
|
227
229
|
for (const r of group) {
|
|
228
|
-
const pre = cfg.prefixSource === 'provider'
|
|
229
|
-
? (r.provider ?? r.ownerPath)
|
|
230
|
-
: r.ownerPath;
|
|
230
|
+
const pre = cfg.prefixSource === 'provider' ? r.provider ?? r.ownerPath : r.ownerPath;
|
|
231
231
|
const name = (0, tool_utils_1.ensureMaxLen)(`${pre}${(0, tool_utils_1.sepFor)(cfg.case)}${base}`, cfg.maxLen);
|
|
232
232
|
out.set(disambiguate(name, out, cfg), r.row.instance);
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
}
|
|
236
|
-
return [...out.entries()]
|
|
237
|
-
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
238
|
-
.map(([name, instance]) => ({ name, instance }));
|
|
236
|
+
return [...out.entries()].sort((a, b) => a[0].localeCompare(b[0])).map(([name, instance]) => ({ name, instance }));
|
|
239
237
|
function disambiguate(candidate, pool, cfg) {
|
|
240
238
|
if (!pool.has(candidate))
|
|
241
239
|
return candidate;
|
|
@@ -251,7 +249,7 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
|
|
|
251
249
|
/** Lookup by the exported (resolved) name. */
|
|
252
250
|
getExported(name, opts) {
|
|
253
251
|
const pairs = this.exportResolvedNames(opts);
|
|
254
|
-
return pairs.find(p => p.name === name)?.instance;
|
|
252
|
+
return pairs.find((p) => p.name === name)?.instance;
|
|
255
253
|
}
|
|
256
254
|
/* -------------------- Subscriptions -------------------- */
|
|
257
255
|
subscribe(opts, cb) {
|
|
@@ -305,7 +303,7 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
|
|
|
305
303
|
const maybe = meta?.providerId ?? meta?.provider ?? meta?.ownerId ?? undefined;
|
|
306
304
|
if (typeof maybe === 'string' && maybe.length)
|
|
307
305
|
return maybe;
|
|
308
|
-
const cls =
|
|
306
|
+
const cls = meta && meta.cls ? meta.cls : undefined;
|
|
309
307
|
if (cls) {
|
|
310
308
|
const id = (0, metadata_utils_1.getMetadata)('id', cls);
|
|
311
309
|
if (typeof id === 'string' && id.length)
|