Craft mcp
Use when reading, searching, creating, or editing Craft documents, tasks, daily notes, or collections through MCP; it applies safe escaping and linking conventions.From its SKILL.md
npx -y skills add phntm7/skills --skill craft-mcpAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.6 KB, as published. Nobody here has run it
Craft MCP (usage)
Craft is a notes app exposed through two MCP tools:
craft_read— read/search/list (connection info,documents list,blocks get,search,collections ...,tasks list).craft_write— create/edit (blocks add|update|move|delete,tasks ...,collections ...,comments add,whiteboards ...).
Each tool takes a single command string (CLI-style, e.g. blocks get <id> --format markdown). Batch independent commands with ;. Discover any command with <entity> <action> --help.
Model: everything is a block. A document is a page block identified by a rootBlockId; its content is a tree of nested blocks, each with a stable id. You address content by block id.
Discovery (do this before reading/writing)
connection info— space id, timezone. Grab the spaceId here (needed to build internal links).documents list— the reliable way to enumerate documents (<rootBlockId> Title). Prefer it.search <query>— may return "No matches found" even when the document exists (depends on indexing/visibility settings). Never conclude a doc is absent from an empty search; confirm withdocuments list.documents resolve-link <craft-url>— turn a Craft share/deep link into arootBlockId. The documentId in a URL is NOT the rootBlockId — always resolve a URL before passing an id toblockscommands.
Reading
blocks get <rootBlockId> [--format markdown|json] [--depth N] [--cursor <c>]--format markdownto read content;--format jsonto get block ids and types (required for targeted edits).- Large docs paginate — follow
nextCursor.
blocks get --date today|YYYY-MM-DD— a daily note. Errors if that daily note does not exist yet. Create it by adding a block with--date.
Writing
- Create a document with
documents create --title <title> [--folder <folderId>] [--destination unsorted|templates](many at once with--documents '<json array>'). It returns arootBlockIdfor an empty doc — fill it withblocks add --id <rootBlockId>. File it in a folder at creation (--folder) or relocate later withdocuments move.- Alternative — a nested page block inside an existing doc or daily note:
blocks add --id <parentRootBlockId> --json {"type":"page","markdown":"Title"}(a page block's markdown is its title; it appears indocuments list). documents move --document <rootBlockId> (--folder <id> | --destination unsorted|templates)relocates;documents delete --document <rootBlockId>trashes it (restore by moving it out of trash).
- Alternative — a nested page block inside an existing doc or daily note:
blocks addtargets (choose one):--id <blockId>→ into a document/page root;--position start|end(default end).--date <date>→ into a daily note.--siblingId <blockId>→ relative to an existing block;--position before|after.- Content via
--markdown <md>or--json <block|array>. Prefer one--jsonarray to insert many blocks (faster than many calls).
blocks update --id <blockId> --markdown <md>— replaces that block. If the markdown produces multiple blocks, the first replaces the target and the rest are inserted after it.blocks move --id <blockId> --targetId <parent> [--position start|end];blocks delete --id <blockId>(bulk:--ids <id1,id2,...>, or a CSV to--id).- Get target block ids first with
blocks get --format json.
CRITICAL caveats (read before writing content)
- Markdown strips backslash escapes → silent corruption. A
\"written inside content collapses to". Inside a code block this breaks shell/TOML/JSON that relies on escaped inner quotes (e.g.-w \"$(cat)\"becomes-w "$(cat)"", invalid). Do not write content that needs backslash-escaped quotes. Rewrite to an escape-free equivalent: drop unnecessary quotes (-w $(cat)), or use a TOML literal string (single quotes, no escaping). Always read the block back after writing code/quote-heavy content and fix if mangled. - Use real newlines, not literal
\n. A single\nstays as the two characters; use actual line breaks.\n\n(real blank line) separates paragraphs. Never double-escape newlines. - rootBlockId ≠ URL documentId. Resolve Craft URLs with
documents resolve-linkfirst. searchis unreliable for existence. Usedocuments listto confirm a doc exists.- Daily notes may not exist.
blocks get --date todayerrors when today's note is absent; create by adding with--date. - Internal links: write a markdown link whose URL is
craftdocs://open?spaceId=<spaceId>&blockId=<blockId>(spaceId fromconnection info). Craft converts it to a workingblock://...link on read. - Command-string quoting: the
commandis parsed shell-style. Wrap a multi-line--markdown/--jsonvalue in single quotes, and avoid apostrophes inside it (a'closes the quote). Double quotes,$, and backticks are safe inside single quotes. When content is quote-heavy, prefer--json(JSON payload) over hand-quoting. - Code fence languages: common ones like
bashrender as highlighted code; some (e.g.toml) fall back to a plain code block. Cosmetic only — content is preserved. - Markdown extensions:
<callout>text</callout>,+ Toggle title(children must be indented beneath it — flush-left lines are not children), and> quote. - Bare
<tag>tokens in plain text break the write (Unexpected HTML token/Expected inline markdown, got html). Any well-formed<word>in prose or a bullet —<model>,<tool>,<file>— is parsed as HTML and rejected. Wrap it in a backtick code span (`<model>`) or rephrase (e.g.MODEL). Safe as-is: angle brackets inside code spans/fences, spaced comparisons (a < b), and the whitelisted<callout>…</callout>extension. This bites hardest in table cells and headings (always inline-parsed).
Tasks and collections
tasks list [--scope active|upcoming|inbox|logbook|document|all];tasks add --markdown <text> [--state todo|done|canceled] [--schedule <date>] [--deadline <date>];tasks update,tasks delete.collectionsare database tables:collections list|schema|items-get|views-list(read) andcollections create|rename|items-add|items-update|items-delete|views-*(write). A collection lives inside a document (--document <rootBlockId>).
Workflow / output contract
- Read before write (
documents list/blocks get), verify after write by reading the affected block back — especially for code blocks and quoted content. - When done, report the
rootBlockId/blockIdtouched and acraftdocs://open?...link.
Do / Don't
Do:
- Use
documents listto find docs anddocuments resolve-linkfor URLs. - Create docs with
documents create(use--folderto file them); read back to confirm rendering. - Keep code-block content free of backslash-escaped quotes; use escape-free equivalents.
- Prefer a single
--jsonarray when adding many blocks.
Don't:
- Don't treat an empty
searchresult as proof a document is absent. - Don't pass a URL's documentId to
blockscommands — resolve it first. - Don't write literal
\n; use real newlines. - Don't put bare
<tag>tokens in plain markdown text — wrap them in backticks or rephrase.
Reference
- For the full command reference, block JSON types, batching, and escaping-workaround patterns with examples, read references/command-reference.md.