feat: Initial release MCP Outline PostgreSQL v1.0.0
86 tools across 12 modules for direct PostgreSQL access to Outline Wiki: - Documents (19), Collections (14), Users (9), Groups (8) - Comments (6), Shares (5), Revisions (3), Events (3) - Attachments (5), File Operations (4), OAuth (8), Auth (2) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
842
SPEC-MCP-OUTLINE.md
Normal file
842
SPEC-MCP-OUTLINE.md
Normal file
@@ -0,0 +1,842 @@
|
||||
# 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<TArgs = Record<string, unknown>> {
|
||||
name: string;
|
||||
description: string;
|
||||
inputSchema: {
|
||||
type: string;
|
||||
properties: Record<string, unknown>;
|
||||
required?: string[];
|
||||
};
|
||||
handler: (args: TArgs, pgClient: Pool) => Promise<ToolResponse>;
|
||||
}
|
||||
|
||||
// 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 |
|
||||
|
||||
---
|
||||
|
||||
## 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®*
|
||||
Reference in New Issue
Block a user