@outfitter/mcp 0.4.2 → 0.5.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 +130 -28
- package/dist/actions.d.ts +7 -2
- package/dist/actions.js +52 -5
- package/dist/core-tools.d.ts +7 -2
- package/dist/core-tools.js +140 -6
- package/dist/index.d.ts +14 -953
- package/dist/index.js +8 -959
- package/dist/internal/content-types.d.ts +2 -0
- package/dist/internal/content-types.js +1 -0
- package/dist/internal/log-config.d.ts +24 -0
- package/dist/internal/log-config.js +13 -0
- package/dist/internal/prompt-types.d.ts +3 -0
- package/dist/internal/prompt-types.js +1 -0
- package/dist/internal/resource-types.d.ts +4 -0
- package/dist/internal/resource-types.js +1 -0
- package/dist/internal/server-types.d.ts +7 -0
- package/dist/internal/server-types.js +20 -0
- package/dist/internal/tool-types.d.ts +2 -0
- package/dist/{shared/@outfitter/mcp-9m5hs2z0.js → internal/tool-types.js} +4 -16
- package/dist/internal/uri-template.d.ts +8 -0
- package/dist/internal/uri-template.js +7 -0
- package/dist/progress.d.ts +2 -0
- package/dist/progress.js +7 -0
- package/dist/schema.js +1 -1
- package/dist/server.d.ts +7 -2
- package/dist/server.js +6 -3
- package/dist/shared/@outfitter/{mcp-5b5726ga.d.ts → mcp-3hxaatj9.d.ts} +37 -6
- package/dist/shared/@outfitter/{mcp-zb3p61y9.d.ts → mcp-4s22693j.d.ts} +1 -1
- package/dist/shared/@outfitter/mcp-7btcghjj.d.ts +304 -0
- package/dist/shared/@outfitter/mcp-9ry52yg3.d.ts +187 -0
- package/dist/shared/@outfitter/mcp-dgwj3jna.d.ts +103 -0
- package/dist/shared/@outfitter/{mcp-5jcgb033.d.ts → mcp-f67dnr72.d.ts} +1 -1
- package/dist/shared/@outfitter/mcp-hw5wz4gb.js +1 -0
- package/dist/shared/@outfitter/mcp-knc1gq0g.d.ts +130 -0
- package/dist/shared/@outfitter/mcp-n9vzcp37.js +55 -0
- package/dist/shared/@outfitter/mcp-q5hr7227.d.ts +24 -0
- package/dist/shared/@outfitter/mcp-q70dtfj6.js +53 -0
- package/dist/shared/@outfitter/mcp-r27vbpc1.d.ts +45 -0
- package/dist/shared/@outfitter/mcp-s2vnhzav.js +2 -0
- package/dist/shared/@outfitter/{mcp-s3gfhcdk.d.ts → mcp-yf0w5cgh.d.ts} +1 -1
- package/dist/shared/@outfitter/{mcp-hh12tqfg.js → mcp-yf1n85e9.js} +79 -119
- package/dist/shared/@outfitter/mcp-zt2s3r38.js +33 -0
- package/dist/transport.d.ts +7 -2
- package/dist/transport.js +161 -5
- package/dist/types.d.ts +7 -2
- package/dist/types.js +1 -1
- package/package.json +33 -27
- package/dist/shared/@outfitter/mcp-fks4zt1z.d.ts +0 -699
- package/dist/shared/@outfitter/mcp-mzky3ck8.js +0 -165
- package/dist/shared/@outfitter/mcp-zmc7ht6z.js +0 -28
- package/dist/shared/@outfitter/mcp-zv3ej45k.js +0 -143
- package/dist/shared/@outfitter/mcp-zy7b487d.js +0 -5
package/README.md
CHANGED
|
@@ -54,9 +54,9 @@ Creates an MCP server instance.
|
|
|
54
54
|
|
|
55
55
|
```typescript
|
|
56
56
|
interface McpServerOptions {
|
|
57
|
-
name: string;
|
|
58
|
-
version: string;
|
|
59
|
-
logger?: Logger;
|
|
57
|
+
name: string; // Server name for MCP handshake
|
|
58
|
+
version: string; // Server version (semver)
|
|
59
|
+
logger?: Logger; // Optional structured logger (BYO)
|
|
60
60
|
defaultLogLevel?: McpLogLevel | null; // Default log forwarding level
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -140,6 +140,7 @@ const server = createMcpServer({
|
|
|
140
140
|
MCP servers can forward log messages to the connected client. The default log level is resolved from environment configuration:
|
|
141
141
|
|
|
142
142
|
**Precedence** (highest wins):
|
|
143
|
+
|
|
143
144
|
1. `OUTFITTER_LOG_LEVEL` environment variable
|
|
144
145
|
2. `options.defaultLogLevel`
|
|
145
146
|
3. `OUTFITTER_ENV` profile defaults (`"debug"` in development, `null` otherwise)
|
|
@@ -176,11 +177,11 @@ Helper for defining typed tools with better type inference.
|
|
|
176
177
|
|
|
177
178
|
```typescript
|
|
178
179
|
interface ToolDefinition<TInput, TOutput, TError> {
|
|
179
|
-
name: string;
|
|
180
|
-
description: string;
|
|
181
|
-
inputSchema: z.ZodType<TInput>;
|
|
180
|
+
name: string; // Unique tool name (kebab-case)
|
|
181
|
+
description: string; // Human-readable description
|
|
182
|
+
inputSchema: z.ZodType<TInput>; // Zod schema for validation
|
|
182
183
|
handler: Handler<TInput, TOutput, TError>;
|
|
183
|
-
deferLoading?: boolean;
|
|
184
|
+
deferLoading?: boolean; // Default: true
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
const getUserTool = defineTool({
|
|
@@ -203,10 +204,10 @@ Helper for defining MCP resources.
|
|
|
203
204
|
|
|
204
205
|
```typescript
|
|
205
206
|
interface ResourceDefinition {
|
|
206
|
-
uri: string;
|
|
207
|
-
name: string;
|
|
208
|
-
description?: string;
|
|
209
|
-
mimeType?: string;
|
|
207
|
+
uri: string; // Unique resource URI
|
|
208
|
+
name: string; // Human-readable name
|
|
209
|
+
description?: string; // Optional description
|
|
210
|
+
mimeType?: string; // Content MIME type
|
|
210
211
|
handler?: ResourceReadHandler; // Optional resources/read handler
|
|
211
212
|
}
|
|
212
213
|
|
|
@@ -236,6 +237,47 @@ server.registerResource(configResource);
|
|
|
236
237
|
const contentResult = await server.readResource("file:///etc/app/config.json");
|
|
237
238
|
```
|
|
238
239
|
|
|
240
|
+
### defineResourceTemplate(definition)
|
|
241
|
+
|
|
242
|
+
Helper for defining MCP resource templates with URI pattern matching and optional Zod validation.
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
import { defineResourceTemplate } from "@outfitter/mcp";
|
|
246
|
+
import { z } from "zod";
|
|
247
|
+
|
|
248
|
+
// Basic template with string variables
|
|
249
|
+
const userTemplate = defineResourceTemplate({
|
|
250
|
+
uriTemplate: "db:///users/{userId}/profile",
|
|
251
|
+
name: "User Profile",
|
|
252
|
+
handler: async (uri, variables, ctx) => {
|
|
253
|
+
const profile = await getProfile(variables.userId);
|
|
254
|
+
return Result.ok([
|
|
255
|
+
{ uri, text: JSON.stringify(profile), mimeType: "application/json" },
|
|
256
|
+
]);
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Typed template with Zod validation and coercion
|
|
261
|
+
const postTemplate = defineResourceTemplate({
|
|
262
|
+
uriTemplate: "db:///users/{userId}/posts/{postId}",
|
|
263
|
+
name: "User Post",
|
|
264
|
+
paramSchema: z.object({
|
|
265
|
+
userId: z.string().min(1),
|
|
266
|
+
postId: z.coerce.number().int().positive(),
|
|
267
|
+
}),
|
|
268
|
+
handler: async (uri, params, ctx) => {
|
|
269
|
+
// params is { userId: string; postId: number } — validated and coerced
|
|
270
|
+
const post = await getPost(params.userId, params.postId);
|
|
271
|
+
return Result.ok([{ uri, text: JSON.stringify(post) }]);
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
server.registerResourceTemplate(userTemplate);
|
|
276
|
+
server.registerResourceTemplate(postTemplate);
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Templates use RFC 6570 Level 1 URI templates (`{param}` placeholders). Typed templates validate extracted variables against a Zod schema before handler invocation.
|
|
280
|
+
|
|
239
281
|
### Server Methods
|
|
240
282
|
|
|
241
283
|
```typescript
|
|
@@ -255,7 +297,11 @@ interface McpServer {
|
|
|
255
297
|
|
|
256
298
|
// Invocation
|
|
257
299
|
readResource(uri: string): Promise<Result<ResourceContent[], McpError>>;
|
|
258
|
-
invokeTool<T>(
|
|
300
|
+
invokeTool<T>(
|
|
301
|
+
name: string,
|
|
302
|
+
input: unknown,
|
|
303
|
+
options?: InvokeToolOptions
|
|
304
|
+
): Promise<Result<T, McpError>>;
|
|
259
305
|
|
|
260
306
|
// Lifecycle
|
|
261
307
|
start(): Promise<void>;
|
|
@@ -269,10 +315,61 @@ Extended handler context for MCP tools with additional metadata:
|
|
|
269
315
|
|
|
270
316
|
```typescript
|
|
271
317
|
interface McpHandlerContext extends HandlerContext {
|
|
272
|
-
toolName?: string;
|
|
318
|
+
toolName?: string; // Name of the tool being invoked
|
|
273
319
|
}
|
|
274
320
|
```
|
|
275
321
|
|
|
322
|
+
## Streaming and Progress (`@outfitter/mcp/progress`)
|
|
323
|
+
|
|
324
|
+
When an MCP client provides a `progressToken` in the tool call params, the server automatically creates a progress callback and injects it into the handler context as `ctx.progress`. Each call emits a `notifications/progress` notification.
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
const tool = defineTool({
|
|
328
|
+
name: "index-files",
|
|
329
|
+
description: "Index workspace files",
|
|
330
|
+
inputSchema: z.object({ path: z.string() }),
|
|
331
|
+
handler: async (input, ctx) => {
|
|
332
|
+
const files = await listFiles(input.path);
|
|
333
|
+
|
|
334
|
+
for (let i = 0; i < files.length; i++) {
|
|
335
|
+
await indexFile(files[i]);
|
|
336
|
+
ctx.progress?.({ type: "progress", current: i + 1, total: files.length });
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
ctx.progress?.({
|
|
340
|
+
type: "step",
|
|
341
|
+
name: "complete",
|
|
342
|
+
status: "complete",
|
|
343
|
+
duration_ms: 150,
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
return Result.ok({ indexed: files.length });
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Use optional chaining (`ctx.progress?.()`) so the handler works whether or not the client requested progress tracking. Without a `progressToken`, `ctx.progress` is `undefined` and no notifications are sent.
|
|
352
|
+
|
|
353
|
+
**Event mapping to MCP notifications:**
|
|
354
|
+
|
|
355
|
+
| StreamEvent type | MCP `progress` | MCP `total` | MCP `message` |
|
|
356
|
+
| ---------------- | -------------- | ----------- | ------------------------- |
|
|
357
|
+
| `start` | `0` | -- | `[start] {command}` |
|
|
358
|
+
| `step` | `0` | -- | `[step] {name}: {status}` |
|
|
359
|
+
| `progress` | `current` | `total` | `message` (if provided) |
|
|
360
|
+
|
|
361
|
+
The progress callback uses the same `StreamEvent` types from `@outfitter/contracts/stream` as the CLI NDJSON adapter, keeping handlers transport-agnostic.
|
|
362
|
+
|
|
363
|
+
**Programmatic usage** (for custom transport layers):
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
import { createMcpProgressCallback } from "@outfitter/mcp/progress";
|
|
367
|
+
|
|
368
|
+
const progress = createMcpProgressCallback("tok-123", (notification) =>
|
|
369
|
+
sdkServer.notification(notification)
|
|
370
|
+
);
|
|
371
|
+
```
|
|
372
|
+
|
|
276
373
|
## Core Tools
|
|
277
374
|
|
|
278
375
|
Pre-built tools for common MCP patterns. These are marked with `deferLoading: false` for immediate availability.
|
|
@@ -372,7 +469,9 @@ const listTool = defineTool({
|
|
|
372
469
|
description: "List all items",
|
|
373
470
|
inputSchema: z.object({}),
|
|
374
471
|
annotations: TOOL_ANNOTATIONS.readOnly,
|
|
375
|
-
handler: async (input, ctx) => {
|
|
472
|
+
handler: async (input, ctx) => {
|
|
473
|
+
/* ... */
|
|
474
|
+
},
|
|
376
475
|
});
|
|
377
476
|
|
|
378
477
|
// Spread and override for edge cases
|
|
@@ -381,17 +480,19 @@ const searchTool = defineTool({
|
|
|
381
480
|
description: "Search external APIs",
|
|
382
481
|
inputSchema: z.object({ q: z.string() }),
|
|
383
482
|
annotations: { ...TOOL_ANNOTATIONS.readOnly, openWorldHint: true },
|
|
384
|
-
handler: async (input, ctx) => {
|
|
483
|
+
handler: async (input, ctx) => {
|
|
484
|
+
/* ... */
|
|
485
|
+
},
|
|
385
486
|
});
|
|
386
487
|
```
|
|
387
488
|
|
|
388
|
-
| Preset
|
|
389
|
-
|
|
390
|
-
| `readOnly`
|
|
391
|
-
| `write`
|
|
392
|
-
| `writeIdempotent` | false
|
|
393
|
-
| `destructive`
|
|
394
|
-
| `openWorld`
|
|
489
|
+
| Preset | readOnly | destructive | idempotent | openWorld |
|
|
490
|
+
| ----------------- | -------- | ----------- | ---------- | --------- |
|
|
491
|
+
| `readOnly` | true | false | true | false |
|
|
492
|
+
| `write` | false | false | false | false |
|
|
493
|
+
| `writeIdempotent` | false | false | true | false |
|
|
494
|
+
| `destructive` | false | true | true | false |
|
|
495
|
+
| `openWorld` | false | false | false | true |
|
|
395
496
|
|
|
396
497
|
For multi-action tools, use the most conservative union of hints. Per-action annotations are an MCP spec limitation.
|
|
397
498
|
|
|
@@ -454,12 +555,12 @@ const { server: sdkServer, toolsList, callTool } = createSdkServer(mcpServer);
|
|
|
454
555
|
|
|
455
556
|
Tools return Results with typed errors. The framework automatically translates `OutfitterError` categories to JSON-RPC error codes:
|
|
456
557
|
|
|
457
|
-
| Category
|
|
458
|
-
|
|
459
|
-
| `validation` | -32602
|
|
460
|
-
| `not_found`
|
|
461
|
-
| `permission` | -32600
|
|
462
|
-
| `internal`
|
|
558
|
+
| Category | JSON-RPC Code | Description |
|
|
559
|
+
| ------------ | ------------- | ---------------- |
|
|
560
|
+
| `validation` | -32602 | Invalid params |
|
|
561
|
+
| `not_found` | -32601 | Method not found |
|
|
562
|
+
| `permission` | -32600 | Invalid request |
|
|
563
|
+
| `internal` | -32603 | Internal error |
|
|
463
564
|
|
|
464
565
|
```typescript
|
|
465
566
|
const result = await server.invokeTool("get-user", { userId: "123" });
|
|
@@ -523,6 +624,7 @@ Add your MCP server to Claude Desktop:
|
|
|
523
624
|
```
|
|
524
625
|
|
|
525
626
|
Config location:
|
|
627
|
+
|
|
526
628
|
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
527
629
|
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
528
630
|
- Linux: `~/.config/claude/claude_desktop_config.json`
|
package/dist/actions.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import { BuildMcpToolsOptions, buildMcpTools } from "./shared/@outfitter/mcp-
|
|
2
|
-
import "./shared/@outfitter/mcp-
|
|
1
|
+
import { BuildMcpToolsOptions, buildMcpTools } from "./shared/@outfitter/mcp-f67dnr72.js";
|
|
2
|
+
import "./shared/@outfitter/mcp-qmdmgxa1.js";
|
|
3
|
+
import "./shared/@outfitter/mcp-7btcghjj.js";
|
|
4
|
+
import "./shared/@outfitter/mcp-knc1gq0g.js";
|
|
5
|
+
import "./shared/@outfitter/mcp-9ry52yg3.js";
|
|
6
|
+
import "./shared/@outfitter/mcp-dgwj3jna.js";
|
|
7
|
+
import "./shared/@outfitter/mcp-q5hr7227.js";
|
|
3
8
|
import "./shared/@outfitter/mcp-cqpyer9m.js";
|
|
4
9
|
export { buildMcpTools, BuildMcpToolsOptions };
|
package/dist/actions.js
CHANGED
|
@@ -1,11 +1,58 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
} from "./shared/@outfitter/mcp-
|
|
5
|
-
import"./shared/@outfitter/mcp-
|
|
3
|
+
defineTool
|
|
4
|
+
} from "./shared/@outfitter/mcp-yf1n85e9.js";
|
|
5
|
+
import"./shared/@outfitter/mcp-n9vzcp37.js";
|
|
6
|
+
import"./shared/@outfitter/mcp-zt2s3r38.js";
|
|
7
|
+
import"./shared/@outfitter/mcp-q70dtfj6.js";
|
|
6
8
|
import"./shared/@outfitter/mcp-fjtxsa0x.js";
|
|
7
|
-
import"./shared/@outfitter/mcp-
|
|
8
|
-
import"./shared/@outfitter/mcp-
|
|
9
|
+
import"./shared/@outfitter/mcp-s2vnhzav.js";
|
|
10
|
+
import"./shared/@outfitter/mcp-hw5wz4gb.js";
|
|
11
|
+
|
|
12
|
+
// packages/mcp/src/actions.ts
|
|
13
|
+
import { DEFAULT_REGISTRY_SURFACES } from "@outfitter/contracts";
|
|
14
|
+
function isActionRegistry(source) {
|
|
15
|
+
return "list" in source;
|
|
16
|
+
}
|
|
17
|
+
function buildAnnotations(mcp) {
|
|
18
|
+
if (!mcp)
|
|
19
|
+
return;
|
|
20
|
+
const annotations = {};
|
|
21
|
+
let hasAnnotation = false;
|
|
22
|
+
if (mcp.readOnly === true) {
|
|
23
|
+
annotations["readOnlyHint"] = true;
|
|
24
|
+
hasAnnotation = true;
|
|
25
|
+
}
|
|
26
|
+
if (mcp.idempotent === true) {
|
|
27
|
+
annotations["idempotentHint"] = true;
|
|
28
|
+
hasAnnotation = true;
|
|
29
|
+
}
|
|
30
|
+
if (mcp.destructive === true) {
|
|
31
|
+
annotations["destructiveHint"] = true;
|
|
32
|
+
hasAnnotation = true;
|
|
33
|
+
}
|
|
34
|
+
return hasAnnotation ? annotations : undefined;
|
|
35
|
+
}
|
|
36
|
+
function buildMcpTools(source, options = {}) {
|
|
37
|
+
const actions = isActionRegistry(source) ? source.list() : source;
|
|
38
|
+
const includeSurfaces = options.includeSurfaces ?? [
|
|
39
|
+
"mcp"
|
|
40
|
+
];
|
|
41
|
+
return actions.filter((action) => {
|
|
42
|
+
const surfaces = action.surfaces ?? DEFAULT_REGISTRY_SURFACES;
|
|
43
|
+
return surfaces.some((surface) => includeSurfaces.includes(surface));
|
|
44
|
+
}).map((action) => {
|
|
45
|
+
const annotations = buildAnnotations(action.mcp);
|
|
46
|
+
return defineTool({
|
|
47
|
+
name: action.mcp?.tool ?? action.id,
|
|
48
|
+
description: action.mcp?.description ?? action.description ?? action.id,
|
|
49
|
+
inputSchema: action.input,
|
|
50
|
+
handler: async (input, ctx) => action.handler(input, ctx),
|
|
51
|
+
...action.mcp?.deferLoading !== undefined ? { deferLoading: action.mcp.deferLoading } : {},
|
|
52
|
+
...annotations ? { annotations } : {}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
9
56
|
export {
|
|
10
57
|
buildMcpTools
|
|
11
58
|
};
|
package/dist/core-tools.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import { ConfigAction, ConfigStore, ConfigToolInput, ConfigToolOptions, ConfigToolResponse, CoreToolDefinition, CoreToolsOptions, DocsSection, DocsToolEntry, DocsToolInput, DocsToolOptions, DocsToolResponse, NormalizedQueryInput, QueryToolInput, QueryToolOptions, QueryToolResponse, createCoreTools, defineConfigTool, defineDocsTool, defineQueryTool } from "./shared/@outfitter/mcp-
|
|
2
|
-
import "./shared/@outfitter/mcp-
|
|
1
|
+
import { ConfigAction, ConfigStore, ConfigToolInput, ConfigToolOptions, ConfigToolResponse, CoreToolDefinition, CoreToolsOptions, DocsSection, DocsToolEntry, DocsToolInput, DocsToolOptions, DocsToolResponse, NormalizedQueryInput, QueryToolInput, QueryToolOptions, QueryToolResponse, createCoreTools, defineConfigTool, defineDocsTool, defineQueryTool } from "./shared/@outfitter/mcp-4s22693j.js";
|
|
2
|
+
import "./shared/@outfitter/mcp-qmdmgxa1.js";
|
|
3
|
+
import "./shared/@outfitter/mcp-7btcghjj.js";
|
|
4
|
+
import "./shared/@outfitter/mcp-knc1gq0g.js";
|
|
5
|
+
import "./shared/@outfitter/mcp-9ry52yg3.js";
|
|
6
|
+
import "./shared/@outfitter/mcp-dgwj3jna.js";
|
|
7
|
+
import "./shared/@outfitter/mcp-q5hr7227.js";
|
|
3
8
|
import "./shared/@outfitter/mcp-cqpyer9m.js";
|
|
4
9
|
export { defineQueryTool, defineDocsTool, defineConfigTool, createCoreTools, QueryToolResponse, QueryToolOptions, QueryToolInput, NormalizedQueryInput, DocsToolResponse, DocsToolOptions, DocsToolInput, DocsToolEntry, DocsSection, CoreToolsOptions, CoreToolDefinition, ConfigToolResponse, ConfigToolOptions, ConfigToolInput, ConfigStore, ConfigAction };
|
package/dist/core-tools.js
CHANGED
|
@@ -1,10 +1,144 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
// packages/mcp/src/core-tools.ts
|
|
3
|
+
import { Result, ValidationError } from "@outfitter/contracts";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
var DEFAULT_DOCS = {
|
|
6
|
+
overview: "No documentation configured yet.",
|
|
7
|
+
tools: [],
|
|
8
|
+
examples: [],
|
|
9
|
+
schemas: {}
|
|
10
|
+
};
|
|
11
|
+
var docsSchema = z.object({
|
|
12
|
+
section: z.enum(["overview", "tools", "examples", "schemas"]).optional()
|
|
13
|
+
});
|
|
14
|
+
function pickDocsSection(payload, section) {
|
|
15
|
+
if (!section) {
|
|
16
|
+
return payload;
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
[section]: payload[section]
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function defineDocsTool(options = {}) {
|
|
23
|
+
return {
|
|
24
|
+
name: "docs",
|
|
25
|
+
description: options.description ?? "Documentation, usage patterns, and examples for this MCP server.",
|
|
26
|
+
deferLoading: false,
|
|
27
|
+
inputSchema: docsSchema,
|
|
28
|
+
handler: async (input) => {
|
|
29
|
+
const payload = options.getDocs ? await options.getDocs(input.section) : options.docs ?? DEFAULT_DOCS;
|
|
30
|
+
return Result.ok(pickDocsSection(payload, input.section));
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
var configSchema = z.object({
|
|
35
|
+
action: z.enum(["get", "set", "list"]),
|
|
36
|
+
key: z.string().optional(),
|
|
37
|
+
value: z.unknown().optional()
|
|
38
|
+
});
|
|
39
|
+
function createInMemoryStore(initial = {}) {
|
|
40
|
+
const store = new Map(Object.entries(initial));
|
|
41
|
+
return {
|
|
42
|
+
get(key) {
|
|
43
|
+
return { value: store.get(key), found: store.has(key) };
|
|
44
|
+
},
|
|
45
|
+
set(key, value) {
|
|
46
|
+
store.set(key, value);
|
|
47
|
+
},
|
|
48
|
+
list() {
|
|
49
|
+
return Object.fromEntries(store.entries());
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function defineConfigTool(options = {}) {
|
|
54
|
+
const store = options.store ?? createInMemoryStore(options.initial);
|
|
55
|
+
return {
|
|
56
|
+
name: "config",
|
|
57
|
+
description: options.description ?? "Read or modify server configuration values.",
|
|
58
|
+
deferLoading: false,
|
|
59
|
+
inputSchema: configSchema,
|
|
60
|
+
handler: async (input) => {
|
|
61
|
+
switch (input.action) {
|
|
62
|
+
case "list": {
|
|
63
|
+
const config = await store.list();
|
|
64
|
+
return Result.ok({ action: "list", config });
|
|
65
|
+
}
|
|
66
|
+
case "get": {
|
|
67
|
+
if (!input.key) {
|
|
68
|
+
return Result.err(new ValidationError({
|
|
69
|
+
message: "Config key is required for action 'get'.",
|
|
70
|
+
field: "key"
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
const { value, found } = await store.get(input.key);
|
|
74
|
+
return Result.ok({ action: "get", key: input.key, value, found });
|
|
75
|
+
}
|
|
76
|
+
case "set": {
|
|
77
|
+
if (!input.key) {
|
|
78
|
+
return Result.err(new ValidationError({
|
|
79
|
+
message: "Config key is required for action 'set'.",
|
|
80
|
+
field: "key"
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
await store.set(input.key, input.value);
|
|
84
|
+
return Result.ok({
|
|
85
|
+
action: "set",
|
|
86
|
+
key: input.key,
|
|
87
|
+
value: input.value
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
default:
|
|
91
|
+
return Result.err(new ValidationError({
|
|
92
|
+
message: `Unknown action: ${input.action}`,
|
|
93
|
+
field: "action"
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
var querySchema = z.object({
|
|
100
|
+
q: z.string().min(1).describe("Search query. Supports natural language or filter syntax.").optional(),
|
|
101
|
+
query: z.string().min(1).describe("Alias for q. Supports natural language or filter syntax.").optional(),
|
|
102
|
+
limit: z.number().int().positive().optional(),
|
|
103
|
+
cursor: z.string().optional(),
|
|
104
|
+
filters: z.record(z.string(), z.unknown()).optional()
|
|
105
|
+
}).refine((value) => {
|
|
106
|
+
const queryValue = (value.q ?? value.query)?.trim();
|
|
107
|
+
return typeof queryValue === "string" && queryValue.length > 0;
|
|
108
|
+
}, {
|
|
109
|
+
message: "Query is required.",
|
|
110
|
+
path: ["q"]
|
|
111
|
+
});
|
|
112
|
+
function defineQueryTool(options = {}) {
|
|
113
|
+
return {
|
|
114
|
+
name: "query",
|
|
115
|
+
description: options.description ?? "Search and discover resources with filters and pagination.",
|
|
116
|
+
deferLoading: false,
|
|
117
|
+
inputSchema: querySchema,
|
|
118
|
+
handler: (input, ctx) => {
|
|
119
|
+
const normalized = {
|
|
120
|
+
...input,
|
|
121
|
+
q: (input.q ?? input.query ?? "").trim()
|
|
122
|
+
};
|
|
123
|
+
if (options.handler) {
|
|
124
|
+
return options.handler(normalized, ctx);
|
|
125
|
+
}
|
|
126
|
+
return Promise.resolve(Result.ok({
|
|
127
|
+
results: [],
|
|
128
|
+
_meta: {
|
|
129
|
+
note: "No query handler configured."
|
|
130
|
+
}
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function createCoreTools(options = {}) {
|
|
136
|
+
return [
|
|
137
|
+
defineDocsTool(options.docs),
|
|
138
|
+
defineConfigTool(options.config),
|
|
139
|
+
defineQueryTool(options.query)
|
|
140
|
+
];
|
|
141
|
+
}
|
|
8
142
|
export {
|
|
9
143
|
defineQueryTool,
|
|
10
144
|
defineDocsTool,
|