Phase 8: pal-e-docs SDK + MCP Rewrite + Integration Tests
Goal: Rebuild the MCP tool surface to exploit Postgres search and block-structured content. Eliminate the list→get→get pattern. Minimize tokens per interaction.
Owner: Dev agent
Repo: pal-e-docs-mcp (primary), pal-e-docs (API endpoints)
Depends on: Phase 5 (tsvector), Phase 6 (pgvector), Phase 7 (blocks)
Why
The current MCP is a dumb HTTP passthrough — 26 tools, no search, no granular access. Finding information costs 12+ tool calls and ~15,000 tokens. Updating a note requires sending the entire html_content blob back (~5,000 tokens) even to fix one sentence. This phase cuts that to 2-3 calls and ~800 tokens.
Current Tool Inventory (26 tools)
| Module | Tools | Problem |
|---|---|---|
| notes (5) | list_notes, get_note, create_note, update_note, delete_note, get_note_revisions | list returns no content, get returns ALL content. No middle ground. update requires full html_content replacement. |
| sprints (8) | create/get/list/update sprint, add/move/remove item, get_board, get_backlog, bulk_move | Reasonable. Board queries are efficient. |
| links (2) | get_note_links, update_note_links | Fine. |
| repos (3) | list_repos, create_repo, update_repo | Fine. |
| projects (2) | list_projects, create_project | Fine. |
| tags (1) | list_tags | Fine. |
New Tools
| Tool | Depends On | What It Does | Token Impact |
|---|---|---|---|
| <code>search_notes(query)</code> | Phase 5 | Full-text search via tsvector. Returns matching notes with ts_headline snippets (just the relevant paragraph). | Replaces list→get→get pattern. 12 calls → 1 call. |
| <code>semantic_search(query)</code> | Phase 6 | Vector similarity search via pgvector. Finds conceptually related notes without keyword match. | Finds notes that keyword search misses. |
| <code>get_note_toc(slug)</code> | Phase 7 | Returns just headings + anchor IDs for a note. No content. | ~50 tokens vs ~5,000 for get_note. |
| <code>get_block(slug, anchor_id)</code> | Phase 7 | Returns one section of a note by anchor ID. | ~200 tokens vs ~5,000 for get_note. |
| <code>update_block(slug, anchor_id, content)</code> | Phase 7 | Updates one section without touching the rest. No need to send full document back. | ~100 tokens vs ~5,000 for update_note. |
| <code>create_block(slug, block_type, content, after_anchor)</code> | Phase 7 | Insert a new block at a specific position in a note. | Targeted insertion without full rewrite. |
| <code>delete_block(slug, anchor_id)</code> | Phase 7 | Remove a specific section from a note. | Targeted deletion without full rewrite. |
Modifications to Existing Tools
| Tool | Change |
|---|---|
| <code>get_note</code> | Add optional <code>include_content=false</code> param. Default true for backward compat. When false, returns metadata + TOC only. |
| <code>update_note</code> | Keep working with full html_content for backward compat. Internally, the backend decomposes HTML into blocks and recompiles. |
| <code>list_notes</code> | Add optional <code>query</code> param that uses tsvector search when provided. Graceful upgrade — existing tag/type filters still work. |
Cross-Cutting Optimizations
- Response size limits: Add
max_tokensparam to search tools. Truncate long responses with "... (truncated, use get_block for full section)" - Batch queries:
get_notes(slugs="sop-a,sop-b,sop-c")— fetch multiple note summaries in one call instead of N calls - Context-aware responses: Search results include anchor IDs so the agent can jump directly to the relevant section
Example: Before vs After
Steps
- Add
search_notestool wrappingGET /notes/search?q=...(Phase 5 API) - Add
semantic_searchtool wrappingGET /notes/semantic-search?q=...(Phase 6 API) - Add block tools:
get_note_toc,get_block,update_block,create_block,delete_block(Phase 7 API) - Add
include_contentparam toget_note - Add
queryparam tolist_notes - Add batch endpoint:
get_notes(slugs=...) - Add
max_tokensresponse truncation to search tools - Update session-start hook to use search instead of list→get pattern
- Update CLAUDE.md to document new tool patterns
- Deprecation notice on raw html_content in update_note docstring
Migration Path
All existing tools keep working unchanged. New tools are additive. The old pattern (list→get→update with full HTML) still works but is discouraged. Block tools are the preferred path for reads and writes. Session-start hooks updated last, after tools are proven stable.
Success Metric
Average token cost per knowledge lookup drops from ~15,000 to <1,000. Average token cost per note update drops from ~5,000 to <500.