A local-first daemon MCP server for knowledge management, task tracking, and agent integration with memory, notes, projects, and AI-powered gardening/research capabilities
Seamless demonstrates good definition quality with strong descriptions and mostly complete schemas. The 6 tools are well-named with action verbs (capture_, favorite_set, gardener_* variants) and descriptions range from 140-450 characters, exceeding the 194-char baseline average for A-tier tools. Input schemas are present and properly typed. However, several critical gaps prevent a higher score: (1) No return/output schemas are documented in the source, violating the 'document output schema' pattern. (2) Tool annotations (readOnlyHint/destructiveHint/idempotentHint) are absent despite MCP 2026-07-28 supporting them, important for agents to understand which calls are safe to retry. (3) The 'gardener_request' and 'gardener_split' tools lack clear parameter constraints (e.g., valid project slugs, guidance on instruction format). (4) Error recovery guidance is missing from descriptions despite these tools having clear failure modes (e.g., invalid project slug, ambiguous reorganization request). Overall, this is solidly B-range work with descriptions that guide LLM selection well, but incomplete output documentation and missing safety annotations hold it back from B+ territory.
Fetch a web page (SSRF-guarded: private/loopback addresses are rejected) and save its readable content as a note. Returns the new note's id.
Star or unstar an item. Favorites sort first in the console, are pinned into session briefings (memories), and get a mild recall rank boost. For memories and notes the flag is stored in the file's frontmatter; starring never bumps an item's updated time.
Resolve a gardener proposal. action=apply carries out the effect (archive -> retire the memory; merge -> supersede the older by the newer; consolidate -> write a unified memory superseding its sources; digest -> save the summary as a note; reproject -> move the memory to another project; rekind -> reclassify the memory's kind in place; split -> create the child/shared projects, link the family, parent the children, retire the source; memory_wanted -> open a task to write the missing memory; tool_error -> open a task to fix the recurring error; merge_plans -> retag a stranded captured plan's notes onto the plan that holds the steps and settle the capture as merged). Rejecting has two strengths: action=dismiss discards this proposal and the evidence behind it, so a pattern that keeps recurring is raised again later; action=hide blocks the pattern permanently, so no recurrence re-raises it. Prefer dismiss unless the suggestion is wrong in principle rather than wrong for now. Both are reversible by the owner from the console.
List pending gardener proposals (merge/consolidate duplicate memories, archive stale memories, write a monthly session digest, reproject a memory to another project, rekind a memory to a different kind, set up a project split, abandon a never-approved captured plan, fold a stranded captured plan into the composition that carries its steps, write a memory agents keep searching for in vain, or fix an error agents keep hitting). Review, then apply, dismiss or hide each with gardener_apply. Read-only.
No output/return schemas documented for any tool. LLMs cannot plan downstream calls or extract required fields without knowing what structure is returned.
Missing tool annotations (readOnlyHint, destructiveHint, idempotentHint) in all tool definitions. These are critical for agents to understand retry safety and state mutation. MCP 2026-07-28 spec supports these natively.
gardener_request and gardener_split lack error recovery guidance in descriptions. If a project slug is invalid or the request is ambiguous, the description should hint at recovery (e.g., 'call project_list to see available projects', 'ask for clarification').
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | B | 71 | 2026-07-28+ | v2 |
The natural-language entry point for REORGANIZING memory. Describe the change in plain language and it returns reviewable pending proposals -- fold duplicates together ("these two memories are duplicates -- keep the newer"), retire stale memories ("archive anything about the old port 8080"), synthesize several into one ("combine the three auth-flow notes"), move a mis-filed memory to another EXISTING project ("the iOS DFU memory belongs in arctop-ios"), or reclassify a memory's kind ("the wordmark memory is a convention, not a constraint"). Use this whenever the user describes how they want their knowledge organized; if the intended change is ambiguous, ask them a clarifying question first. It NEVER mutates memories: it only creates pending proposals -- review with gardener_proposals, resolve with gardener_apply. If the request is to split one project into NEW child projects, it recognizes that and returns guidance (splitSource) pointing you at gardener_split instead. Needs an LLM chat client.
Plan a project SPLIT: divide one existing project into two or more NEW child projects, keeping cross-platform memories in a shared parent (e.g. split arctop-app into arctop-ios + arctop-android with shared arctop-mobile-apps). Use this when the user wants to break one project into several -- gardener_request points you here (via splitSource) when it detects that intent. It NEVER creates a project or moves a memory: it only creates reviewable pending proposals -- one 'split' setup proposal plus one 'reproject' per memory, all under plan 'split-<source>'. Review with gardener_proposals, then apply each with gardener_apply (or retarget a memory first in the console). Needs an LLM chat client and a known source project slug (see project_list).
Parameter 'instruction' in gardener_split is documented as 'optional guidance' but lacks examples or constraints on what constitutes valid guidance. Should specify format/structure to help LLM formulate requests.
gardener_apply's 'action' enum is documented inline but lacks a default value declaration. The description says 'action=apply (default)' but this should be enforced via schema, not description text.