{
  "track_id": "mcp_architecture_refactor_20260606",
  "name": "MCP Architecture Refactor (Sub-MCP Extraction)",
  "initialized": "2026-06-06",
  "owner": "tier2-tech-lead",
  "priority": "high",
  "status": "active",
  "type": "refactor + structural + ai-readability",
  "scope": {
    "new_files": [
      "src/mcp_client_security.py",
      "src/mcp_client_legacy.py",
      "src/mcp_file_io.py",
      "src/mcp_python.py",
      "src/mcp_c.py",
      "src/mcp_cpp.py",
      "src/mcp_web.py",
      "src/mcp_analysis.py",
      "src/mcp_external.py",
      "tests/test_mcp_client.py",
      "tests/test_mcp_client_security.py",
      "tests/test_mcp_file_io.py",
      "tests/test_mcp_python.py",
      "tests/test_mcp_c.py",
      "tests/test_mcp_cpp.py",
      "tests/test_mcp_web.py",
      "tests/test_mcp_analysis.py",
      "tests/test_mcp_external.py",
      "tests/test_mcp_client_legacy.py"
    ],
    "modified_files": [
      "src/mcp_client.py",
      "tests/test_mcp_client_beads.py",
      "tests/test_mcp_config.py",
      "tests/test_mcp_perf_tool.py",
      "tests/test_mcp_ts_integration.py"
    ]
  },
  "blocked_by": ["data_oriented_error_handling_20260606", "data_structure_strengthening_20260606"],
  "blocks": ["mcp_dsl_20260606" /* not yet created; the future DSL track */],
  "estimated_phases": 7,
  "spec": "spec.md",
  "plan": "plan.md",
  "priority_order": "A (foundation + sub-MCPs) > B (Result pattern + security) > C (dispatch inversion + docs) > D (plan DSL follow-up)",
  "naming_convention": "mcp_<type>.py for native MCPs; ExternalMCPManager class name preserved in mcp_external.py",
  "current_state": {
    "mcp_client_py_lines": 2205,
    "function_count": 45,
    "dispatch_entry_points": ["dispatch (sync, line 1338)", "async_dispatch (line 1496)"],
    "external_callers": ["src/app_controller.py:61 (direct mcp_client.py_get_symbol_info call)"],
    "existing_test_files": [
      "tests/test_mcp_client_beads.py",
      "tests/test_mcp_config.py",
      "tests/test_mcp_perf_tool.py",
      "tests/test_mcp_ts_integration.py"
    ],
    "external_mcp_existing_class": "ExternalMCPManager (in mcp_client.py; runtime-loaded MCPs)"
  },
  "sub_mcps": {
    "file_io": {
      "file": "src/mcp_file_io.py",
      "class": "FileIOMCP",
      "tool_count": 9,
      "tools": ["read_file", "list_directory", "search_files", "get_file_summary", "get_file_slice", "set_file_slice", "edit_file", "get_tree", "get_git_diff"],
      "uses_security": true
    },
    "python": {
      "file": "src/mcp_python.py",
      "class": "PythonMCP",
      "tool_count": 14,
      "tools_prefix": "py_",
      "uses_security": true
    },
    "c": {
      "file": "src/mcp_c.py",
      "class": "CMCP",
      "tool_count": 5,
      "tools_prefix": "ts_c_",
      "uses_security": true
    },
    "cpp": {
      "file": "src/mcp_cpp.py",
      "class": "CppMCP",
      "tool_count": 5,
      "tools_prefix": "ts_cpp_",
      "uses_security": true
    },
    "web": {
      "file": "src/mcp_web.py",
      "class": "WebMCP",
      "tool_count": 2,
      "tools": ["web_search", "fetch_url"],
      "uses_security": false,
      "uses_url_validation": true
    },
    "analysis": {
      "file": "src/mcp_analysis.py",
      "class": "AnalysisMCP",
      "tool_count": 2,
      "tools": ["derive_code_path", "get_ui_performance"],
      "uses_security": false
    },
    "external": {
      "file": "src/mcp_external.py",
      "class": "ExternalMCP (was ExternalMCPManager; class name preserved)",
      "registered_in_all_sub_mcps": false,
      "note": "Sub-controller for runtime-loaded MCPs; the main controller delegates to it AFTER native sub-MCPs miss."
    }
  },
  "architectural_invariant": "src/mcp_client.py is the controller; the sub-MCPs (mcp_<type>.py) are self-contained units that implement the SubMCP Protocol. The 3-layer security model lives in src/mcp_client_security.py and is invoked by the controller BEFORE delegating to sub-MCPs. The legacy shim (src/mcp_client_legacy.py) re-exports all old symbols for backward compat. Result[str, ErrorInfo] is the canonical return type from invoke().",
  "threading_constraint": "Same as existing pattern. The dispatch is synchronous; async_dispatch is for external MCPs. Sub-MCPs are stateless (no shared state between calls). The controller's _tool_index is built once at init and is read-only afterward.",
  "dsl_future": {
    "rationale": "Per user notes: 'kinda want to compress the mcp to just have a single intention based DSL per mcp, kinda like command line but more flexible'. Inspired by APL/K/Cosy. Out of scope for this track ('no time for that' per user).",
    "estimated_token_savings": "JSON: ~60-100 tokens per call. DSL: ~10-20 tokens per call. ~5x reduction.",
    "follow_up_track": "mcp_dsl_20260606 (planned; not in this spec)",
    "architectural_fit": "The sub-MCP architecture is the natural unit to pair with a DSL emitter. Each mcp_<type>.py could declare a grammar (e.g., src/mcp_python_grammar.k) that compiles to a parser; the controller dispatches to either the JSON or the DSL path based on tool_input type."
  },
  "verification_criteria": [
    "src/mcp_client_security.py exists with _is_allowed, _resolve_and_check, configure; returns Result[Path] (not tuple); 100% test coverage",
    "src/mcp_client.py is slim (< 200 lines); contains MCPController + SubMCP Protocol + module-level singleton + ALL_SUB_MCPS registration; re-exports from mcp_client_legacy for backward compat",
    "src/mcp_client_legacy.py re-exports all 45+ old function names; tests/test_mcp_client_legacy.py verifies the surface",
    "src/mcp_file_io.py exists with FileIOMCP class; read_file, list_directory, etc. are instance methods; invoke() returns Result[str, ErrorInfo]",
    "src/mcp_python.py exists with PythonMCP class; all 14 py_* tools",
    "src/mcp_c.py exists with CMCP class; all 5 ts_c_* tools",
    "src/mcp_cpp.py exists with CppMCP class; all 5 ts_cpp_* tools",
    "src/mcp_web.py exists with WebMCP class; web_search, fetch_url; URL validation",
    "src/mcp_analysis.py exists with AnalysisMCP class; derive_code_path, get_ui_performance",
    "src/mcp_external.py exists with ExternalMCP class (renamed from ExternalMCPManager); same methods as the existing class",
    "MCPController.dispatch uses the ALL_SUB_MCPS lookup (O(1)); not an if/elif chain",
    "MCPController.dispatch runs _resolve_and_check for path-taking tools BEFORE delegating to sub-MCPs",
    "MCPController.get_tool_schemas aggregates from all sub-MCPs (single source of truth)",
    "tests/test_mcp_client.py: 6+ tests pass (registration, dispatch, security integration, schema aggregation)",
    "tests/test_mcp_client_security.py: 8+ tests pass (allowed, not-allowed, configure, resolve errors)",
    "tests/test_mcp_file_io.py: 9+ tests pass (one per tool + security integration)",
    "tests/test_mcp_python.py: 14+ tests pass (one per py_* tool)",
    "tests/test_mcp_c.py: 5+ tests pass (one per ts_c_* tool)",
    "tests/test_mcp_cpp.py: 5+ tests pass (one per ts_cpp_* tool)",
    "tests/test_mcp_web.py: 4+ tests pass (web_search, fetch_url, URL validation)",
    "tests/test_mcp_analysis.py: 4+ tests pass (derive_code_path, get_ui_performance)",
    "tests/test_mcp_external.py: 4+ tests pass (register_server, async_dispatch, get_tool_schemas)",
    "tests/test_mcp_client_legacy.py: 10+ tests pass (verify all 45+ old symbols re-exported)",
    "tests/test_mcp_client_beads.py (existing): no regressions",
    "tests/test_mcp_config.py (existing): no regressions",
    "tests/test_mcp_perf_tool.py (existing): no regressions",
    "tests/test_mcp_ts_integration.py (existing): no regressions",
    "src/app_controller.py:61 (the direct mcp_client.py_get_symbol_info call) still works (verified by existing tests)",
    "Full test suite: no regressions in 273+ existing tests",
    "No new threading.Thread calls in src/",
    "No new Optional[X] in the new files (the aliases are used where dicts are needed)"
  ],
  "links": {
    "backlog_entry": "conductor/tracks.md (to be added)",
    "current_mcp_client": "src/mcp_client.py",
    "external_mcp_existing": "src/mcp_client.py:ExternalMCPManager (will move to mcp_external.py:ExternalMCP)",
    "related_tracks": [
      "conductor/tracks/data_oriented_error_handling_20260606/",
      "conductor/tracks/data_structure_strengthening_20260606/",
      "conductor/tracks/test_batching_refactor_20260606/",
      "conductor/tracks/qwen_llama_grok_integration_20260606/"
    ]
  }
}
