# MCP Outline - Especificação Completa **Versão:** 1.0.0 **Data:** 2026-01-31 **Autor:** Descomplicar® --- ## 1. Visão Geral ### Objectivo MCP para acesso directo à base de dados PostgreSQL do Outline, seguindo os padrões estabelecidos pelo `mcp-desk-crm-sql-v3`. ### Arquitectura ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Claude Code │────▶│ MCP Outline │────▶│ PostgreSQL │ │ (Cliente) │◀────│ (Servidor) │◀────│ (Outline DB) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ MCP Protocol │ SQL Directo │ (stdio/SSE) │ (pg client) ``` ### Decisões Técnicas | Aspecto | Decisão | Razão | |---------|---------|-------| | **Acesso** | SQL Directo (não API) | Performance, controlo total | | **BD** | PostgreSQL 15 | Compatível com Outline | | **Transporte** | stdio (dev), SSE (prod) | Padrão MCP | | **Linguagem** | TypeScript | Type safety, padrão Desk | --- ## 2. Ambiente de Desenvolvimento ### Configuração Local ```bash # Base de dados Host: localhost Port: 5432 User: outline Password: outline_dev_2026 Database: outline # Connection string postgres://outline:outline_dev_2026@localhost:5432/outline ``` ### Estrutura do Projecto ``` ~/mcp-servers/mcp-outline/ ├── package.json ├── tsconfig.json ├── .env ├── .env.example ├── CHANGELOG.md ├── README.md ├── SPEC-MCP-OUTLINE.md ← Este ficheiro ├── src/ │ ├── index.ts ← Entry point MCP │ ├── pg-client.ts ← Cliente PostgreSQL │ ├── config/ │ │ └── database.ts ← Configuração BD │ ├── types/ │ │ ├── index.ts │ │ ├── tools.ts ← Tipos base das tools │ │ └── db.ts ← Tipos das tabelas │ ├── tools/ │ │ ├── index.ts ← Exporta todas as tools │ │ ├── documents.ts │ │ ├── collections.ts │ │ ├── users.ts │ │ ├── groups.ts │ │ ├── comments.ts │ │ ├── attachments.ts │ │ ├── shares.ts │ │ ├── revisions.ts │ │ └── events.ts │ └── utils/ │ ├── logger.ts │ └── security.ts ├── dist/ ← Build output └── tests/ └── tools/ ``` --- ## 3. Dependências ### package.json ```json { "name": "mcp-outline", "version": "1.0.0", "type": "module", "main": "dist/index.js", "scripts": { "build": "tsc", "start": "node dist/index.js", "dev": "tsx watch src/index.ts", "test": "vitest" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0", "pg": "^8.11.0", "dotenv": "^16.0.0" }, "devDependencies": { "@types/node": "^20.0.0", "@types/pg": "^8.10.0", "typescript": "^5.0.0", "tsx": "^4.0.0", "vitest": "^1.0.0" } } ``` ### tsconfig.json ```json { "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "declaration": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] } ``` --- ## 4. Tipos Base (Padrão Desk) ### src/types/tools.ts ```typescript import { Pool } from 'pg'; export interface ToolResponse { content: Array<{ type: 'text'; text: string; }>; [key: string]: unknown; } export interface BaseTool> { name: string; description: string; inputSchema: { type: string; properties: Record; required?: string[]; }; handler: (args: TArgs, pgClient: Pool) => Promise; } // Argumentos comuns export interface PaginationArgs { limit?: number; offset?: number; } export interface DateRangeArgs { dateFrom?: string; dateTo?: string; } ``` --- ## 5. API Outline → Tools MCP ### 5.1 Documents (17 tools) | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `documents.list` | `list_documents` | SELECT | P1 | | `documents.info` | `get_document` | SELECT | P1 | | `documents.create` | `create_document` | INSERT | P1 | | `documents.update` | `update_document` | UPDATE | P1 | | `documents.delete` | `delete_document` | UPDATE (soft) | P1 | | `documents.search` | `search_documents` | SELECT FTS | P1 | | `documents.drafts` | `list_drafts` | SELECT | P2 | | `documents.viewed` | `list_viewed_documents` | SELECT | P2 | | `documents.archive` | `archive_document` | UPDATE | P2 | | `documents.restore` | `restore_document` | UPDATE | P2 | | `documents.move` | `move_document` | UPDATE | P2 | | `documents.unpublish` | `unpublish_document` | UPDATE | P3 | | `documents.templatize` | `templatize_document` | INSERT | P3 | | `documents.export` | `export_document` | SELECT | P2 | | `documents.import` | `import_document` | INSERT | P3 | | `documents.users` | `list_document_users` | SELECT | P2 | | `documents.memberships` | `list_document_memberships` | SELECT | P3 | #### Exemplo: list_documents ```typescript export const listDocuments: BaseTool = { name: 'list_documents', description: 'Lista documentos com filtros. Suporta paginação e ordenação.', inputSchema: { type: 'object', properties: { collection_id: { type: 'string', description: 'UUID da collection para filtrar' }, user_id: { type: 'string', description: 'UUID do autor para filtrar' }, template: { type: 'boolean', description: 'Filtrar apenas templates' }, published: { type: 'boolean', description: 'Filtrar apenas publicados (default: true)' }, limit: { type: 'number', description: 'Máximo de resultados (default: 25, max: 100)' }, offset: { type: 'number', description: 'Offset para paginação' }, sort: { type: 'string', enum: ['updatedAt', 'createdAt', 'title', 'index'], description: 'Campo para ordenação' }, direction: { type: 'string', enum: ['ASC', 'DESC'], description: 'Direcção da ordenação' } } }, handler: async (args, pgClient) => { const limit = Math.min(args.limit || 25, 100); const offset = args.offset || 0; const sort = args.sort || 'updatedAt'; const direction = args.direction || 'DESC'; let sql = ` SELECT d.id, d.title, d.text, d."collectionId", d."parentDocumentId", d."createdById", d."publishedAt", d."updatedAt", d."archivedAt", d.template, c.name as collection_name, u.name as author_name FROM documents d LEFT JOIN collections c ON d."collectionId" = c.id LEFT JOIN users u ON d."createdById" = u.id WHERE d."deletedAt" IS NULL `; const params: any[] = []; let paramIndex = 1; if (args.collection_id) { sql += ` AND d."collectionId" = $${paramIndex++}`; params.push(args.collection_id); } if (args.user_id) { sql += ` AND d."createdById" = $${paramIndex++}`; params.push(args.user_id); } if (args.template !== undefined) { sql += ` AND d.template = $${paramIndex++}`; params.push(args.template); } if (args.published !== false) { sql += ` AND d."publishedAt" IS NOT NULL`; } sql += ` ORDER BY d."${sort}" ${direction}`; sql += ` LIMIT $${paramIndex++} OFFSET $${paramIndex++}`; params.push(limit, offset); const result = await pgClient.query(sql, params); return { content: [{ type: 'text', text: JSON.stringify({ documents: result.rows, pagination: { limit, offset, count: result.rows.length } }, null, 2) }] }; } }; ``` ### 5.2 Collections (13 tools) | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `collections.list` | `list_collections` | SELECT | P1 | | `collections.info` | `get_collection` | SELECT | P1 | | `collections.create` | `create_collection` | INSERT | P1 | | `collections.update` | `update_collection` | UPDATE | P1 | | `collections.delete` | `delete_collection` | UPDATE (soft) | P2 | | `collections.documents` | `list_collection_documents` | SELECT | P1 | | `collections.add_user` | `add_user_to_collection` | INSERT | P2 | | `collections.remove_user` | `remove_user_from_collection` | DELETE | P2 | | `collections.memberships` | `list_collection_memberships` | SELECT | P2 | | `collections.add_group` | `add_group_to_collection` | INSERT | P3 | | `collections.remove_group` | `remove_group_from_collection` | DELETE | P3 | | `collections.group_memberships` | `list_collection_group_memberships` | SELECT | P3 | | `collections.export` | `export_collection` | SELECT | P3 | ### 5.3 Users (7 tools) | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `users.list` | `list_users` | SELECT | P1 | | `users.info` | `get_user` | SELECT | P1 | | `users.create` | `create_user` | INSERT | P2 | | `users.update` | `update_user` | UPDATE | P2 | | `users.delete` | `delete_user` | UPDATE (soft) | P3 | | `users.suspend` | `suspend_user` | UPDATE | P2 | | `users.activate` | `activate_user` | UPDATE | P2 | ### 5.4 Groups (7 tools) | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `groups.list` | `list_groups` | SELECT | P1 | | `groups.info` | `get_group` | SELECT | P1 | | `groups.create` | `create_group` | INSERT | P2 | | `groups.update` | `update_group` | UPDATE | P2 | | `groups.delete` | `delete_group` | DELETE | P3 | | `groups.memberships` | `list_group_members` | SELECT | P2 | | `groups.add_user` | `add_user_to_group` | INSERT | P2 | ### 5.5 Comments (5 tools) | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `comments.list` | `list_comments` | SELECT | P1 | | `comments.info` | `get_comment` | SELECT | P2 | | `comments.create` | `create_comment` | INSERT | P1 | | `comments.update` | `update_comment` | UPDATE | P2 | | `comments.delete` | `delete_comment` | DELETE | P2 | ### 5.6 Shares (4 tools) | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `shares.info` | `get_share` | SELECT | P2 | | `shares.create` | `create_share` | INSERT | P2 | | `shares.update` | `update_share` | UPDATE | P3 | | `shares.delete` | `delete_share` | DELETE | P2 | ### 5.7 Revisions (2 tools) | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `revisions.list` | `list_revisions` | SELECT | P2 | | `revisions.info` | `get_revision` | SELECT | P2 | ### 5.8 Events (1 tool) | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `events.list` | `list_events` | SELECT | P2 | ### 5.9 Attachments (3 tools) | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `attachments.create` | `create_attachment` | INSERT | P3 | | `attachments.redirect` | `get_attachment_url` | SELECT | P3 | | `attachments.delete` | `delete_attachment` | DELETE | P3 | ### 5.10 Auth (2 tools) | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `auth.info` | `get_auth_info` | SELECT | P3 | | `auth.config` | `get_auth_config` | SELECT | P3 | ### 5.11 Stars (3 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `stars.list` | `list_stars` | SELECT | P2 | | `stars.create` | `star_document` | INSERT | P2 | | `stars.delete` | `unstar_document` | DELETE | P2 | ### 5.12 Pins (3 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `pins.list` | `list_pins` | SELECT | P2 | | `pins.create` | `pin_document` | INSERT | P2 | | `pins.delete` | `unpin_document` | DELETE | P2 | ### 5.13 Views (2 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `views.list` | `list_document_views` | SELECT | P2 | | `views.create` | `register_view` | INSERT | P3 | ### 5.14 Reactions (3 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `reactions.list` | `list_reactions` | SELECT | P3 | | `reactions.create` | `add_reaction` | INSERT | P3 | | `reactions.delete` | `remove_reaction` | DELETE | P3 | ### 5.15 API Keys (4 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `apiKeys.list` | `list_api_keys` | SELECT | P2 | | `apiKeys.create` | `create_api_key` | INSERT | P2 | | `apiKeys.delete` | `delete_api_key` | DELETE | P2 | | `apiKeys.info` | `get_api_key` | SELECT | P3 | ### 5.16 Webhooks (4 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `webhooks.list` | `list_webhooks` | SELECT | P3 | | `webhooks.create` | `create_webhook` | INSERT | P3 | | `webhooks.update` | `update_webhook` | UPDATE | P3 | | `webhooks.delete` | `delete_webhook` | DELETE | P3 | ### 5.17 Backlinks (1 tool) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `backlinks.list` | `list_backlinks` | SELECT | P2 | ### 5.18 Search Queries (2 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `searchQueries.list` | `list_search_queries` | SELECT | P3 | | `searchQueries.popular` | `get_popular_searches` | SELECT | P3 | ### 5.19 Teams (5 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `teams.info` | `get_team` | SELECT | P1 | | `teams.update` | `update_team` | UPDATE | P2 | | `teams.stats` | `get_team_stats` | SELECT | P2 | | `teams.domains` | `list_team_domains` | SELECT | P2 | | `teams.settings` | `update_team_settings` | UPDATE | P2 | ### 5.20 Integrations (6 tools) - CRÍTICO para embeds | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `integrations.list` | `list_integrations` | SELECT | P1 | | `integrations.info` | `get_integration` | SELECT | P1 | | `integrations.create` | `create_integration` | INSERT | P1 | | `integrations.update` | `update_integration` | UPDATE | P2 | | `integrations.delete` | `delete_integration` | DELETE | P2 | | `integrations.sync` | `sync_integration` | UPDATE | P2 | ### 5.21 Notifications (4 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `notifications.list` | `list_notifications` | SELECT | P1 | | `notifications.read` | `mark_notification_read` | UPDATE | P2 | | `notifications.readAll` | `mark_all_notifications_read` | UPDATE | P2 | | `notifications.settings` | `get_notification_settings` | SELECT | P2 | ### 5.22 Subscriptions (4 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `subscriptions.list` | `list_subscriptions` | SELECT | P1 | | `subscriptions.create` | `subscribe_to_document` | INSERT | P2 | | `subscriptions.delete` | `unsubscribe_from_document` | DELETE | P2 | | `subscriptions.settings` | `get_subscription_settings` | SELECT | P2 | ### 5.23 Imports (4 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `imports.list` | `list_imports` | SELECT | P2 | | `imports.status` | `get_import_status` | SELECT | P2 | | `imports.create` | `create_import` | INSERT | P2 | | `imports.cancel` | `cancel_import` | UPDATE | P2 | ### 5.24 Emojis (3 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `emojis.list` | `list_emojis` | SELECT | P2 | | `emojis.create` | `create_emoji` | INSERT | P3 | | `emojis.delete` | `delete_emoji` | DELETE | P3 | ### 5.25 User Permissions (3 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `userPermissions.list` | `list_user_permissions` | SELECT | P2 | | `userPermissions.grant` | `grant_permission` | INSERT | P2 | | `userPermissions.revoke` | `revoke_permission` | DELETE | P2 | ### 5.26 Bulk Operations (6 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `bulk.moveDocuments` | `bulk_move_documents` | UPDATE | P2 | | `bulk.archiveDocuments` | `bulk_archive_documents` | UPDATE | P2 | | `bulk.deleteDocuments` | `bulk_delete_documents` | DELETE | P2 | | `bulk.updateDocuments` | `bulk_update_documents` | UPDATE | P2 | | `documents.duplicate` | `duplicate_document` | INSERT | P2 | | `collections.merge` | `merge_collections` | UPDATE | P2 | ### 5.27 Export/Import Avançado (4 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `export.collectionMarkdown` | `export_collection_to_markdown` | SELECT | P2 | | `export.documentTree` | `export_document_tree` | SELECT | P2 | | `import.markdownFolder` | `import_markdown_folder` | INSERT | P2 | | `import.fromUrl` | `import_from_url` | INSERT | P3 | ### 5.28 Advanced Search (6 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `search.byDateRange` | `search_by_date_range` | SELECT | P2 | | `search.byAuthor` | `search_by_author` | SELECT | P2 | | `search.inCollection` | `search_in_collection` | SELECT | P2 | | `search.orphanDocuments` | `find_orphan_documents` | SELECT | P2 | | `search.emptyCollections` | `find_empty_collections` | SELECT | P2 | | `search.brokenLinks` | `find_broken_links` | SELECT | P2 | ### 5.29 Analytics (6 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `analytics.workspace` | `get_workspace_stats` | SELECT | P2 | | `analytics.userActivity` | `get_user_activity` | SELECT | P2 | | `analytics.collection` | `get_collection_stats` | SELECT | P2 | | `analytics.mostViewed` | `get_most_viewed_documents` | SELECT | P2 | | `analytics.mostEdited` | `get_most_edited_documents` | SELECT | P2 | | `analytics.stale` | `get_stale_documents` | SELECT | P2 | ### 5.30 External Sync (5 tools) - NOVO | API Endpoint | Tool MCP | Operação | Prioridade | |--------------|----------|----------|------------| | `sync.deskProject` | `create_desk_project_doc` | INSERT | P3 | | `sync.deskTask` | `link_desk_task` | INSERT | P3 | | `embeds.create` | `create_embed` | INSERT | P2 | | `embeds.update` | `update_embed` | UPDATE | P2 | | `embeds.list` | `list_document_embeds` | SELECT | P2 | --- ## 6. Resumo de Tools ### Por Prioridade | Prioridade | Quantidade | Descrição | |------------|------------|-----------| | P1 | 18 | Core: CRUD documentos, collections, users, search | | P2 | 37 | Secundárias: memberships, comments, shares, stars, pins, views, apiKeys | | P3 | 28 | Avançadas: templates, OAuth, attachments, reactions, webhooks | | **Total** | **83** | | ### Por Módulo | Módulo | Tools | Estado | |--------|-------|--------| | Documents | 17 | A implementar | | Collections | 13 | A implementar | | Users | 7 | A implementar | | Groups | 7 | A implementar | | Comments | 5 | A implementar | | Shares | 4 | A implementar | | Revisions | 2 | A implementar | | Events | 1 | A implementar | | Attachments | 3 | A implementar | | Auth | 2 | A implementar | | Stars | 3 | A implementar | | Pins | 3 | A implementar | | Views | 2 | A implementar | | Reactions | 3 | A implementar | | API Keys | 4 | A implementar | | Webhooks | 4 | A implementar | | Backlinks | 1 | A implementar | | Search Queries | 2 | A implementar | --- ## 7. Schema PostgreSQL (Outline) ### Tabelas Reais (41 tabelas - verificado 2026-01-31) ```sql -- Core Content documents -- Documentos e drafts collections -- Organizações de documentos revisions -- Histórico de versões comments -- Comentários em documentos attachments -- Ficheiros anexados backlinks -- Links entre documentos -- Users & Auth users -- Utilizadores teams -- Workspaces groups -- Grupos de utilizadores group_users -- Membros de grupos user_permissions -- Permissões de utilizadores user_authentications -- Autenticações de utilizadores user_passkeys -- Passkeys WebAuthn authentications -- Sessões de autenticação authentication_providers -- Providers OAuth oauth_authentications -- Tokens OAuth oauth_authorization_codes -- Códigos OAuth oauth_clients -- Clientes OAuth registados apiKeys -- API tokens -- Permissions collection_users -- Permissões collection-user collection_groups -- Permissões collection-group group_permissions -- Permissões de grupos -- Sharing & Social shares -- Links públicos stars -- Favoritos pins -- Documentos fixados views -- Visualizações de documentos reactions -- Reacções (emojis em docs) emojis -- Emojis customizados relationships -- Relações entre entidades -- Notifications & Events events -- Audit log notifications -- Alertas subscriptions -- Subscrições de notificações -- Import/Export imports -- Imports em curso import_tasks -- Tarefas de import file_operations -- Operações de ficheiros -- Integrations integrations -- Integrações externas webhook_subscriptions -- Webhooks registados webhook_deliveries -- Entregas de webhooks -- System SequelizeMeta -- Migrações Sequelize team_domains -- Domínios por team search_queries -- Histórico de pesquisas ``` ### Relações Chave ``` teams (1) ─────────< (N) users teams (1) ─────────< (N) collections teams (1) ─────────< (N) groups teams (1) ─────────< (N) team_domains teams (1) ─────────< (N) integrations collections (1) ────< (N) documents collections (1) ────< (N) collection_users collections (1) ────< (N) collection_groups documents (1) ──────< (N) comments documents (1) ──────< (N) revisions documents (1) ──────< (N) shares documents (1) ──────< (N) attachments documents (1) ──────< (N) views documents (1) ──────< (N) stars documents (1) ──────< (N) pins documents (1) ──────< (N) reactions documents (1) ──────< (N) backlinks users (1) ──────────< (N) documents (createdById) users (1) ──────────< (N) apiKeys users (1) ──────────< (N) user_authentications users (1) ──────────< (N) notifications users (1) ──────────< (N) subscriptions users (N) ─────────<>───── (N) groups (via group_users) groups (N) ────────<>───── (N) collections (via collection_groups) integrations (1) ───< (N) webhook_subscriptions webhook_subscriptions (1) < (N) webhook_deliveries ``` --- ## 8. Implementação ### Fase 1: Setup (MVP) ```bash # 1. Criar estrutura mkdir -p ~/mcp-servers/mcp-outline/{src/{tools,types,config,utils},tests} cd ~/mcp-servers/mcp-outline # 2. Inicializar npm init -y npm install @modelcontextprotocol/sdk pg dotenv npm install -D typescript @types/node @types/pg tsx vitest # 3. Configurar cp .env.example .env # Editar .env com credenciais # 4. Build npm run build # 5. Testar npm run dev ``` ### Fase 2: Core Tools (P1) Implementar por ordem: 1. `list_documents`, `get_document`, `search_documents` 2. `list_collections`, `get_collection` 3. `list_users`, `get_user` 4. `create_document`, `update_document` 5. `create_collection`, `update_collection` ### Fase 3: Secondary Tools (P2) 1. Comments (CRUD) 2. Memberships 3. Revisions 4. Shares 5. Events ### Fase 4: Advanced Tools (P3) 1. Templates 2. Attachments 3. OAuth 4. Import/Export --- ## 9. Configuração Claude Code ### ~/.claude.json ```json { "mcpServers": { "outline": { "command": "node", "args": ["/home/ealmeida/mcp-servers/mcp-outline/dist/index.js"], "env": { "DATABASE_URL": "postgres://outline:outline_dev_2026@localhost:5432/outline" } } } } ``` --- ## 10. Testes ### Estrutura ``` tests/ ├── setup.ts # Configuração vitest ├── tools/ │ ├── documents.test.ts │ ├── collections.test.ts │ └── users.test.ts └── integration/ └── full-flow.test.ts ``` ### Exemplo Test ```typescript import { describe, it, expect, beforeAll } from 'vitest'; import { Pool } from 'pg'; import { listDocuments } from '../src/tools/documents'; describe('Documents Tools', () => { let pool: Pool; beforeAll(() => { pool = new Pool({ connectionString: process.env.DATABASE_URL }); }); it('list_documents returns array', async () => { const result = await listDocuments.handler({}, pool); const data = JSON.parse(result.content[0].text); expect(Array.isArray(data.documents)).toBe(true); expect(data.pagination).toBeDefined(); }); }); ``` --- ## 11. Padrões de Código (do Desk) ### Response Format ```typescript // SEMPRE retornar neste formato return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }; ``` ### Error Handling ```typescript try { const result = await pgClient.query(sql, params); return { content: [{ type: 'text', text: JSON.stringify({ success: true, data: result.rows }, null, 2) }] }; } catch (error) { return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error' }, null, 2) }] }; } ``` ### Naming Conventions | Tipo | Padrão | Exemplo | |------|--------|---------| | Tool name | snake_case | `list_documents` | | Function | camelCase | `listDocuments` | | Type | PascalCase | `DocumentRow` | | File | kebab-case | `documents.ts` | --- ## 12. Checklist de Implementação ### Setup - [ ] Estrutura de pastas criada - [ ] package.json configurado - [ ] tsconfig.json configurado - [ ] .env configurado - [ ] pg-client.ts implementado ### Tools P1 - [ ] list_documents - [ ] get_document - [ ] create_document - [ ] update_document - [ ] delete_document - [ ] search_documents - [ ] list_collections - [ ] get_collection - [ ] create_collection - [ ] update_collection - [ ] list_collection_documents - [ ] list_users - [ ] get_user - [ ] list_groups - [ ] get_group - [ ] list_comments - [ ] create_comment - [ ] list_group_members ### Tools P2 (novas) - [ ] list_stars - [ ] star_document - [ ] unstar_document - [ ] list_pins - [ ] pin_document - [ ] unpin_document - [ ] list_document_views - [ ] list_backlinks - [ ] list_api_keys - [ ] create_api_key - [ ] delete_api_key ### Integração - [ ] Build sem erros - [ ] Configurado em ~/.claude.json - [ ] Tools visíveis no Claude Code - [ ] Testes P1 passam ### Documentação - [ ] README.md - [ ] CHANGELOG.md - [ ] Obsidian docs actualizados --- ## 13. Referências - [Outline API Docs](https://www.getoutline.com/developers) - [MCP SDK](https://modelcontextprotocol.io/) - [mcp-desk-crm-sql-v3](~/mcp-servers/mcp-desk-crm-sql-v3/) - [PostgreSQL pg docs](https://node-postgres.com/) --- *Documento gerado: 2026-01-31* *Autor: Descomplicar®*