Caliu
Read and write your Caliu notes from any MCP client.
What it can do
- Search Notes: Search and filter notes. With `query`, runs full-text search over title and content, ranked by relevance (title matches weighted highest). It matches whole words with light English stemm
- Get Note: Get a single note by ID, with full content, tags, backlinks (notes that link to it via [[wiki links]]), and any reminders on it, in one response. Works for active and archived notes; a trash
- Create Note: Create a new note from markdown. The first line becomes the title. Tags are auto-detected from #hashtags in the content (including hierarchical #parent/child) — no separate tag tools need
What data it sees
Do you need an account
No: the server works without sign-in
Read and write your Caliu notes from any MCP client.
Caliu is a local-first markdown notes app for web, iPhone, iPad and Mac. It works fully offline, and an account only adds sync.
14 tools across notes, tags, reminders and attachments: search, create, update, archive, set reminders, upload and read files. Tags are derived from #hashtags in the markdown and [[Note Title]] links resolve automatically, so agents just write markdown instead of calling tag-attachment tools.
Connect with no API key: add https://api.caliuapp.com/mcp as a remote server and sign in to Caliu when prompted (OAuth 2.1 with dynamic client registration). Or run it locally with npx @caliu-notes/mcp and a CALIU_API_KEY.
How to connect
How to connect Caliu to Claude
The server address to paste into Claude settings:
https://caliuapp.run.tools
- Open Claude (claude.ai or the desktop app).
- Go to Settings → Connectors.
- Click Add custom connector.
- Paste the server address copied below into Remote MCP server URL and click Add.
- In a chat, click + → Connectors and switch the new connector on.
Custom connectors are available on Free, Pro, Max, Team and Enterprise plans (Free is limited to one). On Team and Enterprise an organization Owner adds the connector first under Organization settings → Connectors.
Authorization
After you click Add, a sign-in window for the service opens. Sign in with your own account and approve access. Claude never sees your password.
How to connect Caliu to ChatGPT
The server address to paste into ChatGPT settings:
https://caliuapp.run.tools
- Open ChatGPT in a browser (chatgpt.com). A Plus, Pro, Business, Enterprise or Edu plan is required.
- Turn on developer mode once: Settings → Apps → Advanced settings → Developer mode.
- Open Settings → Connectors and click Create.
- Fill in the form: Name (anything), Description (one line about what the service does), MCP server URL (copy it below).
- Under Authentication choose OAuth if the service requires sign-in, otherwise None. Click Create.
- In a new chat open + → Apps/Connectors and enable the connector.
OpenAI has renamed this section before (Connectors → Apps/Plugins). If the label differs, search settings for "developer mode". On Business/Enterprise workspaces an admin must allow custom connectors first.
Authorization
On first use ChatGPT opens the service's sign-in window. Sign in and approve access.
How to connect Caliu to Cursor
The server address to paste into Cursor settings:
https://caliuapp.run.tools
Fastest: click Open in Cursor below and confirm the prompt.
Manually:
- In Cursor open Settings → Cursor Settings → MCP and click Add new global MCP server.
- Paste the JSON copied below into
~/.cursor/mcp.json(per project:.cursor/mcp.jsonin the repo root). - Save the file. The server appears in the MCP list; authorize it there if asked.
Authorization
If the service needs sign-in, an authorize button appears next to the server in the MCP list.
Server tool list (14)
Raw names from tools/list. Only developers need these.
| search_notes | Search and filter notes. With `query`, runs full-text search over title and content, ranked by relevance (title matches weighted highest). It matches whole words with light English stemming (plurals and verb forms), OR-combined so a note matching more of the query words ranks higher; it is NOT substring or prefix search, so prefer a few distinctive keywords over a full sentence. `query` cannot be combined with `tag` or `untagged` (the text search wins and those filters are ignored); `pinned` still applies. Without `query`, lists notes filtered by the other params, most-recently-updated first. Use `linksTo` to find notes that reference a given note via [[wiki links]]. `includeTrashed: true` lists trashed notes and `includeArchived: true` lists archived notes; both are plain listings that ignore `query` and all other filters. Pagination via `cursor`. Results carry note metadata and a short `contentPreview` (not the full body or tags) — call get_note to read a note's content and tags. |
| get_note | Get a single note by ID, with full content, tags, backlinks (notes that link to it via [[wiki links]]), and any reminders on it, in one response. Works for active and archived notes; a trashed note returns not-found (restore it first). |
| create_note | Create a new note from markdown. The first line becomes the title. Tags are auto-detected from #hashtags in the content (including hierarchical #parent/child) — no separate tag tools needed. Reuse the user's existing tags: call list_tags first and match an existing handle exactly (same casing and hierarchy), e.g. write #todo rather than coining #todos or #task when #todo already exists. Only invent a new hashtag when no existing tag fits; if you're unsure which tag the user wants, ask them instead of guessing. Link to another note by writing [[Note Title]] with the exact title of an existing note — the server resolves it into a real note link (clickable in the apps, counted in backlinks). Titles that don't match an existing note stay as plain text. |
| update_note | Update a note. Only provided fields change. When `content` is provided, tags are re-derived from #hashtags in the new content (a tag is removed if its hashtag is gone). Reuse the user's existing tags: call list_tags first and match an existing handle exactly rather than coining a near-duplicate; only invent a new hashtag when none fits, and ask the user if you're unsure. Link to another note by writing [[Note Title]] with the exact title of an existing note — the server resolves it into a real note link. When rewriting content that already contains [[id|Title]] links, preserve them verbatim. |
| delete_note | Soft-delete a note (move to trash). Restorable with restore_note. Hard deletion is intentionally not exposed via MCP. |
| restore_note | Restore a soft-deleted note from trash. |
| archive_note | Archive a note. Archived notes are hidden from all listings (and tag/folder views) but are never auto-removed and keep their tags. Reverse with unarchive_note. Distinct from delete_note (trash, auto-purged after 30 days). |
| unarchive_note | Restore a note from the archive back to the active list. |
| list_tags | List all tags with note counts. Each tag includes a `handle` — the full hierarchical path as you'd write it in note content (e.g. `#work/project/subtask` for nested tags, `#work` for a root tag). Call this before writing #hashtags in create_note or update_note so you reuse the user's existing tags (matching handle and casing exactly) instead of scattering near-duplicates like #todo vs #todos vs #task. |
| set_reminder | Create or update a reminder on a note. Pass `reminderId` to update an existing one (e.g. snooze by setting a new `triggerAt`); omit it to create a new one. Updating changes only the fields you pass: omitting `recurrence` keeps the existing recurrence, it does not clear it. A note can have multiple reminders. Reminder IDs come from get_note (its `reminders` array) or the response of a previous set_reminder. |
| delete_reminder | Remove a reminder from a note. |
| get_current_user | Get the currently authenticated user's profile (id, email, name). |
| upload_file | Upload a file of any type (image, PDF, audio, archive, ...) to the user's Caliu storage so it can be embedded in notes. Returns the stored attachment plus a ready-to-use `markdown` snippet — put that snippet into note content via create_note or update_note to make it appear in the note: images render inline, other files render as a downloadable file chip (you may change the link/alt text, but keep the URL exactly as returned). Images are recompressed server-side, so the returned filename/type may differ from the input. Uploading alone does not attach the file to any note. Best for files up to a few MB; base64 inflates payloads by ~33%. |
| get_attachment | Download an attachment from the user's Caliu storage so you can view or process it. Accepts the attachment id or the full download URL found in note markdown (https://.../attachments/<id>/download). Images come back as viewable image content, text-based files (txt, md, csv, json, svg, ...) as text, audio as audio content, and other binaries as a base64 resource. Refuses files over 10MB. |