feat: Code Mode — WASM-sandboxed JS execution for MCP tool orchestration#30
Merged
christianromeni merged 9 commits intomainfrom Mar 29, 2026
Merged
feat: Code Mode — WASM-sandboxed JS execution for MCP tool orchestration#30christianromeni merged 9 commits intomainfrom
christianromeni merged 9 commits intomainfrom
Conversation
…ion (#30) Add Code Mode: LLMs write JavaScript that orchestrates multiple MCP tool calls in a single execution, reducing token usage by 30-80%. Scripts run in a QuickJS/WASM sandbox (fastschema/qjs + Wazero) embedded in VoidLLM. Three new built-in MCP tools: - list_servers: discover available MCP servers - search_tools: find tools by keyword across servers - execute_code: run JS with MCP tools as async functions Runtime: pool of QJS runtimes (default 8), fresh runtime per execution, tool schema cache with lazy fetch, console capture in results. Configurable via voidllm.yaml (disabled by default): mcp.code_mode.enabled, pool_size, memory_limit_mb, timeout, max_tool_calls Also fixes session re-init double-check in MCP proxy.
#31) Split built-in MCP into two servers: - /api/v1/mcp — Code Mode (list_servers, search_tools, execute_code) - /api/v1/mcp/voidllm — Management (list_models, get_usage, etc.) - /api/v1/mcp/:alias — External MCP server proxy Per-tool blocklist for Code Mode: - Migration 0005: mcp_tool_blocklist table - CRUD API: GET/POST/DELETE /mcp-servers/:id/blocklist - Defense in depth: filtered before sandbox injection + checked in ToolCaller - Blocklist also applied to search_tools and list_servers tool counts Tool refresh endpoint: - POST /mcp-servers/:id/refresh-tools with 60s cooldown Admin controls: - code_mode_enabled toggle in API response and PATCH - UI: Code Mode toggle column, expanded row with blocklist management Shared MCP handler helper eliminates POST/SSE handler duplication.
…ory, TypeScript types (#32) JS Proxy pattern replaces static preamble generator: - Single __callTool dispatch via ES6 Proxy interception - Any tool name characters supported, preamble is O(1) in tool count SSE upstream transport support: - Auto-detect Streamable HTTP vs deprecated SSE protocol - Lazy detection with sync.Once, origin validation on endpoints Execution history: - Migration 0006: code_mode_execution_id on mcp_tool_calls - UUIDv7 per execute_code call groups all tool calls Dynamic TypeScript types in execute_code description: - GenerateToolTypeDefs converts cached tool schemas to TS declarations - OnToolsListHook injects types at tools/list time Bug fixes: - MCP access control enforced in all Code Mode closures for global servers - ToolCache fetcher resolves servers across all scopes - Frontend blocklist DELETE matches backend query parameter API
…buttons (#33) Persistent tool cache: - Migration 0007: mcp_server_tools table for DB-backed tool schemas - Startup loads from DB (zero HTTP calls, TypeScript types immediately available) - 24h background refresh keeps schemas current - Write-through on every fetch (RefreshServer, GetTools) - DB entries marked stale on load so they refresh within maxAge SSE transport detection: - Servers using deprecated SSE protocol auto-deactivated at startup - Clear error message: "server uses deprecated SSE transport" - Test connection also detects and deactivates SSE servers Tools list UI: - GET /mcp-servers/:id/tools endpoint returns cached tools with blocked status - Expanded row shows all tools with Block/Unblock buttons - Block buttons work for YAML-sourced servers (blocklist is independent of source) - Plug icon centered in sidebar and MCP servers page Also fixes: - ToolStore.Delete uses server ID (not alias) to avoid soft-delete lookup failure - Corrupt JSON schemas skipped on DB load instead of serving empty schemas
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Extract 3 closures (ExecuteCode, ListAccessibleMCPServers, SearchMCPTools) from app.go into codeModeService in code_mode.go. Shared accessibleServers helper eliminates duplicated server-listing + access-check logic. New tests: - code_mode_test.go: 21 tests (mock DB, real WASM executor) - mcp_tool_blocklist_test.go: 11 tests (CRUD, conflicts, isolation) - mcp_server_tools_test.go: 14 tests (upsert, replace, active filter) app.go reduced by ~400 lines.
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
list_servers,search_tools,execute_codeon dedicated/api/v1/mcpendpointexecute_codedescription so LLMs see available tools attools/listtimeconsole.log/warn/erroroutput returned in execution resultsEndpoints
POST /api/v1/mcpPOST /api/v1/mcp/voidllmPOST /api/v1/mcp/:aliasGET /api/v1/mcp-servers/:id/toolsGET/POST/DELETE /api/v1/mcp-servers/:id/blocklistPOST /api/v1/mcp-servers/:id/refresh-toolsConfig
Migrations
mcp_tool_blocklisttablecode_mode_execution_idonmcp_tool_callsmcp_server_toolspersistent cache tableTest plan
go test ./... -race— all packages green/api/v1/mcp, tools visible and callable