# 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.7 **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 ```bash # 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: ```bash ./start-tunnel.sh start ``` Add to `~/.claude.json` under `mcpServers`: ```json { "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 ```json { "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 ```bash # 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 ```typescript 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 ```typescript 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