Skip to content

Architecture

github-actions[bot] edited this page Mar 18, 2026 · 20 revisions

Architecture

System Overview

AI Agent (Claude, Cursor, Copilot, etc.)
       │
       │ MCP Protocol (stdio or SSE)
       ▼
┌─────────────────────────────────────┐
│   MCP Server (FastMCP) - server.py   │
│   ├─ Server entry point              │
│   ├─ Tool registration & routing     │
│   ├─ Request context management     │
│   └─ Lifespan management            │
└──────────┬──────────────────────────┘
           │
┌──────────▼──────────────────────────┐
│   Security Validator                 │
│   ├─ Code blocklist scanning        │
│   ├─ Filename sanitization          │
│   └─ Upload size validation         │
└──────────┬──────────────────────────┘
           │
┌──────────▼──────────────────────────┐
│   Session Manager                    │
│   ├─ Per-user session isolation     │
│   ├─ Temp directory management      │
│   └─ Idle session cleanup           │
└──────────┬──────────────────────────┘
           │
┌──────────▼──────────────────────────┐
│   Job Executor                       │
│   ├─ Hybrid sync/async execution    │
│   ├─ Timeout-based promotion        │
│   ├─ Job context injection          │
│   └─ Progress tracking              │
└──────────┬──────────────────────────┘
           │
┌──────────▼──────────────────────────┐
│   Job Tracker                        │
│   ├─ In-memory job storage          │
│   ├─ State management               │
│   └─ Completed job pruning          │
└──────────┬──────────────────────────┘
           │
┌──────────▼──────────────────────────┐
│   Engine Pool Manager                │
│   ├─ Elastic scaling (min→max)      │
│   ├─ Health checks                  │
│   ├─ Proactive warmup               │
│   ├─ Idle scale-down                │
│   └─ Queue management               │
└──────────┬──────────────────────────┘
           │
┌──────────▼──────────────────────────┐
│   Engine Wrapper (Pool)              │
│   ├─ Lifecycle (start/stop)         │
│   ├─ Code execution (sync/async)    │
│   ├─ Workspace reset                │
│   ├─ Health check ping              │
│   └─ State tracking                 │
└──────────┬──────────────────────────┘
           │
┌──────────▼──────────────────────────┐
│   Output Formatter                   │
│   ├─ Text formatting & truncation   │
│   ├─ Variable summarization         │
│   ├─ Figure attachment              │
│   ├─ File listings                  │
│   └─ Response structuring           │
└──────────┬──────────────────────────┘
           │
┌──────────▼──────────────────────────┐
│   MATLAB Engines (2020b+)            │
│   Engine 1 │ Engine 2 │ ... │ N      │
└──────────────────────────────────────┘

Component Details

MCP Server (server.py)

The entry point and orchestrator. Uses FastMCP to handle MCP protocol details. Responsibilities:

  • Server initialization: Creates all subsystems (pool, tracker, executor, sessions, security, formatter)
  • Tool registration: Registers all 20+ built-in tools and custom tools from YAML
  • Request routing: Directs tool calls to implementation modules
  • Session management: Maps stdio/SSE requests to sessions via _get_session_id()
  • Lifespan management: Startup (directory creation, helper paths), shutdown (engine cleanup), and periodic background tasks (health checks, session cleanup)
  • Monitoring integration: Optional metrics collection via MetricsCollector

The server state is encapsulated in MatlabMCPServer class which holds references to all components.

Security Validator (security/validator.py)

Pre-execution security checks:

  • Function blocklist: Scans code for blocked functions (system, unix, dos, !, eval, feval, evalc, evalin, assignin, perl, python). Smart enough to strip string literals and comments first to avoid false positives
  • Filename sanitization: Prevents path traversal in upload filenames
  • Upload size limits: Enforces max_upload_size_mb
  • Metrics collection: Optionally records security events to monitoring system

Session Manager (session/manager.py)

Per-user session isolation:

  • Session creation: Each session gets a unique ID and temp directory
  • Session storage: In-memory dict keyed by session ID (thread-safe with lock)
  • Default session: Single "default" session for stdio transport
  • Workspace isolation: Sessions can be cleared between requests (via workspace_isolation config)
  • Idle cleanup: cleanup_expired() removes sessions idle beyond session_timeout, skipping sessions with active jobs
  • Session properties: Track created_at, last_active, idle_seconds, temp_dir

Job Tracker (jobs/tracker.py)

In-memory store for job metadata:

  • Job creation: create_job() allocates new job with status PENDING
  • Job retrieval: get_job(), list_jobs() for querying
  • Job cancellation: cancel_job() marks job CANCELLED
  • State transitions: get_job() updates last_active timestamp
  • Automatic pruning: prune_completed() removes jobs completed more than job_retention_seconds ago
  • Thread-safe: Uses asyncio locks for concurrent access

Job Executor (jobs/executor.py)

Hybrid sync/async execution orchestration:

  1. Job creation: Creates job in tracker
  2. Engine acquisition: await pool.acquire() gets an available engine
  3. Context injection: Injects __mcp_job_id__, __mcp_temp_dir__ and helper paths into MATLAB workspace
  4. Background execution: Starts code with engine.execute(code, background=True) returning a future
  5. Timeout handling:
    • Waits up to sync_timeout seconds for completion
    • If completes in time → returns result inline with status "completed"
    • If times out → spawns background task, returns job_id with status "pending"
  6. Result building: _build_result() collects text output, variables, figures, files from the engine workspace
  7. Engine release: Returns engine to pool after completion or promotion to async
  8. Error handling: Catches exceptions, marks job failed, releases engine
  9. Metrics: Records job events (created, completed, failed) with timing and output details

Engine Pool Manager (pool/manager.py)

Manages a pool of MATLAB engine instances:

  • Initialization: start() launches min_engines in parallel
  • Engine acquisition: acquire() returns available engine; scales up if needed and under max_engines limit
  • Engine release: release() resets workspace and returns engine to queue
  • Elastic scaling: Automatic scale-up when queue is empty and len(all_engines) < max_engines; scale-down during health checks if idle beyond scale_down_idle_timeout and above min_engines
  • Proactive warmup: Optional feature (via proactive_warmup_threshold) to start new engines before load peak
  • Health checks: run_health_checks() runs periodic 1+1 eval on idle engines; replaces failed engines
  • Queue management: Async queue of available engines; blocks acquirers when all engines busy
  • State tracking: Tracks total engines, available count, busy count
  • Metrics collection: Records scale-up events and health check failures

Engine Wrapper (pool/engine.py)

Wraps a single MATLAB engine instance:

  • Lifecycle: start() launches engine and applies default paths + startup commands; stop() quits engine
  • State machine: STOPPED → STARTING → IDLE ↔ BUSY
  • Execution: execute(code, background, nargout, stdout, stderr) runs code via engine.eval()
  • Workspace reset: reset_workspace() clears all variables, closes files, restores paths, re-runs startup
  • Health checks: health_check() runs trivial 1 eval to confirm responsiveness
  • Idle tracking: idle_seconds property returns time since last marked idle
  • State properties: state, is_alive, idle_seconds

Output Formatter (output/formatter.py)

Structures tool responses:

  • Text formatting: format_text() returns inline text if under max_inline_text_length; truncates and saves to file otherwise
  • Variable formatting: format_variables() summarizes workspace variables with name, type, size, value (or placeholder for large objects)
  • Success response: build_success_response() assembles dict with status, job_id, output, variables, figures, files, warnings, execution_time
  • Error response: build_error_response() builds error dict with error_type, message, matlab_id (if available)
  • Large result handling: Uses large_result_threshold to determine when to show only type/size metadata instead of full value

Plotly Converter (output/plotly_convert.py, output/plotly_style_mapper.py + matlab_helpers/mcp_extract_props.m)

Converts MATLAB figures to interactive Plotly JSON:

  1. MATLAB-side extraction: mcp_extract_props.m extracts raw figure properties (line, scatter, bar, histogram, surface, image, text)
  2. Python-side style mapping: plotly_style_mapper.py converts MATLAB styles (line styles, markers, colormaps, fonts, colors) to Plotly equivalents
  3. WebGL support: Automatically uses WebGL rendering for large datasets (10,000+ points) to improve performance
  4. Result bundling: plotly_convert.py / load_plotly_json() reads extracted JSON and builds response with:
    • Interactive Plotly JSON object
    • Static PNG snapshot
    • Optional thumbnail (small preview image)

Monitoring (monitoring/collector.py)

Optional metrics collection:

  • Event recording: record_event(event_type, data) logs events like job creation, completion, engine scale-up
  • Metrics storage: Collects and aggregates metrics if monitoring is enabled in config
  • Integration points: Connected to pool, executor, tracker, sessions, security modules
  • Conditional: Only active if config.monitoring.enabled = true

Data Flow

Sync Execution

Agent → execute_code("x = magic(3)")
  → Session lookup/creation
  → Security check (OK)
  → Create job in tracker
  → Acquire engine from pool
  → Inject job context (__mcp_job_id__, __mcp_temp_dir__)
  → Engine.execute("x = magic(3)", background=True)
  → Wait for future (< sync_timeout)
  → Future completes in 50ms
  → Build result (text, variables, figures)
  → Release engine to pool (reset workspace)
  → Mark job completed
  → Return result with status="completed"

Async Promotion

Agent → execute_code("long_simulation()")
  → Session lookup/creation
  → Security check (OK)
  → Create job in tracker
  → Acquire engine from pool
  → Inject job context
  → Engine.execute("long_simulation()", background=True)
  → Wait for future (< sync_timeout)
  → 30s timeout exceeded
  → Spawn background task to wait for completion
  → Release engine to pool
  → Return {status: "pending", job_id: "abc123"}
  → Agent polls get_job_status("abc123") → {status: "running", progress: 45%}
  → Agent polls get_job_status("abc123") → {status: "running", progress: 90%}
  → Background task finishes, future completes
  → Build result and store in job
  → Job status becomes "completed"
  → Agent calls get_job_result("abc123")
  → Return full result with status="completed"

Workspace Query Flow

Agent → get_workspace()
  → Session lookup
  → Acquire engine from pool
  → Query workspace variables (who -all)
  → Build variable dict with values
  → Release engine
  → Format variables (truncate large arrays)
  → Return variable list

Transport Modes

stdio (Default)

  • One agent, one session
  • Communication via stdin/stdout
  • Uses fixed "default" session ID
  • Simplest setup, no network
  • All requests use same MATLAB workspace (unless workspace isolation enabled)

SSE (Server-Sent Events)

  • Multiple agents, multiple sessions
  • HTTP-based, supports remote connections
  • Session isolation via session IDs from context (ctx.session_id)
  • Each session owns temp directory and workspace
  • Production: Put behind a reverse proxy with auth (require_proxy_auth: true)
  • Security warning logged at startup if SSE enabled without proxy auth

Component Relationships

Component Depends On Provides
Server FastMCP, all subsystems MCP tool interface
Security Validator Config Code validation
Session Manager Config Session/temp_dir management
Job Tracker Config Job storage & lifecycle
Job Executor Pool, Tracker, Config, Security Code execution
Engine Pool Manager Config, Engine Wrapper Engine acquisition/release
Engine Wrapper matlab.engine Code execution interface
Output Formatter Config, Plotly Converter Response structuring
Plotly Converter MATLAB helpers Figure conversion
Monitoring Config, Collector Event recording

Clone this wiki locally