MCP Hub is a self-hosted AI operations platform with a unified MCP gateway, semantic tool routing, persistent vector memory, automation scheduler, multi-agent flows, and a full ReAct orchestration engine.
Connect Claude Desktop, ChatGPT, Cursor, Telegram, or any MCP client to 130+ tools across 12 integrations — through just 3 hub endpoints. The AI never drowns in schemas. It searches, finds, and acts.
Most MCP setups dump every tool schema into the AI's context window on every call. With 10 integrations and 130+ tools, that's thousands of tokens wasted before the AI even starts thinking.
MCP Hub does it differently:
AI sees: hub.integrations.list
hub.tools.search ← semantic vector search
hub.tools.call
Behind the scenes: 130+ tools across 12 integrations
Local embedding model routes queries to the right tools
ReAct loop executes multi-step tasks autonomously
The AI calls hub.tools.search("teamwork create task; add task to project") and gets back exactly the 3-5 tools it needs. Nothing else enters the context. Token usage drops by 60-80% on complex tasks.
| Problem | Solution |
|---|---|
| 130+ tool schemas bloat every LLM call | Semantic routing — AI sees only relevant tools |
| AI can't remember context between sessions | Persistent vector memory with FTS5 + embedding search |
| Each integration needs its own MCP server | Single gateway for everything |
| Token security concerns | AES-256 encrypted storage, tokens never exposed to AI |
| No visibility into what AI does | Full audit trail — every tool call logged |
| Team needs shared access | Multi-user with admin approval, per-user credentials |
| Complex deployment | Single Docker container, SQLite, zero external services |
| Repetitive tasks need automation | Built-in cron/interval/event scheduler with LLM payloads |
| Integration | Auth | Tools | What it does |
|---|---|---|---|
| Teamwork | OAuth 2.0 | 47 | Projects, tasks, subtasks, dependencies, time tracking, tags, comments, board management |
| Slack | OAuth 2.0 | 19 | Channels, messages, DMs, user lookup, canvases |
| Miro | OAuth 2.0 | 18 | Boards, sticky notes, text, shapes, cards, connectors |
| Figma | OAuth 2.0 | 20 | CSS extraction, layout trees, images, comments, components, styles |
| Google Calendar | OAuth 2.0 | 7 | Calendars, events (list/get/create/update/delete), Google Meet |
| Binance | API Key | 11 | Market data + indicators (RSI, MACD, Bollinger), order book, spot trading, portfolio |
| Telegram | MTProto | 5 | Personal account — dialogs, messages, search, history, send |
| Telegram Bot | Bot Token | 2 | Notifications, alerts via Bot API |
| Memory | Built-in | 7 | Persistent AI memory with FTS5 + semantic vector search |
| Automation | Built-in | 11 | Interval/cron/event scheduler, run history, LLM payloads |
| Agents | Built-in | 21 | Multi-agent flows, graph orchestration, delegation, skills |
| Web Search | Built-in | 3 | Web search, page fetch, full-search with content extraction |
| Hub | — | 4 | Semantic discovery + tool routing |
| 170+ |
The centerpiece of MCP Hub's architecture. Instead of loading all 130+ tool schemas on every call, a local sentence-transformers model runs on CPU and routes each request to the 3-5 most relevant tools.
User: "create a task in teamwork for the design review"
↓ LLM generates search phrases:
"teamwork create task; add task to project; teamwork tasks"
↓ Embedding model finds:
teamwork.tasks.bulk_create (score: 0.94)
teamwork.tasklists.list (score: 0.87)
teamwork.projects.list (score: 0.85)
↓ AI calls hub.tools.call → done
How it works:
- On startup, every tool is embedded:
tool name + description + use cases + tags - Per request,
_expand_semantic_intentsgenerates 3-5 action phrases from the user query - Cosine similarity ranks all tools → top N sent to LLM
- Result: the AI only ever sees tools it actually needs
Token impact: A complex 5-step automation that previously consumed ~60K tokens now uses ~20-30K. The AI still has full access to all 130+ tools — it just fetches them on demand.
Persistent AI memory that works across conversations, automations, and agents. Now with dual search: FTS5 full-text + semantic embedding search.
Saved: "prefer concise summaries, not bullet points"
Search: "formatting style preference" → found (semantic, no exact keyword match)
Saved: "BNB target price $700"
Search: "my crypto goals binance" → found (semantic scope match)
Memory item types with auto TTL:
| Type | Lifetime | Use |
|---|---|---|
preference |
Permanent | User preferences, style settings |
constraint |
Permanent | Rules the AI must follow |
decision |
Permanent | Important decisions made |
project |
Permanent | Active project context |
contact |
Permanent | People and entities |
asset |
Permanent | Tracked assets, crypto positions |
goal |
30 days | Objectives and targets |
note |
7 days | Temporary notes (pin to keep forever) |
Features:
- Auto-vectorized on save — every upsert computes and stores embedding
- Hybrid search — FTS5 keywords + vector similarity, results merged and deduplicated
memory.summarize_context(query="...")— semantic context pack: returns only relevant memories for the current task instead of dumping everything- Secret detection — blocks auto-saving passwords, API keys, tokens
- Scope filtering — memories can be scoped to specific integrations (binance, teamwork, etc.)
Every chat message, automation payload, and agent run goes through the built-in ReAct loop:
Step 1: Understand intent, detect provider, generate semantic search phrases
Step 2: hub.tools.search → find relevant tools
Step 3: hub.tools.call → execute
Step 4: Observe result → verify → iterate if needed
Step 5: Synthesize final answer
Smart behaviours built in:
- Identity bootstrap — for "my tasks" requests, auto-fetches
users.mebefore listing - Progressive tool disclosure — new providers loaded only when actually needed
- Repeated call guard — prevents identical tool calls from looping
- Send short-circuit — for action requests, returns immediately after success
- Web search fallback — if a URL fetch times out, retries with next search result
- Multi-LLM — OpenAI, Anthropic, Google, DeepSeek — configured per user
Schedule any LLM workflow. The automation engine is itself accessible via MCP tools, so AI agents can create, update, and monitor their own scheduled tasks.
Trigger types:
interval— run every N seconds (with optionalstart_at/end_atwindow for one-shot runs)cron— full cron expression with timezone (0 8 * * *for 08:00 daily)event— trigger on named event emitted from tools or webhooks
Payload types:
telegram_bot_message— send a notificationllm_tool_agent— full ReAct loop with any prompt and tool accessmcp_tool— call a specific tool with arguments
Practical recipes:
Daily BNB market report at 08:00
cron: "0 8 * * *"
payload: llm_tool_agent
prompt: "Fetch BNBUSDT 1h and 4h klines with RSI/MACD/SMA indicators.
Read my BNB goals from memory. Generate concise analysis.
Send to Telegram."
Weekly Teamwork summary every Monday 09:00
cron: "0 9 * * 1"
prompt: "List my overdue tasks and tasks due this week.
Summarize in bullet points. Send to Slack #general."
One-shot reminder in 5 minutes
interval_sec: 60, start_at: now+5min, end_at: start_at+90sec
payload: telegram_bot_message
Build graphs of specialized agents that delegate to each other. Each agent has:
- Its own system prompt
- Allowed tool set (policy per integration/tool)
- Mounted skills from the global catalog
- Optional custom MCP server connections
Flow: "Morning Operations"
Orchestrator Agent
├── delegates to → Market Agent (Binance tools only)
├── delegates to → Calendar Agent (Google Calendar tools only)
└── delegates to → Notifier Agent (Telegram Bot only)
Flows can be triggered manually, via automation scheduler, or through MCP.
The hub exposes 4 meta-tools that give AI clients full access to everything without schema bloat:
| Tool | When to use |
|---|---|
hub.integrations.list |
Discover which providers are connected |
hub.tools.search |
Primary — find tools by semantic intent. Query = 2-4 action phrases |
hub.tools.list |
Browse all tools for a specific provider |
hub.tools.call |
Execute a tool by exact name |
Optimal workflow for any AI client:
1. hub.tools.search(query="teamwork create task; add task to project")
→ returns: teamwork.tasks.bulk_create, teamwork.projects.list, teamwork.tasklists.list
2. hub.tools.call(provider="teamwork", tool_name="teamwork.tasks.bulk_create",
arguments={...})
→ done
Query format for hub.tools.search:
- Use 2-4 short action phrases separated by
; - Include provider name + action verb + entity type
- Examples:
"slack send message; post to channel""telegram list dialogs; my chats""binance get ticker BNBUSDT; market price""memory save preference; remember this"
┌──────────────────────────────────────────────────────────────────────┐
│ AI Clients │
│ Claude Desktop │ ChatGPT │ Cursor │ Telegram Bot │ Web UI │
└──────────────────────┬───────────────────────────────────────────────┘
│ JSON-RPC 2.0 + Bearer Token
▼
┌──────────────────────────────────────────────────────────────────────┐
│ MCP Hub │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Semantic Tool Router │ │
│ │ sentence-transformers (CPU) · cosine similarity │ │
│ │ intent expansion · provider ranking · tool ranking │ │
│ └───────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ReAct Orchestration Engine │ │
│ │ hub.tools.search · hub.tools.call · multi-step loop │ │
│ │ identity bootstrap · retry logic · answer synthesis │ │
│ └───────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────┬──────┬──────┬──────┴──────┬──────┬──────┬──────┬───────┐ │
│ │Team- │Slack │Miro │Figma │Bin- │Tele- │Mem- │Auto- │ │
│ │work │ │ │ │ance │gram │ory │mation │ │
│ │47 │19 │18 │20 │11 │5+2 │7 │11 │ │
│ │tools │tools │tools │tools │tools │tools │tools │tools │ │
│ └──────┴──────┴──────┴─────────────┴──────┴──────┴──────┴───────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ SQLite │ FTS5 │ Vector Embeddings │ AES-256 Tokens │ │
│ │ Audit Log │ OAuth 2.0 + PKCE │ Auto Migrations │ │
│ └─────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
git clone https://github.com/Vangardo/mcp_hub.git
cd mcp_hub
cp .env.example .env
# Set: ADMIN_EMAIL, ADMIN_PASSWORD, JWT_SECRET, TOKENS_ENCRYPTION_KEY
cd docker
docker-compose up -d
# Open http://localhost:8000python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reloadGenerate a Personal Access Token in MCP Hub → Settings → Tokens, then add to claude_desktop_config.json:
{
"mcpServers": {
"mcp-hub": {
"url": "https://your-domain.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_PAT_TOKEN"
}
}
}
}- Click Get GPT Config in MCP Hub
- Use the OAuth tab — ChatGPT auto-discovers endpoints via RFC 8414
- Server URL:
https://your-domain.com/mcp
Same as Claude Desktop — Bearer token + MCP endpoint URL.
Add X-MCP-Provider header to expose a single integration directly (bypasses hub meta-tools):
{
"mcpServers": {
"mcp-hub-teamwork": {
"url": "https://your-domain.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_TOKEN",
"X-MCP-Provider": "teamwork"
}
}
}
}| Feature | Details |
|---|---|
| Token encryption | AES-256 at rest for all OAuth/API tokens |
| JWT authentication | Configurable expiration, refresh token rotation |
| Personal Access Tokens | SHA-256 hashed, expiration support, last-used tracking |
| OAuth 2.0 + PKCE | Full RFC 8414/7591/9728 for ChatGPT integration |
| Client Credentials | Machine-to-machine auth for custom apps |
| Audit logging | Every tool call: user, provider, tool name, request, response, status |
| Memory safety | Pattern detection blocks auto-saving passwords, keys, secrets |
| Admin approval | New users require admin approval before access |
| Per-user isolation | Each user's credentials, memory, and connections are fully isolated |
Navigate to Admin in the top nav (admin users only):
- Users — Approve/reject signups, manage roles, reset passwords, view per-user connections
- Audit Log — Filter by user, provider, action, status, date range. Full request/response payloads
- Settings — Configure public URL, LLM defaults, OAuth credentials for all integrations
ADMIN_EMAIL=admin@example.com # Auto-created on first run
ADMIN_PASSWORD=your-secure-password
JWT_SECRET=your-jwt-secret-min-32-chars
TOKENS_ENCRYPTION_KEY=your-32-char-encryption-key
BASE_URL=http://localhost:8000SEMANTIC_TOOL_ROUTING_ENABLED=true
EMBEDDING_MODEL_NAME=intfloat/multilingual-e5-small # Downloads on first run
SEMANTIC_TOP_PROVIDERS=3
SEMANTIC_TOP_TOOLS=5
SEMANTIC_INTENT_EXPANSION_ENABLED=true
SEMANTIC_INTENT_PHRASE_COUNT=5# Teamwork (https://developer.teamwork.com/)
TEAMWORK_CLIENT_ID=
TEAMWORK_CLIENT_SECRET=
# Slack (https://api.slack.com/apps)
SLACK_CLIENT_ID=
SLACK_CLIENT_SECRET=
# Miro (https://miro.com/app/settings/user-profile/apps)
MIRO_CLIENT_ID=
MIRO_CLIENT_SECRET=
# Figma (https://www.figma.com/developers/apps)
FIGMA_CLIENT_ID=
FIGMA_CLIENT_SECRET=
# Google Calendar (https://console.cloud.google.com/apis/credentials)
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# Telegram personal account (https://my.telegram.org/)
TELEGRAM_API_ID=
TELEGRAM_API_HASH=
# Binance — users connect via their own API Key in the UI
# No server-side credentials neededAll credentials can also be configured via Admin > Settings in the web UI.
| Tool | Description |
|---|---|
hub.integrations.list |
List connected integrations with tool counts |
hub.tools.search |
Semantic search — find tools by intent phrases. Primary discovery method |
hub.tools.list |
List all tools for a specific provider |
hub.tools.call |
Execute a tool by exact name with arguments |
Projects & People
| Tool | Description |
|---|---|
teamwork.projects.list |
List all projects |
teamwork.people.list |
List team members |
teamwork.people.me |
Get current user |
Tasks — Read
| Tool | Description |
|---|---|
teamwork.tasks.list |
List tasks with filters (status, assignee, due date, tags) |
teamwork.tasks.get |
Get full task details by ID |
teamwork.tasks.due_today |
Tasks due today |
teamwork.tasks.overdue |
Overdue tasks |
teamwork.tasks.actionable |
Unblocked tasks ready to work on |
teamwork.tasks.blocked |
Tasks blocked by dependencies |
Tasks — Create & Update
| Tool | Description |
|---|---|
teamwork.tasks.bulk_create |
Create up to 10 tasks with subtasks, dependencies, and tags |
teamwork.tasks.bulk_update |
Update up to 10 tasks at once |
teamwork.tasks.complete |
Mark task as complete |
Task Lists
| Tool | Description |
|---|---|
teamwork.tasklists.list |
List task lists in a project |
teamwork.tasklists.get |
Get list details |
teamwork.tasklists.create |
Create new list |
teamwork.tasklists.update |
Update list |
teamwork.tasklists.delete |
Delete list |
teamwork.tasklists.copy |
Copy list to another project |
teamwork.tasklists.move |
Move list to another project |
Subtasks & Dependencies
| Tool | Description |
|---|---|
teamwork.subtasks.create |
Create subtask under parent |
teamwork.subtasks.list |
List subtasks |
teamwork.dependencies.get |
Get predecessors & dependents |
teamwork.dependencies.set |
Replace all predecessors |
teamwork.dependencies.add |
Add one predecessor |
teamwork.dependencies.remove |
Remove one predecessor |
teamwork.dependencies.clear |
Remove all predecessors |
teamwork.dependencies.bulk_set |
Set dependencies for up to 10 tasks |
Time Tracking
| Tool | Description |
|---|---|
teamwork.time.log |
Log time entry |
teamwork.time.list |
List time entries |
teamwork.time.totals |
Get time totals for reporting |
Tags, Comments & Board
| Tool | Description |
|---|---|
teamwork.tags.list |
List all tags |
teamwork.tags.ensure |
Get or create tag by name |
teamwork.tags.create |
Create tag |
teamwork.tags.update |
Update tag |
teamwork.tags.delete |
Delete tag |
teamwork.comments.add |
Add comment to task |
teamwork.comments.list |
List task comments |
teamwork.workflows.list |
List workflow stages |
teamwork.stages.list |
List board columns |
teamwork.tasks.set_stage |
Move task to stage by ID |
teamwork.tasks.set_stage_by_name |
Move task to stage by name |
teamwork.tasks.move_to_column |
Move task to column by ID |
teamwork.tasks.move_to_column_by_name |
Move task to column by name |
Channels & Users
| Tool | Description |
|---|---|
slack.channels.list |
List channels (public, private, or filtered) |
slack.users.list |
List workspace users |
slack.users.me |
Get current user |
slack.users.info |
Get user details by ID |
slack.users.find_by_email |
Find user by email |
Messages & DMs
| Tool | Description |
|---|---|
slack.messages.post |
Post to channel (supports threads) |
slack.messages.history |
Get channel message history |
slack.dm.list |
List 1:1 DMs |
slack.dm.group_list |
List group DMs |
slack.dm.send |
Send direct message |
slack.dm.history |
Get DM history |
slack.dm.open |
Open DM with user |
slack.dm.open_group |
Open group DM |
Canvases
| Tool | Description |
|---|---|
slack.canvas.create |
Create canvas with markdown |
slack.canvas.edit |
Edit content (append/prepend/replace) |
slack.canvas.delete |
Delete canvas |
slack.canvas.share |
Share with users/channels |
slack.canvas.sections_lookup |
Find sections by heading |
Boards
| Tool | Description |
|---|---|
miro.boards.list |
Search/list boards |
miro.boards.get |
Get board details |
miro.boards.create |
Create board |
miro.boards.update |
Update board |
miro.boards.delete |
Delete board |
miro.boards.copy |
Copy board with content |
miro.boards.members |
List board members & roles |
miro.boards.share |
Share with users by email |
miro.users.me |
Get current user |
Items & Content
| Tool | Description |
|---|---|
miro.items.list |
List items (filter by type) |
miro.items.get |
Get item details |
miro.items.delete |
Delete item |
miro.sticky_notes.bulk_create |
Create up to 10 sticky notes |
miro.text.bulk_create |
Create up to 10 text items |
miro.shapes.bulk_create |
Create up to 10 shapes (20+ types) |
miro.cards.bulk_create |
Create up to 10 cards |
miro.connectors.bulk_create |
Create up to 10 connectors |
Dev & Layout
| Tool | Description |
|---|---|
figma.dev.get_page |
Main tool — CSS-ready HTML + design tokens. Overview or CSS mode |
figma.files.get_layout |
Compact text tree of file structure |
figma.users.me |
Get current user |
figma.files.get_meta |
Lightweight file metadata |
figma.images.export |
Export nodes as PNG/SVG/JPG/PDF |
figma.images.get_fills |
Get image fill URLs |
figma.files.versions |
List file versions |
Comments, Components & Styles
| Tool | Description |
|---|---|
figma.comments.list |
List comments |
figma.comments.create |
Create comment |
figma.comments.delete |
Delete comment |
figma.projects.list |
List team projects |
figma.projects.files |
List files in project |
figma.components.list_team |
List published team components |
figma.components.list_file |
List file components |
figma.components.get |
Get component metadata |
figma.styles.list_team |
List published styles |
figma.styles.list_file |
List file styles |
figma.styles.get |
Get style metadata |
Market Data
| Tool | Description |
|---|---|
binance.market.klines |
OHLCV candles + indicators (RSI 14, MACD 12/26/9, Bollinger 20/2, SMA 20). Always include indicators in one call. |
binance.market.ticker |
24h price stats. Omit symbol for top 20 by volume |
binance.market.depth |
Order book with spread analysis and wall detection |
binance.market.top_movers |
Top gainers/losers (filters low-volume pairs) |
Account & Trading
| Tool | Description |
|---|---|
binance.account.portfolio |
Spot balances with estimated USD values |
binance.account.open_orders |
List unfilled orders |
binance.account.trade_history |
Recent executed trades |
binance.trade.buy |
Place BUY order (MARKET / LIMIT) |
binance.trade.sell |
Place SELL order (MARKET / LIMIT) |
binance.trade.cancel |
Cancel order by ID |
binance.trade.order_status |
Check order status |
Personal account (MTProto) — send as yourself, read history, search:
| Tool | Description |
|---|---|
telegram.users.me |
Get current user info |
telegram.dialogs.list |
List all chats |
telegram.messages.send |
Send message to peer (username, phone, or ID) |
telegram.messages.search |
Search messages |
telegram.messages.history |
Get chat history |
Bot API — notifications only:
| Tool | Description |
|---|---|
telegram_bot.notifications.send |
Send notification via bot (requires chat_id) |
telegram_bot.users.me |
Get bot identity |
Built-in — always available, no connection needed.
| Tool | Description |
|---|---|
memory.summarize_context |
Load context pack by sections. Pass query= for semantic relevance filtering |
memory.search |
Hybrid search: FTS5 keywords + vector similarity, results merged |
memory.upsert |
Create/update item. Auto-vectorized. Deduplicates by (type + scope + title) |
memory.delete |
Delete by ID or title |
memory.pin |
Toggle pinned status (pinned items never expire) |
memory.set_ttl |
Set expiration in days (null = permanent) |
memory.evaluate_write |
Pre-save check — detects secrets, validates sensitivity, suggests TTL |
| Tool | Description |
|---|---|
web_search.search |
Search the web. Returns titles, URLs, snippets |
web_search.open |
Fetch and extract text from any URL |
web_search.full_search |
Combined: search + open top results in one call |
SQLite with automatic migrations on startup. Zero configuration required.
| Table | Purpose |
|---|---|
users |
Accounts, roles (admin/user), approval status |
connections |
OAuth tokens (AES-256 encrypted), connection metadata |
refresh_tokens |
JWT refresh token rotation |
personal_access_tokens |
PAT with SHA-256 hashing & expiration |
api_clients |
Client credentials for OAuth 2.0 apps |
audit_logs |
Full tool call audit trail |
chat_threads, chat_messages |
Web/Telegram conversation history |
memory_items |
AI memory with FTS5 search index |
memory_items_fts |
FTS5 virtual table (auto-synced via triggers) |
memory_item_embeddings |
Vector embeddings for semantic memory search |
tool_embeddings |
Vector embeddings for semantic tool routing |
provider_embeddings |
Vector embeddings for provider-level routing |
automation_tasks, task_triggers, task_runs, task_queue |
Scheduler engine |
agents, agent_edges, agent_tool_policies, agent_skills |
Agent graph and policies |
agent_flows, agent_flow_runs |
Flow definitions and execution history |
user_skill_catalog |
Global reusable skills library |
Interactive docs at /docs (Swagger) and /redoc.
| Endpoint | Description |
|---|---|
POST /mcp |
MCP JSON-RPC 2.0 gateway |
POST /auth/login |
User login |
POST /auth/refresh |
Refresh access token |
POST /auth/personal_token |
Create Personal Access Token |
GET /integrations |
Integration status |
GET /config/mcp |
MCP config for AI clients |
GET /api/chat/* |
Chat threads, messages, assistant execution |
GET /api/tasks/* |
Automation tasks, triggers, runs |
GET /api/agents/* |
Agents, flows, policies, skills |
GET /memory |
Memory management UI |
GET /.well-known/oauth-authorization-server |
OAuth 2.0 metadata (RFC 8414) |
- Create
app/integrations/your_integration/ - Implement
BaseIntegration(seeapp/integrations/base.py):name,display_name,description,auth_typeget_tools()→ list ofToolDefinitionwithuse_casesandtagsfor semantic routingexecute_tool()→ dispatch to tool handlers
- Register in
app/integrations/registry.py - Add UI card in
app/ui/templates/integrations.html
Tools are automatically embedded into the semantic index on next startup — no additional configuration.
MIT License — see LICENSE for details.
MCP Hub — 130+ tools. 3 endpoints. One server. Semantic routing, vector memory, ReAct orchestration, multi-agent flows, and automation — all self-hosted.