"""Protocol regressions without starting ARTEMIS or invoking a device.""" import json from typing import Any from mcp.server.fastmcp.exceptions import ToolError from mcp.shared.memory import create_connected_server_and_client_session import pytest from apps.admin_console.schemas.task_schema import RunRequest from artemis.mcp.tool_server import ArtemisFastMCP @pytest.mark.asyncio async def test_unknown_arguments_are_rejected_before_dispatch(): mcp = ArtemisFastMCP("strict-input-test", strict_inputs=True) dispatched = [] @mcp.tool() def submit(task_desc: str) -> dict: dispatched.append(task_desc) return {"ok": True} with pytest.raises(ToolError, match="未知参数.*goal"): await mcp.call_tool("submit", {"task_desc": "original", "goal": "silently replace?"}) assert dispatched == [] assert (await mcp.list_tools())[0].inputSchema["additionalProperties"] is False await mcp.call_tool("submit", {"task_desc": "accepted"}) assert dispatched == ["accepted"] @pytest.mark.asyncio async def test_legacy_json_has_structured_content_without_changing_text(): mcp = ArtemisFastMCP("structured-test", strict_inputs=True) @mcp.tool() def legacy() -> Any: return {"items": [{"step_id": "actual-step"}], "offset": 0, "total": 1, "next_offset": None} content, structured = await mcp.call_tool("legacy", {}) assert json.loads(content[0].text) == structured assert structured["items"][0]["step_id"] == "actual-step" async with create_connected_server_and_client_session(mcp) as session: wire = await session.call_tool("legacy", {}) assert wire.structuredContent == structured assert json.loads(wire.content[0].text) == structured rejected = await session.call_tool("legacy", {"goal": "unknown field"}) assert rejected.isError is True def test_http_submission_rejects_unknown_and_misspelled_fields(): from pydantic import ValidationError with pytest.raises(ValidationError, match="extra_forbidden"): RunRequest.model_validate({"goal": "original", "task_desc": "wrong contract"}) assert ( RunRequest.model_validate({"goal": "accepted", "runtime_overrides": {}}).goal == "accepted" )