Skip to content

[git] raise_exceptions=True #4213

@KonecSvetta

Description

@KonecSvetta

Describe the bug
mcp-server-git pass raise_exceptions=True; mcp-server-time and mcp-server-sqlite use the default. With set flag, the SDK turns an exception from stdin_reader into a process exit; without it, the same exception is sent back to the client as a JSON-RPC error and the server keeps running.

I'm not filing this as a CVE-class issue - the README is clear these are reference implementations, not production code. But the divergence itself is worth straightening out.

To Reproduce
The way to trigger (and how i found it) this is a JSON-RPC request with params.arguments nested ~200 levels deep -pydantic-core hits its built-in recursion limit and JSONRPCMessage.model_validate_json() raises ValidationError: recursion limit exceeded. stdin_reader catches that exception correctly and sends it down the stream; the receiver re-raises it because raise_exceptions=True was set, the task group tears down, and the process exits with code 1.

  1. Run python repro.py.
  2. Assertions pass — server exited with code 1 and the stderr contains the recursion-limit ValidationError.
import json, subprocess, tempfile, pathlib

repo = pathlib.Path(tempfile.mkdtemp())
subprocess.run(["git", "init", str(repo)], check=True, capture_output=True)

inner = {"leaf": True}
for _ in range(200):
    inner = {"child": inner}

msgs = [
    {"jsonrpc": "2.0", "id": 1, "method": "initialize",
     "params": {"protocolVersion": "2025-03-26", "capabilities": {},
                "clientInfo": {"name": "repro", "version": "0.1"}}},
    {"jsonrpc": "2.0", "method": "notifications/initialized"},
    {"jsonrpc": "2.0", "id": 1001, "method": "tools/call",
     "params": {"name": "git_add", "arguments": inner}},
]
payload = ("\n".join(json.dumps(m) for m in msgs) + "\n").encode()

proc = subprocess.Popen(
    ["uvx", "--from", "mcp-server-git==2026.1.14",
     "mcp-server-git", "-r", str(repo)],
    stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate(payload, timeout=15)

assert proc.returncode == 1, f"expected crash, got rc={proc.returncode}"
assert b"ValidationError" in err and b"recursion limit exceeded" in err
print("Confirmed: mcp-server-git exited with code 1 on nested JSON-RPC")

Expected behavior
Same as mcp-server-time and mcp-server-sqlite: an unparseable JSON-RPC request should yield a JSON-RPC error response, not crash the server.

Logs

Traceback (most recent call last):
  File ".../mcp/server/lowlevel/server.py", line 714, in _handle_message
    raise message
  File ".../mcp/server/stdio.py", line 65, in stdin_reader
    message = types.JSONRPCMessage.model_validate_json(line)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../pydantic/main.py", line 782, in model_validate_json
    return cls.__pydantic_validator__.validate_json(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 1 validation error for JSONRPCMessage
  Invalid JSON: recursion limit exceeded at line 1 column 2089
  [type=json_invalid, input_value='{"jsonrpc": "2.0", "id":...}}}}}}}}}}}}}}}}}}}}}\n', input_type=str]
    For further information visit https://errors.pydantic.dev/2.13/v/json_invalid

ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)

Additional context
I noticed that a very similar issue was previously fixed for mcp-server-fetch in PR #3515. Thanks to @anshul-garg27 for that fix — this looks like the same kind of follow-up cleanup for mcp-server-git.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions