MCP Pass-Through¶
mcp-v8 can register upstream MCP servers as sub-servers. That lets the
runtime use external MCP tools from JavaScript, while still keeping execution
inside mcp-v8's JavaScript runtime, state model, and policy boundary.
This is why "pass-through" is the right term. mcp-v8 is not only an MCP
server for downstream clients. It can also act as an MCP client to upstream
servers, then expose those capabilities inside run_js.
Register sub-servers¶
You register upstream MCP servers with --mcp-server or --mcp-config.
Those definitions tell mcp-v8 which external servers to connect to at
startup.
At the conceptual level, each configured sub-server becomes another capability source for the JavaScript runtime.
See Connect as an MCP Server and CLI Flags for configuration details.
Call upstream tools from JavaScript¶
Inside the runtime, upstream tools are exposed through globalThis.mcp.
The important pieces are:
mcp.serversfor connected server namesmcp.listTools()for discoverymcp.callTool(server, tool, args)for execution
Conceptually, that means an agent can use JavaScript as the orchestration layer while still reaching out to other MCP systems when needed.
const tools = mcp.listTools("github");
const result = await mcp.callTool("github", "create_issue", {
owner: "acme",
repo: "roadmap",
title: "Document MCP pass-through",
});
console.log(JSON.stringify(result, null, 2));
The tool call still happens through run_js, not as a separate direct tool
dispatch from the outer MCP client.
Expose stub tools for discovery¶
mcp-v8 can also publish optional stub tools on its own MCP surface. These
stubs mirror the upstream tools with names like
runjs__github__create_issue.
This is useful because it preserves native MCP tool discovery for downstream agents:
- the agent can see the tool in
tools/list - the tool carries the upstream input schema
- the agent can reason about the tool as if it were locally available
But the stub is intentionally not a direct proxy. Calling it returns
instructions telling the agent to invoke the tool through run_js and
mcp.callTool(...).
Why stubs point back to run_js¶
This design is deliberate.
If a discovered upstream tool executed directly as a plain proxy call, the
agent would bypass the main reason to use mcp-v8 in the first place:
- JavaScript orchestration
- resumable heaps and sessions
- captured output
- runtime-level control and policy checks
By steering the agent back to run_js, mcp-v8 keeps the tool call inside
the same execution model as the rest of the task.
The result is guided delegation, not transparent proxying.
Compose tools without pushing data through the context window¶
One of the main benefits of pass-through is that JavaScript can compose local runtime capabilities and upstream MCP tools in one workflow.
For example, an agent might:
- fetch structured data from an external API
- write the raw response to the sandboxed filesystem
- transform it into a smaller report
- call an upstream storage MCP server to upload the result to S3
- call another upstream tool to create a signed URL
- return only the signed URL and a short summary to the user
Conceptually:
The key advantage is that the large payload never has to be copied into the agent's context window. The runtime can fetch, store, transform, and hand off artifacts in place, then return only the useful result.
That is a good fit for:
- large API responses
- multi-step document generation
- binary or structured artifacts
- workflows where the user only needs a link, summary, or final status
Policy and control boundaries¶
Pass-through does not mean "anything connected is automatically trusted."
mcp.callTool() can still be gated by policy. That lets operators control
which upstream servers and tools the runtime may use, and with what arguments.
So the control chain becomes:
- discover or select an upstream tool
- invoke it from JavaScript
- evaluate policy
- call the upstream MCP server only if allowed
See Policy System for the broader policy model.
When to use pass-through¶
Use MCP pass-through when:
- JavaScript should orchestrate several steps around an upstream tool call
- the agent benefits from heaps, sessions, or captured output
- you want discovery to stay visible through MCP stubs
- you want one runtime to coordinate both local code and remote MCP tools
Call an upstream server directly from the outer client instead when the
runtime adds no value and you do not need run_js as the execution layer.