2b2b82c2a7
Porta 3175 já ocupada por mcp-metabase-ai no gateway. Deploy confirmado: PM2 online, health OK, 165 tools. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
782 lines
31 KiB
Markdown
782 lines
31 KiB
Markdown
---
|
|
title: "SPEC — MCP Paperclip v1.0"
|
|
date: 2026-04-07
|
|
type: spec
|
|
status: draft
|
|
project: mcp-paperclip
|
|
desk_task: ""
|
|
tags: [mcp, paperclip, typescript, agentes, orquestração]
|
|
---
|
|
|
|
# SPEC — MCP Paperclip v1.0
|
|
|
|
MCP TypeScript para integração completa com o Paperclip AI
|
|
(orquestrador autónomo em `clip.descomplicar.pt`).
|
|
|
|
Permite ao Claude Code gerir agentes, issues, rotinas, goals, projectos, aprovações,
|
|
custos, actividade, skills, segredos e dashboard via API REST.
|
|
|
|
---
|
|
|
|
## Contexto
|
|
|
|
| Item | Valor |
|
|
|------|-------|
|
|
| **API Base** | `https://clip.descomplicar.pt/api` (produção) |
|
|
| **Paperclip Version** | `0.3.1` |
|
|
| **Company ID** | `ebe10308-efd7-453f-86ab-13e6fe84004f` (Descomplicar) |
|
|
| **User ID** | `v1N5OccPn9DGq6iog7qW9nEvnXYFT3iO` (Emanuel) |
|
|
| **Auth** | `Authorization: Bearer {PAPERCLIP_API_KEY}` (Board API Key, SHA256 hash em `board_api_keys`) |
|
|
| **Destino** | `/home/ealmeida/mcp-servers/mcp-paperclip/` |
|
|
| **Transport** | STDIO (Claude Code) + StreamableHTTP porta `3168` + SSE porta `3168` (legado) |
|
|
| **Linguagem** | TypeScript (padrão Descomplicar) |
|
|
| **API Total** | 246 endpoints em 21 módulos — este MCP cobre 159 tools |
|
|
|
|
---
|
|
|
|
## Pré-requisito: Criar Board API Key
|
|
|
|
Antes da primeira utilização, gerar e registar uma Board API Key:
|
|
|
|
```bash
|
|
# Gerar key
|
|
KEY=$(node -e "console.log('pcp_mcp_' + require('crypto').randomBytes(24).toString('hex'))")
|
|
echo "PAPERCLIP_API_KEY=$KEY"
|
|
|
|
# Registar na BD (SHA256 hash)
|
|
HASH=$(node -e "const c=require('crypto'); process.argv[1] && console.log(c.createHash('sha256').update(process.argv[1]).digest('hex'))" "$KEY")
|
|
PGPASSWORD=paperclip psql -h 127.0.0.1 -p 54329 -U paperclip -d paperclip -c \
|
|
"INSERT INTO board_api_keys (user_id, name, key_hash) VALUES ('v1N5OccPn9DGq6iog7qW9nEvnXYFT3iO', 'claude-code-mcp', '$HASH');"
|
|
```
|
|
|
|
Guardar `KEY` no `.env` do MCP como `PAPERCLIP_API_KEY`.
|
|
|
|
---
|
|
|
|
## Arquitectura
|
|
|
|
```
|
|
mcp-paperclip/
|
|
├── src/
|
|
│ ├── index.ts # Entry STDIO (Claude Code)
|
|
│ ├── index-http.ts # Entry StreamableHTTP + SSE porta 3175
|
|
│ ├── server.ts # Lógica comum (createServer)
|
|
│ ├── client.ts # HTTP client para API Paperclip
|
|
│ ├── tools/
|
|
│ │ ├── index.ts # Registar todas as tools
|
|
│ │ ├── agents.ts # Agentes — CRUD, lifecycle, config, keys, heartbeats
|
|
│ │ ├── issues.ts # Issues — CRUD, comments, documents, work-products, labels
|
|
│ │ ├── routines.ts # Rotinas — CRUD, triggers, runs
|
|
│ │ ├── goals.ts # Goals — CRUD
|
|
│ │ ├── projects.ts # Projectos — CRUD, workspaces
|
|
│ │ ├── approvals.ts # Aprovações — governance workflow
|
|
│ │ ├── costs.ts # Custos e budgets — monitorização financeira
|
|
│ │ ├── activity.ts # Actividade — audit log
|
|
│ │ ├── skills.ts # Company skills — gestão de competências
|
|
│ │ ├── secrets.ts # Segredos — gestão de secrets encriptados
|
|
│ │ ├── plugins.ts # Plugins — instalar, activar, config, health
|
|
│ │ ├── assets.ts # Assets — upload imagens e logos
|
|
│ │ ├── settings.ts # Instance settings — configuração geral
|
|
│ │ ├── access.ts # Invites, join requests, members
|
|
│ │ ├── company.ts # Company, org, dashboard, members
|
|
│ │ └── health.ts # Health check
|
|
│ └── utils/
|
|
│ ├── logger.ts # Logger MCP-compatible (stderr, sem cores)
|
|
│ └── annotations.ts # inferAnnotations por prefixo
|
|
├── tests/
|
|
│ └── tools.test.ts
|
|
├── docs/
|
|
│ └── API_REFERENCE.md # Endpoints mapeados
|
|
├── scripts/
|
|
│ ├── validate-capabilities.sh
|
|
│ └── create-api-key.sh # Script criação Board API Key
|
|
├── .gitea/workflows/
|
|
│ └── ci.yml
|
|
├── .env.example
|
|
├── .eslintrc / eslint.config.js
|
|
├── .prettierrc
|
|
├── tsconfig.json
|
|
├── package.json
|
|
├── CLAUDE.md
|
|
├── CHANGELOG.md
|
|
└── README.md
|
|
```
|
|
|
|
---
|
|
|
|
## Tools (159 total)
|
|
|
|
### 1. Health (1 tool)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `get_health` | GET | `/health` | read |
|
|
|
|
Retorna: `{ status, version, deploymentMode, bootstrapStatus }`
|
|
|
|
---
|
|
|
|
### 2. Company / Org (10 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `get_company` | GET | `/companies/:id` | read |
|
|
| `list_companies` | GET | `/companies` | read |
|
|
| `get_company_stats` | GET | `/companies/stats` | read |
|
|
| `update_company` | PATCH | `/companies/:id` | write |
|
|
| `update_company_branding` | PATCH | `/companies/:id/branding` | write |
|
|
| `get_org_chart` | GET | `/companies/:id/org` | read |
|
|
| `get_dashboard` | GET | `/companies/:id/dashboard` | read |
|
|
| `list_members` | GET | `/companies/:id/members` | read |
|
|
| `update_member_permissions` | PATCH | `/companies/:id/members/:memberId/permissions` | write |
|
|
| `get_sidebar_badges` | GET | `/companies/:id/sidebar-badges` | read |
|
|
|
|
**Nota:** `get_org_chart` retorna JSON da hierarquia, não SVG.
|
|
|
|
---
|
|
|
|
### 3. Agentes (22 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_agents` | GET | `/companies/:id/agents` | read |
|
|
| `get_agent` | GET | `/agents/:id` | read |
|
|
| `get_agent_runtime_state` | GET | `/agents/:id/runtime-state` | read |
|
|
| `get_agent_configuration` | GET | `/agents/:id/configuration` | read |
|
|
| `get_agent_config_revisions` | GET | `/agents/:id/config-revisions` | read |
|
|
| `rollback_agent_config` | POST | `/agents/:id/config-revisions/:revisionId/rollback` | write |
|
|
| `get_agent_skills` | GET | `/agents/:id/skills` | read |
|
|
| `sync_agent_skills` | POST | `/agents/:id/skills/sync` | write |
|
|
| `get_agent_task_sessions` | GET | `/agents/:id/task-sessions` | read |
|
|
| `get_agent_instructions_bundle` | GET | `/agents/:id/instructions-bundle` | read |
|
|
| `update_agent_instructions_bundle` | PATCH | `/agents/:id/instructions-bundle` | write |
|
|
| `create_agent` | POST | `/companies/:id/agents` | write |
|
|
| `create_agent_hire` | POST | `/companies/:id/agent-hires` | write |
|
|
| `update_agent` | PATCH | `/agents/:id` | write |
|
|
| `update_agent_permissions` | PATCH | `/agents/:id/permissions` | write |
|
|
| `update_agent_instructions_path` | PATCH | `/agents/:id/instructions-path` | write |
|
|
| `pause_agent` | POST | `/agents/:id/pause` | write |
|
|
| `resume_agent` | POST | `/agents/:id/resume` | write |
|
|
| `wakeup_agent` | POST | `/agents/:id/wakeup` | write |
|
|
| `invoke_agent_heartbeat` | POST | `/agents/:id/heartbeat/invoke` | write |
|
|
| `terminate_agent` | POST | `/agents/:id/terminate` | destrutivo |
|
|
| `delete_agent` | DELETE | `/agents/:id` | destrutivo |
|
|
|
|
**Parâmetros `create_agent`:**
|
|
```typescript
|
|
{
|
|
name: string, // nome do agente
|
|
role: string, // ceo | coo | cto | engineer | analyst | devops | pm | ...
|
|
title?: string, // descrição do cargo
|
|
reports_to?: string, // UUID do agente supervisor
|
|
capabilities?: string, // texto livre
|
|
model?: string, // claude-sonnet-4-6 | claude-opus-4-6 | ...
|
|
budget_monthly_cents?: number,
|
|
instructions_file_path?: string // path absoluto para AGENTS.md
|
|
}
|
|
```
|
|
|
|
**Parâmetros `create_agent_hire`:**
|
|
```typescript
|
|
{
|
|
name: string,
|
|
role: string,
|
|
title?: string,
|
|
reports_to?: string,
|
|
// Passa por governance/approval antes de criar o agente
|
|
}
|
|
```
|
|
|
|
**Parâmetros `wakeup_agent`:**
|
|
```typescript
|
|
{
|
|
agent_id: string,
|
|
issue_id?: string, // acordar em contexto de issue específica
|
|
message?: string // mensagem de contexto
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 4. Agent Keys (3 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_agent_keys` | GET | `/agents/:id/keys` | read |
|
|
| `create_agent_key` | POST | `/agents/:id/keys` | write |
|
|
| `delete_agent_key` | DELETE | `/agents/:id/keys/:keyId` | destrutivo |
|
|
|
|
---
|
|
|
|
### 5. Heartbeat Runs (6 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_heartbeat_runs` | GET | `/companies/:id/heartbeat-runs` | read |
|
|
| `list_live_runs` | GET | `/companies/:id/live-runs` | read |
|
|
| `get_heartbeat_run` | GET | `/heartbeat-runs/:runId` | read |
|
|
| `get_heartbeat_run_events` | GET | `/heartbeat-runs/:runId/events` | read |
|
|
| `get_heartbeat_run_log` | GET | `/heartbeat-runs/:runId/log` | read |
|
|
| `cancel_heartbeat_run` | POST | `/heartbeat-runs/:runId/cancel` | write |
|
|
|
|
---
|
|
|
|
### 6. Issues (17 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_issues` | GET | `/companies/:id/issues` | read |
|
|
| `get_issue` | GET | `/issues/:id` | read |
|
|
| `get_issue_heartbeat_context` | GET | `/issues/:id/heartbeat-context` | read |
|
|
| `create_issue` | POST | `/companies/:id/issues` | write |
|
|
| `update_issue` | PATCH | `/issues/:id` | write |
|
|
| `delete_issue` | DELETE | `/issues/:id` | destrutivo |
|
|
| `checkout_issue` | POST | `/issues/:id/checkout` | write |
|
|
| `release_issue` | POST | `/issues/:id/release` | write |
|
|
| `get_issue_comments` | GET | `/issues/:id/comments` | read |
|
|
| `add_issue_comment` | POST | `/issues/:id/comments` | write |
|
|
| `list_issue_documents` | GET | `/issues/:id/documents` | read |
|
|
| `get_issue_document` | GET | `/issues/:id/documents/:key` | read |
|
|
| `upsert_issue_document` | PUT | `/issues/:id/documents/:key` | write |
|
|
| `delete_issue_document` | DELETE | `/issues/:id/documents/:key` | destrutivo |
|
|
| `list_issue_work_products` | GET | `/issues/:id/work-products` | read |
|
|
| `create_issue_work_product` | POST | `/issues/:id/work-products` | write |
|
|
| `list_issue_live_runs` | GET | `/issues/:id/live-runs` | read |
|
|
|
|
**Parâmetros `create_issue`:**
|
|
```typescript
|
|
{
|
|
title: string,
|
|
description?: string, // markdown
|
|
assignee_id?: string, // UUID do agente
|
|
priority?: 'low' | 'medium' | 'high' | 'urgent',
|
|
labels?: string[]
|
|
}
|
|
```
|
|
|
|
**Nota:** Issues são a forma principal de dar trabalho aos agentes.
|
|
`checkout_issue` -> agente bloqueia e começa a trabalhar.
|
|
`release_issue` -> agente liberta e fica idle.
|
|
|
|
---
|
|
|
|
### 7. Labels (3 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_labels` | GET | `/companies/:id/labels` | read |
|
|
| `create_label` | POST | `/companies/:id/labels` | write |
|
|
| `delete_label` | DELETE | `/labels/:labelId` | destrutivo |
|
|
|
|
---
|
|
|
|
### 8. Issue Attachments (4 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_issue_attachments` | GET | `/issues/:id/attachments` | read |
|
|
| `upload_issue_attachment` | POST | `/companies/:id/issues/:issueId/attachments` | write |
|
|
| `get_attachment_content` | GET | `/attachments/:attachmentId/content` | read |
|
|
| `delete_attachment` | DELETE | `/attachments/:attachmentId` | destrutivo |
|
|
|
|
---
|
|
|
|
### 9. Approvals / Governance (10 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_approvals` | GET | `/companies/:id/approvals` | read |
|
|
| `get_approval` | GET | `/approvals/:id` | read |
|
|
| `create_approval` | POST | `/companies/:id/approvals` | write |
|
|
| `list_approval_issues` | GET | `/approvals/:id/issues` | read |
|
|
| `approve_approval` | POST | `/approvals/:id/approve` | write |
|
|
| `reject_approval` | POST | `/approvals/:id/reject` | write |
|
|
| `request_approval_revision` | POST | `/approvals/:id/request-revision` | write |
|
|
| `resubmit_approval` | POST | `/approvals/:id/resubmit` | write |
|
|
| `list_approval_comments` | GET | `/approvals/:id/comments` | read |
|
|
| `add_approval_comment` | POST | `/approvals/:id/comments` | write |
|
|
|
|
---
|
|
|
|
### 10. Rotinas (8 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_routines` | GET | `/companies/:id/routines` | read |
|
|
| `get_routine` | GET | `/routines/:id` | read |
|
|
| `create_routine` | POST | `/companies/:id/routines` | write |
|
|
| `update_routine` | PATCH | `/routines/:id` | write |
|
|
| `list_routine_runs` | GET | `/routines/:id/runs` | read |
|
|
| `run_routine` | POST | `/routines/:id/run` | write |
|
|
| `create_routine_trigger` | POST | `/routines/:id/triggers` | write |
|
|
| `delete_routine_trigger` | DELETE | `/routine-triggers/:id` | destrutivo |
|
|
|
|
---
|
|
|
|
### 11. Goals (5 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_goals` | GET | `/companies/:id/goals` | read |
|
|
| `get_goal` | GET | `/goals/:id` | read |
|
|
| `create_goal` | POST | `/companies/:id/goals` | write |
|
|
| `update_goal` | PATCH | `/goals/:id` | write |
|
|
| `delete_goal` | DELETE | `/goals/:id` | destrutivo |
|
|
|
|
---
|
|
|
|
### 12. Projectos (7 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_projects` | GET | `/companies/:id/projects` | read |
|
|
| `get_project` | GET | `/projects/:id` | read |
|
|
| `create_project` | POST | `/companies/:id/projects` | write |
|
|
| `update_project` | PATCH | `/projects/:id` | write |
|
|
| `delete_project` | DELETE | `/projects/:id` | destrutivo |
|
|
| `list_project_workspaces` | GET | `/projects/:id/workspaces` | read |
|
|
| `create_project_workspace` | POST | `/projects/:id/workspaces` | write |
|
|
|
|
---
|
|
|
|
### 13. Costs / Budgets (12 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `get_cost_summary` | GET | `/companies/:id/costs/summary` | read |
|
|
| `get_costs_by_agent` | GET | `/companies/:id/costs/by-agent` | read |
|
|
| `get_costs_by_agent_model` | GET | `/companies/:id/costs/by-agent-model` | read |
|
|
| `get_costs_by_provider` | GET | `/companies/:id/costs/by-provider` | read |
|
|
| `get_costs_by_project` | GET | `/companies/:id/costs/by-project` | read |
|
|
| `get_finance_summary` | GET | `/companies/:id/costs/finance-summary` | read |
|
|
| `list_finance_events` | GET | `/companies/:id/costs/finance-events` | read |
|
|
| `get_window_spend` | GET | `/companies/:id/costs/window-spend` | read |
|
|
| `get_quota_windows` | GET | `/companies/:id/costs/quota-windows` | read |
|
|
| `get_budgets_overview` | GET | `/companies/:id/budgets/overview` | read |
|
|
| `update_company_budget` | PATCH | `/companies/:id/budgets` | write |
|
|
| `update_agent_budget` | PATCH | `/agents/:agentId/budgets` | write |
|
|
|
|
---
|
|
|
|
### 14. Activity / Audit Log (4 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_company_activity` | GET | `/companies/:id/activity` | read |
|
|
| `create_activity_entry` | POST | `/companies/:id/activity` | write |
|
|
| `list_issue_activity` | GET | `/issues/:id/activity` | read |
|
|
| `list_issue_runs` | GET | `/issues/:id/runs` | read |
|
|
|
|
---
|
|
|
|
### 15. Company Skills (6 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_company_skills` | GET | `/companies/:id/skills` | read |
|
|
| `get_company_skill` | GET | `/companies/:id/skills/:skillId` | read |
|
|
| `list_skill_files` | GET | `/companies/:id/skills/:skillId/files` | read |
|
|
| `create_company_skill` | POST | `/companies/:id/skills` | write |
|
|
| `import_company_skill` | POST | `/companies/:id/skills/import` | write |
|
|
| `delete_company_skill` | DELETE | `/companies/:id/skills/:skillId` | destrutivo |
|
|
|
|
---
|
|
|
|
### 16. Secrets (5 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_secrets` | GET | `/companies/:id/secrets` | read |
|
|
| `list_secret_providers` | GET | `/companies/:id/secret-providers` | read |
|
|
| `create_secret` | POST | `/companies/:id/secrets` | write |
|
|
| `rotate_secret` | POST | `/secrets/:id/rotate` | write |
|
|
| `delete_secret` | DELETE | `/secrets/:id` | destrutivo |
|
|
|
|
---
|
|
|
|
### 17. Execution Workspaces (3 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_execution_workspaces` | GET | `/companies/:id/execution-workspaces` | read |
|
|
| `get_execution_workspace` | GET | `/execution-workspaces/:id` | read |
|
|
| `update_execution_workspace` | PATCH | `/execution-workspaces/:id` | write |
|
|
|
|
---
|
|
|
|
### 18. Adapters / Models (2 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_adapter_models` | GET | `/companies/:id/adapters/:type/models` | read |
|
|
| `test_adapter_environment` | POST | `/companies/:id/adapters/:type/test-environment` | write |
|
|
|
|
---
|
|
|
|
### 19. Portability / Export-Import (2 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `export_company` | POST | `/companies/:id/exports` | write |
|
|
| `import_company_preview` | POST | `/companies/:id/imports/preview` | read |
|
|
|
|
---
|
|
|
|
### 20. Plugins (17 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `list_plugins` | GET | `/plugins` | read |
|
|
| `get_plugin` | GET | `/plugins/:pluginId` | read |
|
|
| `list_plugin_examples` | GET | `/plugins/examples` | read |
|
|
| `list_plugin_tools` | GET | `/plugins/tools` | read |
|
|
| `install_plugin` | POST | `/plugins/install` | write |
|
|
| `delete_plugin` | DELETE | `/plugins/:pluginId` | destrutivo |
|
|
| `enable_plugin` | POST | `/plugins/:pluginId/enable` | write |
|
|
| `disable_plugin` | POST | `/plugins/:pluginId/disable` | write |
|
|
| `upgrade_plugin` | POST | `/plugins/:pluginId/upgrade` | write |
|
|
| `get_plugin_health` | GET | `/plugins/:pluginId/health` | read |
|
|
| `get_plugin_logs` | GET | `/plugins/:pluginId/logs` | read |
|
|
| `get_plugin_config` | GET | `/plugins/:pluginId/config` | read |
|
|
| `set_plugin_config` | POST | `/plugins/:pluginId/config` | write |
|
|
| `test_plugin_config` | POST | `/plugins/:pluginId/config/test` | write |
|
|
| `get_plugin_dashboard` | GET | `/plugins/:pluginId/dashboard` | read |
|
|
| `list_plugin_jobs` | GET | `/plugins/:pluginId/jobs` | read |
|
|
| `trigger_plugin_job` | POST | `/plugins/:pluginId/jobs/:jobId/trigger` | write |
|
|
|
|
---
|
|
|
|
### 21. Assets (3 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `upload_image_asset` | POST | `/companies/:id/assets/images` | write |
|
|
| `upload_company_logo` | POST | `/companies/:id/logo` | write |
|
|
| `get_asset_content` | GET | `/assets/:assetId/content` | read |
|
|
|
|
**Nota:** Uploads usam `multipart/form-data`.
|
|
|
|
---
|
|
|
|
### 22. Instance Settings (4 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `get_general_settings` | GET | `/instance/settings/general` | read |
|
|
| `update_general_settings` | PATCH | `/instance/settings/general` | write |
|
|
| `get_experimental_settings` | GET | `/instance/settings/experimental` | read |
|
|
| `update_experimental_settings` | PATCH | `/instance/settings/experimental` | write |
|
|
|
|
---
|
|
|
|
### 23. Invites / Onboarding (7 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `create_invite` | POST | `/companies/:id/invites` | write |
|
|
| `get_invite` | GET | `/invites/:token` | read |
|
|
| `get_invite_onboarding` | GET | `/invites/:token/onboarding` | read |
|
|
| `accept_invite` | POST | `/invites/:token/accept` | write |
|
|
| `revoke_invite` | POST | `/invites/:inviteId/revoke` | write |
|
|
| `list_join_requests` | GET | `/companies/:id/join-requests` | read |
|
|
| `approve_join_request` | POST | `/companies/:id/join-requests/:requestId/approve` | write |
|
|
|
|
---
|
|
|
|
### 24. Plugin Bridge / Execution (4 tools)
|
|
|
|
| Tool | Método | Endpoint | Tipo |
|
|
|------|--------|----------|------|
|
|
| `execute_plugin_tool` | POST | `/plugins/tools/execute` | write |
|
|
| `plugin_bridge_data` | POST | `/plugins/:pluginId/bridge/data` | read |
|
|
| `plugin_bridge_action` | POST | `/plugins/:pluginId/bridge/action` | write |
|
|
| `list_ui_contributions` | GET | `/plugins/ui-contributions` | read |
|
|
|
|
---
|
|
|
|
## Endpoints Excluídos (não implementados como tools)
|
|
|
|
| Módulo | Razão |
|
|
|--------|-------|
|
|
| **CLI Auth** (challenges, approve, cancel, revoke) | Fluxo interactivo browser-based — não adequado para MCP |
|
|
| **Board Claims** (get/claim token) | Fluxo de setup inicial — uma vez por instalação |
|
|
| **LLMs** (`/llms/*.txt`) | Documentação estática — aceder directamente via HTTP |
|
|
| **Plugin SSE Stream** (`/plugins/:id/bridge/stream/:channel`) | SSE stream contínuo — não compatível com request/response MCP |
|
|
| **Admin Operations** (promote/demote instance admin, user company access) | Operações privilegiadas de super-admin — proteger de uso acidental |
|
|
|
|
---
|
|
|
|
## Variáveis de Ambiente
|
|
|
|
```bash
|
|
# .env.example
|
|
PAPERCLIP_API_URL=https://clip.descomplicar.pt/api
|
|
PAPERCLIP_API_KEY=pcp_mcp_... # Board API Key gerada pelo script
|
|
PAPERCLIP_COMPANY_ID=ebe10308-efd7-453f-86ab-13e6fe84004f
|
|
|
|
# HTTP/SSE transport
|
|
HTTP_PORT=3168
|
|
```
|
|
|
|
**`PAPERCLIP_COMPANY_ID` injectado automaticamente** nas tools que precisam de `:companyId`,
|
|
sem obrigar o utilizador a passá-lo em cada chamada.
|
|
|
|
---
|
|
|
|
## Cliente HTTP (`src/client.ts`)
|
|
|
|
```typescript
|
|
export class PaperclipClient {
|
|
private baseUrl: string;
|
|
private companyId: string;
|
|
private headers: Record<string, string>;
|
|
|
|
constructor() {
|
|
this.baseUrl = process.env.PAPERCLIP_API_URL ?? 'https://clip.descomplicar.pt/api';
|
|
this.companyId = process.env.PAPERCLIP_COMPANY_ID ?? '';
|
|
this.headers = {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer ${process.env.PAPERCLIP_API_KEY}`,
|
|
};
|
|
}
|
|
|
|
async get<T>(path: string, params?: Record<string, string>): Promise<T>
|
|
async post<T>(path: string, body?: unknown): Promise<T>
|
|
async patch<T>(path: string, body?: unknown): Promise<T>
|
|
async put<T>(path: string, body?: unknown): Promise<T>
|
|
async delete<T>(path: string): Promise<T>
|
|
|
|
// Helpers com company_id injectado
|
|
companyPath(suffix: string): string {
|
|
return `/companies/${this.companyId}${suffix}`;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Tool Annotations
|
|
|
|
```typescript
|
|
// Aplicar inferAnnotations() a todas as tools:
|
|
// list_*, get_* → readOnlyHint: true
|
|
// delete_*, terminate_* → destructiveHint: true
|
|
// update_*, patch_* → idempotentHint: true
|
|
// create_*, add_*, checkout_*, release_*, approve_*, reject_* → write normal
|
|
// run_*, invoke_*, wakeup_*, fire_* → write (side-effects)
|
|
```
|
|
|
|
---
|
|
|
|
## Configuração `~/.claude.json`
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"paperclip": {
|
|
"command": "node",
|
|
"args": ["/home/ealmeida/mcp-servers/mcp-paperclip/dist/index.js"],
|
|
"env": {
|
|
"PAPERCLIP_API_URL": "https://clip.descomplicar.pt/api",
|
|
"PAPERCLIP_API_KEY": "pcp_mcp_...",
|
|
"PAPERCLIP_COMPANY_ID": "ebe10308-efd7-453f-86ab-13e6fe84004f"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Plano de Implementação (6 sprints)
|
|
|
|
### Sprint 1 — Fundação + Health + Agentes (read-only)
|
|
**Objectivo:** MCP operacional com tools de leitura base
|
|
|
|
- [ ] `npm init` + dependências (`@modelcontextprotocol/sdk`, `zod`, `dotenv`, `winston`)
|
|
- [ ] DevDeps: TypeScript, ESLint, Prettier, Jest, Husky
|
|
- [ ] `tsconfig.json`, `eslint.config.js`, `.prettierrc`, `.gitignore`
|
|
- [ ] `src/client.ts` — PaperclipClient com auth Bearer e métodos GET/POST/PATCH/PUT/DELETE
|
|
- [ ] `src/utils/logger.ts` — logger MCP-compatible (stderr, sem cores)
|
|
- [ ] `src/utils/annotations.ts` — inferAnnotations
|
|
- [ ] `src/server.ts` — createServer com capabilities completas
|
|
- [ ] `src/index.ts` — entry STDIO
|
|
- [ ] `src/index-http.ts` — entry StreamableHTTP + SSE porta 3175 (stateless)
|
|
- [ ] `scripts/create-api-key.sh` — script criação Board API Key
|
|
- [ ] Tools `health.ts`: `get_health`
|
|
- [ ] Tools `company.ts`: `get_company`, `list_companies`, `get_company_stats`, `get_org_chart`, `get_dashboard`, `get_sidebar_badges`
|
|
- [ ] Tools `agents.ts` (read): `list_agents`, `get_agent`, `get_agent_runtime_state`, `get_agent_configuration`, `get_agent_config_revisions`, `get_agent_skills`, `get_agent_task_sessions`, `get_agent_instructions_bundle`
|
|
- [ ] `.env.example`, `CLAUDE.md`, `CHANGELOG.md`, `README.md`
|
|
- [ ] Testes básicos das tools read
|
|
- [ ] `npm run quality:check` passa
|
|
- [ ] Repo Gitea criado, CI verde
|
|
|
|
**Critério de aceitação Sprint 1:**
|
|
`list_agents` devolve os 64 agentes da Descomplicar via STDIO.
|
|
|
|
---
|
|
|
|
### Sprint 2 — Issues + Write Operations Agentes
|
|
**Objectivo:** CRUD completo de issues e operações write em agentes
|
|
|
|
- [ ] Tools `issues.ts`: list, get, create, update, delete, comments, checkout, release, documents, work-products, heartbeat-context, live-runs (17 tools)
|
|
- [ ] Tools `labels.ts`: list, create, delete (3 tools)
|
|
- [ ] Tools `attachments.ts`: list, upload, get_content, delete (4 tools)
|
|
- [ ] Tools `agents.ts` (write): create, create_hire, update, update_permissions, update_instructions_path, update_instructions_bundle, rollback_config, sync_skills, pause, resume, wakeup, invoke_heartbeat, terminate, delete (14 tools)
|
|
- [ ] Tools `agent_keys.ts`: list, create, delete (3 tools)
|
|
- [ ] Validação Zod em inputs de write
|
|
- [ ] Tratamento de erros HTTP (401, 403, 404, 422) -> mensagens úteis
|
|
- [ ] Testes issues e write ops
|
|
- [ ] Actualizar `~/.claude.json` com MCP configurado
|
|
- [ ] Smoke test: criar issue, atribuir ao Reality Checker, fazer checkout
|
|
|
|
**Critério de aceitação Sprint 2:**
|
|
Claude Code consegue criar uma issue, assignar a um agente e fazer checkout via MCP.
|
|
|
|
---
|
|
|
|
### Sprint 3 — Routines, Goals, Projects, Approvals
|
|
**Objectivo:** Workflows completos de gestão e governance
|
|
|
|
- [ ] Tools `routines.ts`: list, get, create, update, list_runs, run, create_trigger, delete_trigger (8 tools)
|
|
- [ ] Tools `goals.ts`: list, get, create, update, delete (5 tools)
|
|
- [ ] Tools `projects.ts`: list, get, create, update, delete, list_workspaces, create_workspace (7 tools)
|
|
- [ ] Tools `approvals.ts`: list, get, create, list_issues, approve, reject, request_revision, resubmit, comments (10 tools)
|
|
- [ ] Testes de workflows: criar goal -> criar issue -> aprovar -> executar
|
|
|
|
**Critério de aceitação Sprint 3:**
|
|
Workflow completo de governance: criar approval, aprovar, verificar estado.
|
|
|
|
---
|
|
|
|
### Sprint 4 — Costs, Activity, Skills, Secrets, Workspaces
|
|
**Objectivo:** Observabilidade e gestão operacional
|
|
|
|
- [ ] Tools `costs.ts`: summary, by-agent, by-model, by-provider, by-project, finance, budgets (12 tools)
|
|
- [ ] Tools `activity.ts`: company activity, issue activity, issue runs (4 tools)
|
|
- [ ] Tools `skills.ts`: list, get, files, create, import, delete (6 tools)
|
|
- [ ] Tools `secrets.ts`: list, providers, create, rotate, delete (5 tools)
|
|
- [ ] Tools: execution_workspaces (3 tools), adapters (2 tools), portability (2 tools)
|
|
- [ ] Tools `company.ts` (write): update, update_branding, members, update_member_permissions
|
|
- [ ] Heartbeat runs: list, live, get, events, log, cancel (6 tools)
|
|
- [ ] Testes de observabilidade
|
|
|
|
**Critério de aceitação Sprint 4:**
|
|
`get_cost_summary` + `get_budgets_overview` retornam dados reais.
|
|
|
|
---
|
|
|
|
### Sprint 5 — Plugins, Assets, Settings, Access
|
|
**Objectivo:** Gestão de plugins, assets, configuração e onboarding
|
|
|
|
- [ ] Tools `plugins.ts`: list, get, examples, tools, install, delete, enable, disable, upgrade, health, logs, config, dashboard, jobs, trigger (17 tools)
|
|
- [ ] Tools `plugin_bridge.ts`: execute_tool, bridge_data, bridge_action, ui_contributions (4 tools)
|
|
- [ ] Tools `assets.ts`: upload_image, upload_logo, get_content (3 tools) — suporte multipart/form-data no client
|
|
- [ ] Tools `settings.ts`: get/update general, get/update experimental (4 tools)
|
|
- [ ] Tools `access.ts`: create_invite, get_invite, get_onboarding, accept_invite, revoke_invite, list_join_requests, approve_join_request (7 tools)
|
|
- [ ] Testes de plugins e settings
|
|
|
|
**Critério de aceitação Sprint 5:**
|
|
`list_plugins` + `install_plugin` + `get_plugin_health` funcionais.
|
|
|
|
---
|
|
|
|
### Sprint 6 — Gateway Deploy + CI/CD + Documentação
|
|
**Objectivo:** Deploy produção + cobertura total
|
|
|
|
- [ ] Deploy no gateway (5.9.90.69) via PM2
|
|
- [ ] Registar porta 3175 no `port-map.json` do gateway
|
|
- [ ] CI/CD workflow Gitea (`.gitea/workflows/deploy.yml`)
|
|
- [ ] Actualizar `~/.claude/_resources/mcps.json`
|
|
- [ ] Actualizar `QR-Servidores.md` com novo MCP
|
|
- [ ] `docs/API_REFERENCE.md` completo
|
|
- [ ] Testes integração end-to-end (todas as 159 tools)
|
|
- [ ] Smoke test final: workflow completo via gateway StreamableHTTP
|
|
|
|
**Critério de aceitação Sprint 6:**
|
|
Todas as 159 tools operacionais via STDIO + StreamableHTTP + SSE. CI verde.
|
|
|
|
---
|
|
|
|
## Critérios de Qualidade (pré-entrega)
|
|
|
|
```
|
|
[ ] Zero erros ESLint
|
|
[ ] Testes passam: npm run test
|
|
[ ] Build sem erros: npm run build
|
|
[ ] Capabilities completas (tools + resources + prompts)
|
|
[ ] Nomenclatura snake_case em todas as tools
|
|
[ ] Triple transport funcional (STDIO + StreamableHTTP + SSE na porta 3175)
|
|
[ ] Stateless (sessionIdGenerator: undefined)
|
|
[ ] Logger para stderr (nunca stdout em STDIO mode)
|
|
[ ] .env.example sem valores reais
|
|
[ ] CHANGELOG.md iniciado
|
|
[ ] CI verde no Gitea
|
|
[ ] 159 tools operacionais
|
|
```
|
|
|
|
---
|
|
|
|
## Dependências
|
|
|
|
```json
|
|
{
|
|
"dependencies": {
|
|
"@modelcontextprotocol/sdk": "^1.10.0",
|
|
"dotenv": "^16.4.7",
|
|
"winston": "^3.17.0",
|
|
"zod": "^3.24.0"
|
|
},
|
|
"devDependencies": {
|
|
"@types/node": "^22.0.0",
|
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
"@typescript-eslint/parser": "^7.18.0",
|
|
"eslint": "^8.57.1",
|
|
"jest": "^30.0.5",
|
|
"prettier": "^3.6.2",
|
|
"ts-jest": "^29.4.0",
|
|
"typescript": "^5.3.3"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Notas de Implementação
|
|
|
|
1. **`PAPERCLIP_COMPANY_ID` como constante** — injectar em todas as tools que precisam de `:companyId`, nunca expor como parâmetro obrigatório ao utilizador.
|
|
|
|
2. **Erros da API Paperclip** — mapear para mensagens claras:
|
|
- `401/403` -> "Sem autorização. Verificar `PAPERCLIP_API_KEY`."
|
|
- `404` -> "Recurso não encontrado: {id}"
|
|
- `422` -> incluir erros de validação da resposta
|
|
|
|
3. **`get_org_chart`** — retorna JSON da hierarquia de agentes, não o SVG. Usar `/companies/:id/org` (JSON) e não `/org.svg`.
|
|
|
|
4. **`wakeup_agent`** — o Paperclip acorda agentes via heartbeat; útil para forçar execução de uma rotina ou atribuir uma issue urgente.
|
|
|
|
5. **`checkout_issue`** — permite ao Claude Code "reservar" uma issue enquanto trabalha nela, sinalizando que está em curso.
|
|
|
|
6. **`create_agent_hire`** — usa governance/approval workflow. Preferível a `create_agent` directo quando há supervisão activa.
|
|
|
|
7. **Idempotência** — `create_agent` com mesmo `name` pode criar duplicado. Adicionar verificação prévia com `list_agents` se necessário.
|
|
|
|
8. **Costs** — endpoints de custos aceitam query params `from`, `to` (ISO dates) para filtragem temporal.
|
|
|
|
9. **Secrets** — valores nunca são retornados em plain text. Apenas metadados (nome, provider, criação).
|
|
|
|
10. **Attachments e Assets** — uploads usam `multipart/form-data`. O client precisa de suportar este content-type para `upload_issue_attachment`, `upload_image_asset` e `upload_company_logo`.
|
|
|
|
11. **Plugins** — `install_plugin` aceita URL ou path para o plugin. `execute_plugin_tool` permite invocar tools expostas por plugins instalados.
|
|
|
|
12. **Instance Settings** — alterações a `experimental` podem activar/desactivar funcionalidades em beta. Usar com cautela.
|
|
|
|
13. **Invites** — `create_invite` gera token único para onboarding de novos agentes. O fluxo completo: create -> partilhar token -> accept.
|
|
|
|
14. **Plugin Bridge** — `plugin_bridge_data` e `plugin_bridge_action` permitem comunicação directa com plugins via data/action pattern.
|
|
|
|
---
|
|
|
|
*SPEC criado em 07-04-2026 | Actualizado em 07-04-2026 (cobertura completa API v0.3.1)*
|
|
*Baseado no PROC-MCP-Desenvolvimento.md v2.5 + análise directa do código-fonte Paperclip*
|