agentdog 1.1.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 +22 -0
- package/README.md +244 -0
- package/dist/adapters/adapter-factory.d.ts +21 -0
- package/dist/adapters/adapter-factory.d.ts.map +1 -0
- package/dist/adapters/adapter-factory.js +157 -0
- package/dist/adapters/adapter-factory.js.map +1 -0
- package/dist/adapters/http-sse-adapter.d.ts +49 -0
- package/dist/adapters/http-sse-adapter.d.ts.map +1 -0
- package/dist/adapters/http-sse-adapter.js +485 -0
- package/dist/adapters/http-sse-adapter.js.map +1 -0
- package/dist/adapters/stdio-adapter.d.ts +69 -0
- package/dist/adapters/stdio-adapter.d.ts.map +1 -0
- package/dist/adapters/stdio-adapter.js +664 -0
- package/dist/adapters/stdio-adapter.js.map +1 -0
- package/dist/adapters/streamable-http-adapter.d.ts +38 -0
- package/dist/adapters/streamable-http-adapter.d.ts.map +1 -0
- package/dist/adapters/streamable-http-adapter.js +321 -0
- package/dist/adapters/streamable-http-adapter.js.map +1 -0
- package/dist/ai-gateway/anthropic-errors.d.ts +4 -0
- package/dist/ai-gateway/anthropic-errors.d.ts.map +1 -0
- package/dist/ai-gateway/anthropic-errors.js +17 -0
- package/dist/ai-gateway/anthropic-errors.js.map +1 -0
- package/dist/ai-gateway/auth.d.ts +3 -0
- package/dist/ai-gateway/auth.d.ts.map +1 -0
- package/dist/ai-gateway/auth.js +14 -0
- package/dist/ai-gateway/auth.js.map +1 -0
- package/dist/ai-gateway/auth.test.d.ts +2 -0
- package/dist/ai-gateway/auth.test.d.ts.map +1 -0
- package/dist/ai-gateway/auth.test.js +57 -0
- package/dist/ai-gateway/auth.test.js.map +1 -0
- package/dist/ai-gateway/count-tokens.d.ts +5 -0
- package/dist/ai-gateway/count-tokens.d.ts.map +1 -0
- package/dist/ai-gateway/count-tokens.js +37 -0
- package/dist/ai-gateway/count-tokens.js.map +1 -0
- package/dist/ai-gateway/count-tokens.test.d.ts +2 -0
- package/dist/ai-gateway/count-tokens.test.d.ts.map +1 -0
- package/dist/ai-gateway/count-tokens.test.js +19 -0
- package/dist/ai-gateway/count-tokens.test.js.map +1 -0
- package/dist/ai-gateway/dialects.d.ts +4 -0
- package/dist/ai-gateway/dialects.d.ts.map +1 -0
- package/dist/ai-gateway/dialects.js +15 -0
- package/dist/ai-gateway/dialects.js.map +1 -0
- package/dist/ai-gateway/gateway-server.d.ts +15 -0
- package/dist/ai-gateway/gateway-server.d.ts.map +1 -0
- package/dist/ai-gateway/gateway-server.js +121 -0
- package/dist/ai-gateway/gateway-server.js.map +1 -0
- package/dist/ai-gateway/integration.test.d.ts +2 -0
- package/dist/ai-gateway/integration.test.d.ts.map +1 -0
- package/dist/ai-gateway/integration.test.js +205 -0
- package/dist/ai-gateway/integration.test.js.map +1 -0
- package/dist/ai-gateway/ir/anthropic-in.d.ts +3 -0
- package/dist/ai-gateway/ir/anthropic-in.d.ts.map +1 -0
- package/dist/ai-gateway/ir/anthropic-in.js +121 -0
- package/dist/ai-gateway/ir/anthropic-in.js.map +1 -0
- package/dist/ai-gateway/ir/anthropic-in.test.d.ts +2 -0
- package/dist/ai-gateway/ir/anthropic-in.test.d.ts.map +1 -0
- package/dist/ai-gateway/ir/anthropic-in.test.js +93 -0
- package/dist/ai-gateway/ir/anthropic-in.test.js.map +1 -0
- package/dist/ai-gateway/ir/anthropic-sse.d.ts +22 -0
- package/dist/ai-gateway/ir/anthropic-sse.d.ts.map +1 -0
- package/dist/ai-gateway/ir/anthropic-sse.js +200 -0
- package/dist/ai-gateway/ir/anthropic-sse.js.map +1 -0
- package/dist/ai-gateway/ir/anthropic-sse.test.d.ts +2 -0
- package/dist/ai-gateway/ir/anthropic-sse.test.d.ts.map +1 -0
- package/dist/ai-gateway/ir/anthropic-sse.test.js +101 -0
- package/dist/ai-gateway/ir/anthropic-sse.test.js.map +1 -0
- package/dist/ai-gateway/ir/gemini-out.d.ts +20 -0
- package/dist/ai-gateway/ir/gemini-out.d.ts.map +1 -0
- package/dist/ai-gateway/ir/gemini-out.js +218 -0
- package/dist/ai-gateway/ir/gemini-out.js.map +1 -0
- package/dist/ai-gateway/ir/gemini-out.test.d.ts +2 -0
- package/dist/ai-gateway/ir/gemini-out.test.d.ts.map +1 -0
- package/dist/ai-gateway/ir/gemini-out.test.js +125 -0
- package/dist/ai-gateway/ir/gemini-out.test.js.map +1 -0
- package/dist/ai-gateway/ir/openai-out.d.ts +17 -0
- package/dist/ai-gateway/ir/openai-out.d.ts.map +1 -0
- package/dist/ai-gateway/ir/openai-out.js +226 -0
- package/dist/ai-gateway/ir/openai-out.js.map +1 -0
- package/dist/ai-gateway/ir/openai-out.test.d.ts +2 -0
- package/dist/ai-gateway/ir/openai-out.test.d.ts.map +1 -0
- package/dist/ai-gateway/ir/openai-out.test.js +144 -0
- package/dist/ai-gateway/ir/openai-out.test.js.map +1 -0
- package/dist/ai-gateway/ir/types.d.ts +77 -0
- package/dist/ai-gateway/ir/types.d.ts.map +1 -0
- package/dist/ai-gateway/ir/types.js +4 -0
- package/dist/ai-gateway/ir/types.js.map +1 -0
- package/dist/ai-gateway/ir-channel.d.ts +15 -0
- package/dist/ai-gateway/ir-channel.d.ts.map +1 -0
- package/dist/ai-gateway/ir-channel.js +120 -0
- package/dist/ai-gateway/ir-channel.js.map +1 -0
- package/dist/ai-gateway/model-router.d.ts +11 -0
- package/dist/ai-gateway/model-router.d.ts.map +1 -0
- package/dist/ai-gateway/model-router.js +27 -0
- package/dist/ai-gateway/model-router.js.map +1 -0
- package/dist/ai-gateway/model-router.test.d.ts +2 -0
- package/dist/ai-gateway/model-router.test.d.ts.map +1 -0
- package/dist/ai-gateway/model-router.test.js +43 -0
- package/dist/ai-gateway/model-router.test.js.map +1 -0
- package/dist/ai-gateway/passthrough.d.ts +9 -0
- package/dist/ai-gateway/passthrough.d.ts.map +1 -0
- package/dist/ai-gateway/passthrough.js +81 -0
- package/dist/ai-gateway/passthrough.js.map +1 -0
- package/dist/ai-gateway/passthrough.test.d.ts +2 -0
- package/dist/ai-gateway/passthrough.test.d.ts.map +1 -0
- package/dist/ai-gateway/passthrough.test.js +108 -0
- package/dist/ai-gateway/passthrough.test.js.map +1 -0
- package/dist/ai-gateway/upstream/model-lister.d.ts +13 -0
- package/dist/ai-gateway/upstream/model-lister.d.ts.map +1 -0
- package/dist/ai-gateway/upstream/model-lister.js +61 -0
- package/dist/ai-gateway/upstream/model-lister.js.map +1 -0
- package/dist/ai-gateway/upstream/provider-client.d.ts +20 -0
- package/dist/ai-gateway/upstream/provider-client.d.ts.map +1 -0
- package/dist/ai-gateway/upstream/provider-client.js +76 -0
- package/dist/ai-gateway/upstream/provider-client.js.map +1 -0
- package/dist/ai-gateway/upstream/provider-client.test.d.ts +2 -0
- package/dist/ai-gateway/upstream/provider-client.test.d.ts.map +1 -0
- package/dist/ai-gateway/upstream/provider-client.test.js +69 -0
- package/dist/ai-gateway/upstream/provider-client.test.js.map +1 -0
- package/dist/cli/cli-main.d.ts +7 -0
- package/dist/cli/cli-main.d.ts.map +1 -0
- package/dist/cli/cli-main.js +116 -0
- package/dist/cli/cli-main.js.map +1 -0
- package/dist/cli/cli-router.d.ts +20 -0
- package/dist/cli/cli-router.d.ts.map +1 -0
- package/dist/cli/cli-router.js +271 -0
- package/dist/cli/cli-router.js.map +1 -0
- package/dist/cli/cli-utils.d.ts +30 -0
- package/dist/cli/cli-utils.d.ts.map +1 -0
- package/dist/cli/cli-utils.js +219 -0
- package/dist/cli/cli-utils.js.map +1 -0
- package/dist/cli/commands/audit-commands.d.ts +30 -0
- package/dist/cli/commands/audit-commands.d.ts.map +1 -0
- package/dist/cli/commands/audit-commands.js +417 -0
- package/dist/cli/commands/audit-commands.js.map +1 -0
- package/dist/cli/commands/autostart-command.d.ts +21 -0
- package/dist/cli/commands/autostart-command.d.ts.map +1 -0
- package/dist/cli/commands/autostart-command.js +243 -0
- package/dist/cli/commands/autostart-command.js.map +1 -0
- package/dist/cli/commands/autostart-command.test.d.ts +2 -0
- package/dist/cli/commands/autostart-command.test.d.ts.map +1 -0
- package/dist/cli/commands/autostart-command.test.js +35 -0
- package/dist/cli/commands/autostart-command.test.js.map +1 -0
- package/dist/cli/commands/config-commands.d.ts +30 -0
- package/dist/cli/commands/config-commands.d.ts.map +1 -0
- package/dist/cli/commands/config-commands.js +1013 -0
- package/dist/cli/commands/config-commands.js.map +1 -0
- package/dist/cli/commands/daemon-commands.d.ts +76 -0
- package/dist/cli/commands/daemon-commands.d.ts.map +1 -0
- package/dist/cli/commands/daemon-commands.js +451 -0
- package/dist/cli/commands/daemon-commands.js.map +1 -0
- package/dist/cli/commands/detect-commands.d.ts +17 -0
- package/dist/cli/commands/detect-commands.d.ts.map +1 -0
- package/dist/cli/commands/detect-commands.js +293 -0
- package/dist/cli/commands/detect-commands.js.map +1 -0
- package/dist/cli/commands/diagnose-commands.d.ts +19 -0
- package/dist/cli/commands/diagnose-commands.d.ts.map +1 -0
- package/dist/cli/commands/diagnose-commands.js +326 -0
- package/dist/cli/commands/diagnose-commands.js.map +1 -0
- package/dist/cli/commands/optimize-commands.d.ts +14 -0
- package/dist/cli/commands/optimize-commands.d.ts.map +1 -0
- package/dist/cli/commands/optimize-commands.js +189 -0
- package/dist/cli/commands/optimize-commands.js.map +1 -0
- package/dist/cli/commands/proxy-command.d.ts +27 -0
- package/dist/cli/commands/proxy-command.d.ts.map +1 -0
- package/dist/cli/commands/proxy-command.js +212 -0
- package/dist/cli/commands/proxy-command.js.map +1 -0
- package/dist/cli/commands/start-command.d.ts +22 -0
- package/dist/cli/commands/start-command.d.ts.map +1 -0
- package/dist/cli/commands/start-command.js +275 -0
- package/dist/cli/commands/start-command.js.map +1 -0
- package/dist/config/config-manager.d.ts +125 -0
- package/dist/config/config-manager.d.ts.map +1 -0
- package/dist/config/config-manager.js +569 -0
- package/dist/config/config-manager.js.map +1 -0
- package/dist/config/config-manager.test.d.ts +2 -0
- package/dist/config/config-manager.test.d.ts.map +1 -0
- package/dist/config/config-manager.test.js +209 -0
- package/dist/config/config-manager.test.js.map +1 -0
- package/dist/core/auto-config-generator.d.ts +55 -0
- package/dist/core/auto-config-generator.d.ts.map +1 -0
- package/dist/core/auto-config-generator.js +278 -0
- package/dist/core/auto-config-generator.js.map +1 -0
- package/dist/core/mcpdog-server.d.ts +49 -0
- package/dist/core/mcpdog-server.d.ts.map +1 -0
- package/dist/core/mcpdog-server.js +552 -0
- package/dist/core/mcpdog-server.js.map +1 -0
- package/dist/core/protocol-detector.d.ts +56 -0
- package/dist/core/protocol-detector.d.ts.map +1 -0
- package/dist/core/protocol-detector.js +365 -0
- package/dist/core/protocol-detector.js.map +1 -0
- package/dist/daemon/daemon-client.d.ts +34 -0
- package/dist/daemon/daemon-client.d.ts.map +1 -0
- package/dist/daemon/daemon-client.js +130 -0
- package/dist/daemon/daemon-client.js.map +1 -0
- package/dist/daemon/daemon-client.test.d.ts +2 -0
- package/dist/daemon/daemon-client.test.d.ts.map +1 -0
- package/dist/daemon/daemon-client.test.js +77 -0
- package/dist/daemon/daemon-client.test.js.map +1 -0
- package/dist/daemon/daemon-info.d.ts +7 -0
- package/dist/daemon/daemon-info.d.ts.map +1 -0
- package/dist/daemon/daemon-info.js +34 -0
- package/dist/daemon/daemon-info.js.map +1 -0
- package/dist/daemon/daemon-info.test.d.ts +2 -0
- package/dist/daemon/daemon-info.test.d.ts.map +1 -0
- package/dist/daemon/daemon-info.test.js +57 -0
- package/dist/daemon/daemon-info.test.js.map +1 -0
- package/dist/daemon/daemon-web-server.ai.test.d.ts +2 -0
- package/dist/daemon/daemon-web-server.ai.test.d.ts.map +1 -0
- package/dist/daemon/daemon-web-server.ai.test.js +119 -0
- package/dist/daemon/daemon-web-server.ai.test.js.map +1 -0
- package/dist/daemon/daemon-web-server.d.ts +59 -0
- package/dist/daemon/daemon-web-server.d.ts.map +1 -0
- package/dist/daemon/daemon-web-server.js +1236 -0
- package/dist/daemon/daemon-web-server.js.map +1 -0
- package/dist/daemon/daemon-web-server.test.d.ts +2 -0
- package/dist/daemon/daemon-web-server.test.d.ts.map +1 -0
- package/dist/daemon/daemon-web-server.test.js +93 -0
- package/dist/daemon/daemon-web-server.test.js.map +1 -0
- package/dist/daemon/mcpdog-daemon.d.ts +42 -0
- package/dist/daemon/mcpdog-daemon.d.ts.map +1 -0
- package/dist/daemon/mcpdog-daemon.js +302 -0
- package/dist/daemon/mcpdog-daemon.js.map +1 -0
- package/dist/daemon/stdio-proxy.d.ts +17 -0
- package/dist/daemon/stdio-proxy.d.ts.map +1 -0
- package/dist/daemon/stdio-proxy.js +143 -0
- package/dist/daemon/stdio-proxy.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +198 -0
- package/dist/index.js.map +1 -0
- package/dist/intent-analyzer.d.ts +27 -0
- package/dist/intent-analyzer.d.ts.map +1 -0
- package/dist/intent-analyzer.js +140 -0
- package/dist/intent-analyzer.js.map +1 -0
- package/dist/logging/server-log-manager.d.ts +75 -0
- package/dist/logging/server-log-manager.d.ts.map +1 -0
- package/dist/logging/server-log-manager.js +185 -0
- package/dist/logging/server-log-manager.js.map +1 -0
- package/dist/mcp-registry.d.ts +35 -0
- package/dist/mcp-registry.d.ts.map +1 -0
- package/dist/mcp-registry.js +166 -0
- package/dist/mcp-registry.js.map +1 -0
- package/dist/middleware/auth.d.ts +5 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +81 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/mock-tool-database.d.ts +41 -0
- package/dist/mock-tool-database.d.ts.map +1 -0
- package/dist/mock-tool-database.js +461 -0
- package/dist/mock-tool-database.js.map +1 -0
- package/dist/proxy-server-manager.d.ts +11 -0
- package/dist/proxy-server-manager.d.ts.map +1 -0
- package/dist/proxy-server-manager.js +144 -0
- package/dist/proxy-server-manager.js.map +1 -0
- package/dist/router/tool-router.d.ts +61 -0
- package/dist/router/tool-router.d.ts.map +1 -0
- package/dist/router/tool-router.js +539 -0
- package/dist/router/tool-router.js.map +1 -0
- package/dist/router/tool-router.test.d.ts +2 -0
- package/dist/router/tool-router.test.d.ts.map +1 -0
- package/dist/router/tool-router.test.js +113 -0
- package/dist/router/tool-router.test.js.map +1 -0
- package/dist/streamable-http-server.d.ts +27 -0
- package/dist/streamable-http-server.d.ts.map +1 -0
- package/dist/streamable-http-server.js +302 -0
- package/dist/streamable-http-server.js.map +1 -0
- package/dist/tool-finder.d.ts +21 -0
- package/dist/tool-finder.d.ts.map +1 -0
- package/dist/tool-finder.js +86 -0
- package/dist/tool-finder.js.map +1 -0
- package/dist/tool-recommender.d.ts +23 -0
- package/dist/tool-recommender.d.ts.map +1 -0
- package/dist/tool-recommender.js +200 -0
- package/dist/tool-recommender.js.map +1 -0
- package/dist/types/index.d.ts +145 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/server-name-validator.d.ts +47 -0
- package/dist/utils/server-name-validator.d.ts.map +1 -0
- package/dist/utils/server-name-validator.js +156 -0
- package/dist/utils/server-name-validator.js.map +1 -0
- package/dist/web/web-server.d.ts +44 -0
- package/dist/web/web-server.d.ts.map +1 -0
- package/dist/web/web-server.js +500 -0
- package/dist/web/web-server.js.map +1 -0
- package/package.json +68 -0
- package/web/dist/assets/index-DMVhVtNU.css +1 -0
- package/web/dist/assets/index-VMXIgcOH.js +92 -0
- package/web/dist/assets/index-VMXIgcOH.js.map +1 -0
- package/web/dist/index.html +14 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
+
import { ToolRouter } from './tool-router';
|
|
3
|
+
import { EventEmitter } from 'events';
|
|
4
|
+
// Mock ServerAdapter
|
|
5
|
+
class MockAdapter extends EventEmitter {
|
|
6
|
+
name;
|
|
7
|
+
config;
|
|
8
|
+
isConnected = false;
|
|
9
|
+
tools;
|
|
10
|
+
constructor(name, tools) {
|
|
11
|
+
super();
|
|
12
|
+
this.name = name;
|
|
13
|
+
this.tools = tools;
|
|
14
|
+
this.config = {};
|
|
15
|
+
}
|
|
16
|
+
connect = vi.fn(async () => {
|
|
17
|
+
this.isConnected = true;
|
|
18
|
+
this.emit('connected');
|
|
19
|
+
});
|
|
20
|
+
disconnect = vi.fn(async () => {
|
|
21
|
+
this.isConnected = false;
|
|
22
|
+
this.emit('disconnected');
|
|
23
|
+
});
|
|
24
|
+
getTools = vi.fn(async () => {
|
|
25
|
+
if (!this.isConnected)
|
|
26
|
+
throw new Error('Not connected');
|
|
27
|
+
return this.tools;
|
|
28
|
+
});
|
|
29
|
+
callTool = vi.fn(async (toolName, args) => {
|
|
30
|
+
if (!this.isConnected)
|
|
31
|
+
throw new Error('Not connected');
|
|
32
|
+
return {
|
|
33
|
+
jsonrpc: '2.0',
|
|
34
|
+
id: 1,
|
|
35
|
+
result: { content: `Result from ${this.name}.${toolName}` },
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
// Added to satisfy ServerAdapter interface
|
|
39
|
+
sendRequest = vi.fn(async (request) => {
|
|
40
|
+
return {
|
|
41
|
+
jsonrpc: '2.0',
|
|
42
|
+
id: request.id,
|
|
43
|
+
result: { message: 'Mocked sendRequest' }
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
describe('ToolRouter', () => {
|
|
48
|
+
let toolRouter;
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
toolRouter = new ToolRouter();
|
|
51
|
+
});
|
|
52
|
+
it('should add an adapter and refresh routes on connect', async () => {
|
|
53
|
+
const mockTools = [{ name: 'tool1', description: 'desc1', inputSchema: { type: 'object' } }];
|
|
54
|
+
const adapter = new MockAdapter('server1', mockTools);
|
|
55
|
+
toolRouter.addAdapter(adapter);
|
|
56
|
+
await adapter.connect();
|
|
57
|
+
const allTools = await toolRouter.getAllTools();
|
|
58
|
+
expect(allTools).toHaveLength(1);
|
|
59
|
+
expect(allTools[0].name).toBe('tool1');
|
|
60
|
+
expect(toolRouter.getAdapter('server1')).toBe(adapter);
|
|
61
|
+
});
|
|
62
|
+
it('should handle tool name conflicts by prefixing', async () => {
|
|
63
|
+
const tools1 = [{ name: 'shared_tool', description: 'desc1', inputSchema: { type: 'object' } }];
|
|
64
|
+
const tools2 = [{ name: 'shared_tool', description: 'desc2', inputSchema: { type: 'object' } }];
|
|
65
|
+
const adapter1 = new MockAdapter('server1', tools1);
|
|
66
|
+
const adapter2 = new MockAdapter('server2', tools2);
|
|
67
|
+
toolRouter.addAdapter(adapter1);
|
|
68
|
+
toolRouter.addAdapter(adapter2);
|
|
69
|
+
await adapter1.connect();
|
|
70
|
+
await adapter2.connect();
|
|
71
|
+
const allTools = await toolRouter.getAllTools();
|
|
72
|
+
expect(allTools).toHaveLength(2);
|
|
73
|
+
const toolNames = allTools.map(t => t.name).sort();
|
|
74
|
+
expect(toolNames).toEqual(['server1-shared_tool', 'server2-shared_tool']);
|
|
75
|
+
});
|
|
76
|
+
it('should route a tool call to the correct adapter', async () => {
|
|
77
|
+
const tools1 = [{ name: 'tool1', description: 'desc1', inputSchema: { type: 'object' } }];
|
|
78
|
+
const tools2 = [{ name: 'tool2', description: 'desc2', inputSchema: { type: 'object' } }];
|
|
79
|
+
const adapter1 = new MockAdapter('server1', tools1);
|
|
80
|
+
const adapter2 = new MockAdapter('server2', tools2);
|
|
81
|
+
toolRouter.addAdapter(adapter1);
|
|
82
|
+
toolRouter.addAdapter(adapter2);
|
|
83
|
+
await adapter1.connect();
|
|
84
|
+
await adapter2.connect();
|
|
85
|
+
// Need to manually trigger route creation for testing since it happens on 'connect' event
|
|
86
|
+
// @ts-ignore - access private method for test
|
|
87
|
+
await toolRouter.refreshToolRoutes('server1');
|
|
88
|
+
// @ts-ignore
|
|
89
|
+
await toolRouter.refreshToolRoutes('server2');
|
|
90
|
+
const response = await toolRouter.callTool('tool2', {});
|
|
91
|
+
expect(response.result.content).toBe('Result from server2.tool2');
|
|
92
|
+
expect(adapter2.callTool).toHaveBeenCalledWith('tool2', {});
|
|
93
|
+
expect(adapter1.callTool).not.toHaveBeenCalled();
|
|
94
|
+
});
|
|
95
|
+
it('should return an error if a tool is not found', async () => {
|
|
96
|
+
const response = await toolRouter.callTool('non_existent_tool', {});
|
|
97
|
+
expect(response.error).toBeDefined();
|
|
98
|
+
expect(response.error?.code).toBe(-32601);
|
|
99
|
+
expect(response.error?.message).toContain('Tool not found');
|
|
100
|
+
});
|
|
101
|
+
it('should remove routes when an adapter disconnects', async () => {
|
|
102
|
+
const mockTools = [{ name: 'tool1', description: 'desc1', inputSchema: { type: 'object' } }];
|
|
103
|
+
const adapter = new MockAdapter('server1', mockTools);
|
|
104
|
+
toolRouter.addAdapter(adapter);
|
|
105
|
+
await adapter.connect();
|
|
106
|
+
let allTools = await toolRouter.getAllTools();
|
|
107
|
+
expect(allTools).toHaveLength(1);
|
|
108
|
+
adapter.emit('disconnected');
|
|
109
|
+
const route = toolRouter.findToolRoute('tool1');
|
|
110
|
+
expect(route).toBeUndefined();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
//# sourceMappingURL=tool-router.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-router.test.js","sourceRoot":"","sources":["../../src/router/tool-router.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { ConfigManager } from './config/config-manager.js';
|
|
3
|
+
export declare class StreamableHttpMCPServer extends EventEmitter {
|
|
4
|
+
private server;
|
|
5
|
+
private httpServer;
|
|
6
|
+
private port;
|
|
7
|
+
private authToken?;
|
|
8
|
+
private authMiddleware?;
|
|
9
|
+
private sessions;
|
|
10
|
+
private sessionTimeout;
|
|
11
|
+
constructor(configManager: ConfigManager, port?: number, authToken?: string);
|
|
12
|
+
private setupServer;
|
|
13
|
+
private setupHttpServer;
|
|
14
|
+
private handleAuthenticatedRequest;
|
|
15
|
+
private handleHealthCheck;
|
|
16
|
+
private handleHttpRequest;
|
|
17
|
+
private sendMCPResponse;
|
|
18
|
+
private shouldUseStreaming;
|
|
19
|
+
private sendErrorResponse;
|
|
20
|
+
private createSession;
|
|
21
|
+
private validateSession;
|
|
22
|
+
private updateSessionActivity;
|
|
23
|
+
private cleanupExpiredSessions;
|
|
24
|
+
start(): Promise<void>;
|
|
25
|
+
private shutdown;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=streamable-http-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamable-http-server.d.ts","sourceRoot":"","sources":["../src/streamable-http-server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAItC,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,qBAAa,uBAAwB,SAAQ,YAAY;IACvD,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,cAAc,CAAC,CAAwE;IAC/F,OAAO,CAAC,QAAQ,CAKD;IACf,OAAO,CAAC,cAAc,CAA0B;gBAEpC,aAAa,EAAE,aAAa,EAAE,IAAI,GAAE,MAAa,EAAE,SAAS,CAAC,EAAE,MAAM;IAgBjF,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,eAAe;IAuCvB,OAAO,CAAC,0BAA0B;IAWlC,OAAO,CAAC,iBAAiB;YAUX,iBAAiB;IA6F/B,OAAO,CAAC,eAAe;IA2BvB,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,sBAAsB;IAUxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAgCd,QAAQ;CA4BvB"}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { createServer } from 'http';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
import { MCPDogServer } from './core/mcpdog-server.js';
|
|
5
|
+
import { createAuthMiddleware } from './middleware/auth.js';
|
|
6
|
+
export class StreamableHttpMCPServer extends EventEmitter {
|
|
7
|
+
server;
|
|
8
|
+
httpServer;
|
|
9
|
+
port;
|
|
10
|
+
authToken;
|
|
11
|
+
authMiddleware;
|
|
12
|
+
sessions = new Map();
|
|
13
|
+
sessionTimeout = 30 * 60 * 1000; // 30 minutes
|
|
14
|
+
constructor(configManager, port = 4000, authToken) {
|
|
15
|
+
super();
|
|
16
|
+
console.error(`[HTTP] Creating StreamableHttpMCPServer instance on port ${port}${authToken ? ' with authentication' : ''}`);
|
|
17
|
+
this.port = port;
|
|
18
|
+
this.authToken = authToken;
|
|
19
|
+
this.server = new MCPDogServer(configManager);
|
|
20
|
+
// Setup auth middleware if token is provided
|
|
21
|
+
if (this.authToken) {
|
|
22
|
+
this.authMiddleware = createAuthMiddleware(this.authToken);
|
|
23
|
+
}
|
|
24
|
+
this.setupServer();
|
|
25
|
+
this.setupHttpServer();
|
|
26
|
+
}
|
|
27
|
+
setupServer() {
|
|
28
|
+
this.server.on('notification', (notification) => {
|
|
29
|
+
// HTTP mode doesn't push notifications like stdio, they're request-response based
|
|
30
|
+
console.error(`[HTTP] Received notification: ${notification.method}`);
|
|
31
|
+
});
|
|
32
|
+
this.server.on('error', ({ error, context }) => {
|
|
33
|
+
console.error(`MCPDog error [${context}]:`, error);
|
|
34
|
+
});
|
|
35
|
+
this.server.on('started', () => {
|
|
36
|
+
console.error('MCPDog Server started (HTTP streamable mode)');
|
|
37
|
+
});
|
|
38
|
+
this.server.on('stopped', () => {
|
|
39
|
+
console.error('MCPDog Server stopped');
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
setupHttpServer() {
|
|
43
|
+
this.httpServer = createServer();
|
|
44
|
+
// Enable CORS for web-based MCP clients
|
|
45
|
+
this.httpServer.on('request', (req, res) => {
|
|
46
|
+
// Set CORS headers
|
|
47
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
48
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
49
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, mcp-session-id');
|
|
50
|
+
if (req.method === 'OPTIONS') {
|
|
51
|
+
res.writeHead(200);
|
|
52
|
+
res.end();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
// Apply authentication middleware if configured
|
|
56
|
+
if (this.authMiddleware) {
|
|
57
|
+
this.authMiddleware(req, res, () => {
|
|
58
|
+
this.handleAuthenticatedRequest(req, res);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
this.handleAuthenticatedRequest(req, res);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
this.httpServer.on('error', (error) => {
|
|
66
|
+
console.error('HTTP server error:', error);
|
|
67
|
+
});
|
|
68
|
+
// Handle process signals
|
|
69
|
+
process.on('SIGINT', () => this.shutdown());
|
|
70
|
+
process.on('SIGTERM', () => this.shutdown());
|
|
71
|
+
process.on('uncaughtException', (error) => {
|
|
72
|
+
console.error('Uncaught exception:', error);
|
|
73
|
+
this.shutdown();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
handleAuthenticatedRequest(req, res) {
|
|
77
|
+
if (req.method === 'POST') {
|
|
78
|
+
this.handleHttpRequest(req, res);
|
|
79
|
+
}
|
|
80
|
+
else if (req.method === 'GET') {
|
|
81
|
+
this.handleHealthCheck(req, res);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
85
|
+
res.end(JSON.stringify({ error: 'Method not allowed' }));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
handleHealthCheck(req, res) {
|
|
89
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
90
|
+
res.end(JSON.stringify({
|
|
91
|
+
status: 'healthy',
|
|
92
|
+
service: 'mcpdog-streamable-http',
|
|
93
|
+
version: '2.0.15',
|
|
94
|
+
timestamp: new Date().toISOString()
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
async handleHttpRequest(req, res) {
|
|
98
|
+
let body = '';
|
|
99
|
+
req.on('data', (chunk) => {
|
|
100
|
+
body += chunk.toString();
|
|
101
|
+
});
|
|
102
|
+
req.on('end', async () => {
|
|
103
|
+
try {
|
|
104
|
+
console.error(`[HTTP] Received request: ${body.substring(0, 100)}...`);
|
|
105
|
+
if (!body.trim()) {
|
|
106
|
+
this.sendErrorResponse(res, 400, 'Empty request body');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const message = JSON.parse(body);
|
|
110
|
+
// Extract session ID from headers
|
|
111
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
112
|
+
// Check if it's a notification message (no id field)
|
|
113
|
+
if (!('id' in message)) {
|
|
114
|
+
const notification = message;
|
|
115
|
+
console.error(`[HTTP] Handling notification: ${notification.method}`);
|
|
116
|
+
// Validate session for non-initialize notifications
|
|
117
|
+
if (sessionId && !this.validateSession(sessionId)) {
|
|
118
|
+
this.sendErrorResponse(res, 401, 'Invalid or expired session');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// Notifications get 204 No Content response
|
|
122
|
+
res.writeHead(204);
|
|
123
|
+
res.end();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// Handle regular requests
|
|
127
|
+
const request = message;
|
|
128
|
+
console.error(`[HTTP] Processing request: ${request.method} (id: ${request.id})`);
|
|
129
|
+
// Handle initialize request - create new session
|
|
130
|
+
if (request.method === 'initialize') {
|
|
131
|
+
const response = await this.server.handleRequest(request, 'http-client');
|
|
132
|
+
if (!response.error) {
|
|
133
|
+
// Create new session
|
|
134
|
+
const newSessionId = this.createSession(req.socket?.remoteAddress || 'unknown');
|
|
135
|
+
console.error(`[HTTP] Created new session: ${newSessionId}`);
|
|
136
|
+
// Add session ID to response headers
|
|
137
|
+
res.setHeader('mcp-session-id', newSessionId);
|
|
138
|
+
this.sendMCPResponse(res, response);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
this.sendMCPResponse(res, response);
|
|
142
|
+
}
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// For non-initialize requests, validate session
|
|
146
|
+
if (!sessionId) {
|
|
147
|
+
this.sendErrorResponse(res, 400, 'Missing mcp-session-id header');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (!this.validateSession(sessionId)) {
|
|
151
|
+
this.sendErrorResponse(res, 401, 'Invalid or expired session');
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// Update session activity
|
|
155
|
+
this.updateSessionActivity(sessionId);
|
|
156
|
+
const response = await this.server.handleRequest(request, sessionId);
|
|
157
|
+
console.error(`[HTTP] Sending response for: ${request.method} (id: ${request.id})`);
|
|
158
|
+
this.sendMCPResponse(res, response);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
console.error('[HTTP] Error processing request:', error);
|
|
162
|
+
this.sendErrorResponse(res, 500, 'Internal server error');
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
req.on('error', (error) => {
|
|
166
|
+
console.error('[HTTP] Request error:', error);
|
|
167
|
+
this.sendErrorResponse(res, 400, 'Bad request');
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
sendMCPResponse(res, response) {
|
|
171
|
+
const responseBody = JSON.stringify(response);
|
|
172
|
+
// Check if this could be a streaming response (for future SSE support)
|
|
173
|
+
const isStreamingRequest = this.shouldUseStreaming(response);
|
|
174
|
+
if (isStreamingRequest) {
|
|
175
|
+
// Send as Server-Sent Events for streaming responses
|
|
176
|
+
res.writeHead(200, {
|
|
177
|
+
'Content-Type': 'text/event-stream',
|
|
178
|
+
'Cache-Control': 'no-cache',
|
|
179
|
+
'Connection': 'keep-alive'
|
|
180
|
+
});
|
|
181
|
+
res.write(`event: message\n`);
|
|
182
|
+
res.write(`data: ${responseBody}\n\n`);
|
|
183
|
+
res.end();
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
// Send as regular JSON response
|
|
187
|
+
res.writeHead(200, {
|
|
188
|
+
'Content-Type': 'application/json'
|
|
189
|
+
});
|
|
190
|
+
res.end(responseBody);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
shouldUseStreaming(response) {
|
|
194
|
+
// For now, always use JSON responses
|
|
195
|
+
// In the future, we could detect streaming scenarios (e.g., tool calls that take time)
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
sendErrorResponse(res, statusCode, message) {
|
|
199
|
+
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
200
|
+
res.end(JSON.stringify({
|
|
201
|
+
error: {
|
|
202
|
+
code: statusCode,
|
|
203
|
+
message: message
|
|
204
|
+
}
|
|
205
|
+
}));
|
|
206
|
+
}
|
|
207
|
+
createSession(clientId) {
|
|
208
|
+
const sessionId = randomUUID();
|
|
209
|
+
const now = new Date();
|
|
210
|
+
this.sessions.set(sessionId, {
|
|
211
|
+
id: sessionId,
|
|
212
|
+
clientId: clientId,
|
|
213
|
+
created: now,
|
|
214
|
+
lastActivity: now
|
|
215
|
+
});
|
|
216
|
+
return sessionId;
|
|
217
|
+
}
|
|
218
|
+
validateSession(sessionId) {
|
|
219
|
+
const session = this.sessions.get(sessionId);
|
|
220
|
+
if (!session) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
// Check if session has expired
|
|
224
|
+
const now = new Date();
|
|
225
|
+
if (now.getTime() - session.lastActivity.getTime() > this.sessionTimeout) {
|
|
226
|
+
this.sessions.delete(sessionId);
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
updateSessionActivity(sessionId) {
|
|
232
|
+
const session = this.sessions.get(sessionId);
|
|
233
|
+
if (session) {
|
|
234
|
+
session.lastActivity = new Date();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
cleanupExpiredSessions() {
|
|
238
|
+
const now = new Date();
|
|
239
|
+
for (const [sessionId, session] of this.sessions) {
|
|
240
|
+
if (now.getTime() - session.lastActivity.getTime() > this.sessionTimeout) {
|
|
241
|
+
console.error(`[HTTP] Cleaning up expired session: ${sessionId}`);
|
|
242
|
+
this.sessions.delete(sessionId);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
async start() {
|
|
247
|
+
try {
|
|
248
|
+
console.error(`[HTTP] Starting StreamableHttpMCPServer...`);
|
|
249
|
+
await this.server.start();
|
|
250
|
+
// Start session cleanup timer
|
|
251
|
+
const cleanupInterval = setInterval(() => {
|
|
252
|
+
this.cleanupExpiredSessions();
|
|
253
|
+
}, 5 * 60 * 1000); // Clean up every 5 minutes
|
|
254
|
+
// Store cleanup interval for shutdown
|
|
255
|
+
this.cleanupInterval = cleanupInterval;
|
|
256
|
+
return new Promise((resolve, reject) => {
|
|
257
|
+
this.httpServer.listen(this.port, (error) => {
|
|
258
|
+
if (error) {
|
|
259
|
+
reject(error);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
console.error(`[HTTP] StreamableHttpMCPServer started successfully on port ${this.port}`);
|
|
263
|
+
console.error(`[HTTP] Health check endpoint: http://localhost:${this.port}/`);
|
|
264
|
+
console.error(`[HTTP] MCP endpoint: POST http://localhost:${this.port}/`);
|
|
265
|
+
console.error(`[HTTP] Session management enabled with ${this.sessionTimeout / 1000}s timeout`);
|
|
266
|
+
resolve();
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
console.error('Failed to start HTTP server:', error);
|
|
273
|
+
process.exit(1);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
async shutdown() {
|
|
277
|
+
console.error('Shutting down StreamableHttpMCPServer...');
|
|
278
|
+
try {
|
|
279
|
+
// Clean up session cleanup timer
|
|
280
|
+
if (this.cleanupInterval) {
|
|
281
|
+
clearInterval(this.cleanupInterval);
|
|
282
|
+
}
|
|
283
|
+
// Clear all sessions
|
|
284
|
+
this.sessions.clear();
|
|
285
|
+
if (this.httpServer) {
|
|
286
|
+
await new Promise((resolve) => {
|
|
287
|
+
this.httpServer.close(() => {
|
|
288
|
+
console.error('HTTP server closed');
|
|
289
|
+
resolve();
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
await this.server.stop();
|
|
294
|
+
process.exit(0);
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
console.error('Error during shutdown:', error);
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=streamable-http-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamable-http-server.js","sourceRoot":"","sources":["../src/streamable-http-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { MCPTool } from './mcp-registry.js';
|
|
2
|
+
import { UserIntent } from './intent-analyzer.js';
|
|
3
|
+
export interface ToolMatch {
|
|
4
|
+
server: string;
|
|
5
|
+
tool: MCPTool;
|
|
6
|
+
matchScore: number;
|
|
7
|
+
suggestedCall?: {
|
|
8
|
+
toolName: string;
|
|
9
|
+
parameters: any;
|
|
10
|
+
reasoning: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export declare class ToolFinder {
|
|
14
|
+
private registry;
|
|
15
|
+
constructor();
|
|
16
|
+
findMatchingTools(intent: UserIntent): Promise<ToolMatch[]>;
|
|
17
|
+
private generateToolCall;
|
|
18
|
+
getServerConfig(serverName: string): import("./mcp-registry.js").MCPServerConfig | undefined;
|
|
19
|
+
getAllServers(): import("./mcp-registry.js").MCPServerInfo[];
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=tool-finder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-finder.d.ts","sourceRoot":"","sources":["../src/tool-finder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,GAAG,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAc;;IAMxB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAoBjE,OAAO,CAAC,gBAAgB;IAiExB,eAAe,CAAC,UAAU,EAAE,MAAM;IAKlC,aAAa;CAGd"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { MCPRegistry } from './mcp-registry.js';
|
|
2
|
+
export class ToolFinder {
|
|
3
|
+
registry;
|
|
4
|
+
constructor() {
|
|
5
|
+
this.registry = new MCPRegistry();
|
|
6
|
+
}
|
|
7
|
+
async findMatchingTools(intent) {
|
|
8
|
+
// Use keyword matching to find tools
|
|
9
|
+
const matches = this.registry.findToolsByKeywords(intent.keywords);
|
|
10
|
+
// Generate call suggestions for each matched tool
|
|
11
|
+
const toolMatches = matches.map(match => {
|
|
12
|
+
const suggestedCall = this.generateToolCall(match.tool, intent);
|
|
13
|
+
return {
|
|
14
|
+
server: match.server,
|
|
15
|
+
tool: match.tool,
|
|
16
|
+
matchScore: match.matchScore,
|
|
17
|
+
suggestedCall
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
// Return top 3 best matches
|
|
21
|
+
return toolMatches.slice(0, 3);
|
|
22
|
+
}
|
|
23
|
+
generateToolCall(tool, intent) {
|
|
24
|
+
const parameters = {};
|
|
25
|
+
let reasoning = `Based on your request "${intent.description}", `;
|
|
26
|
+
// Intelligently fill parameters based on tool type and user intent
|
|
27
|
+
switch (tool.name) {
|
|
28
|
+
case 'browser_navigate':
|
|
29
|
+
if (intent.extractedData.url) {
|
|
30
|
+
parameters.url = intent.extractedData.url;
|
|
31
|
+
reasoning += `I have prepared a call to navigate to ${intent.extractedData.url}.`;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
parameters.url = 'https://www.google.com';
|
|
35
|
+
reasoning += `I suggest navigating to Google homepage first.`;
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
case 'browser_type':
|
|
39
|
+
if (intent.extractedData.text) {
|
|
40
|
+
parameters.text = intent.extractedData.text;
|
|
41
|
+
parameters.submit = true;
|
|
42
|
+
reasoning += `I will input the text "${intent.extractedData.text}" and submit.`;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
parameters.text = 'Sample text';
|
|
46
|
+
parameters.submit = false;
|
|
47
|
+
reasoning += `This is a sample call for text input.`;
|
|
48
|
+
}
|
|
49
|
+
// Need to get page snapshot first to find input element
|
|
50
|
+
parameters.element = 'Need to get page snapshot to determine input element';
|
|
51
|
+
parameters.ref = 'Need to get element reference from snapshot';
|
|
52
|
+
break;
|
|
53
|
+
case 'browser_click':
|
|
54
|
+
parameters.element = 'Need to get page snapshot to determine click element';
|
|
55
|
+
parameters.ref = 'Need to get element reference from snapshot';
|
|
56
|
+
reasoning += `Need to get page snapshot to determine which element to click.`;
|
|
57
|
+
break;
|
|
58
|
+
case 'browser_screenshot':
|
|
59
|
+
case 'browser_snapshot':
|
|
60
|
+
case 'browser_go_back':
|
|
61
|
+
case 'browser_go_forward':
|
|
62
|
+
// These tools don't need parameters
|
|
63
|
+
reasoning += `This tool can be called directly.`;
|
|
64
|
+
break;
|
|
65
|
+
case 'browser_wait':
|
|
66
|
+
parameters.time = 2;
|
|
67
|
+
reasoning += `I suggest waiting 2 seconds.`;
|
|
68
|
+
break;
|
|
69
|
+
default:
|
|
70
|
+
reasoning += `This is a generic tool call.`;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
toolName: tool.name,
|
|
74
|
+
parameters,
|
|
75
|
+
reasoning
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
getServerConfig(serverName) {
|
|
79
|
+
const serverInfo = this.registry.getServerByName(serverName);
|
|
80
|
+
return serverInfo?.config;
|
|
81
|
+
}
|
|
82
|
+
getAllServers() {
|
|
83
|
+
return this.registry.getAllServers();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=tool-finder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-finder.js","sourceRoot":"","sources":["../src/tool-finder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { UserIntent } from "./intent-analyzer.js";
|
|
2
|
+
import { MockToolDatabase, MCPTool } from "./mock-tool-database.js";
|
|
3
|
+
export interface ToolRecommendation {
|
|
4
|
+
tool: MCPTool;
|
|
5
|
+
score: number;
|
|
6
|
+
rating: number;
|
|
7
|
+
reasoning: string;
|
|
8
|
+
usageInstructions: string[];
|
|
9
|
+
configurationSteps: string[];
|
|
10
|
+
}
|
|
11
|
+
export declare class ToolRecommendationEngine {
|
|
12
|
+
private toolDatabase;
|
|
13
|
+
constructor(toolDatabase: MockToolDatabase);
|
|
14
|
+
getRecommendations(intent: UserIntent): Promise<ToolRecommendation[]>;
|
|
15
|
+
private calculateRecommendationScore;
|
|
16
|
+
private hasRequiredData;
|
|
17
|
+
private calculateDisplayRating;
|
|
18
|
+
private generateReasoning;
|
|
19
|
+
private generateUsageInstructions;
|
|
20
|
+
private generateContextualExample;
|
|
21
|
+
private generateConfigurationSteps;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=tool-recommender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-recommender.d.ts","sourceRoot":"","sources":["../src/tool-recommender.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEpE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,qBAAa,wBAAwB;IACvB,OAAO,CAAC,YAAY;gBAAZ,YAAY,EAAE,gBAAgB;IAE5C,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAkC3E,OAAO,CAAC,4BAA4B;IAqDpC,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,iBAAiB;IAgCzB,OAAO,CAAC,yBAAyB;IA8BjC,OAAO,CAAC,yBAAyB;IAwBjC,OAAO,CAAC,0BAA0B;CAoCnC"}
|