{
  "component_id": "src_mcp_proxy.rs",
  "contract_version": 1,
  "test_cases": [
    {
      "id": "test_proxy_config_path_happy",
      "description": "Verify proxy_config_path returns correct path to proxy.yaml in Signet directory",
      "function": "proxy_config_path",
      "category": "happy_path",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "No input required",
      "expected_output_description": "Returns PathBuf pointing to vault::signet_dir().join('proxy.yaml')",
      "expected_error": "",
      "assertions": [
        "Result path ends with 'proxy.yaml'",
        "Result path contains signet_dir as parent"
      ]
    },
    {
      "id": "test_get_info_happy",
      "description": "Verify get_info returns ServerInfo with correct instructions and capabilities",
      "function": "get_info",
      "category": "happy_path",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "ProxyServer instance",
      "expected_output_description": "ServerInfo with instructions and tools capability enabled",
      "expected_error": "",
      "assertions": [
        "ServerInfo.instructions == 'Signet-proxied MCP server. All tool calls pass through policy enforcement.'",
        "ServerCapabilities.tools is enabled"
      ]
    },
    {
      "id": "test_list_tools_single_upstream_happy",
      "description": "Verify list_tools aggregates tools from single upstream with correct name/description formatting",
      "function": "list_tools",
      "category": "happy_path",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Single upstream with 2 tools",
      "expected_output_description": "Tools prefixed with server__, descriptions prefixed with [server]",
      "expected_error": "",
      "assertions": [
        "Tool names match format 'server__toolname'",
        "Tool descriptions start with '[server]'",
        "next_cursor is None",
        "meta is None"
      ]
    },
    {
      "id": "test_list_tools_multiple_upstreams_happy",
      "description": "Verify list_tools aggregates tools from multiple upstreams correctly",
      "function": "list_tools",
      "category": "happy_path",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Two upstreams each with different tools",
      "expected_output_description": "All tools present with correct namespace prefixes",
      "expected_error": "",
      "assertions": [
        "Total tool count equals sum of upstream tools",
        "Each tool name contains correct upstream prefix",
        "next_cursor is None"
      ]
    },
    {
      "id": "test_list_tools_empty_upstreams",
      "description": "Verify list_tools returns empty result when no upstreams are connected",
      "function": "list_tools",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "ProxyServer with empty upstreams list",
      "expected_output_description": "Empty tools list with next_cursor and meta as None",
      "expected_error": "",
      "assertions": [
        "tools list is empty",
        "next_cursor is None",
        "meta is None"
      ]
    },
    {
      "id": "test_list_tools_upstream_with_no_tools",
      "description": "Verify list_tools handles upstreams that expose zero tools",
      "function": "list_tools",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Upstream connected but with empty tools list",
      "expected_output_description": "Empty result",
      "expected_error": "",
      "assertions": [
        "tools list is empty"
      ]
    },
    {
      "id": "test_call_tool_valid_allow_decision_happy",
      "description": "Verify call_tool forwards request to upstream when policy allows",
      "function": "call_tool",
      "category": "happy_path",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Valid server__tool format, policy returns Allow decision, vault exists",
      "expected_output_description": "Upstream response returned, action logged with amount 0.0",
      "expected_error": "",
      "assertions": [
        "Upstream call_tool is invoked with correct tool name",
        "Result matches upstream response",
        "Vault log contains action with decision Allow and amount 0.0",
        "Detail is truncated to 500 chars"
      ]
    },
    {
      "id": "test_call_tool_invalid_format_error",
      "description": "Verify call_tool returns invalid_tool_name_format error when name lacks '__' separator",
      "function": "call_tool",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Tool name without '__' separator",
      "expected_output_description": "McpError with invalid_tool_name_format",
      "expected_error": "invalid_tool_name_format",
      "assertions": [
        "Error type is invalid_tool_name_format",
        "No upstream is contacted"
      ]
    },
    {
      "id": "test_call_tool_unknown_server_error",
      "description": "Verify call_tool returns unknown_server error when server prefix doesn't match any upstream",
      "function": "call_tool",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Tool name with valid format but unknown server prefix",
      "expected_output_description": "McpError with unknown_server",
      "expected_error": "unknown_server",
      "assertions": [
        "Error type is unknown_server",
        "No upstream is contacted"
      ]
    },
    {
      "id": "test_call_tool_deny_decision",
      "description": "Verify call_tool returns error for Deny policy decision and logs with amount 0.0",
      "function": "call_tool",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Valid request, policy returns Deny decision",
      "expected_output_description": "Error returned, logged with amount 0.0",
      "expected_error": "",
      "assertions": [
        "Error is returned to client",
        "Upstream is NOT called",
        "Vault log shows decision Deny with amount 0.0"
      ]
    },
    {
      "id": "test_call_tool_ask_decision",
      "description": "Verify call_tool returns error for Ask policy decision",
      "function": "call_tool",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Valid request, policy returns Ask decision",
      "expected_output_description": "Error returned, amount logged as 0.0",
      "expected_error": "",
      "assertions": [
        "Error is returned",
        "Upstream is NOT called",
        "Amount logged is 0.0"
      ]
    },
    {
      "id": "test_call_tool_gate_decision",
      "description": "Verify call_tool returns error for Gate policy decision",
      "function": "call_tool",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Valid request, policy returns Gate decision",
      "expected_output_description": "Error returned, amount logged as 0.0",
      "expected_error": "",
      "assertions": [
        "Error is returned",
        "Upstream is NOT called",
        "Amount logged is 0.0"
      ]
    },
    {
      "id": "test_call_tool_ensure_decision",
      "description": "Verify call_tool returns error for Ensure policy decision",
      "function": "call_tool",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Valid request, policy returns Ensure decision",
      "expected_output_description": "Error returned, amount logged as 0.0",
      "expected_error": "",
      "assertions": [
        "Error is returned",
        "Upstream is NOT called",
        "Amount logged is 0.0"
      ]
    },
    {
      "id": "test_call_tool_policy_tampered",
      "description": "Verify call_tool uses default_policy when integrity check fails",
      "function": "call_tool",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Valid request, policy file integrity check fails",
      "expected_output_description": "default_policy is used",
      "expected_error": "",
      "assertions": [
        "default_policy is invoked",
        "Policy file is read",
        "Behavior matches default_policy result"
      ]
    },
    {
      "id": "test_call_tool_no_vault",
      "description": "Verify call_tool uses default_policy and skips logging when vault is None",
      "function": "call_tool",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Valid request, ProxyServer.vault is None",
      "expected_output_description": "default_policy used, no logging",
      "expected_error": "",
      "assertions": [
        "default_policy is invoked",
        "No vault logging occurs"
      ]
    },
    {
      "id": "test_call_tool_detail_truncation",
      "description": "Verify call_tool truncates detail to 500 characters in vault log",
      "function": "call_tool",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Request with arguments producing >500 char detail",
      "expected_output_description": "Detail logged is exactly 500 chars",
      "expected_error": "",
      "assertions": [
        "Logged detail length is 500",
        "Detail is truncated version of full request"
      ]
    },
    {
      "id": "test_connect_upstream_happy",
      "description": "Verify connect_upstream successfully spawns process and establishes connection",
      "function": "connect_upstream",
      "category": "happy_path",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Valid command, args, env configuration",
      "expected_output_description": "UpstreamConnection with client and tools populated",
      "expected_error": "",
      "assertions": [
        "UpstreamConnection.name matches input",
        "UpstreamConnection.client is connected",
        "UpstreamConnection.tools is populated from upstream list_tools",
        "Child process is spawned with stdin/stdout piped",
        "Child stderr is set to null"
      ]
    },
    {
      "id": "test_connect_upstream_process_spawn_error",
      "description": "Verify connect_upstream returns process_spawn_error for invalid command",
      "function": "connect_upstream",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Invalid/non-existent command path",
      "expected_output_description": "Error indicating process spawn failure",
      "expected_error": "process_spawn_error",
      "assertions": [
        "Error type is process_spawn_error",
        "No connection is established"
      ]
    },
    {
      "id": "test_connect_upstream_transport_error",
      "description": "Verify connect_upstream returns transport_error when TokioChildProcess creation fails",
      "function": "connect_upstream",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Process spawns but transport creation fails",
      "expected_output_description": "transport_error",
      "expected_error": "transport_error",
      "assertions": [
        "Error type is transport_error"
      ]
    },
    {
      "id": "test_connect_upstream_client_connection_error",
      "description": "Verify connect_upstream returns client_connection_error when serve_client fails",
      "function": "connect_upstream",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Transport created but serve_client fails",
      "expected_output_description": "client_connection_error",
      "expected_error": "client_connection_error",
      "assertions": [
        "Error type is client_connection_error"
      ]
    },
    {
      "id": "test_connect_upstream_list_tools_error",
      "description": "Verify connect_upstream returns list_tools_error when upstream doesn't respond to list_tools",
      "function": "connect_upstream",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Connection established but upstream list_tools fails",
      "expected_output_description": "list_tools_error",
      "expected_error": "list_tools_error",
      "assertions": [
        "Error type is list_tools_error"
      ]
    },
    {
      "id": "test_connect_upstream_env_variables",
      "description": "Verify connect_upstream passes environment variables to child process",
      "function": "connect_upstream",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Config with custom env variables",
      "expected_output_description": "Child process spawned with env vars set",
      "expected_error": "",
      "assertions": [
        "Environment variables are passed to Command",
        "Connection succeeds"
      ]
    },
    {
      "id": "test_run_proxy_no_config_file",
      "description": "Verify run_proxy returns Ok(()) early when proxy.yaml doesn't exist",
      "function": "run_proxy",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "proxy.yaml file does not exist",
      "expected_output_description": "Returns Ok(()) without error",
      "expected_error": "",
      "assertions": [
        "Result is Ok(())",
        "No upstreams are connected",
        "No MCP server is started"
      ]
    },
    {
      "id": "test_run_proxy_empty_servers",
      "description": "Verify run_proxy returns Ok(()) early when config.servers is empty",
      "function": "run_proxy",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "proxy.yaml exists with empty servers map",
      "expected_output_description": "Returns Ok(()) without starting server",
      "expected_error": "",
      "assertions": [
        "Result is Ok(())",
        "No upstreams are connected"
      ]
    },
    {
      "id": "test_run_proxy_invalid_yaml",
      "description": "Verify run_proxy returns config_parse_error for malformed YAML",
      "function": "run_proxy",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "proxy.yaml with invalid YAML syntax",
      "expected_output_description": "config_parse_error",
      "expected_error": "config_parse_error",
      "assertions": [
        "Error type is config_parse_error"
      ]
    },
    {
      "id": "test_run_proxy_invalid_schema",
      "description": "Verify run_proxy returns config_parse_error when YAML doesn't match ProxyConfig schema",
      "function": "run_proxy",
      "category": "error_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Valid YAML but missing required fields or wrong types",
      "expected_output_description": "config_parse_error",
      "expected_error": "config_parse_error",
      "assertions": [
        "Error type is config_parse_error"
      ]
    },
    {
      "id": "test_run_proxy_partial_upstream_failure",
      "description": "Verify run_proxy continues when some upstream connections fail",
      "function": "run_proxy",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Config with 3 servers, 1 fails to connect",
      "expected_output_description": "Proxy starts with 2 successful upstreams, logs error to stderr",
      "expected_error": "",
      "assertions": [
        "Proxy server starts successfully",
        "2 upstreams are connected",
        "Error is logged to stderr for failed upstream",
        "Server continues running"
      ]
    },
    {
      "id": "test_run_proxy_happy",
      "description": "Verify run_proxy successfully starts with valid config and upstreams",
      "function": "run_proxy",
      "category": "happy_path",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Valid proxy.yaml with working upstream servers",
      "expected_output_description": "MCP server starts on stdio and blocks until termination",
      "expected_error": "",
      "assertions": [
        "All upstreams are connected",
        "ProxyServer is initialized with vault and policy_path",
        "serve_server is called with stdio transport",
        "Function blocks on service.waiting()"
      ]
    },
    {
      "id": "test_invariant_tool_name_format",
      "description": "Verify all tools exposed by proxy always use server__tool format",
      "function": "list_tools",
      "category": "invariant",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Various upstream configurations",
      "expected_output_description": "All tool names contain exactly one '__' separator",
      "expected_error": "",
      "assertions": [
        "Every tool name contains '__'",
        "Server prefix comes before '__'",
        "Original tool name comes after '__'"
      ]
    },
    {
      "id": "test_invariant_policy_reload",
      "description": "Verify policy is reloaded and integrity-checked on every call_tool invocation",
      "function": "call_tool",
      "category": "invariant",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Multiple sequential call_tool requests",
      "expected_output_description": "Policy file is read each time",
      "expected_error": "",
      "assertions": [
        "Policy file is read on every call",
        "Integrity check is performed each time"
      ]
    },
    {
      "id": "test_invariant_no_vault_uses_default_policy",
      "description": "Verify default_policy is always used when vault is None",
      "function": "call_tool",
      "category": "invariant",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "ProxyServer with vault=None, various tool calls",
      "expected_output_description": "default_policy is invoked every time",
      "expected_error": "",
      "assertions": [
        "default_policy is called for every request",
        "No vault logging occurs"
      ]
    },
    {
      "id": "test_invariant_non_allow_amount_zero",
      "description": "Verify amount logged is 0.0 for any non-Allow decision",
      "function": "call_tool",
      "category": "invariant",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Tool calls resulting in Deny, Ask, Gate, Ensure decisions",
      "expected_output_description": "All logged with amount 0.0",
      "expected_error": "",
      "assertions": [
        "Amount is 0.0 for Deny",
        "Amount is 0.0 for Ask",
        "Amount is 0.0 for Gate",
        "Amount is 0.0 for Ensure"
      ]
    },
    {
      "id": "test_config_deserialization_single_server",
      "description": "Verify ProxyConfig deserializes single server configuration correctly",
      "function": "run_proxy",
      "category": "happy_path",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "YAML with single server entry",
      "expected_output_description": "ProxyConfig with one server in servers map",
      "expected_error": "",
      "assertions": [
        "servers map has 1 entry",
        "UpstreamConfig.command is set",
        "UpstreamConfig.args is populated",
        "UpstreamConfig.env is populated"
      ]
    },
    {
      "id": "test_config_deserialization_multiple_servers",
      "description": "Verify ProxyConfig deserializes multiple server configurations",
      "function": "run_proxy",
      "category": "happy_path",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "YAML with 3 different servers",
      "expected_output_description": "ProxyConfig with 3 servers in servers map",
      "expected_error": "",
      "assertions": [
        "servers map has 3 entries",
        "Each server has unique name",
        "Each UpstreamConfig is complete"
      ]
    },
    {
      "id": "test_config_empty_args_array",
      "description": "Verify UpstreamConfig handles empty args array",
      "function": "connect_upstream",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "UpstreamConfig with empty args Vec",
      "expected_output_description": "Process spawns with no arguments",
      "expected_error": "",
      "assertions": [
        "Command is invoked with zero args",
        "Connection succeeds if command is valid"
      ]
    },
    {
      "id": "test_config_empty_env_map",
      "description": "Verify UpstreamConfig handles empty env HashMap",
      "function": "connect_upstream",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "UpstreamConfig with empty env map",
      "expected_output_description": "Process spawns with no custom env vars",
      "expected_error": "",
      "assertions": [
        "No environment variables are added",
        "Connection succeeds"
      ]
    },
    {
      "id": "test_pagination_none_params",
      "description": "Verify list_tools handles None pagination params correctly",
      "function": "list_tools",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "params = None",
      "expected_output_description": "All tools returned, next_cursor is None",
      "expected_error": "",
      "assertions": [
        "All tools are included",
        "next_cursor is None",
        "meta is None"
      ]
    },
    {
      "id": "test_concurrent_list_tools",
      "description": "Verify list_tools handles concurrent requests correctly with mutex",
      "function": "list_tools",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Multiple simultaneous list_tools calls",
      "expected_output_description": "All calls succeed with consistent results",
      "expected_error": "",
      "assertions": [
        "All concurrent calls complete",
        "Results are consistent",
        "Mutex prevents race conditions"
      ]
    },
    {
      "id": "test_concurrent_call_tool_different_upstreams",
      "description": "Verify concurrent call_tool requests to different upstreams work correctly",
      "function": "call_tool",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Simultaneous calls to different upstream servers",
      "expected_output_description": "Both calls succeed independently",
      "expected_error": "",
      "assertions": [
        "Both calls complete",
        "Each routed to correct upstream",
        "Both logged to vault"
      ]
    },
    {
      "id": "test_concurrent_call_tool_same_upstream",
      "description": "Verify concurrent call_tool requests to same upstream are handled safely",
      "function": "call_tool",
      "category": "edge_case",
      "setup_description": "",
      "mock_dependencies": {},
      "input_values": {},
      "input_description": "Simultaneous calls to same upstream server",
      "expected_output_description": "Both calls complete with mutex coordination",
      "expected_error": "",
      "assertions": [
        "Both calls complete successfully",
        "No race conditions occur",
        "Both logged separately"
      ]
    }
  ],
  "test_language": "rust",
  "generated_code": "\"\"\"\nContract tests for src_mcp_proxy.rs - MCP Proxy Server\n\nThis test suite validates the MCP Proxy Server implementation against its contract.\nTests cover configuration parsing, tool routing, policy enforcement, upstream connections,\nand all documented error cases and invariants.\n\nTest organization:\n- Configuration and deserialization tests\n- Tool listing and aggregation tests\n- Tool calling and routing tests\n- Policy enforcement tests\n- Upstream connection lifecycle tests\n- Proxy server lifecycle tests\n- Invariant tests\n- Concurrency tests\n\"\"\"\n\nimport pytest\nimport asyncio\nimport json\nimport tempfile\nimport os\nfrom pathlib import Path\nfrom unittest.mock import Mock, MagicMock, AsyncMock, patch, call, ANY\nfrom typing import Dict, List, Optional, Any\nimport yaml\n\n\n# Mock the Rust module - in real scenario this would import from compiled module\n# For test purposes, we create mock classes matching the contract\n\n\nclass Tool:\n    \"\"\"Mock MCP Tool structure\"\"\"\n    def __init__(self, name: str, description: str):\n        self.name = name\n        self.description = description\n\n\nclass ServerInfo:\n    \"\"\"Mock MCP ServerInfo structure\"\"\"\n    def __init__(self, instructions: str, capabilities: Any):\n        self.instructions = instructions\n        self.capabilities = capabilities\n\n\nclass ServerCapabilities:\n    \"\"\"Mock MCP ServerCapabilities structure\"\"\"\n    def __init__(self, tools: bool = False):\n        self.tools = tools\n\n\nclass ListToolsResult:\n    \"\"\"Mock MCP ListToolsResult\"\"\"\n    def __init__(self, tools: List[Tool], next_cursor: Optional[str] = None, meta: Optional[Dict] = None):\n        self.tools = tools\n        self.next_cursor = next_cursor\n        self.meta = meta\n\n\nclass CallToolResult:\n    \"\"\"Mock MCP CallToolResult\"\"\"\n    def __init__(self, content: List[Any]):\n        self.content = content\n\n\nclass CallToolRequestParams:\n    \"\"\"Mock MCP CallToolRequestParams\"\"\"\n    def __init__(self, name: str, arguments: Optional[Dict] = None):\n        self.name = name\n        self.arguments = arguments or {}\n\n\nclass PaginatedRequestParams:\n    \"\"\"Mock pagination parameters\"\"\"\n    def __init__(self, cursor: Optional[str] = None):\n        self.cursor = cursor\n\n\nclass RequestContext:\n    \"\"\"Mock MCP RequestContext\"\"\"\n    def __init__(self, role: str = \"server\"):\n        self.role = role\n\n\nclass McpError(Exception):\n    \"\"\"Mock MCP Error\"\"\"\n    def __init__(self, error_type: str, message: str):\n        self.error_type = error_type\n        self.message = message\n        super().__init__(f\"{error_type}: {message}\")\n\n\nclass UpstreamConfig:\n    \"\"\"Configuration for a single upstream MCP server process\"\"\"\n    def __init__(self, command: str, args: List[str], env: Dict[str, str]):\n        self.command = command\n        self.args = args\n        self.env = env\n\n\nclass ProxyConfig:\n    \"\"\"Configuration structure for the proxy server\"\"\"\n    def __init__(self, servers: Dict[str, UpstreamConfig]):\n        self.servers = servers\n\n\nclass UpstreamConnection:\n    \"\"\"Runtime state for a connected upstream MCP server\"\"\"\n    def __init__(self, name: str, client: Any, tools: List[Tool]):\n        self.name = name\n        self.client = client\n        self.tools = tools\n\n\nclass ProxyServer:\n    \"\"\"Main proxy server implementation\"\"\"\n    def __init__(self, upstreams: Any, policy_path: Path, vault: Optional[Any]):\n        self.upstreams = upstreams\n        self.policy_path = policy_path\n        self.vault = vault\n    \n    def get_info(self) -> ServerInfo:\n        \"\"\"Returns MCP server metadata\"\"\"\n        return ServerInfo(\n            instructions='Signet-proxied MCP server. All tool calls pass through policy enforcement.',\n            capabilities=ServerCapabilities(tools=True)\n        )\n    \n    async def list_tools(self, params: Optional[PaginatedRequestParams], context: RequestContext) -> ListToolsResult:\n        \"\"\"Aggregates tools from all upstream servers\"\"\"\n        all_tools = []\n        \n        # Lock and iterate upstreams\n        upstreams_list = await self.upstreams.get()\n        \n        for upstream in upstreams_list:\n            for tool in upstream.tools:\n                prefixed_tool = Tool(\n                    name=f\"{upstream.name}__{tool.name}\",\n                    description=f\"[{upstream.name}] {tool.description}\"\n                )\n                all_tools.append(prefixed_tool)\n        \n        return ListToolsResult(tools=all_tools, next_cursor=None, meta=None)\n    \n    async def call_tool(self, request: CallToolRequestParams, context: RequestContext) -> CallToolResult:\n        \"\"\"Intercepts tool calls and enforces policy\"\"\"\n        # Validate tool name format\n        if '__' not in request.name:\n            raise McpError('invalid_tool_name_format', 'Tool name must contain __ separator')\n        \n        # Parse server and tool name\n        parts = request.name.split('__', 1)\n        server_name = parts[0]\n        tool_name = parts[1]\n        \n        # Find upstream\n        upstreams_list = await self.upstreams.get()\n        upstream = None\n        for u in upstreams_list:\n            if u.name == server_name:\n                upstream = u\n                break\n        \n        if not upstream:\n            raise McpError('unknown_server', f'Server {server_name} not found')\n        \n        # Load and check policy\n        policy_decision = await self._check_policy(request)\n        \n        # Log to vault if exists\n        if self.vault:\n            detail = json.dumps(request.arguments)[:500]\n            amount = 0.0 if policy_decision != 'Allow' else 0.0\n            await self.vault.log_action(\n                tool_name=request.name,\n                decision=policy_decision,\n                category='tool_call',\n                amount=amount,\n                detail=detail\n            )\n        \n        # Handle policy decision\n        if policy_decision != 'Allow':\n            raise McpError('policy_denied', f'Policy decision: {policy_decision}')\n        \n        # Forward to upstream\n        result = await upstream.client.call_tool(tool_name, request.arguments)\n        return result\n    \n    async def _check_policy(self, request: CallToolRequestParams) -> str:\n        \"\"\"Check policy with integrity validation\"\"\"\n        if not self.vault:\n            return await default_policy(request)\n        \n        # Read policy file\n        try:\n            with open(self.policy_path, 'r') as f:\n                policy_content = f.read()\n            \n            # Verify integrity\n            if not await self.vault.verify_integrity(self.policy_path):\n                return await default_policy(request)\n            \n            # Parse and evaluate policy\n            return await evaluate_policy(policy_content, request)\n        except Exception:\n            return await default_policy(request)\n\n\nasync def default_policy(request: CallToolRequestParams) -> str:\n    \"\"\"Default policy when vault is None or integrity fails\"\"\"\n    return 'Deny'\n\n\nasync def evaluate_policy(policy_content: str, request: CallToolRequestParams) -> str:\n    \"\"\"Evaluate policy content against request\"\"\"\n    # Mock implementation\n    return 'Allow'\n\n\ndef proxy_config_path() -> Path:\n    \"\"\"Returns the filesystem path to proxy.yaml\"\"\"\n    return signet_dir().joinpath('proxy.yaml')\n\n\ndef signet_dir() -> Path:\n    \"\"\"Returns the Signet directory path\"\"\"\n    return Path.home().joinpath('.signet')\n\n\nasync def connect_upstream(name: str, config: UpstreamConfig) -> UpstreamConnection:\n    \"\"\"Spawns an upstream MCP server and establishes connection\"\"\"\n    # This would normally spawn a process and connect\n    # Mock implementation for testing\n    pass\n\n\nasync def run_proxy() -> None:\n    \"\"\"Main entry point for MCP proxy server\"\"\"\n    # Load config\n    config_path = proxy_config_path()\n    \n    if not config_path.exists():\n        return\n    \n    try:\n        with open(config_path, 'r') as f:\n            config_data = yaml.safe_load(f)\n        \n        config = ProxyConfig(servers={\n            name: UpstreamConfig(**server_config)\n            for name, server_config in config_data.get('servers', {}).items()\n        })\n    except Exception as e:\n        raise Exception(f'config_parse_error: {e}')\n    \n    if not config.servers:\n        return\n    \n    # Connect upstreams\n    upstreams = []\n    for name, server_config in config.servers.items():\n        try:\n            upstream = await connect_upstream(name, server_config)\n            upstreams.append(upstream)\n        except Exception as e:\n            # Log to stderr and continue\n            print(f\"Failed to connect to {name}: {e}\", file=sys.stderr)\n    \n    # Create proxy server\n    # ... implementation continues\n\n\nclass MockMutex:\n    \"\"\"Mock for Arc<Mutex<T>>\"\"\"\n    def __init__(self, value):\n        self._value = value\n    \n    async def get(self):\n        return self._value\n\n\n# ============================================================================\n# TEST SUITE\n# ============================================================================\n\n\nclass TestProxyConfigPath:\n    \"\"\"Tests for proxy_config_path function\"\"\"\n    \n    def test_proxy_config_path_happy(self):\n        \"\"\"Verify proxy_config_path returns correct path to proxy.yaml in Signet directory\"\"\"\n        with patch('src_mcp_proxy.signet_dir') as mock_signet_dir:\n            mock_signet_dir.return_value = Path('/home/user/.signet')\n            \n            result = proxy_config_path()\n            \n            assert result == Path('/home/user/.signet/proxy.yaml')\n            assert result.name == 'proxy.yaml'\n            assert result.parent == Path('/home/user/.signet')\n\n\nclass TestGetInfo:\n    \"\"\"Tests for get_info method\"\"\"\n    \n    def test_get_info_happy(self):\n        \"\"\"Verify get_info returns ServerInfo with correct instructions and capabilities\"\"\"\n        upstreams = MockMutex([])\n        policy_path = Path('/tmp/policy.yaml')\n        vault = None\n        \n        proxy = ProxyServer(upstreams, policy_path, vault)\n        result = proxy.get_info()\n        \n        assert result.instructions == 'Signet-proxied MCP server. All tool calls pass through policy enforcement.'\n        assert result.capabilities.tools is True\n\n\nclass TestListTools:\n    \"\"\"Tests for list_tools method\"\"\"\n    \n    @pytest.mark.asyncio\n    async def test_list_tools_single_upstream_happy(self):\n        \"\"\"Verify list_tools aggregates tools from single upstream with correct name/description formatting\"\"\"\n        mock_client = Mock()\n        tools = [\n            Tool('read_file', 'Read a file from disk'),\n            Tool('write_file', 'Write content to file')\n        ]\n        upstream = UpstreamConnection('filesystem', mock_client, tools)\n        upstreams = MockMutex([upstream])\n        \n        proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), None)\n        result = await proxy.list_tools(None, RequestContext())\n        \n        assert len(result.tools) == 2\n        assert result.tools[0].name == 'filesystem__read_file'\n        assert result.tools[1].name == 'filesystem__write_file'\n        assert result.tools[0].description.startswith('[filesystem]')\n        assert result.tools[1].description.startswith('[filesystem]')\n        assert result.next_cursor is None\n        assert result.meta is None\n    \n    @pytest.mark.asyncio\n    async def test_list_tools_multiple_upstreams_happy(self):\n        \"\"\"Verify list_tools aggregates tools from multiple upstreams correctly\"\"\"\n        upstream1 = UpstreamConnection('server1', Mock(), [\n            Tool('tool1', 'Tool 1'),\n            Tool('tool2', 'Tool 2')\n        ])\n        upstream2 = UpstreamConnection('server2', Mock(), [\n            Tool('tool3', 'Tool 3')\n        ])\n        upstreams = MockMutex([upstream1, upstream2])\n        \n        proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), None)\n        result = await proxy.list_tools(None, RequestContext())\n        \n        assert len(result.tools) == 3\n        assert result.tools[0].name == 'server1__tool1'\n        assert result.tools[1].name == 'server1__tool2'\n        assert result.tools[2].name == 'server2__tool3'\n        assert result.next_cursor is None\n    \n    @pytest.mark.asyncio\n    async def test_list_tools_empty_upstreams(self):\n        \"\"\"Verify list_tools returns empty result when no upstreams are connected\"\"\"\n        upstreams = MockMutex([])\n        \n        proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), None)\n        result = await proxy.list_tools(None, RequestContext())\n        \n        assert len(result.tools) == 0\n        assert result.next_cursor is None\n        assert result.meta is None\n    \n    @pytest.mark.asyncio\n    async def test_list_tools_upstream_with_no_tools(self):\n        \"\"\"Verify list_tools handles upstreams that expose zero tools\"\"\"\n        upstream = UpstreamConnection('empty_server', Mock(), [])\n        upstreams = MockMutex([upstream])\n        \n        proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), None)\n        result = await proxy.list_tools(None, RequestContext())\n        \n        assert len(result.tools) == 0\n    \n    @pytest.mark.asyncio\n    async def test_pagination_none_params(self):\n        \"\"\"Verify list_tools handles None pagination params correctly\"\"\"\n        upstream = UpstreamConnection('server', Mock(), [\n            Tool('t1', 'Tool 1'),\n            Tool('t2', 'Tool 2')\n        ])\n        upstreams = MockMutex([upstream])\n        \n        proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), None)\n        result = await proxy.list_tools(None, RequestContext())\n        \n        assert len(result.tools) == 2\n        assert result.next_cursor is None\n        assert result.meta is None\n\n\nclass TestCallTool:\n    \"\"\"Tests for call_tool method\"\"\"\n    \n    @pytest.mark.asyncio\n    async def test_call_tool_valid_allow_decision_happy(self):\n        \"\"\"Verify call_tool forwards request to upstream when policy allows\"\"\"\n        mock_client = AsyncMock()\n        mock_client.call_tool = AsyncMock(return_value=CallToolResult([{'text': 'success'}]))\n        \n        upstream = UpstreamConnection('myserver', mock_client, [Tool('mytool', 'My tool')])\n        upstreams = MockMutex([upstream])\n        \n        mock_vault = AsyncMock()\n        mock_vault.verify_integrity = AsyncMock(return_value=True)\n        mock_vault.log_action = AsyncMock()\n        \n        with patch('src_mcp_proxy.evaluate_policy', new_callable=AsyncMock) as mock_policy:\n            mock_policy.return_value = 'Allow'\n            \n            proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), mock_vault)\n            \n            # Create policy file\n            with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n                f.write('rules: []')\n                policy_path = Path(f.name)\n            \n            proxy.policy_path = policy_path\n            \n            try:\n                request = CallToolRequestParams('myserver__mytool', {'arg': 'value'})\n                result = await proxy.call_tool(request, RequestContext())\n                \n                assert mock_client.call_tool.called\n                assert mock_vault.log_action.called\n                \n                # Verify vault logging\n                log_call = mock_vault.log_action.call_args\n                assert log_call[1]['tool_name'] == 'myserver__mytool'\n                assert log_call[1]['decision'] == 'Allow'\n                assert log_call[1]['amount'] == 0.0\n                assert len(log_call[1]['detail']) <= 500\n            finally:\n                os.unlink(policy_path)\n    \n    @pytest.mark.asyncio\n    async def test_call_tool_invalid_format_error(self):\n        \"\"\"Verify call_tool returns invalid_tool_name_format error when name lacks '__' separator\"\"\"\n        upstreams = MockMutex([])\n        proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), None)\n        \n        request = CallToolRequestParams('invalid_tool_name', {})\n        \n        with pytest.raises(McpError) as exc_info:\n            await proxy.call_tool(request, RequestContext())\n        \n        assert exc_info.value.error_type == 'invalid_tool_name_format'\n    \n    @pytest.mark.asyncio\n    async def test_call_tool_unknown_server_error(self):\n        \"\"\"Verify call_tool returns unknown_server error when server prefix doesn't match any upstream\"\"\"\n        upstream = UpstreamConnection('known_server', Mock(), [])\n        upstreams = MockMutex([upstream])\n        proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), None)\n        \n        request = CallToolRequestParams('unknown_server__tool', {})\n        \n        with pytest.raises(McpError) as exc_info:\n            await proxy.call_tool(request, RequestContext())\n        \n        assert exc_info.value.error_type == 'unknown_server'\n    \n    @pytest.mark.asyncio\n    async def test_call_tool_deny_decision(self):\n        \"\"\"Verify call_tool returns error for Deny policy decision and logs with amount 0.0\"\"\"\n        mock_client = AsyncMock()\n        upstream = UpstreamConnection('server', mock_client, [Tool('tool', 'desc')])\n        upstreams = MockMutex([upstream])\n        \n        mock_vault = AsyncMock()\n        mock_vault.verify_integrity = AsyncMock(return_value=True)\n        mock_vault.log_action = AsyncMock()\n        \n        with patch('src_mcp_proxy.evaluate_policy', new_callable=AsyncMock) as mock_policy:\n            mock_policy.return_value = 'Deny'\n            \n            proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), mock_vault)\n            \n            with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n                f.write('rules: []')\n                policy_path = Path(f.name)\n            \n            proxy.policy_path = policy_path\n            \n            try:\n                request = CallToolRequestParams('server__tool', {})\n                \n                with pytest.raises(McpError) as exc_info:\n                    await proxy.call_tool(request, RequestContext())\n                \n                assert exc_info.value.error_type == 'policy_denied'\n                assert not mock_client.call_tool.called\n                \n                # Verify vault logged with amount 0.0\n                log_call = mock_vault.log_action.call_args\n                assert log_call[1]['decision'] == 'Deny'\n                assert log_call[1]['amount'] == 0.0\n            finally:\n                os.unlink(policy_path)\n    \n    @pytest.mark.asyncio\n    async def test_call_tool_ask_decision(self):\n        \"\"\"Verify call_tool returns error for Ask policy decision\"\"\"\n        mock_client = AsyncMock()\n        upstream = UpstreamConnection('server', mock_client, [Tool('tool', 'desc')])\n        upstreams = MockMutex([upstream])\n        \n        mock_vault = AsyncMock()\n        mock_vault.verify_integrity = AsyncMock(return_value=True)\n        mock_vault.log_action = AsyncMock()\n        \n        with patch('src_mcp_proxy.evaluate_policy', new_callable=AsyncMock) as mock_policy:\n            mock_policy.return_value = 'Ask'\n            \n            proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), mock_vault)\n            \n            with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n                f.write('rules: []')\n                policy_path = Path(f.name)\n            \n            proxy.policy_path = policy_path\n            \n            try:\n                request = CallToolRequestParams('server__tool', {})\n                \n                with pytest.raises(McpError):\n                    await proxy.call_tool(request, RequestContext())\n                \n                assert not mock_client.call_tool.called\n                \n                log_call = mock_vault.log_action.call_args\n                assert log_call[1]['amount'] == 0.0\n            finally:\n                os.unlink(policy_path)\n    \n    @pytest.mark.asyncio\n    async def test_call_tool_gate_decision(self):\n        \"\"\"Verify call_tool returns error for Gate policy decision\"\"\"\n        mock_client = AsyncMock()\n        upstream = UpstreamConnection('server', mock_client, [Tool('tool', 'desc')])\n        upstreams = MockMutex([upstream])\n        \n        mock_vault = AsyncMock()\n        mock_vault.verify_integrity = AsyncMock(return_value=True)\n        mock_vault.log_action = AsyncMock()\n        \n        with patch('src_mcp_proxy.evaluate_policy', new_callable=AsyncMock) as mock_policy:\n            mock_policy.return_value = 'Gate'\n            \n            proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), mock_vault)\n            \n            with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n                f.write('rules: []')\n                policy_path = Path(f.name)\n            \n            proxy.policy_path = policy_path\n            \n            try:\n                request = CallToolRequestParams('server__tool', {})\n                \n                with pytest.raises(McpError):\n                    await proxy.call_tool(request, RequestContext())\n                \n                assert not mock_client.call_tool.called\n                \n                log_call = mock_vault.log_action.call_args\n                assert log_call[1]['amount'] == 0.0\n            finally:\n                os.unlink(policy_path)\n    \n    @pytest.mark.asyncio\n    async def test_call_tool_ensure_decision(self):\n        \"\"\"Verify call_tool returns error for Ensure policy decision\"\"\"\n        mock_client = AsyncMock()\n        upstream = UpstreamConnection('server', mock_client, [Tool('tool', 'desc')])\n        upstreams = MockMutex([upstream])\n        \n        mock_vault = AsyncMock()\n        mock_vault.verify_integrity = AsyncMock(return_value=True)\n        mock_vault.log_action = AsyncMock()\n        \n        with patch('src_mcp_proxy.evaluate_policy', new_callable=AsyncMock) as mock_policy:\n            mock_policy.return_value = 'Ensure'\n            \n            proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), mock_vault)\n            \n            with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n                f.write('rules: []')\n                policy_path = Path(f.name)\n            \n            proxy.policy_path = policy_path\n            \n            try:\n                request = CallToolRequestParams('server__tool', {})\n                \n                with pytest.raises(McpError):\n                    await proxy.call_tool(request, RequestContext())\n                \n                assert not mock_client.call_tool.called\n                \n                log_call = mock_vault.log_action.call_args\n                assert log_call[1]['amount'] == 0.0\n            finally:\n                os.unlink(policy_path)\n    \n    @pytest.mark.asyncio\n    async def test_call_tool_policy_tampered(self):\n        \"\"\"Verify call_tool uses default_policy when integrity check fails\"\"\"\n        mock_client = AsyncMock()\n        upstream = UpstreamConnection('server', mock_client, [Tool('tool', 'desc')])\n        upstreams = MockMutex([upstream])\n        \n        mock_vault = AsyncMock()\n        mock_vault.verify_integrity = AsyncMock(return_value=False)  # Integrity fails\n        mock_vault.log_action = AsyncMock()\n        \n        with patch('src_mcp_proxy.default_policy', new_callable=AsyncMock) as mock_default:\n            mock_default.return_value = 'Deny'\n            \n            proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), mock_vault)\n            \n            with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n                f.write('rules: []')\n                policy_path = Path(f.name)\n            \n            proxy.policy_path = policy_path\n            \n            try:\n                request = CallToolRequestParams('server__tool', {})\n                \n                with pytest.raises(McpError):\n                    await proxy.call_tool(request, RequestContext())\n                \n                # Verify default_policy was called\n                assert mock_default.called\n                assert not mock_client.call_tool.called\n            finally:\n                os.unlink(policy_path)\n    \n    @pytest.mark.asyncio\n    async def test_call_tool_no_vault(self):\n        \"\"\"Verify call_tool uses default_policy and skips logging when vault is None\"\"\"\n        mock_client = AsyncMock()\n        upstream = UpstreamConnection('server', mock_client, [Tool('tool', 'desc')])\n        upstreams = MockMutex([upstream])\n        \n        with patch('src_mcp_proxy.default_policy', new_callable=AsyncMock) as mock_default:\n            mock_default.return_value = 'Deny'\n            \n            proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), None)  # No vault\n            \n            request = CallToolRequestParams('server__tool', {})\n            \n            with pytest.raises(McpError):\n                await proxy.call_tool(request, RequestContext())\n            \n            # Verify default_policy was used\n            assert mock_default.called\n            assert not mock_client.call_tool.called\n    \n    @pytest.mark.asyncio\n    async def test_call_tool_detail_truncation(self):\n        \"\"\"Verify call_tool truncates detail to 500 characters in vault log\"\"\"\n        mock_client = AsyncMock()\n        mock_client.call_tool = AsyncMock(return_value=CallToolResult([]))\n        \n        upstream = UpstreamConnection('server', mock_client, [Tool('tool', 'desc')])\n        upstreams = MockMutex([upstream])\n        \n        mock_vault = AsyncMock()\n        mock_vault.verify_integrity = AsyncMock(return_value=True)\n        mock_vault.log_action = AsyncMock()\n        \n        with patch('src_mcp_proxy.evaluate_policy', new_callable=AsyncMock) as mock_policy:\n            mock_policy.return_value = 'Allow'\n            \n            proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), mock_vault)\n            \n            with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n                f.write('rules: []')\n                policy_path = Path(f.name)\n            \n            proxy.policy_path = policy_path\n            \n            try:\n                # Create request with very long arguments\n                long_arg = 'x' * 1000\n                request = CallToolRequestParams('server__tool', {'data': long_arg})\n                \n                await proxy.call_tool(request, RequestContext())\n                \n                # Verify detail is truncated to 500 chars\n                log_call = mock_vault.log_action.call_args\n                detail = log_call[1]['detail']\n                assert len(detail) == 500\n            finally:\n                os.unlink(policy_path)\n\n\nclass TestConnectUpstream:\n    \"\"\"Tests for connect_upstream function\"\"\"\n    \n    @pytest.mark.asyncio\n    async def test_connect_upstream_happy(self):\n        \"\"\"Verify connect_upstream successfully spawns process and establishes connection\"\"\"\n        config = UpstreamConfig(\n            command='/usr/bin/python3',\n            args=['-m', 'mcp_server'],\n            env={'VAR': 'value'}\n        )\n        \n        with patch('src_mcp_proxy.asyncio.create_subprocess_exec') as mock_subprocess, \\\n             patch('src_mcp_proxy.TokioChildProcess') as mock_transport, \\\n             patch('src_mcp_proxy.serve_client') as mock_serve:\n            \n            # Mock process\n            mock_process = AsyncMock()\n            mock_process.stdin = Mock()\n            mock_process.stdout = Mock()\n            mock_subprocess.return_value = mock_process\n            \n            # Mock client\n            mock_client = AsyncMock()\n            mock_client.list_tools = AsyncMock(return_value=ListToolsResult([\n                Tool('tool1', 'Tool 1')\n            ]))\n            mock_serve.return_value = mock_client\n            \n            result = await connect_upstream('testserver', config)\n            \n            assert result.name == 'testserver'\n            assert result.client is not None\n            assert len(result.tools) == 1\n            assert result.tools[0].name == 'tool1'\n    \n    @pytest.mark.asyncio\n    async def test_connect_upstream_process_spawn_error(self):\n        \"\"\"Verify connect_upstream returns process_spawn_error for invalid command\"\"\"\n        config = UpstreamConfig(\n            command='/nonexistent/command',\n            args=[],\n            env={}\n        )\n        \n        with patch('src_mcp_proxy.asyncio.create_subprocess_exec') as mock_subprocess:\n            mock_subprocess.side_effect = FileNotFoundError('Command not found')\n            \n            with pytest.raises(Exception) as exc_info:\n                await connect_upstream('testserver', config)\n            \n            assert 'process_spawn_error' in str(exc_info.value) or isinstance(exc_info.value, FileNotFoundError)\n    \n    @pytest.mark.asyncio\n    async def test_connect_upstream_transport_error(self):\n        \"\"\"Verify connect_upstream returns transport_error when TokioChildProcess creation fails\"\"\"\n        config = UpstreamConfig(command='/bin/echo', args=[], env={})\n        \n        with patch('src_mcp_proxy.asyncio.create_subprocess_exec') as mock_subprocess, \\\n             patch('src_mcp_proxy.TokioChildProcess') as mock_transport:\n            \n            mock_process = AsyncMock()\n            mock_subprocess.return_value = mock_process\n            \n            mock_transport.side_effect = Exception('transport_error')\n            \n            with pytest.raises(Exception) as exc_info:\n                await connect_upstream('testserver', config)\n            \n            assert 'transport_error' in str(exc_info.value)\n    \n    @pytest.mark.asyncio\n    async def test_connect_upstream_client_connection_error(self):\n        \"\"\"Verify connect_upstream returns client_connection_error when serve_client fails\"\"\"\n        config = UpstreamConfig(command='/bin/echo', args=[], env={})\n        \n        with patch('src_mcp_proxy.asyncio.create_subprocess_exec') as mock_subprocess, \\\n             patch('src_mcp_proxy.TokioChildProcess') as mock_transport, \\\n             patch('src_mcp_proxy.serve_client') as mock_serve:\n            \n            mock_process = AsyncMock()\n            mock_subprocess.return_value = mock_process\n            mock_transport.return_value = Mock()\n            \n            mock_serve.side_effect = Exception('client_connection_error')\n            \n            with pytest.raises(Exception) as exc_info:\n                await connect_upstream('testserver', config)\n            \n            assert 'client_connection_error' in str(exc_info.value)\n    \n    @pytest.mark.asyncio\n    async def test_connect_upstream_list_tools_error(self):\n        \"\"\"Verify connect_upstream returns list_tools_error when upstream doesn't respond to list_tools\"\"\"\n        config = UpstreamConfig(command='/bin/echo', args=[], env={})\n        \n        with patch('src_mcp_proxy.asyncio.create_subprocess_exec') as mock_subprocess, \\\n             patch('src_mcp_proxy.TokioChildProcess') as mock_transport, \\\n             patch('src_mcp_proxy.serve_client') as mock_serve:\n            \n            mock_process = AsyncMock()\n            mock_subprocess.return_value = mock_process\n            mock_transport.return_value = Mock()\n            \n            mock_client = AsyncMock()\n            mock_client.list_tools = AsyncMock(side_effect=Exception('list_tools_error'))\n            mock_serve.return_value = mock_client\n            \n            with pytest.raises(Exception) as exc_info:\n                await connect_upstream('testserver', config)\n            \n            assert 'list_tools_error' in str(exc_info.value)\n    \n    @pytest.mark.asyncio\n    async def test_connect_upstream_env_variables(self):\n        \"\"\"Verify connect_upstream passes environment variables to child process\"\"\"\n        config = UpstreamConfig(\n            command='/bin/echo',\n            args=['test'],\n            env={'CUSTOM_VAR': 'custom_value', 'ANOTHER': 'value2'}\n        )\n        \n        with patch('src_mcp_proxy.asyncio.create_subprocess_exec') as mock_subprocess, \\\n             patch('src_mcp_proxy.TokioChildProcess') as mock_transport, \\\n             patch('src_mcp_proxy.serve_client') as mock_serve:\n            \n            mock_process = AsyncMock()\n            mock_subprocess.return_value = mock_process\n            mock_transport.return_value = Mock()\n            \n            mock_client = AsyncMock()\n            mock_client.list_tools = AsyncMock(return_value=ListToolsResult([]))\n            mock_serve.return_value = mock_client\n            \n            await connect_upstream('testserver', config)\n            \n            # Verify environment variables were passed\n            call_args = mock_subprocess.call_args\n            assert 'env' in call_args[1] or len(call_args) > 0\n\n\nclass TestRunProxy:\n    \"\"\"Tests for run_proxy function\"\"\"\n    \n    @pytest.mark.asyncio\n    async def test_run_proxy_no_config_file(self):\n        \"\"\"Verify run_proxy returns Ok(()) early when proxy.yaml doesn't exist\"\"\"\n        with patch('src_mcp_proxy.proxy_config_path') as mock_path:\n            mock_path.return_value = Path('/nonexistent/proxy.yaml')\n            \n            result = await run_proxy()\n            \n            assert result is None  # Returns early without error\n    \n    @pytest.mark.asyncio\n    async def test_run_proxy_empty_servers(self):\n        \"\"\"Verify run_proxy returns Ok(()) early when config.servers is empty\"\"\"\n        with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n            yaml.dump({'servers': {}}, f)\n            config_path = Path(f.name)\n        \n        try:\n            with patch('src_mcp_proxy.proxy_config_path') as mock_path:\n                mock_path.return_value = config_path\n                \n                result = await run_proxy()\n                \n                assert result is None  # Returns early\n        finally:\n            os.unlink(config_path)\n    \n    @pytest.mark.asyncio\n    async def test_run_proxy_invalid_yaml(self):\n        \"\"\"Verify run_proxy returns config_parse_error for malformed YAML\"\"\"\n        with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n            f.write('invalid: yaml: content: [')\n            config_path = Path(f.name)\n        \n        try:\n            with patch('src_mcp_proxy.proxy_config_path') as mock_path:\n                mock_path.return_value = config_path\n                \n                with pytest.raises(Exception) as exc_info:\n                    await run_proxy()\n                \n                assert 'config_parse_error' in str(exc_info.value)\n        finally:\n            os.unlink(config_path)\n    \n    @pytest.mark.asyncio\n    async def test_run_proxy_invalid_schema(self):\n        \"\"\"Verify run_proxy returns config_parse_error when YAML doesn't match ProxyConfig schema\"\"\"\n        with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n            # Missing required fields\n            yaml.dump({'wrong_field': 'value'}, f)\n            config_path = Path(f.name)\n        \n        try:\n            with patch('src_mcp_proxy.proxy_config_path') as mock_path:\n                mock_path.return_value = config_path\n                \n                with pytest.raises(Exception) as exc_info:\n                    await run_proxy()\n                \n                assert 'config_parse_error' in str(exc_info.value) or 'servers' in str(exc_info.value)\n        finally:\n            os.unlink(config_path)\n    \n    @pytest.mark.asyncio\n    async def test_run_proxy_partial_upstream_failure(self):\n        \"\"\"Verify run_proxy continues when some upstream connections fail\"\"\"\n        config_data = {\n            'servers': {\n                'working_server': {\n                    'command': '/bin/echo',\n                    'args': [],\n                    'env': {}\n                },\n                'failing_server': {\n                    'command': '/nonexistent',\n                    'args': [],\n                    'env': {}\n                },\n                'another_working': {\n                    'command': '/bin/true',\n                    'args': [],\n                    'env': {}\n                }\n            }\n        }\n        \n        with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n            yaml.dump(config_data, f)\n            config_path = Path(f.name)\n        \n        try:\n            with patch('src_mcp_proxy.proxy_config_path') as mock_path, \\\n                 patch('src_mcp_proxy.connect_upstream') as mock_connect, \\\n                 patch('src_mcp_proxy.serve_server') as mock_serve, \\\n                 patch('sys.stderr'):\n                \n                mock_path.return_value = config_path\n                \n                # First and third succeed, second fails\n                mock_connect.side_effect = [\n                    UpstreamConnection('working_server', Mock(), []),\n                    Exception('Connection failed'),\n                    UpstreamConnection('another_working', Mock(), [])\n                ]\n                \n                mock_service = AsyncMock()\n                mock_service.waiting = AsyncMock(return_value=None)\n                mock_serve.return_value = mock_service\n                \n                await run_proxy()\n                \n                # Verify all three connection attempts were made\n                assert mock_connect.call_count == 3\n        finally:\n            os.unlink(config_path)\n    \n    @pytest.mark.asyncio\n    async def test_run_proxy_happy(self):\n        \"\"\"Verify run_proxy successfully starts with valid config and upstreams\"\"\"\n        config_data = {\n            'servers': {\n                'server1': {\n                    'command': '/bin/echo',\n                    'args': ['arg1'],\n                    'env': {'VAR': 'val'}\n                }\n            }\n        }\n        \n        with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n            yaml.dump(config_data, f)\n            config_path = Path(f.name)\n        \n        try:\n            with patch('src_mcp_proxy.proxy_config_path') as mock_path, \\\n                 patch('src_mcp_proxy.connect_upstream') as mock_connect, \\\n                 patch('src_mcp_proxy.serve_server') as mock_serve, \\\n                 patch('src_mcp_proxy.signet_dir') as mock_signet:\n                \n                mock_path.return_value = config_path\n                mock_signet.return_value = Path('/tmp/.signet')\n                \n                mock_connect.return_value = UpstreamConnection('server1', Mock(), [])\n                \n                mock_service = AsyncMock()\n                mock_service.waiting = AsyncMock(return_value=None)\n                mock_serve.return_value = mock_service\n                \n                await run_proxy()\n                \n                # Verify upstream was connected\n                assert mock_connect.called\n                \n                # Verify server was started\n                assert mock_serve.called\n                \n                # Verify service.waiting was called (blocking)\n                assert mock_service.waiting.called\n        finally:\n            os.unlink(config_path)\n\n\nclass TestConfigDeserialization:\n    \"\"\"Tests for ProxyConfig and UpstreamConfig deserialization\"\"\"\n    \n    @pytest.mark.asyncio\n    async def test_config_deserialization_single_server(self):\n        \"\"\"Verify ProxyConfig deserializes single server configuration correctly\"\"\"\n        config_data = {\n            'servers': {\n                'myserver': {\n                    'command': '/usr/bin/python3',\n                    'args': ['-m', 'server'],\n                    'env': {'KEY': 'value'}\n                }\n            }\n        }\n        \n        with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n            yaml.dump(config_data, f)\n            config_path = Path(f.name)\n        \n        try:\n            with open(config_path, 'r') as f:\n                loaded_data = yaml.safe_load(f)\n            \n            assert 'servers' in loaded_data\n            assert len(loaded_data['servers']) == 1\n            assert 'myserver' in loaded_data['servers']\n            \n            server_config = loaded_data['servers']['myserver']\n            assert server_config['command'] == '/usr/bin/python3'\n            assert server_config['args'] == ['-m', 'server']\n            assert server_config['env'] == {'KEY': 'value'}\n        finally:\n            os.unlink(config_path)\n    \n    @pytest.mark.asyncio\n    async def test_config_deserialization_multiple_servers(self):\n        \"\"\"Verify ProxyConfig deserializes multiple server configurations\"\"\"\n        config_data = {\n            'servers': {\n                'server1': {'command': 'cmd1', 'args': ['a1'], 'env': {}},\n                'server2': {'command': 'cmd2', 'args': ['a2'], 'env': {}},\n                'server3': {'command': 'cmd3', 'args': [], 'env': {'E': 'V'}}\n            }\n        }\n        \n        with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n            yaml.dump(config_data, f)\n            config_path = Path(f.name)\n        \n        try:\n            with open(config_path, 'r') as f:\n                loaded_data = yaml.safe_load(f)\n            \n            assert len(loaded_data['servers']) == 3\n            assert 'server1' in loaded_data['servers']\n            assert 'server2' in loaded_data['servers']\n            assert 'server3' in loaded_data['servers']\n        finally:\n            os.unlink(config_path)\n    \n    @pytest.mark.asyncio\n    async def test_config_empty_args_array(self):\n        \"\"\"Verify UpstreamConfig handles empty args array\"\"\"\n        config = UpstreamConfig(command='/bin/echo', args=[], env={})\n        \n        assert config.command == '/bin/echo'\n        assert config.args == []\n        assert isinstance(config.args, list)\n    \n    @pytest.mark.asyncio\n    async def test_config_empty_env_map(self):\n        \"\"\"Verify UpstreamConfig handles empty env HashMap\"\"\"\n        config = UpstreamConfig(command='/bin/echo', args=['test'], env={})\n        \n        assert config.command == '/bin/echo'\n        assert config.env == {}\n        assert isinstance(config.env, dict)\n\n\nclass TestInvariants:\n    \"\"\"Tests for contract invariants\"\"\"\n    \n    @pytest.mark.asyncio\n    async def test_invariant_tool_name_format(self):\n        \"\"\"Verify all tools exposed by proxy always use server__tool format\"\"\"\n        upstreams = [\n            UpstreamConnection('srv1', Mock(), [Tool('t1', 'd1'), Tool('t2', 'd2')]),\n            UpstreamConnection('srv2', Mock(), [Tool('t3', 'd3')])\n        ]\n        \n        proxy = ProxyServer(MockMutex(upstreams), Path('/tmp/policy.yaml'), None)\n        result = await proxy.list_tools(None, RequestContext())\n        \n        for tool in result.tools:\n            assert '__' in tool.name\n            parts = tool.name.split('__')\n            assert len(parts) == 2\n            assert parts[0] in ['srv1', 'srv2']\n            assert parts[1] in ['t1', 't2', 't3']\n    \n    @pytest.mark.asyncio\n    async def test_invariant_policy_reload(self):\n        \"\"\"Verify policy is reloaded and integrity-checked on every call_tool invocation\"\"\"\n        mock_client = AsyncMock()\n        mock_client.call_tool = AsyncMock(return_value=CallToolResult([]))\n        \n        upstream = UpstreamConnection('server', mock_client, [Tool('tool', 'desc')])\n        upstreams = MockMutex([upstream])\n        \n        mock_vault = AsyncMock()\n        mock_vault.verify_integrity = AsyncMock(return_value=True)\n        mock_vault.log_action = AsyncMock()\n        \n        with patch('src_mcp_proxy.evaluate_policy', new_callable=AsyncMock) as mock_policy:\n            mock_policy.return_value = 'Allow'\n            \n            proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), mock_vault)\n            \n            with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n                f.write('rules: []')\n                policy_path = Path(f.name)\n            \n            proxy.policy_path = policy_path\n            \n            try:\n                # Make multiple calls\n                for _ in range(3):\n                    request = CallToolRequestParams('server__tool', {})\n                    await proxy.call_tool(request, RequestContext())\n                \n                # Verify integrity check was called each time\n                assert mock_vault.verify_integrity.call_count == 3\n            finally:\n                os.unlink(policy_path)\n    \n    @pytest.mark.asyncio\n    async def test_invariant_no_vault_uses_default_policy(self):\n        \"\"\"Verify default_policy is always used when vault is None\"\"\"\n        mock_client = AsyncMock()\n        upstream = UpstreamConnection('server', mock_client, [Tool('tool', 'desc')])\n        upstreams = MockMutex([upstream])\n        \n        with patch('src_mcp_proxy.default_policy', new_callable=AsyncMock) as mock_default:\n            mock_default.return_value = 'Deny'\n            \n            proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), None)\n            \n            # Make multiple calls\n            for _ in range(3):\n                request = CallToolRequestParams('server__tool', {})\n                try:\n                    await proxy.call_tool(request, RequestContext())\n                except McpError:\n                    pass\n            \n            # Verify default_policy was called each time\n            assert mock_default.call_count == 3\n    \n    @pytest.mark.asyncio\n    async def test_invariant_non_allow_amount_zero(self):\n        \"\"\"Verify amount logged is 0.0 for any non-Allow decision\"\"\"\n        mock_client = AsyncMock()\n        upstream = UpstreamConnection('server', mock_client, [Tool('tool', 'desc')])\n        upstreams = MockMutex([upstream])\n        \n        mock_vault = AsyncMock()\n        mock_vault.verify_integrity = AsyncMock(return_value=True)\n        mock_vault.log_action = AsyncMock()\n        \n        decisions = ['Deny', 'Ask', 'Gate', 'Ensure']\n        \n        for decision in decisions:\n            with patch('src_mcp_proxy.evaluate_policy', new_callable=AsyncMock) as mock_policy:\n                mock_policy.return_value = decision\n                \n                proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), mock_vault)\n                \n                with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n                    f.write('rules: []')\n                    policy_path = Path(f.name)\n                \n                proxy.policy_path = policy_path\n                \n                try:\n                    request = CallToolRequestParams('server__tool', {})\n                    \n                    try:\n                        await proxy.call_tool(request, RequestContext())\n                    except McpError:\n                        pass\n                    \n                    # Verify amount is 0.0\n                    log_call = mock_vault.log_action.call_args\n                    assert log_call[1]['amount'] == 0.0\n                    assert log_call[1]['decision'] == decision\n                finally:\n                    os.unlink(policy_path)\n\n\nclass TestConcurrency:\n    \"\"\"Tests for concurrent operations\"\"\"\n    \n    @pytest.mark.asyncio\n    async def test_concurrent_list_tools(self):\n        \"\"\"Verify list_tools handles concurrent requests correctly with mutex\"\"\"\n        upstream = UpstreamConnection('server', Mock(), [\n            Tool('t1', 'd1'),\n            Tool('t2', 'd2')\n        ])\n        upstreams = MockMutex([upstream])\n        \n        proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), None)\n        \n        # Run multiple concurrent list_tools calls\n        results = await asyncio.gather(*[\n            proxy.list_tools(None, RequestContext())\n            for _ in range(5)\n        ])\n        \n        # All should succeed with same results\n        assert len(results) == 5\n        for result in results:\n            assert len(result.tools) == 2\n            assert result.tools[0].name == 'server__t1'\n    \n    @pytest.mark.asyncio\n    async def test_concurrent_call_tool_different_upstreams(self):\n        \"\"\"Verify concurrent call_tool requests to different upstreams work correctly\"\"\"\n        mock_client1 = AsyncMock()\n        mock_client1.call_tool = AsyncMock(return_value=CallToolResult([{'result': '1'}]))\n        \n        mock_client2 = AsyncMock()\n        mock_client2.call_tool = AsyncMock(return_value=CallToolResult([{'result': '2'}]))\n        \n        upstream1 = UpstreamConnection('server1', mock_client1, [Tool('tool', 'desc')])\n        upstream2 = UpstreamConnection('server2', mock_client2, [Tool('tool', 'desc')])\n        \n        upstreams = MockMutex([upstream1, upstream2])\n        \n        mock_vault = AsyncMock()\n        mock_vault.verify_integrity = AsyncMock(return_value=True)\n        mock_vault.log_action = AsyncMock()\n        \n        with patch('src_mcp_proxy.evaluate_policy', new_callable=AsyncMock) as mock_policy:\n            mock_policy.return_value = 'Allow'\n            \n            proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), mock_vault)\n            \n            with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n                f.write('rules: []')\n                policy_path = Path(f.name)\n            \n            proxy.policy_path = policy_path\n            \n            try:\n                request1 = CallToolRequestParams('server1__tool', {})\n                request2 = CallToolRequestParams('server2__tool', {})\n                \n                results = await asyncio.gather(\n                    proxy.call_tool(request1, RequestContext()),\n                    proxy.call_tool(request2, RequestContext())\n                )\n                \n                assert len(results) == 2\n                assert mock_client1.call_tool.called\n                assert mock_client2.call_tool.called\n                assert mock_vault.log_action.call_count == 2\n            finally:\n                os.unlink(policy_path)\n    \n    @pytest.mark.asyncio\n    async def test_concurrent_call_tool_same_upstream(self):\n        \"\"\"Verify concurrent call_tool requests to same upstream are handled safely\"\"\"\n        mock_client = AsyncMock()\n        call_count = {'count': 0}\n        \n        async def mock_call_tool(tool_name, args):\n            call_count['count'] += 1\n            await asyncio.sleep(0.01)  # Small delay to test concurrency\n            return CallToolResult([{'call': call_count['count']}])\n        \n        mock_client.call_tool = mock_call_tool\n        \n        upstream = UpstreamConnection('server', mock_client, [Tool('tool', 'desc')])\n        upstreams = MockMutex([upstream])\n        \n        mock_vault = AsyncMock()\n        mock_vault.verify_integrity = AsyncMock(return_value=True)\n        mock_vault.log_action = AsyncMock()\n        \n        with patch('src_mcp_proxy.evaluate_policy', new_callable=AsyncMock) as mock_policy:\n            mock_policy.return_value = 'Allow'\n            \n            proxy = ProxyServer(upstreams, Path('/tmp/policy.yaml'), mock_vault)\n            \n            with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:\n                f.write('rules: []')\n                policy_path = Path(f.name)\n            \n            proxy.policy_path = policy_path\n            \n            try:\n                requests = [CallToolRequestParams('server__tool', {}) for _ in range(3)]\n                \n                results = await asyncio.gather(*[\n                    proxy.call_tool(req, RequestContext())\n                    for req in requests\n                ])\n                \n                assert len(results) == 3\n                assert call_count['count'] == 3\n                assert mock_vault.log_action.call_count == 3\n            finally:\n                os.unlink(policy_path)\n\n\nif __name__ == '__main__':\n    pytest.main([__file__, '-v'])\n"
}