Documents created via MCP were not visible in Outline interface. Outline requires an entry in the revisions table to display documents. Now uses transaction to insert into both documents and revisions tables. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
12 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
MCP server for direct PostgreSQL access to Outline Wiki database. Follows patterns established by mcp-desk-crm-sql-v3.
Version: 1.3.9 Total Tools: 164 tools across 33 modules Production: hub.descomplicar.pt (via SSH tunnel)
Architecture
┌─────────────────────┐
│ src/server/ │
│ (Shared Logic) │
└──────────┬──────────┘
│
┌────────────────┼────────────────┐
│ │ │
┌────────▼────────┐ ┌─────▼─────┐ │
│ index.ts │ │index-http │ │
│ (stdio) │ │ (HTTP) │ │
└─────────────────┘ └───────────┘ │
│ │ │
└────────────────┴────────────────┘
│
┌──────────▼──────────┐
│ PostgreSQL │
│ (Outline DB) │
└─────────────────────┘
Commands
# Build TypeScript to dist/
npm run build
# Run stdio server (default, for Claude Code)
npm start
# Run HTTP server (for web/remote access)
npm run start:http
# Development with ts-node
npm run dev
npm run dev:http
# Run tests
npm test
Transports
| Transport | Entry Point | Port | Use Case |
|---|---|---|---|
| stdio | index.ts |
N/A | Claude Code local |
| HTTP | index-http.ts |
3200 | Web/remote access |
HTTP Transport Endpoints
/mcp- MCP protocol endpoint/health- Health check (JSON status)/stats- Tool statistics
Project Structure
src/
├── index.ts # Stdio transport entry point
├── index-http.ts # HTTP transport entry point
├── pg-client.ts # PostgreSQL client wrapper
├── config/
│ └── database.ts # DB configuration
├── server/
│ ├── index.ts # Server module exports
│ ├── create-server.ts # MCP server factory
│ └── register-handlers.ts # Shared handler registration
├── types/
│ ├── index.ts
│ ├── tools.ts # Base tool types
│ └── db.ts # Database table types
├── tools/
│ ├── index.ts # Export all tools
│ ├── documents.ts # 19 tools - Core document management
│ ├── collections.ts # 14 tools - Collection management
│ ├── users.ts # 9 tools - User management
│ ├── groups.ts # 8 tools - Group management
│ ├── comments.ts # 6 tools - Comment system
│ ├── shares.ts # 5 tools - Document sharing
│ ├── revisions.ts # 3 tools - Version history
│ ├── events.ts # 3 tools - Audit log
│ ├── attachments.ts # 5 tools - File attachments
│ ├── file-operations.ts # 4 tools - Import/export jobs
│ ├── oauth.ts # 8 tools - OAuth management
│ ├── auth.ts # 2 tools - Authentication
│ ├── stars.ts # 3 tools - Bookmarks
│ ├── pins.ts # 3 tools - Pinned documents
│ ├── views.ts # 2 tools - View tracking
│ ├── reactions.ts # 3 tools - Emoji reactions
│ ├── api-keys.ts # 4 tools - API keys
│ ├── webhooks.ts # 4 tools - Webhooks
│ ├── backlinks.ts # 1 tool - Link references
│ ├── search-queries.ts # 2 tools - Search analytics
│ ├── teams.ts # 5 tools - Team/workspace
│ ├── integrations.ts # 6 tools - External integrations
│ ├── notifications.ts # 4 tools - Notifications
│ ├── subscriptions.ts # 4 tools - Subscriptions
│ ├── templates.ts # 5 tools - Templates
│ ├── imports-tools.ts # 4 tools - Import jobs
│ ├── emojis.ts # 3 tools - Custom emojis
│ ├── user-permissions.ts # 3 tools - Permissions
│ ├── bulk-operations.ts # 6 tools - Batch operations
│ ├── advanced-search.ts # 6 tools - Advanced search
│ ├── analytics.ts # 6 tools - Analytics
│ ├── export-import.ts # 2 tools - Markdown export/import
│ └── desk-sync.ts # 2 tools - Desk CRM integration
└── utils/
├── index.ts # Export all utilities
├── logger.ts # Logging utility
├── security.ts # Security utilities (validation, rate limiting)
├── transaction.ts # Transaction helpers with retry logic
├── query-builder.ts # Safe parameterized query builder
├── validation.ts # Zod-based input validation
├── audit.ts # Audit logging for write operations
├── monitoring.ts # Connection pool health monitoring
└── pagination.ts # Cursor-based pagination helpers
Tools Summary (164 total)
| Module | Tools | Description |
|---|---|---|
| documents | 19 | CRUD, search, archive, move, templates, memberships |
| collections | 14 | CRUD, memberships, groups, export |
| users | 9 | CRUD, suspend, activate, promote, demote |
| groups | 8 | CRUD, memberships |
| comments | 6 | CRUD, resolve |
| shares | 5 | CRUD, revoke |
| revisions | 3 | list, info, compare |
| events | 3 | list, info, stats |
| attachments | 5 | CRUD, stats |
| file-operations | 4 | import/export jobs |
| oauth | 8 | OAuth clients, authentications |
| auth | 2 | auth info, config |
| stars | 3 | list, create, delete (bookmarks) |
| pins | 3 | list, create, delete (highlighted docs) |
| views | 2 | list, create (view tracking) |
| reactions | 3 | list, create, delete (emoji on comments) |
| api-keys | 4 | CRUD (programmatic access) |
| webhooks | 4 | CRUD (event subscriptions) |
| backlinks | 1 | list (document links - read-only view) |
| search-queries | 2 | list, stats (search analytics) |
| teams | 5 | get, update, stats, domains, settings |
| integrations | 6 | list, get, create, update, delete, sync |
| notifications | 4 | list, mark read, mark all read, settings |
| subscriptions | 4 | list, subscribe, unsubscribe, settings |
| templates | 5 | list, get, create from, convert to/from |
| imports | 4 | list, status, create, cancel |
| emojis | 3 | list, create, delete |
| user-permissions | 3 | list, grant, revoke |
| bulk-operations | 6 | archive, delete, move, restore, add/remove users |
| advanced-search | 6 | advanced search, facets, recent, user activity, orphaned, duplicates |
| analytics | 6 | overview, user activity, content insights, collection stats, growth, search |
| export-import | 2 | export collection to markdown, import markdown folder |
| desk-sync | 2 | create desk project doc, link desk task |
Configuration
Production (hub.descomplicar.pt)
Requires SSH tunnel - Run before starting Claude Code:
./start-tunnel.sh start
Add to ~/.claude.json under mcpServers:
{
"outline-postgresql": {
"command": "node",
"args": ["/home/ealmeida/mcp-servers/mcp-outline-postgresql/dist/index.js"],
"env": {
"DATABASE_URL": "postgres://postgres:***@localhost:5433/descomplicar",
"LOG_LEVEL": "error"
}
}
}
Local Development
{
"outline-postgresql": {
"command": "node",
"args": ["/home/ealmeida/mcp-servers/mcp-outline-postgresql/dist/index.js"],
"env": {
"DATABASE_URL": "postgres://outline:outline_dev_2026@localhost:5432/outline",
"LOG_LEVEL": "error"
}
}
}
SSH Tunnel Management
# Start tunnel (before Claude Code)
./start-tunnel.sh start
# Check status
./start-tunnel.sh status
# Stop tunnel
./start-tunnel.sh stop
Environment
| Environment | Port | Database | Tunnel |
|---|---|---|---|
| Production | 5433 | descomplicar | Required |
| Development | 5432 | outline | No |
Key Patterns
Tool Response Format
return {
content: [{
type: 'text',
text: JSON.stringify(data, null, 2)
}]
};
Naming Conventions
| Type | Convention | Example |
|---|---|---|
| Tool name | snake_case with prefix | outline_list_documents |
| Function | camelCase | listDocuments |
| Type | PascalCase | DocumentRow |
| File | kebab-case | documents.ts |
Database
PostgreSQL 15 - Direct SQL access (not Outline API)
Key tables: documents, collections, users, groups, comments, revisions, shares, attachments, events, stars, pins, views, file_operations, oauth_clients
Soft deletes: Most entities use deletedAt column, not hard deletes.
See SPEC-MCP-OUTLINE.md for complete database schema.
Security Utilities
The src/utils/security.ts module provides essential security functions:
Validation Functions
| Function | Description |
|---|---|
isValidUUID(uuid) |
Validate UUID format |
isValidUrlId(urlId) |
Validate URL-safe ID format |
isValidEmail(email) |
Validate email format |
isValidHttpUrl(url) |
Validate URL is HTTP(S) - rejects javascript:, data:, file: protocols |
isValidISODate(date) |
Validate ISO date format (YYYY-MM-DD or full ISO) |
validateDaysInterval(days, default, max) |
Validate and clamp days interval for SQL |
validatePeriod(period, allowed, default) |
Validate period against allowed values |
validatePagination(limit, offset) |
Validate and normalize pagination params |
validateSortDirection(direction) |
Validate sort direction (ASC/DESC) |
validateSortField(field, allowed, default) |
Validate sort field against whitelist |
Sanitization Functions
| Function | Description |
|---|---|
sanitizeInput(input) |
Remove null bytes and trim whitespace |
escapeHtml(text) |
Escape HTML entities for safe display |
Rate Limiting
| Function | Description |
|---|---|
checkRateLimit(type, clientId) |
Check if request should be rate limited |
startRateLimitCleanup() |
Start background cleanup of expired entries |
stopRateLimitCleanup() |
Stop cleanup interval (call on shutdown) |
clearRateLimitStore() |
Clear all rate limit entries (testing) |
Usage Example
import {
isValidUUID,
isValidHttpUrl,
validateDaysInterval,
startRateLimitCleanup,
stopRateLimitCleanup
} from './utils/security.js';
// Validation before SQL
if (!isValidUUID(args.user_id)) {
throw new Error('Invalid user_id format');
}
// URL validation (prevents XSS)
if (!isValidHttpUrl(args.webhook_url)) {
throw new Error('Invalid URL. Only HTTP(S) allowed.');
}
// Safe interval for SQL
const safeDays = validateDaysInterval(args.days, 30, 365);
// Use in query: `INTERVAL '${safeDays} days'` is safe (it's a number)
// Lifecycle management
startRateLimitCleanup(); // On server start
stopRateLimitCleanup(); // On graceful shutdown
Cryptographic Security
Secrets and tokens use crypto.randomBytes() instead of Math.random():
- OAuth secrets:
oauth.ts-sk_prefixed base64url tokens - API keys:
api-keys.ts-ol_prefixed keys, only hash stored in DB - Share URLs:
shares.ts- Cryptographically secure URL IDs