quillink-mcp
# quillink-mcp
An [MCP](https://modelcontextprotocol.io) server exposing **read-only** access to your [Quillink](https://note-taking-app-prod.web.app) notes, 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
```bash
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:
```bash
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-mcp
```
## Authenticate
Two options:
**Option A — OAuth device login (recommended for interactive use):**
```bash
.venv/bin/quillink-mcp login
```
Opens a device code + verification URL; approve it in your browser. 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`, `folders:read`, `tags:read`, `organizations:read`), then set it as an environment variable:
```bash
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):
```json
{
"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:
```json
{
"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` | List notes, filterable by folder, status, tags, pinned |
| `get_note` | Get a single note by id |
| `search_notes` | Full-text search over title + body |
| `get_note_stats` | Note count, storage used, pinned count |
| `get_note_backlinks` | Notes that link to a given note |
| `get_note_graph` | Local link graph (1 or 2 hops) centered on a note |
| `get_global_note_graph` | Whole-account link graph, paginated (Pro plan) |
| `list_note_recipients` | Who a note has been shared with |
| `list_shared_notes` | Notes shared with you by others |
| `list_folders` | List notebooks/folders |
| `get_folder` | Get a single folder by id |
| `list_tags` | List all tags in use |
| `get_organization` | Your Team-plan organization's name, plan tier, seats, alerts |
| `list_organization_members` | 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. Organization tools 404 for a caller who isn't on a Team-plan organization.
## Configuration (environment variables)
| Variable | Purpose |
|---|---|
| `QUILLINK_TOKEN` | A Personal Access Token — bypasses OAuth login entirely |
| `QUILLINK_API_BASE` | Override the API base URL (default: production) |
| `QUILLINK_CLIENT_ID` | Override the OAuth client id used by `login` |
| `QUILLINK_WORKSPACE` | 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`:
```bash
# 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 login
```
Then 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)
```bash
.venv/bin/quillink-mcp login
.venv/bin/quillink-mcp # runs the server on stdio -- an MCP client normally launches this for you
```
TDQS
Scored across 9 tools
Every tool targets a distinct resource and action: notes, folders, tags, stats, sharing, and shared-with-me. There is no overlap in purpose; even list_notes and search_notes are clearly separated by behavior. An agent can unambiguously pick the right tool for a query.
All tools follow a consistent verb_noun pattern in snake_case, e.g., list_notes, get_note, search_notes, list_folders. No mixed conventions or vague verbs appear. The naming is predictable and self-documenting.
Nine tools is a well-scoped set for a note-taking/sharing domain. Each tool covers a distinct read or metadata feature without bloat or redundancy. The count feels appropriate and complete for a read-focused server surface.
The tool surface is entirely read-only: there is no way to create, update, delete, share, or organize notes, folders, or tags. Agents can retrieve information but cannot perform any write workflow, which is a significant gap for a note management service. The lack of any mutating operations will cause failures in most practical tasks.