Files
Gitea-Tools/docs/mcp-namespace-health.md
T
sysadminandClaude Opus 4.8 287e0c5e65 feat: enforce live-namespace block in review/merge state machine (#543 AC5)
The namespace health check (05fdcee) classified a false-ready namespace but
only returned an advisory blocks_merge_workflow flag; nothing in the merge
gate consumed it. Wire it in so a broken live namespace hard-blocks merge.

- review_merge_state_machine.assess_workflow_blockers: add live_namespace_broken
  blocker (registered-in-FastMCP but not callable-through-namespace).
- assess_state_advancement: forward **blocker_kwargs so can_approve/can_merge/
  workflow_status honor the full blocker set (also fixes latent drop of
  mcp_reconnect_failed/stale_capability_state through those paths).
- gitea_assess_review_merge_state_machine tool: accept live_namespace_broken and
  thread it through all state-machine calls.
- Tests: prove can_merge/workflow_status/tool block on live_namespace_broken even
  with every review state + pre-merge gate satisfied; bridge classify verdict.
- Docs: enforcement section wiring blocks_merge_workflow -> live_namespace_broken.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-09 11:15:02 -04:00

3.0 KiB

MCP namespace EOF recovery

Gitea MCP tools can be registered in the Python FastMCP server while the IDE's live MCP namespace is still unusable. The failure usually appears as client is closing: EOF, transport closed, or an empty response when calling a tool such as gitea_whoami.

Do not treat static tool registration as proof that review or merge workflows can proceed. A reviewer or merger flow must have live namespace evidence that the required tool is callable through the configured namespace.

Required namespace probes

Run the health check after changing MCP config, switching branches that affect server code, or seeing EOF from any Gitea namespace:

python3 test_mcp_conn.py --config ~/.gemini/config/mcp_config.json

By default the script checks these namespaces and required tools:

Namespace Required tool
gitea-author gitea_whoami
gitea-reviewer gitea_whoami
gitea-merger gitea_whoami
gitea-tools gitea_list_profiles

Use --namespace gitea-reviewer to test only one namespace. A passing probe requires:

  1. The namespace exists in the MCP config.
  2. JSON-RPC initialize succeeds.
  3. tools/list returns the required tool.
  4. tools/call successfully invokes the required tool.

Recovery steps

When a namespace returns EOF:

  1. Note the reported namespace, required tool, PID, profile, environment summary, and config path.
  2. Stop any stale MCP server process for that PID.
  3. Reload or touch the MCP config so the IDE reconnects the namespace.
  4. Verify the namespace command, args, profile env, and checkout path point at the current repository.
  5. Re-run python3 test_mcp_conn.py --namespace <name>.
  6. Resume review or merge work only after the required tool call passes.

The read-only gitea_assess_mcp_namespace_health tool can classify probe evidence supplied by a client. It intentionally distinguishes required_tool_registered=true from required_tool_callable=false; the latter must block reviewer and merger workflows until the live namespace is repaired.

Enforcement in the review/merge state machine

The block is not advisory. Feed the blocks_merge_workflow verdict from gitea_assess_mcp_namespace_health into gitea_assess_review_merge_state_machine as live_namespace_broken:

health  = gitea_assess_mcp_namespace_health(namespace="gitea-merger", ...)
state   = gitea_assess_review_merge_state_machine(
              state_completion=...,
              pre_merge_gates=...,
              live_namespace_broken=health["blocks_merge_workflow"],
          )
# state["merge"]["allowed"] is False whenever the live namespace is broken,
# even when every review state and pre-merge gate is otherwise satisfied.

When live_namespace_broken=True, assess_workflow_blockers, can_approve, can_merge, and workflow_status all fail closed. This is the guard that stops a merge from proceeding on a false-ready namespace, as in the PR #418 halt that motivated this work (#543).