-
Notifications
You must be signed in to change notification settings - Fork 84
Description
Problem
When Mux invokes MCP tools (e.g. gitlab_mcp_list_issues), the LLM may supply empty strings or placeholder values for optional parameters:
{
"project_id": "42332",
"assignee_id": "",
"author_id": "",
"author_username": "",
"iteration_id": "",
"search": ""
}Mux forwards these arguments verbatim to MCP servers via wrapMCPTools in src/node/services/mcpServerManager.ts. Downstream APIs that require optional parameters to be omitted (not empty) reject the request. For example, GitLab returns:
400 Bad Request
author_id, author_username are mutually exclusive
assignee_id should be an integer, none, or any, however got ""
iteration_id should be an integer, none, any, or current, however got ""
From a user perspective, this surfaces as a failed tool call with no obvious workaround.
Root Cause
- LLMs commonly emit empty strings (
"") for optional fields they don't have values for, rather than omitting them. wrapMCPToolswraps tool execution for timeout/abort handling and activity tracking, but passesargsthrough without any sanitization.- Many REST-backed MCP servers (GitLab, and likely others) treat empty strings as present-but-invalid, causing 400 errors.
Proposed Fix
Introduce light argument normalization in wrapMCPTools before invoking the original execute function. Specifically:
- Strip keys with empty string values (
"") from the arguments object before forwarding. Empty strings for optional parameters are almost always LLM artifacts, not intentional values. - Do NOT strip
nullvalues — some MCP servers may use explicitnullto mean "clear/unset this field." - Do NOT strip empty arrays (
[]) — these are generally treated as "no filter" by APIs and are benign.
Example normalization (conceptual)
function sanitizeArgs(args: Record<string, unknown>): Record<string, unknown> {
const sanitized: Record<string, unknown> = {};
for (const [key, value] of Object.entries(args)) {
if (value === "") continue; // Skip empty strings
sanitized[key] = value;
}
return sanitized;
}This could be applied inside wrapMCPTools before calling originalExecute(args, context).
Considerations
- Different MCP servers may interpret empty vs. missing differently. The normalization should be conservative (empty strings only).
- Opt-out escape hatch (future): If any MCP server legitimately needs empty strings passed through, a per-server config flag like
sanitizeArgs: falsecould be added later. - Nested objects: For v1, top-level empty string stripping is sufficient. Deep/recursive sanitization can be considered if needed.
Affected Component
src/node/services/mcpServerManager.ts — wrapMCPTools function (line ~131)
Impact
This affects any MCP server backed by a strict REST API that distinguishes between "parameter omitted" and "parameter present but empty." GitLab MCP is one confirmed case, but the issue is generic.