Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ register_all(mcp)
| |- document_organization.register_tools() # If not OUTLINE_READ_ONLY
| |- batch_operations.register_tools() # If not OUTLINE_READ_ONLY
|- resources.register(mcp) # Always
install_dynamic_tool_list(mcp) # Unless OUTLINE_DYNAMIC_TOOL_LIST=false
install_dynamic_tool_list(mcp) # If OUTLINE_DYNAMIC_TOOL_LIST=true
```

### MCP Resources (`outline://` URI scheme)
Expand Down Expand Up @@ -82,7 +82,7 @@ install_dynamic_tool_list(mcp) # Unless OUTLINE_DYNAMIC_TOOL_L
- Comments: create, list, get
- Attachments: get_redirect_url, fetch_content
- AI: answer questions
- Auth: auth_info (user/team verification)
- Auth: probe_endpoint (endpoint connectivity verification)

**Connection Pooling**:
- Uses httpx with class-level connection pool
Expand All @@ -104,7 +104,7 @@ install_dynamic_tool_list(mcp) # Unless OUTLINE_DYNAMIC_TOOL_L

### Common Utilities (`features/documents/common.py`)

- `get_outline_client()` - Async function that creates an OutlineClient and verifies connectivity via `auth_info()`. Checks for a per-request API key from the `x-outline-api-key` HTTP header first (SSE/streamable-http), then falls back to `OUTLINE_API_KEY` env var.
- `get_outline_client()` - Async function that creates an OutlineClient. Checks for a per-request API key from the `x-outline-api-key` HTTP header first (SSE/streamable-http), then falls back to `OUTLINE_API_KEY` env var.
- `_get_header_api_key()` - Reads the `x-outline-api-key` header from the MCP SDK's `request_ctx` ContextVar. Returns `None` for stdio or when header is absent.
- `OutlineClientError` - Exception class for client-related errors

Expand Down Expand Up @@ -318,7 +318,7 @@ OUTLINE_WRITE_TIMEOUT=30.0 # Write timeout in seconds
OUTLINE_DISABLE_AI_TOOLS=true # Disable AI tools
OUTLINE_READ_ONLY=true # Disable all write operations
OUTLINE_DISABLE_DELETE=true # Disable delete operations only
OUTLINE_DYNAMIC_TOOL_LIST=false # Disable per-request tool filtering (on by default)
OUTLINE_DYNAMIC_TOOL_LIST=true # Enable per-request tool filtering (off by default)

# MCP server (optional)
MCP_TRANSPORT=stdio # Transport: stdio, sse, streamable-http
Expand All @@ -329,7 +329,7 @@ MCP_PORT=3000 # Server port
**Access Control Notes**:
- `OUTLINE_READ_ONLY`: Blocks entire write modules at registration (content, lifecycle, organization, batch_operations)
- `OUTLINE_DISABLE_DELETE`: Conditionally registers delete tools within document_lifecycle and collection_tools
- `OUTLINE_DYNAMIC_TOOL_LIST`: On by default. Filters tools per-request based on user role from `auth.info` and API key scopes. Fail-open: if auth check fails, all tools are shown. Set to `false` to disable.
- `OUTLINE_DYNAMIC_TOOL_LIST`: Off by default. Filters tools per-request based on endpoint probing and API key scopes. Fail-open: if endpoint probe fails, all tools are shown. Set to `true` to enable.
- Read-only mode takes precedence: If both are set, server operates in read-only mode

### Critical Requirements
Expand Down
1 change: 1 addition & 0 deletions docker-compose.e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ services:
UTILS_SECRET: "1111111111111111111111111111111111111111111111111111111111111111"
URL: "http://localhost:3031"
OIDC_AUTH_URI: "http://localhost:5557/dex/auth"
RATE_LIMITER_ENABLED: "false"

mcp-outline:
profiles: ["disabled"]
5 changes: 4 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,12 @@ services:
ports:
- ${MCP_PORT:-3000}:${MCP_PORT:-3000}
environment:
- OUTLINE_API_KEY=${OUTLINE_API_KEY:-}
# OUTLINE_API_KEY is optional — set it or use per-request
# x-outline-api-key header instead.
# - OUTLINE_API_KEY=${OUTLINE_API_KEY:-}
- OUTLINE_API_URL=http://outline:3030/api
- OUTLINE_DISABLE_AI_TOOLS=true
- OUTLINE_DYNAMIC_TOOL_LIST=true
- MCP_PORT=${MCP_PORT:-3000}
depends_on:
- outline
Expand Down
7 changes: 1 addition & 6 deletions src/mcp_outline/features/documents/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,7 @@ async def get_outline_client() -> OutlineClient:
api_url = os.getenv("OUTLINE_API_URL")

# Create an instance of the outline client
client = OutlineClient(api_key=api_key, api_url=api_url)

# Test the connection by attempting to get auth info
_ = await client.auth_info()

return client
return OutlineClient(api_key=api_key, api_url=api_url)
except OutlineError as e:
raise OutlineClientError(f"Outline client error: {str(e)}")
except Exception as e:
Expand Down
281 changes: 0 additions & 281 deletions src/mcp_outline/features/dynamic_tools.py

This file was deleted.

Loading