joplin-mcp
The joplin-mcp server integrates with Joplin's Web Clipper API to enable programmatic interaction with your notes and notebooks. It requires Joplin Desktop to be running with its Web Clipper service enabled.
Search notes (
search_notes): Full-text search across Joplin notes with a configurable result limit (default 20), returning matching note titles and IDs.Get note (
get_note): Fetch the complete content of a specific note by its ID.Create note (
create_note): Add a new note with a title and body to a specified notebook (bynotebook_id).Update note (
update_note): Modify an existing note's title and/or body by ID; only provided fields are changed.List notebooks (
list_notebooks): Retrieve all notebooks with their IDs, useful for finding the correctnotebook_idwhen creating notes.Access control: Restrict operations to specific notebooks (by ID or name, or
*for all) with configurable read/write permissions.
Provides tools to search, get, create, and update notes, as well as list notebooks in Joplin via its local Web Clipper REST API.
Click on "Install 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., "@joplin-mcplist my notebooks"
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.
joplin-mcp
A minimal MCP server for Joplin, built with FastMCP. Talks to Joplin's local Web Clipper REST API.
Contents
Related MCP server: Joplin MCP Server
Tools
Tool | Description |
| Full-text search |
| Fetch a note's full content |
| Create a new note |
| Edit an existing note |
| Delete a note (moves it to Joplin's trash) |
| Browse a notebook's notes without a search query |
| List notebooks, to get a |
Setup
In Joplin Desktop: Tools > Options > Web Clipper, enable the service, copy the auth token shown there.
Install uv if you don't have it.
Copy
config.example.jsontoconfig.jsonat the repo root (already gitignored, so it won't be committed) and fill in:{ "token": "paste-your-token-here", "host": "localhost", "port": "41184", "notebooks": [ {"id": "notebook-id-or-name", "access": "write"}, {"id": "another-notebook-id-or-name", "access": "read"} ] }host/portare optional and default tolocalhost/41184. See Access control below for thenotebookslist.
Running it
No manual pip install needed — uv run resolves and caches dependencies
on first run.
uv run --directory /path/to/joplin-mcp joplin-mcp-serverThis looks for config.json in the working directory (which --directory
sets to the repo). To keep the config file somewhere else, set
JOPLIN_CONFIG to its path:
JOPLIN_CONFIG=/path/to/config.json uv run --directory /path/to/joplin-mcp joplin-mcp-serverWiring into an MCP client
Both approaches below point at the repo directory, which is where
config.json lives — one source of truth for secrets and access config.
Claude Code
claude mcp add joplin -s user -- uv run --directory /path/to/joplin-mcp joplin-mcp-server-s user registers it at user scope, so it's available in every Claude
Code session, not just this repo. Verify with claude mcp get joplin;
remove with claude mcp remove joplin -s user.
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json
(macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows), adding:
{
"mcpServers": {
"joplin": {
"command": "uv",
"args": ["run", "--directory", "/path/to/joplin-mcp", "joplin-mcp-server"]
}
}
}Fully quit and restart Claude Desktop afterward — it only picks up config
changes on launch. This is the schema documented at
support.claude.com
and modelcontextprotocol.io.
Some Claude Desktop builds manage MCP servers through a Settings UI
(Extensions/Connectors) instead of this file directly — check there first
if the file on disk doesn't have an mcpServers key already.
Using uvx instead (no local checkout needed)
uv run --directory ... (above) operates on a project already cloned to
disk — it needs a working copy of this repo, its pyproject.toml, and its
lockfile at that path. uvx (short for uv tool run) is different: it
fetches the package straight from git into uv's own cache and runs it in
an ephemeral environment, so the machine running the MCP client doesn't
need a local clone at all — just a config.json and JOPLIN_CONFIG
pointing at it.
uvx --from git+https://github.com/johnsarie27/joplin-mcp@<ref> joplin-mcp-server<ref> can be a branch (e.g. main) or a commit SHA. A branch ref is
re-resolved to whatever the current tip commit is on every launch (a
network round-trip, and a fresh dependency resolve/build whenever that tip
changes) — convenient while iterating, but it means the running server can
change without you touching either client config. Pinning <ref> to a
specific commit SHA, per the SHA-pinning convention, freezes both the code
and its resolved dependency versions until you deliberately bump the pin —
prefer this once the repo's been stable through some real usage.
Since there's no local checkout in this mode, set JOPLIN_CONFIG to an
absolute path so config.json can still be found. Swap the command/args
in whichever client config above to uvx/--from git+... instead of
uv/run --directory ..., and add the JOPLIN_CONFIG env var:
claude mcp add joplin -s user -e JOPLIN_CONFIG=/path/to/config.json -- uvx --from git+https://github.com/johnsarie27/joplin-mcp@<ref> joplin-mcp-server{
"mcpServers": {
"joplin": {
"command": "uvx",
"args": ["--from", "git+https://github.com/johnsarie27/joplin-mcp@<ref>", "joplin-mcp-server"],
"env": {
"JOPLIN_CONFIG": "/path/to/config.json"
}
}
}
}Release tags (v<major>.<minor>.<patch>) are also valid refs — see
Releasing in CONTRIBUTING.md for how they're cut. Use
one as <ref> when pinning uvx --from git+...@<ref> above.
Tip: you can run the server standalone and call each tool manually before wiring it into a client — see Testing changes in CONTRIBUTING.md.
Access control
search_notes, get_note, create_note, update_note, delete_note, and
list_notes_in_notebook are scoped by the notebooks list in
config.json. Each entry is:
{"id": "notebook-id-or-name", "access": "read"}access is "read" (default if omitted) or "write" (implies read).
search_notes/get_note/list_notes_in_notebook require read;
create_note/update_note/delete_note require write. This is
fail-closed: if notebooks is missing, empty, or none of its entries match
a real notebook, all six tools refuse to operate. list_notebooks is
unaffected since it only returns notebook metadata, not note content, and
doubles as the way to find the ids/names to list in config.json in the
first place.
Name matching is case-insensitive (Tech, tech, and TECH are
equivalent) and resolved against the live notebook list on each call, so
a rename takes effect immediately. Since Joplin doesn't require notebook
names to be unique (nested notebooks can share a title), a name that
matches more than one notebook grants that access level to all of them —
use the notebook id instead (from list_notebooks) if you need to scope
to just one of several same-named notebooks.
Use {"id": "*", "access": "read"} or {"id": "*", "access": "write"} to
grant that access level to all notebooks. This is a deliberate opt-in,
distinct from leaving notebooks empty.
Out-of-scope access raises a NotebookAccessError with a message naming
the notebook, distinct from a JoplinError (an actual Joplin API failure).
Notes on this build
Requires Joplin Desktop running with the Web Clipper service enabled (i.e. Joplin itself must be open — this doesn't run Joplin headlessly).
host/portinconfig.jsonoverride the defaults (localhost/41184) if needed.Errors from the Joplin API surface as
JoplinErrorwith the raw status/body — check these first if a tool call fails.
References
Related projects
Contributing
See CONTRIBUTING.md for development setup, testing, and the release process.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/johnsarie27/joplin-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server