feat: MCP Gateway — external server proxy with scoped management#29
Merged
christianromeni merged 6 commits intomainfrom Mar 28, 2026
Merged
feat: MCP Gateway — external server proxy with scoped management#29christianromeni merged 6 commits intomainfrom
christianromeni merged 6 commits intomainfrom
Conversation
Backend for proxying JSON-RPC requests to registered external MCP servers with full access control, usage tracking, metrics, and SSRF protection. Gateway: - POST /api/v1/mcp/:alias routes to built-in voidllm or external servers - HTTP transport with Bearer/Header auth (AES-256-GCM encrypted tokens) - Access control: org/team/key allowlists (most-restrictive-wins) - Prometheus metrics: tool_calls_total, duration, transport_errors - Async usage logger: buffered channel, batch flush, drop-on-full Server CRUD (system_admin only): - POST/GET/PATCH/DELETE /api/v1/mcp-servers - Test connection endpoint (tools/list probe) - Alias validation (reserved "voidllm", URL-safe format) Security: - SSRF protection: blocks private IPs, localhost, cloud metadata by default - Configurable: allow_private_urls for internal deployments (YAML only) - auth_header blocklist (prevents Host/Content-Type override) - Prometheus cardinality protection (unknown methods → "unknown" label) - Response body limits on test connection (10MB) - Error message sanitization DB: migration 0004 — mcp_servers, org/team/key_mcp_access, mcp_tool_calls Tests: transport, DB CRUD, admin API, proxy integration
MCP servers can now be registered at three scopes: - Global (system_admin) — available to all orgs via access control - Org-scoped (org_admin) — visible only within the org - Team-scoped (team_admin) — visible only within the team Alias shadowing: team > org > global priority in proxy resolution. Scoped servers are implicitly accessible — no access control entries needed. Global servers still use explicit org/team/key allowlists. API: - POST/GET /api/v1/orgs/:org_id/mcp-servers (org-scoped) - POST/GET /api/v1/orgs/:org_id/teams/:team_id/mcp-servers (team-scoped) - GET/PATCH/DELETE /api/v1/mcp-servers/:id (ownership-based RBAC) - DNS rebinding protection at transport layer - PostgreSQL-compatible migration (coalesce)
- MCP Servers page under Manage (all roles can view, team_admin+ can create) - Scope selector: Global/Org/Team based on caller's role - Create/Edit/Delete dialogs with Test Connection - Scope badges, auth type badges, active toggle UI improvements: - Auth Type, Key Type, Invite Role use TabSwitcher instead of Select (all options visible without dropdown scroll) - SA Create: Team selector moved to top (avoids scroll on dropdown) - MCP Servers query only fires for caller's role (no 403 retries)
- MCP Servers page under Manage with scoped create (global/org/team) - Create/Edit/Delete dialogs, Test Connection, scope/auth badges - HTTP transport accepts both JSON and SSE responses (auto-detect) - TabSwitcher className prop (replaces -mb-4 hack) - Auth Type, Key Type, Invite Role use TabSwitcher instead of Select - SA Create: Team selector moved to top - Query enablement: no 403 retries for non-system-admin Known limitation: MCP session management not yet implemented — stateful MCP servers (most real-world servers) require Mcp-Session-Id header forwarding after initialize. Next commit.
Session management: - Auto-initialize upstream MCP sessions on first request - Mcp-Session-Id header forwarded on all subsequent requests - Session expired (404) triggers automatic re-initialize + retry - One session per MCP server per VoidLLM instance (in-memory sync.Map) - ListTools() now handles full initialize + notification + tools/list flow UI: - Toast update() function — replaces existing toast content by ID - Test Connection shows loading toast that transitions to success/error - Test timeout increased to 30s (some MCP servers are slow)
YAML sync: - mcp_servers in voidllm.yaml synced to DB at startup (source=yaml) - API-created servers (source=api) preserved, never overwritten - Auth tokens encrypted with server-ID-bound AAD Session management: - Sessions keyed by alias+orgID (cross-org isolation) - Concurrent re-init protected by global mutex with double-check - Metrics use bounded method labels (cardinality protection) API: - PATCH /mcp-servers/:id/activate and /deactivate endpoints - Separate read vs write permission checks (GetMCPServer relaxed) - Source field in response + UI (YAML servers shown as read-only) Config: - MCPServerConfig type with validation (alias, URL, auth_type) - mcp_servers YAML section documented in configuration.md Tests: session forwarding, YAML sync (6), config validation (13), source field (2), auto-initialize flow
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Complete MCP Gateway: register, proxy, and manage external MCP servers with scoped access control, session management, usage tracking, and YAML config sync.
MCP Gateway
Server Management
UI
Access Control
Test plan
go test ./... -race— 19 packages, 75+ MCP Gateway testsnpx tsc --noEmit && npm run lint