@loop_ouroboros/mcp-hub-lite 1.1.1 → 1.2.1

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 (37) hide show
  1. package/CHANGELOG.md +140 -0
  2. package/README.md +73 -115
  3. package/dist/server/src/cli/commands/mcp-tool-use.d.ts +62 -0
  4. package/dist/server/src/cli/commands/mcp-tool-use.d.ts.map +1 -0
  5. package/dist/server/src/cli/commands/mcp-tool-use.js +174 -0
  6. package/dist/server/src/cli/commands/tool-use.d.ts +95 -0
  7. package/dist/server/src/cli/commands/tool-use.d.ts.map +1 -0
  8. package/dist/server/src/cli/commands/tool-use.js +255 -0
  9. package/dist/server/src/cli/index.d.ts +4 -2
  10. package/dist/server/src/cli/index.d.ts.map +1 -1
  11. package/dist/server/src/cli/index.js +35 -3
  12. package/dist/server/src/config/config-loader.js +1 -1
  13. package/dist/server/src/config/config-manager.js +1 -1
  14. package/dist/server/src/models/system-tools.constants.d.ts +2 -2
  15. package/dist/server/src/models/system-tools.constants.d.ts.map +1 -1
  16. package/dist/server/src/models/system-tools.constants.js +2 -2
  17. package/dist/server/src/services/connection/tool-cache.d.ts.map +1 -1
  18. package/dist/server/src/services/connection/tool-cache.js +3 -1
  19. package/dist/server/src/services/gateway/request-handlers/system-tools-handler.js +2 -2
  20. package/dist/server/src/services/hub-tools/system-tool-definitions.d.ts +1 -0
  21. package/dist/server/src/services/hub-tools/system-tool-definitions.d.ts.map +1 -1
  22. package/dist/server/src/services/hub-tools/system-tool-definitions.js +4 -3
  23. package/dist/server/src/services/hub-tools.service.d.ts +3 -2
  24. package/dist/server/src/services/hub-tools.service.d.ts.map +1 -1
  25. package/dist/server/src/services/hub-tools.service.js +36 -19
  26. package/dist/server/src/services/system-tool-handler.js +2 -2
  27. package/dist/server/src/utils/index.d.ts +1 -0
  28. package/dist/server/src/utils/index.d.ts.map +1 -1
  29. package/dist/server/src/utils/index.js +1 -0
  30. package/dist/server/src/utils/name-converter.d.ts +17 -0
  31. package/dist/server/src/utils/name-converter.d.ts.map +1 -0
  32. package/dist/server/src/utils/name-converter.js +27 -0
  33. package/dist/server/tests/unit/services/hub-tools.service.test.js +1 -1
  34. package/dist/server/tests/unit/utils/name-converter.test.d.ts +2 -0
  35. package/dist/server/tests/unit/utils/name-converter.test.d.ts.map +1 -0
  36. package/dist/server/tests/unit/utils/name-converter.test.js +69 -0
  37. package/package.json +2 -2
@@ -1,6 +1,6 @@
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_IN_SERVER_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL } from '../models/system-tools.constants.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
4
  import type { SystemToolName, ListServersParams, ListToolsInServerParams, GetToolParams, CallToolParams, UpdateServerDescriptionParams } 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.
@@ -26,6 +26,7 @@ import type { SystemToolName, ListServersParams, ListToolsInServerParams, GetToo
26
26
  * - `list-tools-in-server`: List all tools from a specific server
27
27
  * - `get-tool`: Retrieve complete schema for a specific tool
28
28
  * - `call-tool`: Execute a tool on a specific server
29
+ * - `update-server-description`: Update the description of a specific MCP server
29
30
  *
30
31
  * ## Architecture Integration
31
32
  *
@@ -133,7 +134,7 @@ export declare class HubToolsService {
133
134
  * @returns {Promise<ConditionalReturnType>} Tool execution result with accurate type safety matching actual method return types
134
135
  * @throws {Error} If the system tool is not found or execution fails
135
136
  */
136
- callSystemTool<T extends SystemToolName>(toolName: T, toolArgs: T extends typeof LIST_SERVERS_TOOL ? ListServersParams : T extends typeof LIST_TOOLS_IN_SERVER_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_IN_SERVER_TOOL ? {
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 ? {
137
138
  serverName: string;
138
139
  tools: ToolSummary[];
139
140
  } : T extends typeof GET_TOOL_TOOL ? Tool | undefined : T extends typeof CALL_TOOL_TOOL ? unknown : T extends typeof UPDATE_SERVER_DESCRIPTION_TOOL ? {
@@ -1 +1 @@
1
- {"version":3,"file":"hub-tools.service.d.ts","sourceRoot":"","sources":["../../../../src/services/hub-tools.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hub-tools.service.d.ts","sourceRoot":"","sources":["../../../../src/services/hub-tools.service.ts"],"names":[],"mappings":"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"}
@@ -4,8 +4,9 @@ import { eventBus, EventTypes } from './event-bus.service.js';
4
4
  import { gateway } from './gateway.service.js';
5
5
  import { logger, LOG_MODULES } from '../utils/logger.js';
6
6
  import { stringifyForLogging } from '../utils/json-utils.js';
7
+ import { normalizeToolName } from '../utils/name-converter.js';
7
8
  import { McpError } from '@modelcontextprotocol/sdk/types.js';
8
- import { MCP_HUB_LITE_SERVER, LIST_SERVERS_TOOL, LIST_TOOLS_IN_SERVER_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, SYSTEM_TOOL_NAMES } from '../models/system-tools.constants.js';
9
10
  import { ToolArgsParser } from '../utils/tool-args-parser.js';
10
11
  import { hasValidId, selectBestInstance, getServerDescription, getSystemTools, generateDynamicResources, readResource as readResourceUtil } from './hub-tools/index.js';
11
12
  /**
@@ -32,6 +33,7 @@ import { hasValidId, selectBestInstance, getServerDescription, getSystemTools, g
32
33
  * - `list-tools-in-server`: List all tools from a specific server
33
34
  * - `get-tool`: Retrieve complete schema for a specific tool
34
35
  * - `call-tool`: Execute a tool on a specific server
36
+ * - `update-server-description`: Update the description of a specific MCP server
35
37
  *
36
38
  * ## Architecture Integration
37
39
  *
@@ -182,7 +184,7 @@ export class HubToolsService {
182
184
  // Handle MCP Hub Lite server (return system tool)
183
185
  if (typeof args.serverName === 'string' && args.serverName === MCP_HUB_LITE_SERVER) {
184
186
  const systemTools = getSystemTools();
185
- const found = systemTools.find((tool) => tool.name === args.toolName);
187
+ const found = systemTools.find((tool) => normalizeToolName(tool.name) === normalizeToolName(args.toolName));
186
188
  if (found) {
187
189
  return {
188
190
  ...found,
@@ -197,7 +199,7 @@ export class HubToolsService {
197
199
  if (tools.length === 0) {
198
200
  throw new Error(`Server not found: ${args.serverName}`);
199
201
  }
200
- return tools.find((t) => t.name === args.toolName);
202
+ return tools.find((t) => normalizeToolName(t.name) === normalizeToolName(args.toolName));
201
203
  }
202
204
  /**
203
205
  * Updates the description of a specific MCP server.
@@ -251,7 +253,7 @@ export class HubToolsService {
251
253
  case LIST_SERVERS_TOOL:
252
254
  result = await this.listServers();
253
255
  break;
254
- case LIST_TOOLS_IN_SERVER_TOOL: {
256
+ case LIST_TOOLS_TOOL: {
255
257
  result = await this.listToolsInServer(toolArgs);
256
258
  break;
257
259
  }
@@ -335,7 +337,7 @@ export class HubToolsService {
335
337
  if (serverInfo && serverInfo.instance.id) {
336
338
  const instanceIndex = serverInfo.instance.index;
337
339
  const tools = mcpConnectionManager.getTools(server.name, instanceIndex);
338
- if (tools.some((tool) => tool.name === toolName)) {
340
+ if (tools.some((tool) => normalizeToolName(tool.name) === normalizeToolName(toolName))) {
339
341
  matchingServers.push(server.name);
340
342
  }
341
343
  }
@@ -354,13 +356,16 @@ export class HubToolsService {
354
356
  // Validate tool exists before doing strict instance selection
355
357
  // Use strictMode=false to get serverInfo without triggering tag-match-unique errors
356
358
  const validationServerInfo = selectBestInstance(serverName, requestOptions, false);
359
+ let actualToolName;
357
360
  if (validationServerInfo && validationServerInfo.instance.id) {
358
361
  const instanceIndex = validationServerInfo.instance.index;
359
362
  const tools = mcpConnectionManager.getTools(serverName, instanceIndex);
360
- if (!tools.some((tool) => tool.name === toolName)) {
363
+ const matchedTool = tools.find((tool) => normalizeToolName(tool.name) === normalizeToolName(toolName));
364
+ if (!matchedTool) {
361
365
  throw new Error(`Tool '${toolName}' not found in server '${serverName}'. ` +
362
- `Use list_tools_in_server(serverName: "${serverName}") to see available tools.`);
366
+ `Use list_tools(serverName: "${serverName}") to see available tools.`);
363
367
  }
368
+ actualToolName = matchedTool.name;
364
369
  }
365
370
  const serverInfo = selectBestInstance(serverName, requestOptions, true);
366
371
  const requestId = `tool-call-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
@@ -374,27 +379,38 @@ export class HubToolsService {
374
379
  throw new Error(`Server not found: ${serverName}`);
375
380
  }
376
381
  const instanceIndex = fallbackServerInfo.instance.index;
382
+ // If actualToolName not set yet, find it now
383
+ if (!actualToolName) {
384
+ const fallbackTools = mcpConnectionManager.getTools(serverName, instanceIndex);
385
+ const matchedTool = fallbackTools.find((tool) => normalizeToolName(tool.name) === normalizeToolName(toolName));
386
+ if (!matchedTool) {
387
+ throw new Error(`Tool '${toolName}' not found in server '${serverName}'. ` +
388
+ `Use list_tools(serverName: "${serverName}") to see available tools.`);
389
+ }
390
+ actualToolName = matchedTool.name;
391
+ }
392
+ const toolNameToUse = actualToolName || toolName;
377
393
  // Publish tool call started event with the resolved serverIndex
378
394
  eventBus.publish(EventTypes.TOOL_CALL_STARTED, {
379
395
  requestId,
380
396
  serverName,
381
397
  serverIndex: instanceIndex,
382
- toolName,
398
+ toolName: toolNameToUse,
383
399
  timestamp: Date.now(),
384
400
  args: toolArgs
385
401
  });
386
402
  try {
387
- const result = await mcpConnectionManager.callTool(serverName, instanceIndex, toolName, toolArgs);
403
+ const result = await mcpConnectionManager.callTool(serverName, instanceIndex, toolNameToUse, toolArgs);
388
404
  // Publish tool call completed event
389
405
  eventBus.publish(EventTypes.TOOL_CALL_COMPLETED, {
390
406
  requestId,
391
407
  serverName,
392
408
  serverIndex: instanceIndex,
393
- toolName,
409
+ toolName: toolNameToUse,
394
410
  timestamp: Date.now(),
395
411
  result
396
412
  });
397
- logger.debug(`Tool call SUCCESS: serverName=${serverName}, toolName=${toolName}`, LOG_MODULES.HUB_TOOLS);
413
+ logger.debug(`Tool call SUCCESS: serverName=${serverName}, toolName=${toolNameToUse}`, LOG_MODULES.HUB_TOOLS);
398
414
  return result;
399
415
  }
400
416
  catch (error) {
@@ -403,37 +419,38 @@ export class HubToolsService {
403
419
  requestId,
404
420
  serverName,
405
421
  serverIndex: instanceIndex,
406
- toolName,
422
+ toolName: toolNameToUse,
407
423
  timestamp: Date.now(),
408
424
  error: error instanceof Error ? error.message : String(error),
409
425
  stack: error instanceof Error ? error.stack : undefined
410
426
  });
411
- logger.error(`Tool call FAILED: serverName=${serverName}, toolName=${toolName}, error=${error instanceof Error ? error.message : String(error)}`, error, LOG_MODULES.HUB_TOOLS);
427
+ logger.error(`Tool call FAILED: serverName=${serverName}, toolName=${toolNameToUse}, error=${error instanceof Error ? error.message : String(error)}`, error, LOG_MODULES.HUB_TOOLS);
412
428
  throw error;
413
429
  }
414
430
  }
415
431
  const instanceIndex = serverInfo.instance.index;
432
+ const toolNameToUse = actualToolName || toolName;
416
433
  // Publish tool call started event
417
434
  eventBus.publish(EventTypes.TOOL_CALL_STARTED, {
418
435
  requestId,
419
436
  serverName,
420
437
  serverIndex: instanceIndex,
421
- toolName,
438
+ toolName: toolNameToUse,
422
439
  timestamp: Date.now(),
423
440
  args: toolArgs
424
441
  });
425
442
  try {
426
- const result = await mcpConnectionManager.callTool(serverName, instanceIndex, toolName, toolArgs);
443
+ const result = await mcpConnectionManager.callTool(serverName, instanceIndex, toolNameToUse, toolArgs);
427
444
  // Publish tool call completed event
428
445
  eventBus.publish(EventTypes.TOOL_CALL_COMPLETED, {
429
446
  requestId,
430
447
  serverName,
431
448
  serverIndex: instanceIndex,
432
- toolName,
449
+ toolName: toolNameToUse,
433
450
  timestamp: Date.now(),
434
451
  result
435
452
  });
436
- logger.debug(`Tool call SUCCESS: serverName=${serverName}, toolName=${toolName}`, LOG_MODULES.HUB_TOOLS);
453
+ logger.debug(`Tool call SUCCESS: serverName=${serverName}, toolName=${toolNameToUse}`, LOG_MODULES.HUB_TOOLS);
437
454
  return result;
438
455
  }
439
456
  catch (error) {
@@ -442,12 +459,12 @@ export class HubToolsService {
442
459
  requestId,
443
460
  serverName,
444
461
  serverIndex: instanceIndex,
445
- toolName,
462
+ toolName: toolNameToUse,
446
463
  timestamp: Date.now(),
447
464
  error: error instanceof Error ? error.message : String(error),
448
465
  stack: error instanceof Error ? error.stack : undefined
449
466
  });
450
- logger.error(`Tool call FAILED: serverName=${serverName}, toolName=${toolName}, error=${error instanceof Error ? error.message : String(error)}`, error, LOG_MODULES.HUB_TOOLS);
467
+ logger.error(`Tool call FAILED: serverName=${serverName}, toolName=${toolNameToUse}, error=${error instanceof Error ? error.message : String(error)}`, error, LOG_MODULES.HUB_TOOLS);
451
468
  throw error;
452
469
  }
453
470
  }
@@ -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_IN_SERVER_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL, MCP_HUB_LITE_SERVER } from '../models/system-tools.constants.js';
4
+ import { LIST_SERVERS_TOOL, LIST_TOOLS_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL, MCP_HUB_LITE_SERVER } from '../models/system-tools.constants.js';
5
5
  import { stringifyForLogging } from '../utils/json-utils.js';
6
6
  /**
7
7
  * Unified system tool call handler
@@ -18,7 +18,7 @@ export class SystemToolHandler {
18
18
  case LIST_SERVERS_TOOL:
19
19
  result = await hubToolsService.listServers();
20
20
  break;
21
- case LIST_TOOLS_IN_SERVER_TOOL: {
21
+ case LIST_TOOLS_TOOL: {
22
22
  const listToolsArgs = toolArgs;
23
23
  result = await hubToolsService.listToolsInServer(listToolsArgs);
24
24
  break;
@@ -1,4 +1,5 @@
1
1
  export { logger, LOG_MODULES } from './logger.js';
2
2
  export * from './sort-utils.js';
3
3
  export * from './version.js';
4
+ export { normalizeToolName } from './name-converter.js';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAClD,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAClD,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1,3 +1,4 @@
1
1
  export { logger, LOG_MODULES } from './logger.js';
2
2
  export * from './sort-utils.js';
3
3
  export * from './version.js';
4
+ export { normalizeToolName } from './name-converter.js';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Normalizes a tool name to a standard format for comparison.
3
+ *
4
+ * This function converts various naming conventions (snake_case, kebab-case,
5
+ * camelCase, space-separated, or uppercase) into a normalized lowercase
6
+ * underscore format for consistent matching.
7
+ *
8
+ * @param toolName - The tool name to normalize
9
+ * @returns Normalized tool name in lowercase underscore format
10
+ * @example
11
+ * normalizeToolName('list-servers') // returns 'list_servers'
12
+ * normalizeToolName('LIST_SERVERS') // returns 'list_servers'
13
+ * normalizeToolName('chatCompletions') // returns 'chat_completions'
14
+ * normalizeToolName('chat_completions') // returns 'chat_completions'
15
+ */
16
+ export declare function normalizeToolName(toolName: string): string;
17
+ //# sourceMappingURL=name-converter.d.ts.map
@@ -0,0 +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,CAa1D"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Normalizes a tool name to a standard format for comparison.
3
+ *
4
+ * This function converts various naming conventions (snake_case, kebab-case,
5
+ * camelCase, space-separated, or uppercase) into a normalized lowercase
6
+ * underscore format for consistent matching.
7
+ *
8
+ * @param toolName - The tool name to normalize
9
+ * @returns Normalized tool name in lowercase underscore format
10
+ * @example
11
+ * normalizeToolName('list-servers') // returns 'list_servers'
12
+ * normalizeToolName('LIST_SERVERS') // returns 'list_servers'
13
+ * normalizeToolName('chatCompletions') // returns 'chat_completions'
14
+ * normalizeToolName('chat_completions') // returns 'chat_completions'
15
+ */
16
+ export function normalizeToolName(toolName) {
17
+ return (toolName
18
+ // Insert underscore before uppercase letters (for camelCase handling)
19
+ // e.g., 'chatCompletions' -> 'chat_Completions'
20
+ .replace(/([a-z])([A-Z])/g, '$1_$2')
21
+ // Convert to lowercase
22
+ .toLowerCase()
23
+ // Replace hyphens, underscores, and spaces with single underscore
24
+ .replace(/[-_\s]+/g, '_')
25
+ // Remove leading and trailing underscores
26
+ .replace(/^_+|_+$/g, ''));
27
+ }
@@ -613,7 +613,7 @@ describe('HubToolsService', () => {
613
613
  // Assert system tools - should have 5 tools now
614
614
  const systemToolNames = allTools['mcp-hub-lite'].tools.map((t) => t.name);
615
615
  expect(systemToolNames).toContain('list_servers');
616
- expect(systemToolNames).toContain('list_tools_in_server');
616
+ expect(systemToolNames).toContain('list_tools');
617
617
  expect(systemToolNames).toContain('get_tool');
618
618
  expect(systemToolNames).toContain('call_tool');
619
619
  expect(systemToolNames).toContain('update_server_description');
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=name-converter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"name-converter.test.d.ts","sourceRoot":"","sources":["../../../../../tests/unit/utils/name-converter.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,69 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { normalizeToolName } from '../../../src/utils/name-converter.js';
3
+ describe('name-converter', () => {
4
+ describe('normalizeToolName', () => {
5
+ it('should convert kebab-case to snake_case', () => {
6
+ expect(normalizeToolName('list-servers')).toBe('list_servers');
7
+ expect(normalizeToolName('get-tool')).toBe('get_tool');
8
+ expect(normalizeToolName('call-tool')).toBe('call_tool');
9
+ });
10
+ it('should convert uppercase to lowercase', () => {
11
+ expect(normalizeToolName('LIST_SERVERS')).toBe('list_servers');
12
+ expect(normalizeToolName('GET_TOOL')).toBe('get_tool');
13
+ expect(normalizeToolName('LIST_SERVERS_TOOL')).toBe('list_servers_tool');
14
+ });
15
+ it('should convert mixed case to lowercase with underscores', () => {
16
+ expect(normalizeToolName('ListServers')).toBe('list_servers');
17
+ expect(normalizeToolName('GetTool')).toBe('get_tool');
18
+ expect(normalizeToolName('chatCompletions')).toBe('chat_completions');
19
+ });
20
+ it('should convert space-separated to underscores', () => {
21
+ expect(normalizeToolName('list servers')).toBe('list_servers');
22
+ expect(normalizeToolName('get tool info')).toBe('get_tool_info');
23
+ });
24
+ it('should handle already normalized names', () => {
25
+ expect(normalizeToolName('list_servers')).toBe('list_servers');
26
+ expect(normalizeToolName('get_tool')).toBe('get_tool');
27
+ expect(normalizeToolName('chat_completions')).toBe('chat_completions');
28
+ });
29
+ it('should remove leading and trailing underscores', () => {
30
+ expect(normalizeToolName('_list_servers_')).toBe('list_servers');
31
+ expect(normalizeToolName('__get_tool__')).toBe('get_tool');
32
+ });
33
+ it('should handle multiple consecutive separators', () => {
34
+ expect(normalizeToolName('list--servers')).toBe('list_servers');
35
+ expect(normalizeToolName('list__servers')).toBe('list_servers');
36
+ expect(normalizeToolName('list servers')).toBe('list_servers');
37
+ expect(normalizeToolName('list-_-servers')).toBe('list_servers');
38
+ });
39
+ it('should handle empty string', () => {
40
+ expect(normalizeToolName('')).toBe('');
41
+ });
42
+ it('should handle single character', () => {
43
+ expect(normalizeToolName('a')).toBe('a');
44
+ expect(normalizeToolName('A')).toBe('a');
45
+ });
46
+ it('should handle names with numbers', () => {
47
+ expect(normalizeToolName('tool123')).toBe('tool123');
48
+ expect(normalizeToolName('tool_123')).toBe('tool_123');
49
+ expect(normalizeToolName('tool-123')).toBe('tool_123');
50
+ });
51
+ });
52
+ describe('normalization consistency', () => {
53
+ it('should normalize different formats to the same value for same base name', () => {
54
+ // All these should normalize to the same value
55
+ const normalized = normalizeToolName('list_servers');
56
+ expect(normalizeToolName('list-servers')).toBe(normalized);
57
+ expect(normalizeToolName('LIST_SERVERS')).toBe(normalized);
58
+ expect(normalizeToolName('list_servers')).toBe(normalized);
59
+ expect(normalizeToolName('List_Servers')).toBe(normalized);
60
+ });
61
+ it('should convert camelCase to snake_case', () => {
62
+ // Note: camelCase normalization properly handles uppercase boundaries
63
+ // e.g., 'chatCompletions' -> 'chat_Completions' -> 'chat_completions'
64
+ expect(normalizeToolName('chatCompletions')).toBe('chat_completions');
65
+ expect(normalizeToolName('getTool')).toBe('get_tool');
66
+ expect(normalizeToolName('listServers')).toBe('list_servers');
67
+ });
68
+ });
69
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loop_ouroboros/mcp-hub-lite",
3
- "version": "1.1.1",
3
+ "version": "1.2.1",
4
4
  "description": "A lightweight MCP management platform designed for independent developers",
5
5
  "license": "MIT",
6
6
  "author": "loop_ouroboros",
@@ -41,7 +41,7 @@
41
41
  "status": "node dist/server/src/cli/index.js status",
42
42
  "list": "node dist/server/src/cli/index.js list",
43
43
  "ui": "node dist/server/src/cli/index.js ui",
44
- "server": "node dist/server/src/cli/index.js server",
44
+ "tool-use": "node dist/server/src/cli/index.js tool-use",
45
45
  "dev": "run-p dev:client dev:server",
46
46
  "dev:client": "vite",
47
47
  "dev:server": "tsx src/server/dev-server.ts",