Skip to content

Commit 8a58a1a

Browse files
Benny ChenBenny Chen
authored andcommitted
revert mcp gym issue
1 parent caf93cf commit 8a58a1a

File tree

3 files changed

+84
-15
lines changed

3 files changed

+84
-15
lines changed

eval_protocol/mcp/client/connection.py

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -441,34 +441,24 @@ async def call_tool(self, session: MCPSession, tool_name: str, arguments: Dict)
441441
# Extract data plane results (observation only)
442442
if tool_result.content and len(tool_result.content) > 0:
443443
content = tool_result.content[0]
444-
# Safely attempt to read a "text" attribute if present across content types
445-
text_attr = getattr(content, "text", None)
446-
if isinstance(text_attr, str):
447-
content_text = text_attr
448-
elif isinstance(text_attr, list):
449-
# text can also be an array of parts with optional .text fields
450-
content_text = "".join([getattr(p, "text", "") for p in text_attr])
451-
else:
452-
content_text = None
453-
454-
if isinstance(content_text, str):
444+
if hasattr(content, "text"):
455445
# Fix: Handle empty or invalid JSON responses gracefully
456-
if content_text.strip() == "":
446+
if not content.text or content.text.strip() == "":
457447
logger.warning(f"Session {session.session_id}: Empty tool response from {tool_name}")
458448
observation = {
459449
"observation": "empty_response",
460450
"session_id": session.session_id,
461451
}
462452
else:
463453
try:
464-
observation = json.loads(content_text)
454+
observation = json.loads(content.text)
465455
except json.JSONDecodeError as e:
466456
logger.warning(
467-
f"Session {session.session_id}: Invalid JSON from {tool_name}: {content_text}. Error: {e}"
457+
f"Session {session.session_id}: Invalid JSON from {tool_name}: {content.text}. Error: {e}"
468458
)
469459
# Create a structured response from the raw text
470460
observation = {
471-
"observation": content_text,
461+
"observation": content.text,
472462
"session_id": session.session_id,
473463
"error": "invalid_json_response",
474464
}

eval_protocol/mcp/mcpgym.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,15 @@ def _get_or_create_session(self, ctx: Context) -> Dict[str, Any]:
205205
"""
206206
session_id = self._get_session_id(ctx)
207207
print(f"🔍 _get_or_create_session: session_id: {session_id}")
208+
if session_id not in self.sessions:
209+
env, obs, info = self._new_env(seed=None)
210+
with self.session_lock:
211+
self.sessions[session_id] = {
212+
"env": env,
213+
"obs": obs,
214+
"session_data": {},
215+
"session_id": session_id,
216+
}
208217
return self.sessions[session_id]
209218

210219
def _register_session_reset_endpoint(self):
@@ -400,6 +409,15 @@ def _execute_session_environment_step(self, session_id: str, action: Any) -> Dic
400409
Returns:
401410
Data plane response (observation only, no rewards)
402411
"""
412+
if session_id not in self.sessions:
413+
env, obs, info = self._new_env(seed=None)
414+
with self.session_lock:
415+
self.sessions[session_id] = {
416+
"env": env,
417+
"obs": obs,
418+
"session_data": {},
419+
"session_id": session_id,
420+
}
403421
session_data = self.sessions[session_id]
404422
env = session_data["env"]
405423

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""
2+
Regression test: ensure MCP-Gym auto-creates a session on first tool call
3+
without requiring a prior initial state fetch, and returns JSON.
4+
"""
5+
6+
import time
7+
from multiprocessing import Process
8+
9+
import httpx
10+
import pytest
11+
12+
from eval_protocol.mcp.client.connection import MCPConnectionManager
13+
from eval_protocol.types import MCPSession
14+
15+
16+
def _run_airline_server():
17+
import os
18+
19+
os.environ["PORT"] = "9780"
20+
from eval_protocol.mcp_servers.tau2.tau2_mcp import AirlineDomainMcp
21+
22+
server = AirlineDomainMcp(seed=None)
23+
server.run(transport="streamable-http")
24+
25+
26+
@pytest.mark.asyncio
27+
async def test_tool_call_returns_json_without_prior_initial_state():
28+
proc = Process(target=_run_airline_server, daemon=True)
29+
proc.start()
30+
31+
try:
32+
base_url = "http://127.0.0.1:9780/mcp"
33+
client = httpx.Client(timeout=1.0)
34+
deadline = time.time() + 20
35+
while time.time() < deadline:
36+
try:
37+
r = client.get(base_url)
38+
if r.status_code in (200, 307, 406):
39+
break
40+
except Exception:
41+
pass
42+
time.sleep(0.2)
43+
else:
44+
pytest.fail("Server did not start on port 9780 in time")
45+
46+
session = MCPSession(base_url=base_url, session_id="test-autocreate", seed=None, model_id="test-model")
47+
48+
mgr = MCPConnectionManager()
49+
await mgr.initialize_session(session)
50+
await mgr.discover_tools(session)
51+
52+
observation, reward, done, info = await mgr.call_tool(session, "list_all_airports", {})
53+
54+
assert isinstance(observation, dict), f"Expected JSON dict, got: {type(observation)} {observation}"
55+
assert observation.get("error") != "invalid_json_response"
56+
57+
await mgr.reset_session(session)
58+
await mgr.close_session(session)
59+
finally:
60+
proc.terminate()
61+
proc.join(timeout=5)

0 commit comments

Comments
 (0)