Skip to content

Support MCP lifecycle basics#563

Open
xingxi0614-cpu wants to merge 2 commits into
ramimbo:mainfrom
xingxi0614-cpu:codex/b406-mcp-initialize-handshake
Open

Support MCP lifecycle basics#563
xingxi0614-cpu wants to merge 2 commits into
ramimbo:mainfrom
xingxi0614-cpu:codex/b406-mcp-initialize-handshake

Conversation

@xingxi0614-cpu
Copy link
Copy Markdown

@xingxi0614-cpu xingxi0614-cpu commented May 28, 2026

Summary

Refs #406.

This adds a focused compatibility fix for the public MCP JSON-RPC endpoint: /mcp now responds to the standard initialize request with protocol version, tool capability, and server info before clients call tools/list or tools/call. It also accepts the follow-up notifications/initialized lifecycle notification with an empty 202 response and supports the optional ping health check.

Evidence

Live public preflight on 2026-05-28 showed:

POST https://mcp.mrwk.ltclab.site/mcp
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}

-> HTTP 200
{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"unknown method"}}

POST https://mcp.mrwk.ltclab.site/mcp
{"jsonrpc":"2.0","method":"notifications/initialized"}

-> HTTP 200
{"jsonrpc":"2.0","id":null,"error":{"code":-32601,"message":"unknown method"}}

POST https://mcp.mrwk.ltclab.site/mcp
{"jsonrpc":"2.0","id":9,"method":"ping"}

-> HTTP 200
{"jsonrpc":"2.0","id":9,"error":{"code":-32601,"message":"unknown method"}}

That is awkward for generic MCP clients because the MCP lifecycle starts with an initialize exchange followed by an initialized notification before normal operation, and the protocol also defines a lightweight ping utility. The project already advertises an MCP host and supports tools/list / tools/call; this PR keeps that behavior and adds the missing lifecycle/basic utility responses.

Scope

  • Adds a minimal initialize branch in app/mcp.py.
  • Returns:
    • requested protocolVersion when supplied, otherwise a default;
    • capabilities: {"tools": {}};
    • serverInfo for MergeWork MCP.
  • Accepts notifications/initialized as a no-body 202 lifecycle notification.
  • Returns an empty JSON-RPC result for ping.
  • Adds a regression test in tests/test_api_mcp.py.
  • Does not change existing tool names, tool execution, wallet behavior, ledger behavior, public docs, auth, payment, or deployment configuration.

Validation

  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .\.venv\Scripts\python.exe -m pytest tests\test_api_mcp.py::test_mcp_initialize_advertises_tool_capability tests\test_api_mcp.py::test_mcp_initialized_notification_returns_accepted tests\test_api_mcp.py::test_mcp_ping_returns_empty_result tests\test_api_mcp.py::test_mcp_tools_list_and_call tests\test_api_mcp.py::test_mcp_rejects_malformed_requests_without_500 -q -> 5 passed
  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .\.venv\Scripts\python.exe -m pytest tests\test_api_mcp.py -q -> 79 passed
  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .\.venv\Scripts\python.exe scripts\docs_smoke.py -> docs smoke ok
  • .\.venv\Scripts\python.exe -m ruff check app\mcp.py tests\test_api_mcp.py -> passed
  • .\.venv\Scripts\python.exe -m ruff format --check app\mcp.py tests\test_api_mcp.py -> 2 files already formatted
  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .\.venv\Scripts\python.exe -m mypy app\mcp.py -> success
  • git diff --check -> clean

Safety

No private data, cookies, admin tokens, wallet material, signatures, OAuth state, deployment secrets, price/off-ramp claims, liquidity claims, exchange claims, bridge promises, or fabricated payout claims are included.

Summary by CodeRabbit

  • New Features

    • Added Model Context Protocol (MCP) support: initialize, initialized notification, and ping endpoints
    • Server advertises available tool capabilities during MCP initialization; initialized notifications are accepted (202) and ping returns an empty success result
  • Tests

    • Added comprehensive test coverage validating initialize behavior, protocol-version defaulting/validation, initialized notification handling, and ping response

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 27976eb0-7910-43d6-acaf-6c23e71d4549

📥 Commits

Reviewing files that changed from the base of the PR and between f000fb1 and 593c3de.

📒 Files selected for processing (2)
  • app/mcp.py
  • tests/test_api_mcp.py

📝 Walkthrough

Walkthrough

The MCP handler adds protocol negotiation via initialize, lifecycle acknowledgment via notifications/initialized, and health check via ping, with explicit JSON-RPC and HTTP response handling before existing tools/list and tools/call routing.

Changes

MCP Protocol Methods

Layer / File(s) Summary
Protocol constants and handler signature
app/mcp.py
Defines DEFAULT_PROTOCOL_VERSION and SERVER_INFO; expands handle_mcp_request return type to include fastapi.responses.Response.
MCP method implementations
app/mcp.py
Adds initialize (validates params dict, normalizes/falls back protocolVersion, returns tools capability and server info), notifications/initialized (returns HTTP 202 when no id, otherwise JSON-RPC invalid request), and ping (returns empty JSON-RPC result).
MCP handler endpoint tests
tests/test_api_mcp.py
Adds tests for initialize response structure and protocolVersion normalization, invalid-params handling, notifications/initialized accepted vs invalid-request behavior, and ping returning an empty result.

Possibly related PRs

  • ramimbo/mergework#329: Introduced the centralized handle_mcp_request JSON-RPC transport that this PR extends with initialize/ping/notifications/initialized.
🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Support MCP lifecycle basics' directly names the changed surface and is fully related to the main change: implementing MCP lifecycle handling (initialize, notifications/initialized, ping).
Description check ✅ Passed The description provides all required template sections: Summary (with issue ref), Evidence (live preflight examples), Scope (detailed changes), Validation (test results and lint checks), and Safety attestation. All template checkboxes are documented as passing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Mergework Public Artifact Hygiene ✅ Passed PR adds MCP lifecycle support with no investment/price/cash-out claims. SERVER_INFO contains only technical name and version metadata. No README or docs changes introduce prohibited claims.
Bounty Pr Focus ✅ Passed PR scope matches stated objectives with only 2 files modified, all changes properly tested, and existing tool logic preserved.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e376b027-eb8e-40eb-b0a6-210d31646308

📥 Commits

Reviewing files that changed from the base of the PR and between d8532d4 and f000fb1.

📒 Files selected for processing (2)
  • app/mcp.py
  • tests/test_api_mcp.py

Comment thread app/mcp.py
Comment on lines +121 to +123
protocol_version = (
requested_version if isinstance(requested_version, str) else DEFAULT_PROTOCOL_VERSION
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider validating protocol version.

The code accepts any string as protocolVersion without validation. If the MCP spec defines version-specific behavior, accepting unsupported versions could lead to protocol violations or unexpected client behavior. Consider either validating against supported versions or documenting that the server accepts any version string.

Comment thread app/mcp.py
Comment thread tests/test_api_mcp.py
Copy link
Copy Markdown

@eliasx45 eliasx45 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked this locally against 593c3deab3f6ee488d3155ba987a1b22ee8619dd. The new lifecycle branches mostly behave as described, but I found one protocol-negotiation issue that should be fixed before merge.

Finding: initialize echoes any string-valued params.protocolVersion back to the client. Per the MCP lifecycle spec, if the server supports the requested protocol version it must return that same version; otherwise it must return another protocol version it supports. Link: https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle#version-negotiation

In this PR, app/mcp.py:120-123 treats every string as supported:

requested_version if isinstance(requested_version, str) else DEFAULT_PROTOCOL_VERSION

That means unsupported or malformed strings are advertised as negotiated successfully. Local probe against the PR branch:

2025-06-18 200 2025-06-18
1900-01-01 200 1900-01-01
not-a-version 200 not-a-version

This can break generic MCP clients because subsequent requests are supposed to respect the negotiated protocol version, but the server just agreed to arbitrary versions. Suggested fix: keep an explicit supported-version set/list. Return the requested version only if it is in that set; otherwise return DEFAULT_PROTOCOL_VERSION (or a JSON-RPC unsupported-version error with supported/requested data). Please also add a regression test for an unsupported string protocol version.

Other verification I ran:

  • .\.venv\Scripts\python.exe -m pytest tests\test_api_mcp.py -q -> 84 passed
  • .\.venv\Scripts\python.exe -m ruff check app\mcp.py tests\test_api_mcp.py -> all checks passed
  • .\.venv\Scripts\python.exe -m ruff format --check app\mcp.py tests\test_api_mcp.py -> 2 files already formatted
  • .\.venv\Scripts\python.exe -m mypy app\mcp.py -> success
  • .\.venv\Scripts\python.exe scripts\docs_smoke.py -> docs smoke ok
  • git diff --check origin/main...HEAD -> clean

@ramimbo
Copy link
Copy Markdown
Owner

ramimbo commented May 28, 2026

Maintainer cleanup note: holding this for changes. The review found an MCP initialize protocol-version negotiation issue: arbitrary string protocolVersion values should not be echoed as negotiated/defaulted in a way that breaks clients. Please address that before maintainer acceptance.

@ramimbo ramimbo added the mrwk:needs-info More information needed label May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mrwk:needs-info More information needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants