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 +419 -0
- package/dist/client.d.ts +52 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +149 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/schema.d.ts +11 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +33 -0
- package/dist/schema.js.map +1 -0
- package/dist/server.d.ts +25 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +131 -0
- package/dist/server.js.map +1 -0
- package/dist/tool.d.ts +22 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +22 -0
- package/dist/tool.js.map +1 -0
- package/dist/transport.d.ts +12 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +87 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +44 -4
- package/index.js +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
# toolcall
|
|
2
|
+
|
|
3
|
+
Create MCP (Model Context Protocol) servers with zero boilerplate.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/toolcall)
|
|
6
|
+
[](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)
|
package/dist/client.d.ts
ADDED
|
@@ -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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/schema.d.ts
ADDED
|
@@ -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"}
|
package/dist/server.d.ts
ADDED
|
@@ -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
|
package/dist/tool.js.map
ADDED
|
@@ -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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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
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
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
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 = {};
|