Skip to content

fix: answer MCP initialize with a protocol version the engine speaks - #5

Merged
VikramLex merged 1 commit into
Graphicle-AI:mainfrom
rudycelekli:fix/graph-mcp-negotiate-protocol-version
Oct 18, 2026
Merged

VikramLex merged 1 commit into
Graphicle-AI:mainfrom
rudycelekli:fix/graph-mcp-negotiate-protocol-version

Conversation

@rudycelekli

Copy link
Copy Markdown
Contributor

The graph engine's MCP server (graphicle-graph serve, stdio and HTTP) answers initialize with whatever protocolVersion the client sent, even one it does not know.

What happens

→ {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"1999-01-01"}}
← {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"1999-01-01", ...}}

The client is told the server speaks a version it has never heard of.

Why it matters

The MCP lifecycle says a server that does not support the requested version must answer with one it does support. The client then decides whether it can continue. Graphify's server negotiates this way through the MCP Python SDK, so on this point the port differs from its reference. The graphicle program's own server already checks the requested version against a list (api.rs, initialize).

Change

initialize answers with the requested version when it is one of 2024-11-05, 2025-03-26, 2025-06-18 or 2025-11-25 (the same list as the program's server). Otherwise it answers 2025-06-18, the version the engine already answered when the client gave none. A client asking for any of those four versions sees no change.

Test

hardening_tests::mcp_initialize_answers_a_protocol_version_it_speaks: each known version is answered as requested. An unknown version, a non-string and a missing one are answered with 2025-06-18.

Verification

In crates/graphicle-graph, with Rust 1.95.0:

  • cargo fmt --package graphicle --package graphicle-graph --check: clean
  • cargo clippy --locked --all-targets --features postgres,bedrock -- -D warnings: clean on Rust 1.95.0 (macOS). The transcription feature was left out locally because whisper-rs-sys needs cmake here; CI builds it.
  • cargo test --locked --all-targets --features postgres,bedrock: 963 passed, 0 failed.

I left CHANGELOG.md to you.

🤖 Generated with Claude Code

The graph engine's MCP server (`graphicle-graph serve`) echoed whatever
`protocolVersion` a client sent in `initialize`, so a client asking for a
version the server does not know (an older or newer revision, a draft,
or a typo) was told it had been agreed. The MCP lifecycle asks a server
to answer with a version it supports when it does not support the one
requested; Graphify's server, on the MCP Python SDK, does, and so does
the graphicle program's own server (`api.rs`).

`initialize` now answers with the requested version when it is one of
the revisions the server speaks (2024-11-05, 2025-03-26, 2025-06-18,
2025-11-25), else with 2025-06-18, the version it already answered when
none was given. A client that asks for a known version sees no change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Rudy Celekli <rudy@gradiahq.com>
@VikramLex
VikramLex merged commit 32c0880 into Graphicle-AI:main Oct 18, 2026
VikramLex added a commit that referenced this pull request Oct 18, 2026
…-off

Dashboard: the app that `graphicle open` shows, and its product and
documentation pages, get a light theme. It follows the operating
system's light or dark setting; Settings > Appearance picks System,
Light or Dark, kept per browser. The theme is set before the first
paint by /theme.js (the Content-Security-Policy allows no inline
script). Every colour of the stylesheets is a token whose dark value is
the old colour, so the dark theme is unchanged; in the light theme, text
is at least 4.5:1 against its background, and control borders and focus
rings at least 3:1.

MCP Registry: from this release on, the mcp-registry workflow adds one
MCP bundle (.mcpb) for each release target to the GitHub release and
lists the release as io.github.Graphicle-AI/graphicle
(packaging/mcpb/, .github/workflows/mcp-registry.yml, glama.json).

Update check: each check is recorded before its request goes out, so a
check still running when a command ends counts as that day's check
instead of running again with the next command. Checks whose requests
fail, or that GitHub refuses or limits, back off a day, then two, then
four. Still one GET with no code or data, and the notice at most once a
day.

Other changes:
- The rcfile tests that use the process-wide state hold a lock, so one
  test can no longer clear the warned folders between another's calls.
- The engine's file ledger marks each application module with a passing
  comparison receipt against Graphify 0.9.91 as verified; STATUS.md,
  AUDIT.json and PROGRESS.json describe the 0.9.91 port.
- cargo-deny ignores RUSTSEC-2026-0367, RUSTSEC-2026-0368 and
  RUSTSEC-2026-0369 (zip 8.6.0): they affect only zip's extract-to-disk
  APIs, and Graphicle reads archive members in memory and never
  extracts them. The ignores go once calamine moves to zip 9.
- Every crate is at 0.1.2, with a CHANGELOG entry. It also credits the
  four contributed fixes merged just before this commit: #3 (a Codex
  config with non-ASCII text in a multi-line string), #4 (a conversation
  opening cut on a character boundary), #5 (initialize answers a protocol
  version the engine speaks) and #6 (Method not found for an unknown MCP
  method), all by @rudycelekli.

Closes #2

Signed-off-by: VikramLex <vikramlex@karlexai.com>
@VikramLex

Copy link
Copy Markdown
Member

Thank you, @rudycelekli. Merged for 0.1.2. Answering a version the server knows, instead of echoing the client's, matches the MCP lifecycle, and the test covers the known, unknown and malformed cases. The CHANGELOG credits you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants