Skip to main content
Glama
luis-easyjur

mcp-mysql-remote

by luis-easyjur

mcp-mysql-remote

Servidor MCP remoto, somente-leitura, que expõe consultas SQL de diagnóstico ao MySQL do EasyJur para o Claude.ai (web) via HTTPS, protegido por OAuth 2.1 restrito ao Claude. É o porte do MCP stdio local (easyjur/fenix/mcp/mysql) para um serviço publicável no Railway.

⚠️ Segurança primeiro. Este serviço fica exposto na internet sobre dados jurídicos multi-tenant (LGPD). Ele não deve apontar para produção direta: use réplica de leitura ou homologação, usuário MySQL com GRANT SELECT apenas, segredos só em Railway Variables, OAuth com PKCE S256 e redirect_uri restrito ao Claude.


Onde está o roadmap (fonte única)

Todo o planejamento vive como uma change OpenSpec (spec-driven). Não duplique detalhes aqui — edite os artefatos:

openspec/changes/bootstrap-remote-mysql-mcp/
├── proposal.md   # POR QUÊ + o que muda + capabilities + impacto
├── design.md     # COMO: arquitetura, design patterns, diagramas, decisões, riscos
├── specs/        # O QUÊ (requisitos testáveis, WHEN/THEN):
│   ├── read-only-query/spec.md
│   ├── remote-mcp-transport/spec.md
│   └── oauth-authorization/spec.md
└── tasks.md      # passo a passo de implementação (setup → deploy → Claude.ai)

Comandos úteis:

openspec show bootstrap-remote-mysql-mcp        # visão geral da change
openspec status --change bootstrap-remote-mysql-mcp
openspec validate bootstrap-remote-mysql-mcp --strict

Related MCP server: FoxTrove Voice MCP Server

Arquitetura (resumo)

Claude.ai ──HTTPS+Bearer──► Railway: mcp-mysql-remote
                              │ [Middleware] auth OAuth (JWT/PKCE)
                              │ [Adapter]    Streamable HTTP ⇄ MCP Server (SDK)
                              │ [Strategy]   QueryValidator (somente leitura)
                              │ [Gateway]    DbClient (pool mysql2)
                              ▼
                        MySQL (réplica, SELECT-only)

Detalhes, patterns e fluxo OAuth completo em design.md.

Estrutura implementada:

src/
├── index.js                # bootstrap HTTP (Express) + montagem de rotas
├── config.js               # env → config, validação fail-fast no boot
├── health.js               # GET /health (sem auth, sem DB)
├── mcp/
│   ├── server.js           # MCP Server + tool query_mysql
│   └── httpTransport.js    # Streamable HTTP (stateless) em POST /mcp
├── db/
│   ├── queryValidator.js   # validação read-only por token (fix substring)
│   └── dbClient.js         # pool mysql2; SHOW/DESC/EXPLAIN via query(), resto execute()
└── auth/
    ├── clients.js          # cliente único (Claude) + allowlist de redirect_uri
    ├── discovery.js        # RFC 8414 + RFC 9728
    ├── oauthServer.js      # GET /authorize + POST /token (PKCE S256, JWT HS256)
    └── middleware.js       # Bearer obrigatório em /mcp (401 + WWW-Authenticate)

Setup local

Requisitos: Node.js 20+.

npm install
cp .env.example .env       # preencha os valores (nunca commite o .env)
npm start                  # sobe em http://localhost:3000
npm test                   # testes unitários do validador + E2E OAuth/MCP

Segredos podem ser gerados com:

openssl rand -hex 32   # OAUTH_CLIENT_ID / OAUTH_CLIENT_SECRET
openssl rand -hex 64   # JWT_SECRET

O boot falha cedo se faltar env obrigatória (DB_PASSWORD, banco, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, JWT_SECRET).


Deploy no Railway

  1. Banco: provisione réplica de leitura ou homologação (nunca produção direta) e crie um usuário com GRANT SELECT apenas nos bancos necessários.

  2. Serviço: crie um projeto no Railway a partir deste repositório (o Dockerfile é detectado automaticamente) ou use railway up.

  3. Variables: configure em Settings → Variables (nada no repo): DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD, DB_CONNECTION (ou DB_NAME), OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, JWT_SECRET, PUBLIC_URL, OAUTH_REDIRECT_ALLOWLIST (opcional; padrão já é o callback do Claude).

  4. Domínio + healthcheck: ative o domínio HTTPS do Railway, aponte PUBLIC_URL para ele (ex.: https://mcp-mysql-remote.up.railway.app) e configure o healthcheck do serviço para GET /health.

  5. Firewall do MySQL: restrinja o acesso ao IP de saída do Railway (security group).

  6. Verifique: https://<dominio>/health → 200 e https://<dominio>/.well-known/oauth-authorization-server → JSON com URLs https://.


Conexão no Claude.ai

  1. Em Settings → Connectors → Add custom connector, informe a URL do MCP: https://<dominio-railway>/mcp.

  2. Insira o OAuth Client ID e o Client Secret (os mesmos das Railway Variables).

  3. Complete o fluxo OAuth (o callback é https://claude.ai/api/mcp/auth_callback). O connector deve ficar Connected.

  4. No chat, a tool query_mysql fica disponível — rode um SELECT de diagnóstico.


Checklist de segurança

  • Banco alvo é réplica/homologação (host distinto de produção)

  • Usuário MySQL com GRANT SELECT apenas (escrita negada pelo banco)

  • Segredos só em Railway Variables; .env ignorado pelo git

  • redirect_uri restrito a https://claude.ai/api/mcp/auth_callback

  • PKCE S256 obrigatório; tokens JWT com TTL curto

  • Acesso ao MySQL restrito ao IP de saída do Railway

  • npm test verde (regressão read-only: escrita/DDL/stacked queries recusadas)


Status

Fase atual: apply concluído localmentesrc/ implementado com testes passando. Pendências para produção (ver tasks.md §5–§7): provisionar banco réplica + usuário SELECT-only, deploy no Railway e registro do connector no Claude.ai. Após validar de ponta a ponta: openspec archive bootstrap-remote-mysql-mcp.

F
license - not found
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/luis-easyjur/mcp-mysql-easyjur'

If you have feedback or need assistance with the MCP directory API, please join our Discord server