Skip to content

Support MCP lifecycle basics#563

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

Support MCP lifecycle basics#563
xingxi0614-cpu wants to merge 3 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) endpoints: initialize (with protocol negotiation and clear errors for unsupported or invalid params), notifications/initialized (accepted as 202 when no id), and ping (returns empty success result). Server advertises tool capabilities and server info during initialization.
  • Tests

    • Added tests covering initialize payloads, protocol-version defaulting/validation, invalid-params and unsupported-version errors, 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: de24e8c7-c530-4dd2-a6dc-101e8264cd93

📥 Commits

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

📒 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, SUPPORTED_PROTOCOL_VERSIONS, 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, negotiates/defaults protocolVersion, rejects unsupported versions with JSON-RPC error and data), 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, unsupported-version and invalid-params errors, 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 accurately summarizes the main change: MCP lifecycle features added to the endpoint.
Description check ✅ Passed The description addresses all template sections with concrete evidence, validation results, scope clarity, and safety attestation. References issue #406, provides live preflight evidence, validation commands/results, and detailed scope listing.
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 only technical MCP lifecycle implementation (initialize, ping, notifications/initialized) with no investment, price, cash-out, payout claims, or private security details.
Bounty Pr Focus ✅ Passed Changes match stated scope: app/mcp.py adds initialize/notifications/initialized/ping handlers; tests/test_api_mcp.py adds 7 tests. Tool functionality preserved, no unrelated scope detected.

✏️ 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 Outdated
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
Copy link
Copy Markdown

@barnacleagent-svg barnacleagent-svg left a comment

Choose a reason for hiding this comment

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

Verdict: APPROVED

Scope: Adds MCP lifecycle basics: initialize handshake with protocol version negotiation, server info (MergeWork MCP v0.1.0), and proper JSON-RPC error responses. Returns Response type for initialize.

Checklist:

  • Implements standard MCP initialize flow
  • Handles missing/invalid params gracefully
  • Backward compatible (existing tools untouched)
  • Tests cover new behavior

Conclusion: Clean MCP lifecycle implementation. Ready to merge.

@xingxi0614-cpu
Copy link
Copy Markdown
Author

Thanks, I addressed the protocol-version negotiation issue.

Follow-up commit: 88098b5

What changed:

  • added an explicit supported MCP protocol-version set;
  • initialize now accepts the supported default version 2025-06-18;
  • unsupported string versions such as 1900-01-01 and not-a-version now return JSON-RPC -32602 with supported/requested version details instead of being echoed as negotiated;
  • added regression coverage for unsupported string protocol versions.

Validation:

  • tests/test_api_mcp.py: 86 passed
  • ruff check/format-check: passed
  • mypy app/mcp.py: success
  • git diff --check origin/main...HEAD: clean

No private data, secrets, wallet material, production mutation, price/off-ramp, liquidity, exchange, bridge-promise, or private security details are included.

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.

Re-reviewed follow-up head 88098b5766047fcac404057bdd71df78f94a134e.

Verdict: approve.

The protocol-version blocker from my previous review is addressed. initialize now uses an explicit supported-version set, accepts the supported default 2025-06-18, and rejects unsupported string versions with JSON-RPC -32602 data instead of echoing them as negotiated.

Validation:

  • git diff --check origin/main...HEAD -> clean.
  • git merge-tree --write-tree origin/main HEAD -> 06a79ad8ff64c8c238d0d0ecb4ac20c534a13809.
  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 ..\mergework\.venv\Scripts\python.exe -m pytest tests\test_api_mcp.py -q --tb=short -> 86 passed.
  • ..\mergework\.venv\Scripts\python.exe -m ruff check app\mcp.py tests\test_api_mcp.py -> passed.
  • ..\mergework\.venv\Scripts\python.exe -m ruff format --check app\mcp.py tests\test_api_mcp.py -> 2 files already formatted.
  • ..\mergework\.venv\Scripts\python.exe -m mypy app\mcp.py -> success.
  • GitHub checks are green: Quality/readiness/docs/image checks and CodeRabbit both passing.

I do not see a remaining blocker on the MCP lifecycle/protocol negotiation slice.

@xingxi0614-cpu
Copy link
Copy Markdown
Author

Thanks again for the review and maintainer cleanup note. I believe the earlier mrwk:needs-info blocker has been addressed now.

Current state:

  • follow-up commit 88098b5 adds an explicit supported MCP protocol-version set;
  • unsupported string protocol versions now return JSON-RPC -32602 with supported/requested version details instead of being echoed as negotiated;
  • the external re-review approved the follow-up head and reported no remaining blocker;
  • GitHub checks are green and merge state is clean.

Could you please re-check and clear mrwk:needs-info if this now satisfies the requested change?

@xingxi0614-cpu
Copy link
Copy Markdown
Author

Quick follow-up: this PR still has the mrwk:needs-info label, but the requested protocol-version blocker appears to be addressed at current head 88098b5.

Current state:

  • unsupported MCP protocolVersion strings now return JSON-RPC -32602 instead of being echoed as negotiated;
  • the follow-up head has an external approval with no remaining blocker reported;
  • GitHub checks are green and merge state is clean.

Could you please re-check and clear mrwk:needs-info if this now satisfies the requested change?

@ramimbo ramimbo removed the mrwk:needs-info More information needed label May 29, 2026
@ramimbo
Copy link
Copy Markdown
Owner

ramimbo commented May 29, 2026

Re-checked current head 88098b5. The MCP protocolVersion blocker is cleared: unsupported strings now return JSON-RPC -32602 instead of being echoed as negotiated. Waiting for a second useful current-head review before merge.

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.

5 participants