Damascus Entry Points P3: damascus-mcp server (stdio, 7 tools) #16

Merged
kaykayyali merged 1 commits from feat/entry-points-mcp into main 2026-06-24 14:58:19 +00:00
Owner

Summary

Implements P3 of the entry-points work. The MCP server is a thin stdio wrapper around damascus-api: seven tools, each one HTTP call. No direct Postgres access — all data flows through the API.

Tool catalog (7)

MCP tool Maps to
list_items GET /v1/items
get_item GET /v1/items/{id}
list_open_questions GET /v1/issues?status=open
answer_question POST /v1/issues/{id}/answer
ingest_story POST /v1/items
bulk_ingest POST /v1/items/bulk
system_status GET /v1/stats

Tool input schemas are derived from Mcp*Args Pydantic models via model_json_schema() — single source of truth, no hand-written JSON. The test test_input_schemas_derived_from_mcp_args_models asserts no drift.

Files

  • src/damascus/mcp_server.py (new, 404 lines) — mcp SDK stdio server + 7 tools
  • src/damascus/api_schemas.py — adds McpBulkIngestArgs + McpBulkIngestStoryItem
  • src/damascus/cli.py — adds damascus mcp-serve subcommand
  • tests/contract/test_mcp_roundtrip.py (new, 524 lines) — 11 round-trip tests via httpx.MockTransport
  • tests/contract/test_mcp_cli.py (new, 77 lines) — CLI subcommand tests
  • pyproject.tomlmcp>=1.0 dep, pytest-asyncio dev extra, asyncio_mode = "auto"

Acceptance

  • python -c "from damascus.mcp_server import mcp; print(len(mcp.list_tools()))"7
  • pytest tests/contract/test_mcp_roundtrip.py tests/contract/test_mcp_cli.py → 14/14 pass
  • All 6 args-derived tools have zero schema drift
  • damascus mcp-serve --help works
  • Subprocess smoke test (python -m damascus mcp-serve with EOF on stdin) exits cleanly
  • No import psycopg / DATABASE_URL references in mcp_server.py (no direct DB access)

Drift / contract notes

The wiki (wiki/concepts/entry-points-contract.md §5) names the bulk-ingest tool ingest_project (server-side directory scan). The P3 task body names it bulk_ingest (client-supplied list). This PR follows the task body: McpBulkIngestArgs.stories is a list of McpBulkIngestStoryItem items, posted directly to POST /v1/items/bulk. The wiki page is .gitignored (per repo .gitignore:wiki/) and lives in the separate kaykayyali/damascus-wiki repo — the schema file is the source of truth per the wiki itself, and the schema is what the MCP catalog is generated from.

How to drive

export DAMASCUS_API_BASE=http://localhost:9110
export DAMASCUS_API_TOKEN=DAMAS....
damascus mcp-serve
## Summary Implements P3 of the entry-points work. The MCP server is a thin stdio wrapper around damascus-api: seven tools, each one HTTP call. No direct Postgres access — all data flows through the API. ## Tool catalog (7) | MCP tool | Maps to | |---|---| | `list_items` | `GET /v1/items` | | `get_item` | `GET /v1/items/{id}` | | `list_open_questions` | `GET /v1/issues?status=open` | | `answer_question` | `POST /v1/issues/{id}/answer` | | `ingest_story` | `POST /v1/items` | | `bulk_ingest` | `POST /v1/items/bulk` | | `system_status` | `GET /v1/stats` | Tool input schemas are derived from `Mcp*Args` Pydantic models via `model_json_schema()` — single source of truth, no hand-written JSON. The test `test_input_schemas_derived_from_mcp_args_models` asserts no drift. ## Files - `src/damascus/mcp_server.py` (new, 404 lines) — mcp SDK stdio server + 7 tools - `src/damascus/api_schemas.py` — adds `McpBulkIngestArgs` + `McpBulkIngestStoryItem` - `src/damascus/cli.py` — adds `damascus mcp-serve` subcommand - `tests/contract/test_mcp_roundtrip.py` (new, 524 lines) — 11 round-trip tests via `httpx.MockTransport` - `tests/contract/test_mcp_cli.py` (new, 77 lines) — CLI subcommand tests - `pyproject.toml` — `mcp>=1.0` dep, `pytest-asyncio` dev extra, `asyncio_mode = "auto"` ## Acceptance - [x] `python -c "from damascus.mcp_server import mcp; print(len(mcp.list_tools()))"` → `7` - [x] `pytest tests/contract/test_mcp_roundtrip.py tests/contract/test_mcp_cli.py` → 14/14 pass - [x] All 6 args-derived tools have zero schema drift - [x] `damascus mcp-serve --help` works - [x] Subprocess smoke test (`python -m damascus mcp-serve` with EOF on stdin) exits cleanly - [x] No `import psycopg` / `DATABASE_URL` references in mcp_server.py (no direct DB access) ## Drift / contract notes The wiki (`wiki/concepts/entry-points-contract.md` §5) names the bulk-ingest tool `ingest_project` (server-side directory scan). The P3 task body names it `bulk_ingest` (client-supplied list). This PR follows the **task body**: `McpBulkIngestArgs.stories` is a list of `McpBulkIngestStoryItem` items, posted directly to `POST /v1/items/bulk`. The wiki page is `.gitignore`d (per repo `.gitignore:wiki/`) and lives in the separate `kaykayyali/damascus-wiki` repo — the schema file is the source of truth per the wiki itself, and the schema is what the MCP catalog is generated from. ## How to drive ```bash export DAMASCUS_API_BASE=http://localhost:9110 export DAMASCUS_API_TOKEN=DAMAS.... damascus mcp-serve ```
kaykayyali added 1 commit 2026-06-24 13:54:10 +00:00
feat(mcp): damascus-mcp stdio server + 7 tools + CLI subcommand (P3)
Some checks failed
test / contract-and-unit (pull_request) Failing after 18s
203bb9c8e1
Implements P3 of the entry-points work. The MCP server is a thin
stdio wrapper around damascus-api: seven tools, each one HTTP call.
No direct Postgres access — all data flows through the API.

Tool catalog (7):
  - list_items           → GET /v1/items
  - get_item             → GET /v1/items/{id}
  - list_open_questions  → GET /v1/issues?status=open
  - answer_question      → POST /v1/issues/{id}/answer
  - ingest_story         → POST /v1/items
  - bulk_ingest          → POST /v1/items/bulk
  - system_status        → GET /v1/stats

Tool input schemas are derived from Mcp*Args Pydantic models via
model_json_schema() — single source of truth, no hand-written JSON.
Test test_input_schemas_derived_from_mcp_args_models asserts no drift.

Adds:
  - src/damascus/mcp_server.py     mcp SDK stdio server + 7 tools
  - tests/contract/test_mcp_roundtrip.py   11 round-trip tests via httpx.MockTransport
  - tests/contract/test_mcp_cli.py         CLI subcommand tests
  - McpBulkIngestArgs / McpBulkIngestStoryItem in api_schemas.py
  - damascus mcp-serve CLI subcommand
  - pyproject.toml: mcp>=1.0 dep, pytest-asyncio dev extra, asyncio_mode=auto

Acceptance:
  - python -c 'from damascus.mcp_server import mcp; print(len(mcp.list_tools()))' → 7
  - pytest tests/contract/test_mcp_roundtrip.py tests/contract/test_mcp_cli.py → 14/14 pass
  - All 6 args-derived tools have zero schema drift
kaykayyali merged commit 22b4056d6d into main 2026-06-24 14:58:19 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: kaykayyali/damascus-orchestrator#16