DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

plaask /

fdtd-mcp

Topic repository only

MCP server for Lumerical FDTD

★ 2 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: master@adcf2dec

FDTD MCP

MCP server for Lumerical FDTD automation. Let AI assistants read, edit, run, and analyze FDTD simulations through the Model Context Protocol.

中文说明

Architecture

AI Assistant --MCP stdio--> server.py (system Python ≥3.10)
                                │ subprocess stdin/stdout
                             bridge.py (Lumerical embed Python 3.6.8)
                                │ lumapi
                             Lumerical FDTD engine

The dual-process design isolates the MCP protocol (which needs modern Python) from the Lumerical API (which only runs on the bundled Python 3.6.8). The bridge communicates via line-delimited JSON over stdin/stdout.

Installation

Prerequisites: Python ≥ 3.10, Lumerical FDTD

1. Install the package

git clone https://github.com/plaask/fdtd-mcp.git && cd fdtd-mcp
pip install .

2. Register with Claude Code

python install.py

This auto-detects your Lumerical installation and prints the registration command (which includes the detected --lumerical-home). Run the printed command, restart Claude Code, done.

If fdtd-mcp is not on your PATH, replace it with python -m fdtd_mcp.server in the printed command.

If auto-detection fails

If Lumerical is installed at a non-standard location, specify the path manually:

Option A — pass it in the registration command:

claude mcp add fdtd -- python -m fdtd_mcp.server --lumerical-home "C:/Program Files/Lumerical/v241"

Option B — set the env var once:

[Environment]::SetEnvironmentVariable("LUMERICAL_HOME", "C:/Program Files/Lumerical/v241", "User")
# Restart the terminal, then just:
claude mcp add fdtd -- python -m fdtd_mcp.server

Other MCP clients (Cursor, VS Code, etc.)

The JSON equivalent of claude mcp add. Auto-detection works here too:

{
  "mcpServers": {
    "fdtd": {
      "command": "python",
      "args": ["-m", "fdtd_mcp.server"]
    }
  }
}

If auto-detection fails, add the --lumerical-home argument:

{
  "mcpServers": {
    "fdtd": {
      "command": "python",
      "args": ["-m", "fdtd_mcp.server", "--lumerical-home", "C:/Program Files/Lumerical/v241"]
    }
  }
}

DeepSeek Harness (DSH)

The MCP server is bridged into DSH through its official plugin @deepseek-ai/dsh-mcp-client (ships with every dsh install). Tools are exposed to DSH as mcp__fdtd__* (e.g. mcp__fdtd__execute, mcp__fdtd__run, mcp__fdtd__model_add; 30 tools total).

Registration steps:

  1. Open the web profile's user patch layer $DSH_HOME/profiles/web/cordis.patch.yml ($DSH_HOME defaults to C:\Users\<you>\.dsh) and append to the top-level array:
- insert:
    - id: mcp-fdtd
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: fdtd
        transport: stdio
        command: D:/coding/anaconda3/python.exe   # ← your Python ≥3.10 (with the mcp package)
        args: ['-m', 'fdtd_mcp.server']
        env:
          PYTHONPATH: D:/project/fdtd-mcp          # ← your checkout; can be removed after pip install .
        cwd: D:/project/fdtd-mcp                   # ← same
        failOnStartupError: false                  # skip tool registration, never block GUI boot
  1. No Lumerical path configuration needed: the server auto-detects it (--lumerical-home arg > LUMERICAL_HOME env var > scanning common install directories, newest version wins). For non-standard installs, change args to ['-m', 'fdtd_mcp.server', '--lumerical-home', '<your-path>'] or set the LUMERICAL_HOME environment variable. Do NOT hardcode a nonexistent LUMERICAL_HOME in the plugin config — the server trusts it without validation and auto-detection would be short-circuited.
  2. The profile patch layer is watched live by DSH, so a restart is usually not needed; if the tools do not appear, restart dsh web.
  3. Verify with dsh web --dump-config — the output should contain the mcp-fdtd row.

For other profiles (e.g. headless), add the same snippet to $DSH_HOME/profiles/<name>/cordis.patch.yml, or to the home-level $DSH_HOME/cordis.patch.yml which applies to every profile. This integration does not affect the Claude Code .mcp.json registration.

Tools (30 tools, 6 modules)

session (5)     session_open, session_new, session_close,
                session_save, session_save_as

model (6)       model_info, model_add, model_get, model_set,
                model_delete, model_script

material (5)    material_add, material_get, material_set,
                material_delete, material_exists

sweep (6)       sweep_add, sweep_get, sweep_set, sweep_delete,
                sweep_run, sweep_result

result (4)      result_list, result_get, result_save, result_has

engine (4)      run, execute, execute_file, reference_lookup

run / sweep_run auto-save an unsaved project to a temp path before solving, so they never block on Lumerical's invisible "Save As" dialog when the engine is run hidden. Note: model variables (addvar) are not available in Lumerical v202 — create them in the GUI, or sweep_add parameter paths like ::model>gap will not resolve.

Module overview

Module Purpose Tools
session Project file lifecycle session_open, session_new, session_close, session_save, session_save_as
model Object tree unified CRUD model_info, model_add, model_get, model_set, model_delete, model_script
material Material database material_add, material_get, material_set, material_delete, material_exists
sweep Parameter sweep lifecycle sweep_add, sweep_get, sweep_set, sweep_delete, sweep_run, sweep_result
result Simulation data result_list, result_get, result_save, result_has
engine Direct engine interaction run, execute, execute_file, reference_lookup

model_add type table

type Lumerical command Category
rectangle, circle, ring, polygon, sphere, pyramid, triangle, waveguide addrect, addcircle, ... Geometry
fdtd addfdtd Solver
mesh addmesh Mesh
dipole, tfsf, plane, gaussian, mode_source adddipole, addtfsf, ... Source
power_monitor, dft_monitor, index_monitor, field_monitor, movie_monitor addpower, adddftmonitor, ... Monitor
structure_group, analysis_group addstructuregroup, addanalysisgroup Group

Usage examples

Open and inspect

session_open("D:/project/my_sim.fsp")
model_info()                           → objects, materials, variables, FDTD summary (one call)
model_get("FDTD")                      → full properties of the FDTD region
model_script("::model", action="get")  → setup + analysis scripts

Build from scratch

session_new(dimension="3D", x_span=2e-6, y_span=2e-6, mesh_accuracy=4)

# Add objects
model_add(type="fdtd")
model_add(type="rectangle", name="substrate",
          properties={"x span": 2e-6, "y span": 2e-6, "z span": 200e-9})
model_add(type="dipole", name="source_1")

# Set properties
model_set("substrate", {"material": "Si (Silicon) - Palik"})
model_set("source_1", {"x": 0, "y": 0, "z": 100e-9, "wavelength start": 500e-9})
session_save("new_sim.fsp")

Custom materials

material_add(type="Sampled 3D data")                      → {name: "material_1"}
material_set("material_1", "name", "PA_RCP")
material_set("material_1", "sampled 3d data",
  [[300e-9, 1.5+0.001i], [800e-9, 1.5+0.001i]])          # Nx2 [wl, n+ik]
material_set("material_1", "mesh order", 2)

# Assign to an object
model_set("substrate", {"material": "PA_RCP"})

# Or import from file
execute('importnk("D:/data/nk_data.txt")')
model_set("substrate", {"material": "nk_data"})

Structure groups and analysis groups

# Create a structure group with script
model_add(type="structure_group", name="dbr_stack")
model_set("dbr_stack", {"x": 0, "y": 0})
model_script("dbr_stack", action="set", script_type="script",
  content="addrect(); set('name', 'layer'); set('x span', 2e-6);")

# Create an analysis group
model_add(type="analysis_group", name="transmission_calc")
model_script("transmission_calc", action="set", script_type="setup",
  content="addpower(); set('name', 'monitor');")
model_script("transmission_calc", action="set", script_type="analysis",
  content="T = transmission('monitor');")

Run and get data

run()
result_has("monitor")                  → check before fetching
result_list("monitor")                 → discover available datasets
result_get("monitor", data="E",
  fields=["Ex", "Ey", "f"])           → get specific fields (fields is REQUIRED)
result_save("monitor", data="E",
  output="C:/data/fields.mat")        → export to .mat file

Parameter sweeps

# Create and run
sweep_add(type=0, name="thickness_sweep",
  parameters=[{"name": "t", "parameter": "::model::substrate::z span",
               "start": 50e-9, "stop": 300e-9, "points": 6}],
  results=[{"name": "T", "result": "::model::monitor::T"}])
sweep_run(name="thickness_sweep")
sweep_result(name="thickness_sweep", result="T")   → get sweep data

Anti-hallucination

reference_lookup(list_only=true)       → verify function names exist
reference_lookup(name="addrect")       → get signature + pitfalls
execute("?getnamed('FDTD', 'dimension')")  → ?expr captures return value

Key design principles

  • Unified CRUD — every module uses consistent add/get/set/delete naming
  • Single-source dispatch — dispatch.json maps every tool to its bridge handler; both processes read the same table, so the two sides can't drift (and a test enforces it)
  • Execute is transparent — execute(code) passes LSF directly to the engine with no parsing
  • model_set handles variables automatically — uses addvar/addanalysisprop/adduserprop based on object type
  • result_get requires fields — call result_list first to discover available fields, then request only what you need
  • Short names resolve — model_get("FDTD") works without the ::model:: prefix

Files

fdtd-mcp/
├── README.md
├── README_zh.md
├── LICENSE
├── pyproject.toml
├── install.py
├── fdtd_mcp/
│   ├── __init__.py
│   ├── discovery.py      # auto-detect Lumerical installation
│   ├── dispatch.json     # single source of truth for tool -> bridge handler
│   ├── bridge.py         # JSON-RPC bridge (Lumerical Python 3.6.8)
│   ├── server.py         # MCP server (system Python)
│   └── cheatsheet/
│       └── lumapi_ref.json  # Lumerical API reference
└── tests/                # pytest suite (no Lumerical needed)

Requirements

  • Python ≥ 3.10
  • Lumerical FDTD (v202 or later)
  • mcp

Timeouts for long-running calls

run, sweep_run, execute, execute_file block until the engine finishes. By default there is no timeout, so legitimate long simulations are never cut short. If you want a bound (e.g. to stop a hung engine freezing the session), set the FDTD_MCP_CALL_TIMEOUT env var in seconds, or pass timeout=<seconds> to a single call. On expiry the bridge is killed and auto-restarted on the next call — note this discards unsaved in-memory engine state, so save your project before running long simulations.

—/ 5

No ratings yet

Manifest verification required

Commit adcf2dec3504

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout