Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion tests/contrib/google_genai/echo_mcp_server.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
"""A minimal stdio MCP server used by the google_genai MCP tests."""
"""A minimal MCP echo server for the google_genai MCP tests.

Run as a script it serves over stdio; imported, ``mcp`` can be connected to
in-memory via ``mcp.shared.memory``.
"""

from mcp.server.fastmcp import FastMCP

Expand Down
29 changes: 23 additions & 6 deletions tests/contrib/google_genai/test_gemini_mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
- full parameter-schema propagation to the model (the MCP wire-format check)
- replay determinism and exact activity-scheduling counts

Only the discovery test spawns the echo server as a stdio subprocess; the
rest connect to the same server over in-memory streams, since they exercise
the pooling, activity, and replay logic rather than the transport.

Plus the server-side pass-through paths that need no shim code:
- Vertex AI ``Tool(mcp_servers=[McpServer(...)])`` config serialization
- Interactions API ``MCPServerToolCallStep`` / ``MCPServerToolResultStep`` rehydration
Expand Down Expand Up @@ -56,7 +60,19 @@

@asynccontextmanager
async def _echo_session() -> AsyncIterator[ClientSession]:
"""Yield a connected, initialized session to the stdio echo MCP server."""
"""Yield an initialized session to the echo MCP server over in-memory streams."""
from mcp.shared.memory import create_connected_server_and_client_session

# Imported here so the sandbox's re-import of this module stays side-effect free.
from tests.contrib.google_genai.echo_mcp_server import mcp as echo_server

async with create_connected_server_and_client_session(echo_server) as session:
yield session


@asynccontextmanager
async def _echo_stdio_session() -> AsyncIterator[ClientSession]:
"""Yield an initialized session to the echo server run as a stdio subprocess."""
params = StdioServerParameters(command=sys.executable, args=[_ECHO_SERVER])
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
Expand Down Expand Up @@ -85,7 +101,7 @@ def _apply_mcp_plugin(

Monkeypatches ``GeminiApiCaller.activities`` (so canned generate_content
responses drive the AFC loop) while leaving the plugin's MCP activities —
built from ``mcp_servers`` — to hit the real stdio echo server.
built from ``mcp_servers`` — to hit the real echo server.
"""
from temporalio.contrib.google_genai._gemini_activity import GeminiApiCaller

Expand Down Expand Up @@ -128,13 +144,14 @@ async def _activity_names(handle: Any) -> list[str]:


@pytest.fixture(autouse=True)
def _clear_mcp_connections(): # pyright: ignore[reportUnusedFunction]
async def _close_mcp_connections(): # pyright: ignore[reportUnusedFunction]
"""Isolate the module-global MCP connection pool between tests."""
from temporalio.contrib.google_genai import _mcp

_mcp._CONNECTIONS.clear()
yield
_mcp._CONNECTIONS.clear()
for server in list(_mcp._CONNECTIONS):
await _mcp._evict_connection(server)


# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -176,15 +193,15 @@ async def run(self, server_name: str, prompt: str) -> str:


async def test_mcp_tool_discovery_and_call(client: Client):
"""The AFC loop discovers + calls an MCP tool through activities."""
"""The AFC loop discovers + calls a tool on a stdio MCP server via activities."""
server = "echo_basic"
new_client, _ = _apply_mcp_plugin(
client,
[
make_function_call_response("echo", {"message": "hello"}),
make_text_response("Done!"),
],
mcp_servers={server: _echo_session},
mcp_servers={server: _echo_stdio_session},
)

async with new_worker(new_client, McpToolWorkflow) as worker:
Expand Down
Loading