{"name":"personal-wiki","version":"0.2.0","protocol":"2024-11-05","transport":"http+json-rpc","instructions":"Personal wiki + bookmark dashboard, backed by Cloudflare D1 (source of truth) and AI Search (hybrid semantic + keyword index).\n\nData model\n- pages: flat namespace, addressed by URL-safe slug. Markdown body. Optionally filed in a page folder (folder_id). Pages can link to each other with [[wiki-style]] links — use slugified target slugs (e.g. [[my-other-page]] or [[my-other-page|display label]]). Page slug \"home\" is the landing page and cannot be deleted.\n- bookmarks: each has url, title, description, favicon_url, alternative_url (e.g. self-hosted mirror), notes (markdown), folder_id, sort_order, and tags (lowercase, hyphenated).\n- folders: pages and bookmarks each have their own SEPARATE nested folder tree (a page folder and a bookmark folder never share an id). A folder has a name and an optional parent_id (null = top level / root). Items reference a folder by folder_id, so renaming a folder never re-files anything. Use list_folders to see a tree, create_folder/rename_folder/move_folder/delete_folder to manage one. Deleting a folder also deletes every sub-folder and every page/bookmark inside it.\n\nWhen to use which tool\n- For natural-language lookup (\"what did I write about X?\"), use search_pages or search_bookmarks. They run hybrid search across the AI Search index and fall back to LIKE if AI Search is unavailable.\n- For \"show me everything created/updated since Y\" or \"what did I edit last week?\", use list_pages_by_date or list_bookmarks_by_date. These bypass AI Search and query D1 directly with date filtering and sorting.\n- For \"give me one specific page\", use read_page with its slug.\n- For writing: create_page / edit_page / delete_page for pages; add_bookmark / edit_bookmark for bookmarks. add_bookmark fetches the title/description/favicon from the URL and asks Workers AI for tag suggestions when those fields are not supplied.\n- For batch bookmark intake (importing a list of URLs), use add_bookmarks — single MCP call, up to 50 items, parallel fetches, per-item success/failure reporting.\n- To improve a bookmark whose initial metadata or tags were poor, call refresh_bookmark with its id. By default it re-fetches the live page and re-runs AI tagging; toggle refetch_metadata or regenerate_tags off to do only one. If the live fetch fails, existing fields are preserved.\n\nConventions\n- Slugs are kebab-case ASCII; if you pass a non-conforming slug it will be slugified.\n- All write tools keep the AI Search index in sync automatically.\n- Limits are clamped to safe values (typically 1–50).\n- Timestamps in returned records are unix seconds since epoch (UTC). Date inputs to filter tools accept either unix seconds (number/string of digits) or ISO-8601 (\"2026-05-08\" or \"2026-05-08T12:00:00Z\"); bare dates resolve to UTC midnight.","tools":[{"name":"search_pages","description":"Hybrid semantic + keyword search across wiki pages, returning the most relevant pages with title, slug, folder_id, an excerpt, and the AI Search relevance score. Use this for natural-language questions about page content. Falls back to title/content LIKE search when AI Search is unavailable."},{"name":"read_page","description":"Fetch one wiki page by slug. Returns the full row: slug, title, folder_id, content (markdown), created_at, updated_at."},{"name":"create_page","description":"Create a new wiki page. The slug is derived from the title if not supplied. Markdown body supports [[wiki-style]] links to other pages by slug. Errors if slug already exists."},{"name":"edit_page","description":"Patch an existing wiki page. Identify the page with slug; pass any subset of title/content/folder_id to update those fields. Pass new_slug to rename."},{"name":"delete_page","description":"Permanently delete a wiki page by slug. Also removes it from the AI Search index and cascades to any shared links. The \"home\" page cannot be deleted."},{"name":"list_pages_by_date","description":"List wiki pages filtered/sorted by created_at or updated_at. Useful for \"what did I work on last week?\" or \"show me all pages created this month\". Hits D1 directly — does not require AI Search."},{"name":"list_folders","description":"List the folder tree for pages or bookmarks. Returns a nested tree of { id, name, parent_id, children }. Pages and bookmarks have completely separate trees."},{"name":"create_folder","description":"Create a folder in the page or bookmark tree. Pass parent_id to nest it under an existing folder of the same type; omit for a top-level folder."},{"name":"rename_folder","description":"Rename a folder. Does not re-file the items inside it (they reference it by id)."},{"name":"move_folder","description":"Re-parent a folder. parent_id null/0 moves it to the top level. Rejects moving a folder into itself or one of its descendants."},{"name":"delete_folder","description":"Delete a folder AND its entire subtree, including every page/bookmark filed anywhere inside it. Deleted pages keep a final history snapshot and can be recovered from the wiki; bookmarks are gone. Irreversible from here — confirm with the user first."},{"name":"search_bookmarks","description":"Find bookmarks by free-text query (hybrid search across title/description/notes/url), or by tag, or list most-recent. Returns full bookmark records including tags."},{"name":"list_bookmarks_by_date","description":"List bookmarks filtered/sorted by created_at or updated_at. Optional folder/tag filters. Hits D1 directly — does not require AI Search."},{"name":"add_bookmark","description":"Add a single bookmark from a URL. If title/description aren't given, the page is fetched and parsed for them. If tags aren't given, Workers AI suggests 3–5 short topic tags from the title/URL/description. Use add_bookmarks for batches."},{"name":"add_bookmarks","description":"Bulk-add up to 50 bookmarks in one call. Each item has the same shape as add_bookmark; per-item failures (bad URL, fetch error, etc.) do not stop the others. Returns { count, ok, failed, results: [{ ok, …, error? }] }. Site fetches and AI tagging run in parallel."},{"name":"refresh_bookmark","description":"Re-fetch a bookmark's site metadata (title/description/favicon) and/or re-run AI tag suggestion against an existing record. Use this when the original URL was added with poor metadata or no tags. If the live fetch fails, existing fields are preserved (never clobbered with hostname fallbacks). When regenerate_tags=true, the entire tag set is replaced."},{"name":"edit_bookmark","description":"Patch a bookmark by id. Pass any subset of fields. Pass tags as an array to replace the full tag set."},{"name":"upload_attachment","description":"Upload a file (image, PDF, etc.) to R2-backed attachment storage. Returns the attachment id, public URL, and a markdown snippet to embed/link to it from a wiki page. For images, an AI vision description is auto-generated unless you supply one. The returned `markdown` is the standard syntax (`![alt](url)` for images, `[name](url)` otherwise) — paste it into a page via edit_page."},{"name":"list_attachments","description":"List all uploaded attachments newest-first. Each record includes id, filename, content_type, size, description, url, and ready-to-embed markdown."},{"name":"search_attachments","description":"Hybrid semantic + keyword search across attachment filenames and AI-generated descriptions. Returns matching attachments with id, filename, content_type, description, url, and markdown."},{"name":"get_attachment","description":"Fetch one attachment by id. Returns the full record plus the embed url and markdown snippet."},{"name":"delete_attachment","description":"Permanently delete an attachment: removes the R2 object, D1 row, and AI Search index entry. Pages that referenced it will show broken links."},{"name":"get_attachment_content","description":"Download the binary content of an attachment from R2 storage. For images, returns an image content block that the model can view directly. For all other file types, returns a JSON object with a data_base64 field containing the base64-encoded bytes. Use get_attachment when you only need metadata."}]}