Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-mcp-network-list-validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sei-js/mcp-server': patch
---

Return MCP validation errors for unsupported `compare_networks` entries instead of throwing an internal error.
16 changes: 7 additions & 9 deletions packages/mcp-server/src/core/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,24 @@ import { isWalletEnabled } from './config.js';

const networkListSchema = z
.string()
.superRefine((value, context) => {
.transform((value, context) => {
const networks = value.split(',').map((network) => network.trim());
if (networks.length === 0 || networks.some((network) => network.length === 0)) {
context.addIssue({ code: z.ZodIssueCode.custom, message: 'At least one supported network is required.' });
return;
return z.NEVER;
}

const normalizedNetworks: string[] = [];
for (const network of networks) {
try {
normalizeNetwork(network);
normalizedNetworks.push(normalizeNetwork(network));
} catch {
context.addIssue({ code: z.ZodIssueCode.custom, message: `Unsupported network: ${network}` });
}
}

return normalizedNetworks.length === networks.length ? normalizedNetworks.join(',') : z.NEVER;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] Using normalizedNetworks.length === networks.length as the success signal works today, but it's an indirect proxy for "no issues were added" and would silently break if the catch ever pushed a fallback value. A explicit flag reads more clearly and is robust to that:

let hasUnsupported = false;
for (const network of networks) {
	try {
		normalizedNetworks.push(normalizeNetwork(network));
	} catch {
		hasUnsupported = true;
		context.addIssue({ code: z.ZodIssueCode.custom, message: `Unsupported network: ${network}` });
	}
}

return hasUnsupported ? z.NEVER : normalizedNetworks.join(',');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] The normalizedNetworks.length === networks.length guard is redundant: the only way the lengths can differ is if the catch above already called context.addIssue, and once an issue is recorded from inside a transform Zod discards the returned value and fails the parse regardless. return normalizedNetworks.join(','); behaves identically and reads more directly.

Not worth blocking on — if you prefer keeping it as belt-and-braces against a future edit that pushes to the array on the failure path, that's a reasonable call.

})
.transform((value) =>
value
.split(',')
.map((network) => normalizeNetwork(network.trim()))
.join(',')
)
.describe("Comma-separated supported networks (for example, 'sei,1328' or '0x531,sei-testnet').");

/**
Expand Down
Loading