toolcall 0.0.3 → 0.1.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.
package/README.md ADDED
@@ -0,0 +1,419 @@
1
+ # toolcall
2
+
3
+ Create MCP (Model Context Protocol) servers with zero boilerplate.
4
+
5
+ [![npm version](https://badge.fury.io/js/toolcall.svg)](https://www.npmjs.com/package/toolcall)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Features
9
+
10
+ - **Minimal API** - Just two functions: `serve()` and `tool()`
11
+ - **Type-safe** - Full TypeScript support with Zod schema validation
12
+ - **Multiple transports** - Supports both stdio and HTTP
13
+ - **MCP compliant** - Implements MCP protocol version `2024-11-05`
14
+ - **Client included** - Connect to any MCP server programmatically
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install toolcall zod
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ Create an MCP server in just a few lines:
25
+
26
+ ```typescript
27
+ import { serve, tool } from 'toolcall'
28
+ import { z } from 'zod'
29
+
30
+ serve({
31
+ name: 'my-server',
32
+ version: '1.0.0',
33
+ tools: {
34
+ greet: tool({
35
+ description: 'Greet someone by name',
36
+ parameters: z.object({
37
+ name: z.string().describe('The name of the person to greet')
38
+ }),
39
+ execute: ({ name }) => `Hello, ${name}!`
40
+ }),
41
+
42
+ add: tool({
43
+ description: 'Add two numbers',
44
+ parameters: z.object({
45
+ a: z.number().describe('First number'),
46
+ b: z.number().describe('Second number')
47
+ }),
48
+ execute: ({ a, b }) => ({ result: a + b })
49
+ })
50
+ }
51
+ })
52
+ ```
53
+
54
+ Run it:
55
+
56
+ ```bash
57
+ npx tsx server.ts
58
+ ```
59
+
60
+ ## Claude Code Integration
61
+
62
+ toolcall servers integrate seamlessly with [Claude Code](https://docs.anthropic.com/en/docs/claude-code). Add your server to Claude Code's MCP configuration:
63
+
64
+ ### 1. Create your server file
65
+
66
+ ```typescript
67
+ // my-tools.ts
68
+ import { serve, tool } from 'toolcall'
69
+ import { z } from 'zod'
70
+
71
+ serve({
72
+ name: 'my-tools',
73
+ tools: {
74
+ get_weather: tool({
75
+ description: 'Get current weather for a city',
76
+ parameters: z.object({
77
+ city: z.string().describe('City name'),
78
+ unit: z.enum(['celsius', 'fahrenheit']).default('celsius')
79
+ }),
80
+ execute: async ({ city, unit }) => {
81
+ // Your implementation here
82
+ return { city, temperature: 22, unit, condition: 'sunny' }
83
+ }
84
+ })
85
+ }
86
+ })
87
+ ```
88
+
89
+ ### 2. Configure Claude Code
90
+
91
+ Add to your Claude Code MCP settings (`~/.claude/claude_desktop_config.json` or via Claude Code settings):
92
+
93
+ ```json
94
+ {
95
+ "mcpServers": {
96
+ "my-tools": {
97
+ "command": "npx",
98
+ "args": ["tsx", "/path/to/my-tools.ts"]
99
+ }
100
+ }
101
+ }
102
+ ```
103
+
104
+ Or if you've compiled your TypeScript:
105
+
106
+ ```json
107
+ {
108
+ "mcpServers": {
109
+ "my-tools": {
110
+ "command": "node",
111
+ "args": ["/path/to/my-tools.js"]
112
+ }
113
+ }
114
+ }
115
+ ```
116
+
117
+ ### 3. Use in Claude Code
118
+
119
+ Once configured, Claude Code will automatically discover your tools. You can ask Claude to use them:
120
+
121
+ > "Use my get_weather tool to check the weather in Tokyo"
122
+
123
+ ## API Reference
124
+
125
+ ### `serve(options)`
126
+
127
+ Creates and starts an MCP server.
128
+
129
+ ```typescript
130
+ serve({
131
+ name: 'my-server', // Server name (default: 'toolcall-server')
132
+ version: '1.0.0', // Server version (default: '1.0.0')
133
+ transport: 'stdio', // Transport type: 'stdio' | 'http' (default: 'stdio')
134
+ port: 3000, // Port for HTTP transport (default: 3000)
135
+ tools: { // Tool definitions
136
+ // ... your tools
137
+ }
138
+ })
139
+ ```
140
+
141
+ ### `tool(definition)`
142
+
143
+ Defines a type-safe tool with Zod schema validation.
144
+
145
+ ```typescript
146
+ tool({
147
+ description: 'Tool description shown to clients',
148
+ parameters: z.object({
149
+ // Zod schema for parameters
150
+ }),
151
+ execute: async (params) => {
152
+ // Tool implementation
153
+ // Can return string, object, or any JSON-serializable value
154
+ }
155
+ })
156
+ ```
157
+
158
+ ### Parameter Types
159
+
160
+ toolcall supports all Zod types:
161
+
162
+ ```typescript
163
+ import { z } from 'zod'
164
+
165
+ // Strings
166
+ z.string()
167
+ z.string().min(1).max(100)
168
+ z.string().email()
169
+ z.string().url()
170
+
171
+ // Numbers
172
+ z.number()
173
+ z.number().min(0).max(100)
174
+ z.number().int()
175
+
176
+ // Booleans
177
+ z.boolean()
178
+
179
+ // Enums
180
+ z.enum(['option1', 'option2', 'option3'])
181
+
182
+ // Arrays
183
+ z.array(z.string())
184
+
185
+ // Optional with defaults
186
+ z.string().optional()
187
+ z.number().default(10)
188
+
189
+ // Descriptions (shown in tool schema)
190
+ z.string().describe('Parameter description')
191
+ ```
192
+
193
+ ### Return Values
194
+
195
+ Tools can return any JSON-serializable value:
196
+
197
+ ```typescript
198
+ // String return
199
+ execute: ({ name }) => `Hello, ${name}!`
200
+
201
+ // Object return (automatically JSON-stringified)
202
+ execute: ({ a, b }) => ({ result: a + b, operation: 'addition' })
203
+
204
+ // Async operations
205
+ execute: async ({ url }) => {
206
+ const response = await fetch(url)
207
+ return await response.json()
208
+ }
209
+ ```
210
+
211
+ ## Transports
212
+
213
+ ### Stdio (Default)
214
+
215
+ The stdio transport reads JSON-RPC messages from stdin and writes responses to stdout. This is the standard transport for MCP servers used by Claude Code and other MCP clients.
216
+
217
+ ```typescript
218
+ serve({
219
+ transport: 'stdio', // or omit - stdio is default
220
+ tools: { /* ... */ }
221
+ })
222
+ ```
223
+
224
+ ### HTTP
225
+
226
+ The HTTP transport creates an HTTP server that accepts JSON-RPC POST requests.
227
+
228
+ ```typescript
229
+ serve({
230
+ transport: 'http',
231
+ port: 3000,
232
+ tools: { /* ... */ }
233
+ })
234
+ ```
235
+
236
+ Test with curl:
237
+
238
+ ```bash
239
+ # Initialize
240
+ curl -X POST http://localhost:3000 \
241
+ -H "Content-Type: application/json" \
242
+ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{}}}'
243
+
244
+ # List tools
245
+ curl -X POST http://localhost:3000 \
246
+ -H "Content-Type: application/json" \
247
+ -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
248
+
249
+ # Call a tool
250
+ curl -X POST http://localhost:3000 \
251
+ -H "Content-Type: application/json" \
252
+ -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"greet","arguments":{"name":"World"}}}'
253
+ ```
254
+
255
+ ## Client Usage
256
+
257
+ toolcall includes a client for connecting to any MCP server:
258
+
259
+ ```typescript
260
+ import { connect } from 'toolcall'
261
+
262
+ // Connect to a stdio server
263
+ const client = await connect('npx tsx ./server.ts')
264
+
265
+ // Or connect to an HTTP server
266
+ const client = await connect('http://localhost:3000')
267
+
268
+ // List available tools
269
+ console.log(client.listTools())
270
+
271
+ // Call a tool
272
+ const result = await client.call('greet', { name: 'World' })
273
+ console.log(result) // "Hello, World!"
274
+
275
+ // Clean up
276
+ client.close()
277
+ ```
278
+
279
+ ## Complete Example
280
+
281
+ ```typescript
282
+ import { serve, tool } from 'toolcall'
283
+ import { z } from 'zod'
284
+
285
+ serve({
286
+ name: 'example-server',
287
+ version: '1.0.0',
288
+ tools: {
289
+ // Simple string return
290
+ greet: tool({
291
+ description: 'Greet someone by name',
292
+ parameters: z.object({
293
+ name: z.string().describe('The name of the person to greet')
294
+ }),
295
+ execute: ({ name }) => `Hello, ${name}!`
296
+ }),
297
+
298
+ // Object return
299
+ add: tool({
300
+ description: 'Add two numbers together',
301
+ parameters: z.object({
302
+ a: z.number().describe('First number'),
303
+ b: z.number().describe('Second number')
304
+ }),
305
+ execute: ({ a, b }) => ({ result: a + b })
306
+ }),
307
+
308
+ // Async with enum and default
309
+ get_weather: tool({
310
+ description: 'Get the current weather for a city',
311
+ parameters: z.object({
312
+ city: z.string().describe('City name'),
313
+ unit: z.enum(['celsius', 'fahrenheit']).default('celsius').describe('Temperature unit')
314
+ }),
315
+ execute: async ({ city, unit }) => {
316
+ // Simulate API call
317
+ const temp = Math.round(Math.random() * 30 + 10)
318
+ const tempInUnit = unit === 'fahrenheit' ? Math.round(temp * 9 / 5 + 32) : temp
319
+ return {
320
+ city,
321
+ temperature: tempInUnit,
322
+ unit,
323
+ condition: ['sunny', 'cloudy', 'rainy'][Math.floor(Math.random() * 3)]
324
+ }
325
+ }
326
+ }),
327
+
328
+ // Constrained parameters
329
+ search: tool({
330
+ description: 'Search for information',
331
+ parameters: z.object({
332
+ query: z.string().describe('Search query'),
333
+ limit: z.number().min(1).max(100).default(10).describe('Maximum results')
334
+ }),
335
+ execute: async ({ query, limit }) => {
336
+ return {
337
+ query,
338
+ results: Array.from({ length: Math.min(limit, 3) }, (_, i) => ({
339
+ title: `Result ${i + 1} for "${query}"`,
340
+ url: `https://example.com/result/${i + 1}`
341
+ }))
342
+ }
343
+ }
344
+ })
345
+ }
346
+ })
347
+ ```
348
+
349
+ ## Error Handling
350
+
351
+ toolcall automatically validates parameters against your Zod schemas. Invalid parameters return a JSON-RPC error:
352
+
353
+ ```json
354
+ {
355
+ "jsonrpc": "2.0",
356
+ "id": 1,
357
+ "error": {
358
+ "code": -32602,
359
+ "message": "Invalid parameters",
360
+ "data": {
361
+ "name": { "_errors": ["Required"] }
362
+ }
363
+ }
364
+ }
365
+ ```
366
+
367
+ Errors thrown in tool execution are caught and returned as internal errors:
368
+
369
+ ```json
370
+ {
371
+ "jsonrpc": "2.0",
372
+ "id": 1,
373
+ "error": {
374
+ "code": -32603,
375
+ "message": "Internal error",
376
+ "data": "Error message here"
377
+ }
378
+ }
379
+ ```
380
+
381
+ ## Protocol Details
382
+
383
+ toolcall implements the [Model Context Protocol](https://modelcontextprotocol.io/) specification:
384
+
385
+ - **Protocol Version**: `2024-11-05`
386
+ - **Transport**: JSON-RPC 2.0 over stdio or HTTP
387
+ - **Methods**:
388
+ - `initialize` - Server initialization handshake
389
+ - `notifications/initialized` - Client initialization acknowledgment
390
+ - `tools/list` - List available tools
391
+ - `tools/call` - Execute a tool
392
+ - `ping` - Health check
393
+
394
+ ## Development
395
+
396
+ ```bash
397
+ # Install dependencies
398
+ npm install
399
+
400
+ # Build
401
+ npm run build
402
+
403
+ # Watch mode
404
+ npm run dev
405
+
406
+ # Run example server
407
+ npx tsx examples/server.ts
408
+
409
+ # Run tests
410
+ npm test
411
+ ```
412
+
413
+ ## License
414
+
415
+ MIT
416
+
417
+ ## Author
418
+
419
+ Yi Min Yang (https://www.yiminyang.dev)
@@ -0,0 +1,52 @@
1
+ import type { McpToolDefinition } from './types.js';
2
+ /**
3
+ * MCP Client for connecting to MCP servers
4
+ */
5
+ export declare class McpClient {
6
+ private process;
7
+ private httpUrl;
8
+ private requestId;
9
+ private pendingRequests;
10
+ private tools;
11
+ private constructor();
12
+ /**
13
+ * Connect to an MCP server
14
+ *
15
+ * @param target - Either a command to spawn (e.g., 'node server.js')
16
+ * or an HTTP URL (e.g., 'http://localhost:3000')
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * // Connect to stdio server
21
+ * const client = await connect('node ./my-server.js')
22
+ *
23
+ * // Connect to HTTP server
24
+ * const client = await connect('http://localhost:3000')
25
+ *
26
+ * // Call a tool
27
+ * const result = await client.call('greet', { name: 'World' })
28
+ * ```
29
+ */
30
+ static connect(target: string): Promise<McpClient>;
31
+ /**
32
+ * Send a JSON-RPC request
33
+ */
34
+ private request;
35
+ /**
36
+ * Call a tool by name
37
+ */
38
+ call(toolName: string, args?: Record<string, unknown>): Promise<unknown>;
39
+ /**
40
+ * List available tools
41
+ */
42
+ listTools(): McpToolDefinition[];
43
+ /**
44
+ * Close the connection
45
+ */
46
+ close(): void;
47
+ }
48
+ /**
49
+ * Connect to an MCP server
50
+ */
51
+ export declare const connect: typeof McpClient.connect;
52
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAmC,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAOpF;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,eAAe,CAA6C;IACpE,OAAO,CAAC,KAAK,CAA0B;IAEvC,OAAO;IAEP;;;;;;;;;;;;;;;;;OAiBG;WACU,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAwDxD;;OAEG;YACW,OAAO;IA4BrB;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqBlF;;OAEG;IACH,SAAS,IAAI,iBAAiB,EAAE;IAIhC;;OAEG;IACH,KAAK,IAAI,IAAI;CAMd;AAED;;GAEG;AACH,eAAO,MAAM,OAAO,0BAAoB,CAAA"}
package/dist/client.js ADDED
@@ -0,0 +1,149 @@
1
+ import { spawn } from 'node:child_process';
2
+ import * as readline from 'node:readline';
3
+ /**
4
+ * MCP Client for connecting to MCP servers
5
+ */
6
+ export class McpClient {
7
+ process = null;
8
+ httpUrl = null;
9
+ requestId = 0;
10
+ pendingRequests = new Map();
11
+ tools = [];
12
+ constructor() { }
13
+ /**
14
+ * Connect to an MCP server
15
+ *
16
+ * @param target - Either a command to spawn (e.g., 'node server.js')
17
+ * or an HTTP URL (e.g., 'http://localhost:3000')
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * // Connect to stdio server
22
+ * const client = await connect('node ./my-server.js')
23
+ *
24
+ * // Connect to HTTP server
25
+ * const client = await connect('http://localhost:3000')
26
+ *
27
+ * // Call a tool
28
+ * const result = await client.call('greet', { name: 'World' })
29
+ * ```
30
+ */
31
+ static async connect(target) {
32
+ const client = new McpClient();
33
+ if (target.startsWith('http://') || target.startsWith('https://')) {
34
+ client.httpUrl = target;
35
+ }
36
+ else {
37
+ // Spawn stdio process
38
+ const [command, ...args] = target.split(' ');
39
+ client.process = spawn(command, args, {
40
+ stdio: ['pipe', 'pipe', 'inherit']
41
+ });
42
+ // Set up response handling
43
+ const rl = readline.createInterface({
44
+ input: client.process.stdout,
45
+ terminal: false
46
+ });
47
+ rl.on('line', (line) => {
48
+ if (!line.trim())
49
+ return;
50
+ try {
51
+ const response = JSON.parse(line);
52
+ const pending = client.pendingRequests.get(response.id);
53
+ if (pending) {
54
+ client.pendingRequests.delete(response.id);
55
+ pending.resolve(response);
56
+ }
57
+ }
58
+ catch {
59
+ // Ignore parse errors
60
+ }
61
+ });
62
+ client.process.on('exit', () => {
63
+ for (const pending of client.pendingRequests.values()) {
64
+ pending.reject(new Error('Process exited'));
65
+ }
66
+ client.pendingRequests.clear();
67
+ });
68
+ }
69
+ // Initialize connection
70
+ await client.request('initialize', {
71
+ protocolVersion: '2024-11-05',
72
+ capabilities: {},
73
+ clientInfo: { name: 'toolcall-client', version: '1.0.0' }
74
+ });
75
+ await client.request('notifications/initialized', {});
76
+ // Get available tools
77
+ const toolsResponse = await client.request('tools/list', {});
78
+ client.tools = toolsResponse.result.tools;
79
+ return client;
80
+ }
81
+ /**
82
+ * Send a JSON-RPC request
83
+ */
84
+ async request(method, params) {
85
+ const id = ++this.requestId;
86
+ const request = {
87
+ jsonrpc: '2.0',
88
+ id,
89
+ method,
90
+ params
91
+ };
92
+ if (this.httpUrl) {
93
+ const response = await fetch(this.httpUrl, {
94
+ method: 'POST',
95
+ headers: { 'Content-Type': 'application/json' },
96
+ body: JSON.stringify(request)
97
+ });
98
+ return response.json();
99
+ }
100
+ if (!this.process?.stdin) {
101
+ throw new Error('Not connected');
102
+ }
103
+ return new Promise((resolve, reject) => {
104
+ this.pendingRequests.set(id, { resolve, reject });
105
+ this.process.stdin.write(JSON.stringify(request) + '\n');
106
+ });
107
+ }
108
+ /**
109
+ * Call a tool by name
110
+ */
111
+ async call(toolName, args = {}) {
112
+ const response = await this.request('tools/call', {
113
+ name: toolName,
114
+ arguments: args
115
+ });
116
+ if (response.error) {
117
+ throw new Error(response.error.message);
118
+ }
119
+ const result = response.result;
120
+ const text = result.content[0]?.text ?? '';
121
+ // Try to parse as JSON
122
+ try {
123
+ return JSON.parse(text);
124
+ }
125
+ catch {
126
+ return text;
127
+ }
128
+ }
129
+ /**
130
+ * List available tools
131
+ */
132
+ listTools() {
133
+ return this.tools;
134
+ }
135
+ /**
136
+ * Close the connection
137
+ */
138
+ close() {
139
+ if (this.process) {
140
+ this.process.kill();
141
+ this.process = null;
142
+ }
143
+ }
144
+ }
145
+ /**
146
+ * Connect to an MCP server
147
+ */
148
+ export const connect = McpClient.connect;
149
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * toolcall - FastMCP for JavaScript
3
+ *
4
+ * Create MCP servers with zero boilerplate.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { serve, tool } from 'toolcall'
9
+ * import { z } from 'zod'
10
+ *
11
+ * serve({
12
+ * tools: {
13
+ * greet: tool({
14
+ * description: 'Greet someone',
15
+ * parameters: z.object({
16
+ * name: z.string().describe('Name to greet')
17
+ * }),
18
+ * execute: ({ name }) => `Hello, ${name}!`
19
+ * }),
20
+ *
21
+ * add: tool({
22
+ * description: 'Add two numbers',
23
+ * parameters: z.object({
24
+ * a: z.number(),
25
+ * b: z.number()
26
+ * }),
27
+ * execute: ({ a, b }) => a + b
28
+ * })
29
+ * }
30
+ * })
31
+ * ```
32
+ */
33
+ export { serve } from './server.js';
34
+ export { tool } from './tool.js';
35
+ export { connect, McpClient } from './client.js';
36
+ export { zodToMcpSchema, toolToMcpDefinition } from './schema.js';
37
+ export type { ToolDefinition, ToolRegistry, ServeOptions, McpToolDefinition, McpCapabilities, McpServerInfo, JsonRpcRequest, JsonRpcResponse } from './types.js';
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACjE,YAAY,EACV,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * toolcall - FastMCP for JavaScript
3
+ *
4
+ * Create MCP servers with zero boilerplate.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { serve, tool } from 'toolcall'
9
+ * import { z } from 'zod'
10
+ *
11
+ * serve({
12
+ * tools: {
13
+ * greet: tool({
14
+ * description: 'Greet someone',
15
+ * parameters: z.object({
16
+ * name: z.string().describe('Name to greet')
17
+ * }),
18
+ * execute: ({ name }) => `Hello, ${name}!`
19
+ * }),
20
+ *
21
+ * add: tool({
22
+ * description: 'Add two numbers',
23
+ * parameters: z.object({
24
+ * a: z.number(),
25
+ * b: z.number()
26
+ * }),
27
+ * execute: ({ a, b }) => a + b
28
+ * })
29
+ * }
30
+ * })
31
+ * ```
32
+ */
33
+ export { serve } from './server.js';
34
+ export { tool } from './tool.js';
35
+ export { connect, McpClient } from './client.js';
36
+ export { zodToMcpSchema, toolToMcpDefinition } from './schema.js';
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod';
2
+ import type { McpToolDefinition, ToolDefinition } from './types.js';
3
+ /**
4
+ * Convert a Zod schema to MCP-compatible JSON Schema
5
+ */
6
+ export declare function zodToMcpSchema(schema: z.ZodType): McpToolDefinition['inputSchema'];
7
+ /**
8
+ * Convert a tool definition to MCP tool format
9
+ */
10
+ export declare function toolToMcpDefinition(name: string, tool: ToolDefinition): McpToolDefinition;
11
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AASnE;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,GAAG,iBAAiB,CAAC,aAAa,CAAC,CAmBlF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,cAAc,GACnB,iBAAiB,CAMnB"}
package/dist/schema.js ADDED
@@ -0,0 +1,33 @@
1
+ import { zodToJsonSchema } from 'zod-to-json-schema';
2
+ /**
3
+ * Convert a Zod schema to MCP-compatible JSON Schema
4
+ */
5
+ export function zodToMcpSchema(schema) {
6
+ const jsonSchema = zodToJsonSchema(schema, { target: 'openApi3' });
7
+ // Ensure we have an object schema
8
+ if (typeof jsonSchema !== 'object' || jsonSchema.type !== 'object') {
9
+ return {
10
+ type: 'object',
11
+ properties: {
12
+ value: jsonSchema
13
+ },
14
+ required: ['value']
15
+ };
16
+ }
17
+ return {
18
+ type: 'object',
19
+ properties: (jsonSchema.properties ?? {}),
20
+ required: jsonSchema.required
21
+ };
22
+ }
23
+ /**
24
+ * Convert a tool definition to MCP tool format
25
+ */
26
+ export function toolToMcpDefinition(name, tool) {
27
+ return {
28
+ name,
29
+ description: tool.description,
30
+ inputSchema: zodToMcpSchema(tool.parameters)
31
+ };
32
+ }
33
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAUpD;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAAiB;IAC9C,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAqB,CAAA;IAEtF,kCAAkC;IAClC,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACnE,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,KAAK,EAAE,UAAqC;aAC7C;YACD,QAAQ,EAAE,CAAC,OAAO,CAAC;SACpB,CAAA;IACH,CAAC;IAED,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,CAAC,UAAU,CAAC,UAAU,IAAI,EAAE,CAA4B;QACpE,QAAQ,EAAE,UAAU,CAAC,QAAQ;KAC9B,CAAA;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAY,EACZ,IAAoB;IAEpB,OAAO;QACL,IAAI;QACJ,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC;KAC7C,CAAA;AACH,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { ServeOptions, ToolRegistry } from './types.js';
2
+ /**
3
+ * Create and start an MCP server with the given tools
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { serve, tool } from 'toolcall'
8
+ * import { z } from 'zod'
9
+ *
10
+ * serve({
11
+ * name: 'my-server',
12
+ * tools: {
13
+ * greet: tool({
14
+ * description: 'Greet someone',
15
+ * parameters: z.object({ name: z.string() }),
16
+ * execute: ({ name }) => `Hello, ${name}!`
17
+ * })
18
+ * }
19
+ * })
20
+ * ```
21
+ */
22
+ export declare function serve(config: ServeOptions & {
23
+ tools: ToolRegistry;
24
+ }): void;
25
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKV,YAAY,EACZ,YAAY,EACb,MAAM,YAAY,CAAA;AAMnB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,KAAK,CACnB,MAAM,EAAE,YAAY,GAAG;IAAE,KAAK,EAAE,YAAY,CAAA;CAAE,GAC7C,IAAI,CAgIN"}
package/dist/server.js ADDED
@@ -0,0 +1,131 @@
1
+ import { toolToMcpDefinition } from './schema.js';
2
+ import { createStdioTransport, createHttpTransport } from './transport.js';
3
+ const PROTOCOL_VERSION = '2024-11-05';
4
+ /**
5
+ * Create and start an MCP server with the given tools
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { serve, tool } from 'toolcall'
10
+ * import { z } from 'zod'
11
+ *
12
+ * serve({
13
+ * name: 'my-server',
14
+ * tools: {
15
+ * greet: tool({
16
+ * description: 'Greet someone',
17
+ * parameters: z.object({ name: z.string() }),
18
+ * execute: ({ name }) => `Hello, ${name}!`
19
+ * })
20
+ * }
21
+ * })
22
+ * ```
23
+ */
24
+ export function serve(config) {
25
+ const { name = 'toolcall-server', version = '1.0.0', transport = 'stdio', port = 3000, tools } = config;
26
+ const serverInfo = { name, version };
27
+ const capabilities = { tools: {} };
28
+ async function handleRequest(request) {
29
+ const { id, method, params } = request;
30
+ try {
31
+ switch (method) {
32
+ case 'initialize': {
33
+ return {
34
+ jsonrpc: '2.0',
35
+ id,
36
+ result: {
37
+ protocolVersion: PROTOCOL_VERSION,
38
+ capabilities,
39
+ serverInfo
40
+ }
41
+ };
42
+ }
43
+ case 'notifications/initialized': {
44
+ // Client acknowledged initialization - no response needed for notifications
45
+ // but we return success anyway since some clients expect it
46
+ return { jsonrpc: '2.0', id, result: {} };
47
+ }
48
+ case 'tools/list': {
49
+ const toolList = Object.entries(tools).map(([toolName, toolDef]) => toolToMcpDefinition(toolName, toolDef));
50
+ return {
51
+ jsonrpc: '2.0',
52
+ id,
53
+ result: { tools: toolList }
54
+ };
55
+ }
56
+ case 'tools/call': {
57
+ const { name: toolName, arguments: args } = params;
58
+ const toolDef = tools[toolName];
59
+ if (!toolDef) {
60
+ return {
61
+ jsonrpc: '2.0',
62
+ id,
63
+ error: {
64
+ code: -32602,
65
+ message: `Unknown tool: ${toolName}`
66
+ }
67
+ };
68
+ }
69
+ // Validate parameters
70
+ const parseResult = toolDef.parameters.safeParse(args ?? {});
71
+ if (!parseResult.success) {
72
+ return {
73
+ jsonrpc: '2.0',
74
+ id,
75
+ error: {
76
+ code: -32602,
77
+ message: 'Invalid parameters',
78
+ data: parseResult.error.format()
79
+ }
80
+ };
81
+ }
82
+ // Execute the tool
83
+ const result = await toolDef.execute(parseResult.data);
84
+ return {
85
+ jsonrpc: '2.0',
86
+ id,
87
+ result: {
88
+ content: [
89
+ {
90
+ type: 'text',
91
+ text: typeof result === 'string' ? result : JSON.stringify(result, null, 2)
92
+ }
93
+ ]
94
+ }
95
+ };
96
+ }
97
+ case 'ping': {
98
+ return { jsonrpc: '2.0', id, result: {} };
99
+ }
100
+ default: {
101
+ return {
102
+ jsonrpc: '2.0',
103
+ id,
104
+ error: {
105
+ code: -32601,
106
+ message: `Method not found: ${method}`
107
+ }
108
+ };
109
+ }
110
+ }
111
+ }
112
+ catch (error) {
113
+ return {
114
+ jsonrpc: '2.0',
115
+ id,
116
+ error: {
117
+ code: -32603,
118
+ message: 'Internal error',
119
+ data: error instanceof Error ? error.message : String(error)
120
+ }
121
+ };
122
+ }
123
+ }
124
+ if (transport === 'http') {
125
+ createHttpTransport(handleRequest, port);
126
+ }
127
+ else {
128
+ createStdioTransport(handleRequest);
129
+ }
130
+ }
131
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/dist/tool.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ import type { ToolDefinition } from './types.js';
3
+ /**
4
+ * Define a tool with type-safe parameters
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * const getWeather = tool({
9
+ * description: 'Get weather for a city',
10
+ * parameters: z.object({
11
+ * city: z.string().describe('City name'),
12
+ * unit: z.enum(['celsius', 'fahrenheit']).default('celsius')
13
+ * }),
14
+ * execute: async ({ city, unit }) => {
15
+ * // Implementation
16
+ * return { temperature: 22, unit }
17
+ * }
18
+ * })
19
+ * ```
20
+ */
21
+ export declare function tool<T extends z.ZodType>(definition: ToolDefinition<T>): ToolDefinition<T>;
22
+ //# sourceMappingURL=tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EACtC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC,GAC5B,cAAc,CAAC,CAAC,CAAC,CAEnB"}
package/dist/tool.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Define a tool with type-safe parameters
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * const getWeather = tool({
7
+ * description: 'Get weather for a city',
8
+ * parameters: z.object({
9
+ * city: z.string().describe('City name'),
10
+ * unit: z.enum(['celsius', 'fahrenheit']).default('celsius')
11
+ * }),
12
+ * execute: async ({ city, unit }) => {
13
+ * // Implementation
14
+ * return { temperature: 22, unit }
15
+ * }
16
+ * })
17
+ * ```
18
+ */
19
+ export function tool(definition) {
20
+ return definition;
21
+ }
22
+ //# sourceMappingURL=tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,IAAI,CAClB,UAA6B;IAE7B,OAAO,UAAU,CAAA;AACnB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import * as http from 'node:http';
2
+ import type { JsonRpcRequest, JsonRpcResponse } from './types.js';
3
+ export type MessageHandler = (request: JsonRpcRequest) => Promise<JsonRpcResponse>;
4
+ /**
5
+ * Create a stdio transport for MCP communication
6
+ */
7
+ export declare function createStdioTransport(handler: MessageHandler): void;
8
+ /**
9
+ * Create an HTTP transport for MCP communication
10
+ */
11
+ export declare function createHttpTransport(handler: MessageHandler, port: number): http.Server;
12
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjE,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,CAAC,CAAA;AAElF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CA+BlE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC,MAAM,CAmDtF"}
@@ -0,0 +1,87 @@
1
+ import * as readline from 'node:readline';
2
+ import * as http from 'node:http';
3
+ /**
4
+ * Create a stdio transport for MCP communication
5
+ */
6
+ export function createStdioTransport(handler) {
7
+ const rl = readline.createInterface({
8
+ input: process.stdin,
9
+ output: process.stdout,
10
+ terminal: false
11
+ });
12
+ rl.on('line', async (line) => {
13
+ if (!line.trim())
14
+ return;
15
+ try {
16
+ const request = JSON.parse(line);
17
+ const response = await handler(request);
18
+ console.log(JSON.stringify(response));
19
+ }
20
+ catch (error) {
21
+ const errorResponse = {
22
+ jsonrpc: '2.0',
23
+ id: 0,
24
+ error: {
25
+ code: -32700,
26
+ message: 'Parse error',
27
+ data: error instanceof Error ? error.message : String(error)
28
+ }
29
+ };
30
+ console.log(JSON.stringify(errorResponse));
31
+ }
32
+ });
33
+ rl.on('close', () => {
34
+ process.exit(0);
35
+ });
36
+ }
37
+ /**
38
+ * Create an HTTP transport for MCP communication
39
+ */
40
+ export function createHttpTransport(handler, port) {
41
+ const server = http.createServer(async (req, res) => {
42
+ // CORS headers
43
+ res.setHeader('Access-Control-Allow-Origin', '*');
44
+ res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
45
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
46
+ if (req.method === 'OPTIONS') {
47
+ res.writeHead(204);
48
+ res.end();
49
+ return;
50
+ }
51
+ if (req.method !== 'POST') {
52
+ res.writeHead(405);
53
+ res.end('Method not allowed');
54
+ return;
55
+ }
56
+ let body = '';
57
+ for await (const chunk of req) {
58
+ body += chunk;
59
+ }
60
+ try {
61
+ const request = JSON.parse(body);
62
+ const response = await handler(request);
63
+ res.setHeader('Content-Type', 'application/json');
64
+ res.writeHead(200);
65
+ res.end(JSON.stringify(response));
66
+ }
67
+ catch (error) {
68
+ const errorResponse = {
69
+ jsonrpc: '2.0',
70
+ id: 0,
71
+ error: {
72
+ code: -32700,
73
+ message: 'Parse error',
74
+ data: error instanceof Error ? error.message : String(error)
75
+ }
76
+ };
77
+ res.setHeader('Content-Type', 'application/json');
78
+ res.writeHead(200);
79
+ res.end(JSON.stringify(errorResponse));
80
+ }
81
+ });
82
+ server.listen(port, () => {
83
+ console.error(`[toolcall] MCP server listening on http://localhost:${port}`);
84
+ });
85
+ return server;
86
+ }
87
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import type { z } from 'zod';
2
+ /** JSON-RPC request structure */
3
+ export interface JsonRpcRequest {
4
+ jsonrpc: '2.0';
5
+ id: number | string;
6
+ method: string;
7
+ params?: unknown;
8
+ }
9
+ /** JSON-RPC response structure */
10
+ export interface JsonRpcResponse {
11
+ jsonrpc: '2.0';
12
+ id: number | string;
13
+ result?: unknown;
14
+ error?: {
15
+ code: number;
16
+ message: string;
17
+ data?: unknown;
18
+ };
19
+ }
20
+ /** MCP Tool definition as returned by list_tools */
21
+ export interface McpToolDefinition {
22
+ name: string;
23
+ description: string;
24
+ inputSchema: {
25
+ type: 'object';
26
+ properties: Record<string, unknown>;
27
+ required?: string[];
28
+ };
29
+ }
30
+ /** MCP Server capabilities */
31
+ export interface McpCapabilities {
32
+ tools?: Record<string, never>;
33
+ resources?: Record<string, never>;
34
+ prompts?: Record<string, never>;
35
+ }
36
+ /** MCP Server info */
37
+ export interface McpServerInfo {
38
+ name: string;
39
+ version: string;
40
+ }
41
+ /** Tool definition with Zod schema */
42
+ export interface ToolDefinition<T extends z.ZodType = z.ZodType> {
43
+ description: string;
44
+ parameters: T;
45
+ execute: (params: z.infer<T>) => Promise<unknown> | unknown;
46
+ }
47
+ /** Options for serve() */
48
+ export interface ServeOptions {
49
+ /** Server name (shown to clients) */
50
+ name?: string;
51
+ /** Server version */
52
+ version?: string;
53
+ /** Transport type: 'stdio' (default) or 'http' */
54
+ transport?: 'stdio' | 'http';
55
+ /** Port for HTTP transport */
56
+ port?: number;
57
+ }
58
+ /** Tool registry - map of tool names to definitions */
59
+ export type ToolRegistry = Record<string, ToolDefinition>;
60
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAE5B,iCAAiC;AACjC,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,KAAK,CAAA;IACd,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,kCAAkC;AAClC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,KAAK,CAAA;IACd,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;QACf,IAAI,CAAC,EAAE,OAAO,CAAA;KACf,CAAA;CACF;AAED,oDAAoD;AACpD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAA;QACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACnC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KACpB,CAAA;CACF;AAED,8BAA8B;AAC9B,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;CAChC;AAED,sBAAsB;AACtB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,sCAAsC;AACtC,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO;IAC7D,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,CAAC,CAAA;IACb,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;CAC5D;AAED,0BAA0B;AAC1B,MAAM,WAAW,YAAY;IAC3B,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IAC5B,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,uDAAuD;AACvD,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,9 +1,37 @@
1
1
  {
2
2
  "name": "toolcall",
3
- "version": "0.0.3",
4
- "description": "LLM tool calling utilities",
5
- "main": "index.js",
6
- "keywords": ["toolcall", "function-calling", "ai", "llm", "agents"],
3
+ "version": "0.1.0",
4
+ "description": "FastMCP for JavaScript - Create MCP servers with zero boilerplate",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "dev": "tsc --watch",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "keywords": [
26
+ "mcp",
27
+ "model-context-protocol",
28
+ "llm",
29
+ "ai",
30
+ "tools",
31
+ "function-calling",
32
+ "anthropic",
33
+ "claude"
34
+ ],
7
35
  "author": "Yi Min Yang (https://www.yiminyang.dev)",
8
36
  "license": "MIT",
9
37
  "repository": {
@@ -13,5 +41,17 @@
13
41
  "homepage": "https://github.com/sceiler/toolcall",
14
42
  "bugs": {
15
43
  "url": "https://github.com/sceiler/toolcall/issues"
44
+ },
45
+ "dependencies": {
46
+ "zod": "^3.23.0",
47
+ "zod-to-json-schema": "^3.23.0"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^22.0.0",
51
+ "typescript": "^5.7.0",
52
+ "vitest": "^4.0.17"
53
+ },
54
+ "engines": {
55
+ "node": ">=18"
16
56
  }
17
57
  }
package/index.js DELETED
@@ -1 +0,0 @@
1
- module.exports = {};