@outfitter/mcp 0.4.2 → 0.4.3

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 CHANGED
@@ -54,9 +54,9 @@ Creates an MCP server instance.
54
54
 
55
55
  ```typescript
56
56
  interface McpServerOptions {
57
- name: string; // Server name for MCP handshake
58
- version: string; // Server version (semver)
59
- logger?: Logger; // Optional structured logger (BYO)
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; // Unique tool name (kebab-case)
180
- description: string; // Human-readable description
181
- inputSchema: z.ZodType<TInput>; // Zod schema for validation
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; // Default: true
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; // Unique resource URI
207
- name: string; // Human-readable name
208
- description?: string; // Optional description
209
- mimeType?: string; // Content MIME type
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
 
@@ -255,7 +256,11 @@ interface McpServer {
255
256
 
256
257
  // Invocation
257
258
  readResource(uri: string): Promise<Result<ResourceContent[], McpError>>;
258
- invokeTool<T>(name: string, input: unknown, options?: InvokeToolOptions): Promise<Result<T, McpError>>;
259
+ invokeTool<T>(
260
+ name: string,
261
+ input: unknown,
262
+ options?: InvokeToolOptions
263
+ ): Promise<Result<T, McpError>>;
259
264
 
260
265
  // Lifecycle
261
266
  start(): Promise<void>;
@@ -269,7 +274,7 @@ Extended handler context for MCP tools with additional metadata:
269
274
 
270
275
  ```typescript
271
276
  interface McpHandlerContext extends HandlerContext {
272
- toolName?: string; // Name of the tool being invoked
277
+ toolName?: string; // Name of the tool being invoked
273
278
  }
274
279
  ```
275
280
 
@@ -372,7 +377,9 @@ const listTool = defineTool({
372
377
  description: "List all items",
373
378
  inputSchema: z.object({}),
374
379
  annotations: TOOL_ANNOTATIONS.readOnly,
375
- handler: async (input, ctx) => { /* ... */ },
380
+ handler: async (input, ctx) => {
381
+ /* ... */
382
+ },
376
383
  });
377
384
 
378
385
  // Spread and override for edge cases
@@ -381,17 +388,19 @@ const searchTool = defineTool({
381
388
  description: "Search external APIs",
382
389
  inputSchema: z.object({ q: z.string() }),
383
390
  annotations: { ...TOOL_ANNOTATIONS.readOnly, openWorldHint: true },
384
- handler: async (input, ctx) => { /* ... */ },
391
+ handler: async (input, ctx) => {
392
+ /* ... */
393
+ },
385
394
  });
386
395
  ```
387
396
 
388
- | Preset | readOnly | destructive | idempotent | openWorld |
389
- |--------|----------|-------------|------------|-----------|
390
- | `readOnly` | true | false | true | false |
391
- | `write` | false | false | false | false |
392
- | `writeIdempotent` | false | false | true | false |
393
- | `destructive` | false | true | true | false |
394
- | `openWorld` | false | false | false | true |
397
+ | Preset | readOnly | destructive | idempotent | openWorld |
398
+ | ----------------- | -------- | ----------- | ---------- | --------- |
399
+ | `readOnly` | true | false | true | false |
400
+ | `write` | false | false | false | false |
401
+ | `writeIdempotent` | false | false | true | false |
402
+ | `destructive` | false | true | true | false |
403
+ | `openWorld` | false | false | false | true |
395
404
 
396
405
  For multi-action tools, use the most conservative union of hints. Per-action annotations are an MCP spec limitation.
397
406
 
@@ -454,12 +463,12 @@ const { server: sdkServer, toolsList, callTool } = createSdkServer(mcpServer);
454
463
 
455
464
  Tools return Results with typed errors. The framework automatically translates `OutfitterError` categories to JSON-RPC error codes:
456
465
 
457
- | Category | JSON-RPC Code | Description |
458
- |----------|--------------|-------------|
459
- | `validation` | -32602 | Invalid params |
460
- | `not_found` | -32601 | Method not found |
461
- | `permission` | -32600 | Invalid request |
462
- | `internal` | -32603 | Internal error |
466
+ | Category | JSON-RPC Code | Description |
467
+ | ------------ | ------------- | ---------------- |
468
+ | `validation` | -32602 | Invalid params |
469
+ | `not_found` | -32601 | Method not found |
470
+ | `permission` | -32600 | Invalid request |
471
+ | `internal` | -32603 | Internal error |
463
472
 
464
473
  ```typescript
465
474
  const result = await server.invokeTool("get-user", { userId: "123" });
@@ -523,6 +532,7 @@ Add your MCP server to Claude Desktop:
523
532
  ```
524
533
 
525
534
  Config location:
535
+
526
536
  - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
527
537
  - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
528
538
  - Linux: `~/.config/claude/claude_desktop_config.json`
package/dist/actions.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { BuildMcpToolsOptions, buildMcpTools } from "./shared/@outfitter/mcp-5jcgb033.js";
2
- import "./shared/@outfitter/mcp-fks4zt1z.js";
1
+ import { BuildMcpToolsOptions, buildMcpTools } from "./shared/@outfitter/mcp-d8vs6vry.js";
2
+ import "./shared/@outfitter/mcp-gqjg15f5.js";
3
3
  import "./shared/@outfitter/mcp-cqpyer9m.js";
4
4
  export { buildMcpTools, BuildMcpToolsOptions };
package/dist/actions.js CHANGED
@@ -1,11 +1,32 @@
1
1
  // @bun
2
2
  import {
3
- buildMcpTools
4
- } from "./shared/@outfitter/mcp-zmc7ht6z.js";
5
- import"./shared/@outfitter/mcp-hh12tqfg.js";
3
+ defineTool
4
+ } from "./shared/@outfitter/mcp-b502y16n.js";
6
5
  import"./shared/@outfitter/mcp-fjtxsa0x.js";
7
- import"./shared/@outfitter/mcp-zy7b487d.js";
8
6
  import"./shared/@outfitter/mcp-9m5hs2z0.js";
7
+ import"./shared/@outfitter/mcp-hw5wz4gb.js";
8
+
9
+ // packages/mcp/src/actions.ts
10
+ import { DEFAULT_REGISTRY_SURFACES } from "@outfitter/contracts";
11
+ function isActionRegistry(source) {
12
+ return "list" in source;
13
+ }
14
+ function buildMcpTools(source, options = {}) {
15
+ const actions = isActionRegistry(source) ? source.list() : source;
16
+ const includeSurfaces = options.includeSurfaces ?? [
17
+ "mcp"
18
+ ];
19
+ return actions.filter((action) => {
20
+ const surfaces = action.surfaces ?? DEFAULT_REGISTRY_SURFACES;
21
+ return surfaces.some((surface) => includeSurfaces.includes(surface));
22
+ }).map((action) => defineTool({
23
+ name: action.mcp?.tool ?? action.id,
24
+ description: action.mcp?.description ?? action.description ?? action.id,
25
+ inputSchema: action.input,
26
+ handler: async (input, ctx) => action.handler(input, ctx),
27
+ ...action.mcp?.deferLoading !== undefined ? { deferLoading: action.mcp.deferLoading } : {}
28
+ }));
29
+ }
9
30
  export {
10
31
  buildMcpTools
11
32
  };
@@ -1,4 +1,4 @@
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-zb3p61y9.js";
2
- import "./shared/@outfitter/mcp-fks4zt1z.js";
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-s6afm4ff.js";
2
+ import "./shared/@outfitter/mcp-gqjg15f5.js";
3
3
  import "./shared/@outfitter/mcp-cqpyer9m.js";
4
4
  export { defineQueryTool, defineDocsTool, defineConfigTool, createCoreTools, QueryToolResponse, QueryToolOptions, QueryToolInput, NormalizedQueryInput, DocsToolResponse, DocsToolOptions, DocsToolInput, DocsToolEntry, DocsSection, CoreToolsOptions, CoreToolDefinition, ConfigToolResponse, ConfigToolOptions, ConfigToolInput, ConfigStore, ConfigAction };
@@ -1,10 +1,144 @@
1
1
  // @bun
2
- import {
3
- createCoreTools,
4
- defineConfigTool,
5
- defineDocsTool,
6
- defineQueryTool
7
- } from "./shared/@outfitter/mcp-zv3ej45k.js";
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,