mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-28 14:07:55 +00:00
159 lines
5.2 KiB
Python
159 lines
5.2 KiB
Python
"""Tests for the MCP tool adapter — round-trip through MCPServer + MCPClient."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from openjarvis.mcp.client import MCPClient
|
|
from openjarvis.mcp.server import MCPServer
|
|
from openjarvis.mcp.transport import InProcessTransport
|
|
from openjarvis.tools._stubs import ToolSpec
|
|
from openjarvis.tools.calculator import CalculatorTool
|
|
from openjarvis.tools.mcp_adapter import MCPToolAdapter, MCPToolProvider
|
|
from openjarvis.tools.think import ThinkTool
|
|
|
|
|
|
@pytest.fixture
|
|
def server():
|
|
"""Create an MCP server with calculator and think tools."""
|
|
return MCPServer([CalculatorTool(), ThinkTool()])
|
|
|
|
|
|
@pytest.fixture
|
|
def client(server):
|
|
"""Create an MCP client connected to the server via in-process transport."""
|
|
transport = InProcessTransport(server)
|
|
c = MCPClient(transport)
|
|
c.initialize()
|
|
return c
|
|
|
|
|
|
class TestMCPToolAdapter:
|
|
def test_adapter_spec(self, client):
|
|
spec = ToolSpec(
|
|
name="calculator",
|
|
description="Evaluate a math expression",
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {"expression": {"type": "string"}},
|
|
},
|
|
)
|
|
adapter = MCPToolAdapter(client, spec)
|
|
assert adapter.spec.name == "calculator"
|
|
assert adapter.spec.description == "Evaluate a math expression"
|
|
|
|
def test_adapter_execute_success(self, client):
|
|
spec = ToolSpec(
|
|
name="calculator",
|
|
description="Calculator",
|
|
parameters={},
|
|
)
|
|
adapter = MCPToolAdapter(client, spec)
|
|
result = adapter.execute(expression="2+2")
|
|
assert result.success is True
|
|
assert "4" in result.content
|
|
assert result.tool_name == "calculator"
|
|
|
|
def test_adapter_execute_think(self, client):
|
|
spec = ToolSpec(
|
|
name="think",
|
|
description="Think tool",
|
|
parameters={},
|
|
)
|
|
adapter = MCPToolAdapter(client, spec)
|
|
result = adapter.execute(thought="Let me analyze this.")
|
|
assert result.success is True
|
|
assert "analyze" in result.content
|
|
|
|
def test_adapter_execute_error(self, client):
|
|
spec = ToolSpec(
|
|
name="calculator",
|
|
description="Calculator",
|
|
parameters={},
|
|
)
|
|
adapter = MCPToolAdapter(client, spec)
|
|
result = adapter.execute(expression="1/0")
|
|
assert result.success is True
|
|
assert result.content == "inf"
|
|
|
|
def test_adapter_unknown_tool(self, client):
|
|
spec = ToolSpec(
|
|
name="nonexistent",
|
|
description="Does not exist",
|
|
parameters={},
|
|
)
|
|
adapter = MCPToolAdapter(client, spec)
|
|
result = adapter.execute(x="y")
|
|
assert result.success is False
|
|
assert "error" in result.content.lower() or "MCP" in result.content
|
|
|
|
def test_adapter_tool_id(self, client):
|
|
spec = ToolSpec(name="calculator", description="Calc", parameters={})
|
|
adapter = MCPToolAdapter(client, spec)
|
|
assert adapter.tool_id == "mcp_adapter"
|
|
|
|
|
|
class TestMCPToolProvider:
|
|
def test_discover_returns_adapters(self, client):
|
|
provider = MCPToolProvider(client)
|
|
tools = provider.discover()
|
|
assert len(tools) == 2
|
|
names = {t.spec.name for t in tools}
|
|
assert "calculator" in names
|
|
assert "think" in names
|
|
|
|
def test_discovered_tools_are_base_tool(self, client):
|
|
from openjarvis.tools._stubs import BaseTool
|
|
|
|
provider = MCPToolProvider(client)
|
|
tools = provider.discover()
|
|
for tool in tools:
|
|
assert isinstance(tool, BaseTool)
|
|
|
|
def test_discovered_tool_execution(self, client):
|
|
provider = MCPToolProvider(client)
|
|
tools = provider.discover()
|
|
calc = next(t for t in tools if t.spec.name == "calculator")
|
|
result = calc.execute(expression="3*7")
|
|
assert result.success is True
|
|
assert "21" in result.content
|
|
|
|
|
|
class TestMCPAdapterRoundTrip:
|
|
"""End-to-end: Server → InProcessTransport → Client → Adapter → execute."""
|
|
|
|
def test_full_round_trip(self):
|
|
server = MCPServer([CalculatorTool(), ThinkTool()])
|
|
transport = InProcessTransport(server)
|
|
client = MCPClient(transport)
|
|
client.initialize()
|
|
provider = MCPToolProvider(client)
|
|
tools = provider.discover()
|
|
|
|
calc = next(t for t in tools if t.spec.name == "calculator")
|
|
result = calc.execute(expression="10+20")
|
|
assert result.success is True
|
|
assert "30" in result.content
|
|
|
|
def test_round_trip_error_handling(self):
|
|
server = MCPServer([CalculatorTool()])
|
|
transport = InProcessTransport(server)
|
|
client = MCPClient(transport)
|
|
client.initialize()
|
|
provider = MCPToolProvider(client)
|
|
tools = provider.discover()
|
|
|
|
calc = tools[0]
|
|
result = calc.execute(expression="1/0")
|
|
assert result.success is True
|
|
assert result.content == "inf"
|
|
|
|
def test_empty_server_discover(self):
|
|
server = MCPServer([])
|
|
transport = InProcessTransport(server)
|
|
client = MCPClient(transport)
|
|
client.initialize()
|
|
provider = MCPToolProvider(client)
|
|
tools = provider.discover()
|
|
assert tools == []
|