Library Book MCP Server
by alianza86
README.md
# MCP de ejemplo: Biblioteca de libros 📚
Un servidor **MCP (Model Context Protocol)** mĂnimo y de **solo lectura**, hecho en
Python, que consulta una base de datos **Postgres** con libros y autores.
El objetivo es aprender cĂłmo un agente (por ejemplo en Azure AI Foundry)
descubre y llama herramientas expuestas por un MCP.
## ¿Qué hace?
Expone 5 herramientas (`tools`) que el agente puede llamar:
| Tool | Qué hace |
|------|----------|
| `search_books` | Busca libros por tĂtulo y/o gĂ©nero, opcionalmente solo disponibles |
| `get_book` | Detalle completo de un libro por id |
| `books_by_author` | Libros de un autor (bĂşsqueda por nombre) |
| `list_authors` | Todos los autores con su nĂşmero de libros |
| `library_stats` | Resumen: totales de tĂtulos, autores y copias |
## Requisitos
- Docker (para Postgres)
- Python 3.11+ (con `uv` no hace falta tenerlo instalado; él descarga uno)
- [uv](https://docs.astral.sh/uv/) (recomendado) o pip
## Puesta en marcha
### 1. Levantar Postgres
```bash
docker compose up -d
```
Esto levanta Postgres vacĂo. Las tablas y los datos de ejemplo los crea la
propia app al arrancar (`init_db` en `server.py`), asĂ que no hay que cargar
nada a mano.
Para reiniciar los datos desde cero:
```bash
docker compose down -v && docker compose up -d
```
### 2. Instalar dependencias
Con uv (recomendado):
```bash
uv sync
```
O con pip + venv:
```bash
python -m venv .venv && source .venv/bin/activate
pip install -e .
```
### 3. Probar el servidor
La forma más rápida de ver las tools sin escribir un cliente es el **MCP Inspector**:
```bash
uv run mcp dev server.py
```
Se abre una UI en el navegador donde puedes listar las tools y llamarlas a mano.
Para correrlo directamente (modo stdio, como lo lanzarĂa un agente):
```bash
uv run server.py
```
O usa el cliente de ejemplo incluido, que arranca el server, lista las tools
y llama algunas (es la forma más fácil de ver la mecánica del protocolo):
```bash
uv run test_client.py
```
## Conectarlo a un cliente MCP
Ejemplo de configuraciĂłn para un cliente tipo Claude Desktop / Cursor
(`mcpServers`):
```json
{
"mcpServers": {
"library": {
"command": "uv",
"args": ["run", "server.py"],
"env": {
"DATABASE_URL": "postgresql://library:library@localhost:5433/library"
}
}
}
}
```
## ConfiguraciĂłn
Variables de entorno:
| Variable | Default | Para qué |
|----------|---------|----------|
| `DATABASE_URL` | `postgresql://library:library@localhost:5433/library` | ConexiĂłn a Postgres |
| `MCP_TRANSPORT` | `stdio` | `stdio` (local) o `streamable-http` (desplegado) |
| `PORT` | `8000` | Puerto HTTP (solo con `streamable-http`) |
| `AUTO_INIT_DB` | `true` | Al arrancar, crea el esquema y carga `seed.sql` si faltan (idempotente) |
> **Seed automático:** la app ejecuta `seed.sql` al arrancar (ver `init_db` en
> [`server.py`](server.py)). Es idempotente, asĂ que no duplica datos ni depende
> de mounts ni de tocar el contenedor de Postgres. Ponlo en `false` para el
> proyecto real, donde normalmente no querrás sembrar datos desde la app.
## Despliegue en Coolify
El server ya soporta transporte HTTP. En modo `streamable-http` expone:
- `GET /health` → `ok` (para el health check)
- `POST /mcp` → el endpoint del protocolo MCP (lo consume el agente/cliente)
La app **se auto-inicializa**: al arrancar crea el esquema y carga los datos de
ejemplo (`seed.sql`) si faltan. No hay que montar `seed.sql` ni tocar el
contenedor de Postgres.
### Opción A — Docker Compose (recomendada)
Usa [`docker-compose.coolify.yml`](docker-compose.coolify.yml): levanta Postgres
+ MCP juntos.
1. En Coolify crea un recurso **Docker Compose** apuntando a tu repo y a
`docker-compose.coolify.yml`.
2. (Opcional) Define `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` como
variables del recurso; si no, usa los defaults (`library`).
3. Asigna un **dominio** al servicio `mcp`. Para enrutar al puerto interno del
contenedor, escrĂbelo en el dominio: `https://<tu-dominio>:8000`. Coolify lo
sirve pĂşblico en 443. No expongas la DB.
> El endpoint MCP para el cliente/agente quedará en `https://<tu-dominio>/mcp`.
> Health check: path `/health` (responde `ok`).
### Opción B — Application (Postgres por separado)
1. **Postgres**: provisiona un contenedor Postgres manualmente (vacĂo; la app lo
siembra sola al arrancar).
2. **MCP**: crea un recurso *Application* apuntando a tu repo (usa el `Dockerfile`).
3. **Variables de entorno** del MCP:
- `DATABASE_URL` → hostname **interno** del Postgres (no `localhost`),
p. ej. `postgresql://library:library@<servicio-postgres>:5432/library`.
- `MCP_TRANSPORT=streamable-http` (ya viene en el Dockerfile).
- `PORT=8000`.
4. **Health check**: path `/health`, GET. **Puerto**: 8000.
### Probar la imagen en local (opcional)
```bash
docker build -t mcp-library .
docker run --rm -p 8000:8000 \
-e DATABASE_URL="postgresql://library:library@host.docker.internal:5433/library" \
mcp-library
curl http://localhost:8000/health # -> ok
```
## Estructura
```
.
├── docker-compose.yml # Postgres 16 para desarrollo local
├── seed.sql # Esquema + datos de ejemplo (carga automática)
├── server.py # El MCP: FastMCP + tools (stdio o streamable-http)
├── test_client.py # Cliente de ejemplo para probar el MCP sin agente (stdio)
├── Dockerfile # Imagen del MCP para desplegar (Coolify, etc.)
├── .dockerignore
├── pyproject.toml # Dependencias
└── README.md
```
## Siguientes pasos (ideas)
- Agregar tools de escritura (crear/prestar libros) cuando quieras practicar acciones.
- Cambiar el transporte a HTTP/SSE para conectar desde Azure AI Foundry.
- Añadir recursos (`resources`) además de tools, p. ej. exponer el esquema de la DB.
TDQS
A4/5.0
Scored across 5 tools
Disambiguation5/5
Each tool serves a distinct purpose: searching by author, retrieving by ID, stats, listing authors, and searching by title/genre/availability. No overlap in functionality.
Naming Consistency4/5
Most names follow a verb_noun pattern (get_book, list_authors, search_books), but 'library_stats' and 'books_by_author' are noun phrases, creating a minor inconsistency.
Tool Count5/5
With 5 tools, the server is well-scoped for a read-only library catalog. Each tool adds distinct value without unnecessary bloat.
Completeness5/5
The tool set covers all essential read operations: search by author, by title/genre, get details by ID, list authors, and aggregate stats. No obvious gaps for its stated purpose.
Maintenance
ActivityStale
ResponsivenessNo issues