64-bit values sent as bare JSON numbers crash BigInt-aware MCP clients

Author: DzenIsRichCreated Aug 13, 2026Updated Aug 13, 2026

Summary

tools/call emits 64-bit integers as bare JSON numbers in structuredContent. Any value outside the JS safe-integer range (|v| > 2**53 - 1) becomes a BigInt in MCP clients that parse with a BigInt-preserving reviver, and the client then dies with TypeError: Do not know how to serialize a BigInt when it re-serializes the tool result.

In my case this killed the agent process mid-session, not just the one tool call.

Reproduction

Any binary works — reading 8 bytes of an ASCII string as u64 always exceeds 2**53 - 1, so tests/crackme03.elf from this repo is enough. No arm64 target needed.

1. Start the server:

bash
uv run idalib-mcp --host 127.0.0.1 --port 8745 tests/crackme03.elf

This serves streamable HTTP at http://127.0.0.1:8745/mcp. Since the supervisor requires database=<session_id> on every tool call, the repro first looks the session up via idb_list.

2. Drive it with a Node-based MCP client:

bash
copilot -p "Use the ida MCP tools: first call idb_list to find the open session_id for crackme03.elf, then call get_int with that database, addr='0x318', ty='u64'. Report the exact returned value." --allow-all --additional-mcp-config '{"mcpServers":{"ida":{"type":"http","url":"http://127.0.0.1:8745/mcp","tools":["*"]}}}'

0x318 is the first ≥8-byte string in crackme03.elf; the server returns:

json
{"result": [{"addr": "0x318", "ty": "u64le", "value": 7795506888185572399}]}

7795506888185572399 > 2**53 - 1, so a BigInt-preserving parser turns it into 7795506888185572399n, and the subsequent JSON.stringify throws TypeError: Do not know how to serialize a BigInt.

Affected tools

Not specific to get_int — anything that can emit a raw 64-bit Python int:

  • get_int with ty: u64 / i64 (easiest trigger, works on every binary)
  • extract_function_constants in utils.py emits "decimal": op.value untyped; arm64 o_imm operands routinely exceed the safe range. This was my original failure, via analyze_batch with include_constants: true.
  • enum member values in api_types.py

Expected

structuredContent should never contain a JSON number outside ±(2**53 - 1).

Prior art

bytebase/dbhub (Universal Database MCP Server) hit the same class of problem and solved it with a single choke point at the response-construction boundary:

Their policy is value-driven (only values that actually don't fit get stringified), which is what I'm proposing here.

Suggested fix

A single choke point in the tools/call middleware in rpc.py: recursively stringify ints outside the safe range (leaving bool, small ints, and existing hex strings alone), and rebuild the content text so it stays consistent with structuredContent.

Two output types then need widening to keep the sanitized value valid against the advertised outputSchema:

  • api_memory.IntReadResult.value: int | Noneint | str | None
  • api_types.EnumMemberUpsertResult.value: intint | str

Untyped list[dict] returns (e.g. the constants extractor) need no schema change.

Environment

  • ida-pro-mcp main @ 0b5f7ae
  • IDA Pro 9.x via idalib, macOS
  • Originally hit with GitHub Copilot CLI (Node client)