{
  "component_id": "src_mcp_proxy.rs",
  "name": "MCP Proxy Server",
  "description": "Signet MCP Proxy wraps upstream MCP servers with policy enforcement. Intercepts tool calls, validates them against hot-reloadable policies with cryptographic integrity verification, logs actions to the vault, and forwards allowed calls to the appropriate upstream server. Provides unified tool discovery across multiple upstream servers with namespaced tool names.",
  "version": 1,
  "types": [
    {
      "name": "ProxyConfig",
      "kind": "struct",
      "fields": [
        {
          "name": "servers",
          "type_ref": "HashMap<String, UpstreamConfig>",
          "required": true,
          "default": "HashMap::new()",
          "description": "Map of server names to their upstream configurations",
          "validators": []
        }
      ],
      "item_type": "",
      "variants": [],
      "inner_types": [],
      "description": "Configuration structure for the proxy server, deserialized from proxy.yaml",
      "owner_component": ""
    },
    {
      "name": "UpstreamConfig",
      "kind": "struct",
      "fields": [
        {
          "name": "command",
          "type_ref": "String",
          "required": true,
          "default": "",
          "description": "Executable command to spawn the upstream server",
          "validators": []
        },
        {
          "name": "args",
          "type_ref": "Vec<String>",
          "required": true,
          "default": "Vec::new()",
          "description": "Command-line arguments for the upstream server",
          "validators": []
        },
        {
          "name": "env",
          "type_ref": "HashMap<String, String>",
          "required": true,
          "default": "HashMap::new()",
          "description": "Environment variables to set for the upstream server process",
          "validators": []
        }
      ],
      "item_type": "",
      "variants": [],
      "inner_types": [],
      "description": "Configuration for a single upstream MCP server process",
      "owner_component": ""
    },
    {
      "name": "UpstreamConnection",
      "kind": "struct",
      "fields": [
        {
          "name": "name",
          "type_ref": "String",
          "required": true,
          "default": "",
          "description": "Server name identifier",
          "validators": []
        },
        {
          "name": "client",
          "type_ref": "rmcp::service::RunningService<rmcp::RoleClient, ()>",
          "required": true,
          "default": "",
          "description": "Active client connection to the upstream server",
          "validators": []
        },
        {
          "name": "tools",
          "type_ref": "Vec<Tool>",
          "required": true,
          "default": "",
          "description": "Cached list of tools provided by this upstream server",
          "validators": []
        }
      ],
      "item_type": "",
      "variants": [],
      "inner_types": [],
      "description": "Runtime state for a connected upstream MCP server",
      "owner_component": ""
    },
    {
      "name": "ProxyServer",
      "kind": "struct",
      "fields": [
        {
          "name": "upstreams",
          "type_ref": "Arc<Mutex<Vec<UpstreamConnection>>>",
          "required": true,
          "default": "",
          "description": "Thread-safe collection of active upstream connections",
          "validators": []
        },
        {
          "name": "policy_path",
          "type_ref": "PathBuf",
          "required": true,
          "default": "",
          "description": "Filesystem path to the policy YAML file, hot-reloaded on every call_tool()",
          "validators": []
        },
        {
          "name": "vault",
          "type_ref": "Option<Vault>",
          "required": true,
          "default": "",
          "description": "Optional cryptographic vault for policy integrity verification and action logging",
          "validators": []
        }
      ],
      "item_type": "",
      "variants": [],
      "inner_types": [],
      "description": "Main proxy server implementation that enforces policies on tool calls to upstream MCP servers",
      "owner_component": ""
    }
  ],
  "functions": [
    {
      "name": "proxy_config_path",
      "description": "Returns the filesystem path to the proxy configuration file (proxy.yaml) within the Signet directory",
      "inputs": [],
      "output_type": "PathBuf",
      "error_cases": [],
      "preconditions": [],
      "postconditions": [
        "Returns vault::signet_dir().join(\"proxy.yaml\")"
      ],
      "idempotent": false,
      "is_async": false,
      "side_effects": [],
      "structured_side_effects": [
        {
          "kind": "reads_file",
          "target": "vault::signet_dir()",
          "description": "Calls vault::signet_dir() which may read filesystem"
        }
      ],
      "performance_budget": null
    },
    {
      "name": "get_info",
      "description": "Returns MCP server metadata including capabilities and instructions. Implements ServerHandler trait method.",
      "inputs": [
        {
          "name": "self",
          "type_ref": "&ProxyServer",
          "required": true,
          "default": "",
          "description": "",
          "validators": []
        }
      ],
      "output_type": "ServerInfo",
      "error_cases": [],
      "preconditions": [],
      "postconditions": [
        "Returns ServerInfo with instructions describing policy enforcement",
        "ServerCapabilities includes tools enabled",
        "ServerInfo.instructions is set to 'Signet-proxied MCP server. All tool calls pass through policy enforcement.'"
      ],
      "idempotent": false,
      "is_async": false,
      "side_effects": [],
      "structured_side_effects": [
        {
          "kind": "none",
          "target": "",
          "description": ""
        }
      ],
      "performance_budget": null
    },
    {
      "name": "list_tools",
      "description": "Aggregates tools from all upstream servers, prefixing each tool name with its server name (server__tool format) and prepending server name to descriptions",
      "inputs": [
        {
          "name": "self",
          "type_ref": "&ProxyServer",
          "required": true,
          "default": "",
          "description": "",
          "validators": []
        },
        {
          "name": "params",
          "type_ref": "Option<PaginatedRequestParams>",
          "required": false,
          "default": "",
          "description": "",
          "validators": []
        },
        {
          "name": "context",
          "type_ref": "RequestContext<RoleServer>",
          "required": true,
          "default": "",
          "description": "",
          "validators": []
        }
      ],
      "output_type": "Result<ListToolsResult, McpError>",
      "error_cases": [],
      "preconditions": [],
      "postconditions": [
        "Tool names are formatted as {upstream.name}__{tool.name}",
        "Tool descriptions are prefixed with [{upstream.name}]",
        "next_cursor and meta fields are None"
      ],
      "idempotent": false,
      "is_async": true,
      "side_effects": [
        "Acquires lock on self.upstreams"
      ],
      "structured_side_effects": [
        {
          "kind": "mutates_state",
          "target": "self.upstreams mutex",
          "description": "Locks the upstreams mutex for read access"
        }
      ],
      "performance_budget": null
    },
    {
      "name": "call_tool",
      "description": "Intercepts tool calls, validates against policy with integrity checks, logs to vault, and forwards allowed calls to upstream servers. Implements policy decisions: Deny, Ask, Gate, Ensure all return errors; Allow forwards to upstream.",
      "inputs": [
        {
          "name": "self",
          "type_ref": "&ProxyServer",
          "required": true,
          "default": "",
          "description": "",
          "validators": []
        },
        {
          "name": "request",
          "type_ref": "CallToolRequestParams",
          "required": true,
          "default": "",
          "description": "",
          "validators": []
        },
        {
          "name": "context",
          "type_ref": "RequestContext<RoleServer>",
          "required": true,
          "default": "",
          "description": "",
          "validators": []
        }
      ],
      "output_type": "Result<CallToolResult, McpError>",
      "error_cases": [
        {
          "name": "invalid_tool_name_format",
          "condition": "Tool name does not contain '__' separator",
          "error_type": "McpError::invalid_params",
          "error_data": {
            "message": "Tool name must be server__tool format"
          }
        },
        {
          "name": "unknown_server",
          "condition": "Server name prefix does not match any upstream connection",
          "error_type": "McpError::invalid_params",
          "error_data": {
            "message": "Unknown server: {server_name}"
          }
        }
      ],
      "preconditions": [
        "request.name must contain '__' separator (server__tool format)"
      ],
      "postconditions": [
        "If vault exists, action is logged with tool_name, decision, category, amount, and detail (truncated to 500 chars)",
        "If policy file is tampered (integrity check fails), default_policy() is used",
        "If no vault exists, default_policy() is used",
        "Amount logged is 0.0 if decision is not Allow"
      ],
      "idempotent": false,
      "is_async": true,
      "side_effects": [
        "Hot-reloads policy from filesystem on every call",
        "Verifies policy integrity using vault session key",
        "Logs action to vault if vault exists",
        "Forwards tool call to upstream server if allowed"
      ],
      "structured_side_effects": [
        {
          "kind": "reads_file",
          "target": "self.policy_path",
          "description": "Reads and reloads policy file on every call"
        },
        {
          "kind": "writes_file",
          "target": "vault log",
          "description": "Logs action to vault if vault exists"
        },
        {
          "kind": "network_call",
          "target": "upstream MCP server",
          "description": "Forwards call to upstream server if allowed"
        },
        {
          "kind": "mutates_state",
          "target": "self.upstreams mutex",
          "description": "Locks upstreams mutex to find target server"
        }
      ],
      "performance_budget": null
    },
    {
      "name": "connect_upstream",
      "description": "Spawns an upstream MCP server as a child process, establishes client connection via stdio transport, and fetches its tool list",
      "inputs": [
        {
          "name": "name",
          "type_ref": "&str",
          "required": true,
          "default": "",
          "description": "",
          "validators": []
        },
        {
          "name": "config",
          "type_ref": "&UpstreamConfig",
          "required": true,
          "default": "",
          "description": "",
          "validators": []
        }
      ],
      "output_type": "Result<UpstreamConnection, Box<dyn std::error::Error>>",
      "error_cases": [
        {
          "name": "process_spawn_error",
          "condition": "Failed to spawn child process (invalid command, missing file, etc.)",
          "error_type": "Box<dyn std::error::Error>",
          "error_data": {}
        },
        {
          "name": "transport_error",
          "condition": "Failed to create TokioChildProcess transport",
          "error_type": "Box<dyn std::error::Error>",
          "error_data": {}
        },
        {
          "name": "client_connection_error",
          "condition": "Failed to establish client connection via serve_client()",
          "error_type": "Box<dyn std::error::Error>",
          "error_data": {}
        },
        {
          "name": "list_tools_error",
          "condition": "Upstream server failed to respond to list_tools() call",
          "error_type": "Box<dyn std::error::Error>",
          "error_data": {}
        }
      ],
      "preconditions": [
        "config.command must be a valid executable path",
        "config.args must be valid arguments for the command",
        "config.env must be valid environment variables"
      ],
      "postconditions": [
        "Child process is spawned with stdin and stdout piped, stderr set to null",
        "Client connection is established via TokioChildProcess transport",
        "Tools are fetched from upstream via list_tools() call",
        "Returns UpstreamConnection with name, client, and tools"
      ],
      "idempotent": false,
      "is_async": true,
      "side_effects": [
        "Spawns child process",
        "Establishes stdio transport with child process",
        "Calls list_tools() on upstream server"
      ],
      "structured_side_effects": [
        {
          "kind": "mutates_state",
          "target": "child process",
          "description": "Spawns child process with configured command, args, and env"
        },
        {
          "kind": "network_call",
          "target": "upstream MCP server",
          "description": "Calls list_tools() RPC on upstream server"
        }
      ],
      "performance_budget": null
    },
    {
      "name": "run_proxy",
      "description": "Main entry point for MCP proxy server. Loads proxy config, connects to all upstream servers, initializes ProxyServer with vault and policy path, and runs MCP server on stdio transport until termination.",
      "inputs": [],
      "output_type": "Result<(), Box<dyn std::error::Error>>",
      "error_cases": [
        {
          "name": "config_parse_error",
          "condition": "proxy.yaml exists but is invalid YAML or does not match ProxyConfig schema",
          "error_type": "Box<dyn std::error::Error>",
          "error_data": {}
        },
        {
          "name": "service_error",
          "condition": "rmcp::serve_server() or service.waiting() fails",
          "error_type": "Box<dyn std::error::Error>",
          "error_data": {}
        }
      ],
      "preconditions": [],
      "postconditions": [
        "Returns Ok(()) early if proxy config file does not exist",
        "Returns Ok(()) early if config.servers is empty",
        "Continues on individual upstream connection failures (logs to stderr)",
        "Blocks until service terminates"
      ],
      "idempotent": false,
      "is_async": true,
      "side_effects": [
        "Reads proxy.yaml from filesystem",
        "Connects to all configured upstream servers",
        "Writes connection status and tool counts to stderr",
        "Initializes vault via vault::try_load_vault()",
        "Runs MCP server on stdio transport",
        "Blocks until service terminates"
      ],
      "structured_side_effects": [
        {
          "kind": "reads_file",
          "target": "proxy_config_path() (proxy.yaml)",
          "description": "Reads and parses proxy configuration"
        },
        {
          "kind": "reads_file",
          "target": "vault::signet_dir().join(\"policy.yaml\")",
          "description": "Policy path is set for later use in call_tool()"
        },
        {
          "kind": "logging",
          "target": "stderr",
          "description": "Logs connection status, tool counts, and errors to stderr"
        },
        {
          "kind": "mutates_state",
          "target": "child processes and upstreams",
          "description": "Spawns and connects to upstream servers"
        },
        {
          "kind": "network_call",
          "target": "stdio transport",
          "description": "Serves MCP protocol on stdin/stdout"
        }
      ],
      "performance_budget": null
    }
  ],
  "dependencies": [
    "rmcp::model",
    "rmcp::RoleServer",
    "rmcp::ServerHandler",
    "rmcp::ErrorData",
    "rmcp::service::RequestContext",
    "rmcp::transport::child_process::TokioChildProcess",
    "rmcp::serve_client",
    "rmcp::serve_server",
    "rmcp::transport::stdio",
    "serde::Deserialize",
    "std::borrow::Cow",
    "std::collections::HashMap",
    "std::path::PathBuf",
    "std::sync::Arc",
    "tokio::sync::Mutex",
    "tokio::process::Command",
    "std::process::Stdio",
    "serde_json::Value",
    "serde_yaml",
    "crate::policy",
    "crate::vault"
  ],
  "dependency_contracts": {},
  "invariants": [
    "Tool names exposed by the proxy are always in server__tool format",
    "Policy is reloaded and integrity-checked on every call_tool() invocation",
    "If policy integrity check fails, default_policy() is used as a safety fallback",
    "If vault is None, default_policy() is always used",
    "Actions are logged to vault only if vault exists",
    "Amount logged is 0.0 for any non-Allow decision",
    "Tool detail logged to vault is truncated to 500 characters maximum",
    "Upstream stderr is redirected to null",
    "Individual upstream connection failures do not prevent proxy startup",
    "Proxy returns Ok(()) early if no config file exists or no servers are configured"
  ],
  "requires": [],
  "processing_register": "",
  "data_access": {
    "reads": [
      "~/.signet/proxy.yaml (via proxy_config_path())",
      "~/.signet/policy.yaml (via vault::signet_dir().join(\"policy.yaml\"))",
      "vault session data (for integrity verification)"
    ],
    "writes": [
      "vault action log (via vault.log_action())",
      "stderr (diagnostic messages)"
    ],
    "rationale": "MCP proxy reads configuration and policy files, writes logs to vault, and communicates with upstream servers via stdio",
    "side_effects": [
      {
        "type": "file_read",
        "classification": "config",
        "fields": [
          "proxy.yaml",
          "policy.yaml"
        ],
        "rationale": "Hot-reloads policy on every call for zero-restart policy updates"
      },
      {
        "type": "file_write",
        "classification": "audit_log",
        "fields": [
          "vault action log"
        ],
        "rationale": "Immutable audit trail of all tool call decisions and parameters"
      },
      {
        "type": "process_spawn",
        "classification": "upstream_server",
        "fields": [
          "command",
          "args",
          "env"
        ],
        "rationale": "Spawns child processes for upstream MCP servers"
      },
      {
        "type": "network_io",
        "classification": "stdio_transport",
        "fields": [
          "stdin",
          "stdout"
        ],
        "rationale": "Communicates with upstream servers and MCP clients via stdio"
      }
    ]
  },
  "authority": {
    "domains": [
      "policy_enforcement",
      "upstream_tool_calls",
      "action_logging"
    ],
    "rationale": "ProxyServer is the sole enforcement point for all tool calls to upstream MCP servers. It owns the decision to allow/deny based on policy evaluation and cryptographic integrity verification."
  }
}