Rewrite MCP tools to wrap SDK + add block tools #23

Merged
forgejo_admin merged 1 commit from 22-mcp-sdk-rewrite into main 2026-03-08 00:13:25 +00:00

Summary

Rewrites all 26 existing MCP tools to wrap pal-e-docs-sdk v0.1.0 instead of making raw httpx calls, and adds 7 new tools (6 block tools + delete_sprint) for 32 total tools with 100% SDK coverage.

Changes

  • pyproject.toml — Replace httpx dependency with pal-e-docs-sdk>=0.1.0, add Forgejo PyPI index ([tool.uv.sources] + [[tool.uv.index]]), bump version to 0.2.0, bump requires-python to >=3.12 to match SDK
  • src/pal_e_docs_mcp/server.py — Replace httpx.Client with PalEDocsClient via get_sdk(), _ok() now takes parsed data (not httpx.Response), _error_response() handles PalEDocsError hierarchy
  • src/pal_e_docs_mcp/tools/notes.py — Rewrite 7 tools to wrap SDK; param translation for content->html_content, project->project_slug, CSV tags->list[str]
  • src/pal_e_docs_mcp/tools/sprints.py — Rewrite 10 tools + add delete_sprint; param translation for CSV labels->list[str], _UNSET sentinel handling for update_sprint, default status="planning" for create_sprint, default position=0 for add_sprint_item
  • src/pal_e_docs_mcp/tools/links.py — Rewrite 2 tools; CSV target_slugs->list[str]
  • src/pal_e_docs_mcp/tools/projects.py — Rewrite 2 tools
  • src/pal_e_docs_mcp/tools/repos.py — Rewrite 3 tools
  • src/pal_e_docs_mcp/tools/tags.py — Rewrite 1 tool
  • src/pal_e_docs_mcp/tools/__init__.py — Add blocks module registration
  • src/pal_e_docs_mcp/tools/blocks.py — 6 new block tools: get_note_toc, list_blocks, get_section, update_block, create_block, delete_block
  • uv.lock — Regenerated with SDK dependency

Test Plan

  • ruff check and ruff format --check pass
  • Server imports successfully with 32 tools discoverable (verified via asyncio.run(mcp.list_tools()))
  • No raw httpx imports in any source file
  • MCP tool signatures unchanged (backward compatible) -- all param translation happens in wrapper layer
  • Manual smoke tests: get_note_toc, get_section, get_note, list_tags, search_notes

Review Checklist

  • No raw httpx imports in any tool file
  • All 32 tools discoverable
  • ruff check passes
  • ruff format --check passes
  • MCP tool signatures unchanged (backward compat)
  • Param translations correct (CSV->list, content->html_content, etc.)
  • Forgejo PyPI index configured in pyproject.toml
  • Version bumped to 0.2.0
  • No unrelated changes
  • Plan: plan-2026-02-26-tf-modularize-postgres (Phase 8f)
  • Forgejo issue: #22
## Summary Rewrites all 26 existing MCP tools to wrap `pal-e-docs-sdk` v0.1.0 instead of making raw httpx calls, and adds 7 new tools (6 block tools + delete_sprint) for 32 total tools with 100% SDK coverage. ## Changes - **`pyproject.toml`** — Replace `httpx` dependency with `pal-e-docs-sdk>=0.1.0`, add Forgejo PyPI index (`[tool.uv.sources]` + `[[tool.uv.index]]`), bump version to 0.2.0, bump `requires-python` to `>=3.12` to match SDK - **`src/pal_e_docs_mcp/server.py`** — Replace `httpx.Client` with `PalEDocsClient` via `get_sdk()`, `_ok()` now takes parsed data (not `httpx.Response`), `_error_response()` handles `PalEDocsError` hierarchy - **`src/pal_e_docs_mcp/tools/notes.py`** — Rewrite 7 tools to wrap SDK; param translation for `content`->`html_content`, `project`->`project_slug`, CSV `tags`->`list[str]` - **`src/pal_e_docs_mcp/tools/sprints.py`** — Rewrite 10 tools + add `delete_sprint`; param translation for CSV `labels`->`list[str]`, `_UNSET` sentinel handling for `update_sprint`, default `status="planning"` for `create_sprint`, default `position=0` for `add_sprint_item` - **`src/pal_e_docs_mcp/tools/links.py`** — Rewrite 2 tools; CSV `target_slugs`->`list[str]` - **`src/pal_e_docs_mcp/tools/projects.py`** — Rewrite 2 tools - **`src/pal_e_docs_mcp/tools/repos.py`** — Rewrite 3 tools - **`src/pal_e_docs_mcp/tools/tags.py`** — Rewrite 1 tool - **`src/pal_e_docs_mcp/tools/__init__.py`** — Add `blocks` module registration - **`src/pal_e_docs_mcp/tools/blocks.py`** — 6 new block tools: `get_note_toc`, `list_blocks`, `get_section`, `update_block`, `create_block`, `delete_block` - **`uv.lock`** — Regenerated with SDK dependency ## Test Plan - `ruff check` and `ruff format --check` pass - Server imports successfully with 32 tools discoverable (verified via `asyncio.run(mcp.list_tools())`) - No raw `httpx` imports in any source file - MCP tool signatures unchanged (backward compatible) -- all param translation happens in wrapper layer - Manual smoke tests: `get_note_toc`, `get_section`, `get_note`, `list_tags`, `search_notes` ## Review Checklist - [x] No raw httpx imports in any tool file - [x] All 32 tools discoverable - [x] `ruff check` passes - [x] `ruff format --check` passes - [x] MCP tool signatures unchanged (backward compat) - [x] Param translations correct (CSV->list, content->html_content, etc.) - [x] Forgejo PyPI index configured in pyproject.toml - [x] Version bumped to 0.2.0 - [x] No unrelated changes ## Related - Plan: `plan-2026-02-26-tf-modularize-postgres` (Phase 8f) - Forgejo issue: #22
Rewrite all 26 MCP tools to wrap SDK + add 7 new tools (blocks + delete_sprint)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
7c5a732b55
Replace raw httpx calls with pal-e-docs-sdk v0.1.0 wrappers across all tool
modules. Add 6 block tools (get_note_toc, list_blocks, get_section,
update_block, create_block, delete_block) for sub-note granularity and 1 new
sprint tool (delete_sprint). Total: 32 tools, 100% SDK coverage.

server.py: get_client()->get_sdk() returning PalEDocsClient, _ok() takes
parsed data instead of httpx.Response, _error_response() handles PalEDocsError
hierarchy. pyproject.toml: httpx->pal-e-docs-sdk>=0.1.0, version 0.2.0,
Forgejo PyPI index configured, requires-python bumped to >=3.12.

Closes #22

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Owner

PR #23 Review

Phase 8f-2: Rewrite MCP tools to wrap SDK + add block/sprint tools.

I reviewed all source files on the 22-mcp-sdk-rewrite branch: server.py, __main__.py, tools/__init__.py, and all 7 tool modules (notes.py, tags.py, projects.py, repos.py, links.py, sprints.py, blocks.py). I cross-referenced every tool against the SDK mixin signatures in pal-e-docs-sdk.

BLOCKERS

None.

NITS

  1. Missing __init__.py at package root -- /src/pal_e_docs_mcp/__init__.py does not exist. Hatchling's packages directive makes this work for builds, but having an empty __init__.py is conventional and helps IDEs. Non-blocking since hatch handles it.

  2. .gitignore does not exclude .claude/ -- The .claude/worktrees/decomposition-tools/ directory exists in the repo tree. If this is local-only (git worktree), it's fine. If it were accidentally staged, it would be a problem. Recommend adding .claude/ to .gitignore as a safety measure.

  3. Tool count discrepancy -- Issue #22 says "26 existing + 7 new = 33 tools". Actual count from @mcp.tool() decorators is 32 (7 notes + 1 tags + 2 projects + 3 repos + 2 links + 11 sprints + 6 blocks). Minor issue text inaccuracy, not a code problem.

  4. noqa: E741 on variable l -- In sprints.py lines 162 and 199, the list comprehension uses l as the loop variable in [l.strip() for l in labels.split(",")]. This triggers the ambiguous variable name lint and requires noqa. A rename to lbl or label would be cleaner. Non-blocking.

Code Quality Assessment

Architecture: Clean modularization. Single server.py with get_sdk(), _ok(), _error_response() helpers. Seven tool modules registered via register_all_tools() in tools/__init__.py. Good separation of concerns.

SDK wrapping: All 32 tools correctly delegate to SDK methods. Zero raw httpx calls remain in the source tree. Verified by grep.

Parameter translations (8 verified correct):

  • content -> html_content (create_note, update_note)
  • project -> project_slug (create_note, update_note)
  • tags CSV string -> list[str] (create_note, update_note)
  • target_slugs CSV string -> list[str] (update_note_links)
  • labels CSV string -> list[str] (add_sprint_item, move_sprint_item)
  • items JSON string -> list[dict] (bulk_move_items)
  • _UNSET sentinel handling for goal, start_date, end_date (update_sprint)
  • _UNSET sentinel handling for labels (move_sprint_item via update_sprint_item)

Error handling: Uniform try/except pattern across all tools. _error_response correctly handles the PalEDocsError hierarchy (base, NotFoundError, ValidationError, ServerError) and generic exceptions.

New tools (7):

  • 6 block tools: get_note_toc, list_blocks, get_section, update_block, create_block, delete_block -- all correctly wrap SDK BlocksMixin methods
  • delete_sprint -- correctly calls get_sdk().delete_sprint(slug) and returns _ok(None)

pyproject.toml: httpx dependency removed, replaced with pal-e-docs-sdk>=0.1.0. Forgejo PyPI index correctly configured via [tool.uv.sources] and [[tool.uv.index]].

No secrets or credentials committed. .env is in .gitignore.

SOP COMPLIANCE

  • Branch named after issue (22-mcp-sdk-rewrite references issue #22)
  • No secrets, .env files, or credentials committed
  • No unnecessary file changes -- scope is tight to the rewrite
  • PR body template (## Summary, ## Changes, ## Test Plan, ## Related) -- could not extract PR body from the API response (single-line JSON exceeds read limits), but branch naming and scope are clean
  • Tests exist -- no test files found in tests/. The Woodpecker CI pipeline only runs ruff lint, no test step. This is consistent with the existing repo state (tests were likely never present), but worth noting.

VERDICT: APPROVED

The rewrite is thorough and correct. All 32 tools properly wrap SDK methods with accurate parameter translations. The _UNSET sentinel handling for nullable sprint fields is well-documented in comments. httpx is fully eliminated from the application code. The modular architecture (7 tool modules) is a clear improvement over whatever the previous monolithic structure was. No blockers found.

## PR #23 Review Phase 8f-2: Rewrite MCP tools to wrap SDK + add block/sprint tools. I reviewed all source files on the `22-mcp-sdk-rewrite` branch: `server.py`, `__main__.py`, `tools/__init__.py`, and all 7 tool modules (`notes.py`, `tags.py`, `projects.py`, `repos.py`, `links.py`, `sprints.py`, `blocks.py`). I cross-referenced every tool against the SDK mixin signatures in `pal-e-docs-sdk`. ### BLOCKERS None. ### NITS 1. **Missing `__init__.py` at package root** -- `/src/pal_e_docs_mcp/__init__.py` does not exist. Hatchling's `packages` directive makes this work for builds, but having an empty `__init__.py` is conventional and helps IDEs. Non-blocking since hatch handles it. 2. **`.gitignore` does not exclude `.claude/`** -- The `.claude/worktrees/decomposition-tools/` directory exists in the repo tree. If this is local-only (git worktree), it's fine. If it were accidentally staged, it would be a problem. Recommend adding `.claude/` to `.gitignore` as a safety measure. 3. **Tool count discrepancy** -- Issue #22 says "26 existing + 7 new = 33 tools". Actual count from `@mcp.tool()` decorators is 32 (7 notes + 1 tags + 2 projects + 3 repos + 2 links + 11 sprints + 6 blocks). Minor issue text inaccuracy, not a code problem. 4. **`noqa: E741` on variable `l`** -- In `sprints.py` lines 162 and 199, the list comprehension uses `l` as the loop variable in `[l.strip() for l in labels.split(",")]`. This triggers the ambiguous variable name lint and requires `noqa`. A rename to `lbl` or `label` would be cleaner. Non-blocking. ### Code Quality Assessment **Architecture**: Clean modularization. Single `server.py` with `get_sdk()`, `_ok()`, `_error_response()` helpers. Seven tool modules registered via `register_all_tools()` in `tools/__init__.py`. Good separation of concerns. **SDK wrapping**: All 32 tools correctly delegate to SDK methods. Zero raw `httpx` calls remain in the source tree. Verified by grep. **Parameter translations (8 verified correct)**: - `content` -> `html_content` (create_note, update_note) - `project` -> `project_slug` (create_note, update_note) - `tags` CSV string -> `list[str]` (create_note, update_note) - `target_slugs` CSV string -> `list[str]` (update_note_links) - `labels` CSV string -> `list[str]` (add_sprint_item, move_sprint_item) - `items` JSON string -> `list[dict]` (bulk_move_items) - `_UNSET` sentinel handling for `goal`, `start_date`, `end_date` (update_sprint) - `_UNSET` sentinel handling for `labels` (move_sprint_item via update_sprint_item) **Error handling**: Uniform try/except pattern across all tools. `_error_response` correctly handles the `PalEDocsError` hierarchy (base, `NotFoundError`, `ValidationError`, `ServerError`) and generic exceptions. **New tools (7)**: - 6 block tools: `get_note_toc`, `list_blocks`, `get_section`, `update_block`, `create_block`, `delete_block` -- all correctly wrap SDK `BlocksMixin` methods - `delete_sprint` -- correctly calls `get_sdk().delete_sprint(slug)` and returns `_ok(None)` **pyproject.toml**: `httpx` dependency removed, replaced with `pal-e-docs-sdk>=0.1.0`. Forgejo PyPI index correctly configured via `[tool.uv.sources]` and `[[tool.uv.index]]`. **No secrets or credentials committed.** `.env` is in `.gitignore`. ### SOP COMPLIANCE - [x] Branch named after issue (`22-mcp-sdk-rewrite` references issue #22) - [x] No secrets, .env files, or credentials committed - [x] No unnecessary file changes -- scope is tight to the rewrite - [ ] PR body template (## Summary, ## Changes, ## Test Plan, ## Related) -- could not extract PR body from the API response (single-line JSON exceeds read limits), but branch naming and scope are clean - [ ] Tests exist -- no test files found in `tests/`. The Woodpecker CI pipeline only runs ruff lint, no test step. This is consistent with the existing repo state (tests were likely never present), but worth noting. ### VERDICT: APPROVED The rewrite is thorough and correct. All 32 tools properly wrap SDK methods with accurate parameter translations. The `_UNSET` sentinel handling for nullable sprint fields is well-documented in comments. httpx is fully eliminated from the application code. The modular architecture (7 tool modules) is a clear improvement over whatever the previous monolithic structure was. No blockers found.
forgejo_admin deleted branch 22-mcp-sdk-rewrite 2026-03-08 00:13:25 +00:00
Sign in to join this conversation.
No description provided.