@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.
Files changed (52) hide show
  1. package/README.md +130 -28
  2. package/dist/actions.d.ts +7 -2
  3. package/dist/actions.js +52 -5
  4. package/dist/core-tools.d.ts +7 -2
  5. package/dist/core-tools.js +140 -6
  6. package/dist/index.d.ts +14 -953
  7. package/dist/index.js +8 -959
  8. package/dist/internal/content-types.d.ts +2 -0
  9. package/dist/internal/content-types.js +1 -0
  10. package/dist/internal/log-config.d.ts +24 -0
  11. package/dist/internal/log-config.js +13 -0
  12. package/dist/internal/prompt-types.d.ts +3 -0
  13. package/dist/internal/prompt-types.js +1 -0
  14. package/dist/internal/resource-types.d.ts +4 -0
  15. package/dist/internal/resource-types.js +1 -0
  16. package/dist/internal/server-types.d.ts +7 -0
  17. package/dist/internal/server-types.js +20 -0
  18. package/dist/internal/tool-types.d.ts +2 -0
  19. package/dist/{shared/@outfitter/mcp-9m5hs2z0.js → internal/tool-types.js} +4 -16
  20. package/dist/internal/uri-template.d.ts +8 -0
  21. package/dist/internal/uri-template.js +7 -0
  22. package/dist/progress.d.ts +2 -0
  23. package/dist/progress.js +7 -0
  24. package/dist/schema.js +1 -1
  25. package/dist/server.d.ts +7 -2
  26. package/dist/server.js +6 -3
  27. package/dist/shared/@outfitter/{mcp-5b5726ga.d.ts → mcp-3hxaatj9.d.ts} +37 -6
  28. package/dist/shared/@outfitter/{mcp-zb3p61y9.d.ts → mcp-4s22693j.d.ts} +1 -1
  29. package/dist/shared/@outfitter/mcp-7btcghjj.d.ts +304 -0
  30. package/dist/shared/@outfitter/mcp-9ry52yg3.d.ts +187 -0
  31. package/dist/shared/@outfitter/mcp-dgwj3jna.d.ts +103 -0
  32. package/dist/shared/@outfitter/{mcp-5jcgb033.d.ts → mcp-f67dnr72.d.ts} +1 -1
  33. package/dist/shared/@outfitter/mcp-hw5wz4gb.js +1 -0
  34. package/dist/shared/@outfitter/mcp-knc1gq0g.d.ts +130 -0
  35. package/dist/shared/@outfitter/mcp-n9vzcp37.js +55 -0
  36. package/dist/shared/@outfitter/mcp-q5hr7227.d.ts +24 -0
  37. package/dist/shared/@outfitter/mcp-q70dtfj6.js +53 -0
  38. package/dist/shared/@outfitter/mcp-r27vbpc1.d.ts +45 -0
  39. package/dist/shared/@outfitter/mcp-s2vnhzav.js +2 -0
  40. package/dist/shared/@outfitter/{mcp-s3gfhcdk.d.ts → mcp-yf0w5cgh.d.ts} +1 -1
  41. package/dist/shared/@outfitter/{mcp-hh12tqfg.js → mcp-yf1n85e9.js} +79 -119
  42. package/dist/shared/@outfitter/mcp-zt2s3r38.js +33 -0
  43. package/dist/transport.d.ts +7 -2
  44. package/dist/transport.js +161 -5
  45. package/dist/types.d.ts +7 -2
  46. package/dist/types.js +1 -1
  47. package/package.json +33 -27
  48. package/dist/shared/@outfitter/mcp-fks4zt1z.d.ts +0 -699
  49. package/dist/shared/@outfitter/mcp-mzky3ck8.js +0 -165
  50. package/dist/shared/@outfitter/mcp-zmc7ht6z.js +0 -28
  51. package/dist/shared/@outfitter/mcp-zv3ej45k.js +0 -143
  52. 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; // 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
 
@@ -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>(name: string, input: unknown, options?: InvokeToolOptions): Promise<Result<T, McpError>>;
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; // Name of the tool being invoked
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 | 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 |
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 | 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 |
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-5jcgb033.js";
2
- import "./shared/@outfitter/mcp-fks4zt1z.js";
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
- buildMcpTools
4
- } from "./shared/@outfitter/mcp-zmc7ht6z.js";
5
- import"./shared/@outfitter/mcp-hh12tqfg.js";
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-zy7b487d.js";
8
- import"./shared/@outfitter/mcp-9m5hs2z0.js";
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
  };
@@ -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-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-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 };
@@ -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,