# Technical Specification

## 1. Problem Statement

AI agents using the Model Context Protocol (MCP) face a scalability problem: each MCP server exposes 5-30 tools, and agents often need capabilities from multiple servers simultaneously.

```mermaid
graph TB
    subgraph Problem["The Scalability Problem"]
        P1["5 servers × 20 tools = 100+ tool definitions"]
        P2["Context window consumed by tool schemas"]
        P3["LLM confused by too many similar tools"]
        P4["Idle servers waste CPU + memory"]
        P5["Static config can't adapt to task"]
    end

    subgraph Impact
        P1 --> I1["❌ High token cost"]
        P2 --> I2["❌ Poor tool selection accuracy"]
        P3 --> I3["❌ Resource waste on 8GB laptops"]
        P4 --> I4["❌ Requires manual config per task"]
    end
```

## 2. Meta-Layer Architecture

MCP Grid introduces a meta-layer between agents and servers:

```mermaid
flowchart TB
    subgraph Before["Before: Direct Connection"]
        A1["Agent"] --> S1["Playwright (15 tools)"]
        A1 --> S2["GitHub (12 tools)"]
        A1 --> S3["SQLite (8 tools)"]
        A1 --> S4["Brave (3 tools)"]
        A1 --> S5["Filesystem (6 tools)"]
        Note1["44 tools in context at all times"]
    end

    subgraph After["After: With MCP Grid"]
        A2["Agent"] -->|"21 meta-tools"| G["MCP Grid"]
        G -.->|"on demand"| S6["Playwright"]
        G -.->|"on demand"| S7["GitHub"]
        G -.->|"dormant"| S8["SQLite"]
        G -.->|"dormant"| S9["Brave"]
        G -.->|"dormant"| S10["Filesystem"]
        Note2["21 tools in context, actual tools loaded per task"]
    end

    style Before fill:#fee2e2,stroke:#dc2626
    style After fill:#e8ffe8,stroke:#16a34a
```

**Core principles:**
- **Fixed interface** -- 21 meta-tools regardless of registered server count
- **On-demand provisioning** -- Servers start only when the agent needs them
- **Dynamic configuration** -- Agents configure servers per-task
- **Automatic cleanup** -- Idle servers auto-shutdown
- **Session isolation** -- Each agent session gets its own instances

---

## 3. Component Specifications

### 3.1 Server Registry (`registry/`)

```mermaid
erDiagram
    SERVERS {
        text id PK "e.g. playwright-mcp"
        text name "Human-readable name"
        text description "What this server does"
        text category "e.g. browser-automation"
        text version "Semver string"
        text tags "JSON array of tags"
        text command "e.g. npx"
        text args "JSON array of CLI args"
        text transport "stdio | http | sse"
        int port "For HTTP transport"
        text endpoint "For HTTP transport"
        text cwd "Working directory"
        text env "JSON: env vars to set"
        text required_env "JSON: required env vars"
        text configurable_options "JSON array of config fields"
        int max_instances "Per-server limit"
        int auto_shutdown_idle_seconds "Idle timeout"
        text tool_filter "JSON: enabled/disabled tools"
        text source "catalog | user | import"
        int enabled "1 or 0"
        text created_at "ISO timestamp"
        text updated_at "ISO timestamp"
    }
```

**Storage**: SQLite database + YAML catalog files loaded at startup.

**Operations**: CRUD, search by category/tag/name, MCP JSON import, source filtering.

### 3.2 Instance Manager (`instances/manager.py`)

```mermaid
flowchart TB
    subgraph Checks["Pre-Activation Checks"]
        C1["Total instances < 20?"]
        C2["Per-server < 5?"]
        C3["Per-agent < 10?"]
        C4["System memory < 80%?"]
        C5["System CPU < 90%?"]
    end

    subgraph Lifecycle["Instance Lifecycle"]
        START["Start Process"] --> INIT["Initialize MCP"]
        INIT --> DISCOVER["Discover Tools"]
        DISCOVER --> ACTIVE["Active (accepting calls)"]
        ACTIVE --> HEALTH["Health Check (periodic)"]
        HEALTH -->|"Pass"| ACTIVE
        HEALTH -->|"Fail"| RESTART["Auto-Restart"]
        RESTART -->|"Success"| ACTIVE
        RESTART -->|"Fail 3x"| DEAD["Mark Failed"]
    end

    Checks -->|"All pass"| START

    style Checks fill:#f0f9ff,stroke:#0284c7
    style Lifecycle fill:#e8ffe8,stroke:#16a34a
```

**Resource limits** (all configurable via environment):

| Limit | Default | Environment Variable |
|-------|---------|---------------------|
| Total instances | 20 | `MCP_BRIDGE_INSTANCE_MAX_TOTAL_INSTANCES` |
| Per-server | 5 | `MCP_BRIDGE_INSTANCE_MAX_INSTANCES_PER_SERVER` |
| Per-agent | 10 | `MCP_BRIDGE_INSTANCE_MAX_INSTANCES_PER_AGENT` |
| Startup timeout | 30s | `MCP_BRIDGE_INSTANCE_STARTUP_TIMEOUT_SECONDS` |
| Idle timeout | 300s | `MCP_BRIDGE_INSTANCE_IDLE_TIMEOUT_SECONDS` |
| Max memory | 80% | `MCP_BRIDGE_SYSTEM_MAX_MEMORY_PERCENT` |
| Max CPU | 90% | `MCP_BRIDGE_SYSTEM_MAX_CPU_PERCENT` |

### 3.3 MCP Connector (`instances/connector.py`)

Two transport implementations behind the same interface:

```mermaid
flowchart LR
    subgraph STDIO["STDIO Transport"]
        S1["stdio_client(StdioServerParameters)"]
        S2["ClientSession"]
        S3["session.initialize()"]
        S4["session.list_tools()"]
        S5["session.call_tool(name, args)"]
        S1 --> S2 --> S3 --> S4 --> S5
    end

    subgraph HTTP["HTTP Transport"]
        H1["subprocess.Popen(server_cmd)"]
        H2["POST /mcp → initialize"]
        H3["POST /mcp → tools/list"]
        H4["POST /mcp → tools/call"]
        H5["mcp-session-id header"]
        H1 --> H2 --> H3 --> H4
        H2 -.-> H5
        H3 -.-> H5
        H4 -.-> H5
    end
```

**Key implementation details:**
- HTTP transport passes dynamically allocated port via `PORT` and `MCP_CFG_PORT` env vars
- `mcp-session-id` from `initialize` response is stored and sent on all subsequent requests
- Instance config options passed as `MCP_CFG_<KEY>` environment variables (not CLI args)
- JSON-RPC IDs are monotonically incrementing per connection

### 3.4 Metrics Collector (`metrics/collector.py`)

```mermaid
erDiagram
    TOOL_CALLS {
        int id PK
        text timestamp
        text agent_session_id
        text instance_id
        text server_id
        text tool_name
        int success "1 or 0"
        real latency_ms
        text error_message "Error class name only"
        int input_size_bytes
        int output_size_bytes
    }

    INSTANCE_EVENTS {
        int id PK
        text timestamp
        text instance_id
        text server_id
        text agent_session_id
        text event_type "started|stopped|error|health_check"
        text details "JSON"
    }
```

**Privacy guarantees:**
- `error_message` stores only the exception class name (e.g., `TimeoutError`), never the full message
- No tool call arguments, results, or content are ever stored
- `export_json()` returns only aggregate data (counts, rates, latencies per server)
- Retention: configurable, default 30 days, auto-cleanup via `cleanup_old_data()`

### 3.5 Credential Store (`credentials/store.py`)

```mermaid
flowchart LR
    subgraph Lookup["Credential Lookup Chain"]
        MEM["MemoryStore<br/>(runtime only)"]
        ENV["EnvironmentStore<br/>(system env vars)"]
        KEY["KeyringStore<br/>(OS keychain)"]
        VAULT["VaultStore<br/>(HashiCorp Vault)"]
    end

    REQ["get_credential(key)"] --> MEM
    MEM -->|"miss"| ENV
    ENV -->|"miss"| KEY
    KEY -->|"miss"| VAULT
    VAULT -->|"miss"| NONE["None"]

    MEM -->|"hit"| RES["Return value"]
    ENV -->|"hit"| RES
    KEY -->|"hit"| RES
    VAULT -->|"hit"| RES

    style MEM fill:#e8ffe8,stroke:#16a34a
    style ENV fill:#e8ffe8,stroke:#16a34a
    style KEY fill:#fff3e0,stroke:#ea580c
    style VAULT fill:#fff3e0,stroke:#ea580c
```

**Current**: MemoryStore + EnvironmentStore via CompositeStore  
**Future**: KeyringStore (OS keychain), VaultStore (HashiCorp Vault / cloud KMS)

### 3.6 Management API (`api/management.py`)

| Method | Path | Purpose |
|--------|------|---------|
| GET | `/api/servers` | List registered servers (with `source`/`exclude_source` filters) |
| POST | `/api/servers` | Register a new server |
| DELETE | `/api/servers/{id}` | Remove a server |
| PATCH | `/api/servers/{id}/toggle` | Enable/disable a server |
| PATCH | `/api/servers/{id}/tools` | Update tool filter (whitelist/blacklist) |
| POST | `/api/servers/import` | Import from mcp.json format |
| GET | `/api/instances` | List active instances |
| POST | `/api/instances` | Create and activate an instance |
| DELETE | `/api/instances/{id}` | Stop an instance |
| GET | `/api/metrics/summary` | Aggregate metrics for dashboard |
| GET | `/api/metrics/calls` | Recent tool calls (with server filter) |
| GET | `/api/status` | System health (CPU, memory, instance count) |
| WS | `/ws` | Real-time events (instance state changes, tool calls, metrics) |

**Security:**
- Binds to `127.0.0.1` only (not `0.0.0.0`)
- Error responses use generic messages; details logged server-side only
- WebSocket clients tracked via set; iteration uses snapshot to prevent mutation errors

---

## 4. OpenAPI Adapter Architecture

```mermaid
flowchart TB
    subgraph Input["Spec Input"]
        URL["URL<br/>https://api.example.com/openapi.json"]
        FILE["File Path<br/>/path/to/spec.yaml"]
        RAW["Raw String<br/>JSON or YAML"]
    end

    subgraph Parser["openapi/parser.py"]
        DETECT["Detect Format<br/>3.x vs Swagger 2.0"]
        EXTRACT["Extract Operations<br/>paths → operations"]
        SCHEMA["Build Schemas<br/>parameters → JSON Schema"]
    end

    subgraph Registry["In-Memory API Registry"]
        APIS["API Name → OpenAPISpec"]
        TOOLS["API Tool → Operation + Schema"]
        AUTH["Auth Config → Scheme + Credentials"]
    end

    subgraph Executor["openapi/executor.py"]
        BUILD["Build HTTP Request<br/>(method, url, headers, body)"]
        SEND["Send via httpx/aiohttp"]
        PARSE_R["Parse Response"]
    end

    Input --> Parser --> Registry
    Registry --> Executor

    style Input fill:#f0f9ff,stroke:#0284c7
    style Parser fill:#f3e8ff,stroke:#7c3aed
    style Registry fill:#e8ffe8,stroke:#16a34a
    style Executor fill:#fff3e0,stroke:#ea580c
```

---

## 5. Enterprise Platform Integration Architecture

```mermaid
sequenceDiagram
    participant Agent as AI Agent
    participant Grid as MCP Grid
    participant TM as Token Manager
    participant WS as WebSocket Adapter
    participant Platform as Enterprise Platform

    Note over Agent,Platform: Connection Phase
    Agent->>Grid: connect_platform(url, jwt)
    Grid->>TM: Store JWT (memory only)
    Grid->>WS: Open WSS connection
    WS->>Platform: WSS + ?Authorization=JWT
    Platform-->>WS: Connected
    WS-->>Grid: Ready
    Grid-->>Agent: Connected

    Note over Agent,Platform: Execution Phase
    Agent->>Grid: execute_workflow(id, query, params)
    Grid->>WS: SendMessageV2 payload
    loop Streaming Response
        Platform-->>WS: answer chunk
        Platform-->>WS: tool_use_request
        Platform-->>WS: tool_use_response
    end
    Platform-->>WS: agent_execution_stats
    WS-->>Grid: Aggregated result
    Grid-->>Agent: Final response + stats

    Note over Agent,Platform: Heartbeat (concurrent)
    loop Every ~27 seconds
        WS->>Platform: {"action": "heartbeat"}
        Platform-->>WS: {"message": "pong"}
    end

    Note over Agent,Platform: Cleanup
    Agent->>Grid: disconnect_platform()
    Grid->>WS: Close connection
    Grid->>TM: Clear all tokens
    Grid-->>Agent: Disconnected
```

See [ENTERPRISE_AI_PLATFORM_INTEGRATION.md](../enterprise/ENTERPRISE_AI_PLATFORM_INTEGRATION.md) for the full protocol specification.

---

## 6. Extension UI Architecture

### Panel Layout

**Sidebar Layout** -- 4 collapsible panels: Servers, Active Instances, Metrics, Marketplace.

![Sidebar Layout](../wireframes/sidebar-layout.svg)

**Dashboard Panel** -- WebView with metrics grid, active instances, registered servers, and recent calls.

![Dashboard Panel](../wireframes/dashboard-panel.svg)

### Add Server Wizard (Webview Panel)

3-tab webview: Manual, OpenAPI/Swagger, WebSocket/Platform.

![Add Server Panel](../wireframes/add-server-panel.svg)

### Marketplace Browser

Full catalog browsing with categories, config options inline, and Install buttons.

![Marketplace Browser](../wireframes/marketplace-browser.svg)

### Configure Server Flow

Step-by-step configuration with summary and activate option.

![Configure Server](../wireframes/configure-server.svg)

---

## 7. Marketplace Delivery Architecture

```mermaid
flowchart LR
    subgraph Private["Private Repo (McpServerStudio)"]
        YAML["catalog/*.yaml"]
        BUILD["build_catalog.py"]
        HTML["marketplace-site/static/"]
        GHA["deploy-marketplace.yml"]
    end

    subgraph Artifact["GitHub Actions Artifact"]
        CATJ["catalog.json"]
        SITE["index.html + assets"]
        MANI["manifest.json<br/>(SHA-256 checksum)"]
    end

    subgraph Public["Public Repo (MCPServerGridStudio)"]
        DEPLOY["deploy-catalog.yml<br/>(repository_dispatch)"]
        PAGES["GitHub Pages<br/>grid.mcpstudio.qabots.diy"]
    end

    subgraph Ext["VS Code Extension"]
        SYNC["CatalogSyncService<br/>(hourly check)"]
    end

    YAML --> BUILD --> CATJ
    HTML --> SITE
    BUILD --> MANI
    GHA -->|"repository_dispatch"| DEPLOY
    CATJ & SITE & MANI --> DEPLOY --> PAGES
    PAGES -->|"manifest.json"| SYNC
    SYNC -->|"checksum changed?"| PAGES

    style Private fill:#f3e8ff,stroke:#7c3aed
    style Public fill:#e8f4f8,stroke:#1a73e8
    style Artifact fill:#fff3e0,stroke:#ea580c
```
