-
Notifications
You must be signed in to change notification settings - Fork 361
Description
Description
In full tool mode (--tool-mode full), every generated MCP tool includes body and upload properties in its inputSchema, regardless of whether the
underlying Google API method actually supports a request body or media upload.
This causes LLM clients to hallucinate values for these fields — most commonly sending "body": {} on GET-only methods (e.g., gmail_users_labels_list),
which causes Google APIs to return HTTP 400 ("Parse Error / malformed or illegal request").
Similarly, LLMs may send "upload": "" on methods that don't support media upload, triggering file-read errors.
Root Cause
In walk_resources() (src/mcp_server.rs), the tool schema is built with a static set of properties that always includes body and upload. However,
the Discovery Document already provides per-method metadata:
method.request— present only when the method accepts a request bodymethod.supports_media_upload— true only when the method supports media upload
This data is already surfaced by gws_discover (via the supportsMediaUpload field) but is not used to conditionally build tool schemas in full mode.
In compact mode, body and upload must remain in the schema since one tool covers all methods in a service. However, the execution layer
(execute_mcp_method) does not filter out empty/no-op values before forwarding them to the HTTP executor.
Impact
- Full mode: LLMs see
bodyanduploadon every tool and frequently populate them with empty values, causing API errors - Compact mode: Same issue at the execution layer — empty
"body": {}is serialized and sent as a JSON request body on GET requests - Related: Gmail users.messages.trash returns 411 (Length Required) — missing Content-Length header on POST #182 / PR fix(executor): add Content-Length: 0 for body-less POST requests #183 addressed body-less POST requests (411 error). This covers the inverse — body-ful GET requests (400 error). Issue POST requests with --json body return 403 despite valid scopes #188 (POST
with body returning 403) may also be related.
Steps to Reproduce
- Start MCP server:
gws mcp -s gmail --tool-mode full - Send a
tools/callforgmail_users_labels_listwith"body": {} - Google API returns 400
{
"method": "tools/call",
"params": {
"name": "gmail_users_labels_list",
"arguments": {
"params": { "userId": "me" },
"body": {}
}
}
}Proposed Fix
- Full mode schemas: Conditionally include body only when method.request.is_some() and upload only when method.supports_media_upload is true
- Execution layer (both modes): Filter out empty body objects ({}) and empty upload strings ("") in execute_mcp_method before forwarding to the HTTP
executor
Branch with fix: https://github.com/shreyaskarnik/cli/tree/fix/mcp-tool-schema-body-upload