Repository navigation
feat(mcp): add Code Mode (execute_script) with a sandboxed V8 engine - #136
Merged
Merged
Conversation
An agent that traces a problem makes many small tool calls that depend on
each other. Each round trip costs time and tokens. Code Mode runs one
agent-written async JavaScript body that calls the tools on the server and
returns only the final result.
The design follows Code Mode in model-context-gateway: `script`/`code` and
`arguments`/`args`; `tools.<tool>(args)`, `cc.callTool(name, args)`, and the
gateway forms `tools.contextcortex.<tool>` and `mcg.callTool`; parsed JSON
results; a tool error throws a JavaScript Error; console logs; the result
envelope {result, logs, executionTimeMs, toolCallsCount}; no recursive
execute_script; and limits on time (30 s), tool calls (50), and memory
(64 MB), set with CODE_MODE_* environment variables.
The sandbox is a new V8 isolate per run (mini-racer 0.14.1). The script
reaches Python only through one async bridge function, and values cross as
JSON strings. Every tool call goes through the normal handler, so its role
check applies. The resource contextcortex://code-mode/sdk.d.ts gives one
typed declaration per tool, made from the tool schemas.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
# Conflicts: # REQUIREMENTS.md # docs/mcp-tools-and-resources.md
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.
Problem
An agent that traces a problem makes many small tool calls that depend on each other: find the route, trace its handler, trace the callers of each repository method, read a file. Each call is one round trip, and each intermediate result goes into the agent's context. In a debugging test on a real repository, the agent with ContextCortex was slower than an agent with only grep and file reads, mostly because of these round trips.
Fix
New tool
execute_script(Code Mode). It uses the same pattern as Code Mode (execute_script) in model-context-gateway, so a script also runs unchanged through the gateway.script(aliascode): an async JavaScript body; top-levelawaitandreturnwork.arguments(aliasargs): an input object, available asargsandarguments.await tools.<tool>(args),await cc.callTool("<tool>", args), and the gateway formstools.contextcortex.<tool>(args)andmcg.callTool(...). Results are parsed JSON. A tool error (an unknown tool, unknown or missing arguments, or a result with anerrorfield) throws anErrorthat the script can catch.{result, logs, executionTimeMs, toolCallsCount}. On a failure:{error: "script_failed", message, logs, executionTimeMs, toolCallsCount}. Line numbers in errors count from the first line of the script. Results larger than 100,000 characters are cut and markedtruncated.app/services/script_sandbox.py): a new V8 isolate per run (mini-racer==0.14.1, ISC license, released 2026-02-01). The script reaches Python only through one async bridge function; values cross as JSON strings. It has no file, network, or process access (require,process, andfetchare not defined).CODE_MODE_TIMEOUT_SECONDS(30, 1..300),CODE_MODE_MAX_TOOL_CALLS(50, 1..500),CODE_MODE_MAX_MEMORY_MB(64, 8..512).CODE_MODE_ENABLED=falseturns it off. V8 has no statement counter, so the timeout stops endless loops.execute_scriptcannot call itself.contextcortex://code-mode/sdk.d.ts, with one typed declaration per tool, made from the tool schemas, with the argument descriptions as JSDoc.mini-raceris inrequirements.txtand pinned inpython-constraints.txt.contextcortex.speccollectspy_mini_racer(the V8 library and the ICU data file), which mini-racer loads from_MEIPASS/py_mini_racerin a PyInstaller build.Tests
tests/test_execute_script.py(13 tests, run locally with mini-racer 0.14.1):args/arguments, the gateway forms, andcc.callTool.return.trace_pathhandler on an SQLite graph and returns the callers of two methods.tests/test_mcp_pagination_and_resources.pynow expects 20 tools. I also builtsdk.d.tsfrom the real registered tools (19 declarations;execute_scriptis not listed).The portable bundle is built only in CI, so the release build is the first check that the V8 library loads from the bundle.
🤖 Generated with Claude Code