A Model Context Protocol (MCP) server for Outline (https://www.getoutline.com)
Project description
MCP Outline Server
A Model Context Protocol server for interacting with Outline document management.
Features
- Document operations: Search, read, create, edit, archive documents
- Collections: List, create, manage document hierarchies
- Comments: Add and view threaded comments
- Backlinks: Find documents referencing a specific document
- MCP Resources: Direct content access via URIs (outline://document/{id}, outline://collection/{id}, etc.)
- Automatic rate limiting: Transparent handling of API limits with retry logic
Prerequisites
Before using this MCP server, you need:
- An Outline account (cloud hosted or self-hosted)
- API key from Outline web UI: Settings → API Keys → Create New
- Python 3.10+ (for non-Docker installations)
Getting your API key: Log into Outline → Click your profile → Settings → API Keys → "New API Key". Copy the generated token.
Installation
Using uv (Recommended)
uvx mcp-outline
Using pip
pip install mcp-outline
Using Docker
docker run -e OUTLINE_API_KEY=<your-key> ghcr.io/vortiago/mcp-outline:latest
Or build from source:
docker buildx build -t mcp-outline .
docker run -e OUTLINE_API_KEY=<your-key> mcp-outline
Configuration
| Variable | Required | Default | Notes |
|---|---|---|---|
OUTLINE_API_KEY |
No | - | Fallback API key. If unset, every request must provide a key via the x-outline-api-key header (details) |
OUTLINE_API_URL |
No | https://app.getoutline.com/api |
For self-hosted: https://your-domain/api |
OUTLINE_READ_ONLY |
No | false |
true = disable ALL write operations (details) |
OUTLINE_DISABLE_DELETE |
No | false |
true = disable only delete operations (details) |
OUTLINE_DISABLE_AI_TOOLS |
No | false |
true = disable AI tools (for Outline instances without OpenAI) |
OUTLINE_DYNAMIC_TOOL_LIST |
No | true |
false = disable per-request tool filtering by user role/key scopes (details) |
OUTLINE_MAX_CONNECTIONS |
No | 100 |
Max concurrent connections in pool |
OUTLINE_MAX_KEEPALIVE |
No | 20 |
Max idle connections in pool |
OUTLINE_TIMEOUT |
No | 30.0 |
Read timeout in seconds |
OUTLINE_CONNECT_TIMEOUT |
No | 5.0 |
Connection timeout in seconds |
OUTLINE_WRITE_TIMEOUT |
No | 30.0 |
Write timeout in seconds |
MCP_TRANSPORT |
No | stdio |
Transport mode: stdio (local), sse or streamable-http (remote) |
MCP_HOST |
No | 127.0.0.1 |
Server host. Use 0.0.0.0 in Docker for external connections |
MCP_PORT |
No | 3000 |
HTTP server port (only for sse and streamable-http modes) |
Access Control
Configure server permissions to control what operations are allowed:
Read-Only Mode
Set OUTLINE_READ_ONLY=true to enable viewer-only access. Only search, read, export, and collaboration viewing tools are available. All write operations (create, update, move, archive, delete) are disabled.
Use cases:
- Shared access for team members who should only view content
- Safe integration with AI assistants that should not modify documents
- Public or demo instances where content should be protected
Available tools:
- Search & Discovery:
search_documents,list_collections,get_collection_structure,get_document_id_from_title - Document Reading:
read_document,export_document - Comments:
list_document_comments,get_comment - Collaboration:
get_document_backlinks - Collections:
export_collection,export_all_collections - AI:
ask_ai_about_documents(if not disabled withOUTLINE_DISABLE_AI_TOOLS)
Disable Delete Operations
Set OUTLINE_DISABLE_DELETE=true to allow create and update workflows while preventing accidental data loss. Only delete operations are disabled.
Use cases:
- Production environments where documents should not be deleted
- Protecting against accidental deletions
- Safe content editing workflows
Disabled tools:
delete_document,delete_collectionbatch_delete_documents
Important: OUTLINE_READ_ONLY=true takes precedence over OUTLINE_DISABLE_DELETE. If both are set, the server operates in read-only mode.
Dynamic Tool List
The server filters the tool list per-request based on the authenticated user's Outline role and API key scopes. On each tools/list request, the server calls auth.info and hides write tools for viewer-role users or read-only-scoped API keys. This is enabled by default; set OUTLINE_DYNAMIC_TOOL_LIST=false to disable.
Use cases:
- Multi-user HTTP deployments where different API keys have different permission levels
- Environments where viewer-role users should not see write tools
- API keys with restricted endpoint scopes should only show matching tools
How it works:
- On each
tools/listrequest, the server calls Outline'sauth.infoendpoint - If the user's role is
viewer, write tools are hidden - If the API key has restricted scopes that exclude write endpoints, write tools are hidden
- If
auth.infofails for any reason, all tools are returned (fail-open)
Note: This is a convenience feature, not a security boundary. Even if a tool is hidden from the list, Outline's own API enforces permissions on individual operations.
This feature composes with OUTLINE_READ_ONLY and OUTLINE_DISABLE_DELETE. If OUTLINE_READ_ONLY=true, write tools are never registered regardless of this setting.
Per-Request Authentication
When running in HTTP mode (sse or streamable-http), you can pass the Outline API key per-request via the x-outline-api-key HTTP header instead of (or in addition to) the OUTLINE_API_KEY environment variable.
Priority: Header value takes precedence over the environment variable. If the header is not present, the server falls back to the env var.
Use cases:
- Multi-tenant deployments where different clients use different Outline accounts
- Centralized API key management via a reverse proxy or gateway
- Dynamic key rotation without restarting the server
Example (with a streamable-http server on port 3000):
Start the server:
docker run -p 3000:3000 \
-e OUTLINE_API_KEY=<DEFAULT_KEY> \
-e MCP_TRANSPORT=streamable-http \
ghcr.io/vortiago/mcp-outline:latest
Then connect from your client with a per-request key:
VS Code (.vscode/mcp.json):
{
"servers": {
"mcp-outline": {
"type": "http",
"url": "http://localhost:3000/mcp",
"headers": {
"x-outline-api-key": "<YOUR_KEY>"
}
}
}
}
Claude Code (.mcp.json):
{
"mcpServers": {
"mcp-outline": {
"type": "http",
"url": "http://localhost:3000/mcp",
"headers": {
"x-outline-api-key": "<YOUR_KEY>"
}
}
}
}
Note: The
x-outline-api-keyheader is only available for HTTP transports. Instdiomode, theOUTLINE_API_KEYenvironment variable is the only option.
Adding to Your Client
Prerequisites: Install
uvwithpip install uvor from astral.sh/uv
Add to Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (or %APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"mcp-outline": {
"command": "uvx",
"args": ["mcp-outline"],
"env": {
"OUTLINE_API_KEY": "<YOUR_API_KEY>",
"OUTLINE_API_URL": "<YOUR_OUTLINE_URL>" // Optional
}
}
}
}
Add to Cursor
Go to Settings → MCP and click Add Server:
{
"mcp-outline": {
"command": "uvx",
"args": ["mcp-outline"],
"env": {
"OUTLINE_API_KEY": "<YOUR_API_KEY>",
"OUTLINE_API_URL": "<YOUR_OUTLINE_URL>" // Optional
}
}
}
Add to VS Code
Create a .vscode/mcp.json file in your workspace with the following configuration:
{
"servers": {
"mcp-outline": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-outline"],
"env": {
"OUTLINE_API_KEY": "<YOUR_API_KEY>"
}
}
}
}
For self-hosted Outline instances, add OUTLINE_API_URL to the env object.
Optional: Use input variables for sensitive credentials:
{
"inputs": [
{
"type": "promptString",
"id": "outline-api-key",
"description": "Outline API Key",
"password": true
}
],
"servers": {
"mcp-outline": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-outline"],
"env": {
"OUTLINE_API_KEY": "${input:outline-api-key}"
}
}
}
}
VS Code will automatically discover and load MCP servers from this configuration file. For more details, see the official VS Code MCP documentation.
Add to Cline (VS Code)
In Cline extension settings, add to MCP servers:
{
"mcp-outline": {
"command": "uvx",
"args": ["mcp-outline"],
"env": {
"OUTLINE_API_KEY": "<YOUR_API_KEY>",
"OUTLINE_API_URL": "<YOUR_OUTLINE_URL>" // Optional
}
}
}
Using pip instead of uvx
If you prefer to use pip instead:
pip install mcp-outline
Then in your client config, replace "command": "uvx" with "command": "mcp-outline" and remove the "args" line:
{
"mcp-outline": {
"command": "mcp-outline",
"env": {
"OUTLINE_API_KEY": "<YOUR_API_KEY>",
"OUTLINE_API_URL": "<YOUR_OUTLINE_URL>" // Optional
}
}
}
Docker Deployment (HTTP)
For remote access or Docker containers, use HTTP transport. This runs the MCP server on port 3000:
docker run -p 3000:3000 \
-e OUTLINE_API_KEY=<YOUR_API_KEY> \
-e MCP_TRANSPORT=streamable-http \
ghcr.io/vortiago/mcp-outline:latest
Then connect from client:
{
"mcp-outline": {
"url": "http://localhost:3000/mcp"
}
}
Note: OUTLINE_API_URL should point to where your Outline instance is running, not localhost:3000.
Per-request API key: In HTTP modes, clients can also pass the API key via the x-outline-api-key header instead of setting it as an env var. See Per-Request Authentication.
Tools
Note: Tool availability depends on your Access Control settings. Some tools are disabled in read-only mode or when delete operations are restricted.
Search & Discovery
search_documents(query, collection_id?, limit?, offset?)- Search documents by keywords with paginationlist_collections()- List all collectionsget_collection_structure(collection_id)- Get document hierarchy within a collectionget_document_id_from_title(query, collection_id?)- Find document ID by title search
Document Reading
read_document(document_id)- Get document contentexport_document(document_id)- Export document as markdown
Document Management
create_document(title, collection_id, text?, parent_document_id?, publish?)- Create new documentupdate_document(document_id, title?, text?, append?)- Update document (append mode available)move_document(document_id, collection_id?, parent_document_id?)- Move document to different collection or parent
Document Lifecycle
archive_document(document_id)- Archive documentunarchive_document(document_id)- Restore document from archivedelete_document(document_id, permanent?)- Delete document (or move to trash)restore_document(document_id)- Restore document from trashlist_archived_documents()- List all archived documentslist_trash()- List all documents in trash
Comments & Collaboration
add_comment(document_id, text, parent_comment_id?)- Add comment to document (supports threaded replies)list_document_comments(document_id, include_anchor_text?, limit?, offset?)- View document comments with paginationget_comment(comment_id, include_anchor_text?)- Get specific comment detailsget_document_backlinks(document_id)- Find documents that link to this document
Collection Management
create_collection(name, description?, color?)- Create new collectionupdate_collection(collection_id, name?, description?, color?)- Update collection propertiesdelete_collection(collection_id)- Delete collectionexport_collection(collection_id, format?)- Export collection (default: outline-markdown)export_all_collections(format?)- Export all collections
Batch Operations
batch_create_documents(documents)- Create multiple documents at oncebatch_update_documents(updates)- Update multiple documents at oncebatch_move_documents(document_ids, collection_id?, parent_document_id?)- Move multiple documentsbatch_archive_documents(document_ids)- Archive multiple documentsbatch_delete_documents(document_ids, permanent?)- Delete multiple documents
AI-Powered
ask_ai_about_documents(question, collection_id?, document_id?)- Ask natural language questions about your documents
Resources
outline://collection/{id}- Collection metadata (name, description, color, document count)outline://collection/{id}/tree- Hierarchical document tree structureoutline://collection/{id}/documents- Flat list of documents in collectionoutline://document/{id}- Full document content (markdown)outline://document/{id}/backlinks- Documents that link to this document
Development
Quick Start with Self-Hosted Outline
# Generate configuration
cp config/outline.env.example config/outline.env
openssl rand -hex 32 > /tmp/secret_key && openssl rand -hex 32 > /tmp/utils_secret
# Update config/outline.env with generated secrets
# Start all services
docker compose up -d
# Create API key: http://localhost:3030 → Settings → API Keys
# Add to .env: OUTLINE_API_KEY=<token>
Setup
git clone https://github.com/Vortiago/mcp-outline.git
cd mcp-outline
uv sync --extra dev
Testing
# Run unit tests
uv run poe test-unit
# Run integration tests (starts real MCP server via stdio)
uv run poe test-integration
# Format code
uv run ruff format .
# Type check
uv run pyright src/
# Lint
uv run ruff check .
E2E Tests
E2E tests run against a real Outline instance via Docker Compose. The fixtures manage the stack lifecycle automatically — just run:
uv run poe test-e2e
The test fixtures automatically:
- Start the isolated Docker Compose stack (
mcp-outline-e2eproject, ports 3031/5557) - Authenticate via OIDC/Dex to create an API key
- Spawn the MCP server via stdio for each test
- Tear down the stack on exit
To start the E2E stack manually (e.g. for debugging):
cp config/outline.env.example config/outline.env
DEX_HOST_PORT=5557 OUTLINE_HOST_PORT=3031 \
docker compose -p mcp-outline-e2e -f docker-compose.yml -f docker-compose.e2e.yml up -d outline
See .github/workflows/e2e.yml for CI configuration.
Running Locally
uv run mcp-outline
Testing with MCP Inspector
Use the MCP Inspector to test the server tools visually via an interactive UI.
For local development (with stdio):
npx @modelcontextprotocol/inspector -e OUTLINE_API_KEY=<your-key> -e OUTLINE_API_URL=<your-url> uv run python -m mcp_outline
For Docker Compose (with HTTP):
npx @modelcontextprotocol/inspector http://localhost:3000
Architecture Notes
Rate Limiting: Automatically handled via header tracking (RateLimit-Remaining, RateLimit-Reset) with exponential backoff retry (up to 3 attempts). No configuration needed.
Transport Modes:
stdio(default): Direct process communicationsse: HTTP Server-Sent Events (use for web clients)streamable-http: Streamable HTTP transport
Connection Pooling: Shared httpx connection pool across instances (configurable: OUTLINE_MAX_CONNECTIONS=100, OUTLINE_MAX_KEEPALIVE=20)
Troubleshooting
Server not connecting?
Check your API credentials:
# Test your API key
curl -H "Authorization: Bearer YOUR_API_KEY" YOUR_OUTLINE_URL/api/auth.info
Common issues:
- Verify
OUTLINE_API_KEYis set correctly in your MCP client configuration - Check
OUTLINE_API_URLpoints to your Outline instance (default:https://app.getoutline.com/api) - For self-hosted Outline, ensure the URL ends with
/api - Verify your API key hasn't expired or been revoked
Tools not appearing in client?
- Read-only mode enabled? Check if
OUTLINE_READ_ONLY=trueis disabling write tools - Delete operations disabled? Check if
OUTLINE_DISABLE_DELETE=trueis hiding delete tools - AI tools missing? Check if
OUTLINE_DISABLE_AI_TOOLS=trueis disabling AI features - Dynamic filtering active? Tools are filtered by user role/key scopes by default (set
OUTLINE_DYNAMIC_TOOL_LIST=falseto disable) - Restart your MCP client after changing environment variables
API rate limiting errors?
The server automatically handles rate limiting with retry logic. If you see persistent rate limit errors:
- Reduce concurrent operations
- Check if multiple clients are using the same API key
- Contact Outline support if limits are too restrictive for your use case
Docker container issues?
Container won't start:
- Ensure
OUTLINE_API_KEYis set:docker run -e OUTLINE_API_KEY=your_key ... - Check logs:
docker logs <container-id>
Can't connect from client:
- Use
0.0.0.0for MCP_HOST:-e MCP_HOST=0.0.0.0 - Verify port mapping:
-p 3000:3000 - Check transport mode:
-e MCP_TRANSPORT=streamable-http
Need more help?
Contributing
Contributions welcome! See CONTRIBUTING.md for setup instructions.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Built with MCP Python SDK
- Uses Outline API for document management
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_outline-1.6.0.tar.gz.
File metadata
- Download URL: mcp_outline-1.6.0.tar.gz
- Upload date:
- Size: 819.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e55846b3c02a249145d62b7e0ab044e9e4dcdd498df20daaf6a9970a265d58de
|
|
| MD5 |
0f5fd6fee4a0d0b94e61f410992de1ea
|
|
| BLAKE2b-256 |
e30a54dab08517967b6383db2cde7530cf0c66261901bd04cad2f1af0a305653
|
Provenance
The following attestation bundles were made for mcp_outline-1.6.0.tar.gz:
Publisher:
publish-pypi.yml on Vortiago/mcp-outline
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_outline-1.6.0.tar.gz -
Subject digest:
e55846b3c02a249145d62b7e0ab044e9e4dcdd498df20daaf6a9970a265d58de - Sigstore transparency entry: 1018001164
- Sigstore integration time:
-
Permalink:
Vortiago/mcp-outline@ec35de47230169dcc890df832cb5e19711f1b659 -
Branch / Tag:
refs/tags/v1.6.0 - Owner: https://github.com/Vortiago
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@ec35de47230169dcc890df832cb5e19711f1b659 -
Trigger Event:
push
-
Statement type:
File details
Details for the file mcp_outline-1.6.0-py3-none-any.whl.
File metadata
- Download URL: mcp_outline-1.6.0-py3-none-any.whl
- Upload date:
- Size: 54.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
03f17042dbe60016545934488469ac1f42eae45de68e59eac48d032283dac198
|
|
| MD5 |
5fa81c082eee18c46992d85af4d3034e
|
|
| BLAKE2b-256 |
443629fd5c2dcf2cd4c6971b46ee7e48ef9ffe02a86dc95800470da9003deb3a
|
Provenance
The following attestation bundles were made for mcp_outline-1.6.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on Vortiago/mcp-outline
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_outline-1.6.0-py3-none-any.whl -
Subject digest:
03f17042dbe60016545934488469ac1f42eae45de68e59eac48d032283dac198 - Sigstore transparency entry: 1018001192
- Sigstore integration time:
-
Permalink:
Vortiago/mcp-outline@ec35de47230169dcc890df832cb5e19711f1b659 -
Branch / Tag:
refs/tags/v1.6.0 - Owner: https://github.com/Vortiago
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@ec35de47230169dcc890df832cb5e19711f1b659 -
Trigger Event:
push
-
Statement type: