mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-28 14:07:55 +00:00
133 lines
4.8 KiB
Python
133 lines
4.8 KiB
Python
"""Tests for MCP server upgrade to protocol version 2025-11-25."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from openjarvis.mcp.protocol import MCPRequest
|
|
from openjarvis.mcp.server import MCPServer
|
|
from openjarvis.tools.calculator import CalculatorTool
|
|
from openjarvis.tools.think import ThinkTool
|
|
|
|
|
|
@pytest.fixture
|
|
def server():
|
|
return MCPServer([CalculatorTool(), ThinkTool()])
|
|
|
|
|
|
class TestProtocolVersion:
|
|
def test_protocol_version_2025(self, server):
|
|
assert server.PROTOCOL_VERSION == "2025-11-25"
|
|
|
|
def test_initialize_returns_2025_version(self, server):
|
|
req = MCPRequest(method="initialize", id=1)
|
|
resp = server.handle(req)
|
|
assert resp.result["protocolVersion"] == "2025-11-25"
|
|
|
|
|
|
class TestServerTitle:
|
|
def test_initialize_includes_title(self, server):
|
|
req = MCPRequest(method="initialize", id=1)
|
|
resp = server.handle(req)
|
|
server_info = resp.result["serverInfo"]
|
|
assert "title" in server_info
|
|
assert server_info["title"] == "OpenJarvis Tool Server"
|
|
|
|
|
|
class TestListChanged:
|
|
def test_tools_capability_list_changed_true(self, server):
|
|
req = MCPRequest(method="initialize", id=1)
|
|
resp = server.handle(req)
|
|
caps = resp.result["capabilities"]
|
|
assert caps["tools"]["listChanged"] is True
|
|
|
|
|
|
class TestAnnotations:
|
|
def test_calculator_has_read_only_annotation(self, server):
|
|
req = MCPRequest(method="tools/list", id=1)
|
|
resp = server.handle(req)
|
|
tools = resp.result["tools"]
|
|
calc = next(t for t in tools if t["name"] == "calculator")
|
|
assert "annotations" in calc
|
|
assert calc["annotations"]["readOnlyHint"] is True
|
|
assert calc["annotations"]["destructiveHint"] is False
|
|
|
|
def test_think_has_read_only_annotation(self, server):
|
|
req = MCPRequest(method="tools/list", id=1)
|
|
resp = server.handle(req)
|
|
tools = resp.result["tools"]
|
|
think = next(t for t in tools if t["name"] == "think")
|
|
assert "annotations" in think
|
|
assert think["annotations"]["readOnlyHint"] is True
|
|
|
|
|
|
class TestAutoDiscovery:
|
|
def test_auto_discover_creates_server(self):
|
|
"""MCPServer() with no tools arg should auto-discover."""
|
|
server = MCPServer()
|
|
req = MCPRequest(method="tools/list", id=1)
|
|
resp = server.handle(req)
|
|
# Should have at least calculator and think (via direct import)
|
|
names = {t["name"] for t in resp.result["tools"]}
|
|
assert "calculator" in names
|
|
assert "think" in names
|
|
|
|
def test_auto_discover_includes_storage_tools(self):
|
|
"""Auto-discovered server should include storage tools."""
|
|
server = MCPServer()
|
|
req = MCPRequest(method="tools/list", id=1)
|
|
resp = server.handle(req)
|
|
names = {t["name"] for t in resp.result["tools"]}
|
|
assert "memory_store" in names
|
|
assert "memory_retrieve" in names
|
|
assert "memory_search" in names
|
|
assert "memory_index" in names
|
|
|
|
def test_auto_discover_tool_count(self):
|
|
"""Auto-discovered server should have all built-in tools."""
|
|
server = MCPServer()
|
|
req = MCPRequest(method="tools/list", id=1)
|
|
resp = server.handle(req)
|
|
# At least: calculator, think, file_read, web_search,
|
|
# code_interpreter, memory_store/retrieve/search/index,
|
|
# llm, retrieval
|
|
assert len(resp.result["tools"]) >= 8
|
|
|
|
def test_explicit_tools_override_auto_discover(self):
|
|
"""Passing explicit tools should NOT auto-discover."""
|
|
server = MCPServer([CalculatorTool()])
|
|
req = MCPRequest(method="tools/list", id=1)
|
|
resp = server.handle(req)
|
|
tools = resp.result["tools"]
|
|
assert len(tools) == 1
|
|
assert tools[0]["name"] == "calculator"
|
|
|
|
def test_empty_list_means_no_tools(self):
|
|
"""Passing empty list should give empty tools (not auto-discover)."""
|
|
server = MCPServer([])
|
|
req = MCPRequest(method="tools/list", id=1)
|
|
resp = server.handle(req)
|
|
assert resp.result["tools"] == []
|
|
|
|
|
|
class TestStorageToolAnnotations:
|
|
def test_memory_store_destructive(self):
|
|
from openjarvis.tools.storage_tools import MemoryStoreTool
|
|
|
|
server = MCPServer([MemoryStoreTool()])
|
|
req = MCPRequest(method="tools/list", id=1)
|
|
resp = server.handle(req)
|
|
tool = resp.result["tools"][0]
|
|
assert tool["annotations"]["destructiveHint"] is True
|
|
assert tool["annotations"]["readOnlyHint"] is False
|
|
|
|
def test_memory_retrieve_read_only(self):
|
|
from openjarvis.tools.storage_tools import MemoryRetrieveTool
|
|
|
|
server = MCPServer([MemoryRetrieveTool()])
|
|
req = MCPRequest(method="tools/list", id=1)
|
|
resp = server.handle(req)
|
|
tool = resp.result["tools"][0]
|
|
assert tool["annotations"]["readOnlyHint"] is True
|
|
assert tool["annotations"]["destructiveHint"] is False
|