Add create_note_from_template MCP tool #28
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo_admin/pal-e-mcp#28
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Lineage
plan-2026-03-09-template-rendering→ Phase 2 (SDK + MCP tool)Repo
forgejo_admin/pal-e-docs-mcpUser Story
As a Claude agent using MCP tools
I want a
create_note_from_templatetoolSo that I can create notes from Jinja2 templates using structured data instead of writing raw HTML
Context
Phase 1 (PR #131, pal-e-docs) shipped
POST /notes/from-template. The SDK methodcreate_note_from_template()is being added in a companion issue onpal-e-docs-sdk. This issue adds the MCP tool that wraps that SDK method.The tool should follow the exact same pattern as the existing
create_notetool intools/notes.py:@mcp.tool()decorator,Annotated[..., Field(description=...)]params, try/except with_ok()/_error_response().API parameters:
template_slug(str, required) — slug of the template note (e.g. "template-plan")slug(str, required) — slug for the new notetitle(str, required) — title for the new notedata(str, required) — JSON string of template variables (MCP tools receive strings, so the tool mustjson.loads()this into a dict before passing to SDK)tags(str | None) — comma-separated tag names (split to list, same ascreate_note)project(str | None) — project slugnote_type(str | None) — note typestatus(str | None) — statusparent_slug(str | None) — parent note slugposition(int | None) — position within parentImportant: The
dataparam is a JSON string at the MCP layer (LLMs pass strings). The tool must parse it withjson.loads()and pass the resulting dict to the SDK. Return 422-style error if JSON is invalid.File Targets
Files the agent should modify:
src/pal_e_docs_mcp/tools/notes.py— addcreate_note_from_templatetool functionFiles the agent should NOT touch:
src/pal_e_docs_mcp/tools/__init__.py— no changes needed (notes module already imported)src/pal_e_docs_mcp/server.py— no changes neededAcceptance Criteria
create_note_from_templatetool is registered and visible to MCP clientstemplate_slug,slug,title,data(JSON string), and optional metadata paramsdatafrom JSON string to dict viajson.loads()tagsstring to list (same pattern ascreate_note)get_sdk().create_note_from_template(...)with correct paramsdatareturns a clear error (not a crash)dataexpects for plan templatesTest Expectations
dataparamcd ~/pal-e-docs-mcp && PALDOCS_BASE_URL=https://paldocs.tail5b443a.ts.net .venv/bin/pytest tests/ -vConstraints
tools/notes.py— same_ok()/_error_response()helpersdatamust be a JSON string param (not a dict) because MCP tool params are strings from the LLMjsonat the top of the filedatashould include keys likevision,repos,phases,decisions, etc.Checklist
Related
plan-2026-03-09-template-rendering— parent planphase-2026-03-09-2-sdk-mcp— phase note in pal-e-docsforgejo_admin/pal-e-docs-sdk(must merge first)PR #31 Review
BLOCKERS
None.
NITS
Missing
is_public/revised_byparams --create_noteexposes both, butcreate_note_from_templatedoes not. The SDK method also omits them, so this is correct at the MCP layer. However, if the SDK adds them later, this tool will need updating. Not blocking -- just flagging for awareness.referenceandpostnote types missing from description -- Thenote_typeField description lists 12 types but the DB has 16. Missing:reference,post,journal,incident. Same gap exists increate_notealready, so this is pre-existing. Consider a follow-up to sync all note_type descriptions across tools.SOP COMPLIANCE
28-add-create-note-from-template-toolreferences issue #28)plan-2026-03-09-template-rendering)Closes #28TestCreateNoteFromTemplate)tools/__init__.pyunchanged (notes module already imported)CODE REVIEW
Tool implementation (
src/pal_e_docs_mcp/tools/notes.py):@mcp.tool()/Annotated[..., Field()]/_ok()/_error_response()pattern established bycreate_note.dataparam isstrat the MCP boundary, parsed viajson.loads()before SDK call. Correct.json.dumps()(not_error_response()) -- correct choice since this is pre-SDK validation, consistent withbulk_move_items.create_note:[t.strip() for t in tags.split(",") if t.strip()] if tags else [].create_note_from_template()signature exactly.try/except Exceptioncatches SDK errors and routes through_error_response().Tests (
tests/test_param_alignment.py):mock_sdkfixture fromconftest.py(which patchesget_sdkinnotes_mod).Lockfile (
uv.lock):>=0.1.0to>=0.2.0to matchpyproject.toml. Legitimate sync.VERDICT: APPROVED