palace-tools
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@palace-tools mesh a microstrip line at 10 GHz, build and lint its config, then estimate RAM at 4 ranks"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
palace-agent-tools
Part of agent.rf — the RF lab: https://benjhardy.github.io/agent-rf/
Tools that let AI coding agents (Claude Code, Codex, Cursor, or a plain script) set up, lint, run, check and post-process AWS Palace finite-element electromagnetic simulations reliably.
Palace is a capable open-source FEM solver, but most mistakes in a Palace model produce a plausible answer and no error: a mesh read in micrometres, a boundary tag that Palace silently ignores, absorbing walls that fake a loss, a solver choice that gives wrong points on some rank counts, S-parameters that are never written. This package turns the lessons from a series of Palace projects (MRI birdcage coil, Wilkinson divider, lumped-filter port tuning, an microstrip AMR study, a GDS-to-Palace benchmark, a mmWave PA) into tools an agent calls with one JSON object and gets one JSON object back:
step | tool | what it does |
geometry, mesh |
| Gmsh OCC parts (boxes, substrates, traces, vias, port rectangles, air box padded in wavelengths), physical-group conventions, wavelength and feature size fields, MSH 2.2 + a |
config |
| Palace JSON from a compact spec with names instead of tag numbers and safe defaults |
lint |
| Palace 0.16 schema validation plus 44 rules from real failures, each with the lesson and its source |
cost |
| peak RAM and wall time (quiet / typical / busy) calibrated on 190 recorded Palace 0.16 runs |
run |
| WSL + Apptainer, Apptainer, Docker or native; refuses to oversubscribe a busy machine or run out of RAM; logs wall time and memory |
results |
| port-S / eig / EPR / Q / energy / AMR / field summaries, Touchstone with the right reference impedances |
check |
| passivity, reciprocity, energy balance, port symmetry, expected eigenmode, log errors, spurious wave-port modes, convergence |
It ships as a Python package with a CLI, an MCP server (stdio) and a Claude Code skill.
Who it is for: RF/microwave and EM engineers who use Palace with an AI agent, and agent builders who want an EM solver step their agent cannot quietly get wrong.
Status: targets Palace 0.16 (the version the rules and cost data come from), with version switches for the behaviour that changed in 0.17 and 0.18. Simulation-only examples; nothing here was measured.
Install
python -m venv .venv
. .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[all]" # numpy + gmsh + scikit-rf + jsonschema; ".[dev]" adds pytestThe core (config, lint, estimate, results, checks) needs only numpy. gmsh is needed for meshing, jsonschema
for schema validation, scikit-rf for Touchstone files. Palace itself is not installed by this package: use
the official container or a native build (see Palace install),
then tell the runner how to call it (PALACE_TOOLS_BACKEND, PALACE_TOOLS_IMAGE, PALACE_TOOLS_CMD,
PALACE_TOOLS_DISTRO; palace-tools doctor shows what it found).
Related MCP server: CST-MCP
Quick start (human)
python examples/cavity_te101/run_example.py --ranks 2 # 10 s: eigenmodes vs analytic TE101 ...
python examples/lumped_port_line/run_example.py --ranks 2 # 1.5 min: lumped ports on an exact TEM line
python examples/microstrip_thru/run_example.py --ranks 2 # 2.5 min: microstrip Z0, eeff vs Hammerstad-JensenOr step by step with the CLI:
palace-tools mesh-template '{"template": "microstrip_line", "out": "case/line", "w": 1.137, "h": 0.508,
"length": 20, "eps_r": 3.55, "side": 4.5, "top": 4.5, "h_mesh": 1.6, "h_edge": 0.12, "ports": "wave", "f_ghz": 10}'
palace-tools build-config @spec.json # {"spec": {...}, "out": "case/config.json"}
palace-tools lint-config '{"config": "case/config.json", "geometry": "case/line.tags.json"}'
palace-tools estimate '{"config": "case/config.json", "tags": "case/line.tags.json", "ranks": 4}'
palace-tools status '{"ranks": 4}'
palace-tools run '{"case_dir": "case", "ranks": 4}'
palace-tools check '{"case_dir": "case", "symmetric_pairs": [[1, 2]]}'
palace-tools results '{"case_dir": "case", "touchstone": "case/line"}'palace-tools list prints every tool. Arguments can come inline, from @file.json, or from stdin (-). Exit
code 1 means the tool reported a problem (ok: false or overall: fail), 2 means bad input.
Quick start (agents)
MCP (any MCP client). The server is dependency-free JSON-RPC over stdio:
claude mcp add palace-tools -- python -m palace_tools.mcp_serveror the repository's .mcp.json. Tools: palace_spec, palace_build_config, palace_lint_config,
palace_lint_rules, palace_gotchas, palace_mesh_template, palace_mesh_report, palace_estimate_cost,
palace_status, palace_run, palace_results, palace_check, palace_doctor. Each has a JSON input schema;
results come back as JSON text and structuredContent.
Claude Code skill. Copy skills/palace-simulation/ into ~/.claude/skills/ (or a project's
.claude/skills/). It teaches the workflow spec -> geometry -> mesh -> config -> lint -> cost estimate -> run
-> check -> report, with the gotchas, recipes, run rules, check meanings and version notes in references/.
Other agents. AGENTS.md has the same workflow and rules in plain form.
The config spec
{"problem": "driven", "mesh": "line.msh", "units": "mm", "tags": "line.tags.json", "order": 2,
"materials": [{"tags": ["substrate"], "eps_r": 3.55, "tan_d": 0.0027}, {"tags": ["air"]}],
"pec": ["ground", "strip"], "pmc": ["ends"],
"lumped_ports": [{"index": 1, "tags": ["port1"], "direction": "+Z", "R": 50},
{"index": 2, "tags": ["port2"], "direction": "+Z", "R": 50}],
"frequency": {"min_ghz": 0.5, "max_ghz": 10, "step_ghz": 0.25, "adaptive_tol": 1e-3}}Also: absorbing, conductivity, impedance (give R, length, width and it sets Rs = R w / l),
lumped_elements (with cut: half-width | half-length for elements split by a symmetry plane), wave_ports,
wave_port_pec, symmetry, eigen, amr, solver, probes, energy_domains, save_fields, and extra
(raw Palace keys merged last). Defaults: MUMPS; a direct factorisation (MGMaxLevels: 1) for eigenmode and
for driven problems up to 600k unknowns; ComplexCoarseSolve; EstimatorMG + EstimatorTol 1e-4 when AMR is
off; Excitation = port index; no ParaView output unless asked. palace-tools spec prints every key.
Examples (Palace 0.16, 8-thread desktop, 2 MPI ranks unless noted)
example | reference | result | size / cost |
| analytic TE/TM resonances; exact dielectric Q | TE101 8.243934 vs 8.243877 GHz (+0.0007 %); first 5 modes within 0.02 %; Q = 1000.00 vs 1000.00 | 17.8k unknowns (order 2), 0.24 GB, 9 s |
| closed-form line S-matrix | max |S - S_ref| = 8.7e-7 over 0.5-10 GHz | 34.5k unknowns, 0.65 GB, 55 s |
| |S11| = 0.2 (-13.979 dB), flat | -13.97940 to -13.97942 dB; also exposes the 0.16 unequal-R bug: |S21|^2 = 2/3 of the delivered power (= R1/R2), flagged by | 23 s |
| Kirschning-Jansen eeff(f) | eeff within 0.4 % over 1-10 GHz; |S11| < -40 dB | 105k unknowns, 2.5 GB, 78 s on 4 ranks (104 s on 2) |
| Hammerstad-Jensen Z0 = 50.0 ohm; Kirschning-Jansen eeff | Z0 49.5 ohm median (48.6-51.7) over 0.5-10 GHz; eeff within 0.25 %; fitted port inductance 143 pH. Single-line extraction without de-embedding: eeff +5.6 %, Z0 40-60 ohm above 5 GHz | 70k + 109k unknowns, 1.5 + 2.4 GB, 45 + 84 s |
Every run passed the passivity, reciprocity, energy-balance, port-symmetry and log checks, except case b,
where the energy check flags the 0.16 bug, as it should. The examples write their summaries to
results*.json next to each script.
Gotchas (what the lint rules encode)
All 44 rules with their full lessons: skills/palace-simulation/references/gotchas.md (generated from the code). The ones that cost the most time:
gotcha | what happened | where it was learned | rule |
| partition-dependent wrong points (S21 ~ -45 dB at 2 of 21 frequencies on 6 ranks) and "singular matrix" aborts; MUMPS identical on any rank count | GDS-to-Palace benchmark | SOL001 |
p-multigrid on an eigenproblem with lumped C | ~1 min per shift-and-invert solve; direct MUMPS ( | birdcage | SOL002 |
default error estimator when AMR is off | half of the run time; | GDS-to-Palace benchmark | SOL003 |
mixed wave and lumped ports | Palace 0.16 writes no | Wilkinson, port tuning | PRT001 |
lumped ports with different R | 0.16 reports |S21|^2 low by R1/R2 (fixed in 0.17: drop the correction after upgrading) |
| PRT011 |
edge lumped port beside an absorbing wall | ~20 % of the port power lost into the wall; PMC end walls are lossless | port tuning | PRT012 |
curved or tilted lumped patch | Palace aborts (projected-length / 1-degree axis check); make patches flat, Direction along an edge | birdcage | PRT009 |
element cut by a symmetry plane | needs C/2 along its width (full C: -7.6 % frequency error), 2C across its length | birdcage | BND004 |
absorbing walls in the near field | 0.03 dB fake loss at 0.2 lambda (Wilkinson); 5 % flat loss and S11 != S22 at 1 mm (benchmark) | Wilkinson, benchmark | BND001 |
wave port smaller than the mode | 3-6 % loss falling with frequency on a bare line; use the whole end face | benchmark | PRT013 |
adaptive sweep in a closed box | aborted after the first sample ("singular matrix", SuperLU); direct points worked | benchmark | BND002 |
adaptive sweep online phase | 2.6 s per frequency per excitation at 258k unknowns: 97 of 128 min | port tuning | DRV003 |
nonconformal AMR with wave ports | the port mode jumped to a spurious mode (n_eff = sqrt(4.4)); conformal refinement fixed it | microstrip-amr | PRT014 |
wave-port de-embedding with lossy conductors | the de-embedded length carries no conductor loss in 0.16 (-0.001 vs -0.30 dB per inch) | microstrip-amr | PRT015 |
AMR size cap | checked after refining: a 450k cap ended at 623k unknowns, 14 GB | microstrip-amr | AMR001 |
several excitations with field output | only the last excitation's ParaView fields are kept (0.16) | Wilkinson | PRT016 |
| the mesh is read in micrometres | Palace docs | MOD001 |
tag typo | Palace prints "Unknown ... boundary attributes! Solver will just ignore them!" and runs on | Palace source | BND005 |
WSL and | WSL kills detached jobs when the last | benchmark, PA | (runner) |
floating port / unresolved via | |S21| ~ -50 dB with no error; S22 = +0.8 dB from one tiny via under a pad | PA, benchmark | ( |
Version-dependent behaviour (0.16 vs 0.17/0.18) is listed in references/version-notes.md.
Cost estimate
palace-tools estimate fits power laws in the number of unknowns to 190 recorded Palace 0.16 runs (eigenmode
and driven, direct and p-multigrid, orders 1-3, 1k to 1.6M unknowns) from the projects above. Anchors: a 1.12 M
unknown order-2 eigenmode solve with MUMPS on 4 ranks used 16.4 GB and 11-19 min (estimate 15.5 GB, 12 min);
a 1.32 M unknown driven sweep with p-multigrid used 10 GB (estimate 10.7 GB). On the recorded runs the median
memory error is 4 % (eigenmode, direct), 10 % (driven, p-multigrid) and 14 % (driven, direct; 80th percentile
41 %). Wall time is only good to 2-3x, because many recorded runs shared the CPU with another job. The estimate is a
go/no-go aid for "ask the user first", not a schedule.
Limits
Rules and cost data come from Palace 0.16 on one 8-thread, 32 GB desktop (WSL2 with 25 GB). Times do not scale with rank count in the model; clusters will differ.
The lint rules catch known failure patterns; they do not prove a model right. Always compare with a reference and refine the mesh once on the figure of merit.
Geometry-aware rules need the
*.tags.jsonfrompalace_tools.mesh; meshes from other tools get the config-only rules.The mesh helpers cover axis-aligned planar RF structures (boxes, traces, vias, rectangular ports) and three templates; complex 3-D CAD should be built with Gmsh directly, using the same group conventions.
The MCP server runs tools synchronously;
palace_runblocks until Palace exits.Not affiliated with AWS or the Palace developers.
Development
pip install -e ".[dev]"
pytest # 67 tests, ~3 s, no Palace needed
python tools/gen_gotchas.py # regenerate the gotchas reference after editing rules
python tools/harvest_costs.py label=<runs folder> ... # add your own finished runs to the cost modelLicence
Apache License 2.0, the same licence as Palace. The vendored Palace config schema
(palace_tools/data/schema_0.16/) is Copyright Amazon.com, Inc. or its affiliates, Apache-2.0; see
NOTICE.
Available Tools
13 toolspalace_build_configA
Build a Palace JSON config from a compact spec (physical-group names, units, ports, sweep) with safe defaults (MUMPS, direct solve for eigen/small driven, cheap estimator, Excitation = Index). Writes it if 'out' is given, and returns lint + schema results.
Inputs: spec (required), out, ram_gb, palace_version.
palace_checkC
Sanity checks: passivity, reciprocity, energy balance (fake wall loss), port symmetry, eigenmode at the expected frequency, log errors, wave-port spurious modes, convergence.
Inputs: config, expect, case_dir, output_dir, +3 more.
palace_doctorC
Which optional modules and Palace backends are available.
Inputs: no named parameters.
palace_estimate_costC
Estimate peak RAM and wall time (quiet/typical/busy) from unknowns or a config + tags file, calibrated on ~200 recorded Palace 0.16 runs.
Inputs: tags, tets, order, ranks, +10 more.
palace_gotchasC
The gotchas list (lint rules plus workflow lessons).
Inputs: no named parameters.
palace_lint_configB
Validate a Palace config against the 0.16 schema and run the lint rules (solver choice, ports, boundaries, units, AMR, sweeps). Pass geometry (the *.tags.json) for distance/patch checks.
Inputs: config (required), spec, ram_gb, geometry, +2 more.
palace_lint_rulesB
List every lint rule with its lesson and source.
Inputs: no named parameters.
palace_mesh_reportB
Quality (minSICN, gamma), tets and exact Nedelec unknowns of a .msh file.
Inputs: mesh (required).
palace_mesh_templateA
Build and mesh a template model with Gmsh: rectangular_cavity(a,b,d,h), parallel_plate_line(w,h,length,eps_r,h_mesh), microstrip_line(w,h,length,eps_r,side,top,h_mesh,h_edge,ports='lumped'|'wave',f_ghz). Writes .msh + .tags.json, returns groups and a mesh report with exact unknowns per order.
Inputs: out (required), template (required).
palace_resultsA
Summarise a Palace output folder (S-parameters, eigenmodes, EPR/Q tables, AMR, fields, log) and optionally write Touchstone with the right per-port reference impedances.
Inputs: z0, config, case_dir, output_dir, +1 more.
palace_runA
Run Palace on case_dir/config (blocks until done). Refuses if another Palace job would be oversubscribed or RAM is short, unless force. Logs palace.log, time.log, run_record.json.
Inputs: case_dir (required), cmd, force, image, +6 more.
palace_specA
Describe the compact config spec accepted by palace_build_config, with an example.
Inputs: no named parameters.
palace_statusB
Running Palace jobs, CPUs and free RAM on the Palace host; progress of a case folder; whether a run with 'ranks' may start now.
Inputs: ranks, distro, backend, case_dir.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 13 tools
Tools mostly target distinct actions (build, lint, mesh, run, results), so selection is usually clear. However, palace_lint_rules and palace_gotchas overlap in content because gotchas includes lint rules plus workflow lessons, which could cause confusion about which to call.
All tools use consistent snake_case with a palace_ prefix and a predictable verb_noun pattern (e.g., palace_build_config, palace_lint_config, palace_mesh_report). Naming is highly coherent and easy to infer.
The 13 tools map cleanly onto the multi-step Palace workflow—config creation, linting, meshing, running, result summary, cost estimation, status, and sanity checks. Each tool appears to earn its place without obvious redundancy.
Core lifecycle coverage from config building through meshing, running, and result summarization is strong, with diagnostic and check tools rounding out the set. Minor gaps exist in case/folder management (e.g., listing, deleting, or comparing runs), but these are workaround-able.
Maintenance
Related MCP Connectors
Safety-first EVM and Bitcoin RPC tools for balances, contracts, blocks, and transactions
Persistent memory, hybrid search and a goal graph for AI agents, over stdio or remote HTTP.
QuLab MCP remote server (Streamable HTTP) for computational science and lab tools.
MCP server (stdio): validate JSON against JSON Schema (draft-07 / 2020-12) via the AgentForge API
Related MCP Servers
AlicenseCqualityBmaintenanceEnables authoring, validating, inspecting, blackbox-inventorying, tracing, and capability-querying SPEC.md documents through MCP tools over stdio JSON-RPC. Each tool wraps the same command modules the CLI uses and returns identical JSON envelopes.9Apache 2.0- AlicenseCqualityCmaintenanceEnables an MCP client to drive CST Studio Suite 2026 through its official Python automation API, covering 3D modelling, materials, ports, boundaries, mesh and solver configuration, solver runs, and result reading. Also provides verification and export tools — S11, reference impedance, port diagnostics, energy budget and model audit — plus Touchstone/ASCII/JSON evidence output and parameter sweeps, all locally over stdio.844MIT
- AlicenseNot gradedqualityBmaintenanceExposes 14 tools that let an agent query charter clauses, route and execute an 8-stage collaboration pipeline, arbitrate conflicts with cited clause IDs, enforce safety gates, run receipt self-checks, deposit and recall memory, solve symbolic anchoring constraints, and mine a 330-entry knowledge base plus semantic-field analysis. It also diagnoses image-generation prompts against a formal feature-cluster grammar, all over a zero-dependency stdio JSON-RPC interface.1MIT
- AlicenseNot gradedqualityNot gradedmaintenanceEnables MCP-compatible clients such as Claude Desktop, Cursor, and Antigravity to invoke deterministic mathematical modeling and System 2 agent capabilities through a native STDIO JSON-RPC 2.0 server with zero external dependencies.MIT