MCP Proxy
Workers never hold real credentials. The gateway resolves them at request time and proxies every outbound MCP call.
Request flow
Section titled “Request flow”Every MCP URL a worker receives points back to the gateway with an X-Mcp-Id header identifying the upstream server.
- Worker sends a JSON-RPC request to the gateway proxy.
- Gateway authenticates the worker JWT, extracts
agentId/userId. - Looks up credentials for that user via the device-auth flow — auto-refreshes expired tokens.
- Injects the
Authorizationheader, forwards to the upstream MCP. - Response flows back to the worker.
Workers call tools/list and tools/call — credential handling is invisible.
Configuration sources
Section titled “Configuration sources”MCP servers come from two sources, merged per agent:
- Skills registry (
config/system-skills.json) — global MCPs available to every agent. - Per-agent settings — MCPs added through the settings page or agent-driven install.
Global MCPs take precedence when IDs collide.
Authentication
Section titled “Authentication”MCP server authentication uses a device-code flow managed through Owletto:
- Worker attempts to use an MCP tool that requires auth.
- Gateway initiates a device-code flow and sends the user a login link.
- User authenticates via the link, credentials are stored in Redis per
(agentId, userId, mcpId). - Future proxy requests inject the token automatically, with auto-refresh on expiry.
Third-party API integrations (GitHub, Google, etc.) are handled entirely by Owletto MCP servers — the gateway acts as a thin proxy.
Agent-driven installation
Section titled “Agent-driven installation”Agents can add MCPs at runtime:
- Agent calls
SearchSkills/InstallSkill(with a capabilityid). - Gateway generates a prefilled settings link.
- User reviews and approves — MCP is active immediately.
Configuration reference
Section titled “Configuration reference”Adding an MCP to the skills registry
Section titled “Adding an MCP to the skills registry”{ "id": "my-mcp", "name": "My MCP Server", "description": "What this MCP does", "mcpServers": [ { "id": "my-mcp", "name": "My MCP", "url": "https://mcp.example.com", "type": "sse" } ]}With custom headers:
{ "id": "my-mcp", "name": "My MCP", "url": "https://mcp.example.com", "type": "sse", "headers": { "Authorization": "Bearer ${env:MY_MCP_TOKEN}" }}Header values support ${env:VAR_NAME} substitution so secrets stay in environment variables.