@outfitter/mcp 0.1.0-rc.1
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 +342 -0
- package/dist/index.d.ts +522 -0
- package/dist/index.js +787 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# @outfitter/mcp
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server framework with typed tools and Result-based error handling.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @outfitter/mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { createMcpServer, defineTool } from "@outfitter/mcp";
|
|
15
|
+
import { Result } from "@outfitter/contracts";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
|
|
18
|
+
const server = createMcpServer({
|
|
19
|
+
name: "calculator",
|
|
20
|
+
version: "1.0.0",
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
server.registerTool(
|
|
24
|
+
defineTool({
|
|
25
|
+
name: "add",
|
|
26
|
+
description: "Add two numbers together",
|
|
27
|
+
inputSchema: z.object({
|
|
28
|
+
a: z.number(),
|
|
29
|
+
b: z.number(),
|
|
30
|
+
}),
|
|
31
|
+
handler: async (input, ctx) => {
|
|
32
|
+
ctx.logger.debug("Adding numbers", { a: input.a, b: input.b });
|
|
33
|
+
return Result.ok({ sum: input.a + input.b });
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
await server.start();
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Features
|
|
42
|
+
|
|
43
|
+
- **Typed Tools** — Define tools with Zod schemas for automatic input validation
|
|
44
|
+
- **Result-Based Errors** — All operations return `Result<T, E>` for explicit error handling
|
|
45
|
+
- **Handler Contract** — Tools use the same `Handler` pattern as other Outfitter packages
|
|
46
|
+
- **Core Tools** — Built-in docs, config, and query tools for common patterns
|
|
47
|
+
- **Deferred Loading** — Support for MCP tool search with `deferLoading` flag
|
|
48
|
+
|
|
49
|
+
## API Reference
|
|
50
|
+
|
|
51
|
+
### createMcpServer(options)
|
|
52
|
+
|
|
53
|
+
Creates an MCP server instance.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
interface McpServerOptions {
|
|
57
|
+
name: string; // Server name for MCP handshake
|
|
58
|
+
version: string; // Server version (semver)
|
|
59
|
+
logger?: Logger; // Optional structured logger
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const server = createMcpServer({
|
|
63
|
+
name: "my-server",
|
|
64
|
+
version: "1.0.0",
|
|
65
|
+
logger: createLogger({ name: "mcp" }),
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### defineTool(definition)
|
|
70
|
+
|
|
71
|
+
Helper for defining typed tools with better type inference.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
interface ToolDefinition<TInput, TOutput, TError> {
|
|
75
|
+
name: string; // Unique tool name (kebab-case)
|
|
76
|
+
description: string; // Human-readable description
|
|
77
|
+
inputSchema: z.ZodType<TInput>; // Zod schema for validation
|
|
78
|
+
handler: Handler<TInput, TOutput, TError>;
|
|
79
|
+
deferLoading?: boolean; // Default: true
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const getUserTool = defineTool({
|
|
83
|
+
name: "get-user",
|
|
84
|
+
description: "Retrieve a user by their unique ID",
|
|
85
|
+
inputSchema: z.object({ userId: z.string().uuid() }),
|
|
86
|
+
handler: async (input, ctx) => {
|
|
87
|
+
const user = await db.users.find(input.userId);
|
|
88
|
+
if (!user) {
|
|
89
|
+
return Result.err(new NotFoundError("user", input.userId));
|
|
90
|
+
}
|
|
91
|
+
return Result.ok(user);
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### defineResource(definition)
|
|
97
|
+
|
|
98
|
+
Helper for defining MCP resources.
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
interface ResourceDefinition {
|
|
102
|
+
uri: string; // Unique resource URI
|
|
103
|
+
name: string; // Human-readable name
|
|
104
|
+
description?: string; // Optional description
|
|
105
|
+
mimeType?: string; // Content MIME type
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const configResource = defineResource({
|
|
109
|
+
uri: "file:///etc/app/config.json",
|
|
110
|
+
name: "Application Config",
|
|
111
|
+
description: "Main configuration file",
|
|
112
|
+
mimeType: "application/json",
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Server Methods
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
interface McpServer {
|
|
120
|
+
readonly name: string;
|
|
121
|
+
readonly version: string;
|
|
122
|
+
|
|
123
|
+
// Registration
|
|
124
|
+
registerTool<TInput, TOutput, TError>(tool: ToolDefinition): void;
|
|
125
|
+
registerResource(resource: ResourceDefinition): void;
|
|
126
|
+
|
|
127
|
+
// Introspection
|
|
128
|
+
getTools(): SerializedTool[];
|
|
129
|
+
getResources(): ResourceDefinition[];
|
|
130
|
+
|
|
131
|
+
// Invocation
|
|
132
|
+
invokeTool<T>(name: string, input: unknown, options?: InvokeToolOptions): Promise<Result<T, McpError>>;
|
|
133
|
+
|
|
134
|
+
// Lifecycle
|
|
135
|
+
start(): Promise<void>;
|
|
136
|
+
stop(): Promise<void>;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### McpHandlerContext
|
|
141
|
+
|
|
142
|
+
Extended handler context for MCP tools with additional metadata:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
interface McpHandlerContext extends HandlerContext {
|
|
146
|
+
toolName?: string; // Name of the tool being invoked
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Core Tools
|
|
151
|
+
|
|
152
|
+
Pre-built tools for common MCP patterns. These are marked with `deferLoading: false` for immediate availability.
|
|
153
|
+
|
|
154
|
+
### Docs Tool
|
|
155
|
+
|
|
156
|
+
Provides documentation, usage patterns, and examples.
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { defineDocsTool, createCoreTools } from "@outfitter/mcp";
|
|
160
|
+
|
|
161
|
+
const docsTool = defineDocsTool({
|
|
162
|
+
docs: {
|
|
163
|
+
overview: "Calculator server for arithmetic operations",
|
|
164
|
+
tools: [{ name: "add", summary: "Add two numbers" }],
|
|
165
|
+
examples: [{ input: { a: 2, b: 3 }, description: "Basic addition" }],
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Or use getDocs for dynamic content
|
|
170
|
+
const dynamicDocsTool = defineDocsTool({
|
|
171
|
+
getDocs: async (section) => {
|
|
172
|
+
return loadDocsFromFile(section);
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Config Tool
|
|
178
|
+
|
|
179
|
+
Read and modify server configuration.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { defineConfigTool } from "@outfitter/mcp";
|
|
183
|
+
|
|
184
|
+
const configTool = defineConfigTool({
|
|
185
|
+
initial: { debug: false, maxRetries: 3 },
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// With custom store
|
|
189
|
+
const persistedConfigTool = defineConfigTool({
|
|
190
|
+
store: {
|
|
191
|
+
get: async (key) => db.config.get(key),
|
|
192
|
+
set: async (key, value) => db.config.set(key, value),
|
|
193
|
+
list: async () => db.config.all(),
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Query Tool
|
|
199
|
+
|
|
200
|
+
Search and discovery with pagination.
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import { defineQueryTool } from "@outfitter/mcp";
|
|
204
|
+
|
|
205
|
+
const queryTool = defineQueryTool({
|
|
206
|
+
handler: async (input, ctx) => {
|
|
207
|
+
const results = await searchIndex(input.q, {
|
|
208
|
+
limit: input.limit,
|
|
209
|
+
cursor: input.cursor,
|
|
210
|
+
filters: input.filters,
|
|
211
|
+
});
|
|
212
|
+
return Result.ok({
|
|
213
|
+
results: results.items,
|
|
214
|
+
nextCursor: results.nextCursor,
|
|
215
|
+
});
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Bundle All Core Tools
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import { createCoreTools } from "@outfitter/mcp";
|
|
224
|
+
|
|
225
|
+
const coreTools = createCoreTools({
|
|
226
|
+
docs: { docs: myDocs },
|
|
227
|
+
config: { initial: myConfig },
|
|
228
|
+
query: { handler: myQueryHandler },
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
for (const tool of coreTools) {
|
|
232
|
+
server.registerTool(tool);
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Transport Helpers
|
|
237
|
+
|
|
238
|
+
### connectStdio
|
|
239
|
+
|
|
240
|
+
Connect server to stdio transport for Claude Desktop integration.
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
import { createMcpServer, connectStdio } from "@outfitter/mcp";
|
|
244
|
+
|
|
245
|
+
const server = createMcpServer({ name: "my-server", version: "1.0.0" });
|
|
246
|
+
// ... register tools ...
|
|
247
|
+
|
|
248
|
+
await connectStdio(server);
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### createSdkServer
|
|
252
|
+
|
|
253
|
+
Create the underlying `@modelcontextprotocol/sdk` server.
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
import { createSdkServer } from "@outfitter/mcp";
|
|
257
|
+
|
|
258
|
+
const { server: sdkServer, toolsList, callTool } = createSdkServer(mcpServer);
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Error Handling
|
|
262
|
+
|
|
263
|
+
Tools return Results with typed errors. The framework automatically translates `OutfitterError` categories to JSON-RPC error codes:
|
|
264
|
+
|
|
265
|
+
| Category | JSON-RPC Code | Description |
|
|
266
|
+
|----------|--------------|-------------|
|
|
267
|
+
| `validation` | -32602 | Invalid params |
|
|
268
|
+
| `not_found` | -32601 | Method not found |
|
|
269
|
+
| `permission` | -32600 | Invalid request |
|
|
270
|
+
| `internal` | -32603 | Internal error |
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
const result = await server.invokeTool("get-user", { userId: "123" });
|
|
274
|
+
|
|
275
|
+
if (result.isErr()) {
|
|
276
|
+
// result.error is McpError with code and context
|
|
277
|
+
console.error(result.error.message, result.error.code);
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Schema Utilities
|
|
282
|
+
|
|
283
|
+
### zodToJsonSchema
|
|
284
|
+
|
|
285
|
+
Convert Zod schemas to JSON Schema for MCP protocol.
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import { zodToJsonSchema } from "@outfitter/mcp";
|
|
289
|
+
|
|
290
|
+
const schema = z.object({
|
|
291
|
+
name: z.string(),
|
|
292
|
+
age: z.number().optional(),
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const jsonSchema = zodToJsonSchema(schema);
|
|
296
|
+
// { type: "object", properties: { name: { type: "string" }, ... } }
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Action Adapter
|
|
300
|
+
|
|
301
|
+
### buildMcpTools
|
|
302
|
+
|
|
303
|
+
Build MCP tools from an action registry (for structured action-based servers).
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
import { buildMcpTools } from "@outfitter/mcp";
|
|
307
|
+
|
|
308
|
+
const tools = buildMcpTools({
|
|
309
|
+
actions: myActionRegistry,
|
|
310
|
+
prefix: "myapp",
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
for (const tool of tools) {
|
|
314
|
+
server.registerTool(tool);
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Claude Desktop Configuration
|
|
319
|
+
|
|
320
|
+
Add your MCP server to Claude Desktop:
|
|
321
|
+
|
|
322
|
+
```json
|
|
323
|
+
{
|
|
324
|
+
"mcpServers": {
|
|
325
|
+
"my-server": {
|
|
326
|
+
"command": "bun",
|
|
327
|
+
"args": ["run", "/path/to/server.ts"]
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Config location:
|
|
334
|
+
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
335
|
+
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
336
|
+
- Linux: `~/.config/claude/claude_desktop_config.json`
|
|
337
|
+
|
|
338
|
+
## Related Packages
|
|
339
|
+
|
|
340
|
+
- [@outfitter/contracts](../contracts/README.md) — Result types and error taxonomy
|
|
341
|
+
- [@outfitter/logging](../logging/README.md) — Structured logging
|
|
342
|
+
- [@outfitter/config](../config/README.md) — Configuration loading
|