Jira Thing

Um exemplo de servidor MCP para interagir com o Jira, implantável no Cloudflare Workers.

Documentação

Servidor Model Context Protocol (MCP) com OAuth do GitHub

Este projeto fornece um modelo para um servidor Model Context Protocol (MCP) que usa o GitHub para autenticação OAuth 2.0. Ele foi construído para rodar no Cloudflare Workers, fornecendo uma base robusta e escalável para seus próprios serviços MCP remotos.

Os usuários podem se conectar ao seu servidor MCP implantado e serão solicitados a entrar com sua conta do GitHub para autorizar o acesso.

Recursos

  • Integração OAuth do GitHub: Autentica usuários com segurança via GitHub, atuando como cliente OAuth para o GitHub e servidor OAuth para o cliente MCP.
  • Carregamento Dinâmico de Ferramentas: Demonstra como expor ferramentas condicionalmente com base na identidade do usuário autenticado.
  • Ferramentas de Exemplo: Inclui duas ferramentas de exemplo:
    • Uma ferramenta pública add disponível para todos os usuários autenticados.
    • Uma ferramenta restrita generateImage disponível apenas para uma lista predefinida de usuários autorizados.
  • Implantação Serverless: Construído no Cloudflare Workers para uma arquitetura serverless escalável e de baixa manutenção.
  • Gerenciamento Seguro de Segredos: Usa segredos do Wrangler para gerenciar credenciais sensíveis, evitando valores codificados no código-fonte.

Começando

Pré-requisitos

Instalação

  1. Clone o repositório:

    git clone https://github.com/PortNumber53/mcp-jira-thing.git
    cd mcp-jira-thing
    
  2. Instale as dependências:

    npm install
    

Frontend React (frontend/)

Um aplicativo de página única React + Vite fica em frontend/. Ele fornece o fluxo de login do GitHub para usuários e pode ser desenvolvido com o servidor Vite padrão.

cd mcp-jira-thing
npm install    # install Worker + shared dependencies (repo root)

cd frontend
npm install    # install local dependencies before development
npm run dev          # starts the Vite development server with HMR
npm run dev:worker   # runs the merged Worker locally on :18112

Para builds reproduzíveis e implantação:

npm run build   # runs tsc + vite build (Worker deploy is from repo root)
npm run deploy  # uploads the merged Worker and SPA assets via wrangler deploy

O Cloudflare Worker é definido na raiz do repositório (src/index.ts). Ele serve o SPA de frontend/dist/client em / e expõe o servidor MCP em /sse (e /mcp). A implantação é realizada a partir da raiz do repositório com npm run deploy, que compila o SPA primeiro. Executar npm run dev:worker em frontend/ inicia o mesmo Worker mesclado localmente usando ../wrangler.jsonc.

Aplicativo Slack (integração de projeto Jira por canal)

Se você quiser que usuários do Slack interajam com o Jira no contexto de um canal do Slack (por exemplo, criar/pesquisar issues contra um projeto Jira padrão por canal), conecte um aplicativo Slack a este Worker e armazene um mapeamento:

  • ID do canal do Slackchave do projeto Jira (por exemplo, C01234567ENG)

Este repositório não inclui endpoints do Slack ainda, mas as etapas abaixo descrevem a configuração que você precisará quando adicioná-los.

1) Crie um aplicativo Slack

No Slack, crie um aplicativo do zero e habilite:

  • Interatividade e Atalhos (opcional, mas recomendado)
  • Comandos de Barra (recomendado)
  • Assinaturas de Eventos (opcional; útil para menções @yourapp)
  • OAuth e Permissões

2) Configurações de OAuth + escopos necessários

Adicione uma URL de redirecionamento para o Worker, por exemplo:

  • http://localhost:18112/slack/oauth/callback (local)
  • https://<your-worker>.<your-subdomain>.workers.dev/slack/oauth/callback (produção)

Escopos de token de bot sugeridos (ajuste conforme suas necessidades):

  • commands: habilita comandos de barra como /jira
  • chat:write: posta respostas/mensagens
  • channels:read e/ou groups:read: lê metadados do canal (público vs privado)
  • app_mentions:read (se usar eventos para menções)
  • users:read (se quiser exibir nomes de usuário / enriquecer mensagens)

3) Configure URLs de solicitação do Slack (endpoints do Worker que você adicionará)

Uma vez implementado, o Slack deve apontar para endpoints do Worker como:

  • URL de solicitação de comando de barra: .../slack/commands
  • URL de solicitação de interatividade: .../slack/interactions
  • URL de solicitação de eventos (se habilitado): .../slack/events

Todos esses endpoints devem:

  • Verificar assinaturas do Slack usando SLACK_SIGNING_SECRET
  • Responder dentro de 3 segundos (use response_url ou acompanhamentos assíncronos para chamadas Jira lentas)

4) Armazene o mapeamento "canal → projeto Jira"

Abordagem recomendada neste repositório:

  • Armazene o mapeamento no Cloudflare KV (simples) ou em um Durable Object (consistência forte)
  • Chave por ID de canal, valor inclui pelo menos { projectKey, updatedAt, updatedBy }

Exemplo de chave de mapeamento:

  • slack:channel-project:C01234567{"projectKey":"ENG","updatedAt":...}

5) UX sugerida do Slack (comandos)

Um padrão prático é um comando /jira que define ou usa o projeto padrão do canal:

  • Definir padrão: /jira project set ENG
  • Mostrar padrão: /jira project get
  • Criar issue: /jira create "Bug title" --type Task
  • Pesquisar: /jira search status=Open assignee=me

Detalhe de implementação: o manipulador lê o ID do canal do payload do Slack, procura a chave do projeto para aquele canal e então chama o cliente/ferramentas Jira existentes em src/tools/jira/ para executar a ação solicitada.

6) Variáveis de ambiente que você precisará

Adicione estas como segredos/variáveis do Wrangler (nomes são sugestões; escolha uma convenção e siga-a):

  • SLACK_SIGNING_SECRET: necessário para verificar solicitações do Slack
  • SLACK_CLIENT_ID / SLACK_CLIENT_SECRET: necessário para o fluxo de instalação OAuth do Slack
  • SLACK_BOT_TOKEN: necessário para chamar APIs do Slack (ou armazenar tokens por workspace após OAuth)

Se você suportar múltiplos workspaces do Slack, armazene as informações de instalação do workspace/equipe chaveadas por team_id, não globalmente.

Backend Go (backend/)

O backend Go expõe endpoints REST que servem dados ao frontend (ou outros consumidores). A implementação inicial inclui:

  • GET /healthz — sonda de saúde simples para balanceadores de carga e verificações de fumaça do Jenkins.
  • GET /api/users?limit=50 — retorna uma lista paginada de usuários NextAuth do banco de dados.

Variáveis de ambiente

Crie uma cópia de backend/env.example e forneça os valores necessários:

VariávelObrigatóriaDescrição
BACKEND_ADDRopcionalEndereço em que o servidor HTTP escuta. Padrão :18111.
DATABASE_URLDSN Postgres usado pelo backend em tempo de execução.
MCP_SESSION_API_TOKENopcionalCredencial interna Node MCP → backend; padrão COOKIE_SECRET.
BACKEND_HTTP_TIMEOUT_SECONDSopcionalTimeout de solicitação de saída, padrão 15 segundos.

go test e o código em tempo de execução esperam que as variáveis de ambiente estejam presentes. Ao executar localmente, você pode exportá-las ou usar um carregador dotenv (direnv, dotenvx, etc.).

Desenvolvimento local

cd backend
cp env.example .env   # edit with your credentials (or export env vars)
go test ./...
go run ./cmd/server

# or via make
make test
make run

Recarga automática com Air

Air oferece recarga ao vivo para aplicações Go, para que as alterações sejam recompiladas e reiniciadas automaticamente durante o desenvolvimento, reduzindo os ciclos de feedback 1.

# install once (requires Go 1.25+)
go install github.com/air-verse/air@latest

# start the watcher from the backend directory
cd backend
make dev  # runs `air -c .air.toml`

O Air usa a configuração em backend/.air.toml para recompilar ./tmp/main sempre que arquivos Go ou de ambiente mudarem, e então reinicia o servidor de forma transparente. Garanta que seus valores .env estejam presentes antes de iniciar o observador.

Fluxo de implantação

  • Build/Teste: make build compila um binário estático Linux em backend/bin/mcp-backend. make test executa os testes unitários. Ambos os comandos são orquestrados pelo pipeline Jenkins (veja abaixo).
  • Artefato: Jenkins compacta o binário em backend/bin/mcp-backend.tar.gz e o publica como artefato de build.
  • Script de implantação: scripts/deploy-backend.sh compila cruzadamente o binário Linux, envia via scp, descompacta em $DEPLOY_PATH e opcionalmente reinicia um serviço systemd quando SERVICE_NAME é fornecido.

Pipeline Jenkins

Este repositório agora contém um Jenkinsfile de nível superior que executa as seguintes etapas:

  1. Checkout — puxa o repositório para o build atual.
  2. Teste Go — executa go test ./... dentro de backend/.
  3. Build do Backend — executa make build para gerar o binário mcp-backend.
  4. Arquivar Artefato — compacta o binário e o arquiva para recuperação posterior.
  5. Implantar (somente master) — executa scripts/deploy-backend.sh, que espera as seguintes variáveis de ambiente fornecidas pelas credenciais do Jenkins ou configuração do job:
    • DEPLOY_HOST: Host/IP do servidor de produção (Arch Linux).
    • DEPLOY_USER: Usuário SSH com permissão para escrever em DEPLOY_PATH e executar sudo systemctl restart no serviço de destino.
    • DEPLOY_PATH: Diretório de destino no servidor (por exemplo, /opt/mcp-backend).
    • SERVICE_NAME (opcional): nome da unidade systemd para reiniciar após a implantação.

A etapa de implantação só é executada para builds no branch master, então branches de recursos permanecem apenas para teste. O Jenkins deve fornecer acesso SSH, tipicamente via uma credencial de chave SSH associada à conta DEPLOY_USER. Revise scripts/deploy-backend.sh para detalhes adicionais ou pontos de personalização.

Configuração e Implantação

Siga estas etapas para configurar e implantar seu servidor MCP.

1. Crie um aplicativo OAuth do GitHub

Primeiro, você precisa criar um aplicativo OAuth do GitHub para obter suas credenciais de cliente.

  • URL da página inicial: https://<your-worker-name>.<your-subdomain>.workers.dev
  • URL de callback de autorização: https://<your-worker-name>.<your-subdomain>.workers.dev/callback/github

Depois que o aplicativo for criado, anote o ID do cliente e gere um novo segredo do cliente.

2. Configure os segredos

Em seguida, use o Wrangler para armazenar com segurança suas credenciais do GitHub e uma chave de criptografia de sessão como segredos.

# Will prompt for your GitHub Client ID
npx wrangler secret put GITHUB_CLIENT_ID

# Will prompt for your GitHub Client Secret
npx wrangler secret put GITHUB_CLIENT_SECRET

# Will prompt for a random string used to sign session cookies
npx wrangler secret put SESSION_SECRET

# Optionally, provide COOKIE_SECRET if you need an override for local testing
npx wrangler secret put COOKIE_SECRET

Para o SESSION_SECRET, você pode gerar uma string aleatória segura com openssl rand -hex 32.

3. Armazenamento de sessão

O estado OAuth e os dados de sessão do usuário são armazenados em cookies assinados e somente HTTP; nenhum namespace Cloudflare KV é necessário. Garanta que SESSION_SECRET (ou COOKIE_SECRET) esteja configurado para que o Worker possa assinar e validar esses cookies com segurança. Se você usou COOKIE_ENCRYPTION_KEY anteriormente, renomeie esse segredo para SESSION_SECRET.

4. Autorize usuários

Para conceder acesso a ferramentas restritas como generateImage, você deve adicionar os nomes de usuário do GitHub dos usuários autorizados ao conjunto ALLOWED_USERNAMES em src/index.ts.

// src/index.ts
const ALLOWED_USERNAMES = new Set<string>([
  "PortNumber53",
  // Add other authorized GitHub usernames here
]);

5. Implante o Worker

Finalmente, implante seu worker configurado no Cloudflare.

npx wrangler deploy

Ferramentas Disponíveis

Este servidor MCP expõe as seguintes ferramentas:

  • add

    • Descrição: Adiciona dois números.
    • Acesso: Público (disponível para todos os usuários autenticados).
    • Parâmetros: a (número), b (número).
  • generateImage

    • Descrição: Gera uma imagem usando o modelo @cf/black-forest-labs/flux-1-schnell.
    • Acesso: Restrito (disponível apenas para usuários em ALLOWED_USERNAMES).
    • Parâmetros: prompt (string), steps (número, 4-8).

Uso

Você pode testar seu servidor remoto usando o MCP Inspector:

npx @modelcontextprotocol/inspector@latest

Digite a URL SSE do seu worker (https://<your-worker-name>.<your-subdomain>.workers.dev/sse) e clique em Conectar. Você será redirecionado ao GitHub para autenticar. Após a autenticação, você verá as ferramentas disponíveis no Inspector.

MCP Inspector showing available tools

Estrutura do Projeto

  • src/index.ts: O ponto de entrada principal para o Cloudflare Worker. Define o servidor MCP, suas ferramentas e a lógica para acesso condicional a ferramentas.
  • src/github-handler.ts: Contém a lógica para lidar com o fluxo OAuth do GitHub.
  • src/workers-oauth-utils.ts: Fornece funções utilitárias para o processo OAuth, adaptadas da biblioteca workers-oauth-provider.
  • wrangler.jsonc: O arquivo de configuração para o Cloudflare Worker.
  • package.json: Define scripts do projeto e dependências.

Agora você tem um servidor MCP remoto implantado!

Controle de Acesso

Este servidor MCP usa OAuth do GitHub para autenticação. Todos os usuários autenticados do GitHub podem acessar ferramentas básicas como "add" e "userInfoOctokit".

A ferramenta "generateImage" é restrita a usuários específicos do GitHub listados na configuração ALLOWED_USERNAMES:

// Add GitHub usernames for image generation access
const ALLOWED_USERNAMES = new Set(["yourusername", "teammate1"]);

Acesse o servidor MCP remoto pelo Claude Desktop

Abra o Claude Desktop e navegue até Settings -> Developer -> Edit Config. Isso abre o arquivo de configuração que controla quais servidores MCP o Claude pode acessar.

Substitua o conteúdo pela configuração a seguir. Depois de reiniciar o Claude Desktop, uma janela do navegador será aberta mostrando sua página de login OAuth. Conclua o fluxo de autenticação para conceder ao Claude acesso ao seu servidor MCP. Após conceder o acesso, as ferramentas ficarão disponíveis para uso.

{
  "mcpServers": {
    "math": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://mcp-github-oauth.<your-subdomain>.workers.dev/sse"
      ]
    }
  }
}

Assim que as Tools (em 🔨) aparecerem na interface, você pode pedir ao Claude para usá-las. Por exemplo: "Você poderia usar a ferramenta de matemática para somar 23 e 19?". O Claude deve acionar a ferramenta e mostrar o resultado gerado pelo servidor MCP.

Para desenvolvimento local

Se você quiser iterar e testar seu servidor MCP, pode fazer isso no desenvolvimento local. Isso exigirá que você crie outro OAuth App no GitHub:

  • Para a Homepage URL, especifique http://localhost:18112
  • Para a Authorization callback URL, especifique http://localhost:18112/callback/github
  • Anote seu Client ID e gere um Client secret.
  • Crie um arquivo .dev.vars na raiz do seu projeto com:
GITHUB_CLIENT_ID=your_development_github_client_id
GITHUB_CLIENT_SECRET=your_development_github_client_secret

Desenvolver e testar

Execute o servidor localmente para disponibilizá-lo em http://localhost:18112 wrangler dev

Para testar o servidor local, insira http://localhost:18112/sse no Inspector e clique em conectar. Depois de seguir as instruções, você poderá "List Tools".

Usando Claude e outros clientes MCP

Ao usar o Claude para se conectar ao seu servidor MCP remoto, você pode ver algumas mensagens de erro. Isso acontece porque o Claude Desktop ainda não suporta servidores MCP remotos, então às vezes ele fica confuso. Para verificar se o servidor MCP está conectado, passe o mouse sobre o ícone 🔨 no canto inferior direito da interface do Claude. Você deve ver suas ferramentas disponíveis lá.

Usando Cursor e outros clientes MCP

Para conectar o Cursor ao seu servidor MCP, escolha Type: "Command" e no campo Command, combine os campos command e args em um só (ex.: npx mcp-remote https://<your-worker-name>.<your-subdomain>.workers.dev/sse).

Observe que, embora o Cursor suporte servidores HTTP+SSE, ele não suporta autenticação, então você ainda precisa usar mcp-remote (e usar um servidor STDIO, não um HTTP).

Você pode conectar seu servidor MCP a outros clientes MCP, como o Windsurf, abrindo o arquivo de configuração do cliente, adicionando o mesmo JSON usado na configuração do Claude e reiniciando o cliente MCP.

Como funciona?

Transporte e persistência do MCP

Os Workers do Cloudflare roteiam o tráfego /sse e /mcp para o servidor MCP Node.js autônomo configurado por MCP_SERVER_URL. O serviço Node não se conecta diretamente ao banco de dados. Ele persiste a identidade da sessão de transporte, metadados de inicialização, propriedade do locatário, expiração e carimbos de última visualização por meio da API interna protegida do backend Go. O backend Go é o único proprietário do banco de dados e armazena esses registros no PostgreSQL.

Sessões HTTP transmissíveis podem ser reconstruídas a partir do PostgreSQL após uma reinicialização do processo Node. Fluxos de resposta ao vivo e sockets SSE legados permanecem necessariamente locais ao processo; se um socket SSE for interrompido, o cliente se reconecta e cria uma nova sessão persistida.

Defina MCP_SESSION_API_TOKEN com o mesmo valor no backend Go e no serviço MCP Node. Se omitido, ambos os serviços podem usar o COOKIE_SECRET/SESSION_SECRET compartilhado existente. MCP_SESSION_TTL_SECONDS controla o tempo de vida da sessão contínua do serviço Node e o padrão é 24 horas.

MCP Remote

A biblioteca MCP Remote permite que seu servidor exponha ferramentas que podem ser invocadas por clientes MCP, como o Inspector. Ela:

  • Define o protocolo de comunicação entre clientes e seu servidor
  • Fornece uma maneira estruturada de definir ferramentas
  • Lida com a serialização e desserialização de solicitações e respostas
  • Mantém a conexão Server-Sent Events (SSE) entre clientes e seu servidor

Footnotes

  1. Air é um utilitário de recarga ao vivo de código aberto para aplicações Go que observa o código-fonte, recompila e reexecuta o binário compilado automaticamente para agilizar o desenvolvimento air-verse/air.