Skip to content

feat: add MCP routing modes (direct, code_execution, retrieve_tools)#327

Merged
Dumbris merged 15 commits intomainfrom
031-routing-modes
Mar 10, 2026
Merged

feat: add MCP routing modes (direct, code_execution, retrieve_tools)#327
Dumbris merged 15 commits intomainfrom
031-routing-modes

Conversation

@Dumbris
Copy link
Member

@Dumbris Dumbris commented Mar 10, 2026

Summary

  • Add three MCP routing modes: retrieve_tools (current default/BM25 search), direct (all tools exposed with serverName__toolName naming), and code_execution (JS orchestration with tool catalog)
  • Dedicated endpoints always available: /mcp/all (direct), /mcp/code (code_execution), /mcp/call (retrieve_tools)
  • Default /mcp endpoint respects routing_mode config setting
  • Auth enforcement: agent token permissions checked in direct mode handlers and JS runtime call_tool() invocations
  • Permission tracking: code_execution activity logs record highest permission level used across all tool calls
  • CLI: routing mode shown in mcpproxy status and mcpproxy doctor output
  • API: GET /api/v1/routing endpoint with mode info and available endpoints
  • Web UI: routing mode badge in TopHeader with endpoint URLs

Related #279

Test plan

  • Config validation: routing_mode accepts only valid values, defaults to retrieve_tools
  • Tool name parsing: serverName__toolName round-trip (format/parse) with edge cases
  • Auth enforcement: permission denied, server access denied, admin bypass, destructive permissions
  • JS runtime auth: read-only token blocked from write calls, permission aggregation
  • API routing endpoint: returns correct mode and endpoints
  • CLI status: includes routing_mode in output
  • Nil config guard: handles nil GetConfig() in test mocks
  • Build verification: personal and server editions compile clean
  • Race detector: all tests pass with -race

claude added 12 commits March 10, 2026 09:49
Add RoutingMode field to Config struct supporting three modes:
- retrieve_tools (default): BM25 search via retrieve_tools + call_tool variants
- direct: All upstream tools exposed with serverName__toolName naming
- code_execution: JS orchestration via code_execution tool

Includes validation, default application, JSON serialization, and tests.
…c 031)

Create mcp_routing.go with:
- ParseDirectToolName/FormatDirectToolName for serverName__toolName convention
- buildDirectModeTools: discovers upstream tools and creates direct handlers
- buildCodeExecModeTools: creates code_execution + retrieve_tools tool set
- makeDirectModeHandler: handles auth, permissions, upstream calls, activity logging
- buildToolCatalogDescription: generates tool catalog for code_execution description
Add directServer and codeExecServer fields to MCPProxyServer struct.
Initialize separate MCP server instances during proxy creation:
- server (existing): retrieve_tools mode tools
- directServer: direct mode with serverName__toolName tools
- codeExecServer: code_execution + retrieve_tools tools

Add GetMCPServerForMode() to select the correct instance by mode.
Add RefreshDirectModeTools() for rebuilding tools on server changes.
Register per-mode MCP endpoints in startCustomHTTPServer:
- /mcp/all  -> direct mode (all upstream tools with serverName__toolName)
- /mcp/code -> code_execution mode (JS orchestration + retrieve_tools)
- /mcp/call -> retrieve_tools mode (explicit, same as /mcp default)
- /mcp      -> configured routing_mode (backward compatible default)

Add listenForRoutingModeRefresh goroutine to rebuild direct and
code_execution mode tools when servers.changed events fire.
Test cases for makeDirectModeHandler:
- Permission denied when agent lacks required permission tier
- Server access denied for restricted agent tokens
- Agent with correct permissions passes auth checks
- Destructive tools require destructive permission specifically
- No auth context (backward compatible) passes auth checks
Add AuthInfo and ToolAnnotationLookup to ExecutionOptions for permission
enforcement during code_execution. Each call_tool() invocation now:
- Checks server access against auth context AllowedServers
- Looks up tool annotations to determine required permission tier
- Validates agent has the required permission (read/write/destructive)
- Tracks max_permission_level across all calls in the execution

Wire up auth context from MCP handler to jsruntime via handleCodeExecution.
Add lookupToolPermission helper to resolve tool permission from index.
- Add routing_mode field to StatusInfo struct (table and JSON output)
- Display routing mode in printStatusTable with "Routing:" label
- Default to retrieve_tools when routing_mode is empty
- Show routing mode description and endpoints in doctor output
- Add tests for routing mode in table, JSON, and config-fallback
- Add GET /api/v1/routing endpoint returning mode, description, endpoints, available_modes
- Add routing_mode field to GET /api/v1/status response
- Default to retrieve_tools when routing_mode is not configured
- Add tests for routing endpoint and status routing_mode field
- Add RoutingInfo type and routing_mode to StatusUpdate in api.ts
- Add getRouting() API method for /api/v1/routing endpoint
- Add routing state, routingMode computed, and fetchRouting action to system store
- Display routing mode badge in TopHeader.vue
- Fetch routing info on app initialization
- Add routing_mode to config schema in swagger.yaml
- Add GET /api/v1/routing endpoint to OpenAPI spec
- Rebuild frontend dist with routing mode UI changes
GetConfig() can return nil config (e.g., in tests with mock controllers).
Add nil guard before accessing cfg.RoutingMode to prevent panic.
C1: Default /mcp endpoint now respects routing_mode config by using
GetMCPServerForMode() instead of always using retrieve_tools server.

C2: lookupToolPermission now uses exact match via lookupToolAnnotations
(StateView) as primary lookup, with BM25 index search (limit 20) as
fallback. Prevents wrong permission tier from fuzzy search results.

I1: When code execution is disabled in config, the /mcp/code endpoint
returns a clear error message instead of confusing runtime failure.
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Mar 10, 2026

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: dc8de2d
Status:⚡️  Build in progress...

View logs

@github-actions
Copy link

github-actions bot commented Mar 10, 2026

📦 Build Artifacts

Workflow Run: View Run
Branch: 031-routing-modes

Available Artifacts

  • archive-darwin-amd64 (24 MB)
  • archive-darwin-arm64 (21 MB)
  • archive-linux-amd64 (13 MB)
  • archive-linux-arm64 (11 MB)
  • archive-windows-amd64 (23 MB)
  • archive-windows-arm64 (21 MB)
  • frontend-dist-pr (0 MB)
  • installer-dmg-darwin-amd64 (26 MB)
  • installer-dmg-darwin-arm64 (24 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page linked above
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 22897560537 --repo smart-mcp-proxy/mcpproxy-go

Note: Artifacts expire in 14 days.

claude added 3 commits March 10, 2026 12:13
Resolves staticcheck QF1003 lint error by converting if/else chain
to a tagged switch on routingMode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Dumbris Dumbris merged commit 88bd598 into main Mar 10, 2026
9 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants