@loop_ouroboros/mcp-hub-lite 1.2.4 → 1.2.6
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/CHANGELOG.md +33 -0
- package/dist/server/src/api/web/hub-tools.d.ts.map +1 -1
- package/dist/server/src/api/web/hub-tools.js +15 -0
- package/dist/server/src/api/web/mcp-status.d.ts.map +1 -1
- package/dist/server/src/api/web/mcp-status.js +4 -0
- package/dist/server/src/cli/commands/status.js +13 -3
- package/dist/server/src/cli/commands/tool-use.d.ts +5 -1
- package/dist/server/src/cli/commands/tool-use.d.ts.map +1 -1
- package/dist/server/src/cli/commands/tool-use.js +27 -4
- package/dist/server/src/cli/server.d.ts +2 -0
- package/dist/server/src/cli/server.d.ts.map +1 -1
- package/dist/server/src/cli/server.js +2 -0
- package/dist/server/src/models/system-tools.constants.d.ts +6 -2
- package/dist/server/src/models/system-tools.constants.d.ts.map +1 -1
- package/dist/server/src/models/system-tools.constants.js +3 -1
- package/dist/server/src/services/connection/connection-manager.d.ts +6 -0
- package/dist/server/src/services/connection/connection-manager.d.ts.map +1 -1
- package/dist/server/src/services/connection/connection-manager.js +23 -0
- package/dist/server/src/services/gateway/request-handlers/system-tools-handler.d.ts.map +1 -1
- package/dist/server/src/services/gateway/request-handlers/system-tools-handler.js +28 -1
- package/dist/server/src/services/gateway/tool-list-generator.js +1 -1
- package/dist/server/src/services/hub-tools/instance-selector.d.ts +8 -1
- package/dist/server/src/services/hub-tools/instance-selector.d.ts.map +1 -1
- package/dist/server/src/services/hub-tools/instance-selector.js +24 -10
- package/dist/server/src/services/hub-tools/resource-generator.d.ts.map +1 -1
- package/dist/server/src/services/hub-tools/resource-generator.js +17 -13
- package/dist/server/src/services/hub-tools/server-selector.d.ts +2 -2
- package/dist/server/src/services/hub-tools/server-selector.d.ts.map +1 -1
- package/dist/server/src/services/hub-tools/server-selector.js +4 -3
- package/dist/server/src/services/hub-tools/system-tool-definitions.d.ts.map +1 -1
- package/dist/server/src/services/hub-tools/system-tool-definitions.js +23 -3
- package/dist/server/src/services/hub-tools.service.d.ts +29 -7
- package/dist/server/src/services/hub-tools.service.d.ts.map +1 -1
- package/dist/server/src/services/hub-tools.service.js +96 -36
- package/dist/server/src/services/system-tool-handler.d.ts.map +1 -1
- package/dist/server/src/services/system-tool-handler.js +21 -8
- package/dist/server/src/utils/name-converter.d.ts.map +1 -1
- package/dist/server/src/utils/name-converter.js +2 -0
- package/dist/server/tests/unit/services/hub-tools/instance-selector.test.js +21 -16
- package/dist/server/tests/unit/services/hub-tools.service.test.js +42 -40
- package/package.json +1 -1
|
@@ -3,14 +3,15 @@ import { InstanceSelector, TagMatchUniqueError } from './instance-selector.js';
|
|
|
3
3
|
import { logger } from '../../utils/logger.js';
|
|
4
4
|
import { LOG_MODULES } from '../../utils/logger/log-modules.js';
|
|
5
5
|
/**
|
|
6
|
-
* Gets the description for a server, using
|
|
6
|
+
* Gets the description for a server, using the server name as default if none is provided.
|
|
7
7
|
*
|
|
8
8
|
* @param serverConfig - Server configuration object (may contain description in template)
|
|
9
9
|
* @param serverName - Name of the server
|
|
10
|
-
* @returns The server description or
|
|
10
|
+
* @returns The server description or the server name with usage note if no description is configured
|
|
11
11
|
*/
|
|
12
12
|
export function getServerDescription(serverConfig, serverName) {
|
|
13
|
-
return serverConfig?.template?.description ||
|
|
13
|
+
return (serverConfig?.template?.description ||
|
|
14
|
+
`${serverName} (You can check the tool list to understand its capabilities and update the description.)`);
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
17
|
* Type guard to validate that a server object has valid name and configuration.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-tool-definitions.d.ts","sourceRoot":"","sources":["../../../../../src/services/hub-tools/system-tool-definitions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"system-tool-definitions.d.ts","sourceRoot":"","sources":["../../../../../src/services/hub-tools/system-tool-definitions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAW/D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,IAAI,oBAAoB,EAAE,CAiKvD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SYSTEM_TOOL_NAMES, LIST_SERVERS_TOOL, LIST_TOOLS_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL } from '../../models/system-tools.constants.js';
|
|
1
|
+
import { SYSTEM_TOOL_NAMES, LIST_SERVERS_TOOL, LIST_TOOLS_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL, LIST_TAGS_TOOL } from '../../models/system-tools.constants.js';
|
|
2
2
|
/**
|
|
3
3
|
* Retrieves the complete list of system tools provided by this service.
|
|
4
4
|
*
|
|
@@ -91,7 +91,7 @@ export function getSystemTools() {
|
|
|
91
91
|
required: ['serverName', 'toolName']
|
|
92
92
|
},
|
|
93
93
|
annotations: {
|
|
94
|
-
title: 'Get Tool
|
|
94
|
+
title: 'Get Tool Schema',
|
|
95
95
|
readOnlyHint: true,
|
|
96
96
|
destructiveHint: false,
|
|
97
97
|
idempotentHint: true,
|
|
@@ -103,7 +103,7 @@ export function getSystemTools() {
|
|
|
103
103
|
systemTools.push({
|
|
104
104
|
name: toolName,
|
|
105
105
|
description: 'Call a specific tool from an external MCP server. ' +
|
|
106
|
-
'System tools (list_servers, list_tools, get_tool, update_server_description) ' +
|
|
106
|
+
'System tools (list_servers, list_tools, get_tool, list_tags, update_server_description) ' +
|
|
107
107
|
'must be called directly via tools/call, not through this tool.',
|
|
108
108
|
inputSchema: {
|
|
109
109
|
type: 'object',
|
|
@@ -154,6 +154,26 @@ export function getSystemTools() {
|
|
|
154
154
|
}
|
|
155
155
|
});
|
|
156
156
|
break;
|
|
157
|
+
case LIST_TAGS_TOOL:
|
|
158
|
+
systemTools.push({
|
|
159
|
+
name: toolName,
|
|
160
|
+
description: 'List all instance tags for a specific MCP server',
|
|
161
|
+
inputSchema: {
|
|
162
|
+
type: 'object',
|
|
163
|
+
properties: {
|
|
164
|
+
serverName: { type: 'string', description: 'Name of the MCP server' }
|
|
165
|
+
},
|
|
166
|
+
required: ['serverName']
|
|
167
|
+
},
|
|
168
|
+
annotations: {
|
|
169
|
+
title: 'List Instance Tags',
|
|
170
|
+
readOnlyHint: true,
|
|
171
|
+
destructiveHint: false,
|
|
172
|
+
idempotentHint: true,
|
|
173
|
+
openWorldHint: false
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
break;
|
|
157
177
|
default:
|
|
158
178
|
// This should never happen due to TypeScript type checking
|
|
159
179
|
throw new Error(`Unknown system tool: ${toolName}`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Tool, ToolSummary } from '../../shared/models/tool.model.js';
|
|
2
2
|
import type { Resource } from '../../shared/models/resource.model.js';
|
|
3
|
-
import { LIST_SERVERS_TOOL, LIST_TOOLS_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL } from '../models/system-tools.constants.js';
|
|
4
|
-
import type { SystemToolName, ListServersParams, ListToolsInServerParams, GetToolParams, CallToolParams, UpdateServerDescriptionParams } from '../models/system-tools.constants.js';
|
|
3
|
+
import { LIST_SERVERS_TOOL, LIST_TOOLS_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL, LIST_TAGS_TOOL } from '../models/system-tools.constants.js';
|
|
4
|
+
import type { SystemToolName, ListServersParams, ListToolsInServerParams, GetToolParams, CallToolParams, UpdateServerDescriptionParams, ListTagsParams } from '../models/system-tools.constants.js';
|
|
5
5
|
/**
|
|
6
6
|
* Central service for managing system tools and MCP server interactions in the MCP Hub Lite gateway.
|
|
7
7
|
*
|
|
@@ -51,10 +51,6 @@ import type { SystemToolName, ListServersParams, ListToolsInServerParams, GetToo
|
|
|
51
51
|
* ```
|
|
52
52
|
*/
|
|
53
53
|
export declare class HubToolsService {
|
|
54
|
-
/**
|
|
55
|
-
* Cached dynamic resource list to avoid regenerating on every request
|
|
56
|
-
*/
|
|
57
|
-
private generatedResourcesCache;
|
|
58
54
|
constructor();
|
|
59
55
|
/**
|
|
60
56
|
* Retrieves the complete list of system tools provided by this service.
|
|
@@ -122,6 +118,25 @@ export declare class HubToolsService {
|
|
|
122
118
|
serverName: string;
|
|
123
119
|
description: string;
|
|
124
120
|
}>;
|
|
121
|
+
/**
|
|
122
|
+
* Lists all instance tags for a specific MCP server.
|
|
123
|
+
*
|
|
124
|
+
* This method retrieves all instances of the specified server and returns their tags,
|
|
125
|
+
* useful for understanding which instances are available and how to select them
|
|
126
|
+
* when using tag-match-unique instance selection strategy.
|
|
127
|
+
*
|
|
128
|
+
* @param {ListTagsParams} args - Server name
|
|
129
|
+
* @returns {Promise<{ serverName: string; instances: Array<{ index: number; id: string; tags: Record<string, string> }> }>} Instance tags information
|
|
130
|
+
* @throws {Error} If the specified server is not found
|
|
131
|
+
*/
|
|
132
|
+
listTags(args: ListTagsParams): Promise<{
|
|
133
|
+
serverName: string;
|
|
134
|
+
instances: Array<{
|
|
135
|
+
index: number;
|
|
136
|
+
id: string;
|
|
137
|
+
tags: Record<string, string>;
|
|
138
|
+
}>;
|
|
139
|
+
}>;
|
|
125
140
|
/**
|
|
126
141
|
* Calls a specific system tool directly with type-safe conditional return types.
|
|
127
142
|
*
|
|
@@ -134,13 +149,20 @@ export declare class HubToolsService {
|
|
|
134
149
|
* @returns {Promise<ConditionalReturnType>} Tool execution result with accurate type safety matching actual method return types
|
|
135
150
|
* @throws {Error} If the system tool is not found or execution fails
|
|
136
151
|
*/
|
|
137
|
-
callSystemTool<T extends SystemToolName>(toolName: T, toolArgs: T extends typeof LIST_SERVERS_TOOL ? ListServersParams : T extends typeof LIST_TOOLS_TOOL ? ListToolsInServerParams : T extends typeof GET_TOOL_TOOL ? GetToolParams : T extends typeof CALL_TOOL_TOOL ? CallToolParams : T extends typeof UPDATE_SERVER_DESCRIPTION_TOOL ? UpdateServerDescriptionParams : never): Promise<T extends typeof LIST_SERVERS_TOOL ? Record<string, string> : T extends typeof LIST_TOOLS_TOOL ? {
|
|
152
|
+
callSystemTool<T extends SystemToolName>(toolName: T, toolArgs: T extends typeof LIST_SERVERS_TOOL ? ListServersParams : T extends typeof LIST_TOOLS_TOOL ? ListToolsInServerParams : T extends typeof GET_TOOL_TOOL ? GetToolParams : T extends typeof CALL_TOOL_TOOL ? CallToolParams : T extends typeof UPDATE_SERVER_DESCRIPTION_TOOL ? UpdateServerDescriptionParams : T extends typeof LIST_TAGS_TOOL ? ListTagsParams : never): Promise<T extends typeof LIST_SERVERS_TOOL ? Record<string, string> : T extends typeof LIST_TOOLS_TOOL ? {
|
|
138
153
|
serverName: string;
|
|
139
154
|
tools: ToolSummary[];
|
|
140
155
|
} : T extends typeof GET_TOOL_TOOL ? Tool | undefined : T extends typeof CALL_TOOL_TOOL ? unknown : T extends typeof UPDATE_SERVER_DESCRIPTION_TOOL ? {
|
|
141
156
|
success: boolean;
|
|
142
157
|
serverName: string;
|
|
143
158
|
description: string;
|
|
159
|
+
} : T extends typeof LIST_TAGS_TOOL ? {
|
|
160
|
+
serverName: string;
|
|
161
|
+
instances: Array<{
|
|
162
|
+
index: number;
|
|
163
|
+
id: string;
|
|
164
|
+
tags: Record<string, string>;
|
|
165
|
+
}>;
|
|
144
166
|
} : never>;
|
|
145
167
|
/**
|
|
146
168
|
* Calls a specific tool from a specific MCP server with comprehensive event tracking.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hub-tools.service.d.ts","sourceRoot":"","sources":["../../../../src/services/hub-tools.service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAOjE,OAAO,EAEL,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,cAAc,EACd,8BAA8B,
|
|
1
|
+
{"version":3,"file":"hub-tools.service.d.ts","sourceRoot":"","sources":["../../../../src/services/hub-tools.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,9 +6,11 @@ import { logger, LOG_MODULES } from '../utils/logger.js';
|
|
|
6
6
|
import { stringifyForLogging } from '../utils/json-utils.js';
|
|
7
7
|
import { normalizeToolName } from '../utils/name-converter.js';
|
|
8
8
|
import { McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
-
import { MCP_HUB_LITE_SERVER, LIST_SERVERS_TOOL, LIST_TOOLS_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL, SYSTEM_TOOL_NAMES } from '../models/system-tools.constants.js';
|
|
9
|
+
import { MCP_HUB_LITE_SERVER, LIST_SERVERS_TOOL, LIST_TOOLS_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL, LIST_TAGS_TOOL, SYSTEM_TOOL_NAMES } from '../models/system-tools.constants.js';
|
|
10
10
|
import { ToolArgsParser } from '../utils/tool-args-parser.js';
|
|
11
11
|
import { hasValidId, selectBestInstance, getServerDescription, getSystemTools, generateDynamicResources, readResource as readResourceUtil } from './hub-tools/index.js';
|
|
12
|
+
import { InstanceSelector } from './hub-tools/instance-selector.js';
|
|
13
|
+
import { InstanceSelectionStrategy } from '../models/server.model.js';
|
|
12
14
|
/**
|
|
13
15
|
* Central service for managing system tools and MCP server interactions in the MCP Hub Lite gateway.
|
|
14
16
|
*
|
|
@@ -58,27 +60,9 @@ import { hasValidId, selectBestInstance, getServerDescription, getSystemTools, g
|
|
|
58
60
|
* ```
|
|
59
61
|
*/
|
|
60
62
|
export class HubToolsService {
|
|
61
|
-
|
|
62
|
-
* Cached dynamic resource list to avoid regenerating on every request
|
|
63
|
-
*/
|
|
64
|
-
generatedResourcesCache = null;
|
|
63
|
+
// Cache removed - listResources() now calls generateDynamicResources() directly
|
|
65
64
|
constructor() {
|
|
66
|
-
//
|
|
67
|
-
eventBus.subscribe(EventTypes.SERVER_STATUS_CHANGE, () => {
|
|
68
|
-
this.generatedResourcesCache = null;
|
|
69
|
-
});
|
|
70
|
-
eventBus.subscribe(EventTypes.SERVER_CONNECTED, () => {
|
|
71
|
-
this.generatedResourcesCache = null;
|
|
72
|
-
});
|
|
73
|
-
eventBus.subscribe(EventTypes.SERVER_DISCONNECTED, () => {
|
|
74
|
-
this.generatedResourcesCache = null;
|
|
75
|
-
});
|
|
76
|
-
eventBus.subscribe(EventTypes.RESOURCES_UPDATED, () => {
|
|
77
|
-
this.generatedResourcesCache = null;
|
|
78
|
-
});
|
|
79
|
-
eventBus.subscribe(EventTypes.TOOLS_UPDATED, () => {
|
|
80
|
-
this.generatedResourcesCache = null;
|
|
81
|
-
});
|
|
65
|
+
// No cache-related initialization needed
|
|
82
66
|
}
|
|
83
67
|
/**
|
|
84
68
|
* Retrieves the complete list of system tools provided by this service.
|
|
@@ -107,9 +91,9 @@ export class HubToolsService {
|
|
|
107
91
|
const servers = hubManager.getAllServers();
|
|
108
92
|
const result = {};
|
|
109
93
|
for (const server of servers.filter(hasValidId)) {
|
|
110
|
-
//
|
|
111
|
-
const
|
|
112
|
-
if (
|
|
94
|
+
// Use getConnectedIndexes for reliable multi-instance support
|
|
95
|
+
const indexes = mcpConnectionManager.getConnectedIndexes(server.name);
|
|
96
|
+
if (indexes.length === 0) {
|
|
113
97
|
continue;
|
|
114
98
|
}
|
|
115
99
|
// Use non-strict mode for management operations to avoid tag-match-unique errors
|
|
@@ -136,6 +120,9 @@ export class HubToolsService {
|
|
|
136
120
|
* @throws {Error} If the specified server is not found or not connected
|
|
137
121
|
*/
|
|
138
122
|
async listToolsInServer(args) {
|
|
123
|
+
if (!args.serverName) {
|
|
124
|
+
throw new Error('serverName is required');
|
|
125
|
+
}
|
|
139
126
|
// Handle MCP Hub Lite server (return system tools list)
|
|
140
127
|
if (typeof args.serverName === 'string' && args.serverName === MCP_HUB_LITE_SERVER) {
|
|
141
128
|
// Generate tool list using the same logic as tools/list
|
|
@@ -152,6 +139,11 @@ export class HubToolsService {
|
|
|
152
139
|
tools: toolSummaries
|
|
153
140
|
};
|
|
154
141
|
}
|
|
142
|
+
// Check if server has any connected instances before trying to get tools
|
|
143
|
+
const indexes = mcpConnectionManager.getConnectedIndexes(args.serverName);
|
|
144
|
+
if (indexes.length === 0) {
|
|
145
|
+
throw new Error(`Server not found: ${args.serverName}`);
|
|
146
|
+
}
|
|
155
147
|
// Use server name level cache to get tools directly without triggering instance selection
|
|
156
148
|
// This avoids tag-match-unique errors for multi-instance servers when listing tools
|
|
157
149
|
const tools = mcpConnectionManager.getToolsByServerName(args.serverName);
|
|
@@ -193,6 +185,11 @@ export class HubToolsService {
|
|
|
193
185
|
}
|
|
194
186
|
return undefined;
|
|
195
187
|
}
|
|
188
|
+
// Check if server has any connected instances before trying to get tools
|
|
189
|
+
const indexes = mcpConnectionManager.getConnectedIndexes(args.serverName);
|
|
190
|
+
if (indexes.length === 0) {
|
|
191
|
+
throw new Error(`Server not found: ${args.serverName}`);
|
|
192
|
+
}
|
|
196
193
|
// Use server name level cache to get tools directly without triggering instance selection
|
|
197
194
|
// This avoids tag-match-unique errors for multi-instance servers when getting tool details
|
|
198
195
|
const tools = mcpConnectionManager.getToolsByServerName(args.serverName);
|
|
@@ -237,6 +234,33 @@ export class HubToolsService {
|
|
|
237
234
|
description
|
|
238
235
|
};
|
|
239
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Lists all instance tags for a specific MCP server.
|
|
239
|
+
*
|
|
240
|
+
* This method retrieves all instances of the specified server and returns their tags,
|
|
241
|
+
* useful for understanding which instances are available and how to select them
|
|
242
|
+
* when using tag-match-unique instance selection strategy.
|
|
243
|
+
*
|
|
244
|
+
* @param {ListTagsParams} args - Server name
|
|
245
|
+
* @returns {Promise<{ serverName: string; instances: Array<{ index: number; id: string; tags: Record<string, string> }> }>} Instance tags information
|
|
246
|
+
* @throws {Error} If the specified server is not found
|
|
247
|
+
*/
|
|
248
|
+
async listTags(args) {
|
|
249
|
+
const serverConfig = hubManager.getServerByName(args.serverName);
|
|
250
|
+
if (!serverConfig) {
|
|
251
|
+
throw new Error(`Server not found: ${args.serverName}`);
|
|
252
|
+
}
|
|
253
|
+
const instances = hubManager.getServerInstancesByName(args.serverName);
|
|
254
|
+
const instanceTags = instances.map((instance) => ({
|
|
255
|
+
index: instance.index ?? 0,
|
|
256
|
+
id: instance.id || '',
|
|
257
|
+
tags: instance.tags || {}
|
|
258
|
+
}));
|
|
259
|
+
return {
|
|
260
|
+
serverName: args.serverName,
|
|
261
|
+
instances: instanceTags
|
|
262
|
+
};
|
|
263
|
+
}
|
|
240
264
|
/**
|
|
241
265
|
* Calls a specific system tool directly with type-safe conditional return types.
|
|
242
266
|
*
|
|
@@ -281,6 +305,10 @@ export class HubToolsService {
|
|
|
281
305
|
result = await this.updateServerDescription(toolArgs);
|
|
282
306
|
break;
|
|
283
307
|
}
|
|
308
|
+
case LIST_TAGS_TOOL: {
|
|
309
|
+
result = await this.listTags(toolArgs);
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
284
312
|
default:
|
|
285
313
|
throw new Error(`System tool "${toolName}" not found`);
|
|
286
314
|
}
|
|
@@ -317,14 +345,17 @@ export class HubToolsService {
|
|
|
317
345
|
serverName = parsedTool.serverName;
|
|
318
346
|
toolName = parsedTool.toolName;
|
|
319
347
|
}
|
|
320
|
-
//
|
|
321
|
-
if (!serverName
|
|
322
|
-
serverName
|
|
348
|
+
// Validate serverName is required
|
|
349
|
+
if (!serverName) {
|
|
350
|
+
throw new Error('serverName is required');
|
|
323
351
|
}
|
|
352
|
+
// Handle MCP Hub Lite server (system tool call or find tool in all servers)
|
|
324
353
|
if (typeof serverName === 'string' && serverName === MCP_HUB_LITE_SERVER) {
|
|
325
|
-
// System tools cannot be called via call_tool - they must be called directly
|
|
354
|
+
// System tools (except call_tool) cannot be called via call_tool - they must be called directly
|
|
355
|
+
// call_tool is the gateway tool for calling external tools, so it should be allowed
|
|
326
356
|
if (Array.isArray(SYSTEM_TOOL_NAMES) &&
|
|
327
|
-
SYSTEM_TOOL_NAMES.includes(toolName)
|
|
357
|
+
SYSTEM_TOOL_NAMES.includes(toolName) &&
|
|
358
|
+
toolName !== CALL_TOOL_TOOL) {
|
|
328
359
|
throw new McpError(-32801, `System tools cannot be called via 'call_tool'. Use 'tools/call' with the system tool name directly. ` +
|
|
329
360
|
`Example: use 'list_servers' directly instead of call_tool(serverName: "mcp-hub-lite", toolName: "list_servers").`);
|
|
330
361
|
}
|
|
@@ -377,7 +408,40 @@ export class HubToolsService {
|
|
|
377
408
|
// Server not found in hubManager, try direct call by name through mcpConnectionManager
|
|
378
409
|
logger.debug(`Server not found in hubManager, trying direct call by name: ${serverName}`, LOG_MODULES.HUB_TOOLS);
|
|
379
410
|
// Use selectBestInstance with non-strict mode to find an available instance
|
|
380
|
-
|
|
411
|
+
let fallbackServerInfo = selectBestInstance(serverName, undefined, false);
|
|
412
|
+
// If selectBestInstance returns undefined (e.g., TAG_MATCH_UNIQUE strategy without tags),
|
|
413
|
+
// fall back to directly selecting an enabled instance with RANDOM strategy
|
|
414
|
+
if (!fallbackServerInfo) {
|
|
415
|
+
logger.debug(`selectBestInstance returned undefined for ${serverName}, trying direct instance selection with RANDOM strategy`, LOG_MODULES.HUB_TOOLS);
|
|
416
|
+
const serverConfig = hubManager.getServerByName(serverName);
|
|
417
|
+
if (serverConfig && serverConfig.instances.length > 0) {
|
|
418
|
+
// Filter: use runtime connected status, NOT config enabled flag
|
|
419
|
+
// enabled=false means "do not auto-start" but user can manually start it
|
|
420
|
+
const connectedInstances = serverConfig.instances.filter((instance) => {
|
|
421
|
+
if (instance.index === undefined)
|
|
422
|
+
return false;
|
|
423
|
+
const status = mcpConnectionManager.getStatus(serverName, instance.index);
|
|
424
|
+
return status?.connected;
|
|
425
|
+
});
|
|
426
|
+
if (connectedInstances.length > 0) {
|
|
427
|
+
// Use RANDOM strategy regardless of server's configured strategy
|
|
428
|
+
const selectedInstance = InstanceSelector.selectInstance(serverName, {
|
|
429
|
+
...serverConfig,
|
|
430
|
+
template: {
|
|
431
|
+
...serverConfig.template,
|
|
432
|
+
instanceSelectionStrategy: InstanceSelectionStrategy.RANDOM
|
|
433
|
+
}
|
|
434
|
+
}, undefined);
|
|
435
|
+
if (selectedInstance) {
|
|
436
|
+
fallbackServerInfo = {
|
|
437
|
+
name: serverName,
|
|
438
|
+
config: serverConfig,
|
|
439
|
+
instance: selectedInstance
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
381
445
|
if (!fallbackServerInfo) {
|
|
382
446
|
logger.error(`Server not found: ${serverName}`, LOG_MODULES.HUB_TOOLS);
|
|
383
447
|
throw new Error(`Server not found: ${serverName}`);
|
|
@@ -525,12 +589,8 @@ export class HubToolsService {
|
|
|
525
589
|
* @returns {Promise<Resource[]>} Array of MCP resource objects representing Hub resources
|
|
526
590
|
*/
|
|
527
591
|
async listResources() {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
}
|
|
531
|
-
const resources = generateDynamicResources();
|
|
532
|
-
this.generatedResourcesCache = resources;
|
|
533
|
-
return resources;
|
|
592
|
+
// Always regenerate to ensure fresh data based on runtime status
|
|
593
|
+
return generateDynamicResources();
|
|
534
594
|
}
|
|
535
595
|
/**
|
|
536
596
|
* Reads content from a specific Hub resource URI.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-tool-handler.d.ts","sourceRoot":"","sources":["../../../../src/services/system-tool-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"system-tool-handler.d.ts","sourceRoot":"","sources":["../../../../src/services/system-tool-handler.ts"],"names":[],"mappings":"AAqBA;;GAEG;AACH,qBAAa,iBAAiB;IAC5B;;OAEG;WACU,oBAAoB,CAC/B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,OAAO,CAAC;CA2EpB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { hubToolsService } from './hub-tools.service.js';
|
|
2
2
|
import { McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
3
3
|
import { logger, LOG_MODULES } from '../utils/logger.js';
|
|
4
|
-
import { LIST_SERVERS_TOOL, LIST_TOOLS_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL,
|
|
4
|
+
import { LIST_SERVERS_TOOL, LIST_TOOLS_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL, LIST_TAGS_TOOL } from '../models/system-tools.constants.js';
|
|
5
5
|
import { stringifyForLogging } from '../utils/json-utils.js';
|
|
6
6
|
/**
|
|
7
7
|
* Unified system tool call handler
|
|
@@ -20,31 +20,44 @@ export class SystemToolHandler {
|
|
|
20
20
|
break;
|
|
21
21
|
case LIST_TOOLS_TOOL: {
|
|
22
22
|
const listToolsArgs = toolArgs;
|
|
23
|
+
if (!listToolsArgs.serverName) {
|
|
24
|
+
throw new McpError(-32802, 'serverName is required');
|
|
25
|
+
}
|
|
23
26
|
result = await hubToolsService.listToolsInServer(listToolsArgs);
|
|
24
27
|
break;
|
|
25
28
|
}
|
|
26
29
|
case GET_TOOL_TOOL: {
|
|
27
30
|
const getToolArgs = toolArgs;
|
|
31
|
+
if (!getToolArgs.serverName) {
|
|
32
|
+
throw new McpError(-32802, 'serverName is required');
|
|
33
|
+
}
|
|
28
34
|
result = await hubToolsService.getTool(getToolArgs);
|
|
29
35
|
break;
|
|
30
36
|
}
|
|
31
37
|
case CALL_TOOL_TOOL: {
|
|
32
38
|
const callToolArgs = toolArgs;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
serverName = MCP_HUB_LITE_SERVER;
|
|
39
|
+
if (!callToolArgs.serverName) {
|
|
40
|
+
throw new McpError(-32802, 'serverName is required');
|
|
36
41
|
}
|
|
37
|
-
result = await hubToolsService.callTool(
|
|
38
|
-
...callToolArgs,
|
|
39
|
-
serverName
|
|
40
|
-
});
|
|
42
|
+
result = await hubToolsService.callTool(callToolArgs);
|
|
41
43
|
break;
|
|
42
44
|
}
|
|
43
45
|
case UPDATE_SERVER_DESCRIPTION_TOOL: {
|
|
44
46
|
const updateDescArgs = toolArgs;
|
|
47
|
+
if (!updateDescArgs.serverName) {
|
|
48
|
+
throw new McpError(-32802, 'serverName is required');
|
|
49
|
+
}
|
|
45
50
|
result = await hubToolsService.updateServerDescription(updateDescArgs);
|
|
46
51
|
break;
|
|
47
52
|
}
|
|
53
|
+
case LIST_TAGS_TOOL: {
|
|
54
|
+
const listTagsArgs = toolArgs;
|
|
55
|
+
if (!listTagsArgs.serverName) {
|
|
56
|
+
throw new McpError(-32802, 'serverName is required');
|
|
57
|
+
}
|
|
58
|
+
result = await hubToolsService.listTags(listTagsArgs);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
48
61
|
default:
|
|
49
62
|
throw new McpError(-32801, `Unknown system tool: ${toolName}`);
|
|
50
63
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"name-converter.d.ts","sourceRoot":"","sources":["../../../../src/utils/name-converter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"name-converter.d.ts","sourceRoot":"","sources":["../../../../src/utils/name-converter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAe1D"}
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* normalizeToolName('chat_completions') // returns 'chat_completions'
|
|
15
15
|
*/
|
|
16
16
|
export function normalizeToolName(toolName) {
|
|
17
|
+
if (!toolName)
|
|
18
|
+
return '';
|
|
17
19
|
return (toolName
|
|
18
20
|
// Insert underscore before uppercase letters (for camelCase handling)
|
|
19
21
|
// e.g., 'chatCompletions' -> 'chat_Completions'
|
|
@@ -17,8 +17,13 @@ describe('InstanceSelector', () => {
|
|
|
17
17
|
headers: {},
|
|
18
18
|
tags: {}
|
|
19
19
|
};
|
|
20
|
+
// Mock statusChecker that simulates connected instances
|
|
21
|
+
const mockConnectedStatus = () => ({ connected: true });
|
|
22
|
+
const mockDisconnectedStatus = () => ({ connected: false });
|
|
20
23
|
describe('random strategy', () => {
|
|
21
|
-
it('should select random instance from
|
|
24
|
+
it('should select random instance from connected instances', () => {
|
|
25
|
+
// Local mock that simulates idx=2 being disconnected
|
|
26
|
+
const localMockConnectedStatus = (_name, idx) => idx === 2 ? { connected: false } : { connected: true };
|
|
22
27
|
const config = {
|
|
23
28
|
template: {
|
|
24
29
|
...baseTemplate,
|
|
@@ -31,11 +36,11 @@ describe('InstanceSelector', () => {
|
|
|
31
36
|
],
|
|
32
37
|
tagDefinitions: []
|
|
33
38
|
};
|
|
34
|
-
const selected = InstanceSelector.selectInstance('test-server', config);
|
|
39
|
+
const selected = InstanceSelector.selectInstance('test-server', config, undefined, localMockConnectedStatus);
|
|
35
40
|
expect(selected).toBeDefined();
|
|
36
41
|
expect(['1', '2']).toContain(selected.id);
|
|
37
42
|
});
|
|
38
|
-
it('should return undefined when no
|
|
43
|
+
it('should return undefined when no connected instances', () => {
|
|
39
44
|
const config = {
|
|
40
45
|
template: {
|
|
41
46
|
...baseTemplate,
|
|
@@ -47,12 +52,12 @@ describe('InstanceSelector', () => {
|
|
|
47
52
|
],
|
|
48
53
|
tagDefinitions: []
|
|
49
54
|
};
|
|
50
|
-
const selected = InstanceSelector.selectInstance('test-server', config);
|
|
55
|
+
const selected = InstanceSelector.selectInstance('test-server', config, undefined, mockDisconnectedStatus);
|
|
51
56
|
expect(selected).toBeUndefined();
|
|
52
57
|
});
|
|
53
58
|
});
|
|
54
59
|
describe('round-robin strategy', () => {
|
|
55
|
-
it('should cycle through
|
|
60
|
+
it('should cycle through connected instances', () => {
|
|
56
61
|
const config = {
|
|
57
62
|
template: {
|
|
58
63
|
...baseTemplate,
|
|
@@ -65,10 +70,10 @@ describe('InstanceSelector', () => {
|
|
|
65
70
|
],
|
|
66
71
|
tagDefinitions: []
|
|
67
72
|
};
|
|
68
|
-
const selected1 = InstanceSelector.selectInstance('test-server-rr', config);
|
|
69
|
-
const selected2 = InstanceSelector.selectInstance('test-server-rr', config);
|
|
70
|
-
const selected3 = InstanceSelector.selectInstance('test-server-rr', config);
|
|
71
|
-
const selected4 = InstanceSelector.selectInstance('test-server-rr', config);
|
|
73
|
+
const selected1 = InstanceSelector.selectInstance('test-server-rr', config, undefined, mockConnectedStatus);
|
|
74
|
+
const selected2 = InstanceSelector.selectInstance('test-server-rr', config, undefined, mockConnectedStatus);
|
|
75
|
+
const selected3 = InstanceSelector.selectInstance('test-server-rr', config, undefined, mockConnectedStatus);
|
|
76
|
+
const selected4 = InstanceSelector.selectInstance('test-server-rr', config, undefined, mockConnectedStatus);
|
|
72
77
|
expect(selected1.id).toBe('1');
|
|
73
78
|
expect(selected2.id).toBe('2');
|
|
74
79
|
expect(selected3.id).toBe('3');
|
|
@@ -91,7 +96,7 @@ describe('InstanceSelector', () => {
|
|
|
91
96
|
};
|
|
92
97
|
const selected = InstanceSelector.selectInstance('test-server', config, {
|
|
93
98
|
tags: { env: 'prod', region: 'us' }
|
|
94
|
-
});
|
|
99
|
+
}, mockConnectedStatus);
|
|
95
100
|
expect(selected).toBeDefined();
|
|
96
101
|
expect(selected.id).toBe('2');
|
|
97
102
|
});
|
|
@@ -110,7 +115,7 @@ describe('InstanceSelector', () => {
|
|
|
110
115
|
expect(() => {
|
|
111
116
|
InstanceSelector.selectInstance('test-server', config, {
|
|
112
117
|
tags: { env: 'staging' }
|
|
113
|
-
});
|
|
118
|
+
}, mockConnectedStatus);
|
|
114
119
|
}).toThrow('No instance found matching tags');
|
|
115
120
|
});
|
|
116
121
|
it('should throw error when multiple instances match tags', () => {
|
|
@@ -128,7 +133,7 @@ describe('InstanceSelector', () => {
|
|
|
128
133
|
expect(() => {
|
|
129
134
|
InstanceSelector.selectInstance('test-server', config, {
|
|
130
135
|
tags: { env: 'prod' }
|
|
131
|
-
});
|
|
136
|
+
}, mockConnectedStatus);
|
|
132
137
|
}).toThrow('Multiple instances match tags');
|
|
133
138
|
});
|
|
134
139
|
it('should return the single instance when no tags provided and only one instance exists', () => {
|
|
@@ -140,7 +145,7 @@ describe('InstanceSelector', () => {
|
|
|
140
145
|
instances: [{ ...baseInstance, id: '1', index: 0 }],
|
|
141
146
|
tagDefinitions: []
|
|
142
147
|
};
|
|
143
|
-
const selected = InstanceSelector.selectInstance('test-server', config);
|
|
148
|
+
const selected = InstanceSelector.selectInstance('test-server', config, undefined, mockConnectedStatus);
|
|
144
149
|
expect(selected).toBeDefined();
|
|
145
150
|
expect(selected.id).toBe('1');
|
|
146
151
|
});
|
|
@@ -157,7 +162,7 @@ describe('InstanceSelector', () => {
|
|
|
157
162
|
tagDefinitions: []
|
|
158
163
|
};
|
|
159
164
|
expect(() => {
|
|
160
|
-
InstanceSelector.selectInstance('test-server', config);
|
|
165
|
+
InstanceSelector.selectInstance('test-server', config, undefined, mockConnectedStatus);
|
|
161
166
|
}).toThrow('No tags provided for tag-match-unique strategy with 2 instances. Available: [0:{}, 1:{}]. Pass matching tags to select.');
|
|
162
167
|
});
|
|
163
168
|
});
|
|
@@ -171,7 +176,7 @@ describe('InstanceSelector', () => {
|
|
|
171
176
|
instances: [{ ...baseInstance, id: '1', index: 0 }],
|
|
172
177
|
tagDefinitions: []
|
|
173
178
|
};
|
|
174
|
-
const selected = InstanceSelector.selectInstance('test-server', config);
|
|
179
|
+
const selected = InstanceSelector.selectInstance('test-server', config, undefined, mockConnectedStatus);
|
|
175
180
|
expect(selected).toBeDefined();
|
|
176
181
|
expect(selected.id).toBe('1');
|
|
177
182
|
});
|
|
@@ -187,7 +192,7 @@ describe('InstanceSelector', () => {
|
|
|
187
192
|
tagDefinitions: []
|
|
188
193
|
// No instanceSelectionStrategy field
|
|
189
194
|
};
|
|
190
|
-
const selected = InstanceSelector.selectInstance('test-server', config);
|
|
195
|
+
const selected = InstanceSelector.selectInstance('test-server', config, undefined, mockConnectedStatus);
|
|
191
196
|
expect(selected).toBeDefined();
|
|
192
197
|
expect(['1', '2']).toContain(selected.id);
|
|
193
198
|
});
|