Skip to content

Extract MCP tool dispatch from app.main#356

Closed
TUPM96 wants to merge 2 commits into
ramimbo:mainfrom
TUPM96:codex/bounty-320-mcp-dispatch
Closed

Extract MCP tool dispatch from app.main#356
TUPM96 wants to merge 2 commits into
ramimbo:mainfrom
TUPM96:codex/bounty-320-mcp-dispatch

Conversation

@TUPM96
Copy link
Copy Markdown
Contributor

@TUPM96 TUPM96 commented May 26, 2026

Refs #320

Summary

  • Move MCP tool dispatch and MCP-specific argument validation/response shaping out of app.main into app.mcp_tools.
  • Keep the /mcp route in app.main as thin route wiring through handle_mcp_request and the new call_mcp_tool handler.
  • Add direct mcp_tools tests so MCP dispatch can be covered without routing through FastAPI.
  • Preserve the existing OAuth next-path safety expectation required by the test suite for encoded backslash redirects.

Complexity reduced

  • app.main no longer carries the MCP command dispatcher, nested MCP argument parsers, proof/bounty/wallet MCP response shaping, or MCP work-proof guidance builders. That makes route wiring, public pages, admin flows, and MCP behavior easier to review independently.

Tests

  • python -m ruff check .
  • python -m pytest tests\test_wallet_api.py::test_github_login_stores_safe_default_for_backslash_next tests\test_mcp_tools.py tests\test_api_mcp.py -q
  • python -m pytest -q

Copilot AI review requested due to automatic review settings May 26, 2026 01:40
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Warning

Review limit reached

@TUPM96, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 3 minutes and 33 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6a524f1a-e71c-4e52-b28b-9048ee44ef47

📥 Commits

Reviewing files that changed from the base of the PR and between ac99d79 and 4462654.

📒 Files selected for processing (3)
  • app/main.py
  • app/mcp_tools.py
  • tests/test_mcp_tools.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR extracts MCP tool dispatch into a dedicated app/mcp_tools.py module so MCP tools can be invoked without the FastAPI route wiring, updates the /mcp route to use the extracted dispatcher, and adds tests validating tool behavior against a SQLite DB.

Changes:

  • Added app/mcp_tools.py with call_mcp_tool() and supporting validation/serialization helpers.
  • Updated app/main.py to use call_mcp_tool for /mcp and hardened _safe_next_path by validating decoded values.
  • Added pytest coverage for listing bounties and rejecting invalid ledger arguments without an HTTP layer.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
tests/test_mcp_tools.py Adds tests invoking MCP tools directly against SQLite schema/data.
app/mcp_tools.py Introduces extracted MCP tool dispatcher and argument normalization utilities.
app/main.py Wires /mcp to the extracted dispatcher and strengthens redirect “next” path validation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/mcp_tools.py
proof = session.get(Proof, _proof_hash_from_arg(str_arg("hash")))
if proof is None:
return "proof not found"
public_payload = json.loads(proof.public_json)
Comment thread app/mcp_tools.py
"ledger_sequence": proof.ledger_sequence,
"bounty_id": proof.bounty_id,
"submission_id": proof.submission_id,
"created_at": proof.created_at.isoformat(),
Comment thread app/mcp_tools.py
Comment on lines +114 to +122
bounty_id = lower.removeprefix(reserve_prefix)
try:
normalized_bounty_id = int(bounty_id) if bounty_id.isdigit() else 0
except ValueError as exc:
raise ValueError("reserve bounty id is too large") from exc
if normalized_bounty_id <= 0:
raise ValueError("reserve bounty id must be positive")
if normalized_bounty_id > SQLITE_INTEGER_MAX:
raise ValueError("reserve bounty id is too large")
Comment thread app/mcp_tools.py
Comment on lines +150 to +156
elif isinstance(value, str):
clean = value.strip()
if clean and clean.lstrip("+-").isdigit():
try:
parsed = int(clean)
except ValueError as exc:
raise ValueError(f"{field} must be an integer") from exc
Comment thread tests/test_mcp_tools.py
Comment on lines +34 to +40
def test_call_mcp_tool_rejects_invalid_arguments_without_http_layer(sqlite_url: str) -> None:
create_schema(sqlite_url)
with session_scope(sqlite_url) as session:
ensure_genesis(session)

with pytest.raises(ValueError, match="sequence must be positive"):
call_mcp_tool(sqlite_url, "get_ledger_entry", {"sequence": 0})
Copy link
Copy Markdown
Contributor

@tolga-tom-nook tolga-tom-nook left a comment

Choose a reason for hiding this comment

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

Requested change: current head d164d08 fails the repository formatting gate.

What I checked:

  • Inspected app/mcp_tools.py, app/main.py, and tests/test_mcp_tools.py against origin/main.
  • Verified the MCP tool dispatch extraction is mechanically wired through /mcp via handle_mcp_request(..., call_mcp_tool) and that the extracted helper preserves the existing session/argument validation/tool dispatch behavior.
  • Ran ./.venv/bin/python -m pytest tests/test_mcp_tools.py tests/test_api_mcp.py -q — passed, 78 tests.
  • Ran full ./.venv/bin/python -m pytest -q — passed, 337 tests.
  • Ran ./.venv/bin/python -m ruff check app/main.py app/mcp_tools.py tests/test_mcp_tools.py tests/test_api_mcp.py — passed.
  • Ran ./.venv/bin/python -m mypy app — passed.
  • Ran ./.venv/bin/python scripts/docs_smoke.py — passed.
  • Ran git diff --check origin/main...HEAD — passed.

Blocker:

  • ./.venv/bin/python -m ruff format --check . fails with Would reformat: app/mcp_tools.py.
  • The diff from ./.venv/bin/python -m ruff format --diff app/mcp_tools.py is only the _bounty_attempt_to_dict(...) signature collapsing to one line, so this should be a tiny formatting-only fix.

After formatting app/mcp_tools.py and re-running the format gate, I do not see functional blockers in the MCP dispatch extraction.

Copy link
Copy Markdown
Contributor

@ayskobtw-lil ayskobtw-lil left a comment

Choose a reason for hiding this comment

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

Follow-up review after the formatting fix in 4462654.

Evidence checked:

  • Rechecked current head 44626549aa7b5c6f0364296d05fa42623d990452 after the earlier review blocker that app/mcp_tools.py failed the formatter gate.
  • Inspected app/mcp_tools.py, app/main.py, and tests/test_mcp_tools.py; verified /mcp now delegates through handle_mcp_request(..., call_mcp_tool) while the extracted dispatcher preserves direct list_bounties, get_ledger_entry, and existing MCP route coverage.
  • Confirmed the decoded OAuth next-path guard still covers the wallet login regression included in the focused run.

Validation:

  • python -m ruff format --check app/mcp_tools.py app/main.py tests/test_mcp_tools.py -> 3 files already formatted.
  • python -m pytest tests/test_mcp_tools.py tests/test_api_mcp.py tests/test_wallet_api.py::test_github_login_stores_safe_default_for_backslash_next -q -> 79 passed.
  • python -m ruff check app/main.py app/mcp_tools.py tests/test_mcp_tools.py tests/test_api_mcp.py tests/test_wallet_api.py -> passed.
  • python -m mypy app/mcp_tools.py app/main.py -> success.
  • git diff --check origin/main...HEAD -> clean.
  • GitHub reports the hosted Quality/readiness/docs/image check green and the PR mergeable.

The earlier formatting blocker is resolved; I do not see remaining blockers from this follow-up pass.

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

ramimbo commented May 26, 2026

Maintainer note after #320 filled: this PR still references closed bounty #320. If you want it considered for the current code-health round, rebase against main, update the bounty reference to #377, and keep the scope distinct from already accepted #328, #337, #364, #375, and #376. This is not accepted or paid as-is.

@ramimbo
Copy link
Copy Markdown
Owner

ramimbo commented May 26, 2026

Closing this stale bounty submission. It still references a closed/filled bounty round and is dirty or unstable against current main after the route/test extraction batches. A future attempt needs a fresh PR against current main, a currently open bounty reference, and scope distinct from work already accepted.

@ramimbo ramimbo added the mrwk:rejected Submission rejected label May 26, 2026
@ramimbo ramimbo closed this May 26, 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 mrwk:rejected Submission rejected

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants