modelcontextprotocol/servers · error · ValueError

Error processing mcp-server-time query: {str(e)}

Error message

Error processing mcp-server-time query: {str(e)}

What it means

The time server's call_tool wraps its entire body in try/except Exception (server.py:187, 215-216) and re-raises every failure as ValueError('Error processing mcp-server-time query: {e}'). This is the error the MCP client actually sees for ANY internal failure, including errors 44-48. It is a code smell: it downgrades the structured McpError(INVALID_PARAMS) from get_zoneinfo (error 44) into a plain ValueError, destroying the error code and nesting the message twice. The git server, by contrast, uses raise_exceptions=True with no catch-all.

Source

Thrown at src/time/src/mcp_server_time/server.py:216

                        k in arguments
                        for k in ["source_timezone", "time", "target_timezone"]
                    ):
                        raise ValueError("Missing required arguments")

                    result = time_server.convert_time(
                        arguments["source_timezone"],
                        arguments["time"],
                        arguments["target_timezone"],
                    )
                case _:
                    raise ValueError(f"Unknown tool: {name}")

            return [
                TextContent(type="text", text=json.dumps(result.model_dump(), indent=2))
            ]

        except Exception as e:
            raise ValueError(f"Error processing mcp-server-time query: {str(e)}")

    options = server.create_initialization_options()
    async with stdio_server() as (read_stream, write_stream):
        await server.run(read_stream, write_stream, options)

View on GitHub (pinned to 76d64c822f)

Solutions

  1. Read the full message: the original error text is appended after 'query: ' and identifies the real cause (44/45/46/47/48).
  2. Pre-validate tz/time/args client-side (see 44-48) so this path is never reached.
  3. If you maintain the server: re-raise McpError unchanged and only wrap truly unexpected exceptions, mirroring the git server's no-catch-all approach.
  4. Until fixed, do not rely on the error code; parse the message tail or inspect server logs.

Example fix

# before
except Exception as e:
    raise ValueError(f"Error processing mcp-server-time query: {str(e)}")

# after
from mcp.shared.exceptions import McpError
except McpError:
    raise  # preserve INVALID_PARAMS code and message
except Exception as e:
    raise ValueError(f"Error processing mcp-server-time query: {str(e)}")
Defensive patterns

Strategy: try-catch

Validate before calling

# This error IS the catch; there is no pre-call code for it.
# Prevention = pre-validate inputs for errors 44-48 so this path is never hit.
# See validationCode for errorIndex 44, 45, 46, 47, 48.

Try / catch

try:
    result = await session.call_tool(name, arguments)
except Exception as e:
    msg = str(e)
    # The real cause is appended after 'query: ' — log it; do not branch on a code.
    if msg.startswith("Error processing mcp-server-time query:"):
        cause = msg.split("query:", 1)[-1].strip()
        log.error("time server failure, underlying cause: %s", cause)
    raise

Prevention

When it happens

Trigger: Any exception inside get_current_time or convert_time dispatch: invalid timezone (44), bad time format (45), missing args (46/47), unknown tool (48), or any unexpected runtime error.

Common situations: Operators see only the generic wrapper and must read server logs to find the cause. Clients that branch on INVALID_PARAMS never see it because the McpError was converted to ValueError. Every distinct internal failure looks the same to the caller.

Related errors


AI-assisted analysis of modelcontextprotocol/servers@76d64c822f (2026-08-12). Data as JSON: /api/errors/ea306774297e4bd5. Report an issue: GitHub.