universal-agent-memory 1.0.19 → 1.0.20

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.
Files changed (44) hide show
  1. package/dist/benchmarks/benchmark.d.ts +2 -2
  2. package/dist/bin/cli.js +30 -0
  3. package/dist/bin/cli.js.map +1 -1
  4. package/dist/cli/mcp-router.d.ts +16 -0
  5. package/dist/cli/mcp-router.d.ts.map +1 -0
  6. package/dist/cli/mcp-router.js +143 -0
  7. package/dist/cli/mcp-router.js.map +1 -0
  8. package/dist/index.d.ts +2 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +2 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/mcp-router/config/parser.d.ts +9 -0
  13. package/dist/mcp-router/config/parser.d.ts.map +1 -0
  14. package/dist/mcp-router/config/parser.js +137 -0
  15. package/dist/mcp-router/config/parser.js.map +1 -0
  16. package/dist/mcp-router/executor/client.d.ts +31 -0
  17. package/dist/mcp-router/executor/client.d.ts.map +1 -0
  18. package/dist/mcp-router/executor/client.js +187 -0
  19. package/dist/mcp-router/executor/client.js.map +1 -0
  20. package/dist/mcp-router/index.d.ts +18 -0
  21. package/dist/mcp-router/index.d.ts.map +1 -0
  22. package/dist/mcp-router/index.js +16 -0
  23. package/dist/mcp-router/index.js.map +1 -0
  24. package/dist/mcp-router/search/fuzzy.d.ts +26 -0
  25. package/dist/mcp-router/search/fuzzy.d.ts.map +1 -0
  26. package/dist/mcp-router/search/fuzzy.js +94 -0
  27. package/dist/mcp-router/search/fuzzy.js.map +1 -0
  28. package/dist/mcp-router/server.d.ts +50 -0
  29. package/dist/mcp-router/server.d.ts.map +1 -0
  30. package/dist/mcp-router/server.js +229 -0
  31. package/dist/mcp-router/server.js.map +1 -0
  32. package/dist/mcp-router/tools/discover.d.ts +37 -0
  33. package/dist/mcp-router/tools/discover.d.ts.map +1 -0
  34. package/dist/mcp-router/tools/discover.js +65 -0
  35. package/dist/mcp-router/tools/discover.js.map +1 -0
  36. package/dist/mcp-router/tools/execute.d.ts +38 -0
  37. package/dist/mcp-router/tools/execute.d.ts.map +1 -0
  38. package/dist/mcp-router/tools/execute.js +92 -0
  39. package/dist/mcp-router/tools/execute.js.map +1 -0
  40. package/dist/mcp-router/types.d.ts +54 -0
  41. package/dist/mcp-router/types.d.ts.map +1 -0
  42. package/dist/mcp-router/types.js +6 -0
  43. package/dist/mcp-router/types.js.map +1 -0
  44. package/package.json +1 -1
@@ -0,0 +1,187 @@
1
+ /**
2
+ * MCP Client Executor
3
+ * Spawns and communicates with MCP servers
4
+ */
5
+ import { spawn } from 'child_process';
6
+ export class McpClient {
7
+ process = null;
8
+ requestId = 0;
9
+ pendingRequests = new Map();
10
+ buffer = '';
11
+ initialized = false;
12
+ serverName;
13
+ config;
14
+ constructor(serverName, config) {
15
+ this.serverName = serverName;
16
+ this.config = config;
17
+ }
18
+ async connect() {
19
+ if (this.process)
20
+ return;
21
+ if (this.config.url) {
22
+ // HTTP/SSE transport - not implemented in lightweight version
23
+ throw new Error(`HTTP transport not yet supported for ${this.serverName}`);
24
+ }
25
+ if (!this.config.command) {
26
+ throw new Error(`No command specified for server ${this.serverName}`);
27
+ }
28
+ const env = { ...process.env, ...this.config.env };
29
+ this.process = spawn(this.config.command, this.config.args || [], {
30
+ stdio: ['pipe', 'pipe', 'pipe'],
31
+ env,
32
+ });
33
+ this.process.stdout?.on('data', (data) => {
34
+ this.handleData(data.toString());
35
+ });
36
+ this.process.stderr?.on('data', (data) => {
37
+ // Log stderr but don't fail
38
+ console.error(`[${this.serverName}] stderr:`, data.toString());
39
+ });
40
+ this.process.on('error', (err) => {
41
+ console.error(`[${this.serverName}] process error:`, err);
42
+ this.cleanup();
43
+ });
44
+ this.process.on('exit', (code) => {
45
+ if (code !== 0) {
46
+ console.error(`[${this.serverName}] exited with code ${code}`);
47
+ }
48
+ this.cleanup();
49
+ });
50
+ // Initialize MCP connection
51
+ await this.initialize();
52
+ }
53
+ handleData(data) {
54
+ this.buffer += data;
55
+ // Process complete JSON-RPC messages (newline-delimited)
56
+ const lines = this.buffer.split('\n');
57
+ this.buffer = lines.pop() || '';
58
+ for (const line of lines) {
59
+ if (!line.trim())
60
+ continue;
61
+ try {
62
+ const response = JSON.parse(line);
63
+ const pending = this.pendingRequests.get(response.id);
64
+ if (pending) {
65
+ this.pendingRequests.delete(response.id);
66
+ if (response.error) {
67
+ pending.reject(new Error(response.error.message));
68
+ }
69
+ else {
70
+ pending.resolve(response.result);
71
+ }
72
+ }
73
+ }
74
+ catch (e) {
75
+ // Ignore non-JSON lines
76
+ }
77
+ }
78
+ }
79
+ async sendRequest(method, params) {
80
+ if (!this.process?.stdin) {
81
+ throw new Error(`Not connected to ${this.serverName}`);
82
+ }
83
+ const id = ++this.requestId;
84
+ const request = {
85
+ jsonrpc: '2.0',
86
+ id,
87
+ method,
88
+ params,
89
+ };
90
+ return new Promise((resolve, reject) => {
91
+ this.pendingRequests.set(id, { resolve, reject });
92
+ const timeout = setTimeout(() => {
93
+ this.pendingRequests.delete(id);
94
+ reject(new Error(`Request timeout for ${method}`));
95
+ }, 30000);
96
+ const originalResolve = this.pendingRequests.get(id).resolve;
97
+ this.pendingRequests.get(id).resolve = (value) => {
98
+ clearTimeout(timeout);
99
+ originalResolve(value);
100
+ };
101
+ this.process.stdin.write(JSON.stringify(request) + '\n');
102
+ });
103
+ }
104
+ async initialize() {
105
+ await this.sendRequest('initialize', {
106
+ protocolVersion: '2024-11-05',
107
+ capabilities: {},
108
+ clientInfo: {
109
+ name: 'uam-mcp-router',
110
+ version: '1.0.0',
111
+ },
112
+ });
113
+ // Send initialized notification
114
+ this.process?.stdin?.write(JSON.stringify({
115
+ jsonrpc: '2.0',
116
+ method: 'notifications/initialized',
117
+ }) + '\n');
118
+ this.initialized = true;
119
+ }
120
+ async listTools() {
121
+ if (!this.initialized) {
122
+ await this.connect();
123
+ }
124
+ const result = await this.sendRequest('tools/list');
125
+ return (result.tools || []).map(tool => ({
126
+ name: tool.name,
127
+ description: tool.description || '',
128
+ inputSchema: tool.inputSchema,
129
+ serverName: this.serverName,
130
+ serverConfig: this.config,
131
+ }));
132
+ }
133
+ async callTool(toolName, args = {}) {
134
+ if (!this.initialized) {
135
+ await this.connect();
136
+ }
137
+ const result = await this.sendRequest('tools/call', {
138
+ name: toolName,
139
+ arguments: args,
140
+ });
141
+ return result;
142
+ }
143
+ cleanup() {
144
+ this.process = null;
145
+ this.initialized = false;
146
+ this.buffer = '';
147
+ // Reject all pending requests
148
+ for (const [_id, { reject }] of this.pendingRequests) {
149
+ reject(new Error('Connection closed'));
150
+ }
151
+ this.pendingRequests.clear();
152
+ }
153
+ disconnect() {
154
+ if (this.process) {
155
+ this.process.stdin?.end();
156
+ this.process.kill();
157
+ this.cleanup();
158
+ }
159
+ }
160
+ get isConnected() {
161
+ return this.process !== null && this.initialized;
162
+ }
163
+ }
164
+ // Connection pool for reusing MCP clients
165
+ export class McpClientPool {
166
+ clients = new Map();
167
+ getClient(serverName, config) {
168
+ let client = this.clients.get(serverName);
169
+ if (!client) {
170
+ client = new McpClient(serverName, config);
171
+ this.clients.set(serverName, client);
172
+ }
173
+ return client;
174
+ }
175
+ async disconnectAll() {
176
+ for (const client of this.clients.values()) {
177
+ client.disconnect();
178
+ }
179
+ this.clients.clear();
180
+ }
181
+ getConnectedServers() {
182
+ return Array.from(this.clients.entries())
183
+ .filter(([_, client]) => client.isConnected)
184
+ .map(([name]) => name);
185
+ }
186
+ }
187
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/mcp-router/executor/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * MCP Router - Lightweight Hierarchical Router for 98%+ Token Reduction
3
+ *
4
+ * Instead of exposing 150+ tools to the LLM, exposes just 2:
5
+ * - discover_tools: Find tools matching a query
6
+ * - execute_tool: Execute a tool by path
7
+ *
8
+ * This reduces context window consumption from ~75,000 tokens to ~700 tokens.
9
+ */
10
+ export { McpRouter, runStdioServer } from './server.js';
11
+ export type { RouterOptions } from './server.js';
12
+ export { loadConfigFromPaths, loadConfigFromFile, mergeConfigs } from './config/parser.js';
13
+ export { ToolSearchIndex } from './search/fuzzy.js';
14
+ export { McpClient, McpClientPool } from './executor/client.js';
15
+ export { DISCOVER_TOOLS_DEFINITION, handleDiscoverTools, estimateDiscoverToolsTokens, } from './tools/discover.js';
16
+ export { EXECUTE_TOOL_DEFINITION, handleExecuteTool, estimateExecuteToolTokens, } from './tools/execute.js';
17
+ export type { McpConfig, McpServerConfig, ToolDefinition, ToolSearchResult, DiscoverToolsArgs, ExecuteToolArgs, ToolRegistry, RouterStats, } from './types.js';
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp-router/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC3F,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,SAAS,EACT,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,WAAW,GACZ,MAAM,YAAY,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * MCP Router - Lightweight Hierarchical Router for 98%+ Token Reduction
3
+ *
4
+ * Instead of exposing 150+ tools to the LLM, exposes just 2:
5
+ * - discover_tools: Find tools matching a query
6
+ * - execute_tool: Execute a tool by path
7
+ *
8
+ * This reduces context window consumption from ~75,000 tokens to ~700 tokens.
9
+ */
10
+ export { McpRouter, runStdioServer } from './server.js';
11
+ export { loadConfigFromPaths, loadConfigFromFile, mergeConfigs } from './config/parser.js';
12
+ export { ToolSearchIndex } from './search/fuzzy.js';
13
+ export { McpClient, McpClientPool } from './executor/client.js';
14
+ export { DISCOVER_TOOLS_DEFINITION, handleDiscoverTools, estimateDiscoverToolsTokens, } from './tools/discover.js';
15
+ export { EXECUTE_TOOL_DEFINITION, handleExecuteTool, estimateExecuteToolTokens, } from './tools/execute.js';
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp-router/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC3F,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Fuzzy Search for MCP Tools
3
+ * Uses Fuse.js for semantic-like matching
4
+ */
5
+ import type { ToolDefinition, ToolSearchResult } from '../types.js';
6
+ interface FuzzyOptions {
7
+ threshold?: number;
8
+ keys?: string[];
9
+ }
10
+ export declare class ToolSearchIndex {
11
+ private tools;
12
+ private options;
13
+ constructor(options?: FuzzyOptions);
14
+ addTools(tools: ToolDefinition[]): void;
15
+ clear(): void;
16
+ search(query: string, limit?: number): ToolSearchResult[];
17
+ searchByServer(serverName: string, limit?: number): ToolSearchResult[];
18
+ getAllTools(): ToolDefinition[];
19
+ getToolByPath(path: string): ToolDefinition | undefined;
20
+ getStats(): {
21
+ servers: number;
22
+ tools: number;
23
+ };
24
+ }
25
+ export {};
26
+ //# sourceMappingURL=fuzzy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzzy.d.ts","sourceRoot":"","sources":["../../../src/mcp-router/search/fuzzy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAKpE,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AA+BD,qBAAa,eAAe;IAC1B,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,OAAO,CAAe;gBAElB,OAAO,GAAE,YAAiB;IAOtC,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,IAAI;IAIvC,KAAK,IAAI,IAAI;IAIb,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,gBAAgB,EAAE;IA4BrD,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,gBAAgB,EAAE;IAalE,WAAW,IAAI,cAAc,EAAE;IAI/B,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAKvD,QAAQ,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;CAO/C"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Fuzzy Search for MCP Tools
3
+ * Uses Fuse.js for semantic-like matching
4
+ */
5
+ function tokenize(str) {
6
+ return str.toLowerCase().split(/[\s_\-./]+/).filter(Boolean);
7
+ }
8
+ function calculateScore(query, target) {
9
+ const queryTokens = tokenize(query);
10
+ const targetTokens = tokenize(target);
11
+ if (queryTokens.length === 0 || targetTokens.length === 0)
12
+ return 0;
13
+ let matchCount = 0;
14
+ let partialMatches = 0;
15
+ for (const qToken of queryTokens) {
16
+ for (const tToken of targetTokens) {
17
+ if (tToken === qToken) {
18
+ matchCount++;
19
+ break;
20
+ }
21
+ else if (tToken.includes(qToken) || qToken.includes(tToken)) {
22
+ partialMatches += 0.5;
23
+ break;
24
+ }
25
+ }
26
+ }
27
+ const totalMatches = matchCount + partialMatches;
28
+ return totalMatches / queryTokens.length;
29
+ }
30
+ export class ToolSearchIndex {
31
+ tools = [];
32
+ options;
33
+ constructor(options = {}) {
34
+ this.options = {
35
+ threshold: options.threshold ?? 0.3,
36
+ keys: options.keys ?? ['name', 'description'],
37
+ };
38
+ }
39
+ addTools(tools) {
40
+ this.tools.push(...tools);
41
+ }
42
+ clear() {
43
+ this.tools = [];
44
+ }
45
+ search(query, limit = 10) {
46
+ const results = [];
47
+ for (const tool of this.tools) {
48
+ // Calculate score across all searchable fields
49
+ const nameScore = calculateScore(query, tool.name) * 1.5; // Weight name higher
50
+ const descScore = calculateScore(query, tool.description);
51
+ const serverScore = calculateScore(query, tool.serverName) * 0.5;
52
+ const score = Math.max(nameScore, descScore, serverScore);
53
+ if (score >= this.options.threshold) {
54
+ results.push({ tool, score });
55
+ }
56
+ }
57
+ // Sort by score descending
58
+ results.sort((a, b) => b.score - a.score);
59
+ return results.slice(0, limit).map(({ tool, score }) => ({
60
+ path: `${tool.serverName}.${tool.name}`,
61
+ name: tool.name,
62
+ description: tool.description,
63
+ server: tool.serverName,
64
+ score: Math.round(score * 100) / 100,
65
+ }));
66
+ }
67
+ searchByServer(serverName, limit = 50) {
68
+ return this.tools
69
+ .filter(t => t.serverName === serverName)
70
+ .slice(0, limit)
71
+ .map(tool => ({
72
+ path: `${tool.serverName}.${tool.name}`,
73
+ name: tool.name,
74
+ description: tool.description,
75
+ server: tool.serverName,
76
+ score: 1.0,
77
+ }));
78
+ }
79
+ getAllTools() {
80
+ return [...this.tools];
81
+ }
82
+ getToolByPath(path) {
83
+ const [serverName, toolName] = path.split('.');
84
+ return this.tools.find(t => t.serverName === serverName && t.name === toolName);
85
+ }
86
+ getStats() {
87
+ const servers = new Set(this.tools.map(t => t.serverName));
88
+ return {
89
+ servers: servers.size,
90
+ tools: this.tools.length,
91
+ };
92
+ }
93
+ }
94
+ //# sourceMappingURL=fuzzy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzzy.js","sourceRoot":"","sources":["../../../src/mcp-router/search/fuzzy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * MCP Router Server
3
+ * Exposes 2 meta-tools: discover_tools and execute_tool
4
+ * Achieves 98%+ token reduction by hiding individual tool definitions
5
+ */
6
+ import { DISCOVER_TOOLS_DEFINITION } from './tools/discover.js';
7
+ import { EXECUTE_TOOL_DEFINITION } from './tools/execute.js';
8
+ import type { McpConfig, RouterStats } from './types.js';
9
+ export interface RouterOptions {
10
+ configPath?: string;
11
+ autoDiscover?: boolean;
12
+ verbose?: boolean;
13
+ }
14
+ export declare class McpRouter {
15
+ private config;
16
+ private searchIndex;
17
+ private clientPool;
18
+ private options;
19
+ private toolsLoaded;
20
+ constructor(options?: RouterOptions);
21
+ /**
22
+ * Load tools from all configured MCP servers
23
+ */
24
+ loadTools(): Promise<void>;
25
+ /**
26
+ * Get the 2 meta-tool definitions (for MCP tools/list)
27
+ */
28
+ getToolDefinitions(): Array<typeof DISCOVER_TOOLS_DEFINITION | typeof EXECUTE_TOOL_DEFINITION>;
29
+ /**
30
+ * Handle tool call
31
+ */
32
+ handleToolCall(name: string, args: unknown): Promise<unknown>;
33
+ /**
34
+ * Get router statistics
35
+ */
36
+ getStats(): RouterStats;
37
+ /**
38
+ * Shutdown - cleanup all connections
39
+ */
40
+ shutdown(): Promise<void>;
41
+ /**
42
+ * Get loaded config
43
+ */
44
+ getConfig(): McpConfig;
45
+ }
46
+ /**
47
+ * Run as stdio MCP server
48
+ */
49
+ export declare function runStdioServer(options?: RouterOptions): Promise<void>;
50
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp-router/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EACL,yBAAyB,EAG1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,uBAAuB,EAGxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAkB,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,GAAE,aAAkB;IAkBvC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAuChC;;OAEG;IACH,kBAAkB,IAAI,KAAK,CAAC,OAAO,yBAAyB,GAAG,OAAO,uBAAuB,CAAC;IAI9F;;OAEG;IACG,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAsBnE;;OAEG;IACH,QAAQ,IAAI,WAAW;IAsBvB;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B;;OAEG;IACH,SAAS,IAAI,SAAS;CAGvB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsH/E"}
@@ -0,0 +1,229 @@
1
+ /**
2
+ * MCP Router Server
3
+ * Exposes 2 meta-tools: discover_tools and execute_tool
4
+ * Achieves 98%+ token reduction by hiding individual tool definitions
5
+ */
6
+ import { loadConfigFromPaths, loadConfigFromFile } from './config/parser.js';
7
+ import { ToolSearchIndex } from './search/fuzzy.js';
8
+ import { McpClient, McpClientPool } from './executor/client.js';
9
+ import { DISCOVER_TOOLS_DEFINITION, handleDiscoverTools, estimateDiscoverToolsTokens, } from './tools/discover.js';
10
+ import { EXECUTE_TOOL_DEFINITION, handleExecuteTool, estimateExecuteToolTokens, } from './tools/execute.js';
11
+ export class McpRouter {
12
+ config;
13
+ searchIndex;
14
+ clientPool;
15
+ options;
16
+ toolsLoaded = false;
17
+ constructor(options = {}) {
18
+ this.options = {
19
+ autoDiscover: true,
20
+ verbose: false,
21
+ ...options,
22
+ };
23
+ // Load config
24
+ if (options.configPath) {
25
+ this.config = loadConfigFromFile(options.configPath);
26
+ }
27
+ else {
28
+ this.config = loadConfigFromPaths();
29
+ }
30
+ this.searchIndex = new ToolSearchIndex({ threshold: 0.2 });
31
+ this.clientPool = new McpClientPool();
32
+ }
33
+ /**
34
+ * Load tools from all configured MCP servers
35
+ */
36
+ async loadTools() {
37
+ if (this.toolsLoaded)
38
+ return;
39
+ const servers = Object.entries(this.config.mcpServers);
40
+ if (this.options.verbose) {
41
+ console.error(`[router] Loading tools from ${servers.length} servers...`);
42
+ }
43
+ const allTools = [];
44
+ for (const [serverName, serverConfig] of servers) {
45
+ try {
46
+ const client = new McpClient(serverName, serverConfig);
47
+ await client.connect();
48
+ const tools = await client.listTools();
49
+ allTools.push(...tools);
50
+ client.disconnect();
51
+ if (this.options.verbose) {
52
+ console.error(`[router] ${serverName}: ${tools.length} tools`);
53
+ }
54
+ }
55
+ catch (error) {
56
+ if (this.options.verbose) {
57
+ console.error(`[router] ${serverName}: failed to load - ${error}`);
58
+ }
59
+ }
60
+ }
61
+ this.searchIndex.clear();
62
+ this.searchIndex.addTools(allTools);
63
+ this.toolsLoaded = true;
64
+ if (this.options.verbose) {
65
+ const stats = this.searchIndex.getStats();
66
+ console.error(`[router] Loaded ${stats.tools} tools from ${stats.servers} servers`);
67
+ }
68
+ }
69
+ /**
70
+ * Get the 2 meta-tool definitions (for MCP tools/list)
71
+ */
72
+ getToolDefinitions() {
73
+ return [DISCOVER_TOOLS_DEFINITION, EXECUTE_TOOL_DEFINITION];
74
+ }
75
+ /**
76
+ * Handle tool call
77
+ */
78
+ async handleToolCall(name, args) {
79
+ // Ensure tools are loaded
80
+ if (!this.toolsLoaded && this.options.autoDiscover) {
81
+ await this.loadTools();
82
+ }
83
+ switch (name) {
84
+ case 'discover_tools':
85
+ return handleDiscoverTools(args, this.searchIndex);
86
+ case 'execute_tool':
87
+ return handleExecuteTool(args, this.searchIndex, this.clientPool);
88
+ default:
89
+ throw new Error(`Unknown tool: ${name}`);
90
+ }
91
+ }
92
+ /**
93
+ * Get router statistics
94
+ */
95
+ getStats() {
96
+ const { servers, tools } = this.searchIndex.getStats();
97
+ // Estimate traditional token usage: ~500 tokens per tool
98
+ const traditionalTokens = tools * 500;
99
+ // Router uses only 2 tools
100
+ const routerTokens = estimateDiscoverToolsTokens() + estimateExecuteToolTokens();
101
+ const savings = traditionalTokens > 0
102
+ ? ((traditionalTokens - routerTokens) / traditionalTokens * 100).toFixed(1) + '%'
103
+ : '0%';
104
+ return {
105
+ totalServers: servers,
106
+ totalTools: tools,
107
+ traditionalTokens,
108
+ routerTokens,
109
+ savings,
110
+ };
111
+ }
112
+ /**
113
+ * Shutdown - cleanup all connections
114
+ */
115
+ async shutdown() {
116
+ await this.clientPool.disconnectAll();
117
+ }
118
+ /**
119
+ * Get loaded config
120
+ */
121
+ getConfig() {
122
+ return this.config;
123
+ }
124
+ }
125
+ /**
126
+ * Run as stdio MCP server
127
+ */
128
+ export async function runStdioServer(options = {}) {
129
+ const router = new McpRouter({ ...options, verbose: true });
130
+ let buffer = '';
131
+ function send(message) {
132
+ process.stdout.write(JSON.stringify(message) + '\n');
133
+ }
134
+ function handleMessage(message) {
135
+ const { id, method, params } = message;
136
+ switch (method) {
137
+ case 'initialize':
138
+ send({
139
+ jsonrpc: '2.0',
140
+ id,
141
+ result: {
142
+ protocolVersion: '2024-11-05',
143
+ capabilities: {
144
+ tools: {},
145
+ },
146
+ serverInfo: {
147
+ name: 'uam-mcp-router',
148
+ version: '1.0.0',
149
+ },
150
+ },
151
+ });
152
+ break;
153
+ case 'notifications/initialized':
154
+ // No response needed
155
+ break;
156
+ case 'tools/list':
157
+ send({
158
+ jsonrpc: '2.0',
159
+ id,
160
+ result: {
161
+ tools: router.getToolDefinitions(),
162
+ },
163
+ });
164
+ break;
165
+ case 'tools/call': {
166
+ const { name, arguments: args } = params;
167
+ router.handleToolCall(name, args)
168
+ .then(result => {
169
+ send({
170
+ jsonrpc: '2.0',
171
+ id,
172
+ result: {
173
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
174
+ },
175
+ });
176
+ })
177
+ .catch(error => {
178
+ send({
179
+ jsonrpc: '2.0',
180
+ id,
181
+ error: {
182
+ code: -32000,
183
+ message: error instanceof Error ? error.message : String(error),
184
+ },
185
+ });
186
+ });
187
+ break;
188
+ }
189
+ default:
190
+ if (id !== undefined) {
191
+ send({
192
+ jsonrpc: '2.0',
193
+ id,
194
+ error: {
195
+ code: -32601,
196
+ message: `Method not found: ${method}`,
197
+ },
198
+ });
199
+ }
200
+ }
201
+ }
202
+ process.stdin.on('data', (data) => {
203
+ buffer += data.toString();
204
+ const lines = buffer.split('\n');
205
+ buffer = lines.pop() || '';
206
+ for (const line of lines) {
207
+ if (!line.trim())
208
+ continue;
209
+ try {
210
+ const message = JSON.parse(line);
211
+ handleMessage(message);
212
+ }
213
+ catch (e) {
214
+ console.error('[router] Invalid JSON:', e);
215
+ }
216
+ }
217
+ });
218
+ process.stdin.on('end', async () => {
219
+ await router.shutdown();
220
+ process.exit(0);
221
+ });
222
+ process.on('SIGINT', async () => {
223
+ await router.shutdown();
224
+ process.exit(0);
225
+ });
226
+ console.error('[router] MCP Router server started (stdio)');
227
+ console.error('[router] Exposing 2 tools: discover_tools, execute_tool');
228
+ }
229
+ //# sourceMappingURL=server.js.map