Skip to content

Add script middleware with config toggle for code mode#4821

Draft
jerm-dro wants to merge 6 commits intomainfrom
jerm-dro/script-middleware
Draft

Add script middleware with config toggle for code mode#4821
jerm-dro wants to merge 6 commits intomainfrom
jerm-dro/script-middleware

Conversation

@jerm-dro
Copy link
Copy Markdown
Contributor

Summary

  • vMCP code mode (Ship opt-in code mode for vMCP #4742) lets agents execute Starlark scripts server-side to batch multi-tool workflows into a single call. PR 1 introduced the script engine package; this PR adds the HTTP middleware that integrates it into the vMCP request pipeline.
  • Adds a ScriptEngine config toggle (disabled by default) that controls whether the execute_tool_script virtual tool is available. When enabled, the middleware intercepts tools/call for script execution and injects the virtual tool into tools/list responses.

Part of #4742

Type of change

  • New feature

Test plan

  • Unit tests (task test)
  • Linting (task lint-fix)

Changes

File Change
pkg/vmcp/config/config.go Add ScriptEngineConfig type and ScriptEngine field to Config
pkg/script/response_capture.go Minimal http.ResponseWriter for capturing inner tool call responses
pkg/script/middleware.go HTTP middleware: tools/list injection, tools/call interception, inner tool dispatch
pkg/script/middleware_test.go Table-driven tests for config toggle, script execution, error paths
pkg/vmcp/server/server.go Add ScriptMiddleware to Config, insert in Handler() chain after authz
cmd/vmcp/app/commands.go Wire createScriptMiddleware from config

Does this introduce a user-facing change?

No. The config toggle defaults to disabled. This becomes user-facing when CRD types are added in PR 4.

Special notes for reviewers

Review by commit — each commit introduces one concern:

  1. Config type (ScriptEngineConfig)
  2. Response capture writer (no httptest.NewRecorder in production)
  3. Middleware implementation (tools/list injection, tools/call interception, inner dispatch)
  4. Server wiring (Config field, Handler() chain, commands.go)
  5. Unit tests

Inner tool dispatch: Scripts call tools through next.ServeHTTP(capture, innerReq) where capture is a purpose-built responseCapture writer. The parsed MCP request is cleared from context so the parser re-parses the synthetic request. This ensures inner calls flow through the full middleware chain (authz, discovery, etc.).

Middleware chain placement: Script middleware wraps after authz, so scripts only see authorized tools and inner tool calls are subject to authorization.

Generated with Claude Code

jerm-dro and others added 5 commits April 14, 2026 11:37
Add configuration type for the script execution engine (code mode).
ScriptEngineConfig controls whether execute_tool_script is available,
with tuning parameters for step limits and parallel concurrency.

Part of #4742

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Minimal http.ResponseWriter implementation that captures status,
headers, and body into a buffer. Used by the script middleware to
dispatch inner tool calls through the middleware chain without
importing net/http/httptest in production code.

Part of #4742

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
HTTP middleware that integrates the script engine into the vMCP
request pipeline:

- Intercepts tools/call for execute_tool_script: extracts script and
  data arguments, constructs an Executor with tool bindings that route
  inner calls through the middleware chain, returns the aggregated
  result as a JSON-RPC response.
- Intercepts tools/list: appends the execute_tool_script virtual tool
  definition with a dynamic description listing all available tools.
- Uses ParsedMCPRequest from context to inspect requests without
  re-reading the body.
- Inner tool calls dispatch through next handler via responseCapture,
  clearing the parsed request context so the MCP parser re-parses
  the synthetic request.

Part of #4742

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add ScriptMiddleware field to server Config and insert it into the
middleware chain after authz. Inner tool calls from scripts flow
through the full chain (discovery, authz, etc.).

Wire createScriptMiddleware in commands.go: when
config.ScriptEngine.Enabled is true, creates the middleware with the
configured step limit and parallel concurrency; otherwise nil (no
virtual tool exposed).

Part of #4742

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Table-driven tests covering:
- tools/list injects execute_tool_script when middleware is active
- Script execution calls multiple backend tools and returns aggregated
  result
- Non-script tools/call passes through to backend unchanged
- Missing, non-string, and syntactically invalid script arguments
  return appropriate JSON-RPC errors
- Non-MCP methods pass through unchanged
- Config toggle: no middleware → no virtual tool; with middleware →
  virtual tool present

Part of #4742

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions bot added the size/L Large PR: 600-999 lines changed label Apr 14, 2026
Generated artifacts for the new ScriptEngineConfig type:
- docs/operator/crd-api.md — CRD API reference documentation
- pkg/vmcp/config/zz_generated.deepcopy.go — deepcopy methods
- deploy/charts/operator-crds/ — CRD manifests with scriptEngine field
- cmd/vmcp/app/commands.go — import ordering fix (gci)

Part of #4742

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/L Large PR: 600-999 lines changed labels Apr 14, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 14, 2026

Codecov Report

❌ Patch coverage is 66.94215% with 80 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.97%. Comparing base (47f4289) to head (c256972).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
pkg/script/middleware.go 70.00% 40 Missing and 26 partials ⚠️
cmd/vmcp/app/commands.go 0.00% 9 Missing ⚠️
pkg/vmcp/server/server.go 0.00% 2 Missing and 1 partial ⚠️
pkg/script/response_capture.go 80.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4821      +/-   ##
==========================================
- Coverage   69.05%   68.97%   -0.08%     
==========================================
  Files         530      532       +2     
  Lines       55375    55523     +148     
==========================================
+ Hits        38238    38297      +59     
- Misses      14193    14258      +65     
- Partials     2944     2968      +24     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Large PR: 600-999 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant