Files
claude-plugins/infraestrutura/skills/mcp-dev/SKILL.md
Emanuel Almeida 9404af7ac9 feat: sync all plugins, skills, agents updates
New plugins: core-tools
New skills: auto-expense, ticket-triage, design, security-check,
  aiktop-tasks, daily-digest, imap-triage, index-update, mindmap,
  notebooklm, proc-creator, tasks-overview, validate-component,
  perfex-module, report, calendar-manager
New agents: design-critic, design-generator, design-lead,
  design-prompt-architect, design-researcher, compliance-auditor,
  metabase-analyst, gitea-integration-specialist
Updated: all plugin configs, knowledge datasets, existing skills

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:16:32 +00:00

1150 lines
28 KiB
Markdown

---
name: mcp-dev
description: MCP server development and testing. Creates new MCP servers following
Descomplicar standards with SSE transport. Use when user mentions "mcp development",
"novo mcp", "criar mcp", "mcp server", "mcp testing".
author: Descomplicar® Crescimento Digital
version: 1.3.0
quality_score: 75
user_invocable: true
desk_task: 1476
allowed-tools: Grep
---
# /mcp-dev - Desenvolvimento de MCPs
Skill para criação, configuração e gestão de servidores MCP customizados.
> **Regra #48:** Novos MCPs devem ser desenvolvidos no **container dev** (`server:"dev"`, path `/root/Dev/<nome-mcp>`). O path `/home/ealmeida/mcp-servers/` é para MCPs já em produção. Desenvolvimento inicial -> `/root/Dev/` -> depois mover para `mcp-servers/` no deploy final.
---
## Comandos
| Comando | Descrição |
|---------|-----------|
| `/mcp-dev create <nome>` | Criar novo MCP (scaffold TypeScript) |
| `/mcp-dev config <nome>` | Configurar MCP em ~/.claude.json |
| `/mcp-dev test <nome>` | Testar conexão e ferramentas |
| `/mcp-dev docs <nome>` | Gerar documentação Obsidian |
| `/mcp-dev list` | Listar MCPs instalados |
| `/mcp-dev status` | Estado dos MCPs activos |
---
## Estrutura MCP Padrão
```
~/mcp-servers/<nome>/
├── package.json
├── tsconfig.json
├── src/
│ ├── index.ts # Entry point
│ ├── tools/ # Ferramentas MCP
│ │ └── example.ts
│ └── types.ts # Tipos TypeScript
├── README.md
├── .env.example
└── .gitignore
```
---
## /mcp-dev create <nome>
Cria scaffold completo para novo MCP.
### Execução
```
1. Criar pasta ~/mcp-servers/<nome>/
2. Gerar package.json com dependências MCP
3. Gerar tsconfig.json
4. Criar src/index.ts com estrutura base
5. Criar README.md
6. Criar .env.example
7. npm install
8. Sugerir configuração
```
### Template package.json
```json
{
"name": "mcp-<nome>",
"version": "1.0.0",
"type": "module",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx src/index.ts"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"zod": "^3.22.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^5.0.0",
"tsx": "^4.0.0"
}
}
```
### Template index.ts
```typescript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
const server = new Server(
{
name: 'mcp-<nome>',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'example_tool',
description: 'Descrição da ferramenta',
inputSchema: {
type: 'object',
properties: {
param: {
type: 'string',
description: 'Parâmetro exemplo',
},
},
required: ['param'],
},
},
],
}));
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case 'example_tool':
return {
content: [
{
type: 'text',
text: `Resultado: ${args?.param}`,
},
],
};
default:
throw new Error(`Unknown tool: ${name}`);
}
});
// Start server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('MCP Server running on stdio');
}
main().catch(console.error);
```
---
## /mcp-dev config <nome>
Adiciona MCP ao ficheiro de configuração.
### Claude Code (~/.claude.json)
```json
{
"mcpServers": {
"<nome>": {
"command": "node",
"args": ["/home/ealmeida/mcp-servers/<nome>/dist/index.js"],
"env": {}
}
}
}
```
### Claude Desktop (~/.config/claude/claude_desktop_config.json)
```json
{
"mcpServers": {
"<nome>": {
"command": "node",
"args": ["/home/ealmeida/mcp-servers/<nome>/dist/index.js"]
}
}
}
```
### Verificação
```bash
# Testar se compila
cd ~/mcp-servers/<nome> && npm run build
# Testar manualmente
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node dist/index.js
```
---
## /mcp-dev test <nome>
Testa conexão e lista ferramentas disponíveis.
### Output Esperado
```
🔧 MCP Test: <nome>
──────────────────
Status: ✅ Conectado
Versão: 1.0.0
Transport: stdio
Ferramentas (3):
• tool_1 - Descrição
• tool_2 - Descrição
• tool_3 - Descrição
Recursos (0):
(nenhum)
Prompts (0):
(nenhum)
```
---
## /mcp-dev docs <nome>
Gera documentação Obsidian para o MCP.
### Output
Cria `Stack/Claude Code/MCPs/MCP-<Nome>.md`:
```markdown
---
title: MCP <Nome>
date: YYYY-MM-DD
type: mcp
status: active
tags: [mcp, <nome>]
---
# MCP <Nome>
Descrição do MCP.
## Ferramentas
| Tool | Descrição | Parâmetros |
|------|-----------|------------|
| tool_1 | ... | param1, param2 |
## Configuração
...
## Exemplos
...
```
---
## /mcp-dev list
Lista todos os MCPs em ~/mcp-servers/.
### Output
```
📋 MCPs Instalados
──────────────────
~/mcp-servers/
├── desk-crm-v3/ ✅ Configurado
├── memory-supabase/ ✅ Configurado
├── google-workspace/ ✅ Configurado
├── novo-mcp/ ⚠️ Não configurado
└── teste/ ❌ Não compila
Total: 5 | Activos: 3 | Pendentes: 2
```
---
## /mcp-dev status
Estado dos MCPs activos na sessão.
### Output
```
🔌 MCPs Activos
───────────────
✅ desk-crm-v3 (15 tools)
✅ memory-supabase (5 tools)
✅ google-workspace (42 tools)
✅ filesystem (8 tools)
⚠️ youtube-uploader (auth required)
Total: 5 | OK: 4 | Problemas: 1
```
---
## Padrões de Desenvolvimento
### Limites de Nomes de Tools
> **REGRA 31/01/2026:** Nomes de tools MCP têm limite de caracteres.
| Limite | Valor | Cálculo |
|--------|-------|---------|
| Tool name | **≤40 chars** | Nome da função |
| Total com prefixo | **≤64 chars** | `mcp__<server>__<tool_name>` |
**Exemplo:**
```
mcp__desk-crm-v3__get_customer_notes
└─────────┘ └────────────────┘
server=12 tool_name=18 = 30 chars ✅
mcp__desk-crm-v3__get_customer_alternate_addresses_with_details
└─────────┘ └──────────────────────────────────────────┘
server=12 tool_name=46 = 58 chars ❌ (tool > 40)
```
**Validação recomendada:**
```typescript
function validateToolName(name: string): void {
if (name.length > 40) {
throw new Error(`Tool name "${name}" exceeds 40 char limit (${name.length})`);
}
}
// Aplicar a todas as tools no array
allTools.forEach(t => validateToolName(t.name));
```
---
### Error Handling
```typescript
try {
// operação
} catch (error) {
return {
content: [{
type: 'text',
text: `Erro: ${error instanceof Error ? error.message : 'Unknown error'}`,
}],
isError: true,
};
}
```
### Validação com Zod
```typescript
import { z } from 'zod';
const InputSchema = z.object({
param: z.string().min(1),
optional: z.number().optional(),
});
// No handler
const validated = InputSchema.parse(args);
```
### Logging
```typescript
// Usar console.error (não console.log - interfere com stdio)
console.error(`[MCP] Processing: ${param}`);
```
---
## Transporte HTTP (StreamableHTTP) - RECOMENDADO
**Padrão oficial MCP SDK.** Usar para todos os novos MCPs.
### Vantagens HTTP vs SSE
| Aspecto | HTTP (StreamableHTTP) | SSE (deprecated) |
|---------|----------------------|------------------|
| Padrão | ✅ Oficial MCP SDK | ⚠️ Deprecated |
| Stateless | ✅ Suportado | ❌ Sempre stateful |
| Simplicidade | ✅ Um endpoint | ❌ /sse + /message |
| Gate ready | ✅ REST-like | ❌ Streaming complexo |
### Template index-http.ts (PADRÃO)
```typescript
#!/usr/bin/env node
/**
* MCP <Nome> - HTTP Server Mode
* StreamableHTTP transport for web/remote access
* @author Descomplicar® | @link descomplicar.pt | @copyright 2026
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import {
ListToolsRequestSchema,
CallToolRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import * as http from 'http';
import { URL } from 'url';
import { randomUUID } from 'crypto';
const PORT = parseInt(process.env.MCP_HTTP_PORT || '32XX', 10);
const HOST = process.env.MCP_HTTP_HOST || '127.0.0.1';
const STATEFUL = process.env.MCP_STATEFUL !== 'false';
// Track active sessions (stateful mode)
const sessions = new Map<string, { transport: StreamableHTTPServerTransport }>();
// Define tools array
const allTools = [
{
name: 'example_tool',
description: 'Descrição da ferramenta',
inputSchema: {
type: 'object',
properties: {
param: { type: 'string', description: 'Parâmetro exemplo' }
},
required: ['param']
},
handler: async (args: any) => ({
content: [{ type: 'text', text: `Resultado: ${args.param}` }]
})
}
];
function createMcpServer(): Server {
const server = new Server(
{ name: 'mcp-nome', version: '1.0.0' },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: allTools.map(t => ({
name: t.name,
description: t.description,
inputSchema: t.inputSchema
}))
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
const tool = allTools.find(t => t.name === name);
if (!tool) {
return { content: [{ type: 'text', text: `Tool not found: ${name}` }] };
}
try {
return await tool.handler(args);
} catch (error) {
return {
content: [{
type: 'text',
text: `Error: ${error instanceof Error ? error.message : String(error)}`
}],
isError: true
};
}
});
return server;
}
async function main() {
const httpServer = http.createServer(async (req, res) => {
// CORS headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Mcp-Session-Id');
if (req.method === 'OPTIONS') {
res.writeHead(200);
res.end();
return;
}
const url = new URL(req.url || '/', `http://${HOST}:${PORT}`);
// Health check endpoint
if (url.pathname === '/health') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
status: 'ok',
transport: 'streamable-http',
version: '1.0.0',
sessions: sessions.size,
stateful: STATEFUL,
tools: allTools.length
}));
return;
}
// Stats endpoint
if (url.pathname === '/stats') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
totalTools: allTools.length,
activeSessions: sessions.size
}, null, 2));
return;
}
// MCP endpoint
if (url.pathname === '/mcp') {
try {
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: STATEFUL ? () => randomUUID() : undefined
});
const server = createMcpServer();
if (STATEFUL && transport.sessionId) {
sessions.set(transport.sessionId, { transport });
transport.onclose = () => {
if (transport.sessionId) {
sessions.delete(transport.sessionId);
}
};
}
await server.connect(transport);
await transport.handleRequest(req, res);
} catch (error) {
if (!res.headersSent) {
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Internal server error' }));
}
}
return;
}
// 404
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Not found' }));
});
httpServer.listen(PORT, HOST, () => {
console.log(`MCP HTTP Server v1.0.0`);
console.log(` Endpoint: http://${HOST}:${PORT}/mcp`);
console.log(` Health: http://${HOST}:${PORT}/health`);
console.log(` Mode: ${STATEFUL ? 'Stateful' : 'Stateless'}`);
console.log(` Tools: ${allTools.length}`);
});
// Graceful shutdown
const shutdown = () => {
httpServer.close(() => process.exit(0));
};
process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);
}
main().catch(console.error);
```
### Configuração HTTP
```json
// ~/.claude.json - HTTP transport
{
"mcpServers": {
"meu-mcp": {
"type": "http",
"url": "http://127.0.0.1:32XX/mcp"
}
}
}
```
### Portas HTTP Reservadas
| Porta | MCP | Estado |
|-------|-----|--------|
| 3200 | outline-postgresql | ✅ HTTP |
| 3201+ | disponíveis | - |
### Scripts package.json (HTTP)
```json
{
"scripts": {
"start:http": "node dist/index-http.js",
"dev:http": "tsx src/index-http.ts",
"reload:http": "npm run build && systemctl --user restart mcp-nome && sleep 2 && curl -s http://127.0.0.1:32XX/health"
}
}
```
---
## Transporte SSE (Server-Sent Events) - DEPRECATED
⚠️ **DEPRECATED:** Usar HTTP (StreamableHTTP) para novos MCPs. SSE mantido apenas para retrocompatibilidade.
Para MCPs que precisam de conexao persistente (ex: Claude Code com multiplos terminais).
**IMPORTANTE:** Verificar MCPs existentes (desk-crm-v3, moloni) antes de implementar!
### Configuracao SSE
```json
// ~/.claude.json
{
"mcpServers": {
"meu-mcp": {
"type": "sse",
"url": "http://127.0.0.1:31XX/sse"
}
}
}
```
### Template index-sse.ts (http nativo - RECOMENDADO)
```typescript
#!/usr/bin/env node
/** @author Descomplicar | @link descomplicar.pt | @copyright 2026 */
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import {
ListToolsRequestSchema,
CallToolRequestSchema,
ListResourcesRequestSchema,
ListPromptsRequestSchema
} from '@modelcontextprotocol/sdk/types.js';
import * as http from 'http';
import { URL } from 'url';
const PORT = parseInt(process.env.MCP_SSE_PORT || '31XX');
const HOST = process.env.MCP_SSE_HOST || '127.0.0.1';
// Track active sessions
const sessions = new Map<string, SSEServerTransport>();
// Define tools array
const allTools = [
// ... your tools
];
// Create MCP server for each session
function createMcpServer(): Server {
const server = new Server({
name: 'mcp-nome',
version: '1.0.0'
});
// Set capabilities
(server as any)._capabilities = {
tools: {},
resources: {},
prompts: {}
};
// List tools
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: allTools.map((t) => ({
name: t.name,
description: t.description,
inputSchema: t.inputSchema
}))
}));
// List resources (empty)
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: []
}));
// List prompts (empty)
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
prompts: []
}));
// Call tool
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
const tool = allTools.find((t) => t.name === name);
if (!tool) {
return { content: [{ type: 'text', text: 'Tool not found' }] };
}
try {
return await tool.handler(args);
} catch (error) {
return {
content: [{
type: 'text',
text: `Error: ${error instanceof Error ? error.message : String(error)}`
}]
};
}
});
return server;
}
async function main() {
const httpServer = http.createServer(async (req, res) => {
// CORS headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') {
res.writeHead(200);
res.end();
return;
}
const url = new URL(req.url || '/', `http://${HOST}:${PORT}`);
// Health check
if (url.pathname === '/health') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
status: 'ok',
sessions: sessions.size,
tools: allTools.length
}));
return;
}
// SSE endpoint - new session
if (url.pathname === '/sse' && req.method === 'GET') {
const transport = new SSEServerTransport('/message', res);
const sessionId = transport.sessionId; // USAR sessionId do transport!
sessions.set(sessionId, transport);
// Criar NOVO server por sessao
const server = createMcpServer();
transport.onclose = () => {
sessions.delete(sessionId);
};
await server.connect(transport);
return;
}
// Message endpoint
if (url.pathname === '/message' && req.method === 'POST') {
const sessionId = url.searchParams.get('sessionId');
if (!sessionId) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Missing sessionId' }));
return;
}
const transport = sessions.get(sessionId);
if (!transport) {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Session not found' }));
return;
}
await transport.handlePostMessage(req, res);
return;
}
// 404
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Not found' }));
});
httpServer.listen(PORT, HOST, () => {
console.log(`MCP SSE Server running at http://${HOST}:${PORT}/sse`);
});
// Graceful shutdown
process.on('SIGTERM', () => httpServer.close(() => process.exit(0)));
process.on('SIGINT', () => httpServer.close(() => process.exit(0)));
}
main().catch(console.error);
```
### Pontos Criticos SSE
| Aspecto | Correcto | Errado |
|---------|----------|--------|
| sessionId | `transport.sessionId` | `Date.now().toString()` |
| Server | Novo por sessao | Reutilizar mesmo |
| HTTP | `http.createServer` | Express (overhead) |
| /message | Com `?sessionId=` | Sem sessionId |
### Template systemd Service
Criar em `~/.config/systemd/user/mcp-nome.service`:
```ini
[Unit]
Description=MCP Nome SSE Server
After=network.target
[Service]
Type=simple
WorkingDirectory=/home/ealmeida/mcp-servers/mcp-nome
ExecStart=/home/ealmeida/.nvm/versions/node/v22.18.0/bin/node dist/index.js --sse --port 31XX
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production
Environment=LOG_LEVEL=error
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=default.target
```
### Comandos systemd
```bash
# Activar
systemctl --user daemon-reload
systemctl --user enable mcp-nome.service
systemctl --user start mcp-nome.service
# Ver estado
systemctl --user status mcp-nome
# Ver logs
journalctl --user -u mcp-nome -f
# Reiniciar apos alteracoes
systemctl --user restart mcp-nome
```
### Portas SSE Reservadas
| Porta | MCP |
|-------|-----|
| 3100 | desk-crm-v3 |
| 3101 | memory-supabase |
| 3102 | wikijs |
| 3103 | ssh-unified |
| 3104 | dify-kb |
| 3105 | n8n |
| 3106 | cwp |
| 3107 | youtube-research |
| 3108 | moloni |
| 3109+ | disponiveis |
### Script de Desenvolvimento (reload:sse)
Adicionar ao `package.json`:
```json
{
"scripts": {
"start:sse": "node dist/index.js --sse",
"reload:sse": "npm run build && systemctl --user restart mcp-nome && sleep 2 && curl -s http://127.0.0.1:31XX/health"
}
}
```
---
## Padrões SQL (Perfex CRM)
Para MCPs que integram com Perfex CRM:
### Campos FK (Foreign Keys)
```typescript
// CORRECTO: Perfex usa 0 como "não definido", NÃO NULL
client_id || 0,
project_id || 0,
country || 0,
assigned || 0,
// EXCEPÇÃO: source em leads precisa ID válido (buscar da BD)
let leadSource = source;
if (!leadSource) {
const [defaultSource] = await client.query(
'SELECT id FROM tblleads_sources ORDER BY id ASC LIMIT 1'
);
leadSource = defaultSource?.id || 1;
}
```
### Padrão de Fallback
```typescript
// Para campos que aceitam 0 como default
field || 0
// Para campos que precisam valor válido da BD
const defaultValue = await getDefaultFromDB();
field || defaultValue
```
### Tabelas Perfex (prefixo tbl)
```
tblclients, tblprojects, tbltasks, tblinvoices,
tblleads, tblleads_sources, tblleads_status,
tblstaff, tbltaskstimers, tblexpenses
```
---
## Checklist de Segurança MCP
**Baseado em audit MCP Outline PostgreSQL (164 tools, 7 bugs corrigidos).**
### Antes de Commit
- [ ] **SQL Injection:** Todos os inputs validados antes de entrar em queries?
```typescript
// ERRADO: interpolação directa
const query = `ORDER BY ${field} ASC`;
// CORRECTO: validar primeiro
validateFieldName(field); // rejeita keywords SQL
const query = `ORDER BY ${field} ASC`;
```
- [ ] **Transações:** Operações multi-query relacionadas em transação?
```typescript
// ERRADO: queries separadas
await query('DELETE FROM children WHERE parentId = $1', [id]);
await query('DELETE FROM parents WHERE id = $1', [id]);
// CORRECTO: transação
await withTransaction(async (client) => {
await client.query('DELETE FROM children WHERE parentId = $1', [id]);
await client.query('DELETE FROM parents WHERE id = $1', [id]);
});
```
- [ ] **Recursos:** Aquisição tem `finally` com release?
```typescript
// ERRADO: release pode não executar
const client = await pool.connect();
await client.query('SELECT 1');
client.release();
// CORRECTO: finally garante release
let client = null;
try {
client = await pool.connect();
await client.query('SELECT 1');
} finally {
if (client) client.release();
}
```
- [ ] **Cleanup:** Código de cleanup tem try-catch próprio?
```typescript
// ERRADO: ROLLBACK pode falhar e mascarar erro
catch (error) {
await client.query('ROLLBACK');
throw error;
}
// CORRECTO: ROLLBACK com try-catch
catch (error) {
try {
await client.query('ROLLBACK');
} catch (rollbackError) {
console.error('Rollback failed', rollbackError);
}
throw error;
}
```
- [ ] **Random:** Usando `crypto.randomBytes()` e não `Math.random()`?
- [ ] **Versão:** Sincronizada com package.json?
### Grep de Validação
```bash
# Verificar interpolação SQL perigosa
grep -rn '`.*\${.*}`' src/ | grep -i 'select\|insert\|update\|delete\|order'
# Verificar Math.random em produção
grep -rn 'Math.random' src/
# Verificar .connect() sem finally
grep -rn '\.connect()' src/
```
---
## MCPs Existentes (Referência)
| MCP | Path | Tools |
|-----|------|-------|
| desk-crm-v3 | ~/mcp-servers/desk-crm-v3/ | 150+ |
| memory-supabase | ~/mcp-servers/memory-supabase/ | 5 |
| google-workspace | (npm package) | 42 |
| filesystem | (npm package) | 8 |
---
## Integração com Agente
O agente `mcp-protocol-developer` é invocado para:
- Desenvolvimento complexo de ferramentas
- Debug de problemas MCP
- Optimização de performance
- Implementação de recursos avançados
---
## Datasets Dify
```
mcp__notebooklm__notebook_query, mcp__dify-kb__dify_kb_retrieve_segments dataset:"MCP Servers" query:"..."
mcp__dify-kb__dify_kb_retrieve_segments dataset:"Claude Code" query:"..."
mcp__dify-kb__dify_kb_retrieve_segments dataset:"Desenvolvimento de Software" query:"..."
```
---
## Referências e Documentação
### Procedimentos Obrigatórios (D7-Tecnologia)
**SEMPRE consultar antes de criar/modificar MCPs:**
- **[PROC-MCP-Desenvolvimento.md](file:///media/ealmeida/Dados/Hub/06-Operacoes/Procedimentos/D7-Tecnologia/MCP/PROC-MCP-Desenvolvimento.md)** - Guia oficial v2.3: Regra de Ouro MCP, capabilities obrigatórias, validação pre-deploy, fallback enterprise
- **[PROC-MCP-Troubleshooting-Erro-471.md](file:///media/ealmeida/Dados/Hub/06-Operacoes/Procedimentos/D7-Tecnologia/MCP/PROC-MCP-Troubleshooting-Erro-471.md)** - Debug erro 471 (capabilities incompletas, too many requests)
- **[PROC-MCP-Google-Auth.md](file:///media/ealmeida/Dados/Hub/06-Operacoes/Procedimentos/D7-Tecnologia/MCP/PROC-MCP-Google-Auth.md)** - Autenticação OAuth Google Workspace, refresh tokens, troubleshooting
- **[PROC-MCP-Session-Recovery.md](file:///media/ealmeida/Dados/Hub/06-Operacoes/Procedimentos/D7-Tecnologia/MCP/PROC-MCP-Session-Recovery.md)** - Recuperação de sessões MCP após crash
- **[PROC-MCP-Desk-Timer.md](file:///media/ealmeida/Dados/Hub/06-Operacoes/Procedimentos/D7-Tecnologia/MCP/PROC-MCP-Desk-Timer.md)** - Workflow timer Desk CRM (atribuição e status obrigatórios)
### Quick Reference (ver PROC-MCP-Desenvolvimento.md)
- **ESLint + Prettier:** Ver PROC secção "Scripts package.json"
- **Husky pre-commit:** Ver PROC secção "Husky + Lint-Staged"
- **Checklist novo MCP:** Ver PROC secção "Checklist Desenvolvimento MCP"
- **Schema BD:** Ver PROC secção "Documentação Schema BD"
- **Validação pre-deploy:** Ver PROC secção "Validação Obrigatória"
### Agente Especializado
- **Agent:** `mcp-protocol-developer` - Desenvolvimento complexo, debug, optimização, recursos avançados
### Documentação Técnica
- [MCP SDK Documentation](https://modelcontextprotocol.io/)
- [[Stack/Claude Code/MCPs/|MCPs Documentados]]
- [[D7-Tecnologia/INDEX|Ver Todos Procedimentos D7]]
---
---
## Changelog
### v1.3.0 (2026-01-31)
- **HTTP StreamableHTTP** como padrão oficial (template completo)
- SSE marcado como DEPRECATED (retrocompatibilidade)
- **Checklist de Segurança MCP** (baseado em audit 164 tools)
- SQL injection prevention
- Transacções para operações multi-query
- Resource release em finally blocks
- Cleanup error handling
- crypto.randomBytes() vs Math.random()
- Grep de validação para code review
- Portas HTTP reservadas (3200+)
### v1.2.0 (2026-01-27)
- Template SSE completo com http nativo (nao Express)
- Pontos criticos SSE documentados (sessionId, Server por sessao)
- Template systemd service para MCPs SSE
- Tabela de portas SSE reservadas
- Comandos systemd documentados
### v1.1.0 (2026-01-27)
- Adicionada seccao SSE (Server-Sent Events)
- Script reload:sse para desenvolvimento
- Padroes SQL Perfex CRM (FKs usam 0, nao NULL)
- Workflow de desenvolvimento documentado
### v1.0.0 (2026-01-27)
- Versao inicial
---
*Skill v1.3 | Descomplicar®*
---
## Instrumentação Automática
Esta skill grava métricas automaticamente para análise PDCA.
### Query para Gravar (executar no final)
```sql
INSERT INTO tblskill_agent_metrics (
type, name, duration_ms, status, staff_id,
kb_consulted, kb_cache_hit, tool_calls, project_id
) VALUES (
'skill', '/$SKILL_NAME', {DURACAO_MS}, '{STATUS}', 25,
{KB_CONSULTADO}, {CACHE_HIT}, {TOOL_CALLS}, {PROJECT_ID}
);
```
---
**Instrumentação**: Activa | **Data**: 2026-02-03
---
## Quando NÃO Usar
- Para tarefas fora do domínio de especialização desta skill
- Quando outra skill mais específica está disponível
- Para operações que requerem confirmação manual do utilizador
## Protocolo
1. Analisar requisitos da tarefa
2. Verificar disponibilidade de ferramentas necessárias
3. Executar operações de forma incremental
4. Validar resultados antes de concluir
5. Reportar status e próximos passos