Skip to main content

A Model Context Protocol (MCP) server for Outline (https://www.getoutline.com)

Project description

MCP Outline Server

PyPI Python 3.10+ License: MIT CI Docker

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 with OUTLINE_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_collection
  • batch_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:

  1. On each tools/list request, the server calls Outline's auth.info endpoint
  2. If the user's role is viewer, write tools are hidden
  3. If the API key has restricted scopes that exclude write endpoints, write tools are hidden
  4. If auth.info fails 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-key header is only available for HTTP transports. In stdio mode, the OUTLINE_API_KEY environment variable is the only option.

Adding to Your Client

Prerequisites: Install uv with pip install uv or 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 pagination
  • list_collections() - List all collections
  • get_collection_structure(collection_id) - Get document hierarchy within a collection
  • get_document_id_from_title(query, collection_id?) - Find document ID by title search

Document Reading

  • read_document(document_id) - Get document content
  • export_document(document_id) - Export document as markdown

Document Management

  • create_document(title, collection_id, text?, parent_document_id?, publish?) - Create new document
  • update_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 document
  • unarchive_document(document_id) - Restore document from archive
  • delete_document(document_id, permanent?) - Delete document (or move to trash)
  • restore_document(document_id) - Restore document from trash
  • list_archived_documents() - List all archived documents
  • list_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 pagination
  • get_comment(comment_id, include_anchor_text?) - Get specific comment details
  • get_document_backlinks(document_id) - Find documents that link to this document

Collection Management

  • create_collection(name, description?, color?) - Create new collection
  • update_collection(collection_id, name?, description?, color?) - Update collection properties
  • delete_collection(collection_id) - Delete collection
  • export_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 once
  • batch_update_documents(updates) - Update multiple documents at once
  • batch_move_documents(document_ids, collection_id?, parent_document_id?) - Move multiple documents
  • batch_archive_documents(document_ids) - Archive multiple documents
  • batch_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 structure
  • outline://collection/{id}/documents - Flat list of documents in collection
  • outline://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-e2e project, 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

MCP Inspector

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 communication
  • sse: 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_KEY is set correctly in your MCP client configuration
  • Check OUTLINE_API_URL points 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=true is disabling write tools
  • Delete operations disabled? Check if OUTLINE_DISABLE_DELETE=true is hiding delete tools
  • AI tools missing? Check if OUTLINE_DISABLE_AI_TOOLS=true is disabling AI features
  • Dynamic filtering active? Tools are filtered by user role/key scopes by default (set OUTLINE_DYNAMIC_TOOL_LIST=false to 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_KEY is set: docker run -e OUTLINE_API_KEY=your_key ...
  • Check logs: docker logs <container-id>

Can't connect from client:

  • Use 0.0.0.0 for 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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_outline-1.6.0.tar.gz (819.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_outline-1.6.0-py3-none-any.whl (54.5 kB view details)

Uploaded Python 3

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

Hashes for mcp_outline-1.6.0.tar.gz
Algorithm Hash digest
SHA256 e55846b3c02a249145d62b7e0ab044e9e4dcdd498df20daaf6a9970a265d58de
MD5 0f5fd6fee4a0d0b94e61f410992de1ea
BLAKE2b-256 e30a54dab08517967b6383db2cde7530cf0c66261901bd04cad2f1af0a305653

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcp_outline-1.6.0.tar.gz:

Publisher: publish-pypi.yml on Vortiago/mcp-outline

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for mcp_outline-1.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 03f17042dbe60016545934488469ac1f42eae45de68e59eac48d032283dac198
MD5 5fa81c082eee18c46992d85af4d3034e
BLAKE2b-256 443629fd5c2dcf2cd4c6971b46ee7e48ef9ffe02a86dc95800470da9003deb3a

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page