geo-explorer-mcp
by GuiC1ntra
README.md
# 🌎 Geo-Explorer
> Explorador de trilhas de aprendizagem em linha de comando, com servidor MCP integrado.
> Projeto do desafio **"Construindo Seu Primeiro Produto com um Agente de IA"** da [DIO](https://dio.me).
[](https://www.python.org/)
[](#-como-executar-os-testes)
[](LICENSE)
---
## đź“– O que Ă© o Geo-Explorer
O Geo-Explorer é uma ferramenta de linha de comando que ajuda alguém a **explorar uma trilha de estudos** de ponta a ponta:
1. escolhe uma tecnologia e recebe um **plano de estudos** com módulos, tópicos e carga horária;
2. pede um **desafio de cĂłdigo** no nĂvel em que está;
3. ao terminar, emite um **certificado fictĂcio** de conclusĂŁo.
Tudo roda sobre uma base de trilhas fictĂcia (`trilhas.json`) criada especialmente para o projeto — **nenhum dado aqui representa um curso real, e o certificado nĂŁo tem validade legal**.
AlĂ©m da CLI, o projeto expõe os mesmos trĂŞs comandos como um **servidor MCP**, permitindo que ferramentas de IA (Claude Desktop, Claude Code, IDEs compatĂveis) usem o Geo-Explorer como fonte de dados sem precisar do terminal.
### Base de trilhas
| Trilha | Categoria | NĂveis | Carga horária total | Desafios |
|---|---|---|---|---|
| Python | Backend | iniciante, intermediário, avançado | 180h | 6 |
| JavaScript | Frontend | iniciante, intermediário, avançado | 164h | 6 |
| SQL e Dados | Dados | iniciante, intermediário, avançado | 144h | 6 |
| DevOps | Infraestrutura | iniciante, intermediário, avançado | 156h | 6 |
| Inteligência Artificial | IA | iniciante, intermediário, avançado | 146h | 6 |
**5 trilhas · 15 planos de estudo · 30 desafios de código**
---
## 🚀 Como executar o projeto
### Pré-requisitos
- Python 3.10 ou superior
- Nada além disso: o projeto tem **zero dependências externas** em runtime
### Instalação
```bash
# 1. clone o repositĂłrio
git clone https://github.com/GuiC1ntra/geo-explorer.git
cd geo-explorer
# 2. (recomendado) crie um ambiente virtual
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# 3. instale em modo editável, com as dependências de teste
pip install -e ".[dev]"
```
Depois disso o comando `geo-explorer` fica disponĂvel no terminal.
> **Sem instalar nada?** Também funciona direto do código-fonte:
> ```bash
> PYTHONPATH=src python3 -m geo_explorer listar
> ```
---
## đź§ Como usar os comandos
### `listar` — ver todas as trilhas
```bash
geo-explorer listar
```
```
================================================================
TRILHAS DISPONIVEIS
================================================================
devops DevOps
Infraestrutura | 156h totais
niveis: iniciante, intermediario, avancado
ia Inteligencia Artificial
IA | 146h totais
niveis: iniciante, intermediario, avancado
...
```
### `trilha` — plano de estudos
Apresenta o plano de estudos da tecnologia escolhida.
```bash
geo-explorer trilha python
geo-explorer trilha python --nivel intermediario
geo-explorer trilha "InteligĂŞncia Artificial" --nivel avancado
geo-explorer trilha frontend # busca por tag também funciona
```
```
================================================================
TRILHA: PYTHON
================================================================
Categoria......: Backend
Nivel..........: intermediario
Carga horaria..: 60h
Modulos........: 5
PLANO DE ESTUDOS
----------------------------------------------------------------
1. Programacao orientada a objetos (12h)
- Classes e heranca
- dataclasses
- Metodos magicos
...
Proximo passo: nivel 'avancado' (geo-explorer trilha python --nivel avancado)
```
| Opção | Descrição | Padrão |
|---|---|---|
| `tecnologia` | Id, nome ou tag da trilha | obrigatĂłrio |
| `--nivel`, `-n` | `iniciante`, `intermediario` ou `avancado` | `iniciante` |
### `desafio` — gerar um desafio de código
```bash
geo-explorer desafio sql --nivel avancado
geo-explorer desafio ia --nivel intermediario --seed 42
```
```
================================================================
DESAFIO: Carga incremental idempotente
================================================================
Id.............: sql-avc-02
Trilha.........: SQL e Dados
Nivel..........: avancado
Tempo estimado.: 120 min
ENUNCIADO
----------------------------------------------------------------
Monte um MERGE que carregue apenas registros novos ou alterados
e possa ser reexecutado sem duplicar dados.
CRITERIOS DE ACEITE
----------------------------------------------------------------
[ ] Usar chave de negocio
[ ] Tratar updates e inserts
[ ] Ser idempotente
DICA
----------------------------------------------------------------
Uma coluna updated_at mais MERGE ON chave resolve os dois casos.
```
| Opção | Descrição | Padrão |
|---|---|---|
| `tecnologia` | Id, nome ou tag da trilha | obrigatĂłrio |
| `--nivel`, `-n` | NĂvel do desafio | `iniciante` |
| `--seed`, `-s` | Semente do sorteio — a mesma semente devolve sempre o mesmo desafio | aleatório |
### `certificado` — emitir certificado fictĂcio
```bash
geo-explorer certificado "Guilherme Cintra" --trilha python --nivel intermediario
geo-explorer certificado "Guilherme Cintra" -t ia -n avancado --data 2026-08-28
```
```
+--------------------------------------------------------------+
| |
| CERTIFICADO DE CONCLUSAO |
| (documento ficticio - projeto de estudo) |
| |
| Certificamos que |
| |
| GUILHERME CINTRA |
| |
| concluiu a trilha de Inteligencia Artificial |
| no nivel intermediario, com 50 horas |
| distribuidas em 4 modulos. |
| |
| Emitido em 2026-08-28 |
| Codigo de validacao: GEO-8028-633F-AD41 |
| |
+--------------------------------------------------------------+
```
| Opção | Descrição | Padrão |
|---|---|---|
| `aluno` | Nome de quem concluiu | obrigatĂłrio |
| `--trilha`, `-t` | Id ou nome da trilha | obrigatĂłrio |
| `--nivel`, `-n` | NĂvel concluĂdo | `iniciante` |
| `--data`, `-d` | Data de emissĂŁo (`AAAA-MM-DD`) | hoje |
O **cĂłdigo de validação** Ă© gerado por um hash SHA-256 dos dados do certificado. Ele Ă© determinĂstico: os mesmos dados sempre produzem o mesmo cĂłdigo, e qualquer alteração produz um cĂłdigo diferente. NĂŁo Ă© uma assinatura criptográfica de verdade — Ă© o que dá cara de documento ao resultado e o torna testável.
### SaĂda em JSON
Qualquer comando aceita `--json`, o que torna o Geo-Explorer utilizável dentro de scripts:
```bash
geo-explorer --json trilha python --nivel avancado | jq '.modulos[].titulo'
geo-explorer --json desafio devops --seed 1 | jq -r '.enunciado'
```
---
## 🔌 Servidor MCP
O **MCP (Model Context Protocol)** é um protocolo baseado em JSON-RPC 2.0 que permite que ferramentas de IA descubram e chamem funções de um programa externo. Na prática: em vez de você digitar `geo-explorer trilha python`, o agente de IA chama a ferramenta sozinho durante a conversa.
O servidor foi escrito Ă mĂŁo, sem SDK, para manter o projeto com zero dependĂŞncias e deixar visĂvel o que acontece em cada mensagem do protocolo.
### Ferramentas expostas
| Tool | Descrição |
|---|---|
| `listar_trilhas` | Lista todas as trilhas disponĂveis |
| `consultar_trilha` | Plano de estudos de uma trilha/nĂvel |
| `gerar_desafio` | Sorteia um desafio de cĂłdigo |
| `emitir_certificado` | Emite um certificado fictĂcio |
### Testando manualmente
```bash
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | geo-explorer-mcp
```
### Configurando no Claude Desktop / Claude Code
Adicione ao arquivo de configuração MCP:
```json
{
"mcpServers": {
"geo-explorer": {
"command": "geo-explorer-mcp"
}
}
}
```
A documentação completa do protocolo, com exemplos de todas as mensagens, está em [`docs/mcp.md`](docs/mcp.md).
---
## đź§Ş Como executar os testes
```bash
pip install -e ".[dev]"
pytest
```
```
74 passed in 0.12s
```
Outras formas de rodar:
```bash
pytest -v # saĂda detalhada
pytest tests/test_mcp_server.py # sĂł o servidor MCP
pytest -k certificado # sĂł o que menciona "certificado"
```
### O que Ă© testado
| Arquivo | Testes | Cobre |
|---|---|---|
| `test_repository.py` | 18 | Carga da base, busca com acento/caixa/tag, consistência dos dados, arquivos inválidos |
| `test_comando_trilha.py` | 12 | Plano de estudos, nĂveis, sugestĂŁo de prĂłximo nĂvel, listagem |
| `test_comando_desafio.py` | 9 | Sorteio, reprodutibilidade por seed, cobertura de todas as combinações |
| `test_comando_certificado.py` | 12 | Dados, determinismo e unicidade do código, validação de entrada |
| `test_cli.py` | 11 | CĂłdigos de saĂda, formato texto e JSON, erros de argumento |
| `test_mcp_server.py` | 12 | Handshake, catálogo de tools, execução, erros JSON-RPC, sessão completa |
Vale destacar dois testes que pegam problemas de verdade na base de dados:
- `test_carga_horaria_do_nivel_bate_com_a_soma_dos_modulos` — impede que a carga horária declarada divirja da soma dos módulos ao adicionar uma trilha nova;
- `test_toda_trilha_tem_desafio_em_cada_nivel` — impede que uma trilha nova entre sem desafio em algum nĂvel, o que quebraria o comando `desafio`.
---
## 🗂️ Estrutura do projeto
```
geo-explorer/
├── src/geo_explorer/
│ ├── data/trilhas.json # base fictĂcia de trilhas e desafios
│ ├── commands/ # um arquivo por comando
│ │ ├── trilha.py
│ │ ├── desafio.py
│ │ └── certificado.py
│ ├── models.py # dataclasses do domĂnio
│ ├── repository.py # única camada que conhece o JSON
│ ├── formatters.py # dicionário → texto do terminal
│ ├── errors.py # exceções de domĂnio
│ ├── cli.py # interface de linha de comando
│ └── mcp_server.py # servidor MCP (JSON-RPC sobre stdio)
├── tests/ # 74 testes com pytest
├── docs/
│ ├── arquitetura.md
│ ├── mcp.md
│ └── base-de-dados.md
├── examples/ # exemplos de uso e configuração
├── .claude/commands/ # slash commands para agentes de IA
└── .github/workflows/ci.yml # testes automáticos a cada push
```
A decisão de arquitetura mais importante: **os comandos devolvem dicionários, não texto**. A formatação vive separada, em `formatters.py`. Foi isso que permitiu que a CLI e o servidor MCP compartilhassem exatamente a mesma lógica — o MCP entrega o texto formatado *e* o JSON estruturado na mesma resposta, sem duplicar uma linha de regra de negócio.
Mais detalhes em [`docs/arquitetura.md`](docs/arquitetura.md).
---
## ✨ Melhorias que eu fiz
Além do fluxo pedido no desafio (trilha, desafio, certificado e servidor MCP):
1. **Comando `listar`** — o desafio original não previa uma forma de descobrir o que existe na base. Sem ele, a pessoa precisa adivinhar o nome da trilha.
2. **Busca tolerante** — `python`, `Python`, `PYTHON`, `Inteligência Artificial`, `inteligencia artificial` e a tag `frontend` chegam à trilha certa. Normalizo removendo acento e caixa antes de comparar.
3. **Mensagens de erro que ensinam** — errar o nome da trilha devolve a lista das trilhas disponĂveis, em vez de um "nĂŁo encontrado" seco.
4. **Flag `--json` global** — todo comando pode ser consumido por script, `jq` ou outro programa.
5. **Desafio reprodutĂvel com `--seed`** — sem isso, um comando que sorteia Ă© impossĂvel de testar de forma determinĂstica.
6. **CĂłdigo de certificado determinĂstico** — SHA-256 dos dados, no formato `GEO-XXXX-XXXX-XXXX`, com teste garantindo que muda se qualquer campo mudar.
7. **SugestĂŁo de prĂłximo nĂvel** — ao final do plano de estudos, o comando indica qual Ă© o passo seguinte e como pedi-lo.
8. **Testes de consistĂŞncia da base** — nĂŁo testam sĂł o cĂłdigo, testam os *dados*: carga horária coerente, ids Ăşnicos, todo nĂvel com desafio.
9. **Zero dependências em runtime** — o servidor MCP foi escrito à mão sobre JSON-RPC. Clona e roda, sem instalar nada.
10. **CI no GitHub Actions** — os testes rodam em Python 3.10, 3.11 e 3.12 a cada push.
11. **Slash commands em `.claude/commands/`** — atalhos para usar o projeto de dentro de um agente de IA.
12. **TrĂŞs trilhas a mais que o mĂnimo** — SQL, DevOps e IA, cada uma com 3 nĂveis e 6 desafios.
---
## 🎓 O que eu aprendi
**Separar dados de apresentação vale mais do que parece.** Comecei fazendo os comandos imprimirem direto na tela. Quando cheguei no servidor MCP, percebi que teria de reescrever tudo — o MCP precisa de dados estruturados, nĂŁo de texto formatado. Refiz para que cada comando devolvesse um dicionário e a formatação virasse uma camada separada. A partir daĂ, adicionar o MCP custou quase nada: ele chama a mesma função da CLI.
**Testar aleatoriedade exige projetar para isso.** O comando `desafio` sorteia. NĂŁo dava para testar atĂ© eu adicionar o parâmetro `seed` e usar `random.Random(seed)` em vez do `random` global. Foi a primeira vez que mudei uma assinatura de função *por causa* do teste — e o resultado ficou melhor tambĂ©m para quem usa, porque agora dá para repetir um desafio especĂfico.
**MCP Ă© mais simples do que o nome sugere.** É JSON-RPC 2.0 sobre stdin/stdout: uma mensagem JSON por linha. Implementar `initialize`, `tools/list` e `tools/call` Ă mĂŁo me fez entender o protocolo de verdade, em vez de sĂł configurar um SDK. Aprendi tambĂ©m uma distinção importante: erro de domĂnio (trilha inexistente) volta como resultado com `isError: true`, para o agente ler e corrigir; erro de protocolo (mĂ©todo desconhecido) volta como erro JSON-RPC.
**Teste de dados pega o que teste de código não pega.** O `test_carga_horaria_do_nivel_bate_com_a_soma_dos_modulos` falhou de verdade enquanto eu montava a base — eu tinha digitado uma carga horária que não batia com a soma dos módulos. O código estava certo; os dados é que estavam errados.
**Revisar o que o agente escreve é parte do trabalho.** Usei IA como apoio o tempo todo, mas cada arquivo passou por leitura minha. O ponto do desafio não é gerar muitos arquivos — é conseguir explicar cada escolha. Escrever este README foi o teste final disso: o que eu não conseguia explicar, eu não tinha entendido.
---
## 🤝 Créditos
Projeto desenvolvido por **Guilherme Cintra** para o desafio *Construindo Seu Primeiro Produto com um Agente de IA* da [Digital Innovation One](https://dio.me).
- GitHub: [@GuiC1ntra](https://github.com/GuiC1ntra)
- LinkedIn: [guilherme-cintr4](https://linkedin.com/in/guilherme-cintr4)
## 📄 Licença
[MIT](LICENSE) — use, estude e adapte à vontade.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues