Skip to main content
Glama
Abishek-0607

Book Library MCP Server

by Abishek-0607
README.md
# ๐Ÿ“š Book Library โ€” MCP Server Demo

A **production-ready** reference implementation showing how Claude (or any LLM) connects to
a real REST API through an MCP Server.

---

## ๐Ÿ—๏ธ Architecture

```
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                        YOU / CLAUDE                             โ”‚
โ”‚              (natural language: "find me Python books")         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                            โ”‚  MCP Protocol (JSON-RPC 2.0)
                            โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    MCP SERVER  :9000                            โ”‚
โ”‚                   (book_mcp โ€” FastMCP)                          โ”‚
โ”‚                                                                 โ”‚
โ”‚  Tools exposed:                                                 โ”‚
โ”‚   book_list   book_search   book_get                           โ”‚
โ”‚   book_create book_update   book_delete                        โ”‚
โ”‚                                                                 โ”‚
โ”‚  Responsibilities:                                              โ”‚
โ”‚   โœ… Translate MCP tool calls โ†’ HTTP requests                  โ”‚
โ”‚   โœ… Validate inputs with Pydantic                             โ”‚
โ”‚   โœ… Format API responses as Markdown or JSON                  โ”‚
โ”‚   โœ… Handle and surface errors cleanly                         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                            โ”‚  REST API (HTTP/JSON)
                            โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                   BOOK LIBRARY API  :8000                       โ”‚
โ”‚                      (FastAPI)                                  โ”‚
โ”‚                                                                 โ”‚
โ”‚  Endpoints:                                                     โ”‚
โ”‚   GET    /api/v1/books/          List + filter + paginate      โ”‚
โ”‚   GET    /api/v1/books/search    Full-text search              โ”‚
โ”‚   GET    /api/v1/books/{id}      Get single book               โ”‚
โ”‚   POST   /api/v1/books/          Create book                   โ”‚
โ”‚   PATCH  /api/v1/books/{id}      Update book                   โ”‚
โ”‚   DELETE /api/v1/books/{id}      Delete book                   โ”‚
โ”‚   GET    /health                 Health probe                   โ”‚
โ”‚   GET    /docs                   Swagger UI                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
```

---

## ๐Ÿ“ Folder Structure

```
book-mcp-demo/
โ”‚
โ”œโ”€โ”€ api/                          # FastAPI REST API
โ”‚   โ”œโ”€โ”€ core/
โ”‚   โ”‚   โ””โ”€โ”€ config.py             # Settings from env vars
โ”‚   โ”œโ”€โ”€ exceptions/
โ”‚   โ”‚   โ””โ”€โ”€ __init__.py           # Custom exception classes
โ”‚   โ”œโ”€โ”€ models/
โ”‚   โ”‚   โ””โ”€โ”€ book.py               # Domain model + in-memory store
โ”‚   โ”œโ”€โ”€ routers/
โ”‚   โ”‚   โ””โ”€โ”€ books.py              # All CRUD route handlers
โ”‚   โ”œโ”€โ”€ schemas/
โ”‚   โ”‚   โ””โ”€โ”€ book.py               # Pydantic request/response schemas
โ”‚   โ”œโ”€โ”€ main.py                   # FastAPI app entry point
โ”‚   โ””โ”€โ”€ requirements.txt
โ”‚
โ”œโ”€โ”€ mcp_server/
โ”‚   โ”œโ”€โ”€ server.py                 # FastMCP server with 6 tools
โ”‚   โ””โ”€โ”€ requirements.txt
โ”‚
โ”œโ”€โ”€ mcp_client/
โ”‚   โ”œโ”€โ”€ client.py                 # Demo client (shows MCP wire protocol)
โ”‚   โ””โ”€โ”€ requirements.txt
โ”‚
โ”œโ”€โ”€ tests/
โ”‚   โ””โ”€โ”€ test_books_api.py         # API integration tests
โ”‚
โ”œโ”€โ”€ Dockerfile.api                # Multi-stage Docker build for API
โ”œโ”€โ”€ Dockerfile.mcp                # Multi-stage Docker build for MCP server
โ”œโ”€โ”€ Dockerfile.client             # Docker build for demo client
โ”œโ”€โ”€ docker-compose.yml            # Orchestrates all 3 services
โ”œโ”€โ”€ requirements.txt              # Root deps for local dev
โ””โ”€โ”€ .env                          # Environment variables
```

---

## ๐Ÿš€ Quick Start

### Option 1 โ€” Docker Compose (Recommended)

```bash
# Clone and enter the project
cd book-mcp-demo

# Start all 3 services (API + MCP Server + Client demo)
docker compose up --build

# You'll see:
# book_api    โ†’ ready on port 8000
# book_mcp    โ†’ ready on port 9000
# book_mcp_client โ†’ runs all demo scenarios, then exits
```

### Option 2 โ€” Local Development

```bash
# Install all dependencies
pip install -r requirements.txt

# Terminal 1: Start the API
uvicorn api.main:app --reload --port 8000

# Terminal 2: Start the MCP server
python mcp_server/server.py

# Terminal 3: Run the client demo
python mcp_client/client.py
```

---

## ๐Ÿงช Running Tests

```bash
# Install test deps
pip install -r requirements.txt

# Run all tests
pytest tests/ -v

# Run with coverage
pytest tests/ -v --cov=api
```

---

## ๐ŸŒ API Documentation

Once the API is running, open:

| URL | Description |
|-----|-------------|
| http://localhost:8000/docs | Swagger UI (interactive) |
| http://localhost:8000/redoc | ReDoc UI |
| http://localhost:8000/health | Health check |

---

## ๐Ÿ”ง MCP Tools Reference

| Tool | Description | Read-only |
|------|-------------|-----------|
| `book_list` | List all books with filters and pagination | โœ… Yes |
| `book_search` | Search by title or author | โœ… Yes |
| `book_get` | Get a single book by ID | โœ… Yes |
| `book_create` | Add a new book (ISBN must be unique) | โŒ No |
| `book_update` | Partially update a book | โŒ No |
| `book_delete` | Permanently delete a book | โŒ No |

---

## ๐Ÿ” How MCP Works (Step by Step)

```
Step 1 โ€” Handshake
  Client โ†’ Server: initialize (announce capabilities)
  Server โ†’ Client: serverInfo + available tools list

Step 2 โ€” Tool Discovery
  Client โ†’ Server: tools/list
  Server โ†’ Client: [{name, description, inputSchema}, ...]

Step 3 โ€” Tool Call
  Client โ†’ Server: tools/call {name: "book_search", arguments: {query: "python"}}
  Server:           validates input โ†’ calls Book API โ†’ formats response
  Server โ†’ Client: {content: [{type: "text", text: "### Search results..."}]}
```

---

## ๐Ÿ›ก๏ธ Error Handling Strategy

### API Layer (FastAPI)
- **Custom exceptions** (`BookNotFoundError`, `DuplicateISBNError`) โ€” raised in business logic
- **Exception handlers** in routers convert them to proper HTTP status codes
- **Global handler** catches anything unexpected โ†’ always returns clean JSON

### MCP Layer (FastMCP)
- **`_handle_api_error()`** โ€” single shared function maps all error types:
  - `httpx.HTTPStatusError` โ†’ maps HTTP codes to user-friendly messages
  - `httpx.TimeoutException` โ†’ timeout message
  - `httpx.ConnectError` โ†’ connectivity message
- **Never exposes raw stack traces** to the LLM client
- **Structured logging** to stderr (stdout is reserved for MCP protocol)

---

## ๐Ÿณ Container Design Decisions

| Decision | Reason |
|----------|--------|
| Multi-stage builds | Smaller final images (no build tools in runtime) |
| Non-root user | Security best practice |
| Health checks | Docker and orchestrators (K8s) need these for readiness |
| `depends_on: condition: service_healthy` | MCP won't start until API is truly ready |
| `PYTHONUNBUFFERED=1` | Logs appear immediately in Docker |
| Per-service `requirements.txt` | Only installs what each container needs |

---

## โš™๏ธ Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `BOOK_API_BASE_URL` | `http://localhost:8000/api/v1` | API base URL seen by MCP server |
| `BOOK_API_TIMEOUT` | `10.0` | HTTP timeout in seconds |
| `MCP_HOST` | `0.0.0.0` | MCP server bind host |
| `MCP_PORT` | `9000` | MCP server port |
| `MCP_SERVER_URL` | `http://localhost:9000` | MCP URL seen by client |
| `DEBUG` | `false` | Enable debug logging |