Features: add mcp proxy#9
Conversation
Groundwire Verification FailedThis PR will not be reviewed because commits are not signed by a recognized Groundwire ID. Why?This repository requires contributors to prove ownership of an onchain Groundwire identity. How to fix this
This repository is protected by Groundwire for GitHub. |
bonbud-macryg
left a comment
There was a problem hiding this comment.
Otherwise staggering genius, very cool
There was a problem hiding this comment.
Pls import in /peru.yaml at the root of this repo, same for all other Landscape dependencies.
| 2. **MCP proxy** at `/apps/mcp/mcp` — aggregates the native server plus any | ||
| number of remote MCP / OpenAPI / Google Discovery upstreams behind a single | ||
| endpoint, with per-server tool filtering and OAuth 2.0 + PKCE token | ||
| management. OpenAPI and Discovery spec docs are dynamically converted | ||
| to MCP tool calls. | ||
| 3. **Operator console** at `/apps/mcp/` — a web UI for configuring upstreams, | ||
| OAuth providers, the API key, and inspecting tools. |
There was a problem hiding this comment.
The endpoint situation with /mcp and /apps/mcp is kind of weird now, clean layout might be:
/mcp- Urbit MCP endpoint/apps/mcp- Urbit MCP UI/mcp/servers- MCP proxy endpoint/mcp/servers/{id}- endpoint for a single proxied MCP server
|
|
||
| Get your ship's web login code from the Dojo: | ||
| - `%mcp-server` — native MCP server bound to `/mcp` | ||
| - `%mcp-proxy` — aggregator bound to `/apps/mcp/api` and `/apps/mcp/mcp` |
There was a problem hiding this comment.
Endpoint layout as above
| +$ state-0 | ||
| $: %0 | ||
| servers=(map server-id mcp-server-0) | ||
| server-order=(list server-id) | ||
| == | ||
| :: | ||
| +$ state-1 | ||
| $: %1 | ||
| servers=(map server-id mcp-server-1) | ||
| server-order=(list server-id) | ||
| == | ||
| :: | ||
| +$ state-2 | ||
| $: %2 | ||
| servers=(map server-id mcp-server) | ||
| server-order=(list server-id) | ||
| == | ||
| :: | ||
| +$ state-3 | ||
| $: %3 | ||
| servers=(map server-id mcp-server) | ||
| server-order=(list server-id) | ||
| tool-filters=(map server-id tool-filter) | ||
| == | ||
| :: | ||
| +$ state-4 | ||
| $: %4 | ||
| servers=(map server-id mcp-server) | ||
| server-order=(list server-id) | ||
| tool-filters=(map server-id tool-filter) | ||
| client-key=(unit @t) :: user-set x-api-key for /apps/mcp/mcp | ||
| internal-token=(unit @t) :: mcp-server's auto-gen token (cached) | ||
| == | ||
| :: | ||
| +$ versioned-state | ||
| $% state-0 | ||
| state-1 | ||
| state-2 | ||
| state-3 | ||
| state-4 | ||
| == |
There was a problem hiding this comment.
Do we need all these on the first release?
| %- agent:dbug | ||
| =| state-0:oauth | ||
| =* state - | ||
| =/ refreshing *(set provider-id:oauth) :: in-flight refresh locks (non-persisted) |
There was a problem hiding this comment.
Is this an Tlon convention for transient state in an agent? Never seen this before
This PR merges the urbit-mcp-proxy desk into %mcp as a single integrated control plane.
Features
/apps/mcp/mcp. Point MCP client here and it sees the union of every upstreamyou've configured, with tools namespaced by server id.
%oauthagent). Store provider credentials and config, attach them to upstreams, and the proxy injects bearer tokens per request. Grants are refreshed automatically before expiry with single-flight locking. Client secrets stay on the ship and are never surfaced to the browser./apps/mcpNote about breaking changes
I refactored the auth to use an
X-API-Keyheader, both on the original/mcpendpoint as well as the new aggregated/apps/mcp/mcpendpoint; this is user-definable. With proxied tool whitelisting this allows for scoped clients, but breaks previously configured clients.This is the only change to the original MCP server functionality, everything else is additive.
GUI screenshots