@outfitter/mcp 0.4.3 → 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 (44) hide show
  1. package/README.md +92 -0
  2. package/dist/actions.d.ts +7 -2
  3. package/dist/actions.js +35 -9
  4. package/dist/core-tools.d.ts +7 -2
  5. package/dist/index.d.ts +12 -6
  6. package/dist/index.js +1 -0
  7. package/dist/internal/content-types.d.ts +2 -0
  8. package/dist/internal/content-types.js +1 -0
  9. package/dist/internal/log-config.d.ts +24 -0
  10. package/dist/internal/log-config.js +13 -0
  11. package/dist/internal/prompt-types.d.ts +3 -0
  12. package/dist/internal/prompt-types.js +1 -0
  13. package/dist/internal/resource-types.d.ts +4 -0
  14. package/dist/internal/resource-types.js +1 -0
  15. package/dist/internal/server-types.d.ts +7 -0
  16. package/dist/internal/server-types.js +20 -0
  17. package/dist/internal/tool-types.d.ts +2 -0
  18. package/dist/{shared/@outfitter/mcp-9m5hs2z0.js → internal/tool-types.js} +4 -16
  19. package/dist/internal/uri-template.d.ts +8 -0
  20. package/dist/internal/uri-template.js +7 -0
  21. package/dist/progress.d.ts +2 -0
  22. package/dist/progress.js +7 -0
  23. package/dist/server.d.ts +7 -2
  24. package/dist/server.js +5 -2
  25. package/dist/shared/@outfitter/{mcp-knq080yt.d.ts → mcp-3hxaatj9.d.ts} +37 -6
  26. package/dist/shared/@outfitter/{mcp-s6afm4ff.d.ts → mcp-4s22693j.d.ts} +1 -1
  27. package/dist/shared/@outfitter/mcp-7btcghjj.d.ts +304 -0
  28. package/dist/shared/@outfitter/mcp-9ry52yg3.d.ts +187 -0
  29. package/dist/shared/@outfitter/mcp-dgwj3jna.d.ts +103 -0
  30. package/dist/shared/@outfitter/{mcp-d8vs6vry.d.ts → mcp-f67dnr72.d.ts} +1 -1
  31. package/dist/shared/@outfitter/mcp-knc1gq0g.d.ts +130 -0
  32. package/dist/shared/@outfitter/mcp-n9vzcp37.js +55 -0
  33. package/dist/shared/@outfitter/mcp-q5hr7227.d.ts +24 -0
  34. package/dist/shared/@outfitter/mcp-q70dtfj6.js +53 -0
  35. package/dist/shared/@outfitter/mcp-r27vbpc1.d.ts +45 -0
  36. package/dist/shared/@outfitter/mcp-s2vnhzav.js +2 -0
  37. package/dist/shared/@outfitter/{mcp-7kcw2814.d.ts → mcp-yf0w5cgh.d.ts} +1 -1
  38. package/dist/shared/@outfitter/{mcp-b502y16n.js → mcp-yf1n85e9.js} +76 -116
  39. package/dist/shared/@outfitter/mcp-zt2s3r38.js +33 -0
  40. package/dist/transport.d.ts +7 -2
  41. package/dist/types.d.ts +7 -2
  42. package/dist/types.js +1 -1
  43. package/package.json +26 -20
  44. package/dist/shared/@outfitter/mcp-gqjg15f5.d.ts +0 -669
@@ -0,0 +1,130 @@
1
+ import { Handler, OutfitterError } from "@outfitter/contracts";
2
+ import { z } from "zod";
3
+ /**
4
+ * Behavioral hints for MCP tools.
5
+ *
6
+ * Annotations help clients understand tool behavior without invoking them.
7
+ * All fields are optional — only include hints that apply.
8
+ *
9
+ * @see https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#annotations
10
+ */
11
+ interface ToolAnnotations {
12
+ /** When true, the tool may perform destructive operations (e.g., deleting data). */
13
+ destructiveHint?: boolean;
14
+ /** When true, calling the tool multiple times with the same input has the same effect. */
15
+ idempotentHint?: boolean;
16
+ /** When true, the tool may interact with external systems beyond the server. */
17
+ openWorldHint?: boolean;
18
+ /** When true, the tool does not modify any state. */
19
+ readOnlyHint?: boolean;
20
+ }
21
+ /**
22
+ * Common annotation presets for MCP tools.
23
+ *
24
+ * Use these as a starting point and spread-override individual hints:
25
+ *
26
+ * ```typescript
27
+ * annotations: { ...TOOL_ANNOTATIONS.readOnly, openWorldHint: true }
28
+ * ```
29
+ *
30
+ * For multi-action tools (e.g., a single tool with read and write actions),
31
+ * use the most conservative union of hints — if any action is destructive,
32
+ * mark the whole tool as destructive. Per-action annotations are an MCP spec
33
+ * limitation; presets + spread cover most edge cases.
34
+ */
35
+ declare const TOOL_ANNOTATIONS: {
36
+ readonly destructive: ToolAnnotations;
37
+ readonly openWorld: ToolAnnotations;
38
+ readonly readOnly: ToolAnnotations;
39
+ readonly write: ToolAnnotations;
40
+ readonly writeIdempotent: ToolAnnotations;
41
+ };
42
+ /**
43
+ * Definition of an MCP tool that can be invoked by clients.
44
+ *
45
+ * Tools are the primary way clients interact with MCP servers.
46
+ * Each tool has a name, description, input schema (for validation),
47
+ * and a handler function that processes requests.
48
+ *
49
+ * @typeParam TInput - The validated input type (inferred from Zod schema)
50
+ * @typeParam TOutput - The success output type
51
+ * @typeParam TError - The error type (must extend OutfitterError)
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * const getUserTool: ToolDefinition<
56
+ * { userId: string },
57
+ * { name: string; email: string },
58
+ * NotFoundError
59
+ * > = {
60
+ * name: "get-user",
61
+ * description: "Retrieve a user by ID",
62
+ * inputSchema: z.object({ userId: z.string().uuid() }),
63
+ * handler: async (input, ctx) => {
64
+ * ctx.logger.debug("Fetching user", { userId: input.userId });
65
+ * const user = await db.users.find(input.userId);
66
+ * if (!user) {
67
+ * return Result.err(new NotFoundError({
68
+ * message: `User ${input.userId} not found`,
69
+ * resourceType: "user",
70
+ * resourceId: input.userId,
71
+ * }));
72
+ * }
73
+ * return Result.ok({ name: user.name, email: user.email });
74
+ * },
75
+ * };
76
+ * ```
77
+ */
78
+ interface ToolDefinition<
79
+ TInput,
80
+ TOutput,
81
+ TError extends OutfitterError = OutfitterError
82
+ > {
83
+ /**
84
+ * Optional behavioral annotations for the tool.
85
+ * Helps clients understand tool behavior without invoking it.
86
+ */
87
+ annotations?: ToolAnnotations;
88
+ /**
89
+ * Whether the tool should be deferred for tool search.
90
+ * Defaults to true for domain tools; core tools set this to false.
91
+ */
92
+ deferLoading?: boolean;
93
+ /**
94
+ * Human-readable description of what the tool does.
95
+ * Shown to clients and used by LLMs to understand tool capabilities.
96
+ */
97
+ description: string;
98
+ /**
99
+ * Handler function that processes the tool invocation.
100
+ * Receives validated input and HandlerContext, returns Result.
101
+ */
102
+ handler: Handler<TInput, TOutput, TError>;
103
+ /**
104
+ * Zod schema for validating and parsing input.
105
+ * The schema defines the expected input structure.
106
+ */
107
+ inputSchema: z.ZodType<TInput>;
108
+ /**
109
+ * Unique tool name (kebab-case recommended).
110
+ * Used by clients to invoke the tool.
111
+ */
112
+ name: string;
113
+ }
114
+ /**
115
+ * Serialized tool information for MCP protocol.
116
+ * This is the format sent to clients during tool listing.
117
+ */
118
+ interface SerializedTool {
119
+ /** Behavioral annotations for the tool */
120
+ annotations?: ToolAnnotations;
121
+ /** MCP tool-search hint: whether tool is deferred */
122
+ defer_loading?: boolean;
123
+ /** Tool description */
124
+ description: string;
125
+ /** JSON Schema representation of the input schema */
126
+ inputSchema: Record<string, unknown>;
127
+ /** Tool name */
128
+ name: string;
129
+ }
130
+ export { ToolAnnotations, TOOL_ANNOTATIONS, ToolDefinition, SerializedTool };
@@ -0,0 +1,55 @@
1
+ // @bun
2
+ // packages/mcp/src/internal/log-config.ts
3
+ import { getEnvironment, getEnvironmentDefaults } from "@outfitter/config";
4
+ import { createPrettyFormatter } from "@outfitter/logging";
5
+ var VALID_MCP_LOG_LEVELS = new Set([
6
+ "debug",
7
+ "info",
8
+ "notice",
9
+ "warning",
10
+ "error",
11
+ "critical",
12
+ "alert",
13
+ "emergency"
14
+ ]);
15
+ var DEFAULTS_TO_MCP = {
16
+ debug: "debug",
17
+ info: "info",
18
+ warn: "warning",
19
+ error: "error"
20
+ };
21
+ function createDefaultMcpSink() {
22
+ const formatter = createPrettyFormatter({ colors: false });
23
+ return {
24
+ formatter,
25
+ write(record, formatted) {
26
+ const serialized = formatted ?? formatter.format(record);
27
+ const line = serialized.endsWith(`
28
+ `) ? serialized : `${serialized}
29
+ `;
30
+ if (typeof process !== "undefined" && process.stderr?.write) {
31
+ process.stderr.write(line);
32
+ }
33
+ }
34
+ };
35
+ }
36
+ function resolveDefaultLogLevel(options) {
37
+ const envLogLevel = process.env["OUTFITTER_LOG_LEVEL"];
38
+ if (envLogLevel !== undefined && VALID_MCP_LOG_LEVELS.has(envLogLevel)) {
39
+ return envLogLevel;
40
+ }
41
+ if (options.defaultLogLevel !== undefined && (options.defaultLogLevel === null || VALID_MCP_LOG_LEVELS.has(options.defaultLogLevel))) {
42
+ return options.defaultLogLevel;
43
+ }
44
+ const env = getEnvironment();
45
+ const defaults = getEnvironmentDefaults(env);
46
+ if (defaults.logLevel !== null) {
47
+ const mapped = DEFAULTS_TO_MCP[defaults.logLevel];
48
+ if (mapped !== undefined) {
49
+ return mapped;
50
+ }
51
+ }
52
+ return null;
53
+ }
54
+
55
+ export { VALID_MCP_LOG_LEVELS, DEFAULTS_TO_MCP, createDefaultMcpSink, resolveDefaultLogLevel };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Shared content type definitions used across prompt and resource types.
3
+ *
4
+ * @internal
5
+ */
6
+ /**
7
+ * Annotations for content items (resource content, prompt messages).
8
+ *
9
+ * Provides hints about content audience and priority.
10
+ *
11
+ * @see https://spec.modelcontextprotocol.io/specification/2025-03-26/server/utilities/annotations/
12
+ */
13
+ interface ContentAnnotations {
14
+ /**
15
+ * Who the content is intended for.
16
+ * Can include "user", "assistant", or both.
17
+ */
18
+ audience?: Array<"user" | "assistant">;
19
+ /**
20
+ * Priority level from 0.0 (least) to 1.0 (most important).
21
+ */
22
+ priority?: number;
23
+ }
24
+ export { ContentAnnotations };
@@ -0,0 +1,53 @@
1
+ // @bun
2
+ // packages/mcp/src/progress.ts
3
+ function mapStreamEventToNotification(token, event, latestProgress) {
4
+ switch (event.type) {
5
+ case "start": {
6
+ return {
7
+ method: "notifications/progress",
8
+ params: {
9
+ progressToken: token,
10
+ progress: latestProgress,
11
+ message: `[start] ${event.command}`
12
+ }
13
+ };
14
+ }
15
+ case "step": {
16
+ const durationSuffix = event.duration_ms !== undefined ? ` (${event.duration_ms}ms)` : "";
17
+ return {
18
+ method: "notifications/progress",
19
+ params: {
20
+ progressToken: token,
21
+ progress: latestProgress,
22
+ message: `[step] ${event.name}: ${event.status}${durationSuffix}`
23
+ }
24
+ };
25
+ }
26
+ case "progress": {
27
+ const params = {
28
+ progressToken: token,
29
+ progress: event.current,
30
+ total: event.total
31
+ };
32
+ if (event.message !== undefined) {
33
+ params.message = event.message;
34
+ }
35
+ return {
36
+ method: "notifications/progress",
37
+ params
38
+ };
39
+ }
40
+ }
41
+ }
42
+ function createMcpProgressCallback(progressToken, send) {
43
+ let latestProgress = 0;
44
+ return (event) => {
45
+ if (event.type === "progress") {
46
+ latestProgress = event.current;
47
+ }
48
+ const notification = mapStreamEventToNotification(progressToken, event, latestProgress);
49
+ send(notification);
50
+ };
51
+ }
52
+
53
+ export { createMcpProgressCallback };
@@ -0,0 +1,45 @@
1
+ import { ProgressCallback } from "@outfitter/contracts/stream";
2
+ /**
3
+ * Function signature for sending a raw MCP notification.
4
+ *
5
+ * Matches the `sdkServer.notification()` method shape from the MCP SDK.
6
+ */
7
+ type McpNotificationSender = (notification: unknown) => void;
8
+ /**
9
+ * MCP progress notification payload matching the MCP specification.
10
+ *
11
+ * @see https://spec.modelcontextprotocol.io/specification/2025-03-26/server/utilities/progress/
12
+ */
13
+ interface McpProgressNotification {
14
+ method: "notifications/progress";
15
+ params: {
16
+ progressToken: string | number;
17
+ progress: number;
18
+ total?: number;
19
+ message?: string;
20
+ };
21
+ }
22
+ /**
23
+ * Create a {@link ProgressCallback} that emits MCP `notifications/progress`.
24
+ *
25
+ * Each call to the returned callback translates a {@link StreamEvent} into
26
+ * an MCP progress notification and sends it via the provided sender function.
27
+ *
28
+ * @param progressToken - The progress token from the MCP client request
29
+ * @param send - Function to send the raw MCP notification (typically `sdkServer.notification`)
30
+ * @returns A `ProgressCallback` compatible with `ctx.progress`
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const progress = createMcpProgressCallback(
35
+ * "tok-123",
36
+ * (n) => sdkServer.notification(n)
37
+ * );
38
+ *
39
+ * // In handler:
40
+ * ctx.progress?.({ type: "start", command: "deploy", ts: new Date().toISOString() });
41
+ * ctx.progress?.({ type: "progress", current: 5, total: 10 });
42
+ * ```
43
+ */
44
+ declare function createMcpProgressCallback(progressToken: string | number, send: McpNotificationSender): ProgressCallback;
45
+ export { McpNotificationSender, McpProgressNotification, createMcpProgressCallback };
@@ -0,0 +1,2 @@
1
+ export { adaptHandler, McpError, TaggedError } from "../../internal/server-types.js";
2
+ export { TOOL_ANNOTATIONS } from "../../internal/tool-types.js";
@@ -1,4 +1,4 @@
1
- import { McpServer } from "./mcp-gqjg15f5.js";
1
+ import { McpServer } from "./mcp-7btcghjj.js";
2
2
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
@@ -1,70 +1,33 @@
1
1
  // @bun
2
+ import {
3
+ VALID_MCP_LOG_LEVELS,
4
+ createDefaultMcpSink,
5
+ resolveDefaultLogLevel
6
+ } from "./mcp-n9vzcp37.js";
7
+ import {
8
+ matchUriTemplate
9
+ } from "./mcp-zt2s3r38.js";
10
+ import {
11
+ createMcpProgressCallback
12
+ } from "./mcp-q70dtfj6.js";
2
13
  import {
3
14
  shouldEmitLog
4
15
  } from "./mcp-fjtxsa0x.js";
5
16
  import {
6
17
  McpError
7
- } from "./mcp-9m5hs2z0.js";
18
+ } from "./mcp-s2vnhzav.js";
8
19
  import {
9
20
  zodToJsonSchema
10
21
  } from "./mcp-hw5wz4gb.js";
11
22
 
12
23
  // packages/mcp/src/server.ts
13
- import { getEnvironment, getEnvironmentDefaults } from "@outfitter/config";
14
- import { generateRequestId, Result } from "@outfitter/contracts";
15
24
  import {
16
- createOutfitterLoggerFactory,
17
- createPrettyFormatter
18
- } from "@outfitter/logging";
19
- var VALID_MCP_LOG_LEVELS = new Set([
20
- "debug",
21
- "info",
22
- "notice",
23
- "warning",
24
- "error",
25
- "critical",
26
- "alert",
27
- "emergency"
28
- ]);
29
- var DEFAULTS_TO_MCP = {
30
- debug: "debug",
31
- info: "info",
32
- warn: "warning",
33
- error: "error"
34
- };
35
- function createDefaultMcpSink() {
36
- const formatter = createPrettyFormatter({ colors: false });
37
- return {
38
- formatter,
39
- write(record, formatted) {
40
- const serialized = formatted ?? formatter.format(record);
41
- const line = serialized.endsWith(`
42
- `) ? serialized : `${serialized}
43
- `;
44
- if (typeof process !== "undefined" && process.stderr?.write) {
45
- process.stderr.write(line);
46
- }
47
- }
48
- };
49
- }
50
- function resolveDefaultLogLevel(options) {
51
- const envLogLevel = process.env["OUTFITTER_LOG_LEVEL"];
52
- if (envLogLevel !== undefined && VALID_MCP_LOG_LEVELS.has(envLogLevel)) {
53
- return envLogLevel;
54
- }
55
- if (options.defaultLogLevel !== undefined && (options.defaultLogLevel === null || VALID_MCP_LOG_LEVELS.has(options.defaultLogLevel))) {
56
- return options.defaultLogLevel;
57
- }
58
- const env = getEnvironment();
59
- const defaults = getEnvironmentDefaults(env);
60
- if (defaults.logLevel !== null) {
61
- const mapped = DEFAULTS_TO_MCP[defaults.logLevel];
62
- if (mapped !== undefined) {
63
- return mapped;
64
- }
65
- }
66
- return null;
67
- }
25
+ formatZodIssues,
26
+ generateRequestId,
27
+ Result,
28
+ ValidationError
29
+ } from "@outfitter/contracts";
30
+ import { createOutfitterLoggerFactory } from "@outfitter/logging";
68
31
  function createMcpServer(options) {
69
32
  const { name, version, logger: providedLogger } = options;
70
33
  let loggerFactory = null;
@@ -84,10 +47,10 @@ function createMcpServer(options) {
84
47
  let sdkServer = null;
85
48
  const subscriptions = new Set;
86
49
  let clientLogLevel = resolveDefaultLogLevel(options);
87
- function createHandlerContext(toolName, requestId, signal, progressToken) {
50
+ function createHandlerContext(label, requestId, signal, progressToken, loggerMeta) {
88
51
  const ctx = {
89
52
  requestId,
90
- logger: logger.child({ tool: toolName, requestId }),
53
+ logger: logger.child(loggerMeta ?? { tool: label, requestId }),
91
54
  cwd: process.cwd(),
92
55
  env: process.env
93
56
  };
@@ -95,19 +58,27 @@ function createMcpServer(options) {
95
58
  ctx.signal = signal;
96
59
  }
97
60
  if (progressToken !== undefined && sdkServer) {
98
- ctx.progress = {
99
- report(progress, total, message) {
100
- sdkServer?.notification?.({
101
- method: "notifications/progress",
102
- params: {
103
- progressToken,
104
- progress,
105
- ...total !== undefined ? { total } : {},
106
- ...message ? { message } : {}
107
- }
61
+ const sender = (notification) => {
62
+ const maybePromise = sdkServer?.notification?.(notification);
63
+ if (typeof maybePromise === "object" && maybePromise !== null && "then" in maybePromise) {
64
+ maybePromise.catch((error) => {
65
+ logger.warn("Failed to send MCP progress notification", {
66
+ error: error instanceof Error ? error.message : String(error)
67
+ });
108
68
  });
109
69
  }
110
70
  };
71
+ const streamProgress = createMcpProgressCallback(progressToken, sender);
72
+ const progress = streamProgress;
73
+ progress.report = (value, total, message) => {
74
+ streamProgress({
75
+ type: "progress",
76
+ current: value,
77
+ total: total ?? value,
78
+ ...message !== undefined ? { message } : {}
79
+ });
80
+ };
81
+ ctx.progress = progress;
111
82
  }
112
83
  return ctx;
113
84
  }
@@ -125,13 +96,17 @@ function createMcpServer(options) {
125
96
  cancelled: -32603
126
97
  };
127
98
  const code = codeMap[error.category] ?? -32603;
99
+ const context = {
100
+ originalTag: error._tag,
101
+ category: error.category
102
+ };
103
+ if (error._tag === "ValidationError" && "field" in error && typeof error.field === "string") {
104
+ context["field"] = error.field;
105
+ }
128
106
  return new McpError({
129
107
  message: error.message,
130
108
  code,
131
- context: {
132
- originalTag: error._tag,
133
- category: error.category
134
- }
109
+ context
135
110
  });
136
111
  }
137
112
  const server = {
@@ -322,12 +297,10 @@ function createMcpServer(options) {
322
297
  }));
323
298
  }
324
299
  const requestId = generateRequestId();
325
- const ctx = {
326
- requestId,
327
- logger: logger.child({ resource: uri, requestId }),
328
- cwd: process.cwd(),
329
- env: process.env
330
- };
300
+ const ctx = createHandlerContext(uri, requestId, undefined, undefined, {
301
+ resource: uri,
302
+ requestId
303
+ });
331
304
  try {
332
305
  const result = await resource.handler(uri, ctx);
333
306
  if (result.isErr()) {
@@ -346,18 +319,15 @@ function createMcpServer(options) {
346
319
  const variables = matchUriTemplate(template.uriTemplate, uri);
347
320
  if (variables) {
348
321
  const templateRequestId = generateRequestId();
349
- const templateCtx = {
350
- requestId: templateRequestId,
351
- logger: logger.child({
352
- resource: uri,
353
- requestId: templateRequestId
354
- }),
355
- cwd: process.cwd(),
356
- env: process.env
357
- };
322
+ const templateCtx = createHandlerContext(uri, templateRequestId, undefined, undefined, { resource: uri, requestId: templateRequestId });
358
323
  try {
359
324
  const result = await template.handler(uri, variables, templateCtx);
360
325
  if (result.isErr()) {
326
+ logger.warn("Resource template handler returned error", {
327
+ uri,
328
+ requestId: templateRequestId,
329
+ error: result.error._tag
330
+ });
361
331
  return Result.err(translateError(result.error));
362
332
  }
363
333
  return Result.ok(result.value);
@@ -390,7 +360,7 @@ function createMcpServer(options) {
390
360
  }
391
361
  const parseResult = tool.zodSchema.safeParse(input);
392
362
  if (!parseResult.success) {
393
- const errorMessages = parseResult.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
363
+ const errorMessages = formatZodIssues(parseResult.error.issues);
394
364
  logger.warn("Input validation failed", {
395
365
  tool: toolName,
396
366
  requestId,
@@ -460,6 +430,10 @@ function createMcpServer(options) {
460
430
  sdkServer?.sendPromptListChanged?.();
461
431
  },
462
432
  setLogLevel(level) {
433
+ if (!VALID_MCP_LOG_LEVELS.has(level)) {
434
+ logger.warn("Ignoring invalid client log level", { level });
435
+ return;
436
+ }
463
437
  clientLogLevel = level;
464
438
  logger.debug("Client log level set", { level });
465
439
  },
@@ -496,39 +470,25 @@ function createMcpServer(options) {
496
470
  function defineTool(definition) {
497
471
  return definition;
498
472
  }
499
- function escapeRegex(str) {
500
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
501
- }
502
- function matchUriTemplate(template, uri) {
503
- const paramNames = [];
504
- const parts = template.split(/(\{[^}]+\})/);
505
- const regexSource = parts.map((part) => {
506
- const paramMatch = part.match(/^\{([^}]+)\}$/);
507
- if (paramMatch?.[1]) {
508
- paramNames.push(paramMatch[1]);
509
- return "([^/]+)";
510
- }
511
- return escapeRegex(part);
512
- }).join("");
513
- const regex = new RegExp(`^${regexSource}$`);
514
- const match = uri.match(regex);
515
- if (!match) {
516
- return null;
517
- }
518
- const variables = {};
519
- for (let i = 0;i < paramNames.length; i++) {
520
- const name = paramNames[i];
521
- const value = match[i + 1];
522
- if (name !== undefined && value !== undefined) {
523
- variables[name] = value;
524
- }
525
- }
526
- return variables;
527
- }
528
473
  function defineResource(definition) {
529
474
  return definition;
530
475
  }
531
476
  function defineResourceTemplate(definition) {
477
+ if ("paramSchema" in definition && definition.paramSchema !== undefined) {
478
+ const { paramSchema, handler: typedHandler, ...rest } = definition;
479
+ const wrappedHandler = async (uri, variables, ctx) => {
480
+ const parseResult = paramSchema.safeParse(variables);
481
+ if (!parseResult.success) {
482
+ const errorMessages = formatZodIssues(parseResult.error.issues);
483
+ return Result.err(new ValidationError({
484
+ message: `Invalid resource parameters: ${errorMessages}`,
485
+ field: "params"
486
+ }));
487
+ }
488
+ return typedHandler(uri, parseResult.data, ctx);
489
+ };
490
+ return { ...rest, handler: wrappedHandler };
491
+ }
532
492
  return definition;
533
493
  }
534
494
  function definePrompt(definition) {
@@ -0,0 +1,33 @@
1
+ // @bun
2
+ // packages/mcp/src/internal/uri-template.ts
3
+ function escapeRegex(str) {
4
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5
+ }
6
+ function matchUriTemplate(template, uri) {
7
+ const paramNames = [];
8
+ const parts = template.split(/(\{[^}]+\})/);
9
+ const regexSource = parts.map((part) => {
10
+ const paramMatch = part.match(/^\{([^}]+)\}$/);
11
+ if (paramMatch?.[1]) {
12
+ paramNames.push(paramMatch[1]);
13
+ return "([^/]+)";
14
+ }
15
+ return escapeRegex(part);
16
+ }).join("");
17
+ const regex = new RegExp(`^${regexSource}$`);
18
+ const match = uri.match(regex);
19
+ if (!match) {
20
+ return null;
21
+ }
22
+ const variables = {};
23
+ for (let i = 0;i < paramNames.length; i++) {
24
+ const name = paramNames[i];
25
+ const value = match[i + 1];
26
+ if (name !== undefined && value !== undefined) {
27
+ variables[name] = value;
28
+ }
29
+ }
30
+ return variables;
31
+ }
32
+
33
+ export { matchUriTemplate };
@@ -1,4 +1,9 @@
1
- import { McpToolResponse, connectStdio, createSdkServer, wrapToolError, wrapToolResult } from "./shared/@outfitter/mcp-7kcw2814.js";
2
- import "./shared/@outfitter/mcp-gqjg15f5.js";
1
+ import { McpToolResponse, connectStdio, createSdkServer, wrapToolError, wrapToolResult } from "./shared/@outfitter/mcp-yf0w5cgh.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 { wrapToolResult, wrapToolError, createSdkServer, connectStdio, McpToolResponse };
package/dist/types.d.ts CHANGED
@@ -1,3 +1,8 @@
1
- import { BlobResourceContent, CompletionHandler, CompletionRef, CompletionResult, ContentAnnotations, InvokeToolOptions, McpError, McpHandlerContext, McpServer, McpServerOptions, ProgressReporter, PromptArgument, PromptDefinition, PromptHandler, PromptMessage, PromptMessageContent, PromptResult, ResourceContent, ResourceDefinition, ResourceReadHandler, ResourceTemplateDefinition, ResourceTemplateReadHandler, Result, SerializedTool, TOOL_ANNOTATIONS, TaggedError, TextResourceContent, ToolAnnotations, ToolDefinition, adaptHandler } from "./shared/@outfitter/mcp-gqjg15f5.js";
1
+ import "./shared/@outfitter/mcp-qmdmgxa1.js";
2
+ import { InvokeToolOptions, McpError, McpHandlerContext, McpServer, McpServerOptions, ProgressReporter, Result, TaggedError, adaptHandler } from "./shared/@outfitter/mcp-7btcghjj.js";
3
+ import { SerializedTool, TOOL_ANNOTATIONS, ToolAnnotations, ToolDefinition } from "./shared/@outfitter/mcp-knc1gq0g.js";
4
+ import { BlobResourceContent, ResourceContent, ResourceDefinition, ResourceReadHandler, ResourceTemplateDefinition, ResourceTemplateReadHandler, TextResourceContent, TypedResourceTemplateDefinition, TypedResourceTemplateReadHandler } from "./shared/@outfitter/mcp-9ry52yg3.js";
5
+ import { CompletionHandler, CompletionRef, CompletionResult, PromptArgument, PromptDefinition, PromptHandler, PromptMessage, PromptMessageContent, PromptResult } from "./shared/@outfitter/mcp-dgwj3jna.js";
6
+ import { ContentAnnotations } from "./shared/@outfitter/mcp-q5hr7227.js";
2
7
  import "./shared/@outfitter/mcp-cqpyer9m.js";
3
- export { adaptHandler, ToolDefinition, ToolAnnotations, TextResourceContent, TaggedError, TOOL_ANNOTATIONS, SerializedTool, Result, ResourceTemplateReadHandler, ResourceTemplateDefinition, ResourceReadHandler, ResourceDefinition, ResourceContent, PromptResult, PromptMessageContent, PromptMessage, PromptHandler, PromptDefinition, PromptArgument, ProgressReporter, McpServerOptions, McpServer, McpHandlerContext, McpError, InvokeToolOptions, ContentAnnotations, CompletionResult, CompletionRef, CompletionHandler, BlobResourceContent };
8
+ export { adaptHandler, TypedResourceTemplateReadHandler, TypedResourceTemplateDefinition, ToolDefinition, ToolAnnotations, TextResourceContent, TaggedError, TOOL_ANNOTATIONS, SerializedTool, Result, ResourceTemplateReadHandler, ResourceTemplateDefinition, ResourceReadHandler, ResourceDefinition, ResourceContent, PromptResult, PromptMessageContent, PromptMessage, PromptHandler, PromptDefinition, PromptArgument, ProgressReporter, McpServerOptions, McpServer, McpHandlerContext, McpError, InvokeToolOptions, ContentAnnotations, CompletionResult, CompletionRef, CompletionHandler, BlobResourceContent };
package/dist/types.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  TOOL_ANNOTATIONS,
5
5
  TaggedError,
6
6
  adaptHandler
7
- } from "./shared/@outfitter/mcp-9m5hs2z0.js";
7
+ } from "./shared/@outfitter/mcp-s2vnhzav.js";
8
8
  export {
9
9
  adaptHandler,
10
10
  TaggedError,