quillink-mcp
A read-only MCP server that gives AI clients browse, search, graph, and export access to your Quillink notes, folders, tags, attachments, sharing info, and Team organization.
Notes: list notes filtered by folder, status, tags (any/all), pinned; fetch one by id; full-text search titles/bodies.
Stats: note counts, storage used, pinned count, creation histogram.
Links & graphs: backlinks, related-note suggestions, local 1–2 hop link graph, paginated whole-account graph, and community/centrality analysis (Pro-gated).
Export: single note as standalone Markdown, or bulk export of active notes as NDJSON or concatenated Markdown for backups/scripting.
Attachments: list a note's attachments and get a short-lived signed download URL.
Sharing: see who a note is shared with, and list notes shared with you.
Organization: list folders and tags (with note/canvas counts), get folder by id, view Team-plan org details and members (plain members see only themselves).
Safety limits: no create/edit/delete tools; locked-note bodies withheld; Vault/Zero-Knowledge content never readable.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@quillink-mcp search my notes for API design"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
quillink-mcp
An MCP server exposing read-only access to your Quillink notes, tasks, canvases, folders, and tags to AI tools like Claude Desktop, Claude Code, and other MCP-compatible clients.
Requires a Pro Quillink plan (API Access is a Pro-only feature).
Not published to PyPI -- build and run it locally from source.
Build
git clone https://github.com/dagistankaradeniz/gcp-note-taking-mcp.git
cd gcp-note-taking-mcp
python3 -m venv .venv
.venv/bin/pip install -e .This installs the quillink-mcp command into .venv/bin/. Note the full
path to that binary (e.g. /Users/you/gcp-note-taking-mcp/.venv/bin/quillink-mcp)
-- MCP clients launch it directly, not through an activated shell, so
they need the absolute path.
macOS: if you clone the repo under ~/Documents, ~/Desktop, or
~/Downloads, Claude Desktop may fail to launch the server with
"Server disconnected" -- macOS privacy protection (TCC) blocks its child
processes from reading those folders. Either grant Claude Desktop access
to the folder (System Settings -> Privacy & Security -> Files and
Folders), or build the venv outside the protected folders:
python3 -m venv ~/.local/share/quillink-mcp-venv
~/.local/share/quillink-mcp-venv/bin/pip install /path/to/gcp-note-taking-mcp
# then point your MCP client at ~/.local/share/quillink-mcp-venv/bin/quillink-mcpRelated MCP server: notes-mcp
Authenticate
Two options:
Option A — OAuth device login (recommended for interactive use):
.venv/bin/quillink-mcp loginOpens the sign-in page in your browser with the code filled in; approve it there. Over SSH, or with --no-browser / QUILLINK_NO_BROWSER=1, it only prints the link and code. The token is stored in your OS keyring (or ~/.config/quillink-mcp/credential as a fallback).
Requires a registered OAuth client id for this tool -- if login fails with an "Unknown client_id" error, set QUILLINK_CLIENT_ID to a registered client id (see Configuration below), or use a PAT instead.
Option B — Personal Access Token:
Create one in Quillink under Settings → Developer → Tokens (scopes: notes:read, tasks:read, canvases:read, folders:read, tags:read, organizations:read), then set it as an environment variable:
export QUILLINK_TOKEN=qlk_pat_...QUILLINK_TOKEN always takes priority over a stored OAuth login.
Use with Claude Desktop
Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"quillink": {
"command": "/absolute/path/to/gcp-note-taking-mcp/.venv/bin/quillink-mcp"
}
}
}If using a PAT instead of login, pass it as an env var in the config:
{
"mcpServers": {
"quillink": {
"command": "/absolute/path/to/gcp-note-taking-mcp/.venv/bin/quillink-mcp",
"env": { "QUILLINK_TOKEN": "qlk_pat_..." }
}
}
}Restart Claude Desktop after editing the config.
Use with other MCP clients
Any client that can launch a local stdio MCP server works the same way: point it at the absolute path to .venv/bin/quillink-mcp (with QUILLINK_TOKEN set, or after running quillink-mcp login once so the credential is already stored). This includes Claude Code (claude mcp add quillink -- /absolute/path/to/.venv/bin/quillink-mcp) and any OpenAI-compatible agent runtime that supports the MCP stdio transport.
Tools
All read-only — this server cannot create, edit, or delete anything.
Tool | Description |
| List notes, filterable by folder, status, tags (any, or all with |
| Get a single note by id |
| Full-text search over title + body, optionally within tags |
| Note count, storage used, pinned count |
| Notes that link to a given note |
| Tag/link-similarity "you might want to link these" suggestions for a note (Pro plan) |
| Local link graph (1 or 2 hops) centered on a note |
| Whole-account link graph, paginated (Pro plan) |
| Community detection + centrality ranking over the whole-account graph (Pro plan) |
| A single note as a standalone Markdown file |
| Bulk export of active notes as NDJSON or concatenated Markdown, for backups/scripting |
| List a note's file attachments |
| A short-lived signed URL to download one attachment's file bytes |
| Who a note has been shared with |
| Notes shared with you by others |
| List tasks, by status, due-date window, or shared with you |
| Get a single task by id |
| List canvases (without their elements), filterable like notes |
| Get a single canvas with its elements as JSON |
| List folders |
| Get a single folder by id |
| List all tags in use |
| Every tag with how many notes and canvases carry it |
| Your Team-plan organization's name, plan tier, seats, alerts |
| Your organization's members (plain members see only their own entry) |
Vault notes are never accessible here — they're end-to-end encrypted client-side, so no server (including this one) can read them. Zero-Knowledge accounts can't use this server: their content is encrypted on their own devices, so every content tool answers "not available for Zero-Knowledge accounts" (use the app or the quillink CLI). Organization tools 404 for a caller who isn't on a Team-plan organization.
Security notes
Read-only. The server only requests read scopes and has no tools that create, change or delete anything.
Note content is untrusted input. A note -- especially one shared with you or imported -- can contain text written to steer an AI assistant ("prompt injection"), e.g. asking it to send your notes somewhere through another tool. The server tells clients to treat note content as data, not instructions, but that's a request to the model, not a guarantee. Keep tool approval on in your MCP client when other tools (email, web, file write) are enabled alongside this one.
HTTPS only.
QUILLINK_API_BASEmust behttps://(plainhttp://is allowed forlocalhostonly).Token storage. The OS keychain, or a
0600file under~/.config/quillink-mcp/when no keychain is available.
Configuration (environment variables)
Variable | Purpose |
| A Personal Access Token — bypasses OAuth login entirely |
| Override the API base URL (default: production) |
| Override the OAuth client id used by |
| Use a named workspace's api-base/client-id/credential instead (see below) |
Workspaces (multiple environments/accounts)
This server is a single long-running process, launched once per MCP client config entry — there's no per-call "switch workspace" the way the CLI has --workspace. To use several environments or accounts, register one server entry per workspace, each pinned to a different QUILLINK_WORKSPACE:
# One-time: define the workspaces with the CLI (gcp-note-taking-cli)
quillink workspace add staging --api-base https://staging.example.com
quillink workspace login staging
# Point this server at it
QUILLINK_WORKSPACE=staging .venv/bin/quillink-mcp loginThen in your MCP client config, add a second server entry (e.g. quillink-staging) alongside your existing one, with "env": {"QUILLINK_WORKSPACE": "staging"} — both can be active at once.
Workspace metadata (api_base/client_id, no secrets) lives in ~/.config/quillink/workspaces.json — the same file gcp-note-taking-cli's quillink workspace add/use manages, so a workspace defined once via the CLI is immediately visible here. This server keeps its own separate keyring entry per workspace for the actual token, though, so you still need to login (or set QUILLINK_TOKEN) once per workspace here too. QUILLINK_TOKEN/QUILLINK_API_BASE/QUILLINK_CLIENT_ID set directly always take precedence over QUILLINK_WORKSPACE.
Running it directly (for testing)
.venv/bin/quillink-mcp login
.venv/bin/quillink-mcp # runs the server on stdio -- an MCP client normally launches this for youAvailable Tools
21 toolsexport_noteB
A single note rendered as a standalone Markdown file (title as an H1, followed by the body). A locked note's body can't be exported without its password -- returns just the title with a note explaining why. Fails with 403/404 same as get_note.
Inputs: note_id (required). Returns: result
export_notesA
Bulk export of the caller's active notes -- for backups/scripting, not paged browsing (use list_notes for that). format="ndjson" (default) returns one full note object per line; format="markdown" returns one "# Title" block per note, concatenated into a single document. Locked notes are included with their body withheld, same as list_notes.
Inputs: tags, limit, format, folder_id, +1 more. Returns: result
get_attachment_download_urlA
A short-lived signed URL to download one attachment's file bytes directly (not through this tool) -- expires_in seconds from now. A ZK/ Vault/lock-encrypted note's attachment is still opaque ciphertext at that URL; there's no decrypt path here, same as a locked note's body.
Inputs: note_id (required), attachment_id (required). Returns: object
get_folderA
Get a single folder by id.
Inputs: folder_id (required). Returns: object
get_global_note_graphA
Whole-account link graph, paginated: nodes and edges across every note that has at least one link (in or out) or is locked. Pass the response's next_cursor back in to fetch the next page; None means the graph is exhausted. Requires a Pro plan, same gate as the web app's Global Graph feature.
Inputs: limit, cursor. Returns: object
get_graph_analysisA
Community detection + importance ranking over the caller's whole account graph. community_algo: "louvain" (default), "label_propagation", "greedy_modularity", or "connected_components". centrality_algo: "pagerank" (default), "betweenness", "degree", or "closeness". Requires a Pro plan, same gate as get_global_note_graph. On a very large graph the response may note that a cheaper approximation was substituted for the exact algorithm requested.
Inputs: community_algo, centrality_algo. Returns: object
get_noteA
Get a single note by id. Fails with 403 if it isn't owned by the caller, 404 if it doesn't exist.
Inputs: note_id (required). Returns: object
get_note_backlinksA
List notes that link to note_id, each with an id/title/snippet. Fails with 403 if note_id isn't owned by the caller, 404 if it doesn't exist.
Inputs: note_id (required). Returns: object
get_note_graphA
Local link graph centered on note_id: nodes (id/title/locked) and edges (source -> target) for its direct links and backlinks. hops=1 is direct neighbors only; hops=2 also expands each neighbor's own neighbors one level further.
Inputs: note_id (required), hops. Returns: object
get_note_statsA
Aggregate stats: total active notes, total storage bytes used, pinned-note count, and a created-at histogram by day.
Inputs: no named parameters. Returns: object
get_organizationA
Get the caller's Team-plan organization: name, plan tier, seat allocations, member count, and any active alerts. 404s if the caller doesn't belong to a Team-plan organization.
Inputs: no named parameters. Returns: object
list_attachmentsA
List a note's file attachments. Fails with 403 if note_id isn't owned by the caller, 404 if it doesn't exist.
Inputs: note_id (required). Returns: object
list_foldersC
List the caller's notebooks/folders.
Inputs: include_trashed. Returns: object
list_note_recipientsA
List who a note (owned by the caller) has been shared with.
Inputs: note_id (required). Returns: object
list_notesA
List the caller's notes. folder_id="" lists notes with no folder; omit it to list across all folders. status is "active" or "trashed". tags filters to notes with any of them, or every one of them with tag_match="all". Locked notes are included but their body is withheld (null).
Inputs: tags, limit, pinned, status, +3 more. Returns: object
list_organization_membersA
List the caller's organization's members. A plain member sees only their own entry -- other members' emails/names/roles are admin/owner- only information, scoped the same way the web app scopes it.
Inputs: no named parameters. Returns: result
list_tag_countsA
Every tag with how many active notes and canvases carry it, most-used first.
Inputs: no named parameters. Returns: result
list_tagsA
List every tag used across the caller's active notes.
Inputs: no named parameters. Returns: result
search_notesA
Full-text search over the caller's active notes' titles and body
text, optionally only within notes carrying any of tags (every one
with tag_match="all"). Locked notes only match on title (their body is
never substring-matched, so a search hit can't leak hidden content).
Inputs: q (required), tags, limit, tag_match. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 21 tools
Most tools are clearly scoped by resource and operation, but the graph family (get_note_backlinks, get_related_notes, get_note_graph, get_global_note_graph, get_graph_analysis) and the tag pair (list_tags vs list_tag_counts) have overlapping boundaries that could cause misselection without careful reading. The descriptions mostly disambiguate them, so only minor confusion remains.
All names use snake_case with a consistent verb_noun shape (get_*, list_*, search_*, export_*). No mixed conventions or vague verbs; prefixes consistently signal the operation type.
21 tools is on the heavy side for a note-app integration, especially with separate local/global graph tools and overlapping tag-listing variants. The count is not extreme, but consolidation would improve scoping.
Read coverage is broad across notes, folders, tags, sharing, graphs, export, attachments, and organization data. However, there are no create, update, delete, move, or share operations, leaving common note lifecycle workflows as dead ends.
Maintenance
Related MCP Connectors
Markdown-based note-taking with a hosted MCP server. Your notes serve you and your AI.
OAuth-protected, read-only-by-default MCP server for provenance-labeled QuillCaddie project memory.
Google Keep-style notes app with an MCP server for AI agents to read/write notes.
Read-only MCP server for ClassQuill, a tutoring-business-management platform.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceMCP server that provides standardized tools for querying and retrieving notes from Joplin personal knowledge manager through its API, enabling AI assistants to access and reference personal notes contextually.9-
- AlicenseAqualityDmaintenanceMCP server for a personal notes/knowledge base that enables AI assistants to create, search, and retrieve notes using natural language. It exposes tools like create_note and search_notes, resources for each note, and a summarize_tag prompt.6MIT
- FlicenseNot gradedqualityDmaintenanceMCP server for reading and searching Markdown notes in any directory, such as an Obsidian vault. It integrates with MCP clients like Claude Desktop to access note contents.914 npm-
- AlicenseNot gradedqualityCmaintenanceRemote MCP server for Obsidian vaults, enabling secure access to markdown notes from Claude clients without the Obsidian desktop app. Provides tools for searching, reading, listing recent notes, resolving daily notes, and creating/appending notes via HTTPS.7 npmMIT