Skip to content

Commit ba4cc37

Browse files
soamatipunkpeye
andauthored
feat: allow custom friendlyErrors message on parameters validation error (#151)
* feat: allow custom friendlyErrors message on parameters validation error Add general usage utils param to server constructor * fix: add formatInvalidParamsErrorMessage callback test --------- Co-authored-by: Frank Fiegel <[email protected]>
1 parent e8e23a0 commit ba4cc37

File tree

2 files changed

+81
-6
lines changed

2 files changed

+81
-6
lines changed

src/FastMCP.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2914,3 +2914,60 @@ test("HTTP Stream: calls a tool", { timeout: 20000 }, async () => {
29142914
await server.stop();
29152915
}
29162916
});
2917+
2918+
test("uses `formatInvalidParamsErrorMessage` callback to build ErrorCode.InvalidParams error message", async () => {
2919+
await runWithTestServer({
2920+
run: async ({ client }) => {
2921+
try {
2922+
await client.callTool({
2923+
arguments: {
2924+
a: 1,
2925+
b: "invalid",
2926+
},
2927+
name: "add",
2928+
});
2929+
} catch (error) {
2930+
expect(error).toBeInstanceOf(McpError);
2931+
2932+
// @ts-expect-error - we know that error is an McpError
2933+
expect(error.code).toBe(ErrorCode.InvalidParams);
2934+
2935+
// @ts-expect-error - we know that error is an McpError
2936+
expect(error.message).toBe(
2937+
`MCP error -32602: MCP error -32602: Tool 'add' parameter validation failed: My custom error message: Field b failed with error 'Expected number, received string'. Please check the parameter types and values according to the tool's schema.`,
2938+
);
2939+
}
2940+
},
2941+
server: async () => {
2942+
const server = new FastMCP({
2943+
name: "Test",
2944+
utils: {
2945+
formatInvalidParamsErrorMessage: (issues) => {
2946+
const message = issues
2947+
.map((issue) => {
2948+
const path = issue.path?.join(".") || "root";
2949+
return `Field ${path} failed with error '${issue.message}'`;
2950+
})
2951+
.join(", ");
2952+
return `My custom error message: ${message}`;
2953+
},
2954+
},
2955+
version: "1.0.0",
2956+
});
2957+
2958+
server.addTool({
2959+
description: "Add two numbers",
2960+
execute: async (args) => {
2961+
return String(args.a + args.b);
2962+
},
2963+
name: "add",
2964+
parameters: z.object({
2965+
a: z.number(),
2966+
b: z.number(),
2967+
}),
2968+
});
2969+
2970+
return server;
2971+
},
2972+
});
2973+
});

src/FastMCP.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,14 @@ type ServerOptions<T extends FastMCPSessionAuth> = {
670670
*/
671671
enabled?: boolean;
672672
};
673+
/**
674+
* General utilities
675+
*/
676+
utils?: {
677+
formatInvalidParamsErrorMessage?: (
678+
issues: readonly StandardSchemaV1.Issue[],
679+
) => string;
680+
};
673681
version: `${number}.${number}.${number}`;
674682
};
675683

@@ -790,6 +798,8 @@ export class FastMCPSession<
790798

791799
#server: Server;
792800

801+
#utils?: ServerOptions<T>["utils"];
802+
793803
constructor({
794804
auth,
795805
instructions,
@@ -801,6 +811,7 @@ export class FastMCPSession<
801811
roots,
802812
tools,
803813
transportType,
814+
utils,
804815
version,
805816
}: {
806817
auth?: T;
@@ -813,6 +824,7 @@ export class FastMCPSession<
813824
roots?: ServerOptions<T>["roots"];
814825
tools: Tool<T>[];
815826
transportType?: "httpStream" | "stdio";
827+
utils?: ServerOptions<T>["utils"];
816828
version: string;
817829
}) {
818830
super();
@@ -845,6 +857,8 @@ export class FastMCPSession<
845857
{ capabilities: this.#capabilities, instructions: instructions },
846858
);
847859

860+
this.#utils = utils;
861+
848862
this.setupErrorHandling();
849863
this.setupLoggingHandlers();
850864
this.setupRootsHandlers();
@@ -1487,12 +1501,14 @@ export class FastMCPSession<
14871501
);
14881502

14891503
if (parsed.issues) {
1490-
const friendlyErrors = parsed.issues
1491-
.map((issue) => {
1492-
const path = issue.path?.join(".") || "root";
1493-
return `${path}: ${issue.message}`;
1494-
})
1495-
.join(", ");
1504+
const friendlyErrors = this.#utils?.formatInvalidParamsErrorMessage
1505+
? this.#utils.formatInvalidParamsErrorMessage(parsed.issues)
1506+
: parsed.issues
1507+
.map((issue) => {
1508+
const path = issue.path?.join(".") || "root";
1509+
return `${path}: ${issue.message}`;
1510+
})
1511+
.join(", ");
14961512

14971513
throw new McpError(
14981514
ErrorCode.InvalidParams,
@@ -1872,6 +1888,7 @@ export class FastMCP<
18721888
roots: this.#options.roots,
18731889
tools: this.#tools,
18741890
transportType: "stdio",
1891+
utils: this.#options.utils,
18751892
version: this.#options.version,
18761893
});
18771894

@@ -1903,6 +1920,7 @@ export class FastMCP<
19031920
roots: this.#options.roots,
19041921
tools: this.#tools,
19051922
transportType: "httpStream",
1923+
utils: this.#options.utils,
19061924
version: this.#options.version,
19071925
});
19081926
},

0 commit comments

Comments
 (0)