Content
# MCP Weather Server
POC de um servidor [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) utilizando Spring Boot 4.1.0 com transporte WebMVC (HTTP + SSE). O servidor expõe ferramentas de consulta meteorológica via API pública Open-Meteo.
## Spec Driven Development com Kiro
Este projeto foi desenvolvido utilizando **Spec Driven Development** com o [Kiro](https://kiro.dev), uma IDE com agente de IA que transforma requisitos vagos em especificações estruturadas antes de gerar código.
O fluxo seguido foi:
1. **Requirements** → Kiro gerou requisitos funcionais e não-funcionais a partir da ideia inicial (`.kiro/specs/mcp-server-weather-tool/requirements.md`)
2. **Design** → Gerou design técnico com diagramas e decisões de arquitetura (`.kiro/specs/mcp-server-weather-tool/design.md`)
3. **Tasks** → Criou lista de tarefas incrementais para implementação (`.kiro/specs/mcp-server-weather-tool/tasks.md`)
4. **Implementação** → Código gerado seguindo as specs, com validação a cada passo
Essa abordagem garante rastreabilidade entre requisitos e código, e reduz retrabalho por ambiguidade.
## Pré-requisitos
- Java 21
- Maven 3.9+
## Build
```bash
./mvnw clean package
```
## Execução
```bash
./mvnw spring-boot:run
```
O servidor será iniciado na porta 8080 com transporte SSE.
## Capacidades MCP
| Tipo | Nome | Descrição |
|------|------|-----------|
| **Tool** | `get-current-weather` | Temperatura atual para coordenadas geográficas |
| **Tool** | `get-weather-forecast` | Previsão diária (máx/mín) para coordenadas geográficas |
| **Resource** | `weather://cities/{cityName}` | Coordenadas de cidades brasileiras cadastradas |
| **Prompt** | `weather-query` | Gera consulta meteorológica estruturada |
## Cidades Cadastradas
São Paulo, Rio de Janeiro, Brasília, Curitiba, Belo Horizonte
---
## Teste de Integração MCP (via curl)
O protocolo MCP sobre SSE funciona assim:
1. Cliente abre `GET /sse` (conexão long-lived)
2. Servidor responde com `event:endpoint` contendo o sessionId
3. Cliente envia JSON-RPC via `POST /mcp/messages?sessionId=...`
4. Respostas chegam pelo stream SSE como `event:message`
### Script de teste
```bash
#!/bin/bash
# Abre conexão SSE em background
SSE_LOG=/tmp/mcp-sse-events.log
curl -s -N http://localhost:8080/sse > $SSE_LOG 2>&1 &
SSE_PID=$!
sleep 2
# Extrai endpoint com sessionId
SESSION_ENDPOINT=$(grep "^data:" $SSE_LOG | head -1 | sed 's/^data://')
BASE="http://localhost:8080${SESSION_ENDPOINT}"
# 1. Initialize
curl -s -X POST "$BASE" -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2024-11-05","capabilities":{},
"clientInfo":{"name":"test-client","version":"1.0.0"}}
}'
sleep 1
# 2. Initialized notification
curl -s -X POST "$BASE" -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","method":"notifications/initialized"
}'
sleep 1
# 3. List tools
curl -s -X POST "$BASE" -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":2,"method":"tools/list"
}'
sleep 1
# 4. Call get-current-weather (São Paulo)
curl -s -X POST "$BASE" -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"get-current-weather","arguments":{"latitude":-23.55,"longitude":-46.63}}
}'
sleep 2
# 5. Call get-weather-forecast (Curitiba, 3 dias)
curl -s -X POST "$BASE" -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":4,"method":"tools/call",
"params":{"name":"get-weather-forecast","arguments":{"latitude":-25.43,"longitude":-49.27,"days":3}}
}'
sleep 2
# 6. List prompts
curl -s -X POST "$BASE" -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":5,"method":"prompts/list"
}'
sleep 1
# 7. Get prompt
curl -s -X POST "$BASE" -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":6,"method":"prompts/get",
"params":{"name":"weather-query","arguments":{"city":"Curitiba","language":"pt-BR"}}
}'
sleep 1
# 8. List resource templates
curl -s -X POST "$BASE" -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":7,"method":"resources/templates/list"
}'
sleep 1
# 9. Read resource
curl -s -X POST "$BASE" -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":8,"method":"resources/read",
"params":{"uri":"weather://cities/São Paulo"}
}'
sleep 1
# Mostra respostas recebidas via SSE
echo "=== Respostas SSE ==="
cat $SSE_LOG
kill $SSE_PID 2>/dev/null
```
### Resultados obtidos (25/06/2026)
Todos os endpoints responderam com sucesso:
| # | Método JSON-RPC | Resultado |
|---|----------------|-----------|
| 1 | `initialize` | ✅ Server: `mcp-weather-server v1.0.0`, protocol `2024-11-05` |
| 2 | `notifications/initialized` | ✅ ACK |
| 3 | `tools/list` | ✅ 2 tools: `get-current-weather`, `get-weather-forecast` |
| 4 | `tools/call` get-current-weather | ✅ **São Paulo: 11,5°C** |
| 5 | `tools/call` get-weather-forecast | ✅ **Curitiba 3 dias: 13.5/2.3, 17.7/5.6, 20.1/10.6 °C** |
| 6 | `prompts/list` | ✅ 1 prompt: `weather-query` |
| 7 | `prompts/get` | ✅ Mensagem gerada para buscar clima de Curitiba em pt-BR |
| 8 | `resources/templates/list` | ✅ 1 template: `weather://cities/{cityName}` |
| 9 | `resources/read` | ✅ São Paulo: lat -23.5505, lon -46.6333 |
### Respostas SSE (raw)
```
event:endpoint
data:/mcp/messages?sessionId=91b0c7e6-f404-4e44-9850-cc819246a7b4
event:message
data:{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{"completions":{},"logging":{},"prompts":{"listChanged":true},"resources":{"subscribe":false,"listChanged":true},"tools":{"listChanged":true}},"serverInfo":{"name":"mcp-weather-server","version":"1.0.0"}}}
event:message
data:{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"get-current-weather","description":"Get the current temperature for a given location using latitude and longitude coordinates","inputSchema":{"type":"object","properties":{"latitude":{"type":"number","description":"Latitude (-90.0 to 90.0)"},"longitude":{"type":"number","description":"Longitude (-180.0 to 180.0)"}},"required":["latitude","longitude"]}},{"name":"get-weather-forecast","description":"Get daily weather forecast (max/min temperatures) for a location for the next days","inputSchema":{"type":"object","properties":{"latitude":{"type":"number","description":"Latitude (-90.0 to 90.0)"},"longitude":{"type":"number","description":"Longitude (-180.0 to 180.0)"},"days":{"type":"integer","description":"Number of forecast days (1-7, defaults to 3)"}},"required":["latitude","longitude"]}}]}}
event:message
data:{"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"Temperatura atual em (-23,5149, -46,6105): 11,5°C"}],"isError":false}}
event:message
data:{"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"Previsão para (-25,4130, -49,2416) - 3 dias:\n2026-06-25: máx 13,5°C, mín 2,3°C\n2026-06-26: máx 17,7°C, mín 5,6°C\n2026-06-27: máx 20,1°C, mín 10,6°C"}],"isError":false}}
event:message
data:{"jsonrpc":"2.0","id":5,"result":{"prompts":[{"name":"weather-query","description":"Generate a structured weather query prompt for a given city","arguments":[{"name":"city","description":"City name (required)","required":true},{"name":"language","description":"Response language (default: pt-BR)","required":false}]}]}}
event:message
data:{"jsonrpc":"2.0","id":6,"result":{"description":"Weather query prompt for Curitiba","messages":[{"role":"user","content":{"type":"text","text":"Busque informações meteorológicas atuais para a cidade de Curitiba e apresente os resultados em pt-BR."}}]}}
event:message
data:{"jsonrpc":"2.0","id":7,"result":{"resourceTemplates":[{"uriTemplate":"weather://cities/{cityName}","name":"City Coordinates","description":"Get geographic coordinates for a registered Brazilian city","mimeType":"text/plain"}]}}
event:message
data:{"jsonrpc":"2.0","id":8,"result":{"contents":[{"uri":"weather://cities/São Paulo","mimeType":"text/plain","text":"{\"name\": \"São Paulo\", \"latitude\": -23.5505, \"longitude\": -46.6333}"}]}}
```