Skip to content

Add experimental CodeMode transform#3297

Merged
jlowin merged 20 commits intomainfrom
code-mode
Feb 27, 2026
Merged

Add experimental CodeMode transform#3297
jlowin merged 20 commits intomainfrom
code-mode

Conversation

@aaazzam
Copy link
Copy Markdown
Collaborator

@aaazzam aaazzam commented Feb 25, 2026

Closes #3296

Summary

Adds CodeMode, an experimental transform inspired by Cloudflare's Code Mode that collapses a large tool surface into two meta-tools: search (inspect tool metadata via Python) and execute (chain call_tool(...) invocations in Python). Useful when LLMs need to plan multi-step workflows against many tools without listing them all in context.

Changes

  • New fastmcp.experimental.transforms.CodeMode transform with pluggable SandboxProvider protocol
  • Default MontySandboxProvider backed by pydantic-monty (new fastmcp[code-mode] optional dep)
  • Supports custom tool names/descriptions, default arguments, search helpers, and respects disabled/auth-gated tools
  • Documentation at docs/servers/transforms/code-mode.mdx
  • 10 test cases with an in-process sandbox provider

Design notes

Placed under fastmcp.experimental.transforms since this is an experimental API. The sandbox provider is a protocol so third-party runtimes (remote sandboxes, WASM, etc.) can plug in without changes to the transform itself.


JL notes update from review:

@marvin-context-protocol marvin-context-protocol Bot added feature Major new functionality. Reserved for 2-4 significant PRs per release. Not for issues. server Related to FastMCP server implementation or server-side functionality. labels Feb 25, 2026
chatgpt-codex-connector[bot]

This comment was marked as resolved.

@marvin-context-protocol
Copy link
Copy Markdown
Contributor

marvin-context-protocol Bot commented Feb 25, 2026

Test Failure Analysis

Summary: The Windows CI job failed because test_server_performance_no_latency asserts that OpenAPIProvider initialization completes in under 100ms, but the Windows runner took ~317ms (~3x the threshold).

Root Cause: The test at tests/server/providers/openapi/test_comprehensive.py:736 uses a hard wall-clock timing assertion (< 0.1 seconds). Windows CI runners are typically slower than Linux, making this threshold unreliable across platforms.

Suggested Solution:

In tests/server/providers/openapi/test_comprehensive.py, either:

  1. Increase the threshold to something reasonable for all platforms (e.g., < 1.0):

    assert initialization_time < 1.0  # Should be well under 1 second
  2. Skip on Windows (if Linux-only timing is sufficient):

    @pytest.mark.skipif(sys.platform == "win32", reason="performance thresholds unreliable on Windows CI")
    async def test_server_performance_no_latency(self, ...):

Option 1 is simpler and still validates the basic intent (no multi-second startup cost).

Detailed Analysis

Failed job: "Tests: Python 3.10 on windows-latest" (Job ID: 65171185865)

Log excerpt:

FAILED tests/server/providers/openapi/test_comprehensive.py::TestOpenAPIComprehensive::test_server_performance_no_latency
E       assert 0.3173520565032959 < 0.1
tests\server\providers\openapi\test_comprehensive.py:736: AssertionError

The test passed on:

  • Python 3.10 on ubuntu-latest ✅
  • Python 3.13 on ubuntu-latest ✅

But failed on:

  • Python 3.10 on windows-latest ❌ (317ms vs 100ms threshold)

This is a performance assertion that's sensitive to CI runner speed. The 100ms threshold is reasonable for a development machine but too tight for Windows CI runners, which are known to be slower than Linux runners.

All other 4,415 tests passed. This appears to be a pre-existing flakiness issue introduced with the test itself, not caused by the CodeMode transform changes.

Related Files
  • tests/server/providers/openapi/test_comprehensive.py (line 736) - Contains the failing performance assertion
  • src/fastmcp/server/providers/openapi/ - The OpenAPIProvider being tested

🤖 Automated triage via Claude Code · edited to reflect latest analysis

aaazzam and others added 13 commits February 26, 2026 22:43
🤖 Generated with Claude Code
🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 <[email protected]>
🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Removes the duplicate ContextVar bypass pattern in favor of the shared
CatalogTransform machinery. Also fixes a pre-existing bug where
`from __future__ import annotations` caused NameError for Annotated
in nested function scopes at runtime.
chatgpt-codex-connector[bot]

This comment was marked as resolved.

call_tool() inside execute blocks now returns structured content as-is,
preserving the {"result": value} wrapping. This means the output schema
shown in search results accurately describes what call_tool() returns,
so LLMs can trust the schema when writing code.

Also adds examples/code_mode/ with a server and narrated client demo.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d1b4c50977

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


async def call_tool(tool_name: str, params: dict[str, Any]) -> Any:
backend_tools = await _get_cached_tools()
tool = transform._find_tool(tool_name, backend_tools)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Select highest-version backend tool before execute call

execute resolves a backend tool by scanning the list_tools() catalog and taking the first name match, then pins that exact version for the call. Because list_tools() returns all versions in provider/registration order, a versioned tool like foo@1 + foo@2 can be invoked as foo@1 through CodeMode even though normal call_tool("foo", ...) semantics return the highest version; this causes silent behavior drift for any server that relies on versioned tools.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a296d4e895

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/fastmcp/experimental/transforms/code_mode.py
Comment thread src/fastmcp/experimental/transforms/code_mode.py
@jlowin jlowin merged commit b915340 into main Feb 27, 2026
8 of 9 checks passed
@jlowin jlowin deleted the code-mode branch February 27, 2026 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Major new functionality. Reserved for 2-4 significant PRs per release. Not for issues. server Related to FastMCP server implementation or server-side functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add experimental CodeMode transform

2 participants