PM Copilot MCP
by smarjorie
README.md
# PM Copilot MCP
Servidor MCP para times de produto — sem nenhuma API key de LLM. Roda como app Next.js na Vercel e expõe, via Model Context Protocol (Streamable HTTP), as integrações do dia a dia de PMs e PDs: transcrições do Google Meet, criação de tasks no Linear com dedupe, mensagens e DMs no Slack, e um digest semanal automático via cron.
A inteligência fica no cliente: quando conectado ao Claude, é o próprio Claude que lê a transcrição (via tools deste servidor) e produz a síntese, os action items e o parecer de produtividade — seguindo a metodologia embarcada no servidor (prompt `analisar_reuniao` / tool `get_analysis_method`). O digest semanal do cron é 100% determinístico (TypeScript puro), então roda sozinho sem custo de LLM.
## Arquitetura
```
Claude.ai (conector MCP) Vercel Cron (segunda, 9h BRT)
│ ← a análise acontece aqui │
▼ ▼
/api/mcp (mcp-handler) /api/cron/weekly-digest
│ │ (formatador determinístico,
├── Google Drive (transcrições do Meet) │ lib/digest.ts — sem LLM)
├── Linear GraphQL (issues) ◄──────────────────┤
└── Slack Web API (canal + DMs) ◄──────────────┘
```
## Tools e prompts expostos
| Nome | Tipo | O que faz |
|---|---|---|
| `analisar_reuniao` | prompt | Fluxo guiado: localiza a transcrição, lê e aplica a metodologia de análise |
| `list_meet_transcripts` | tool | Lista transcrições recentes do Meet no Drive |
| `get_meet_transcript` | tool | Retorna o texto completo de uma transcrição |
| `get_analysis_method` | tool | Metodologia padrão de análise (síntese, decisões, action items, score 0-100) |
| `linear_list_teams` | tool | Lista os times do workspace Linear |
| `create_linear_tasks` | tool | Cria issues em lote com dedupe por título |
| `linear_open_issues` | tool | Issues abertas por time (dono, estado, prazo) |
| `slack_post_message` | tool | Posta em canal |
| `slack_dm_by_email` | tool | DM individual a partir do e-mail |
| `run_weekly_digest` | tool | Gera e posta o digest sob demanda (`dryRun` disponível) |
O parecer de produtividade avalia 5 critérios: propósito claro, decisões tomadas, action items com dono, participação equilibrada e "poderia ter sido assíncrona?". Score parte de 100 e desconta por critério falho; sem decisões nem donos, o teto é 40.
## Setup
### 1. Clonar e instalar
```bash
git clone <seu-repo>
cd pm-copilot-mcp
npm install
cp .env.example .env
```
### 2. Google (transcrições do Meet)
O Meet salva transcrições como Google Docs no Drive do organizador. O servidor lê via Drive API com OAuth refresh token:
1. No [Google Cloud Console](https://console.cloud.google.com), crie um projeto e ative a **Google Drive API**.
2. Em *APIs & Services → Credentials*, crie um **OAuth client ID** (tipo "Web application") com redirect URI `https://developers.google.com/oauthplayground`.
3. No [OAuth Playground](https://developers.google.com/oauthplayground): engrenagem → "Use your own OAuth credentials" → cole client ID/secret. Autorize o escopo `https://www.googleapis.com/auth/drive.readonly` e troque o code por tokens.
4. Copie o **refresh token** para `GOOGLE_REFRESH_TOKEN`, junto com `GOOGLE_CLIENT_ID` e `GOOGLE_CLIENT_SECRET`.
Importante: habilite a transcrição nas reuniões (Meet → Atividades → Transcrição) — só assim o doc é gerado no Drive.
### 3. Linear
Em *Linear → Settings → Security & access → Personal API keys*, crie uma key e preencha `LINEAR_API_KEY`.
### 4. Slack
1. Crie um app em https://api.slack.com/apps ("From scratch").
2. Em *OAuth & Permissions → Bot Token Scopes*, adicione: `chat:write`, `users:read`, `users:read.email`, `im:write`.
3. Instale o app no workspace e copie o **Bot User OAuth Token** (`xoxb-...`) para `SLACK_BOT_TOKEN`.
4. Convide o bot para o canal do digest: `/invite @seu-bot`.
### 5. Segurança (leia antes de publicar)
Este servidor tem poder de escrita no seu Slack e no seu Linear, e leitura no seu Drive. **Um MCP "público" sem autenticação significa que qualquer pessoa que descobrir a URL pode usar essas credenciais.**
- Defina `MCP_AUTH_TOKEN` com um valor longo e aleatório (`openssl rand -hex 32`). O endpoint passa a exigir `Authorization: Bearer <token>`.
- Defina `CRON_SECRET` — a Vercel injeta esse header nos crons e o endpoint rejeita chamadas sem ele.
- Observação sobre o Claude.ai: conectores customizados na interface autenticam via OAuth ou sem auth; header Bearer estático é suportado ao usar o servidor via API (`mcp_servers` com `authorization_token`). Se você for conectar pela interface do Claude.ai sem OAuth, mantenha a URL secreta, monitore os logs da Vercel e considere implementar OAuth (o pacote `mcp-handler` tem suporte experimental via `withMcpAuth`). Verifique o comportamento atual em https://support.claude.com.
### 6. Deploy na Vercel
```bash
git init && git add -A && git commit -m "feat: PM Copilot MCP"
git remote add origin <seu-repo>
git push -u origin main
```
Na Vercel: *Add New → Project* → importe o repo → configure todas as variáveis do `.env.example` em *Settings → Environment Variables* → deploy. O cron do `vercel.json` (`0 12 * * 1` = segunda 9h em Brasília) é registrado automaticamente.
Seu endpoint MCP será: `https://<seu-projeto>.vercel.app/api/mcp`
### 7. Conectar no Claude
No Claude.ai: *Settings → Connectors → Add custom connector* → cole a URL do endpoint. A partir daí, prompts como estes funcionam de ponta a ponta:
- "Liste as transcrições dessa semana e analise a Weekly de Produto de ontem."
- "Crie no time PROD as tasks dessa análise, atribuídas pelos e-mails, e mande DM pra cada dono com os itens."
- "Rode o digest semanal em dry run pra eu revisar antes de postar no #produto."
## Usando dentro do Slack
Há duas formas de acionar o sistema sem sair do Slack:
**1. Slash command `/copilot` (nativo, sem LLM, qualquer plano).** No seu app do Slack (api.slack.com/apps): *Slash Commands → Create New Command* → Command `/copilot`, Request URL `https://<seu-projeto>.vercel.app/api/slack/commands`. Depois copie o *Signing Secret* (em Basic Information) para a env var `SLACK_SIGNING_SECRET`. Comandos:
- `/copilot digest PROD` — posta o digest do time no canal atual
- `/copilot tarefas PROD` — lista as issues abertas (visível só pra você)
- `/copilot task "Revisar PRD do checkout" ana@empresa.com 2026-07-24 PROD` — cria issue no Linear com dedupe (título entre aspas obrigatório; e-mail, prazo e time são opcionais)
- `/copilot times` — lista os times do Linear
- `/copilot ajuda` — mostra os comandos
Se omitir o time, usa `DIGEST_LINEAR_TEAM` como padrão.
**2. Claude no Slack (com LLM, linguagem natural).** Instale o app oficial do Claude pelo Slack Marketplace e autentique com sua conta Claude; para times Claude Team/Enterprise, o Claude Tag entra como membro do canal e pode usar as ferramentas conectadas à organização — incluindo este MCP. Aí "@Claude analisa a weekly de ontem e cria as tasks" funciona direto no canal. Verifique disponibilidade e requisitos do seu plano em https://support.claude.com.
## Digest semanal automático
Toda segunda o cron: (1) lê as issues abertas de `DIGEST_LINEAR_TEAM`, (2) formata o resumo deterministicamente — panorama, atrasadas, itens por pessoa, issues sem dono — e (3) posta em `DIGEST_SLACK_CHANNEL`. Se `DIGEST_DM_ASSIGNEES=true`, envia também DM individual com os itens de cada pessoa.
Para testar sem esperar segunda-feira: `curl -H "Authorization: Bearer $CRON_SECRET" https://<seu-projeto>.vercel.app/api/cron/weekly-digest`
## Roadmap sugerido
- **Digest com narrativa**: se um dia quiser um digest escrito por LLM em vez do template, basta plugar a Anthropic API no cron (a versão determinística continua como fallback).
- **Webhook do Drive**: notificar no Slack assim que uma nova transcrição aparecer.
- **Métricas agregadas**: histórico do score de produtividade das reuniões ao longo do tempo.
- **OAuth no MCP**: substituir o Bearer estático por OAuth 2.1 para conexão segura direto pela interface do Claude.ai.
## Stack
Next.js 15 (App Router) · [`mcp-handler`](https://www.npmjs.com/package/mcp-handler) · Google Drive API v3 · Linear GraphQL · Slack Web API · Vercel Cron
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues