linkwarden-mcp
No, this is not relevant.
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., "@linkwarden-mcpsearch my bookmarks for articles about AI and show the saved content"
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.
linkwarden-mcp
MCP server for self-hosted Linkwarden: ask your AI about bookmarks, collections, and tags.
What is Linkwarden?
Linkwarden is a self-hosted, open-source bookmark manager. You collect, organize, annotate, and preserve webpages in one place, with full-page archives so content stays readable after the original page disappears. It also supports collaboration and public sharing.
This project wires the Linkwarden HTTP API into the Model Context Protocol so Cursor, Claude, VS Code Copilot, and other MCP hosts can query your live library in natural language.
Useful Linkwarden links:
Related MCP server: ai-bookmark-mcp
What this server does
Default is read-only. You get:
18 read tools - discovery (
list_resources), six core reads (search, get, preserved content, collections, tags, overview), and eleven triage/hygiene workflowsTask tools (opt-in) - intent-shaped writes such as
save_link,smart_save_link,organise_links,create_collection,apply_triage_plan(register when matching write scopes are set)Delete tools (opt-in) -
delete_links,delete_tags,merge_tags,delete_collection(register only under delete scopes; never implied by write)Hard denylist - tokens, session, auth, user admin (except
GET /api/v1/users/me), migration, and whole-instance preservation stay blocked even when writes are on
Transport is stdio. No HTTP server. No global install required if you use uv / uvx.
Branding / icons
Four surfaces (keep them in sync when the mark changes):
stdio hosts (Cursor, Claude Desktop via
mcp.json):serverInfo.iconsfromserver_icons()— embedded data URI fromsrc/linkwarden_mcp/assets/icon.png, plus HTTPS fallbackdocs/icon-512.png(https://raw.githubusercontent.com/flumpiey/linkwarden-mcp/main/docs/icon-512.png).website_urlishttps://linkwarden.app/.Cursor plugin:
.cursor-plugin/plugin.jsonlogo→docs/linkwarden-icon.svg.Claude Desktop Extension:
mcpb/icon.png(packed withnpx @anthropic-ai/mcpb pack mcpb).Claude.ai remote connectors: Claude.ai ignores
serverInfo.iconsand uses the root-domain favicon of the connector URL. If you host a remote MCP later, servedocs/favicon.icoat the registrable domain root (e.g.https://acme.com/favicon.icoforhttps://mcp.acme.com/...).
server.json registry metadata also points its icons[0].src at the same raw docs/icon-512.png URL.
Requirements
Python ≥ 3.10 (pulled in automatically by
uvx)uv (provides
uvx)A reachable Linkwarden instance:
LINKWARDEN_API_URL+LINKWARDEN_API_KEY
Access token
Sign in to your Linkwarden instance (self-hosted or Cloud).
Open Settings → Access Tokens (or go to
/settings/access-tokens).Create a New Access Token, give it a name, and copy the value into
LINKWARDEN_API_KEY.Set
LINKWARDEN_API_URLto your instance base URL (usually without/api/v1; include/api/v1only if your deployment requires it), e.g.https://links.example.comor local Dockerhttp://127.0.0.1:3000.
linkwarden-mcp sends the token as Authorization: Bearer …. API overview: API Introduction.
Copy .env.example to .env for local runs — never commit .env. Prefer the Cursor plugin Configure UI for credentials, or a secret manager in production.
Quick start
Run the PyPI package with uvx:
uvx linkwarden-mcpPaste a client config below, set LINKWARDEN_API_URL / LINKWARDEN_API_KEY, restart the host, then ask: “Find my unread bookmarks about Python” or “What's in my Dev collection?”
From a git clone (dev): uvx --from git+https://github.com/flumpiey/linkwarden-mcp linkwarden-mcp or uv run --directory /path/to/linkwarden-mcp linkwarden-mcp.
Installation
Configs below pull linkwarden-mcp from PyPI. Leave write-scope env vars unset for read-only.
Plugin (Configure UI for URL, key, and scopes): this repo is a Cursor plugin via .cursor-plugin/plugin.json + root mcp.json.
Symlink or copy the clone to
~/.cursor/plugins/local/linkwarden-mcp(Windows:%USERPROFILE%\.cursor\plugins\local\linkwarden-mcp).macOS / Linux:
ln -s /path/to/linkwarden-mcp ~/.cursor/plugins/local/linkwarden-mcpWindows: Cursor does not follow symlinks for local plugins. Use a junction or copy instead:
mklink /J "%USERPROFILE%\.cursor\plugins\local\linkwarden-mcp" "E:\Development\linkwarden-mcp"or:
robocopy "E:\Development\linkwarden-mcp" "%USERPROFILE%\.cursor\plugins\local\linkwarden-mcp" /E
Reload the window.
Open Plugins → Configure on
linkwarden-mcp. Set Linkwarden API URL and Linkwarden API key. Leave Write scopes / Delete scopes empty for read-only, or paste a CSV such aslinks,collections.Confirm the
linkwardenMCP server is enabled under Customize / MCP.
Marketplace listing is a separate submit at cursor.com/marketplace/publish.
Manual mcp.json: project .cursor/mcp.json or user-wide ~/.cursor/mcp.json. Root mcp.json is plugin wiring with ${…} placeholders only — never commit real secrets there.
From PyPI:
{
"mcpServers": {
"linkwarden": {
"type": "stdio",
"command": "uvx",
"args": ["linkwarden-mcp"],
"env": {
"LINKWARDEN_API_URL": "https://links.example.com",
"LINKWARDEN_API_KEY": "your-token"
}
}
}
}Local editable (dev):
{
"mcpServers": {
"linkwarden": {
"type": "stdio",
"command": "uv",
"args": ["run", "--directory", "/path/to/linkwarden-mcp", "linkwarden-mcp"],
"env": {
"LINKWARDEN_API_URL": "https://links.example.com",
"LINKWARDEN_API_KEY": "your-token"
}
}
}
}Optional scoped writes in the env block:
"LINKWARDEN_MCP_WRITE_SCOPES": "links,collections",
"LINKWARDEN_MCP_DELETE_SCOPES": "links"Restart Cursor after saving. Confirm linkwarden under MCP settings.
Desktop Extension (.mcpb): download mcpb.mcpb from GitHub Releases. Use v0.1.5+ (needs uv on PATH). Launch is uv tool run --python 3.12 linkwarden-mcp. Do not put the PyPI package in mcpb/pyproject.toml dependencies — Claude Desktop syncs that file at install and can fail on system Python 3.13.
Open Claude Desktop → Settings → Extensions.
Open Advanced settings → Install Extension…
Select
mcpb.mcpb. Review permissions, enter Linkwarden API URL and Linkwarden API key, then click Install.Leave Write scopes and Delete scopes empty for read-only.
Restart Claude Desktop if tools do not appear.
Build your own bundle from a clone:
npx @anthropic-ai/mcpb pack mcpbOn Windows, double-click often does nothing and dragging the file into chat attaches it to the conversation instead of installing it. Use Install Extension… in Settings.
Manual claude_desktop_config.json fallback: edit the Claude Desktop config, then restart the app.
OS | Path |
macOS |
|
Windows |
|
{
"mcpServers": {
"linkwarden": {
"command": "uvx",
"args": ["linkwarden-mcp"],
"env": {
"LINKWARDEN_API_URL": "https://links.example.com",
"LINKWARDEN_API_KEY": "your-token"
}
}
}
}Local clone:
{
"mcpServers": {
"linkwarden": {
"command": "uv",
"args": ["run", "--directory", "/path/to/linkwarden-mcp", "linkwarden-mcp"],
"env": {
"LINKWARDEN_API_URL": "https://links.example.com",
"LINKWARDEN_API_KEY": "your-token"
}
}
}
}Add via CLI:
claude mcp add linkwarden --env LINKWARDEN_API_URL=https://links.example.com --env LINKWARDEN_API_KEY=your-token -- uvx linkwarden-mcpOr edit ~/.claude.json / project MCP config:
{
"mcpServers": {
"linkwarden": {
"command": "uvx",
"args": ["linkwarden-mcp"],
"env": {
"LINKWARDEN_API_URL": "https://links.example.com",
"LINKWARDEN_API_KEY": "your-token"
}
}
}
}Create .vscode/mcp.json in the project root:
{
"servers": {
"linkwarden": {
"type": "stdio",
"command": "uvx",
"args": ["linkwarden-mcp"],
"env": {
"LINKWARDEN_API_URL": "https://links.example.com",
"LINKWARDEN_API_KEY": "your-token"
}
}
}
}Local editable:
{
"servers": {
"linkwarden": {
"type": "stdio",
"command": "uv",
"args": ["run", "--directory", "/path/to/linkwarden-mcp", "linkwarden-mcp"],
"env": {
"LINKWARDEN_API_URL": "https://links.example.com",
"LINKWARDEN_API_KEY": "your-token"
}
}
}
}Reload the window. Open Copilot Chat and confirm the linkwarden tools are available.
Edit ~/.codeium/windsurf/mcp_config.json (macOS/Linux) or the Windsurf MCP settings UI:
{
"mcpServers": {
"linkwarden": {
"command": "uvx",
"args": ["linkwarden-mcp"],
"env": {
"LINKWARDEN_API_URL": "https://links.example.com",
"LINKWARDEN_API_KEY": "your-token"
}
}
}
}Restart Windsurf after saving.
Add under context_servers in Zed settings.json (Agent Panel → settings also works):
{
"context_servers": {
"linkwarden": {
"command": "uvx",
"args": ["linkwarden-mcp"],
"env": {
"LINKWARDEN_API_URL": "https://links.example.com",
"LINKWARDEN_API_KEY": "your-token"
}
}
}
}Edit the Cline MCP settings file (cline_mcp_settings.json via the Cline MCP UI):
{
"mcpServers": {
"linkwarden": {
"command": "uvx",
"args": ["linkwarden-mcp"],
"env": {
"LINKWARDEN_API_URL": "https://links.example.com",
"LINKWARDEN_API_KEY": "your-token"
}
}
}
}In .continue/config.yaml:
mcpServers:
- name: linkwarden
command: uvx
args:
- linkwarden-mcp
env:
LINKWARDEN_API_URL: https://links.example.com
LINKWARDEN_API_KEY: your-tokenAny host that can spawn a stdio MCP server:
Field | Value |
Command |
|
Args |
|
Env |
|
uvx linkwarden-mcpDev from a clone: uv run --directory /path/to/linkwarden-mcp linkwarden-mcp.
npx only runs npm packages. This is a Python package; use uvx.
Environment
Variable | Required | Notes |
| yes | Base URL (include |
| yes | Access token from Settings → Access Tokens; sent as |
| no | Comma-separated domains for create/update. Empty = no writes. |
| no | Comma-separated domains for delete only. Never implied by WRITE_SCOPES. |
| no | Max records per bulk op (default |
| integration only | Live sandbox URL for |
| integration only | Live sandbox token for |
Valid scopes: links, collections, tags, raw. No wildcards (*, all). raw expands effective scopes to all domain scopes (escape hatch).
Recommended (covers most bookmark workflows without every mutating tool):
"LINKWARDEN_MCP_WRITE_SCOPES": "links,collections",
"LINKWARDEN_MCP_DELETE_SCOPES": "links"Default with no scopes: 18 tools. All three domain scopes in WRITE and DELETE: 31 tools.
Legacy LINKWARDEN_MCP_ALLOW_WRITES / ALLOW_WRITES / LINKWARDEN_MCP_WRITES hard-fail if set. Use the scoped vars instead.
MCP host env (.cursor/mcp.json or Cursor plugin Configure) must match process env / .env or scope behavior drifts.
See .env.example. Never commit .env. Prefer Cursor plugin Configure UI or a secret manager in production.
Write scopes and task tools
When a scope is listed in LINKWARDEN_MCP_WRITE_SCOPES, the server registers task tools for that domain. LINKWARDEN_MCP_DELETE_SCOPES enables delete/merge tools per domain. Call list_resources to inspect read_only, scope lists, and the live boundary string.
Tool | Scopes | Purpose |
| WRITE | Save a URL into a collection (by name) |
| WRITE | Save with optional heuristic collection/tags |
| WRITE | Move or retag multiple links |
| WRITE | Update link fields (read-modify-write) |
| WRITE | Queue preservation (async; not immediate) |
| WRITE | Apply |
| WRITE | Match |
| WRITE | Create a collection (optional parent) |
| WRITE | Apply domain→tag rules; default |
| DELETE | Delete multiple links |
| DELETE | Delete tags by id or name |
| DELETE | Merge tags into a new name (destructive) |
| DELETE | Delete a collection after user chooses delete/move/cancel for its links (elicitation or |
Example with recommended scopes only:
"LINKWARDEN_MCP_WRITE_SCOPES": "links,collections",
"LINKWARDEN_MCP_DELETE_SCOPES": "links"Denylist (always blocked): /api/v1/tokens, /api/v1/session, /api/v1/auth, /api/v1/users/** (except GET /api/v1/users/me), migration, and whole-instance preservation worker actions.
Tools
Read tools
Always registered (18 total).
Tool | Purpose |
| Discovery; reports |
| Search by query, collection, tag, or pin status |
| Full metadata for one link |
| Preserved plain text ( |
| Collections with link counts |
| Tags with link counts |
| Totals, empty collections, unused tags |
| Heuristic collection suggestions for a URL |
| Suggest existing-library tags (never invents names) |
| List unsorted links (default collection: Unorganized) |
| Propose collection/tags for link ids (no writes) |
| Group links with the same normalized URL |
| Consensus collection for a batch of links |
| Find links elsewhere that likely belong |
| Compare two collections for shared domains/tags/URLs |
| Hygiene: empty, near-duplicate names, overcrowded |
| Tags used on similar-domain links |
| One-shot triage: unsorted, duplicates, empty, largest |
Write tools
Registered only when matching scopes are set (see table above). Prefer smart_save_link / triage tools over raw field edits when you are sorting an inbox.
Pattern | Requires | Notes |
Link create/update/organise/archive | WRITE | Includes workflow writers with |
Collection create | WRITE | Optional parent by name |
Domain auto-tag | WRITE | Only existing tag names |
Deletes / tag merge | matching DELETE scope | Destructive; confirm ids first |
Agent Skill
Companion skill: skills/linkwarden-bookmarks/SKILL.md.
The Cursor plugin discovers this skill from skills/. Without the plugin, copy or symlink that folder into your agent skills path. It tells the model to call list_resources first, verify after writes, and which workflow tools to prefer.
Development
uv sync --extra dev
npm install # installs lefthook + commitlint; registers git hooks
uv run linkwarden-mcpOffline tests only (respx). No live Linkwarden required:
uv run ruff check src tests
uv run pytestGit hooks (lefthook)
Hook / command | What it runs |
pre-commit |
|
commit-msg | commitlint Conventional Commits |
| ensure build/twine → ruff → pytest → sdist contents → |
Commit messages must follow Conventional Commits, e.g. feat(api): add delete_links tool.
Run the local publish gate before tagging a release:
npm run pre-publishGitHub Actions matrix: Python 3.10 and 3.12.
Caveats
One process ↔ one
LINKWARDEN_API_URL. Multi-instance routing is out of scope.Multi-user / team disambiguation on a shared instance is unverified. Do not claim multi-tenant support until validated against a live shared library.
Collection/tag suggestions are heuristic and library-local; they do not invent new tag names.
Bulk mutating workflows default to
dry_run=true; setdry_run=falseonly after you review the plan.ChatGPT Apps need a hosted HTTP MCP endpoint. This package is stdio-only.
License
MIT. See LICENSE.
This server cannot be installed
Maintenance
Related MCP Servers
- AlicenseBqualityCmaintenanceMCP Server for accessing Raindrop.io bookmark manager.Last updated3798174MIT
- AlicenseCqualityCmaintenanceA local-first MCP server that turns browser bookmark exports into a searchable knowledge base with classification, merging, full-text indexing, and Chrome integration.Last updated20MIT
- Alicense-qualityBmaintenanceMCP server that fetches web pages, extracts clean markdown (reducing token count), caches results, and provides searchable reading history.Last updatedMIT
- Alicense-qualityCmaintenanceAn MCP server for Linkding bookmarks and web archival, enabling Claude to search, add, tag, archive, and delete bookmarks including archival snapshots.Last updatedMIT
Related MCP Connectors
MCP server for AgentDocs (agentdocs.eu): read, search, write, comment on & share Markdown docs.
Official remote MCP server for Archivist AI TTRPG campaign memory: characters, sessions, and more.
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
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/flumpiey/linkwarden-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server