agent-recorder 0.0.9 → 0.0.10

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 (79) hide show
  1. package/package.json +1 -1
  2. package/vendor/node_modules/@agent-recorder/cli/commands/configure-wrap.d.ts.map +1 -1
  3. package/vendor/node_modules/@agent-recorder/cli/commands/configure-wrap.js +5 -31
  4. package/vendor/node_modules/@agent-recorder/cli/commands/configure-wrap.js.map +1 -1
  5. package/vendor/node_modules/@agent-recorder/cli/commands/configure.d.ts +2 -0
  6. package/vendor/node_modules/@agent-recorder/cli/commands/configure.d.ts.map +1 -1
  7. package/vendor/node_modules/@agent-recorder/cli/commands/configure.js +117 -1
  8. package/vendor/node_modules/@agent-recorder/cli/commands/configure.js.map +1 -1
  9. package/vendor/node_modules/@agent-recorder/cli/commands/doctor.d.ts.map +1 -1
  10. package/vendor/node_modules/@agent-recorder/cli/commands/doctor.js +113 -19
  11. package/vendor/node_modules/@agent-recorder/cli/commands/doctor.js.map +1 -1
  12. package/vendor/node_modules/@agent-recorder/cli/commands/doctor.test.d.ts +5 -0
  13. package/vendor/node_modules/@agent-recorder/cli/commands/doctor.test.d.ts.map +1 -0
  14. package/vendor/node_modules/@agent-recorder/cli/commands/doctor.test.js +152 -0
  15. package/vendor/node_modules/@agent-recorder/cli/commands/doctor.test.js.map +1 -0
  16. package/vendor/node_modules/@agent-recorder/cli/commands/install.d.ts +7 -1
  17. package/vendor/node_modules/@agent-recorder/cli/commands/install.d.ts.map +1 -1
  18. package/vendor/node_modules/@agent-recorder/cli/commands/install.js +89 -14
  19. package/vendor/node_modules/@agent-recorder/cli/commands/install.js.map +1 -1
  20. package/vendor/node_modules/@agent-recorder/cli/commands/install.test.d.ts +5 -0
  21. package/vendor/node_modules/@agent-recorder/cli/commands/install.test.d.ts.map +1 -0
  22. package/vendor/node_modules/@agent-recorder/cli/commands/install.test.js +173 -0
  23. package/vendor/node_modules/@agent-recorder/cli/commands/install.test.js.map +1 -0
  24. package/vendor/node_modules/@agent-recorder/cli/config/hubify.d.ts +51 -0
  25. package/vendor/node_modules/@agent-recorder/cli/config/hubify.d.ts.map +1 -0
  26. package/vendor/node_modules/@agent-recorder/cli/config/hubify.js +125 -0
  27. package/vendor/node_modules/@agent-recorder/cli/config/hubify.js.map +1 -0
  28. package/vendor/node_modules/@agent-recorder/cli/config/hubify.test.d.ts +5 -0
  29. package/vendor/node_modules/@agent-recorder/cli/config/hubify.test.d.ts.map +1 -0
  30. package/vendor/node_modules/@agent-recorder/cli/config/hubify.test.js +329 -0
  31. package/vendor/node_modules/@agent-recorder/cli/config/hubify.test.js.map +1 -0
  32. package/vendor/node_modules/@agent-recorder/cli/index.js +7 -3
  33. package/vendor/node_modules/@agent-recorder/cli/index.js.map +1 -1
  34. package/vendor/node_modules/@agent-recorder/core/claude-config.d.ts +32 -0
  35. package/vendor/node_modules/@agent-recorder/core/claude-config.d.ts.map +1 -0
  36. package/vendor/node_modules/@agent-recorder/core/claude-config.js +65 -0
  37. package/vendor/node_modules/@agent-recorder/core/claude-config.js.map +1 -0
  38. package/vendor/node_modules/@agent-recorder/core/index.d.ts +3 -0
  39. package/vendor/node_modules/@agent-recorder/core/index.d.ts.map +1 -1
  40. package/vendor/node_modules/@agent-recorder/core/index.js +3 -0
  41. package/vendor/node_modules/@agent-recorder/core/index.js.map +1 -1
  42. package/vendor/node_modules/@agent-recorder/core/providers/index.d.ts +9 -0
  43. package/vendor/node_modules/@agent-recorder/core/providers/index.d.ts.map +1 -0
  44. package/vendor/node_modules/@agent-recorder/core/providers/index.js +9 -0
  45. package/vendor/node_modules/@agent-recorder/core/providers/index.js.map +1 -0
  46. package/vendor/node_modules/@agent-recorder/core/providers/io.d.ts +36 -0
  47. package/vendor/node_modules/@agent-recorder/core/providers/io.d.ts.map +1 -0
  48. package/vendor/node_modules/@agent-recorder/core/providers/io.js +88 -0
  49. package/vendor/node_modules/@agent-recorder/core/providers/io.js.map +1 -0
  50. package/vendor/node_modules/@agent-recorder/core/providers/io.test.d.ts +5 -0
  51. package/vendor/node_modules/@agent-recorder/core/providers/io.test.d.ts.map +1 -0
  52. package/vendor/node_modules/@agent-recorder/core/providers/io.test.js +248 -0
  53. package/vendor/node_modules/@agent-recorder/core/providers/io.test.js.map +1 -0
  54. package/vendor/node_modules/@agent-recorder/core/providers/types.d.ts +36 -0
  55. package/vendor/node_modules/@agent-recorder/core/providers/types.d.ts.map +1 -0
  56. package/vendor/node_modules/@agent-recorder/core/providers/types.js +6 -0
  57. package/vendor/node_modules/@agent-recorder/core/providers/types.js.map +1 -0
  58. package/vendor/node_modules/@agent-recorder/core/wrap-utils.d.ts +42 -0
  59. package/vendor/node_modules/@agent-recorder/core/wrap-utils.d.ts.map +1 -0
  60. package/vendor/node_modules/@agent-recorder/core/wrap-utils.js +80 -0
  61. package/vendor/node_modules/@agent-recorder/core/wrap-utils.js.map +1 -0
  62. package/vendor/node_modules/@agent-recorder/service/index.d.ts.map +1 -1
  63. package/vendor/node_modules/@agent-recorder/service/index.js +19 -0
  64. package/vendor/node_modules/@agent-recorder/service/index.js.map +1 -1
  65. package/vendor/node_modules/@agent-recorder/service/mcp/auto-wrap-manager.d.ts +43 -0
  66. package/vendor/node_modules/@agent-recorder/service/mcp/auto-wrap-manager.d.ts.map +1 -0
  67. package/vendor/node_modules/@agent-recorder/service/mcp/auto-wrap-manager.js +221 -0
  68. package/vendor/node_modules/@agent-recorder/service/mcp/auto-wrap-manager.js.map +1 -0
  69. package/vendor/node_modules/@agent-recorder/service/mcp/hub.test.d.ts +6 -0
  70. package/vendor/node_modules/@agent-recorder/service/mcp/hub.test.d.ts.map +1 -0
  71. package/vendor/node_modules/@agent-recorder/service/mcp/hub.test.js +319 -0
  72. package/vendor/node_modules/@agent-recorder/service/mcp/hub.test.js.map +1 -0
  73. package/vendor/node_modules/@agent-recorder/service/mcp/proxy.d.ts +1 -0
  74. package/vendor/node_modules/@agent-recorder/service/mcp/proxy.d.ts.map +1 -1
  75. package/vendor/node_modules/@agent-recorder/service/mcp/proxy.js +239 -34
  76. package/vendor/node_modules/@agent-recorder/service/mcp/proxy.js.map +1 -1
  77. package/vendor/node_modules/@agent-recorder/service/routes/events.d.ts.map +1 -1
  78. package/vendor/node_modules/@agent-recorder/service/routes/events.js +1 -0
  79. package/vendor/node_modules/@agent-recorder/service/routes/events.js.map +1 -1
@@ -9,6 +9,7 @@ import { loadConfig, openDatabase, runMigrations, getDefaultMigrationsDir, getDa
9
9
  import { createServer, startServer } from "./server.js";
10
10
  import { createMcpProxy } from "./mcp/index.js";
11
11
  import { createSessionManager } from "./session-manager.js";
12
+ import { AutoWrapManager } from "./mcp/auto-wrap-manager.js";
12
13
  export { createServer, startServer } from "./server.js";
13
14
  export { createMcpProxy } from "./mcp/index.js";
14
15
  export { createSessionManager } from "./session-manager.js";
@@ -51,6 +52,20 @@ export async function startDaemon(options = {}) {
51
52
  // Store for health endpoint
52
53
  daemonSessionId = sessionManager.sessionId;
53
54
  daemonStartedAt = startedAt;
55
+ // Initialize auto-wrap manager (fail-open: errors logged, not thrown)
56
+ let autoWrapManager = null;
57
+ try {
58
+ autoWrapManager = new AutoWrapManager({
59
+ config,
60
+ sessionId: sessionManager.sessionId,
61
+ db,
62
+ });
63
+ await autoWrapManager.initialize();
64
+ }
65
+ catch (error) {
66
+ console.error("[AutoWrap] Initialization failed:", error instanceof Error ? error.message : "Unknown error");
67
+ console.error("Continuing in manual wrap mode...");
68
+ }
54
69
  // Create and start REST API server (pass currentSessionId for /api/sessions/current)
55
70
  const app = await createServer({
56
71
  db,
@@ -89,6 +104,10 @@ export async function startDaemon(options = {}) {
89
104
  sessionManager.shutdown(status);
90
105
  await proxy.close();
91
106
  await app.close();
107
+ // Cleanup auto-wrap manager
108
+ if (autoWrapManager) {
109
+ await autoWrapManager.cleanup();
110
+ }
92
111
  db.close();
93
112
  // Clean up PID file and lock in daemon mode
94
113
  if (daemonMode) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Auto-Wrap Manager
3
+ * Automatically discovers and wraps MCP servers from Claude Code config.
4
+ * Supports URL-based servers (stdio support in later phase).
5
+ */
6
+ import type Database from "better-sqlite3";
7
+ import type { Config } from "@agent-recorder/core";
8
+ export interface AutoWrapManagerOptions {
9
+ config: Config;
10
+ sessionId: string;
11
+ db: Database.Database;
12
+ }
13
+ export declare class AutoWrapManager {
14
+ private wrappedServers;
15
+ private config;
16
+ private sessionId;
17
+ private db;
18
+ private claudeConfigPath;
19
+ private originalClaudeConfig;
20
+ constructor(options: AutoWrapManagerOptions);
21
+ /**
22
+ * Discover servers from Claude config and wrap them.
23
+ * Fail-open: logs errors but doesn't throw.
24
+ */
25
+ initialize(): Promise<void>;
26
+ /**
27
+ * Re-discover and wrap new servers (for hot-reload).
28
+ */
29
+ handleConfigChange(): Promise<void>;
30
+ /**
31
+ * Cleanup: restore config, unregister servers.
32
+ */
33
+ cleanup(): Promise<void>;
34
+ /**
35
+ * Discover MCP servers from Claude config.
36
+ */
37
+ private discoverServers;
38
+ /**
39
+ * Wrap a single URL-based MCP server.
40
+ */
41
+ private wrapUrlServer;
42
+ }
43
+ //# sourceMappingURL=auto-wrap-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-wrap-manager.d.ts","sourceRoot":"","sources":["../../src/mcp/auto-wrap-manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAsBnD,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC;CACvB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,cAAc,CAAyC;IAC/D,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,oBAAoB,CAAiB;gBAEjC,OAAO,EAAE,sBAAsB;IAM3C;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAiEjC;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAuDzC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA0B9B;;OAEG;YACW,eAAe;IAqD7B;;OAEG;YACW,aAAa;CAuD5B"}
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Auto-Wrap Manager
3
+ * Automatically discovers and wraps MCP servers from Claude Code config.
4
+ * Supports URL-based servers (stdio support in later phase).
5
+ */
6
+ import { registerUrlServer, unregisterServer, isAlreadyWrapped, detectClaudeConfig, readJsonFile, writeJsonFileAtomic, } from "@agent-recorder/core";
7
+ export class AutoWrapManager {
8
+ wrappedServers = new Map();
9
+ config;
10
+ sessionId;
11
+ db;
12
+ claudeConfigPath = null;
13
+ originalClaudeConfig = null;
14
+ constructor(options) {
15
+ this.config = options.config;
16
+ this.sessionId = options.sessionId;
17
+ this.db = options.db;
18
+ }
19
+ /**
20
+ * Discover servers from Claude config and wrap them.
21
+ * Fail-open: logs errors but doesn't throw.
22
+ */
23
+ async initialize() {
24
+ try {
25
+ // Detect Claude config
26
+ const detected = detectClaudeConfig();
27
+ if (detected.kind === "none" || !detected.path) {
28
+ console.log("[AutoWrap] No Claude Code config found - skipping auto-wrap");
29
+ return;
30
+ }
31
+ this.claudeConfigPath = detected.path;
32
+ console.log(`[AutoWrap] Found Claude config: ${detected.path}`);
33
+ // Read and backup original config
34
+ const configData = readJsonFile(this.claudeConfigPath);
35
+ if (!configData) {
36
+ console.error("[AutoWrap] Could not read Claude config - skipping");
37
+ return;
38
+ }
39
+ this.originalClaudeConfig = structuredClone(configData);
40
+ // Discover servers
41
+ const discovered = await this.discoverServers(configData);
42
+ console.log(`[AutoWrap] Discovered ${discovered.url.size} URL server(s), ${discovered.stdio.size} stdio server(s)`);
43
+ // Wrap URL servers
44
+ let wrappedCount = 0;
45
+ for (const [key, url] of discovered.url.entries()) {
46
+ try {
47
+ await this.wrapUrlServer(key, url);
48
+ wrappedCount++;
49
+ }
50
+ catch (error) {
51
+ console.error(`[AutoWrap] Failed to wrap server "${key}":`, error instanceof Error ? error.message : "Unknown error");
52
+ }
53
+ }
54
+ if (wrappedCount > 0) {
55
+ console.log(`[AutoWrap] Successfully wrapped ${wrappedCount} server(s)`);
56
+ }
57
+ // TODO: Wrap stdio servers (later phase)
58
+ if (discovered.stdio.size > 0) {
59
+ console.log(`[AutoWrap] Skipping ${discovered.stdio.size} stdio server(s) (not yet supported)`);
60
+ }
61
+ }
62
+ catch (error) {
63
+ console.error("[AutoWrap] Initialization failed:", error instanceof Error ? error.message : "Unknown error");
64
+ console.error("Continuing in manual wrap mode...");
65
+ }
66
+ }
67
+ /**
68
+ * Re-discover and wrap new servers (for hot-reload).
69
+ */
70
+ async handleConfigChange() {
71
+ console.log("[AutoWrap] Config change detected - re-wrapping...");
72
+ try {
73
+ if (!this.claudeConfigPath) {
74
+ console.error("[AutoWrap] No config path - cannot reload");
75
+ return;
76
+ }
77
+ // Read updated config
78
+ const configData = readJsonFile(this.claudeConfigPath);
79
+ if (!configData) {
80
+ console.error("[AutoWrap] Could not read updated config");
81
+ return;
82
+ }
83
+ // Discover servers
84
+ const discovered = await this.discoverServers(configData);
85
+ // Find new servers (not already wrapped)
86
+ const newServers = new Map();
87
+ for (const [key, url] of discovered.url.entries()) {
88
+ if (!this.wrappedServers.has(key)) {
89
+ newServers.set(key, url);
90
+ }
91
+ }
92
+ if (newServers.size === 0) {
93
+ console.log("[AutoWrap] No new servers to wrap");
94
+ return;
95
+ }
96
+ // Wrap new servers
97
+ let wrappedCount = 0;
98
+ for (const [key, url] of newServers.entries()) {
99
+ try {
100
+ await this.wrapUrlServer(key, url);
101
+ wrappedCount++;
102
+ }
103
+ catch (error) {
104
+ console.error(`[AutoWrap] Failed to wrap new server "${key}":`, error instanceof Error ? error.message : "Unknown error");
105
+ }
106
+ }
107
+ console.log(`[AutoWrap] Wrapped ${wrappedCount} new server(s)`);
108
+ }
109
+ catch (error) {
110
+ console.error("[AutoWrap] Config reload failed:", error instanceof Error ? error.message : "Unknown error");
111
+ }
112
+ }
113
+ /**
114
+ * Cleanup: restore config, unregister servers.
115
+ */
116
+ async cleanup() {
117
+ try {
118
+ console.log("[AutoWrap] Cleaning up...");
119
+ // Unregister all wrapped servers
120
+ for (const [key, server] of this.wrappedServers.entries()) {
121
+ if (server.type === "url") {
122
+ unregisterServer(key, this.config.upstreamsPath);
123
+ }
124
+ }
125
+ // Restore original Claude config
126
+ if (this.claudeConfigPath && this.originalClaudeConfig) {
127
+ writeJsonFileAtomic(this.claudeConfigPath, this.originalClaudeConfig);
128
+ console.log("[AutoWrap] Restored original Claude config");
129
+ }
130
+ this.wrappedServers.clear();
131
+ }
132
+ catch (error) {
133
+ console.error("[AutoWrap] Cleanup failed:", error instanceof Error ? error.message : "Unknown error");
134
+ }
135
+ }
136
+ /**
137
+ * Discover MCP servers from Claude config.
138
+ */
139
+ async discoverServers(configData) {
140
+ const url = new Map();
141
+ const stdio = new Map();
142
+ if (!configData ||
143
+ typeof configData !== "object" ||
144
+ Array.isArray(configData)) {
145
+ return { url, stdio };
146
+ }
147
+ const config = configData;
148
+ const mcpServers = config.mcpServers;
149
+ if (!mcpServers ||
150
+ typeof mcpServers !== "object" ||
151
+ Array.isArray(mcpServers)) {
152
+ return { url, stdio };
153
+ }
154
+ const servers = mcpServers;
155
+ for (const [key, entry] of Object.entries(servers)) {
156
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
157
+ continue;
158
+ }
159
+ const serverEntry = entry;
160
+ // URL-based server
161
+ if (typeof serverEntry.url === "string") {
162
+ url.set(key, serverEntry.url);
163
+ continue;
164
+ }
165
+ // Command-based server (stdio)
166
+ if (typeof serverEntry.command === "string") {
167
+ const args = Array.isArray(serverEntry.args)
168
+ ? serverEntry.args
169
+ : [];
170
+ stdio.set(key, { command: serverEntry.command, args });
171
+ continue;
172
+ }
173
+ }
174
+ return { url, stdio };
175
+ }
176
+ /**
177
+ * Wrap a single URL-based MCP server.
178
+ */
179
+ async wrapUrlServer(key, url) {
180
+ // Check if already wrapped
181
+ if (isAlreadyWrapped(key, this.config.upstreamsPath)) {
182
+ console.log(`[AutoWrap] Server "${key}" already wrapped - skipping`);
183
+ return;
184
+ }
185
+ // Register in upstreams registry
186
+ const proxyUrl = registerUrlServer(key, url, this.config.upstreamsPath, this.config.mcpProxyPort);
187
+ // Update Claude config to use proxy URL
188
+ if (!this.claudeConfigPath) {
189
+ throw new Error("Claude config path not set");
190
+ }
191
+ const configData = readJsonFile(this.claudeConfigPath);
192
+ if (!configData) {
193
+ throw new Error("Could not read Claude config");
194
+ }
195
+ const config = configData;
196
+ const mcpServers = config.mcpServers;
197
+ const serverEntry = mcpServers[key];
198
+ // Update URL to proxy
199
+ const newEntry = {
200
+ ...serverEntry,
201
+ url: proxyUrl,
202
+ };
203
+ const newConfig = {
204
+ ...config,
205
+ mcpServers: {
206
+ ...mcpServers,
207
+ [key]: newEntry,
208
+ },
209
+ };
210
+ // Write updated config atomically
211
+ writeJsonFileAtomic(this.claudeConfigPath, newConfig);
212
+ // Track wrapped server
213
+ this.wrappedServers.set(key, {
214
+ key,
215
+ type: "url",
216
+ originalUrl: url,
217
+ });
218
+ console.log(`[AutoWrap] Wrapped "${key}": ${url} -> ${proxyUrl}`);
219
+ }
220
+ }
221
+ //# sourceMappingURL=auto-wrap-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-wrap-manager.js","sourceRoot":"","sources":["../../src/mcp/auto-wrap-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Tests for MCP Hub mode.
3
+ * Verifies tools/list aggregation and tools/call routing with multiple providers.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=hub.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hub.test.d.ts","sourceRoot":"","sources":["../../src/mcp/hub.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,319 @@
1
+ /**
2
+ * Tests for MCP Hub mode.
3
+ * Verifies tools/list aggregation and tools/call routing with multiple providers.
4
+ */
5
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
6
+ import Fastify, {} from "fastify";
7
+ import { loadConfig, openMemoryDatabase, runMigrations, writeProvidersFile, getDefaultProvidersPath, } from "@agent-recorder/core";
8
+ import { createMcpProxy } from "./proxy.js";
9
+ import * as fs from "node:fs";
10
+ import { join, dirname } from "node:path";
11
+ import { fileURLToPath } from "node:url";
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = dirname(__filename);
14
+ /**
15
+ * Create a mock MCP server that responds to tools/list and tools/call.
16
+ */
17
+ async function createMockMcpServer(port, tools) {
18
+ const app = Fastify({ logger: false });
19
+ // Mock tools/list endpoint
20
+ app.post("/", async (request, reply) => {
21
+ const body = request.body;
22
+ if (body.method === "tools/list") {
23
+ return reply.code(200).send({
24
+ jsonrpc: "2.0",
25
+ result: {
26
+ tools: tools.map((t) => ({
27
+ name: t.name,
28
+ description: t.description,
29
+ inputSchema: { type: "object", properties: {} },
30
+ })),
31
+ },
32
+ id: body.id ?? null,
33
+ });
34
+ }
35
+ if (body.method === "tools/call") {
36
+ const params = body.params;
37
+ const tool = tools.find((t) => t.name === params.name);
38
+ if (!tool) {
39
+ return reply.code(200).send({
40
+ jsonrpc: "2.0",
41
+ error: {
42
+ code: -32602,
43
+ message: `Unknown tool: ${params.name}`,
44
+ },
45
+ id: body.id ?? null,
46
+ });
47
+ }
48
+ return reply.code(200).send({
49
+ jsonrpc: "2.0",
50
+ result: { success: true, tool: params.name },
51
+ id: body.id ?? null,
52
+ });
53
+ }
54
+ return reply.code(400).send({
55
+ jsonrpc: "2.0",
56
+ error: { code: -32601, message: "Method not found" },
57
+ id: body.id ?? null,
58
+ });
59
+ });
60
+ await app.listen({ port, host: "127.0.0.1" });
61
+ return {
62
+ app,
63
+ close: async () => {
64
+ await app.close();
65
+ },
66
+ };
67
+ }
68
+ describe("MCP Hub Mode", () => {
69
+ let db;
70
+ let sessionId;
71
+ let mockServer1;
72
+ let mockServer2;
73
+ beforeEach(async () => {
74
+ // Create in-memory database with migrations
75
+ db = openMemoryDatabase();
76
+ const migrationsDir = join(__dirname, "..", "..", "..", "core", "migrations");
77
+ runMigrations(db, migrationsDir);
78
+ // Create session
79
+ sessionId = "test-session-hub";
80
+ db.prepare("INSERT INTO sessions (id, started_at, status, created_at) VALUES (?, datetime('now'), ?, datetime('now'))").run(sessionId, "active");
81
+ // Start mock MCP servers
82
+ mockServer1 = await createMockMcpServer(9991, [
83
+ { name: "echo", description: "Echo tool" },
84
+ { name: "uppercase", description: "Uppercase tool" },
85
+ ]);
86
+ mockServer2 = await createMockMcpServer(9992, [
87
+ { name: "reverse", description: "Reverse tool" },
88
+ { name: "lowercase", description: "Lowercase tool" },
89
+ ]);
90
+ });
91
+ afterEach(async () => {
92
+ if (mockServer1)
93
+ await mockServer1.close();
94
+ if (mockServer2)
95
+ await mockServer2.close();
96
+ if (db)
97
+ db.close();
98
+ });
99
+ it("aggregates tools/list from multiple providers with namespacing", async () => {
100
+ // Write providers BEFORE creating proxy so it loads them during init
101
+ writeProvidersFile({
102
+ version: 1,
103
+ providers: [
104
+ { id: "server1", type: "http", url: "http://127.0.0.1:9991/" },
105
+ { id: "server2", type: "http", url: "http://127.0.0.1:9992/" },
106
+ ],
107
+ }, getDefaultProvidersPath());
108
+ const config = loadConfig();
109
+ const { app, close } = await createMcpProxy({
110
+ db,
111
+ config: {
112
+ ...config,
113
+ // Override providers path for test
114
+ mcpProxyPort: 19991,
115
+ },
116
+ sessionId,
117
+ });
118
+ try {
119
+ await app.listen({ port: 19991, host: "127.0.0.1" });
120
+ // Call tools/list
121
+ const response = await fetch("http://127.0.0.1:19991/", {
122
+ method: "POST",
123
+ headers: { "Content-Type": "application/json" },
124
+ body: JSON.stringify({
125
+ jsonrpc: "2.0",
126
+ method: "tools/list",
127
+ id: 1,
128
+ }),
129
+ });
130
+ expect(response.status).toBe(200);
131
+ const data = (await response.json());
132
+ const tools = data.result.tools;
133
+ // Verify namespaced tool names from both providers
134
+ expect(tools).toHaveLength(4);
135
+ const toolNames = tools.map((t) => t.name).sort();
136
+ expect(toolNames).toEqual([
137
+ "server1.echo",
138
+ "server1.uppercase",
139
+ "server2.lowercase",
140
+ "server2.reverse",
141
+ ]);
142
+ }
143
+ finally {
144
+ await close();
145
+ // Cleanup providers file
146
+ if (fs.existsSync(getDefaultProvidersPath())) {
147
+ fs.unlinkSync(getDefaultProvidersPath());
148
+ }
149
+ }
150
+ });
151
+ it("routes tools/call to correct provider and records with upstreamKey", async () => {
152
+ // Write providers BEFORE creating proxy so it loads them during init
153
+ writeProvidersFile({
154
+ version: 1,
155
+ providers: [
156
+ { id: "server1", type: "http", url: "http://127.0.0.1:9991/" },
157
+ { id: "server2", type: "http", url: "http://127.0.0.1:9992/" },
158
+ ],
159
+ }, getDefaultProvidersPath());
160
+ const config = loadConfig();
161
+ const { app, close } = await createMcpProxy({
162
+ db,
163
+ config: {
164
+ ...config,
165
+ mcpProxyPort: 19992,
166
+ },
167
+ sessionId,
168
+ });
169
+ try {
170
+ await app.listen({ port: 19992, host: "127.0.0.1" });
171
+ // Call namespaced tool from server1
172
+ const response1 = await fetch("http://127.0.0.1:19992/", {
173
+ method: "POST",
174
+ headers: { "Content-Type": "application/json" },
175
+ body: JSON.stringify({
176
+ jsonrpc: "2.0",
177
+ method: "tools/call",
178
+ params: { name: "server1.echo", arguments: { text: "hello" } },
179
+ id: 2,
180
+ }),
181
+ });
182
+ expect(response1.status).toBe(200);
183
+ const data1 = (await response1.json());
184
+ expect(data1.result.tool).toBe("echo"); // Tool name without namespace
185
+ // Call namespaced tool from server2
186
+ const response2 = await fetch("http://127.0.0.1:19992/", {
187
+ method: "POST",
188
+ headers: { "Content-Type": "application/json" },
189
+ body: JSON.stringify({
190
+ jsonrpc: "2.0",
191
+ method: "tools/call",
192
+ params: { name: "server2.reverse", arguments: { text: "world" } },
193
+ id: 3,
194
+ }),
195
+ });
196
+ expect(response2.status).toBe(200);
197
+ const data2 = (await response2.json());
198
+ expect(data2.result.tool).toBe("reverse");
199
+ // Verify events recorded with correct upstreamKey
200
+ const events = db
201
+ .prepare("SELECT * FROM events WHERE session_id = ? ORDER BY sequence ASC")
202
+ .all(sessionId);
203
+ expect(events).toHaveLength(2);
204
+ // First event: server1.echo -> routed to server1
205
+ expect(events[0].tool_name).toBe("echo");
206
+ expect(events[0].upstream_key).toBe("server1");
207
+ expect(events[0].status).toBe("success");
208
+ // Second event: server2.reverse -> routed to server2
209
+ expect(events[1].tool_name).toBe("reverse");
210
+ expect(events[1].upstream_key).toBe("server2");
211
+ expect(events[1].status).toBe("success");
212
+ }
213
+ finally {
214
+ await close();
215
+ if (fs.existsSync(getDefaultProvidersPath())) {
216
+ fs.unlinkSync(getDefaultProvidersPath());
217
+ }
218
+ }
219
+ });
220
+ it("handles unknown provider gracefully", async () => {
221
+ // Write providers BEFORE creating proxy so it loads them during init
222
+ writeProvidersFile({
223
+ version: 1,
224
+ providers: [
225
+ { id: "server1", type: "http", url: "http://127.0.0.1:9991/" },
226
+ ],
227
+ }, getDefaultProvidersPath());
228
+ const config = loadConfig();
229
+ const { app, close } = await createMcpProxy({
230
+ db,
231
+ config: {
232
+ ...config,
233
+ mcpProxyPort: 19993,
234
+ },
235
+ sessionId,
236
+ });
237
+ try {
238
+ await app.listen({ port: 19993, host: "127.0.0.1" });
239
+ // Call tool with unknown provider ID
240
+ const response = await fetch("http://127.0.0.1:19993/", {
241
+ method: "POST",
242
+ headers: { "Content-Type": "application/json" },
243
+ body: JSON.stringify({
244
+ jsonrpc: "2.0",
245
+ method: "tools/call",
246
+ params: { name: "unknown.tool", arguments: {} },
247
+ id: 4,
248
+ }),
249
+ });
250
+ expect(response.status).toBe(404);
251
+ const data = (await response.json());
252
+ expect(data.error.message).toContain("Unknown provider");
253
+ expect(data.error.data.category).toBe("downstream_unreachable");
254
+ // Verify error event recorded
255
+ const events = db
256
+ .prepare("SELECT * FROM events WHERE session_id = ?")
257
+ .all(sessionId);
258
+ expect(events).toHaveLength(1);
259
+ expect(events[0].tool_name).toBe("tool");
260
+ expect(events[0].upstream_key).toBe("unknown");
261
+ expect(events[0].status).toBe("error");
262
+ expect(events[0].error_category).toBe("downstream_unreachable");
263
+ }
264
+ finally {
265
+ await close();
266
+ if (fs.existsSync(getDefaultProvidersPath())) {
267
+ fs.unlinkSync(getDefaultProvidersPath());
268
+ }
269
+ }
270
+ });
271
+ it("handles provider failure during tools/list gracefully", async () => {
272
+ // Write providers BEFORE creating proxy so it loads them during init
273
+ // Include one unreachable provider
274
+ writeProvidersFile({
275
+ version: 1,
276
+ providers: [
277
+ { id: "server1", type: "http", url: "http://127.0.0.1:9991/" },
278
+ { id: "unreachable", type: "http", url: "http://127.0.0.1:19999/" },
279
+ ],
280
+ }, getDefaultProvidersPath());
281
+ const config = loadConfig();
282
+ const { app, close } = await createMcpProxy({
283
+ db,
284
+ config: {
285
+ ...config,
286
+ mcpProxyPort: 19994,
287
+ debugProxy: true, // Enable debug logging for failure test
288
+ },
289
+ sessionId,
290
+ });
291
+ try {
292
+ await app.listen({ port: 19994, host: "127.0.0.1" });
293
+ // Call tools/list - should return tools from server1 only
294
+ const response = await fetch("http://127.0.0.1:19994/", {
295
+ method: "POST",
296
+ headers: { "Content-Type": "application/json" },
297
+ body: JSON.stringify({
298
+ jsonrpc: "2.0",
299
+ method: "tools/list",
300
+ id: 5,
301
+ }),
302
+ });
303
+ expect(response.status).toBe(200);
304
+ const data = (await response.json());
305
+ const tools = data.result.tools;
306
+ // Should only have tools from server1 (unreachable provider omitted)
307
+ expect(tools).toHaveLength(2);
308
+ const toolNames = tools.map((t) => t.name).sort();
309
+ expect(toolNames).toEqual(["server1.echo", "server1.uppercase"]);
310
+ }
311
+ finally {
312
+ await close();
313
+ if (fs.existsSync(getDefaultProvidersPath())) {
314
+ fs.unlinkSync(getDefaultProvidersPath());
315
+ }
316
+ }
317
+ });
318
+ });
319
+ //# sourceMappingURL=hub.test.js.map