Django 5.2 backend for the MCP (Model Context Protocol) Hub. Provides GraphQL API for managing MCP servers, categories, and AI-powered chat using LangGraph agents with CopilotKit integration.
- Framework: Django 5.2 (Python 3.12)
- API: GraphQL with Strawberry Django
- Database: SQLite (PostgreSQL-ready)
- Cache: Redis (connection state management)
- AI: LangGraph agents, OpenAI/DeepSeek
- Chat: CopilotKit integration
- Auth: Google OAuth (token validation)
- 🔧 MCP Server Management - CRUD operations with user ownership
- 📂 Category System - Organize servers with icons and colors
- 🤖 AI Chat Agent - LangGraph with dynamic tool binding
- 🔐 Authentication - Google OAuth with NextAuth.js integration
- 📊 GraphQL API - Advanced filtering, pagination, relay support
- 🔄 Redis State - Connection state with 24hr TTL
- 🌐 Multi-transport - stdio, SSE, WebSocket, HTTP streaming
- Python 3.12+
- Redis server running
- Google OAuth credentials
- API keys (OpenAI/DeepSeek, Tavily for web search)
# Using uv (recommended)
cd mcp-hub
uv venv
uv pip install -r requirements.txt
# Or using pip
python -m venv env
env\Scripts\activate # Windows
source env/bin/activate # macOS/Linux
pip install -r requirements.txtCreate .env file:
SECRET_KEY=your_django_secret_key
DEBUG=True
ALLOWED_HOSTS=localhost
GOOGLE_CLIENT_ID=your_google_client_id
OPENAI_API_KEY=your_openai_api_key
DEEPSEEK_API_KEY=your_deepseek_api_key # Optional
TAVILY_API_KEY=your_tavily_api_key # Optional for web search
REDIS_URL=redis://localhost:6379/0
NEXT_PUBLIC_APP_URL=http://localhost:3000uv run manage.py migrateuv run python seed_categories.pyThis creates 11 default categories: Productivity, Development, Data & Analytics, Communication, AI & Machine Learning, Cloud & Infrastructure, Database, Security, APIs & Integration, Content & Media, and Other.
uv run uvicorn assistant.asgi:application --reloadServer runs at http://localhost:8000
mcp-hub/
├── app/
│ ├── mcp/ # MCP server management
│ │ ├── models.py # MCPServer & Category models
│ │ ├── manager.py # MCP manager singleton
│ │ ├── mcp_schema.py # MCP GraphQL operations
│ │ ├── category_schema.py # Category GraphQL operations
│ │ ├── types.py # Strawberry types & filters
│ │ ├── adapter_builder.py # Transport adapters
│ │ └── redis_manager.py # Connection state management
│ ├── agent/ # LangGraph agents
│ │ ├── chat.py # Chat node with tool binding
│ │ ├── model.py # LLM configuration
│ │ └── agent.py # Agent graph definition
│ ├── auth/ # Authentication
│ │ ├── middleware.py # Google OAuth middleware
│ │ └── schema.py # Auth GraphQL queries
│ ├── graphql/ # GraphQL root schema
│ │ └── schema.py # Combines all schemas
│ └── admin.py # Django admin config
├── assistant/ # Django project settings
├── seed_categories.py # Category seeding script
└── manage.py # Django CLI
- GraphQL:
http://localhost:8000/graphql - GraphiQL:
http://localhost:8000/graphql(interactive explorer) - Health:
http://localhost:8000/api/health
Include Google ID token for authenticated requests:
Authorization: Bearer <google_id_token>
Get all servers with categories:
query {
mcpServers {
edges {
node {
id
name
transport
category {
id
name
icon
color
}
connectionStatus
}
}
}
}Filter servers by category:
query {
mcpServers(filters: { category: { name: { exact: "Productivity" } } }) {
edges {
node {
name
category {
name
icon
}
}
}
}
}Get all categories with servers:
query {
categories {
edges {
node {
id
name
icon
color
servers {
id
name
transport
}
}
}
}
}Create category:
mutation {
createCategory(
name: "Productivity"
icon: "🚀"
color: "#4CAF50"
description: "Productivity tools"
) {
id
name
}
}Save server with category:
mutation {
saveMcpServer(
name: "GitHub MCP"
transport: "stdio"
command: "npx"
categoryId: "ctg_abc123"
) {
id
name
category {
name
icon
}
}
}Connect to server:
mutation {
connectMcpServer(name: "GitHub MCP") {
success
message
connectionStatus
tools {
name
description
}
}
}Strawberry Django supports powerful filtering:
query {
mcpServers(
filters: {
AND: [
{ enabled: { exact: true } }
{ transport: { exact: "stdio" } }
{ category: { name: { iContains: "data" } } }
]
}
) {
edges {
node {
name
}
}
}
}Available lookups: exact, contains, iContains, startsWith, endsWith, inList, isNull, AND, OR, NOT
- MCP Servers:
mcp_abc123xyz(shortuuid) - Categories:
ctg_abc123xyz(shortuuid withctg_prefix)
- Database (SQLite): Server configs, categories, users
- Redis (volatile): Connection state, tools cache (24hr TTL)
- Private servers: User-owned, only owner can modify
- Public servers: Available to all, requires admin to modify
- Server names unique per user (private) or globally (public)
- stdio - Subprocess (command + args)
- sse - Server-Sent Events
- websocket - WebSocket connection
- streamable_http - HTTP streaming
uv run manage.py makemigrations
uv run manage.py migrateuv run manage.py createsuperuserAccess at http://localhost:8000/admin
uv run manage.py shelluv run pytestInstall:
- Windows:
choco install redis-64 - macOS:
brew install redis - Linux:
sudo apt install redis-server
Start:
redis-serverVerify:
redis-cli ping # Should return PONGThe backend exposes CopilotKit-compatible endpoints:
POST /api/copilotkit/info- Agent informationPOST /api/copilotkit/agent/{name}- Execute agentPOST /api/copilotkit/agent/{name}/state- Get state
Frontend uses @copilotkit/react-core and @copilotkit/runtime-client-gql.
500 Internal Server Error:
- Check API keys in
.env - Ensure
DEBUG=Truefor detailed errors - Verify Redis is running:
redis-cli ping
Authentication Issues:
- Verify
GOOGLE_CLIENT_IDmatches frontend - Check Authorization header format
- Ensure Google OAuth is configured correctly
MCP Connection Failures:
- Verify Redis connection
- Check server transport configuration
- For stdio: ensure command is executable
- Use
mcpServerHealthquery to diagnose
Port Conflicts:
- Backend: port 8000
- Frontend: port 3000
- Redis: port 6379
- Change with
--portflag if needed