@kolisachint/hoocode-agent-core 0.4.119 → 0.4.121

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.
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-tools.js","sourceRoot":"","sources":["../../src/tools/mcp-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Headless MCP tool loader: parse a standard mcp.json file (the\n * `{ \"mcpServers\": { ... } }` format used by Claude Desktop, VS Code, and the\n * hoocode CLI), spawn the declared stdio servers, and expose their tools as\n * AgentTool instances usable by any Agent in any process.\n *\n * Spawned servers are tracked per loader call and reaped on process exit so\n * they never linger as orphans. Call closeMcpTools() to terminate them\n * earlier (tests, graceful shutdown).\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport { readFile } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport { type TObject, Type } from \"typebox\";\nimport type { AgentTool, AgentToolResult } from \"../types.js\";\n\nexport interface McpToolsServerConfig {\n\t/** Unique server identifier used as prefix for tool names. */\n\tname: string;\n\tcommand: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n}\n\ninterface McpToolDef {\n\tname: string;\n\tdescription?: string;\n\tinputSchema?: {\n\t\ttype?: string;\n\t\tproperties?: Record<string, { type?: string; description?: string }>;\n\t\trequired?: string[];\n\t};\n}\n\ninterface McpConnection {\n\trpc(method: string, params?: unknown, timeoutMs?: number): Promise<unknown>;\n\tnotify(method: string, params?: unknown): void;\n\tterminate(): void;\n}\n\n/** Timeout for the connection handshake (initialize / tools/list). Tool calls\n * themselves are left untimed since MCP tools can be long-running. */\nconst MCP_HANDSHAKE_TIMEOUT_MS = 15000;\n\nconst liveConnections = new Set<McpConnection>();\nlet exitCleanupInstalled = false;\n\n/** Kill spawned MCP servers when the host process exits so they don't linger\n * as orphans (their stdin merely goes idle, which doesn't terminate them). */\nfunction installExitCleanup(): void {\n\tif (exitCleanupInstalled) return;\n\texitCleanupInstalled = true;\n\tprocess.once(\"exit\", () => {\n\t\tcloseMcpTools();\n\t});\n}\n\n/** Terminate every MCP server spawned by loadMcpTools() in this process. */\nexport function closeMcpTools(): void {\n\tfor (const conn of liveConnections) {\n\t\ttry {\n\t\t\tconn.terminate();\n\t\t} catch {\n\t\t\t// best-effort cleanup\n\t\t}\n\t}\n\tliveConnections.clear();\n}\n\nfunction spawnMcpServer(config: McpToolsServerConfig): McpConnection {\n\tconst proc: ChildProcess = spawn(config.command, config.args ?? [], {\n\t\tenv: { ...process.env, ...(config.env ?? {}) },\n\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t});\n\n\tlet nextId = 1;\n\tconst pending = new Map<number, { resolve: (r: unknown) => void; reject: (e: Error) => void }>();\n\n\tconst rl = createInterface({ input: proc.stdout! });\n\trl.on(\"line\", (line) => {\n\t\tif (!line.trim()) return;\n\t\ttry {\n\t\t\tconst msg = JSON.parse(line) as { id?: number; result?: unknown; error?: { message: string } };\n\t\t\tif (msg.id === undefined) return;\n\t\t\tconst cb = pending.get(msg.id);\n\t\t\tif (!cb) return;\n\t\t\tpending.delete(msg.id);\n\t\t\tif (msg.error) cb.reject(new Error(msg.error.message));\n\t\t\telse cb.resolve(msg.result);\n\t\t} catch {\n\t\t\t// ignore non-JSON server startup output\n\t\t}\n\t});\n\n\tproc.on(\"exit\", () => {\n\t\tfor (const cb of pending.values()) cb.reject(new Error(`MCP server \"${config.name}\" exited unexpectedly`));\n\t\tpending.clear();\n\t});\n\n\tfunction rpc(method: string, params?: unknown, timeoutMs?: number): Promise<unknown> {\n\t\tconst id = nextId++;\n\t\treturn new Promise<unknown>((resolve, reject) => {\n\t\t\tlet timer: NodeJS.Timeout | undefined;\n\t\t\tif (timeoutMs && timeoutMs > 0) {\n\t\t\t\ttimer = setTimeout(() => {\n\t\t\t\t\tif (pending.delete(id)) {\n\t\t\t\t\t\treject(new Error(`MCP server \"${config.name}\" timed out after ${timeoutMs}ms on ${method}`));\n\t\t\t\t\t}\n\t\t\t\t}, timeoutMs);\n\t\t\t\ttimer.unref?.();\n\t\t\t}\n\t\t\tpending.set(id, {\n\t\t\t\tresolve: (r) => {\n\t\t\t\t\tif (timer) clearTimeout(timer);\n\t\t\t\t\tresolve(r);\n\t\t\t\t},\n\t\t\t\treject: (e) => {\n\t\t\t\t\tif (timer) clearTimeout(timer);\n\t\t\t\t\treject(e);\n\t\t\t\t},\n\t\t\t});\n\t\t\tproc.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", id, method, params })}\\n`);\n\t\t});\n\t}\n\n\tfunction notify(method: string, params?: unknown): void {\n\t\tproc.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", method, params })}\\n`);\n\t}\n\n\treturn {\n\t\trpc,\n\t\tnotify,\n\t\tterminate: () => {\n\t\t\trl.close();\n\t\t\tproc.kill();\n\t\t},\n\t};\n}\n\nasync function connectMcpServer(config: McpToolsServerConfig): Promise<{ conn: McpConnection; tools: McpToolDef[] }> {\n\tconst conn = spawnMcpServer(config);\n\ttry {\n\t\tawait conn.rpc(\n\t\t\t\"initialize\",\n\t\t\t{\n\t\t\t\tprotocolVersion: \"2024-11-05\",\n\t\t\t\tcapabilities: { tools: {} },\n\t\t\t\tclientInfo: { name: \"hoocode-agent-core\", version: \"1.0.0\" },\n\t\t\t},\n\t\t\tMCP_HANDSHAKE_TIMEOUT_MS,\n\t\t);\n\t\t// Per the MCP spec the client must acknowledge a successful initialize with\n\t\t// the initialized notification before issuing further requests; strict\n\t\t// servers gate tools/call on it.\n\t\tconn.notify(\"notifications/initialized\");\n\t\tconst toolsResult = (await conn.rpc(\"tools/list\", {}, MCP_HANDSHAKE_TIMEOUT_MS)) as { tools?: McpToolDef[] };\n\t\treturn { conn, tools: toolsResult.tools ?? [] };\n\t} catch (error) {\n\t\tconn.terminate();\n\t\tthrow error;\n\t}\n}\n\nfunction buildMcpSchema(tool: McpToolDef): TObject {\n\tconst props = tool.inputSchema?.properties ?? {};\n\tconst required = new Set(tool.inputSchema?.required ?? []);\n\tconst shape: Record<string, ReturnType<typeof Type.String>> = {};\n\n\tfor (const [key, prop] of Object.entries(props)) {\n\t\tlet field: ReturnType<typeof Type.String>;\n\t\tswitch (prop.type) {\n\t\t\tcase \"number\":\n\t\t\tcase \"integer\":\n\t\t\t\tfield = Type.Number({ description: prop.description }) as unknown as ReturnType<typeof Type.String>;\n\t\t\t\tbreak;\n\t\t\tcase \"boolean\":\n\t\t\t\tfield = Type.Boolean({ description: prop.description }) as unknown as ReturnType<typeof Type.String>;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tfield = Type.String({ description: prop.description });\n\t\t}\n\t\tshape[key] = required.has(key) ? field : (Type.Optional(field) as unknown as ReturnType<typeof Type.String>);\n\t}\n\n\treturn Type.Object(shape);\n}\n\nfunction createMcpAgentTool(serverName: string, conn: McpConnection, tool: McpToolDef): AgentTool<any> {\n\tconst schema = buildMcpSchema(tool);\n\treturn {\n\t\tname: `mcp_${serverName}_${tool.name}`,\n\t\tlabel: `[MCP] ${serverName} › ${tool.name}`,\n\t\tdescription: tool.description ?? `MCP tool ${tool.name} from server ${serverName}`,\n\t\tparameters: schema,\n\t\texecute: async (_toolCallId, params, signal): Promise<AgentToolResult<undefined>> => {\n\t\t\tconst abortPromise = new Promise<never>((_, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsignal?.addEventListener(\"abort\", () => reject(new Error(\"Aborted\")), { once: true });\n\t\t\t});\n\t\t\tconst result = await Promise.race([\n\t\t\t\tconn.rpc(\"tools/call\", { name: tool.name, arguments: params }),\n\t\t\t\tabortPromise,\n\t\t\t]);\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n\t\t\t\tdetails: undefined,\n\t\t\t};\n\t\t},\n\t};\n}\n\ninterface StandardMcpConfig {\n\tmcpServers?: Record<string, { command: string; args?: string[]; env?: Record<string, string> }>;\n}\n\n/**\n * Parse a standard mcp.json file, start every declared stdio server, and\n * return their tools as AgentTool instances (named `mcp_<server>_<tool>`).\n *\n * An empty or server-less config resolves to []. A missing or malformed file,\n * or a server that fails its handshake, rejects — callers decide whether MCP\n * is optional. Spawned servers are terminated automatically on process exit.\n */\nexport async function loadMcpTools(mcpJsonPath: string): Promise<AgentTool<any>[]> {\n\tconst raw = await readFile(mcpJsonPath, \"utf-8\");\n\tconst parsed = JSON.parse(raw) as StandardMcpConfig;\n\tconst servers = Object.entries(parsed.mcpServers ?? {});\n\tif (servers.length === 0) return [];\n\n\tinstallExitCleanup();\n\tconst tools: AgentTool<any>[] = [];\n\tfor (const [name, serverConfig] of servers) {\n\t\tif (!serverConfig || typeof serverConfig.command !== \"string\") {\n\t\t\tthrow new Error(`${mcpJsonPath}: mcpServers[\"${name}\"] is missing a \"command\"`);\n\t\t}\n\t\tconst { conn, tools: toolDefs } = await connectMcpServer({\n\t\t\tname,\n\t\t\tcommand: serverConfig.command,\n\t\t\targs: serverConfig.args,\n\t\t\tenv: serverConfig.env,\n\t\t});\n\t\tliveConnections.add(conn);\n\t\tfor (const toolDef of toolDefs) {\n\t\t\ttools.push(createMcpAgentTool(name, conn, toolDef));\n\t\t}\n\t}\n\treturn tools;\n}\n"]}
1
+ {"version":3,"file":"mcp-tools.js","sourceRoot":"","sources":["../../src/tools/mcp-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Headless MCP tool loader: parse a standard mcp.json file (the\n * `{ \"mcpServers\": { ... } }` format used by Claude Desktop, VS Code, and the\n * hoocode CLI), connect the declared servers — stdio (`command`), Streamable\n * HTTP (`{ \"type\": \"http\", \"url\": ... }`), or legacy SSE (`\"type\": \"sse\"`) —\n * and expose their tools as AgentTool instances usable by any Agent in any\n * process.\n *\n * Connections are tracked per loader call and reaped on process exit so\n * spawned servers never linger as orphans. Call closeMcpTools() to terminate\n * them earlier (tests, graceful shutdown).\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport { readFile } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport { type TObject, Type } from \"typebox\";\nimport type { AgentTool, AgentToolResult } from \"../types.js\";\nimport { connectHttpMcpServer, type McpRemoteOptions } from \"./mcp-http-transport.js\";\n\nexport interface McpToolsServerConfig {\n\t/** Unique server identifier used as prefix for tool names. */\n\tname: string;\n\tcommand: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n}\n\ninterface McpToolDef {\n\tname: string;\n\tdescription?: string;\n\tinputSchema?: {\n\t\ttype?: string;\n\t\tproperties?: Record<string, { type?: string; description?: string }>;\n\t\trequired?: string[];\n\t};\n}\n\ninterface McpConnection {\n\trpc(method: string, params?: unknown, timeoutMs?: number): Promise<unknown>;\n\tnotify(method: string, params?: unknown): void;\n\tterminate(): void;\n}\n\n/** Timeout for the connection handshake (initialize / tools/list). Tool calls\n * themselves are left untimed since MCP tools can be long-running. */\nconst MCP_HANDSHAKE_TIMEOUT_MS = 15000;\n\nconst liveConnections = new Set<McpConnection>();\nlet exitCleanupInstalled = false;\n\n/** Kill spawned MCP servers when the host process exits so they don't linger\n * as orphans (their stdin merely goes idle, which doesn't terminate them). */\nfunction installExitCleanup(): void {\n\tif (exitCleanupInstalled) return;\n\texitCleanupInstalled = true;\n\tprocess.once(\"exit\", () => {\n\t\tcloseMcpTools();\n\t});\n}\n\n/** Terminate every MCP server spawned by loadMcpTools() in this process. */\nexport function closeMcpTools(): void {\n\tfor (const conn of liveConnections) {\n\t\ttry {\n\t\t\tconn.terminate();\n\t\t} catch {\n\t\t\t// best-effort cleanup\n\t\t}\n\t}\n\tliveConnections.clear();\n}\n\nfunction spawnMcpServer(config: McpToolsServerConfig): McpConnection {\n\tconst proc: ChildProcess = spawn(config.command, config.args ?? [], {\n\t\tenv: { ...process.env, ...(config.env ?? {}) },\n\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t});\n\n\tlet nextId = 1;\n\tconst pending = new Map<number, { resolve: (r: unknown) => void; reject: (e: Error) => void }>();\n\n\tconst rl = createInterface({ input: proc.stdout! });\n\trl.on(\"line\", (line) => {\n\t\tif (!line.trim()) return;\n\t\ttry {\n\t\t\tconst msg = JSON.parse(line) as { id?: number; result?: unknown; error?: { message: string } };\n\t\t\tif (msg.id === undefined) return;\n\t\t\tconst cb = pending.get(msg.id);\n\t\t\tif (!cb) return;\n\t\t\tpending.delete(msg.id);\n\t\t\tif (msg.error) cb.reject(new Error(msg.error.message));\n\t\t\telse cb.resolve(msg.result);\n\t\t} catch {\n\t\t\t// ignore non-JSON server startup output\n\t\t}\n\t});\n\n\tproc.on(\"exit\", () => {\n\t\tfor (const cb of pending.values()) cb.reject(new Error(`MCP server \"${config.name}\" exited unexpectedly`));\n\t\tpending.clear();\n\t});\n\n\tfunction rpc(method: string, params?: unknown, timeoutMs?: number): Promise<unknown> {\n\t\tconst id = nextId++;\n\t\treturn new Promise<unknown>((resolve, reject) => {\n\t\t\tlet timer: NodeJS.Timeout | undefined;\n\t\t\tif (timeoutMs && timeoutMs > 0) {\n\t\t\t\ttimer = setTimeout(() => {\n\t\t\t\t\tif (pending.delete(id)) {\n\t\t\t\t\t\treject(new Error(`MCP server \"${config.name}\" timed out after ${timeoutMs}ms on ${method}`));\n\t\t\t\t\t}\n\t\t\t\t}, timeoutMs);\n\t\t\t\ttimer.unref?.();\n\t\t\t}\n\t\t\tpending.set(id, {\n\t\t\t\tresolve: (r) => {\n\t\t\t\t\tif (timer) clearTimeout(timer);\n\t\t\t\t\tresolve(r);\n\t\t\t\t},\n\t\t\t\treject: (e) => {\n\t\t\t\t\tif (timer) clearTimeout(timer);\n\t\t\t\t\treject(e);\n\t\t\t\t},\n\t\t\t});\n\t\t\tproc.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", id, method, params })}\\n`);\n\t\t});\n\t}\n\n\tfunction notify(method: string, params?: unknown): void {\n\t\tproc.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", method, params })}\\n`);\n\t}\n\n\treturn {\n\t\trpc,\n\t\tnotify,\n\t\tterminate: () => {\n\t\t\trl.close();\n\t\t\tproc.kill();\n\t\t},\n\t};\n}\n\nasync function handshake(conn: McpConnection): Promise<McpToolDef[]> {\n\tawait conn.rpc(\n\t\t\"initialize\",\n\t\t{\n\t\t\tprotocolVersion: \"2024-11-05\",\n\t\t\tcapabilities: { tools: {} },\n\t\t\tclientInfo: { name: \"hoocode-agent-core\", version: \"1.0.0\" },\n\t\t},\n\t\tMCP_HANDSHAKE_TIMEOUT_MS,\n\t);\n\t// Per the MCP spec the client must acknowledge a successful initialize with\n\t// the initialized notification before issuing further requests; strict\n\t// servers gate tools/call on it.\n\tconn.notify(\"notifications/initialized\");\n\tconst toolsResult = (await conn.rpc(\"tools/list\", {}, MCP_HANDSHAKE_TIMEOUT_MS)) as { tools?: McpToolDef[] };\n\treturn toolsResult.tools ?? [];\n}\n\nasync function connectMcpServer(config: McpToolsServerConfig): Promise<{ conn: McpConnection; tools: McpToolDef[] }> {\n\tconst conn = spawnMcpServer(config);\n\ttry {\n\t\treturn { conn, tools: await handshake(conn) };\n\t} catch (error) {\n\t\tconn.terminate();\n\t\tthrow error;\n\t}\n}\n\nfunction buildMcpSchema(tool: McpToolDef): TObject {\n\tconst props = tool.inputSchema?.properties ?? {};\n\tconst required = new Set(tool.inputSchema?.required ?? []);\n\tconst shape: Record<string, ReturnType<typeof Type.String>> = {};\n\n\tfor (const [key, prop] of Object.entries(props)) {\n\t\tlet field: ReturnType<typeof Type.String>;\n\t\tswitch (prop.type) {\n\t\t\tcase \"number\":\n\t\t\tcase \"integer\":\n\t\t\t\tfield = Type.Number({ description: prop.description }) as unknown as ReturnType<typeof Type.String>;\n\t\t\t\tbreak;\n\t\t\tcase \"boolean\":\n\t\t\t\tfield = Type.Boolean({ description: prop.description }) as unknown as ReturnType<typeof Type.String>;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tfield = Type.String({ description: prop.description });\n\t\t}\n\t\tshape[key] = required.has(key) ? field : (Type.Optional(field) as unknown as ReturnType<typeof Type.String>);\n\t}\n\n\treturn Type.Object(shape);\n}\n\nfunction createMcpAgentTool(serverName: string, conn: McpConnection, tool: McpToolDef): AgentTool<any> {\n\tconst schema = buildMcpSchema(tool);\n\treturn {\n\t\tname: `mcp_${serverName}_${tool.name}`,\n\t\tlabel: `[MCP] ${serverName} › ${tool.name}`,\n\t\tdescription: tool.description ?? `MCP tool ${tool.name} from server ${serverName}`,\n\t\tparameters: schema,\n\t\texecute: async (_toolCallId, params, signal): Promise<AgentToolResult<undefined>> => {\n\t\t\tconst abortPromise = new Promise<never>((_, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsignal?.addEventListener(\"abort\", () => reject(new Error(\"Aborted\")), { once: true });\n\t\t\t});\n\t\t\tconst result = await Promise.race([\n\t\t\t\tconn.rpc(\"tools/call\", { name: tool.name, arguments: params }),\n\t\t\t\tabortPromise,\n\t\t\t]);\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n\t\t\t\tdetails: undefined,\n\t\t\t};\n\t\t},\n\t};\n}\n\ninterface StandardMcpServerEntry {\n\tcommand?: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n\t/** \"stdio\" (default with command), \"http\" (Streamable HTTP), or \"sse\" (legacy). */\n\ttype?: string;\n\t/** Remote server URL for http/sse transports. */\n\turl?: string;\n\t/** Extra HTTP headers (e.g. Authorization) for remote transports. */\n\theaders?: Record<string, string>;\n}\n\ninterface StandardMcpConfig {\n\tmcpServers?: Record<string, StandardMcpServerEntry>;\n}\n\nasync function connectRemoteMcpServer(\n\tname: string,\n\tentry: StandardMcpServerEntry,\n\tremoteOptions?: McpRemoteOptions,\n): Promise<{ conn: McpConnection; tools: McpToolDef[] }> {\n\tconst conn = connectHttpMcpServer(\n\t\t{\n\t\t\tname,\n\t\t\turl: entry.url!,\n\t\t\theaders: entry.headers,\n\t\t\ttype: entry.type === \"sse\" ? \"sse\" : \"http\",\n\t\t},\n\t\tremoteOptions,\n\t);\n\ttry {\n\t\treturn { conn, tools: await handshake(conn) };\n\t} catch (error) {\n\t\tconn.terminate();\n\t\tthrow error;\n\t}\n}\n\n/**\n * Parse a standard mcp.json file, connect every declared server — stdio\n * (`command`) or remote (`{ \"type\": \"http\" | \"sse\", \"url\": ... }`) — and\n * return their tools as AgentTool instances (named `mcp_<server>_<tool>`).\n *\n * An empty or server-less config resolves to []. A missing or malformed file,\n * or a server that fails its handshake, rejects — callers decide whether MCP\n * is optional. Connections are terminated automatically on process exit.\n *\n * `remoteOptions` customizes remote-server behavior (OAuth storage directory,\n * browser opener, authorization timeout); see {@link McpRemoteOptions}.\n */\nexport async function loadMcpTools(mcpJsonPath: string, remoteOptions?: McpRemoteOptions): Promise<AgentTool<any>[]> {\n\tconst raw = await readFile(mcpJsonPath, \"utf-8\");\n\tconst parsed = JSON.parse(raw) as StandardMcpConfig;\n\tconst servers = Object.entries(parsed.mcpServers ?? {});\n\tif (servers.length === 0) return [];\n\n\tinstallExitCleanup();\n\tconst tools: AgentTool<any>[] = [];\n\tfor (const [name, serverConfig] of servers) {\n\t\tconst isRemote =\n\t\t\tserverConfig &&\n\t\t\t(serverConfig.type === \"http\" ||\n\t\t\t\tserverConfig.type === \"sse\" ||\n\t\t\t\t(typeof serverConfig.command !== \"string\" && typeof serverConfig.url === \"string\"));\n\t\tlet connected: { conn: McpConnection; tools: McpToolDef[] };\n\t\tif (isRemote) {\n\t\t\tif (typeof serverConfig.url !== \"string\") {\n\t\t\t\tthrow new Error(`${mcpJsonPath}: mcpServers[\"${name}\"] has type \"${serverConfig.type}\" but no \"url\"`);\n\t\t\t}\n\t\t\tconnected = await connectRemoteMcpServer(name, serverConfig, remoteOptions);\n\t\t} else {\n\t\t\tif (!serverConfig || typeof serverConfig.command !== \"string\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${mcpJsonPath}: mcpServers[\"${name}\"] is missing a \"command\" (or a \"url\" for remote servers)`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconnected = await connectMcpServer({\n\t\t\t\tname,\n\t\t\t\tcommand: serverConfig.command,\n\t\t\t\targs: serverConfig.args,\n\t\t\t\tenv: serverConfig.env,\n\t\t\t});\n\t\t}\n\t\tliveConnections.add(connected.conn);\n\t\tfor (const toolDef of connected.tools) {\n\t\t\ttools.push(createMcpAgentTool(name, connected.conn, toolDef));\n\t\t}\n\t}\n\treturn tools;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolisachint/hoocode-agent-core",
3
- "version": "0.4.119",
3
+ "version": "0.4.121",
4
4
  "description": "General-purpose agent with transport abstraction, state management, and attachment support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,7 +17,8 @@
17
17
  "prepublishOnly": "npm run clean && npm run build"
18
18
  },
19
19
  "dependencies": {
20
- "@kolisachint/hoocode-ai": "^0.4.119",
20
+ "@kolisachint/hoocode-ai": "^0.4.121",
21
+ "@modelcontextprotocol/sdk": "^1.29.0",
21
22
  "ignore": "^7.0.5",
22
23
  "typebox": "^1.1.24",
23
24
  "uuid": "^14.0.0",