MCP Python Examples
README.md
# MCP Python Examples
Este proyecto tiene tres paquetes de servidor/cliente MCP en Python:
- [basico/mini_mcp.py](basico/mini_mcp.py): ejemplo mínimo para entender la estructura
- [basico/main.py](basico/main.py): ejemplo de clima usando Open-Meteo, sin seguridad
- [seguro/](seguro/) y [github_login/](github_login/): la misma tool de clima, pero
protegida con OAuth 2.1 (Scalekit) — client credentials (M2M) y login real de
usuario con GitHub
También incluye [index.html](index.html), una presentación explicando **uv**, **pipx** y **MCP** con `weather-mcp` como ejemplo real (arquitectura, seguridad, y cómo exponerlo en la nube). Ábrelo directo en el navegador.
## Qué se versiona en este repo
Solo el código y los archivos de configuración de uv, sin artefactos generados:
| Se versiona | No se versiona (ver [.gitignore](.gitignore)) |
| --- | --- |
| `basico/`, `seguro/`, `github_login/` (código) | `.venv/`, `__pycache__/` |
| `pyproject.toml`, `.python-version` | `*.egg-info`, `build/`, `dist/` |
| `index.html`, `README.md`, `.gitignore`, `.env.template` | `.uv-cache/`, `.claude/`, `.DS_Store`, `.env`, `usuarios_registrados.json` |
## Ejemplo mínimo
El archivo [basico/mini_mcp.py](basico/mini_mcp.py) es el más simple del proyecto.
Hace solo esto:
- crea un servidor MCP
- registra una sola tool
- devuelve un saludo
La tool se llama `saludar` y recibe:
```json
{
"nombre": "Juan Camilo"
}
```
Respuesta esperada:
```json
{
"result": "Hola, Juan Camilo"
}
```
## Cómo correrlo
Puedes correr el MCP mínimo de cualquiera de estas dos formas:
```bash
uv run python basico/mini_mcp.py
```
o:
```bash
uv run mini-mcp
```
No recibe argumentos por consola. Los parámetros se envían cuando un cliente MCP invoca la tool `saludar`.
## Cómo probarlo localmente
Modo desarrollo con inspector MCP:
```bash
uv run mcp dev basico/mini_mcp.py
```
Prueba directa como función Python:
```bash
uv run python -c "from basico.mini_mcp import saludar; print(saludar('Juan Camilo'))"
```
## Configurar en clientes MCP
La opción más estable en este proyecto es registrar este comando:
```bash
/Users/sebastianzapata/.local/bin/uv run --project /Users/sebastianzapata/mcp mini-mcp
```
Después de editar la configuración de cualquier cliente, reinicia la aplicación.
### Codex
Archivo:
`~/.codex/config.toml`
Bloque:
```toml
[mcp_servers.mini-mcp]
command = "/Users/sebastianzapata/.local/bin/uv"
args = ["run", "--project", "/Users/sebastianzapata/mcp", "mini-mcp"]
```
También puedes agregarlo con CLI:
```bash
codex mcp add mini-mcp -- /Users/sebastianzapata/.local/bin/uv run --project /Users/sebastianzapata/mcp mini-mcp
```
### Claude Desktop
Archivo:
`~/Library/Application Support/Claude/claude_desktop_config.json`
Dentro de `mcpServers`:
```json
{
"mini-mcp": {
"command": "/Users/sebastianzapata/.local/bin/uv",
"args": [
"run",
"--frozen",
"--with",
"mcp[cli]",
"--with-editable",
"/Users/sebastianzapata/mcp",
"mcp",
"run",
"/Users/sebastianzapata/mcp/basico/mini_mcp.py"
]
}
}
```
También puedes instalarlo con:
```bash
uv run mcp install /Users/sebastianzapata/mcp/basico/mini_mcp.py --name mini-mcp --with-editable /Users/sebastianzapata/mcp
```
Para ensayarlo en Claude, abre un chat nuevo y pide:
```text
Usa la herramienta saludar del MCP mini-mcp con {"nombre":"Juan Camilo"}
```
### Antigravity
Archivo:
`~/Library/Application Support/Antigravity/User/settings.json`
Dentro de `mcpServers`:
```json
{
"mini-mcp": {
"command": "/Users/sebastianzapata/.local/bin/uv",
"args": [
"run",
"--project",
"/Users/sebastianzapata/mcp",
"mini-mcp"
]
}
}
```
## Ejemplo de clima
El archivo [basico/main.py](basico/main.py) es un ejemplo más completo.
Expone la tool `get_weather`, recibe:
```json
{
"latitude": 4.711,
"longitude": -74.0721,
"elevation": 2640
}
```
Consulta la API de Open-Meteo y devuelve el clima actual.
Ejecutarlo:
```bash
uv run python basico/main.py
```
o:
```bash
uv run weather-mcp
```
Modo desarrollo:
```bash
uv run mcp dev basico/main.py
```
Notas:
- usa Open-Meteo: https://open-meteo.com/en/docs
- `elevation` es opcional
### Registrado en Claude Code
```bash
claude mcp add weather-mcp -- /Users/sebastianzapata/.local/bin/uv run --project /Users/sebastianzapata/mcp weather-mcp
```
### Registrado en Codex
En `~/.codex/config.toml`:
```toml
[mcp_servers.weather-mcp]
command = "/Users/sebastianzapata/.local/bin/uv"
args = ["run", "--project", "/Users/sebastianzapata/mcp", "weather-mcp"]
```
## Login de usuario con GitHub (Scalekit)
`seguro/secure_mcp.py` valida tokens, pero hasta ahora solo los generaban
scripts (client credentials / M2M): ningún humano iniciaba sesión de verdad.
`github_login/app.py` añade ese flujo: una persona se autentica con su cuenta
de **GitHub** a través de Scalekit, queda registrada, y el token que recibe
sirve exactamente igual para llamar al MCP seguro.
Requisitos previos en el Dashboard de Scalekit:
- Tener habilitada una conexión social de **GitHub**.
- Colocar en **Allow Callback** la URL `http://localhost:8787/callback` (o el valor que uses en
`SCALEKIT_REDIRECT_URI`) para que la autenticación funcione y te redireccione donde lo debe hacer.
Ejecutarlo:
```bash
cp .env.template .env # si no lo has hecho ya; agrega tus credenciales de Scalekit
uv run github-login
```
Luego:
1. Abre `http://localhost:8787` en el navegador.
2. Haz clic en "Iniciar sesión con GitHub".
3. Tras autorizar en GitHub, Scalekit te redirige de vuelta con un token de
usuario y lo registra en `github_login/usuarios_registrados.json` (solo
local, no se sube a git — ver `.gitignore`).
4. Usa ese token como cualquier otro Bearer token contra `secure-mcp`:
```bash
claude mcp add --transport http secure-mcp \
https://tu-dominio.com/sse \
--header "Authorization: Bearer <token_del_usuario>"
```
Los dos flujos conviven: `weather_client.py` e `inspector_cloud.py` siguen
usando client credentials (un Agente autenticándose a sí mismo), mientras que
`github_login/app.py` autentica a una persona real. `secure_mcp.py` no
distingue entre ambos: solo valida que el token sea un JWT vigente firmado
por tu entorno de Scalekit.
## Seguridad
`basico/main.py` ya sigue estas prácticas:
- **Sin API key**: Open-Meteo es pública, no hay secretos que proteger o filtrar.
- **Validación de entrada**: `latitude`/`longitude` se validan contra rangos físicos antes de armar la URL.
- **TLS verificado**: usa un `SSLContext` con el bundle de `certifi`, no desactiva la verificación de certificados.
- **Timeout explícito**: 15s, para que una API externa lenta no cuelgue el servidor.
- **Alcance mínimo**: una sola tool de solo lectura, sin acceso a filesystem ni shell.
Reglas generales para servidores MCP propios o de terceros:
- Secretos siempre en variables de entorno, nunca hardcodeados en el código.
- Si agregas un `.env` con claves, súmalo a `.gitignore` (ya cubre `.venv` y caches).
- Cada tool debe hacer una sola cosa bien definida; evita tools genéricas tipo "ejecutar comando" o "leer cualquier archivo".
- Revisa el código de cualquier servidor MCP de terceros antes de instalarlo — corre con tus permisos locales.
- Fija versiones de dependencias (considera generar un `uv.lock`).
## Publicarlo para que otros lo descarguen
**GitHub**: el repo ya existe en [github.com/sebastianzapatar/mcp2026](https://github.com/sebastianzapatar/mcp2026) (rama `main`). Para subir el resto de archivos:
```bash
git add basico/ seguro/ github_login/ pyproject.toml .python-version index.html README.md .gitignore .env.template
git commit -m "Add weather MCP server and presentation"
git push
```
**PyPI** (instalable con `pip install weather-mcp` o `uvx weather-mcp`, requiere cuenta en pypi.org y un token de API):
```bash
uv build
uv publish
```
**Directorios de MCP**: con el repo público en GitHub, puedes enviarlo al [registro comunitario de MCP](https://github.com/modelcontextprotocol/servers) o a directorios como Smithery/Glama.
TDQS
C2.7/5.0
Scored across 1 tool
Disambiguation5/5
With only one tool, there is no possibility of confusion with other tools. The purpose is clear and unambiguous.
Naming Consistency5/5
With a single tool, there is no naming inconsistency to evaluate. The name 'saludar' is a simple, descriptive verb in Spanish.
Tool Count1/5
A single tool that merely returns a greeting is far too minimal for a server purporting to provide Python examples. It lacks any substantial functionality.
Completeness1/5
The server offers only one trivial action (a greeting), leaving virtually every possible operation for a Python examples server unimplemented. It is severely incomplete.
Maintenance
ActivityInactive
ResponsivenessNo issues