Skip to content

Commit c7072a2

Browse files
committed
[1/n] Implement RFC 003: MCP Infrastructure + Echo Env
Core MCP infrastructure: - Add mcp_types.py with ListToolsAction, CallToolAction, observations - Add mcp_environment.py with MCPEnvironment base class - Update http_server.py with /mcp JSON-RPC endpoint - Add mcp/fastmcp dependencies to pyproject.toml Echo env conversion: - Add mcp_server.py with echo_message tool - Update echo_environment.py to use MCPEnvironment - Update client.py with MCP action support - Remove deprecated EchoAction/EchoObservation (models.py) Tests and examples: - Add tests/core/mcp/test_mcp.py - Add examples/echo_mcp_demo.py
1 parent 8693974 commit c7072a2

File tree

17 files changed

+1093
-184
lines changed

17 files changed

+1093
-184
lines changed

examples/echo_mcp_demo.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""
2+
Example: Using Echo Environment with MCP
3+
4+
This example demonstrates:
5+
1. Connecting to echo_env server
6+
2. Listing available tools via MCP
7+
3. Calling tools using the step() API
8+
"""
9+
10+
import asyncio
11+
12+
try:
13+
from core.env_server.types import CallToolAction, ListToolsAction
14+
except ImportError:
15+
from openenv_core.env_server.types import CallToolAction, ListToolsAction
16+
17+
from envs.echo_env import EchoEnv
18+
19+
20+
async def main():
21+
# Connect to echo_env (assumes server is running on localhost:8000)
22+
# To start the server: uvicorn envs.echo_env.server.app:app
23+
client = EchoEnv(base_url="http://localhost:8000")
24+
25+
print("=== Echo Environment MCP Demo ===\n")
26+
27+
# Reset the environment
28+
print("1. Resetting environment...")
29+
result = client.reset()
30+
print(f" Reset result: {result.observation.metadata}\n")
31+
32+
# List available tools using step API
33+
print("2. Listing available tools...")
34+
list_action = ListToolsAction()
35+
list_result = client.step(list_action)
36+
for tool in list_result.observation.tools:
37+
print(f" - {tool['name']}: {tool['description']}")
38+
print()
39+
40+
# Call echo_message tool using step API
41+
print("3. Calling echo_message tool...")
42+
call_action = CallToolAction(tool_name="echo_message", parameters={"message": "Hello from MCP!"})
43+
call_result = client.step(call_action)
44+
print(f" Result: {call_result.observation.result}\n")
45+
46+
# Check environment state
47+
print("4. Checking environment state...")
48+
state = client.state
49+
print(f" Episode ID: {state.episode_id}")
50+
print(f" Step count: {state.step_count}\n")
51+
52+
print("Demo complete!")
53+
54+
55+
if __name__ == "__main__":
56+
asyncio.run(main())

examples/test_mcp_integration.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/usr/bin/env python3
2+
"""Quick test script to verify MCP integration works."""
3+
4+
import asyncio
5+
import sys
6+
sys.path.insert(0, 'src')
7+
8+
from envs.echo_env.server.echo_environment import EchoEnvironment
9+
from core.env_server.types import ListToolsAction, CallToolAction
10+
11+
12+
async def main():
13+
print("=" * 60)
14+
print("Testing MCP Integration")
15+
print("=" * 60)
16+
17+
# Create echo environment (MCPEnvironment handles MCP setup automatically)
18+
print("\n1. Creating Echo Environment...")
19+
env = EchoEnvironment()
20+
21+
# Test list tools
22+
print("\n2. Testing ListToolsAction...")
23+
list_action = ListToolsAction()
24+
obs = await env._handle_mcp_action(list_action)
25+
print(f" - Done: {obs.done}")
26+
print(f" - Has 'tools' attribute: {hasattr(obs, 'tools')}")
27+
if hasattr(obs, "tools"):
28+
print(f" - Number of tools: {len(obs.tools)}")
29+
print(f" - Tool names: {[t['name'] for t in obs.tools]}")
30+
else:
31+
print(" - ERROR: No 'tools' attribute!")
32+
return False
33+
34+
# Test call tool
35+
print("\n3. Testing CallToolAction...")
36+
call_action = CallToolAction(
37+
tool_name="echo_message",
38+
parameters={"message": "Hello MCP!"}
39+
)
40+
obs = await env._handle_mcp_action(call_action)
41+
print(f" - Done: {obs.done}")
42+
print(f" - Has 'result' attribute: {hasattr(obs, 'result')}")
43+
print(f" - Error: {obs.error}")
44+
if hasattr(obs, "result") and obs.result is not None:
45+
result = obs.result
46+
print(f" - Result type: {type(result)}")
47+
print(f" - Result: {result}")
48+
else:
49+
print(" - ERROR: No 'result' attribute or result is None!")
50+
return False
51+
52+
print("\n" + "=" * 60)
53+
print("✅ All tests passed!")
54+
print("=" * 60)
55+
return True
56+
57+
58+
if __name__ == "__main__":
59+
success = asyncio.run(main())
60+
sys.exit(0 if success else 1)

0 commit comments

Comments
 (0)