feat: CoDA MCP server for Genie Code integration#64
Open
datasciencemonkey wants to merge 3 commits into
Open
Conversation
Mounts an MCP server at `/mcp` so Databricks Genie Code (and other MCP clients like Claude Desktop, Cursor) can delegate coding tasks to the existing Hermes Agent infrastructure. Exposes three high-level tools following the v2 background-execution pattern: - coda_run — submit a coding task, returns task_id immediately - coda_inbox — poll all task statuses (24h window) - coda_get_result — fetch structured output of a completed task Plus internal helpers (`coda_create_session`, `coda_get_status`, `coda_close_session`). Sessions and task state are persisted to disk under `~/.coda/sessions/` so tasks survive worker restarts. Architecture ------------ - Native MCP SDK transport (`FastMCP.streamable_http_app()`) — required by Genie Code's Custom MCP server picker (custom JSON-RPC handlers don't work). - `stateless_http=True`, `json_response=True`. DNS-rebinding protection disabled (proxy handles auth, workspace origin allowed via CORS middleware). - Switches the production entrypoint from gunicorn → uvicorn so we can serve both the MCP ASGI app and the existing Flask UI side-by-side (Flask mounted via WSGIMiddleware). WebSocket falls back to HTTP polling under uvicorn — acceptable per the design doc; the Web Worker poller is already in place. - Skips CSP/security headers on the `/mcp` path (CSP interfered with Genie Code's transport). - Hermes is always the agent invoked; it routes to sub-agents internally. - Adds a stdio MCP bridge (`tools/coda-bridge.py`) for Claude Code's OAuth-based auth flow. Repository reshuffles --------------------- - New `coda_mcp/` package: `mcp_server`, `mcp_endpoint`, `mcp_asgi`, `task_manager`. - `setup_*.py` moved from repo root to `setup/`. - `install_*.sh` moved from repo root to `scripts/`. - Tests: new coverage for the MCP server, integration flow, task manager, content filter proxy, sync_to_workspace, _run_step. - Docs: `docs/mcp-client-setup.md`, `docs/mcp-v2-background-execution.md`, and the full implementation plan at `docs/plans/2026-05-01-coda-mcp-server.md`. Safety guardrails ----------------- The CODA-TASK prompt envelope explicitly forbids destructive operations (DROP/DELETE/TRUNCATE, CLI deletes, permission changes) at the prompt level, in line with the CoDA Constitution. Tested as `mcp-test-coda` on workspace `fevm-serverless-9cefok` (profile `9cefok`). App name must start with `mcp-` to appear in the Genie Code Custom MCP server picker. Provenance ---------- Squashed from 40 commits originally on `datasciencemonkey/coding-agents-databricks-apps#156`, last working tip `1ce86bf`. Full commit-by-commit history preserved locally on the tag `coda-mcp-backup-2026-05-25`. Conflict resolutions during the squash: - README.md MLflow section: kept main's Claude+Codex unified switch (newer than coda-mcp's Claude-only state). - setup/setup_claude.py: combined main's enterprise installer URL handling with coda-mcp's `SKIP_CLAUDE_INSTALL` test escape hatch.
Surfaces a doc audit pass against the squash: - README: replace the gunicorn+Flask architecture diagram with the actual uvicorn ASGI stack (socketio.ASGIApp → /mcp + WSGI(Flask)). Update the startup-flow narrative, the "Server" config section (was "Gunicorn"), the project-structure annotations for app.yaml and gunicorn.conf.py (legacy, retained for WSGI-only dev), and the Technologies list. - app.yaml: prepend a comment block explaining why the entrypoint is uvicorn (FastMCP.streamable_http_app is native ASGI; gunicorn WSGI cannot serve it). Notes the polling-fallback behaviour and the retained-but-unused gunicorn.conf.py. - docs/plans/2026-05-01-coda-mcp-server.md: prepend a SUPERSEDED banner. The shipped implementation is the v2 design in docs/mcp-v2-background-execution.md (3 tools on uvicorn+ASGI), not the 5-tool gunicorn+WSGI plan in this file. Kept for design- evolution archaeology. - coda_mcp/mcp_endpoint.py: docstring now clearly states this module is a Flask Blueprint fallback for WSGI runtimes (gunicorn local dev, Flask test client). Production routes through coda_mcp.mcp_asgi.
Closes two coverage gaps surfaced by a pre-merge test audit. Both
files exercise surfaces that production traffic actually hits, and
neither had a dedicated test file before this commit.
tests/test_mcp_endpoint.py (9 tests, all pass)
- Pin the Flask Blueprint's JSON-RPC contract: initialize, tools/list,
ping, tools/call (unknown), unknown method, CORS preflight,
jsonrpc id echo, non-JSON body resilience, tool schema presence.
- Asserts the tool surface is exactly {coda_run, coda_inbox,
coda_get_result}. Drift from the v2 contract fails loudly.
tests/test_coda_bridge.py (3 pass + 1 documented skip)
- Verify the bridge injects the Databricks Bearer token mounted via
`databricks auth token` into Authorization on every forwarded
request (regression guard — a silent drop would 401 every Genie
Code call against a deployed app).
- Verify it surfaces server response bodies and refuses to run
without CODA_MCP_URL configured.
- Skip and document the stdout-capture variant for a follow-up.
Full suite: 490 passed, 2 skipped (was 478/1 before this PR). No
regressions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/mcpso Databricks Genie Code (and other MCP clients like Claude Desktop, Cursor) can delegate coding tasks to Hermes Agent over the MCP protocol.coda_run,coda_inbox,coda_get_result. Session and task state persists to~/.coda/sessions/.tools/coda-bridge.py) so Claude Code's OAuth flow can talk to CoDA.setup_*.py→setup/andinstall_*.sh→scripts/so the repo root stays uncluttered.Architecture highlights
FastMCP.streamable_http_app()) — required by Genie Code's Custom MCP server picker. Custom JSON-RPC handlers don't work.stateless_http=True,json_response=True. DNS-rebinding protection disabled (the Databricks Apps proxy handles auth; workspace origin allowed via CORSMiddleware)./mcppath (CSP interfered with Genie Code's transport).Deployment notes
mcp-to appear in the Genie Code Custom MCP server picker.mcp-test-codaon workspacefevm-serverless-9cefok(profile9cefok).docs/plans/2026-05-01-coda-mcp-server.mdfor the full design rationale anddocs/mcp-v2-background-execution.mdfor the v2 background flow diagram.Provenance
This work was originally developed on a personal fork at
datasciencemonkey/coding-agents-databricks-apps#156across 40 commits, last working tip1ce86bf. Squashed for clean review against current labsmain. Full 40-commit history retained locally on tagcoda-mcp-backup-2026-05-25.Two conflicts surfaced during the squash and were resolved as follows:
SKIP_CLAUDE_INSTALLtest escape hatch.Test plan
make testpasses locally (478 passed, 1 skipped, 0 failed in ~21s)uvicorn coda_mcp.mcp_asgi:appboots without tracebackfrom coda_mcp import mcp_server, mcp_asgi, task_managersucceeds/mcp, run one task end-to-end viacoda_run/(terminal works under uvicorn's polling fallback)