Minimal remote MCP server template: Hono + streamable HTTP, token auth, Zod-validated tools, Postgres via Drizzle
Strong foundation with clear naming, complete schemas, and good descriptions. All four tools follow verb_noun convention (list_*, read_*, write_*, list_*). Zod schemas are present and properly typed for all tools. Descriptions are substantive (50-200 chars range, well within baseline). Error handling uses safe() wrapper to convert exceptions to structured MCP errors. Main gaps: output schemas are not formally documented (only inferred from code), parameter descriptions could be more prescriptive about constraints, and no tool annotations (readOnlyHint/destructiveHint) despite clear risk stratification in code.
List the snapshot history of one note (most recent first).
List all notes (id, title, updatedAt). Call this first to orient yourself.
Read one note in full by id.
WRITE TOOL — requires prior explicit user approval in chat. Create a note (omit noteId) or update one (pass noteId). Updates that change content snapshot the previous version first.
Output schemas not formally documented. Tool descriptions state what is returned (e.g., 'List all notes (id, title, updatedAt)') but no structured schema definition is visible in tool registration. LLMs cannot reliably parse response structure without explicit schema.
Tool annotations missing. Code clearly stratifies tools by risk (READ_ONLY vs WRITE) and write_note includes explicit policy prefix, but no readOnlyHint/destructiveHint/idempotentHint annotations are registered with the MCP server. Clients cannot programmatically detect risk level.
Parameter descriptions lack constraint details. 'noteId' is described as 'UUID of the note to read' but does not state format or validation behavior. 'limit' in list_note_versions states range (1-50, default 10) in description but this is enforced only in Zod schema, not visible to LLM.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 68 | 2026-07-28+ | v2 |
write_note parameter dependencies underdocumented. Description states 'omit noteId to create' but does not explicitly warn that title is required for creation and optional for updates. LLMs may pass incomplete payloads.
Error messages are minimal. fail() returns only error text (e.g., 'NOTE_NOT_FOUND'). No recovery guidance (e.g., 'Try list_notes() to find valid IDs'). Agents cannot self-correct without extra reasoning.