@tryhamster/gerbil 1.0.0-rc.0

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 (103) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +253 -0
  3. package/bin/cli.js +2 -0
  4. package/dist/auto-update-BbNHbSU1.mjs +3 -0
  5. package/dist/browser/index.d.mts +262 -0
  6. package/dist/browser/index.d.mts.map +1 -0
  7. package/dist/browser/index.mjs +755 -0
  8. package/dist/browser/index.mjs.map +1 -0
  9. package/dist/chrome-backend-C5Un08O4.mjs +771 -0
  10. package/dist/chrome-backend-C5Un08O4.mjs.map +1 -0
  11. package/dist/chrome-backend-CtwPENIW.mjs +3 -0
  12. package/dist/chunk-Ct1HF2bE.mjs +7 -0
  13. package/dist/cli.d.mts +1 -0
  14. package/dist/cli.mjs +7078 -0
  15. package/dist/cli.mjs.map +1 -0
  16. package/dist/frameworks/express.d.mts +22 -0
  17. package/dist/frameworks/express.d.mts.map +1 -0
  18. package/dist/frameworks/express.mjs +123 -0
  19. package/dist/frameworks/express.mjs.map +1 -0
  20. package/dist/frameworks/fastify.d.mts +11 -0
  21. package/dist/frameworks/fastify.d.mts.map +1 -0
  22. package/dist/frameworks/fastify.mjs +73 -0
  23. package/dist/frameworks/fastify.mjs.map +1 -0
  24. package/dist/frameworks/hono.d.mts +14 -0
  25. package/dist/frameworks/hono.d.mts.map +1 -0
  26. package/dist/frameworks/hono.mjs +82 -0
  27. package/dist/frameworks/hono.mjs.map +1 -0
  28. package/dist/frameworks/next.d.mts +31 -0
  29. package/dist/frameworks/next.d.mts.map +1 -0
  30. package/dist/frameworks/next.mjs +116 -0
  31. package/dist/frameworks/next.mjs.map +1 -0
  32. package/dist/frameworks/react.d.mts +56 -0
  33. package/dist/frameworks/react.d.mts.map +1 -0
  34. package/dist/frameworks/react.mjs +172 -0
  35. package/dist/frameworks/react.mjs.map +1 -0
  36. package/dist/frameworks/trpc.d.mts +12 -0
  37. package/dist/frameworks/trpc.d.mts.map +1 -0
  38. package/dist/frameworks/trpc.mjs +80 -0
  39. package/dist/frameworks/trpc.mjs.map +1 -0
  40. package/dist/gerbil-BfnsFWRE.mjs +644 -0
  41. package/dist/gerbil-BfnsFWRE.mjs.map +1 -0
  42. package/dist/gerbil-BjW-z7Fq.mjs +5 -0
  43. package/dist/gerbil-DZ1k3ChC.d.mts +138 -0
  44. package/dist/gerbil-DZ1k3ChC.d.mts.map +1 -0
  45. package/dist/index.d.mts +223 -0
  46. package/dist/index.d.mts.map +1 -0
  47. package/dist/index.mjs +13 -0
  48. package/dist/index.mjs.map +1 -0
  49. package/dist/integrations/ai-sdk.d.mts +78 -0
  50. package/dist/integrations/ai-sdk.d.mts.map +1 -0
  51. package/dist/integrations/ai-sdk.mjs +199 -0
  52. package/dist/integrations/ai-sdk.mjs.map +1 -0
  53. package/dist/integrations/langchain.d.mts +41 -0
  54. package/dist/integrations/langchain.d.mts.map +1 -0
  55. package/dist/integrations/langchain.mjs +93 -0
  56. package/dist/integrations/langchain.mjs.map +1 -0
  57. package/dist/integrations/llamaindex.d.mts +45 -0
  58. package/dist/integrations/llamaindex.d.mts.map +1 -0
  59. package/dist/integrations/llamaindex.mjs +86 -0
  60. package/dist/integrations/llamaindex.mjs.map +1 -0
  61. package/dist/integrations/mcp-client.d.mts +206 -0
  62. package/dist/integrations/mcp-client.d.mts.map +1 -0
  63. package/dist/integrations/mcp-client.mjs +507 -0
  64. package/dist/integrations/mcp-client.mjs.map +1 -0
  65. package/dist/integrations/mcp.d.mts +177 -0
  66. package/dist/integrations/mcp.d.mts.map +1 -0
  67. package/dist/integrations/mcp.mjs +8 -0
  68. package/dist/mcp-R8kRLIKb.mjs +348 -0
  69. package/dist/mcp-R8kRLIKb.mjs.map +1 -0
  70. package/dist/models-DKULvhOr.mjs +136 -0
  71. package/dist/models-DKULvhOr.mjs.map +1 -0
  72. package/dist/models-De2-_GmQ.d.mts +22 -0
  73. package/dist/models-De2-_GmQ.d.mts.map +1 -0
  74. package/dist/one-liner-BUQR0nqq.mjs +98 -0
  75. package/dist/one-liner-BUQR0nqq.mjs.map +1 -0
  76. package/dist/skills/index.d.mts +390 -0
  77. package/dist/skills/index.d.mts.map +1 -0
  78. package/dist/skills/index.mjs +7 -0
  79. package/dist/skills-D3CEpgDc.mjs +630 -0
  80. package/dist/skills-D3CEpgDc.mjs.map +1 -0
  81. package/dist/tools-BsiEE6f2.mjs +567 -0
  82. package/dist/tools-BsiEE6f2.mjs.map +1 -0
  83. package/dist/types-BS1N92Jt.d.mts +183 -0
  84. package/dist/types-BS1N92Jt.d.mts.map +1 -0
  85. package/dist/utils-7vXqtq2Q.mjs +63 -0
  86. package/dist/utils-7vXqtq2Q.mjs.map +1 -0
  87. package/docs/ai-sdk.md +80 -0
  88. package/docs/architecture/README.md +84 -0
  89. package/docs/architecture/caching.md +227 -0
  90. package/docs/architecture/inference.md +176 -0
  91. package/docs/architecture/overview.md +179 -0
  92. package/docs/architecture/streaming.md +261 -0
  93. package/docs/architecture/webgpu.md +213 -0
  94. package/docs/browser.md +328 -0
  95. package/docs/cli.md +155 -0
  96. package/docs/frameworks.md +90 -0
  97. package/docs/mcp-client.md +224 -0
  98. package/docs/mcp.md +109 -0
  99. package/docs/memory.md +229 -0
  100. package/docs/repl.md +473 -0
  101. package/docs/skills.md +261 -0
  102. package/docs/tools.md +304 -0
  103. package/package.json +207 -0
@@ -0,0 +1,206 @@
1
+ //#region src/integrations/mcp-client.d.ts
2
+ /**
3
+ * Gerbil MCP Client
4
+ *
5
+ * Connect to external MCP servers and use their tools.
6
+ * Uses the official @modelcontextprotocol/sdk for protocol compliance.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { MCPClient, MCPHub } from "gerbil/mcp-client";
11
+ *
12
+ * // Connect to a single server
13
+ * const client = new MCPClient({
14
+ * name: "filesystem",
15
+ * command: "uvx",
16
+ * args: ["mcp-server-filesystem", "/tmp"]
17
+ * });
18
+ * await client.connect();
19
+ * const tools = await client.listTools();
20
+ * const result = await client.callTool("read_file", { path: "/tmp/test.txt" });
21
+ *
22
+ * // Or use the hub for multiple servers
23
+ * const hub = new MCPHub();
24
+ * await hub.addServer("filesystem", { command: "uvx", args: ["mcp-server-filesystem", "/tmp"] });
25
+ * await hub.addServer("browser", { command: "npx", args: ["-y", "@anthropic/mcp-server-puppeteer"] });
26
+ *
27
+ * // All tools from all servers are available
28
+ * const allTools = hub.getAllTools();
29
+ * ```
30
+ */
31
+ type MCPServerConfig = {
32
+ /** Command to run the MCP server */
33
+ command: string;
34
+ /** Arguments for the command */
35
+ args?: string[];
36
+ /** Environment variables */
37
+ env?: Record<string, string>;
38
+ /** Working directory */
39
+ cwd?: string;
40
+ /** Timeout for requests (ms, default: 30000) */
41
+ timeout?: number;
42
+ };
43
+ type MCPTool = {
44
+ name: string;
45
+ description?: string;
46
+ inputSchema?: {
47
+ type: string;
48
+ properties?: Record<string, any>;
49
+ required?: string[];
50
+ };
51
+ };
52
+ type MCPResource = {
53
+ uri: string;
54
+ name: string;
55
+ description?: string;
56
+ mimeType?: string;
57
+ };
58
+ /**
59
+ * Client for a single MCP server.
60
+ *
61
+ * Uses @modelcontextprotocol/sdk when available, falls back to
62
+ * a minimal stdio implementation otherwise.
63
+ */
64
+ declare class MCPClient {
65
+ private readonly config;
66
+ private client;
67
+ private transport;
68
+ private connected;
69
+ private _tools;
70
+ private _resources;
71
+ private readonly serverName;
72
+ private useFallback;
73
+ private fallbackProcess;
74
+ private fallbackRequestId;
75
+ private readonly fallbackPending;
76
+ private fallbackBuffer;
77
+ constructor(config: MCPServerConfig & {
78
+ name?: string;
79
+ });
80
+ /**
81
+ * Connect to the MCP server
82
+ */
83
+ connect(): Promise<void>;
84
+ /**
85
+ * Try to load the official MCP SDK
86
+ * Uses dynamic import to avoid bundling issues when SDK is not installed
87
+ */
88
+ private loadSDK;
89
+ /**
90
+ * Connect using the official SDK
91
+ */
92
+ private connectWithSDK;
93
+ /**
94
+ * Fallback: Connect without SDK using raw stdio
95
+ */
96
+ private connectFallback;
97
+ private processFallbackBuffer;
98
+ private fallbackRequest;
99
+ private fallbackNotify;
100
+ /**
101
+ * Disconnect from the MCP server
102
+ */
103
+ disconnect(): Promise<void>;
104
+ /**
105
+ * Refresh tools and resources from the server
106
+ */
107
+ refreshCapabilities(): Promise<void>;
108
+ /**
109
+ * List available tools
110
+ */
111
+ listTools(): MCPTool[];
112
+ /**
113
+ * List available resources
114
+ */
115
+ listResources(): MCPResource[];
116
+ /**
117
+ * Call a tool
118
+ */
119
+ callTool(name: string, args?: Record<string, any>): Promise<any>;
120
+ /**
121
+ * Read a resource
122
+ */
123
+ readResource(uri: string): Promise<string>;
124
+ /**
125
+ * Check if connected
126
+ */
127
+ isConnected(): boolean;
128
+ /**
129
+ * Get server name
130
+ */
131
+ getName(): string;
132
+ }
133
+ /**
134
+ * Hub for managing multiple MCP server connections
135
+ */
136
+ declare class MCPHub {
137
+ private readonly clients;
138
+ private readonly toolPrefix;
139
+ /**
140
+ * Add and connect to an MCP server
141
+ */
142
+ addServer(name: string, config: MCPServerConfig): Promise<MCPClient>;
143
+ /**
144
+ * Remove and disconnect an MCP server
145
+ */
146
+ removeServer(name: string): Promise<void>;
147
+ /**
148
+ * Get a specific client
149
+ */
150
+ getClient(name: string): MCPClient | undefined;
151
+ /**
152
+ * List connected servers
153
+ */
154
+ listServers(): string[];
155
+ /**
156
+ * Get all tools from all servers
157
+ */
158
+ getAllTools(): Array<{
159
+ server: string;
160
+ tool: MCPTool;
161
+ }>;
162
+ /**
163
+ * Call a tool from any connected server
164
+ * Tool name format: "server_name:tool_name" or just "tool_name" (searches all)
165
+ */
166
+ callTool(toolName: string, args?: Record<string, any>): Promise<any>;
167
+ /**
168
+ * Disconnect all servers
169
+ */
170
+ disconnectAll(): Promise<void>;
171
+ /**
172
+ * Register tools from an MCP server into Gerbil's tool registry
173
+ */
174
+ private registerServerTools;
175
+ /**
176
+ * Convert MCP JSON Schema to Zod schema (simplified)
177
+ */
178
+ private mcpSchemaToZod;
179
+ }
180
+ /**
181
+ * Get the default MCP hub (singleton)
182
+ */
183
+ declare function getMCPHub(): MCPHub;
184
+ /**
185
+ * Connect to an MCP server
186
+ */
187
+ declare function connectMCP(name: string, config: MCPServerConfig): Promise<MCPClient>;
188
+ /**
189
+ * Disconnect from an MCP server
190
+ */
191
+ declare function disconnectMCP(name: string): Promise<void>;
192
+ /**
193
+ * Call an MCP tool
194
+ */
195
+ declare function callMCPTool(toolName: string, args?: Record<string, any>): Promise<any>;
196
+ declare const _default: {
197
+ MCPClient: typeof MCPClient;
198
+ MCPHub: typeof MCPHub;
199
+ getMCPHub: typeof getMCPHub;
200
+ connectMCP: typeof connectMCP;
201
+ disconnectMCP: typeof disconnectMCP;
202
+ callMCPTool: typeof callMCPTool;
203
+ };
204
+ //#endregion
205
+ export { MCPClient, MCPHub, MCPResource, MCPServerConfig, MCPTool, callMCPTool, connectMCP, _default as default, disconnectMCP, getMCPHub };
206
+ //# sourceMappingURL=mcp-client.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-client.d.mts","names":[],"sources":["../../src/integrations/mcp-client.ts"],"sourcesContent":[],"mappings":";;AAqCA;AAiBA;AAUA;AAiBA;;;;;;;;;;;AAyUA;;;;;;;;;;;;AAmLA;AAUA;AAAuD,KAljB3C,eAAA,GAkjB2C;EAA0B;EAAR,OAAA,EAAA,MAAA;EAAO;EAO1D,IAAA,CAAA,EAAA,MAAA,EAAA;EAOA;EAErB,GAAA,CAAA,EA1jBO,MA0jBP,CAAA,MAAA,EAAA,MAAA,CAAA;;;;;;KAjjBW,OAAA;;;;;iBAKK;;;;KAKL,WAAA;;;;;;;;;;;;cAiBC,SAAA;;;;;;;;;;;;;sBAmBS;;;;;;aAWH;;;;;;;;;;;;;;;;;;;;gBAyKG;;;;yBAsBS;;;;eA6BhB;;;;mBAOI;;;;gCAOkB,sBAA2B;;;;6BAyB7B;;;;;;;;;;;;;cAwCtB,MAAA;;;;;;kCAO2B,kBAAkB,QAAQ;;;;8BAmB9B;;;;2BAWT;;;;;;;;iBAcV;;UAA8B;;;;;;oCAgBN,sBAA2B;;;;mBAyB3C;;;;;;;;;;;;;iBAuFT,SAAA,CAAA,GAAa;;;;iBAUP,UAAA,uBAAiC,kBAAkB,QAAQ;;;;iBAO3D,aAAA,gBAA6B;;;;iBAO7B,WAAA,0BAAqC,sBAAsB;cAEhF"}
@@ -0,0 +1,507 @@
1
+ import "../utils-7vXqtq2Q.mjs";
2
+ import { t as defineTool } from "../tools-BsiEE6f2.mjs";
3
+ import { z } from "zod";
4
+
5
+ //#region src/integrations/mcp-client.ts
6
+ /**
7
+ * Gerbil MCP Client
8
+ *
9
+ * Connect to external MCP servers and use their tools.
10
+ * Uses the official @modelcontextprotocol/sdk for protocol compliance.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { MCPClient, MCPHub } from "gerbil/mcp-client";
15
+ *
16
+ * // Connect to a single server
17
+ * const client = new MCPClient({
18
+ * name: "filesystem",
19
+ * command: "uvx",
20
+ * args: ["mcp-server-filesystem", "/tmp"]
21
+ * });
22
+ * await client.connect();
23
+ * const tools = await client.listTools();
24
+ * const result = await client.callTool("read_file", { path: "/tmp/test.txt" });
25
+ *
26
+ * // Or use the hub for multiple servers
27
+ * const hub = new MCPHub();
28
+ * await hub.addServer("filesystem", { command: "uvx", args: ["mcp-server-filesystem", "/tmp"] });
29
+ * await hub.addServer("browser", { command: "npx", args: ["-y", "@anthropic/mcp-server-puppeteer"] });
30
+ *
31
+ * // All tools from all servers are available
32
+ * const allTools = hub.getAllTools();
33
+ * ```
34
+ */
35
+ /**
36
+ * Client for a single MCP server.
37
+ *
38
+ * Uses @modelcontextprotocol/sdk when available, falls back to
39
+ * a minimal stdio implementation otherwise.
40
+ */
41
+ var MCPClient = class {
42
+ config;
43
+ client = null;
44
+ transport = null;
45
+ connected = false;
46
+ _tools = [];
47
+ _resources = [];
48
+ serverName;
49
+ useFallback = false;
50
+ fallbackProcess = null;
51
+ fallbackRequestId = 0;
52
+ fallbackPending = /* @__PURE__ */ new Map();
53
+ fallbackBuffer = "";
54
+ constructor(config) {
55
+ this.config = {
56
+ timeout: 3e4,
57
+ ...config
58
+ };
59
+ this.serverName = config.name || "mcp";
60
+ }
61
+ /**
62
+ * Connect to the MCP server
63
+ */
64
+ async connect() {
65
+ if (this.connected) return;
66
+ try {
67
+ const sdk = await this.loadSDK();
68
+ if (sdk) await this.connectWithSDK(sdk);
69
+ else await this.connectFallback();
70
+ this.connected = true;
71
+ await this.refreshCapabilities();
72
+ } catch (e) {
73
+ this.connected = false;
74
+ throw e;
75
+ }
76
+ }
77
+ /**
78
+ * Try to load the official MCP SDK
79
+ * Uses dynamic import to avoid bundling issues when SDK is not installed
80
+ */
81
+ async loadSDK() {
82
+ try {
83
+ const importDynamic = new Function("modulePath", "return import(modulePath)");
84
+ const clientModule = await importDynamic("@modelcontextprotocol/sdk/client");
85
+ const stdioModule = await importDynamic("@modelcontextprotocol/sdk/client/stdio");
86
+ return {
87
+ Client: clientModule.Client,
88
+ StdioClientTransport: stdioModule.StdioClientTransport
89
+ };
90
+ } catch {
91
+ return null;
92
+ }
93
+ }
94
+ /**
95
+ * Connect using the official SDK
96
+ */
97
+ async connectWithSDK(sdk) {
98
+ const { Client, StdioClientTransport } = sdk;
99
+ this.transport = new StdioClientTransport({
100
+ command: this.config.command,
101
+ args: this.config.args || [],
102
+ env: this.config.env
103
+ });
104
+ this.client = new Client({
105
+ name: "gerbil",
106
+ version: "1.0.0"
107
+ }, { capabilities: {} });
108
+ await this.client.connect(this.transport);
109
+ }
110
+ /**
111
+ * Fallback: Connect without SDK using raw stdio
112
+ */
113
+ async connectFallback() {
114
+ this.useFallback = true;
115
+ const { spawn } = await import("child_process");
116
+ this.fallbackProcess = spawn(this.config.command, this.config.args || [], {
117
+ cwd: this.config.cwd,
118
+ env: {
119
+ ...process.env,
120
+ ...this.config.env
121
+ },
122
+ stdio: [
123
+ "pipe",
124
+ "pipe",
125
+ "pipe"
126
+ ]
127
+ });
128
+ this.fallbackProcess.stdout?.on("data", (data) => {
129
+ this.fallbackBuffer += data.toString();
130
+ this.processFallbackBuffer();
131
+ });
132
+ this.fallbackProcess.on("error", (err) => {
133
+ this.connected = false;
134
+ throw new Error(`MCP server error: ${err.message}`);
135
+ });
136
+ this.fallbackProcess.on("exit", (code) => {
137
+ this.connected = false;
138
+ for (const [_, req] of this.fallbackPending) req.reject(/* @__PURE__ */ new Error(`MCP server exited with code ${code}`));
139
+ this.fallbackPending.clear();
140
+ });
141
+ await this.fallbackRequest("initialize", {
142
+ protocolVersion: "2024-11-05",
143
+ capabilities: {},
144
+ clientInfo: {
145
+ name: "gerbil",
146
+ version: "0.1.0"
147
+ }
148
+ });
149
+ this.fallbackNotify("notifications/initialized", {});
150
+ }
151
+ processFallbackBuffer() {
152
+ const lines = this.fallbackBuffer.split("\n");
153
+ this.fallbackBuffer = lines.pop() || "";
154
+ for (const line of lines) {
155
+ if (!line.trim()) continue;
156
+ try {
157
+ const response = JSON.parse(line);
158
+ if (response.id !== void 0) {
159
+ const pending = this.fallbackPending.get(response.id);
160
+ if (pending) {
161
+ this.fallbackPending.delete(response.id);
162
+ if (response.error) pending.reject(new Error(response.error.message));
163
+ else pending.resolve(response.result);
164
+ }
165
+ }
166
+ } catch {}
167
+ }
168
+ }
169
+ fallbackRequest(method, params) {
170
+ return new Promise((resolve, reject) => {
171
+ if (!this.fallbackProcess?.stdin) {
172
+ reject(/* @__PURE__ */ new Error("Not connected"));
173
+ return;
174
+ }
175
+ const id = ++this.fallbackRequestId;
176
+ const request = {
177
+ jsonrpc: "2.0",
178
+ id,
179
+ method,
180
+ params
181
+ };
182
+ const timeout = setTimeout(() => {
183
+ this.fallbackPending.delete(id);
184
+ reject(/* @__PURE__ */ new Error(`Request timeout: ${method}`));
185
+ }, this.config.timeout);
186
+ this.fallbackPending.set(id, {
187
+ resolve: (v) => {
188
+ clearTimeout(timeout);
189
+ resolve(v);
190
+ },
191
+ reject: (e) => {
192
+ clearTimeout(timeout);
193
+ reject(e);
194
+ }
195
+ });
196
+ this.fallbackProcess.stdin.write(`${JSON.stringify(request)}\n`);
197
+ });
198
+ }
199
+ fallbackNotify(method, params) {
200
+ if (!this.fallbackProcess?.stdin) return;
201
+ this.fallbackProcess.stdin.write(`${JSON.stringify({
202
+ jsonrpc: "2.0",
203
+ method,
204
+ params
205
+ })}\n`);
206
+ }
207
+ /**
208
+ * Disconnect from the MCP server
209
+ */
210
+ async disconnect() {
211
+ if (!this.connected) return;
212
+ if (this.useFallback && this.fallbackProcess) {
213
+ this.fallbackProcess.kill("SIGTERM");
214
+ this.fallbackProcess = null;
215
+ } else if (this.client) {
216
+ await this.client.close();
217
+ this.client = null;
218
+ this.transport = null;
219
+ }
220
+ this.connected = false;
221
+ this._tools = [];
222
+ this._resources = [];
223
+ }
224
+ /**
225
+ * Refresh tools and resources from the server
226
+ */
227
+ async refreshCapabilities() {
228
+ try {
229
+ if (this.useFallback) this._tools = (await this.fallbackRequest("tools/list", {})).tools || [];
230
+ else if (this.client) this._tools = (await this.client.listTools()).tools || [];
231
+ } catch {
232
+ this._tools = [];
233
+ }
234
+ try {
235
+ if (this.useFallback) this._resources = (await this.fallbackRequest("resources/list", {})).resources || [];
236
+ else if (this.client) this._resources = (await this.client.listResources()).resources || [];
237
+ } catch {
238
+ this._resources = [];
239
+ }
240
+ }
241
+ /**
242
+ * List available tools
243
+ */
244
+ listTools() {
245
+ return this._tools;
246
+ }
247
+ /**
248
+ * List available resources
249
+ */
250
+ listResources() {
251
+ return this._resources;
252
+ }
253
+ /**
254
+ * Call a tool
255
+ */
256
+ async callTool(name, args = {}) {
257
+ let result;
258
+ if (this.useFallback) result = await this.fallbackRequest("tools/call", {
259
+ name,
260
+ arguments: args
261
+ });
262
+ else if (this.client) result = await this.client.callTool({
263
+ name,
264
+ arguments: args
265
+ });
266
+ else throw new Error("Not connected");
267
+ if (result.content && Array.isArray(result.content)) return result.content.map((c) => c.text || JSON.stringify(c)).join("\n");
268
+ return result;
269
+ }
270
+ /**
271
+ * Read a resource
272
+ */
273
+ async readResource(uri) {
274
+ let result;
275
+ if (this.useFallback) result = await this.fallbackRequest("resources/read", { uri });
276
+ else if (this.client) result = await this.client.readResource({ uri });
277
+ else throw new Error("Not connected");
278
+ if (result.contents && Array.isArray(result.contents)) return result.contents.map((c) => c.text || c.blob || "").join("\n");
279
+ return typeof result === "string" ? result : JSON.stringify(result);
280
+ }
281
+ /**
282
+ * Check if connected
283
+ */
284
+ isConnected() {
285
+ return this.connected;
286
+ }
287
+ /**
288
+ * Get server name
289
+ */
290
+ getName() {
291
+ return this.serverName;
292
+ }
293
+ };
294
+ /**
295
+ * Hub for managing multiple MCP server connections
296
+ */
297
+ var MCPHub = class {
298
+ clients = /* @__PURE__ */ new Map();
299
+ toolPrefix = "mcp";
300
+ /**
301
+ * Add and connect to an MCP server
302
+ */
303
+ async addServer(name, config) {
304
+ if (this.clients.has(name)) await this.removeServer(name);
305
+ const client = new MCPClient({
306
+ ...config,
307
+ name
308
+ });
309
+ await client.connect();
310
+ this.clients.set(name, client);
311
+ this.registerServerTools(name, client);
312
+ return client;
313
+ }
314
+ /**
315
+ * Remove and disconnect an MCP server
316
+ */
317
+ async removeServer(name) {
318
+ const client = this.clients.get(name);
319
+ if (client) {
320
+ await client.disconnect();
321
+ this.clients.delete(name);
322
+ }
323
+ }
324
+ /**
325
+ * Get a specific client
326
+ */
327
+ getClient(name) {
328
+ return this.clients.get(name);
329
+ }
330
+ /**
331
+ * List connected servers
332
+ */
333
+ listServers() {
334
+ return Array.from(this.clients.keys());
335
+ }
336
+ /**
337
+ * Get all tools from all servers
338
+ */
339
+ getAllTools() {
340
+ const tools = [];
341
+ for (const [serverName, client] of this.clients) for (const tool of client.listTools()) tools.push({
342
+ server: serverName,
343
+ tool
344
+ });
345
+ return tools;
346
+ }
347
+ /**
348
+ * Call a tool from any connected server
349
+ * Tool name format: "server_name:tool_name" or just "tool_name" (searches all)
350
+ */
351
+ async callTool(toolName, args = {}) {
352
+ if (toolName.includes(":")) {
353
+ const [serverName, actualToolName] = toolName.split(":", 2);
354
+ const client = this.clients.get(serverName);
355
+ if (!client) throw new Error(`MCP server "${serverName}" not connected`);
356
+ return client.callTool(actualToolName, args);
357
+ }
358
+ for (const [_, client] of this.clients) if (client.listTools().some((t) => t.name === toolName)) return client.callTool(toolName, args);
359
+ throw new Error(`Tool "${toolName}" not found in any connected MCP server`);
360
+ }
361
+ /**
362
+ * Disconnect all servers
363
+ */
364
+ async disconnectAll() {
365
+ for (const [name] of this.clients) await this.removeServer(name);
366
+ }
367
+ /**
368
+ * Register tools from an MCP server into Gerbil's tool registry
369
+ */
370
+ registerServerTools(serverName, client) {
371
+ const tools = client.listTools();
372
+ for (const tool of tools) {
373
+ const gerbilToolName = `${this.toolPrefix}_${serverName}_${tool.name}`;
374
+ const zodSchema = this.mcpSchemaToZod(tool.inputSchema);
375
+ defineTool({
376
+ name: gerbilToolName,
377
+ description: `[MCP:${serverName}] ${tool.description || tool.name}`,
378
+ parameters: zodSchema,
379
+ execute: async (params) => {
380
+ const result = await client.callTool(tool.name, params);
381
+ return typeof result === "string" ? result : JSON.stringify(result);
382
+ }
383
+ });
384
+ }
385
+ }
386
+ /**
387
+ * Convert MCP JSON Schema to Zod schema (simplified)
388
+ */
389
+ mcpSchemaToZod(schema) {
390
+ if (!schema || schema.type !== "object") return z.object({}).passthrough();
391
+ const shape = {};
392
+ const properties = schema.properties || {};
393
+ const required = new Set(schema.required || []);
394
+ for (const [key, prop] of Object.entries(properties)) {
395
+ let zodType;
396
+ switch (prop.type) {
397
+ case "string":
398
+ zodType = z.string();
399
+ if (prop.description) zodType = zodType.describe(prop.description);
400
+ break;
401
+ case "number":
402
+ case "integer":
403
+ zodType = z.number();
404
+ break;
405
+ case "boolean":
406
+ zodType = z.boolean();
407
+ break;
408
+ case "array":
409
+ zodType = z.array(z.any());
410
+ break;
411
+ default: zodType = z.any();
412
+ }
413
+ if (!required.has(key)) zodType = zodType.optional();
414
+ shape[key] = zodType;
415
+ }
416
+ return z.object(shape).passthrough();
417
+ }
418
+ };
419
+ let defaultHub = null;
420
+ /**
421
+ * Get the default MCP hub (singleton)
422
+ */
423
+ function getMCPHub() {
424
+ if (!defaultHub) defaultHub = new MCPHub();
425
+ return defaultHub;
426
+ }
427
+ /**
428
+ * Connect to an MCP server
429
+ */
430
+ async function connectMCP(name, config) {
431
+ return getMCPHub().addServer(name, config);
432
+ }
433
+ /**
434
+ * Disconnect from an MCP server
435
+ */
436
+ async function disconnectMCP(name) {
437
+ return getMCPHub().removeServer(name);
438
+ }
439
+ /**
440
+ * Call an MCP tool
441
+ */
442
+ async function callMCPTool(toolName, args) {
443
+ return getMCPHub().callTool(toolName, args);
444
+ }
445
+ /**
446
+ * Tool for the LLM to call MCP tools
447
+ */
448
+ defineTool({
449
+ name: "mcp_call",
450
+ description: "Call a tool from a connected MCP server. Use this when you need to interact with external tools like file systems, browsers, databases, etc.",
451
+ parameters: z.object({
452
+ server: z.string().describe("The MCP server name (e.g., 'filesystem', 'browser')"),
453
+ tool: z.string().describe("The tool name to call"),
454
+ args: z.record(z.any()).optional().describe("Arguments to pass to the tool")
455
+ }),
456
+ execute: async ({ server, tool, args }) => {
457
+ const hub = getMCPHub();
458
+ const client = hub.getClient(server);
459
+ if (!client) {
460
+ const servers = hub.listServers();
461
+ if (servers.length === 0) return "No MCP servers are connected. Use the MCP settings to connect to servers first.";
462
+ return `Server "${server}" not found. Available servers: ${servers.join(", ")}`;
463
+ }
464
+ try {
465
+ const result = await client.callTool(tool, args || {});
466
+ return typeof result === "string" ? result : JSON.stringify(result, null, 2);
467
+ } catch (e) {
468
+ return `Error calling ${server}:${tool}: ${e}`;
469
+ }
470
+ }
471
+ });
472
+ /**
473
+ * Tool to list available MCP tools
474
+ */
475
+ defineTool({
476
+ name: "mcp_list",
477
+ description: "List all tools available from connected MCP servers",
478
+ parameters: z.object({ server: z.string().optional().describe("Filter by server name (optional)") }),
479
+ execute: async ({ server }) => {
480
+ const hub = getMCPHub();
481
+ if (server) {
482
+ const client = hub.getClient(server);
483
+ if (!client) return `Server "${server}" not connected`;
484
+ return client.listTools().map((t) => `- ${t.name}: ${t.description || "(no description)"}`).join("\n");
485
+ }
486
+ const allTools = hub.getAllTools();
487
+ if (allTools.length === 0) return "No MCP servers connected. Connect to MCP servers to use external tools.";
488
+ const byServer = {};
489
+ for (const { server: s, tool } of allTools) {
490
+ if (!byServer[s]) byServer[s] = [];
491
+ byServer[s].push(` - ${tool.name}: ${tool.description || "(no description)"}`);
492
+ }
493
+ return Object.entries(byServer).map(([s, tools]) => `[${s}]\n${tools.join("\n")}`).join("\n\n");
494
+ }
495
+ });
496
+ var mcp_client_default = {
497
+ MCPClient,
498
+ MCPHub,
499
+ getMCPHub,
500
+ connectMCP,
501
+ disconnectMCP,
502
+ callMCPTool
503
+ };
504
+
505
+ //#endregion
506
+ export { MCPClient, MCPHub, callMCPTool, connectMCP, mcp_client_default as default, disconnectMCP, getMCPHub };
507
+ //# sourceMappingURL=mcp-client.mjs.map