fix(runtime): MCP proxy router drops downstream subpaths and returns 404
- Dominant language
- TypeScript
- Stars
- 147
- Forks
- 26
- Avg merge
- 5h 6m
- Merged PRs (30d)
- 40
Description
### Area
Runtime
### Summary
`driver.all("/mcp/proxy/:serverId", ...)` in `apps/api/src/adapters/http/routes/driver-route.ts` only matches the single exact path segment without wildcard subpath matching (`/*`). When a client or driver sends requests with downstream subpaths (e.g. `/mcp/proxy/:serverId/messages` or `/mcp/proxy/:serverId/sse`), Hono returns 404 Route Not Found. Additionally, `toUpstreamProxyUrl` only copies search parameters and completely ignores incoming request pathnames, dropping any subpaths even if received.
### Steps to reproduce
1. Configure an MCP server with target URL (e.g. `https://mcp.example.com/base`).
2. Mint a runtime action grant for `mcp_proxy`.
3. Send an HTTP request to `/api/driver/mcp/proxy//messages` with the authorization grant.
4. Inspect the HTTP response status.
### Expected behavior
Requests with subpaths should match the proxy route, validate paths against directory traversal, and forward the request to `https://mcp.example.com/base/messages` with original query parameters (excluding the internal `grant` token).
### Actual behavior
1. Hono returns 404 Route Not Found because the router is defined as `driver.all("/mcp/proxy/:serverId", ...)` without wildcard support.
2. `toUpstreamProxyUrl` unconditionally discards incoming subpaths, resolving only `new URL(upstreamUrl)` with search parameters.
### Evidence
- In `apps/api/src/adapters/http/routes/driver-route.ts`, line 783 registers only the single-segment route:
```ts
driver.all("/mcp/proxy/:serverId", async (c) => { ... });
```
In contrast, LLM proxy (line 652) registers `/llm/proxy/:credentialId/*` and extracts subpaths via `extractLlmProxySubPath`.
- `toUpstreamProxyUrl` ignores `request.url` pathname completely:
```ts
function toUpstreamProxyUrl(request: Request, upstreamUrl: string): string {
const target = new URL(upstreamUrl);
const incoming = new URL(request.url);
for (const [key, value] of incoming.searchParams) {
if (key !== "grant") {
target.searchParams.append(key, value);
}
}
return target.toString();
}
```
### Environment
- Repository: `langgenius/mosoo`
- Revision: HEAD (`main`)
- Component: `apps/api` (Driver HTTP routes)
### Contribution
I can submit a PR
Contributor guide
Research direction
Start in apps/api/src/adapters/http/routes/driver-route.ts, comparing the MCP proxy route around line 783 with the wildcard LLM proxy route around line 652 and tracing toUpstreamProxyUrl. Reproduce the /api/driver/mcp/proxy//messages request, then verify subpaths are validated and forwarded to the configured upstream with query parameters preserved except grant.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100