Implementación profesional de un servidor MCP (Model Context Protocol) Chat en Python usando FastAPI y SQLAlchemy, basado en laravel-mcp-chat.
- 14 herramientas MCP completas para chat
- SQLAlchemy 2.0 con relaciones y cascadas
- FastAPI para API REST opcional
- Pydantic v2 para validación de datos
- Threads de mensajes con respuestas anidadas
- Reacciones con emojis (16 emojis permitidos)
- Múltiples canales (#general, #python, #jobs, etc.)
- Búsqueda avanzada por contenido, usuario y fechas
- Estadísticas de usuarios y canales
- Python 3.10+
- FastAPI - Framework web moderno
- SQLAlchemy 2.0+ - ORM con relaciones
- Pydantic v2 - Validación de datos
- mcp library - Servidor MCP
- SQLite - Base de datos
git clone https://github.com/Glifaus/python-mcp-chat.git
cd python-mcp-chatpython -m venv venv
source venv/bin/activate # En Windows: venv\Scripts\activatepip install -r requirements.txtpython seed.pypython -m app.mainuvicorn app.api:api --reloadAcceder a la documentación interactiva: http://localhost:8000/docs
Editar el archivo de configuración de Claude Desktop y agregar:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"python-mcp-chat": {
"command": "python",
"args": ["-m", "app.main"],
"cwd": "/ruta/completa/a/python-mcp-chat"
}
}
}Importante: Reemplazar /ruta/completa/a/python-mcp-chat con la ruta absoluta a tu proyecto.
| # | Herramienta | Descripción | Parámetros |
|---|---|---|---|
| 1 | send-message |
Enviar mensaje a un canal | name, content, channel |
| 2 | get-messages |
Obtener mensajes recientes | limit (1-100) |
| 3 | reply-to-message |
Responder a un mensaje (thread) | parent_message_id, name, content |
| 4 | get-message-thread |
Ver thread completo con respuestas | message_id |
| 5 | get-channels |
Listar canales con estadísticas | - |
| 6 | get-channel-messages |
Mensajes de un canal específico | channel, limit |
| 7 | add-reaction |
Añadir emoji a un mensaje | message_id, user_name, emoji |
| 8 | remove-reaction |
Quitar emoji de un mensaje | message_id, user_name, emoji |
| 9 | get-message-reactions |
Ver reacciones agrupadas por emoji | message_id |
| 10 | get-users-list |
Listar usuarios con estadísticas | limit, sort_by |
| 11 | search-messages |
Buscar mensajes por contenido | query, limit |
| 12 | get-messages-by-user |
Filtrar mensajes por autor | name, limit |
| 13 | get-messages-by-date-range |
Filtrar mensajes por fechas | start_date, end_date, limit |
👍 ❤️ 😂 🎉 🚀 👏 🔥 💯 👎 😮 😢 😡 🤔 💡 ✅ ❌
{
"name": "send-message",
"arguments": {
"name": "Alice",
"content": "¡Hola mundo!",
"channel": "general"
}
}{
"name": "get-messages",
"arguments": {
"limit": 20
}
}{
"name": "reply-to-message",
"arguments": {
"parent_message_id": 1,
"name": "Bob",
"content": "¡Hola Alice!"
}
}{
"name": "add-reaction",
"arguments": {
"message_id": 1,
"user_name": "Charlie",
"emoji": "👍"
}
}{
"name": "search-messages",
"arguments": {
"query": "Python",
"limit": 50
}
}{
"name": "get-users-list",
"arguments": {
"limit": 10,
"sort_by": "last_activity"
}
}{
"name": "get-messages-by-date-range",
"arguments": {
"start_date": "2024-01-01T00:00:00",
"end_date": "2024-12-31T23:59:59",
"limit": 100
}
}| Campo | Tipo | Descripción |
|---|---|---|
| id | INTEGER | Primary key |
| parent_id | INTEGER | FK a messages.id (nullable) |
| name | VARCHAR(50) | Nombre del usuario |
| content | VARCHAR(500) | Contenido del mensaje |
| channel | VARCHAR(50) | Canal del mensaje |
| created_at | DATETIME | Fecha de creación |
| updated_at | DATETIME | Fecha de actualización |
Índices: channel, parent_id, created_at
| Campo | Tipo | Descripción |
|---|---|---|
| id | INTEGER | Primary key |
| message_id | INTEGER | FK a messages.id |
| user_name | VARCHAR(50) | Nombre del usuario |
| emoji | VARCHAR(10) | Emoji de reacción |
| created_at | DATETIME | Fecha de creación |
| updated_at | DATETIME | Fecha de actualización |
Constraint único: (message_id, user_name, emoji)
Índice: message_id
Message.parent→ Mensaje padre (self-referential)Message.replies→ Lista de respuestas (cascade delete)Message.reactions→ Lista de reacciones (cascade delete)Reaction.message→ Mensaje asociado
python-mcp-chat/
├── app/
│ ├── __init__.py # Metadata del paquete
│ ├── main.py # Servidor MCP con 14 herramientas
│ ├── api.py # API REST con FastAPI (opcional)
│ ├── database.py # Configuración SQLAlchemy
│ ├── models.py # Modelos Message y Reaction
│ ├── schemas.py # Schemas Pydantic para validación
│ ├── crud.py # Operaciones CRUD optimizadas
│ └── config.py # Configuración y constantes
├── requirements.txt # Dependencias Python
├── seed.py # Script para poblar BD
├── README.md # Este archivo
├── .mcp.json # Configuración MCP
└── .gitignore # Archivos ignorados por Git
- name: 1-50 caracteres
- content: 1-500 caracteres
- channel: máximo 50 caracteres
- query (búsqueda): 1-200 caracteres
- limit: 1-100 (default: 50)
- Los mensajes principales tienen
parent_id = NULL - Las respuestas heredan el
channeldel mensaje padre - Las reacciones son únicas por
(message_id, user_name, emoji) - Solo se permiten los 16 emojis definidos en
ALLOWED_EMOJIS - Las búsquedas son case-insensitive
- El cascade delete elimina respuestas y reacciones al borrar un mensaje
El módulo crud.py utiliza:
- Subqueries para contar replies y reactions eficientemente
- GROUP BY para estadísticas de canales y usuarios
- Índices en campos frecuentemente consultados
- SQLAlchemy 2.0 style con
select()yMappedtypes - Eager loading para reducir queries N+1
| Aspecto | Laravel MCP Chat | Python MCP Chat |
|---|---|---|
| Lenguaje | PHP 8.2+ | Python 3.10+ |
| Framework Web | Laravel 11 | FastAPI |
| ORM | Eloquent | SQLAlchemy 2.0 |
| Validación | Form Requests | Pydantic v2 |
| Async | No nativo | Nativo (asyncio) |
| Migraciones | Artisan migrations | SQLAlchemy Base.metadata |
| Testing | PHPUnit | pytest (recomendado) |
✅ Las 14 herramientas MCP
✅ Mismo modelo de datos (Message + Reaction)
✅ Mismas validaciones y límites
✅ Mismo comportamiento de threads y reacciones
✅ Mismos emojis permitidos
Para agregar tests con pytest:
pip install pytest pytest-asyncioCrear tests/test_crud.py:
from app.database import SessionLocal, init_db
from app import crud
def test_send_message():
init_db()
db = SessionLocal()
msg_id = crud.send_message(db, "Test", "Hello", "general")
assert msg_id > 0
db.close()Ejecutar tests:
pytestSi ejecutas uvicorn app.api:api --reload:
GET /- Estado de la APIGET /messages- Listar mensajesPOST /messages- Crear mensajeGET /messages/{id}- Obtener mensajeGET /messages/{id}/thread- Ver threadPOST /messages/{id}/replies- Crear respuestaGET /channels- Listar canalesGET /channels/{channel}/messages- Mensajes de canalPOST /messages/{id}/reactions- Añadir reacciónDELETE /messages/{id}/reactions- Quitar reacciónGET /messages/{id}/reactions- Ver reaccionesGET /users- Listar usuariosGET /search- Buscar mensajesGET /users/{name}/messages- Mensajes por usuarioGET /messages/date-range- Mensajes por fechas
Documentación interactiva: http://localhost:8000/docs
- Fork el proyecto
- Crea una rama (
git checkout -b feature/nueva-funcionalidad) - Commit tus cambios (
git commit -am 'Agregar nueva funcionalidad') - Push a la rama (
git push origin feature/nueva-funcionalidad) - Abre un Pull Request
MIT License - ver LICENSE para más detalles.
- Proyecto base: laravel-mcp-chat
- Model Context Protocol
- FastAPI Documentation
- SQLAlchemy 2.0 Documentation
- Pydantic Documentation
Glifaus - GitHub
¡Disfruta usando Python MCP Chat! 🚀