Skip to content

Commit 106ea05

Browse files
authored
Add 52 PhD-level RF engineering tools, fix connected-mode bugs (#42)
Fix critical bugs, security vulnerabilities, and add tests
2 parents 63233f0 + 6aac263 commit 106ea05

53 files changed

Lines changed: 15470 additions & 564 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version: ["3.10", "3.11", "3.12"]
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Set up Python ${{ matrix.python-version }}
19+
uses: actions/setup-python@v5
20+
with:
21+
python-version: ${{ matrix.python-version }}
22+
23+
- name: Install dependencies
24+
run: pip install -e ".[dev]"
25+
26+
- name: Run tests
27+
run: pytest tests/ -v --tb=short
28+
29+
lint:
30+
runs-on: ubuntu-latest
31+
steps:
32+
- uses: actions/checkout@v4
33+
34+
- name: Set up Python
35+
uses: actions/setup-python@v5
36+
with:
37+
python-version: "3.12"
38+
39+
- name: Install dependencies
40+
run: pip install -e ".[dev]"
41+
42+
- name: Lint with ruff
43+
run: ruff check src/ tests/
44+
45+
typecheck:
46+
runs-on: ubuntu-latest
47+
steps:
48+
- uses: actions/checkout@v4
49+
50+
- name: Set up Python
51+
uses: actions/setup-python@v5
52+
with:
53+
python-version: "3.12"
54+
55+
- name: Install dependencies
56+
run: pip install -e ".[dev]"
57+
58+
- name: Type check with mypy
59+
run: mypy src/mcp_cst_studio/ --ignore-missing-imports
60+
61+
build:
62+
runs-on: ubuntu-latest
63+
steps:
64+
- uses: actions/checkout@v4
65+
66+
- name: Set up Python
67+
uses: actions/setup-python@v5
68+
with:
69+
python-version: "3.12"
70+
71+
- name: Install build tools
72+
run: pip install build
73+
74+
- name: Build package
75+
run: python -m build
76+
77+
- name: Verify wheel
78+
run: pip install dist/*.whl && mcp-cst-studio --help || true

.github/workflows/publish.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
permissions:
8+
id-token: write
9+
10+
jobs:
11+
build:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Set up Python
17+
uses: actions/setup-python@v5
18+
with:
19+
python-version: "3.12"
20+
21+
- name: Install build tools
22+
run: pip install build
23+
24+
- name: Build package
25+
run: python -m build
26+
27+
- name: Publish to PyPI
28+
uses: pypa/gh-action-pypi-publish@release/v1

CLAUDE.md

Lines changed: 90 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,80 @@
33
## Architecture
44

55
- **Dual-mode**: Connected (Windows+CST) and Offline (any OS, generates VBA scripts)
6-
- **VBA Builder pattern**: All VBA generated via `vba_builder.py` — never use raw f-strings
6+
- **VBA Builder pattern**: All VBA generated via `vba_builder.py` — never use raw f-strings for VBA
77
- **Modular tools**: Each `tools/*.py` exports `TOOLS` list + `handle()` function + `register_*_tools()`
8-
- **ToolRegistry**: `tools/__init__.py` collects all tools and wires single `list_tools`/`call_tool` handlers
8+
- **ToolRegistry**: `tools/__init__.py` collects all tools via `_registry.add_module(TOOLS, handle, client)` and wires single `list_tools`/`call_tool` handlers
9+
- **Offline-first**: Server works fully on Linux/macOS. VBA scripts generated for manual execution in CST
910

1011
## Key Files
1112

12-
- `types.py` — Enums and dataclasses (ProjectType, SolverType, etc.)
13-
- `config.py` — Env vars, CST path auto-detection
14-
- `validators.py` — Input validation, VBA injection prevention
15-
- `vba_builder.py` — Safe VBA code generation (builder pattern)
16-
- `cst_client.py` — Session manager (connected/offline modes)
17-
- `server.py` — MCP entry point
18-
- `tools/` — 16 tool modules (~107 tools total)
19-
- `data/` — JSON material databases, antenna templates, VBA reference
20-
21-
## Adding New Tools
22-
23-
1. Add Tool definition to the module's `TOOLS` list
24-
2. Add handler in the module's `handle()` function
25-
3. Use `VBABuilder` for all VBA generation
26-
4. Validate all inputs via `validators.py`
13+
| File | Purpose |
14+
|------|---------|
15+
| `types.py` | Enums and dataclasses (ProjectType, SolverType, MeshType, etc.) |
16+
| `config.py` | Env vars, CST path auto-detection |
17+
| `validators.py` | Input validation, VBA injection prevention |
18+
| `vba_builder.py` | Safe VBA code generation (VBABuilder + VBAScript classes) |
19+
| `cst_client.py` | Session manager (connected/offline modes) |
20+
| `server.py` | MCP entry point, stdio transport |
21+
| `tools/__init__.py` | ToolRegistry aggregator, register_all_tools() |
22+
| `data/` | JSON material databases, antenna templates, VBA reference |
23+
24+
## Tool Categories (~107 tools)
25+
26+
| Module | Tools | Description |
27+
|--------|-------|-------------|
28+
| project.py | 8 | Create, open, save, close, export, status |
29+
| geometry.py | 13 | Brick, cylinder, sphere, cone, torus, extrude, loft, wire, polygon |
30+
| boolean.py | 4 | Add, subtract, intersect, insert |
31+
| transforms.py | 4 | Translate, rotate, mirror, scale |
32+
| materials.py | 8 | Create, load, list, assign, lossy metal, anisotropic |
33+
| ports.py | 7 | Waveguide, discrete, lumped, plane wave, Floquet, list, delete |
34+
| boundaries.py | 4 | Boundary conditions, background, symmetry, frequency range |
35+
| mesh.py | 5 | Mesh type, density, refinement, adaptive, info |
36+
| solvers.py | 5 | Time domain, frequency domain, eigenmode, integral equation, info |
37+
| simulation.py | 6 | Run, run_async, status, pause, resume, stop |
38+
| results.py | 10 | S-params, farfield, field monitor, impedance, VSWR, gain, efficiency |
39+
| import_export.py | 5 | CAD import/export, Touchstone, farfield |
40+
| parameters.py | 6 | Set, get, list, delete, sweep, optimize |
41+
| antenna_templates.py | 13 | Parametric designs: patch, dipole, monopole, horn, Yagi, helix, etc. |
42+
| pcb.py | 6 | Stackup, traces, vias, ground planes, Gerber import |
43+
| vba.py | 3 | Raw VBA execution, help reference, object listing |
44+
45+
## Adding a New Tool
46+
47+
1. Add `Tool()` definition to the module's `TOOLS` list with proper inputSchema
48+
2. Add handler in the module's `handle()` function (inside the try/except)
49+
3. Use `VBABuilder` for all VBA generation — never raw f-strings
50+
4. Validate all inputs via `validators.py` functions
2751
5. Return `list[TextContent]` with JSON response
52+
6. Register in `tools/__init__.py` via `register_*_tools()`
53+
54+
### Adding a New Tool Module
55+
56+
1. Create `tools/new_category.py` with `TOOLS`, `handle()`, and `register_*_tools()`
57+
2. Follow the pattern: try/except in handle(), error format `{"status": "error", "message": "..."}`
58+
3. Import and call `register_*_tools()` in `tools/__init__.py:register_all_tools()`
59+
4. Add tests in `tests/test_tools_new_category.py`
60+
61+
## Error Handling Contract
62+
63+
All `handle()` functions return consistent error format:
64+
```json
65+
{"status": "error", "message": "Human-readable error description"}
66+
```
67+
68+
- Every `handle()` must wrap its body in `try/except Exception as e`
69+
- Internal validation errors (e.g., bad enum value) return the same format
70+
- Never raise exceptions from handle() — always return TextContent with error JSON
71+
72+
## Security Rules
73+
74+
- All VBA passes through `validate_vba_input()` — blocks Shell, CreateObject, file I/O, Declare, SendKeys
75+
- All file paths checked for traversal (`..`) via `validate_file_path()`
76+
- All names restricted to `[A-Za-z_][A-Za-z0-9_ .-]*` via `validate_name()`
77+
- Component paths validated via `validate_component_path()`
78+
- VBA strings escaped via `_escape_vba_string()` — blocks concatenation injection
79+
- No hardcoded paths — everything via env vars or auto-detection
2880

2981
## Testing
3082

@@ -33,14 +85,26 @@ pip install -e ".[dev]"
3385
pytest tests/ -v
3486
```
3587

36-
Tests run in offline mode — no CST installation needed.
88+
Tests run in offline mode — no CST installation needed. The offline client returns `{"status": "offline", "vba": code}` for all execute_vba calls.
3789

38-
## Security Rules
90+
### Test Pattern
91+
```python
92+
@pytest.mark.asyncio
93+
async def test_tool(client: CSTClient):
94+
from mcp_cst_studio.tools.module import handle
95+
result = await handle("cst_tool_name", {args}, client)
96+
data = json.loads(result[0].text)
97+
assert "vba" in data or "status" in data
98+
```
3999

40-
- All VBA passes through `validate_vba_input()` — blocks Shell, CreateObject, file I/O
41-
- All file paths checked for traversal (`..`)
42-
- All names restricted to alphanumeric + underscore + space + dot + hyphen
43-
- No hardcoded paths — everything via env vars or auto-detection
100+
## RF Engineering References
101+
102+
- Patch antenna dimensions: Balanis Ch. 14, Hammerstad-Jensen effective permittivity (Eq. 14-1)
103+
- Microstrip impedance: Wheeler synthesis (narrow/wide strip regimes)
104+
- Stripline impedance: Cohn formula (Z0 = 94.25/sqrt(eps_r) * ...)
105+
- Yagi design: reflector 0.20λ spacing, directors 0.25λ spacing
106+
- Helix gain: Kraus formula (C²NS/λ³)
107+
- Horn gain: aperture efficiency formula
44108

45109
## Build & Run
46110

@@ -50,6 +114,6 @@ mcp-cst-studio # runs stdio server
50114
```
51115

52116
Environment variables:
53-
- `CST_PATH` — CST installation directory
54-
- `CST_WORK_DIR` — Working directory for projects
55-
- `CST_VERSION` — CST version (default: 2026)
117+
- `CST_PATH` — CST installation directory (auto-detected on Windows)
118+
- `CST_WORK_DIR` — Working directory for projects (default: ~/cst_projects)
119+
- `CST_VERSION` — CST version year (default: 2026)

README.md

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,72 @@ Each template calculates dimensions from target frequency and generates a comple
108108
| Vivaldi | Planar | 5-12 dBi | 100%+ |
109109
| IFA/PIFA | Planar | 1-3 dBi | 5-10% |
110110

111+
## Connected Mode Setup (Windows)
112+
113+
To use with a live CST Studio installation:
114+
115+
### Prerequisites
116+
117+
- Windows 10/11 with CST Studio Suite 2024+ installed
118+
- CST Python libraries on your Python path (typically `C:\Program Files\CST Studio Suite 20XX\LinuxAMD64\python_cst_libraries`)
119+
- Python 3.10+
120+
121+
### Setup
122+
123+
```bash
124+
# 1. Clone and install
125+
git clone https://github.com/RFingAdam/mcp-cst-studio.git
126+
cd mcp-cst-studio
127+
pip install -e .
128+
129+
# 2. Set environment (or let auto-detect find CST)
130+
set CST_PATH=C:\Program Files\CST Studio Suite 2026
131+
set CST_WORK_DIR=C:\cst_projects
132+
133+
# 3. Add CST Python libs to PYTHONPATH
134+
set PYTHONPATH=%CST_PATH%\LinuxAMD64\python_cst_libraries;%PYTHONPATH%
135+
136+
# 4. Verify
137+
python -c "import cst.interface; print('CST available')"
138+
mcp-cst-studio # starts stdio server
139+
```
140+
141+
### Claude Code / Claude Desktop
142+
143+
Add to your `.mcp.json` or Claude Desktop config:
144+
145+
```json
146+
{
147+
"mcpServers": {
148+
"cst-studio": {
149+
"command": "mcp-cst-studio",
150+
"env": {
151+
"CST_PATH": "C:\\Program Files\\CST Studio Suite 2026",
152+
"CST_WORK_DIR": "C:\\cst_projects",
153+
"PYTHONPATH": "C:\\Program Files\\CST Studio Suite 2026\\LinuxAMD64\\python_cst_libraries"
154+
}
155+
}
156+
}
157+
}
158+
```
159+
160+
### Validation Checklist
161+
162+
Once connected, verify with these prompts:
163+
164+
1. **Connection**: "What is the CST connection status?" — should show `connected` mode
165+
2. **Geometry**: "Create a brick from (0,0,0) to (10,10,5) in component1" — should appear in CST
166+
3. **Antenna**: "Design a 2.4 GHz patch antenna on FR-4" — should build full model
167+
4. **Simulation**: "Run a time-domain simulation" — should start solver
168+
5. **Results**: "Show me the S-parameters" — should extract S11 data
169+
111170
## Development
112171

113172
```bash
114173
pip install -e ".[dev]"
115-
pytest tests/ -v
174+
pytest tests/ -v # 215 tests, all offline
175+
ruff check src/ tests/ # linting
176+
mypy src/mcp_cst_studio/ # type checking
116177
```
117178

118179
## License

0 commit comments

Comments
 (0)