@loop_ouroboros/mcp-hub-lite 1.1.0 → 1.1.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 (64) hide show
  1. package/dist/client/assets/{HomeView-Bu2joUvW.js → HomeView-BBwvy1oj.js} +1 -1
  2. package/dist/client/assets/{ResourceDetailView-BvrhDCD1.js → ResourceDetailView-CZ2aB73w.js} +1 -1
  3. package/dist/client/assets/{ResourcesView-LjqioF_s.js → ResourcesView-CN1NlhWs.js} +1 -1
  4. package/dist/client/assets/{ServerDashboard-FhHJFvUi.js → ServerDashboard-k652Vw4Z.js} +1 -1
  5. package/dist/client/assets/{ServerDetail-BKV-M4qT.js → ServerDetail-BLQ-a4cO.js} +1 -1
  6. package/dist/client/assets/{ServerListView-BXgtDyt3.js → ServerListView-BHrsFD5i.js} +4 -4
  7. package/dist/client/assets/{ServerStatusTags.vue_vue_type_script_setup_true_lang-D-ooYNdN.js → ServerStatusTags.vue_vue_type_script_setup_true_lang-BHhwEuGe.js} +1 -1
  8. package/dist/client/assets/{SettingsView-CMFG91Z4.js → SettingsView-CUOFNXrz.js} +1 -1
  9. package/dist/client/assets/{ToolCallDialog-Bf4Xe4gH.js → ToolCallDialog-BfPjLxfV.js} +1 -1
  10. package/dist/client/assets/ToolsView-BxgXvPC3.css +1 -0
  11. package/dist/client/assets/ToolsView-CyuhYAE2.js +1 -0
  12. package/dist/client/assets/{_baseClone-Bp9Rjwd7.js → _baseClone-DO5qfalW.js} +1 -1
  13. package/dist/client/assets/{el-form-item-DdSUWYsl.js → el-form-item-CcGsD2K_.js} +2 -2
  14. package/dist/client/assets/{el-input-99gMrutP.js → el-input-tYgeiaCT.js} +1 -1
  15. package/dist/client/assets/{el-loading-CIQ5pD5u.js → el-loading-Dwl9E_Vr.js} +1 -1
  16. package/dist/client/assets/{el-overlay-BVM6msGX.js → el-overlay-kqX_BABo.js} +1 -1
  17. package/dist/client/assets/{el-radio-group-DhXWy7ry.js → el-radio-group-D8aWBVOT.js} +1 -1
  18. package/dist/client/assets/el-skeleton-item-BRwIFspE.js +1 -0
  19. package/dist/client/assets/{el-switch-Bu8AQ5uM.js → el-switch-BF8c-xeU.js} +1 -1
  20. package/dist/client/assets/{el-tab-pane-BnGMaV56.js → el-tab-pane-C4Ep94cd.js} +1 -1
  21. package/dist/client/assets/{el-table-column-BMWOaLS_.js → el-table-column-Cog6uCh-.js} +1 -1
  22. package/dist/client/assets/{index-C2V-ZGji.js → index-ByNBhPAR.js} +1 -1
  23. package/dist/client/assets/index-CTB6oe-9.js +2 -0
  24. package/dist/client/assets/omit-CUnDT6sS.js +1 -0
  25. package/dist/client/assets/{raf-C2wXzaVU.js → raf-CmzeRPMd.js} +1 -1
  26. package/dist/client/assets/{vue-vendor-BLHLXXJK.js → vue-vendor-CbgVSHIh.js} +3 -3
  27. package/dist/client/index.html +2 -2
  28. package/dist/server/src/api/mcp/debug-response-wrapper.js +2 -2
  29. package/dist/server/src/api/mcp/gateway.d.ts.map +1 -1
  30. package/dist/server/src/api/mcp/gateway.js +17 -3
  31. package/dist/server/src/api/mcp/session-context-extractor.d.ts.map +1 -1
  32. package/dist/server/src/api/mcp/session-context-extractor.js +14 -5
  33. package/dist/server/src/cli/commands/server.d.ts +57 -0
  34. package/dist/server/src/cli/commands/server.d.ts.map +1 -0
  35. package/dist/server/src/cli/commands/server.js +169 -0
  36. package/dist/server/src/services/gateway/gateway.service.d.ts.map +1 -1
  37. package/dist/server/src/services/gateway/gateway.service.js +38 -4
  38. package/dist/server/src/services/gateway/global-transport.d.ts +14 -5
  39. package/dist/server/src/services/gateway/global-transport.d.ts.map +1 -1
  40. package/dist/server/src/services/gateway/global-transport.js +54 -30
  41. package/dist/server/src/services/gateway/request-handlers/initialize-handler.d.ts.map +1 -1
  42. package/dist/server/src/services/gateway/request-handlers/initialize-handler.js +12 -1
  43. package/dist/server/src/services/gateway/request-handlers/tools-handler.d.ts.map +1 -1
  44. package/dist/server/src/services/gateway/request-handlers/tools-handler.js +3 -4
  45. package/dist/server/src/services/search/search-core.service.d.ts +5 -5
  46. package/dist/server/src/services/search/search-core.service.js +11 -11
  47. package/dist/server/src/services/session/session-manager.d.ts +256 -12
  48. package/dist/server/src/services/session/session-manager.d.ts.map +1 -1
  49. package/dist/server/src/services/session/session-manager.js +585 -23
  50. package/dist/server/src/services/session-tracker.service.d.ts +10 -2
  51. package/dist/server/src/services/session-tracker.service.d.ts.map +1 -1
  52. package/dist/server/src/services/session-tracker.service.js +53 -2
  53. package/dist/server/src/utils/request-context.d.ts +18 -0
  54. package/dist/server/src/utils/request-context.d.ts.map +1 -1
  55. package/dist/server/src/utils/request-context.js +20 -0
  56. package/dist/server/tests/evaluation/evaluation.test.js +9 -10
  57. package/dist/server/tests/integration/api/gateway.test.js +2 -2
  58. package/dist/server/tests/unit/utils/request-context.test.js +24 -5
  59. package/package.json +3 -1
  60. package/dist/client/assets/ToolsView-DFpha1z0.js +0 -1
  61. package/dist/client/assets/ToolsView-E3Ps9c7i.css +0 -1
  62. package/dist/client/assets/el-skeleton-item-DJz-Us12.js +0 -1
  63. package/dist/client/assets/index-vhkqgpmN.js +0 -2
  64. package/dist/client/assets/omit-CqPQN3XP.js +0 -1
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" href="/favicon.ico" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>MCP Server Manager</title>
8
- <script type="module" crossorigin src="/assets/index-vhkqgpmN.js"></script>
9
- <link rel="modulepreload" crossorigin href="/assets/vue-vendor-BLHLXXJK.js">
8
+ <script type="module" crossorigin src="/assets/index-CTB6oe-9.js"></script>
9
+ <link rel="modulepreload" crossorigin href="/assets/vue-vendor-CbgVSHIh.js">
10
10
  <link rel="stylesheet" crossorigin href="/assets/index-DpH6ZSbs.css">
11
11
  </head>
12
12
  <body>
@@ -269,10 +269,10 @@ export function wrapReplyForDebug(reply, sessionId) {
269
269
  }
270
270
  }
271
271
  if (headers) {
272
- logger.debug(`MCP Gateway error response: ${statusCode} ${statusMessage || ''} Headers: ${stringifyForLogging(headers)}`, LOG_MODULES.COMMUNICATION);
272
+ logger.debug(`Full error response context - statusCode: ${statusCode}, statusMessage: ${statusMessage || 'none'}, headers: ${stringifyForLogging(headers)}`, LOG_MODULES.COMMUNICATION);
273
273
  }
274
274
  else {
275
- logger.debug(`MCP Gateway error response: ${statusCode} ${statusMessage || ''}`, LOG_MODULES.COMMUNICATION);
275
+ logger.debug(`Full error response context - statusCode: ${statusCode}, statusMessage: ${statusMessage || 'none'}`, LOG_MODULES.COMMUNICATION);
276
276
  }
277
277
  }
278
278
  }
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../../../../src/api/mcp/gateway.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAM7E;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,eAAe,iBA0F9D"}
1
+ {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../../../../src/api/mcp/gateway.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAM7E;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,eAAe,iBAqH9D"}
@@ -5,7 +5,7 @@
5
5
  import { logger, LOG_MODULES } from '../../utils/logger/index.js';
6
6
  import { stringifyForLogging, getMcpCommDebugSetting } from '../../utils/json-utils.js';
7
7
  import { wrapReplyForDebug } from './debug-response-wrapper.js';
8
- import { globalTransport } from '../../services/gateway/global-transport.js';
8
+ import { createSessionTransport } from '../../services/gateway/global-transport.js';
9
9
  /**
10
10
  * MCP Gateway routes registration.
11
11
  *
@@ -44,11 +44,25 @@ export async function mcpGatewayRoutes(fastify) {
44
44
  wrapReplyForDebug(reply, '');
45
45
  reply.hijack();
46
46
  try {
47
- await globalTransport.handleRequest(request.raw, reply.raw, request.body);
47
+ logger.debug(`About to create session transport for MCP request`, LOG_MODULES.GATEWAY);
48
+ const { transport, server } = await createSessionTransport();
49
+ logger.debug(`Created session transport successfully, handling MCP request`, LOG_MODULES.GATEWAY);
50
+ try {
51
+ await transport.handleRequest(request.raw, reply.raw, request.body);
52
+ logger.debug(`Successfully handled MCP request with server: ${server.constructor.name}`, LOG_MODULES.GATEWAY);
53
+ }
54
+ finally {
55
+ // Resources will be automatically cleaned up by garbage collection
56
+ // since transport and server are local to this request scope
57
+ logger.debug(`Session transport request completed, resources will be GC'd`, LOG_MODULES.GATEWAY);
58
+ }
48
59
  }
49
60
  catch (error) {
50
61
  const errorMessage = error instanceof Error ? error.message : String(error);
51
- logger.error(`Error handling MCP request: ${errorMessage}`, error, LOG_MODULES.GATEWAY);
62
+ const errorStack = error instanceof Error ? error.stack : 'No stack available';
63
+ logger.error(`Error handling MCP request: ${errorMessage}`, LOG_MODULES.GATEWAY);
64
+ logger.error(`Full error stack: ${errorStack}`, LOG_MODULES.GATEWAY);
65
+ logger.error(`Request body that caused error: ${JSON.stringify(request.body)}`, LOG_MODULES.GATEWAY);
52
66
  if (!reply.raw.headersSent) {
53
67
  reply.raw.writeHead(500, { 'Content-Type': 'application/json' });
54
68
  reply.raw.end(JSON.stringify({
@@ -1 +1 @@
1
- {"version":3,"file":"session-context-extractor.d.ts","sourceRoot":"","sources":["../../../../../src/api/mcp/session-context-extractor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAI7E,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE;QACP,UAAU,CAAC,EAAE;YACX,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;SACjB,CAAC;QACF,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,CAAC;IAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAAA;CAAE,CAAC,GAAG;IAC5F,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,cAAc,CAAC;CAChC,CAyFA"}
1
+ {"version":3,"file":"session-context-extractor.d.ts","sourceRoot":"","sources":["../../../../../src/api/mcp/session-context-extractor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAI7E,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE;QACP,UAAU,CAAC,EAAE;YACX,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;SACjB,CAAC;QACF,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,CAAC;IAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAAA;CAAE,CAAC,GAAG;IAC5F,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,cAAc,CAAC;CAChC,CAsGA"}
@@ -49,14 +49,14 @@ export function extractSessionContext(request) {
49
49
  logger.debug(`Extracted sessionId from URL: ${sessionId}`, LOG_MODULES.CONTEXT);
50
50
  }
51
51
  }
52
- // If sessionId was extracted, check if it exists in memory (for debugging)
52
+ // If sessionId was extracted, check if it exists in persisted sessions (for debugging)
53
53
  if (sessionId) {
54
- const hasSession = mcpSessionManager.hasSession(sessionId);
55
- if (hasSession) {
56
- logger.debug(`Session ${sessionId} found in active sessions`, LOG_MODULES.CONTEXT);
54
+ const persistedSession = mcpSessionManager.getSessionState(sessionId);
55
+ if (persistedSession) {
56
+ logger.debug(`Session ${sessionId} found in persisted sessions`, LOG_MODULES.CONTEXT);
57
57
  }
58
58
  else {
59
- logger.debug(`Session ${sessionId} not found in active sessions (will create new)`, LOG_MODULES.CONTEXT);
59
+ logger.debug(`Session ${sessionId} not found in persisted sessions (will create new)`, LOG_MODULES.CONTEXT);
60
60
  }
61
61
  }
62
62
  // Extract client info from headers and request body
@@ -90,11 +90,20 @@ export function extractSessionContext(request) {
90
90
  logger.debug(`Generated new sessionId: ${sessionId}`, LOG_MODULES.CONTEXT);
91
91
  }
92
92
  }
93
+ // Add consistency check before returning session information
94
+ if (sessionId && mcpSessionManager.getSessionState(sessionId)) {
95
+ const hasSessionObject = mcpSessionManager.hasSession(sessionId);
96
+ if (!hasSessionObject) {
97
+ logger.warn(`Session state exists but session object missing for ${sessionId}`, LOG_MODULES.CONTEXT);
98
+ }
99
+ }
93
100
  const sessionContext = {
94
101
  sessionId,
95
102
  clientName,
96
103
  clientVersion,
97
104
  protocolVersion,
105
+ cwd: undefined, // Will be populated from roots/list response later
106
+ project: undefined, // Will be populated from roots/list response later
98
107
  ip: request.ip,
99
108
  userAgent: headers['user-agent'],
100
109
  timestamp: Date.now()
@@ -0,0 +1,57 @@
1
+ import { Command } from 'commander';
2
+ /**
3
+ * CLI command for dynamic MCP server tool operations via API.
4
+ *
5
+ * This command provides a simplified CLI interface for interacting with MCP server tools,
6
+ * supporting four actions: list-servers, list-tools, get-tool, and call-tool. It wraps
7
+ * the HTTP API endpoints and requires the MCP Hub Lite server to be running.
8
+ *
9
+ * ## Command Format
10
+ *
11
+ * ```
12
+ * npm run server <serverName> <action> [toolName] [--args <json>] [--tags <json>]
13
+ * ```
14
+ *
15
+ * ## Supported Actions
16
+ *
17
+ * - `list-servers` - List all connected MCP servers
18
+ * - `list-tools` - List all tools from the specified server
19
+ * - `get-tool <toolName>` - Get complete schema for a specific tool
20
+ * - `call-tool <toolName>` - Call a tool on the specified server
21
+ *
22
+ * ## Options
23
+ *
24
+ * - `--args <json>` - JSON string of tool arguments (for call-tool action)
25
+ * - `--tags <json>` - JSON object of instance selection tags (call-tool only, for multi-instance servers)
26
+ *
27
+ * ## Usage Examples
28
+ *
29
+ * ```bash
30
+ * # List all connected servers
31
+ * npm run server mcp-hub-lite list-servers
32
+ *
33
+ * # List all tools from a specific server
34
+ * npm run server mcp-hub-lite list-tools
35
+ *
36
+ * # Get tool schema
37
+ * npm run server mcp-hub-lite get-tool list_tools
38
+ *
39
+ * # Call a tool with arguments
40
+ * npm run server mcp-hub-lite call-tool list_tools --args '{"serverName":"mcp-hub-lite"}'
41
+ *
42
+ * # Call a tool with tags for multi-instance selection
43
+ * npm run server baidu-search call-tool search --args '{"query":"天气"}' --tags '{"env":"prod"}'
44
+ * ```
45
+ *
46
+ * ## Error Handling
47
+ *
48
+ * - Exits with code 1 if the server is not running
49
+ * - Exits with code 1 if action is unknown
50
+ * - Exits with code 1 if toolName is required but not provided
51
+ * - Exits with code 1 if JSON parsing fails for --args or --tags
52
+ * - Exits with code 1 if the underlying API call fails
53
+ *
54
+ * @returns {Command} The configured server command instance for registration with Commander.js
55
+ */
56
+ export declare const serverCommand: Command;
57
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,eAAO,MAAM,aAAa,SAkItB,CAAC"}
@@ -0,0 +1,169 @@
1
+ import { Command } from 'commander';
2
+ import { getServerStatus } from '../server.js';
3
+ /**
4
+ * CLI command for dynamic MCP server tool operations via API.
5
+ *
6
+ * This command provides a simplified CLI interface for interacting with MCP server tools,
7
+ * supporting four actions: list-servers, list-tools, get-tool, and call-tool. It wraps
8
+ * the HTTP API endpoints and requires the MCP Hub Lite server to be running.
9
+ *
10
+ * ## Command Format
11
+ *
12
+ * ```
13
+ * npm run server <serverName> <action> [toolName] [--args <json>] [--tags <json>]
14
+ * ```
15
+ *
16
+ * ## Supported Actions
17
+ *
18
+ * - `list-servers` - List all connected MCP servers
19
+ * - `list-tools` - List all tools from the specified server
20
+ * - `get-tool <toolName>` - Get complete schema for a specific tool
21
+ * - `call-tool <toolName>` - Call a tool on the specified server
22
+ *
23
+ * ## Options
24
+ *
25
+ * - `--args <json>` - JSON string of tool arguments (for call-tool action)
26
+ * - `--tags <json>` - JSON object of instance selection tags (call-tool only, for multi-instance servers)
27
+ *
28
+ * ## Usage Examples
29
+ *
30
+ * ```bash
31
+ * # List all connected servers
32
+ * npm run server mcp-hub-lite list-servers
33
+ *
34
+ * # List all tools from a specific server
35
+ * npm run server mcp-hub-lite list-tools
36
+ *
37
+ * # Get tool schema
38
+ * npm run server mcp-hub-lite get-tool list_tools
39
+ *
40
+ * # Call a tool with arguments
41
+ * npm run server mcp-hub-lite call-tool list_tools --args '{"serverName":"mcp-hub-lite"}'
42
+ *
43
+ * # Call a tool with tags for multi-instance selection
44
+ * npm run server baidu-search call-tool search --args '{"query":"天气"}' --tags '{"env":"prod"}'
45
+ * ```
46
+ *
47
+ * ## Error Handling
48
+ *
49
+ * - Exits with code 1 if the server is not running
50
+ * - Exits with code 1 if action is unknown
51
+ * - Exits with code 1 if toolName is required but not provided
52
+ * - Exits with code 1 if JSON parsing fails for --args or --tags
53
+ * - Exits with code 1 if the underlying API call fails
54
+ *
55
+ * @returns {Command} The configured server command instance for registration with Commander.js
56
+ */
57
+ export const serverCommand = new Command('server')
58
+ .description('Manage MCP server tools via API (list-servers, list-tools, get-tool, call-tool)')
59
+ .argument('<serverName>', 'Server name to target (use "mcp-hub-lite" for system tools)')
60
+ .argument('<action>', 'Action: list-servers, list-tools, get-tool, call-tool')
61
+ .argument('[toolName]', 'Tool name (required for get-tool and call-tool actions)')
62
+ .option('--args <json>', 'JSON string of tool arguments (call-tool only)')
63
+ .option('--tags <json>', 'JSON object of instance selection tags (call-tool only, for multi-instance servers)')
64
+ .action(async (serverName, action, toolName, options) => {
65
+ try {
66
+ // Check if server is running and get connection info
67
+ const status = await getServerStatus();
68
+ if (!status.running) {
69
+ console.error('Error: MCP Hub Lite server is not running.');
70
+ console.error('Start the server with: mcp-hub-lite start');
71
+ process.exit(1);
72
+ }
73
+ const baseUrl = `http://${status.host}:${status.port}`;
74
+ switch (action) {
75
+ case 'list-servers': {
76
+ const response = await fetch(`${baseUrl}/web/hub-tools/servers`, {
77
+ headers: { Accept: 'application/json' }
78
+ });
79
+ if (!response.ok) {
80
+ throw new Error(`API error: ${response.status} ${response.statusText}`);
81
+ }
82
+ const result = await response.json();
83
+ console.log(JSON.stringify(result, null, 2));
84
+ break;
85
+ }
86
+ case 'list-tools': {
87
+ const tagsParam = options.tags ? `?tags=${encodeURIComponent(options.tags)}` : '';
88
+ const response = await fetch(`${baseUrl}/web/hub-tools/servers/${serverName}/tools${tagsParam}`, {
89
+ headers: { Accept: 'application/json' }
90
+ });
91
+ if (!response.ok) {
92
+ const error = await response.json().catch(() => ({ message: response.statusText }));
93
+ throw new Error(error.message || `API error: ${response.status}`);
94
+ }
95
+ const result = await response.json();
96
+ console.log(JSON.stringify(result, null, 2));
97
+ break;
98
+ }
99
+ case 'get-tool': {
100
+ if (!toolName) {
101
+ console.error('Error: toolName is required for get-tool action');
102
+ process.exit(1);
103
+ }
104
+ const tagsParam = options.tags ? `?tags=${encodeURIComponent(options.tags)}` : '';
105
+ const response = await fetch(`${baseUrl}/web/hub-tools/servers/${serverName}/tools/${toolName}${tagsParam}`, { headers: { Accept: 'application/json' } });
106
+ if (!response.ok) {
107
+ const error = await response.json().catch(() => ({ message: response.statusText }));
108
+ throw new Error(error.message || `API error: ${response.status}`);
109
+ }
110
+ const result = await response.json();
111
+ console.log(JSON.stringify(result, null, 2));
112
+ break;
113
+ }
114
+ case 'call-tool': {
115
+ if (!toolName) {
116
+ console.error('Error: toolName is required for call-tool action');
117
+ process.exit(1);
118
+ }
119
+ // Parse tool arguments
120
+ let toolArgs = {};
121
+ if (options.args) {
122
+ try {
123
+ toolArgs = JSON.parse(options.args);
124
+ }
125
+ catch {
126
+ console.error('Error: Invalid JSON in --args option');
127
+ process.exit(1);
128
+ }
129
+ }
130
+ // Parse tags for instance selection (call-tool only)
131
+ let requestOptions;
132
+ if (options.tags) {
133
+ try {
134
+ requestOptions = { tags: JSON.parse(options.tags) };
135
+ }
136
+ catch {
137
+ console.error('Error: Invalid JSON in --tags option');
138
+ process.exit(1);
139
+ }
140
+ }
141
+ const response = await fetch(`${baseUrl}/web/hub-tools/servers/${serverName}/tools/${toolName}/call`, {
142
+ method: 'POST',
143
+ headers: {
144
+ 'Content-Type': 'application/json',
145
+ Accept: 'application/json'
146
+ },
147
+ body: JSON.stringify({ toolArgs, requestOptions })
148
+ });
149
+ if (!response.ok) {
150
+ const error = await response.json().catch(() => ({ message: response.statusText }));
151
+ throw new Error(error.message || `API error: ${response.status}`);
152
+ }
153
+ const result = await response.json();
154
+ console.log(JSON.stringify(result, null, 2));
155
+ break;
156
+ }
157
+ default: {
158
+ console.error(`Unknown action: ${action}`);
159
+ console.error('Valid actions: list-servers, list-tools, get-tool, call-tool');
160
+ process.exit(1);
161
+ }
162
+ }
163
+ process.exit(0);
164
+ }
165
+ catch (error) {
166
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
167
+ process.exit(1);
168
+ }
169
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/gateway/gateway.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAcpE,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5D,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;;IAOpC,OAAO,CAAC,wBAAwB;IAkBhC,OAAO,CAAC,gBAAgB;IAUxB;;;;;OAKG;IACI,wBAAwB,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC;IAIvF;;;;;OAKG;IACI,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM;IAI5C;;;;;OAKG;IACI,kBAAkB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM;IAIpD;;;;OAIG;IACI,sBAAsB,IAAI,SAAS;IAI1C;;;;OAIG;IACU,KAAK;CAKnB;AAED,eAAO,MAAM,OAAO,gBAAuB,CAAC"}
1
+ {"version":3,"file":"gateway.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/gateway/gateway.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAcpE,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5D,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;;IAOpC,OAAO,CAAC,wBAAwB;IAqBhC,OAAO,CAAC,gBAAgB;IAyCxB;;;;;OAKG;IACI,wBAAwB,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC;IAIvF;;;;;OAKG;IACI,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM;IAI5C;;;;;OAKG;IACI,kBAAkB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM;IAIpD;;;;OAIG;IACI,sBAAsB,IAAI,SAAS;IAI1C;;;;OAIG;IACU,KAAK;CAKnB;AAED,eAAO,MAAM,OAAO,gBAAuB,CAAC"}
@@ -34,6 +34,7 @@ export class GatewayService {
34
34
  this.server = this.createServerWithHandlers();
35
35
  }
36
36
  createServerWithHandlers() {
37
+ logger.debug('Creating new MCP server with handlers', LOG_MODULES.GATEWAY_SERVICE);
37
38
  const server = new McpServer({
38
39
  name: MCP_HUB_LITE_SERVER,
39
40
  version: this.appVersion
@@ -43,16 +44,49 @@ export class GatewayService {
43
44
  resources: {}
44
45
  }
45
46
  });
47
+ logger.debug('MCP server created successfully', LOG_MODULES.GATEWAY_SERVICE);
46
48
  this.registerHandlers(server);
49
+ logger.debug('Handlers registered successfully on MCP server', LOG_MODULES.GATEWAY_SERVICE);
47
50
  return server;
48
51
  }
49
52
  registerHandlers(server) {
53
+ logger.debug('Registering handlers on MCP server', LOG_MODULES.GATEWAY_SERVICE);
50
54
  // Local toolMap for this connection
51
55
  const toolMap = new Map();
52
- registerInitializeHandlers(server);
53
- registerResourcesHandlers(server);
54
- registerSystemToolsHandlers(server);
55
- registerCallToolHandler(server, toolMap);
56
+ logger.debug('Created local toolMap for connection', LOG_MODULES.GATEWAY_SERVICE);
57
+ try {
58
+ registerInitializeHandlers(server);
59
+ logger.debug('Initialize handlers registered successfully', LOG_MODULES.GATEWAY_SERVICE);
60
+ }
61
+ catch (error) {
62
+ logger.error('Failed to register initialize handlers:', error, LOG_MODULES.GATEWAY_SERVICE);
63
+ throw error;
64
+ }
65
+ try {
66
+ registerResourcesHandlers(server);
67
+ logger.debug('Resources handlers registered successfully', LOG_MODULES.GATEWAY_SERVICE);
68
+ }
69
+ catch (error) {
70
+ logger.error('Failed to register resources handlers:', error, LOG_MODULES.GATEWAY_SERVICE);
71
+ throw error;
72
+ }
73
+ try {
74
+ registerSystemToolsHandlers(server);
75
+ logger.debug('System tools handlers registered successfully', LOG_MODULES.GATEWAY_SERVICE);
76
+ }
77
+ catch (error) {
78
+ logger.error('Failed to register system tools handlers:', error, LOG_MODULES.GATEWAY_SERVICE);
79
+ throw error;
80
+ }
81
+ try {
82
+ registerCallToolHandler(server, toolMap);
83
+ logger.debug('Call tool handler registered successfully', LOG_MODULES.GATEWAY_SERVICE);
84
+ }
85
+ catch (error) {
86
+ logger.error('Failed to register call tool handler:', error, LOG_MODULES.GATEWAY_SERVICE);
87
+ throw error;
88
+ }
89
+ logger.debug('All handlers registered successfully', LOG_MODULES.GATEWAY_SERVICE);
56
90
  }
57
91
  /**
58
92
  * Generates a unified list of gateway tools with proper naming and collision resolution.
@@ -1,10 +1,19 @@
1
1
  /**
2
- * Global stateless MCP transport and server.
2
+ * MCP transport factory for per-request transport instances.
3
3
  *
4
- * This module provides a shared, stateless MCP transport and server instance
5
- * that can be used across all requests without session isolation.
4
+ * This module provides a factory function to create isolated MCP transport and server instances
5
+ * for each HTTP request, ensuring proper state isolation between concurrent clients.
6
6
  */
7
7
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
8
- export declare const globalTransport: StreamableHTTPServerTransport;
9
- export declare const globalServer: import("@modelcontextprotocol/sdk/server/mcp.js").McpServer;
8
+ /**
9
+ * Creates a new MCP transport and server instance for a single request session.
10
+ * Each call returns isolated instances that should be cleaned up after the request completes.
11
+ *
12
+ * @returns {Promise<{ transport: StreamableHTTPServerTransport, server: import('@modelcontextprotocol/sdk/server/mcp.js').McpServer }>}
13
+ * Object containing the transport and server instances
14
+ */
15
+ export declare function createSessionTransport(): Promise<{
16
+ transport: StreamableHTTPServerTransport;
17
+ server: import("@modelcontextprotocol/sdk/server/mcp").McpServer;
18
+ }>;
10
19
  //# sourceMappingURL=global-transport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"global-transport.d.ts","sourceRoot":"","sources":["../../../../../src/services/gateway/global-transport.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAwCnG,eAAO,MAAM,eAAe,+BAAY,CAAC;AACzC,eAAO,MAAM,YAAY,6DAAS,CAAC"}
1
+ {"version":3,"file":"global-transport.d.ts","sourceRoot":"","sources":["../../../../../src/services/gateway/global-transport.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAMnG;;;;;;GAMG;AACH,wBAAsB,sBAAsB;;;GA+D3C"}
@@ -1,42 +1,66 @@
1
1
  /**
2
- * Global stateless MCP transport and server.
2
+ * MCP transport factory for per-request transport instances.
3
3
  *
4
- * This module provides a shared, stateless MCP transport and server instance
5
- * that can be used across all requests without session isolation.
4
+ * This module provides a factory function to create isolated MCP transport and server instances
5
+ * for each HTTP request, ensuring proper state isolation between concurrent clients.
6
6
  */
7
7
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
8
8
  import { gateway } from './gateway.service.js';
9
9
  import { logger, LOG_MODULES } from '../../utils/logger/index.js';
10
- import { getMcpCommDebugSetting } from '../../utils/json-utils.js';
10
+ import { stringifyForLogging, getMcpCommDebugSetting } from '../../utils/json-utils.js';
11
11
  import { formatMcpMessageForLogging, logNotificationMessage } from '../../utils/logger/log-output.js';
12
- // Create shared transport in STATELESS MODE - NO PARAMETERS NEEDED!
13
- const transport = new StreamableHTTPServerTransport();
14
- // Create shared server
15
- const server = gateway.createConnectionServer();
16
- // Set up message logging (use empty string for sessionId in stateless mode)
17
- transport.onmessage = (message) => {
18
- if (getMcpCommDebugSetting()) {
19
- const logMessage = formatMcpMessageForLogging(message);
20
- logger.debug(`MCP message received: ${logMessage}`, LOG_MODULES.COMMUNICATION);
21
- }
22
- logNotificationMessage(message, ''); // Empty sessionId for stateless
23
- };
24
- // Wrap send method for debug logging
25
- if (getMcpCommDebugSetting()) {
26
- const originalSend = transport.send;
27
- transport.send = async (message, options) => {
12
+ /**
13
+ * Creates a new MCP transport and server instance for a single request session.
14
+ * Each call returns isolated instances that should be cleaned up after the request completes.
15
+ *
16
+ * @returns {Promise<{ transport: StreamableHTTPServerTransport, server: import('@modelcontextprotocol/sdk/server/mcp.js').McpServer }>}
17
+ * Object containing the transport and server instances
18
+ */
19
+ export async function createSessionTransport() {
20
+ const transport = new StreamableHTTPServerTransport();
21
+ const server = gateway.createConnectionServer();
22
+ // Set up message logging (use empty string for sessionId in per-request mode)
23
+ transport.onmessage = (message) => {
24
+ logger.debug(`Session transport onmessage called with: ${stringifyForLogging(message)}`, LOG_MODULES.GATEWAY);
28
25
  try {
29
- const logMessage = formatMcpMessageForLogging(message);
30
- logger.debug(`MCP message sent: ${logMessage}`, LOG_MODULES.COMMUNICATION);
26
+ if (getMcpCommDebugSetting()) {
27
+ const logMessage = formatMcpMessageForLogging(message);
28
+ logger.debug(`MCP message received: ${logMessage}`, LOG_MODULES.COMMUNICATION);
29
+ }
30
+ logNotificationMessage(message, ''); // Empty sessionId for per-request
31
+ logger.debug(`Session transport onmessage completed successfully`, LOG_MODULES.GATEWAY);
31
32
  }
32
- catch {
33
- logger.debug(`MCP message sent: [Error formatting response]`, LOG_MODULES.COMMUNICATION);
33
+ catch (error) {
34
+ const errorMessage = error instanceof Error ? error.message : String(error);
35
+ logger.error(`Error in session transport onmessage handler: ${errorMessage}`, LOG_MODULES.GATEWAY);
36
+ logger.error(`Message that caused error: ${stringifyForLogging(message)}`, LOG_MODULES.GATEWAY);
34
37
  }
35
- return await originalSend.call(transport, message, options);
36
38
  };
39
+ // Wrap send method for debug logging
40
+ if (getMcpCommDebugSetting()) {
41
+ const originalSend = transport.send;
42
+ transport.send = async (message, options) => {
43
+ try {
44
+ const logMessage = formatMcpMessageForLogging(message);
45
+ logger.debug(`MCP message sent: ${logMessage}`, LOG_MODULES.COMMUNICATION);
46
+ }
47
+ catch {
48
+ logger.debug(`MCP message sent: [Error formatting response]`, LOG_MODULES.COMMUNICATION);
49
+ }
50
+ return await originalSend.call(transport, message, options);
51
+ };
52
+ }
53
+ // Connect server to transport
54
+ logger.debug('About to connect session server to transport', LOG_MODULES.GATEWAY);
55
+ try {
56
+ await server.connect(transport);
57
+ logger.info('MCP session transport initialized (per-request mode)', LOG_MODULES.GATEWAY);
58
+ }
59
+ catch (error) {
60
+ const errorMessage = error instanceof Error ? error.message : String(error);
61
+ logger.error(`Failed to connect session server to transport: ${errorMessage}`, LOG_MODULES.GATEWAY);
62
+ logger.error(`Transport connection error details: ${stringifyForLogging(error)}`, LOG_MODULES.GATEWAY);
63
+ throw error;
64
+ }
65
+ return { transport, server };
37
66
  }
38
- // Connect server to transport
39
- await server.connect(transport);
40
- logger.info('Global MCP transport initialized (stateless mode)', LOG_MODULES.GATEWAY);
41
- export const globalTransport = transport;
42
- export const globalServer = server;
@@ -1 +1 @@
1
- {"version":3,"file":"initialize-handler.d.ts","sourceRoot":"","sources":["../../../../../../src/services/gateway/request-handlers/initialize-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWpE;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4ClE"}
1
+ {"version":3,"file":"initialize-handler.d.ts","sourceRoot":"","sources":["../../../../../../src/services/gateway/request-handlers/initialize-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWpE;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+DlE"}
@@ -40,7 +40,18 @@ export function registerInitializeHandlers(server) {
40
40
  server.server.setRequestHandler(PingRequestSchema, async () => {
41
41
  return { pong: true };
42
42
  });
43
- server.server.setNotificationHandler(InitializedNotificationSchema, async () => {
43
+ server.server.setNotificationHandler(InitializedNotificationSchema, async (notification) => {
44
44
  logger.debug('Received initialized notification from client', LOG_MODULES.GATEWAY);
45
+ logger.debug(`Initialized notification details: ${JSON.stringify(notification)}`, LOG_MODULES.GATEWAY);
46
+ try {
47
+ // Process the notification
48
+ logger.debug('Successfully processed initialized notification', LOG_MODULES.GATEWAY);
49
+ }
50
+ catch (error) {
51
+ const errorMessage = error instanceof Error ? error.message : String(error);
52
+ logger.error(`Error processing initialized notification: ${errorMessage}`, LOG_MODULES.GATEWAY);
53
+ logger.error(`Notification that caused error: ${JSON.stringify(notification)}`, LOG_MODULES.GATEWAY);
54
+ throw error; // Re-throw to see if this is the source of the problem
55
+ }
45
56
  });
46
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tools-handler.d.ts","sourceRoot":"","sources":["../../../../../../src/services/gateway/request-handlers/tools-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAqE7D"}
1
+ {"version":3,"file":"tools-handler.d.ts","sourceRoot":"","sources":["../../../../../../src/services/gateway/request-handlers/tools-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAqE7D"}
@@ -4,7 +4,6 @@
4
4
  import { z } from 'zod';
5
5
  import { McpError } from '@modelcontextprotocol/sdk/types.js';
6
6
  import { logger } from '../../../utils/index.js';
7
- import { LOG_MODULES } from '../../../utils/logger/log-modules.js';
8
7
  import { searchCoreService } from '../../search/search-core.service.js';
9
8
  import { hubManager } from '../../hub-manager.service.js';
10
9
  /**
@@ -43,7 +42,7 @@ export function registerToolsHandlers(server) {
43
42
  filters: {}
44
43
  };
45
44
  if (filters.serverName) {
46
- const serverInstances = hubManager.getServerInstancesByName(filters.serverName);
45
+ const serverInstances = hubManager.getServerInstanceByName(filters.serverName);
47
46
  if (serverInstances.length > 0) {
48
47
  // Use the first instance's ID as filter condition
49
48
  searchOptions.filters.serverId = serverInstances[0].id;
@@ -68,11 +67,11 @@ export function registerToolsHandlers(server) {
68
67
  }
69
68
  catch (error) {
70
69
  if (error instanceof Error) {
71
- logger.error(`Search tools error:`, error, LOG_MODULES.TOOLS_HANDLER);
70
+ logger.error(`Search tools error:`, error);
72
71
  throw new McpError(-32802, `Search failed: ${error.message}`);
73
72
  }
74
73
  else {
75
- logger.error(`Search tools error:`, error, LOG_MODULES.TOOLS_HANDLER);
74
+ logger.error(`Search tools error:`, error);
76
75
  throw new McpError(-32802, `Search failed: ${String(error)}`);
77
76
  }
78
77
  }
@@ -60,16 +60,16 @@ export declare class SearchCoreService {
60
60
  *
61
61
  * This method first checks if tools are available in the cache. If cached data exists,
62
62
  * it returns the cached tools immediately. Otherwise, it fetches tools from all connected
63
- * MCP servers, applies server-level filtering based on aggregatedTools configuration,
63
+ * MCP servers, applies server-level filtering based on allowedTools configuration,
64
64
  * caches the result, and returns the filtered tools.
65
65
  *
66
66
  * @returns A promise that resolves to an array of Tool objects from all connected servers.
67
67
  *
68
68
  * @remarks
69
- * - Tools are filtered based on each server's aggregatedTools configuration
70
- * - If aggregatedTools is null or undefined, all tools from that server are included
71
- * - If aggregatedTools is an empty array, no tools from that server are included
72
- * - Tools are filtered using strict name matching against the aggregatedTools list
69
+ * - Tools are filtered based on each server's allowedTools configuration
70
+ * - If allowedTools is null or undefined, all tools from that server are included
71
+ * - If allowedTools is an empty array, no tools from that server are included
72
+ * - Tools are filtered using strict name matching against the allowedTools list
73
73
  */
74
74
  private getToolsWithCache;
75
75
  /**