Skill: pick the engine¶
For: an AI agent deciding which MagicON AI engine answers the question in front of it.
There are four design engines. Choosing the wrong one is the most common and most expensive mistake, because every one of them returns a confident, well-formed result — so a wrong choice does not fail, it succeeds at answering a question nobody asked.
Every path and rate limit below was verified against the production API on
2026-09-09. Base URL https://api.pcbgenerator.com, every route POST,
anonymous, Content-Type: application/json, no Authorization header.
Decide in one table¶
| Your user's question | Engine | Endpoint | Limit |
|---|---|---|---|
| "Design a transmitter / power amplifier chain to N dBm" | design_rf_chain |
/api/rf-chain/design-sync |
5/min |
| "Design a receiver / how sensitive can I get at this frequency" | design_rf_receiver |
/api/receiver/design |
30/min |
| "Design a radar / transceiver / T/R front end that shares one antenna" | design_tr_module |
/api/tr-module/design |
15/min |
| "What is the gain / NF / OIP3 of these stages" | run_link_budget |
/api/link-budget/compute |
120/min |
If two of these look right, the tie-breaker is at the bottom of this page.
The four engines¶
design_rf_chain — a transmit chain¶
POST /api/rf-chain/design-sync — 5 requests/minute. The tightest limit on
the platform; it does the most work.
Picks and cascades VCO → driver → attenuator pads → power amplifier → filtering → isolator → connector → substrate, converges on your output target, and returns a power flow, a power tree, a priced BOM and a power verdict.
curl -X POST https://api.pcbgenerator.com/api/rf-chain/design-sync \
-H "Content-Type: application/json" \
-d '{"params": {"frequency": 2.4, "targetOutputPower": 30, "application": "wifi"}}'
Note the nesting: the design point goes inside params. Frequency is in GHz
here.
⚠ This route enforces no required field, and that is a trap. Measured: {}
returns 200, "status": "success", a selected PA (CG2H40010F) and a 1.0 dBm
output. It answered a design point you did not state, so a 200 from this route
is not evidence that you asked a meaningful question.
The response tells you, if you look: chain.params echoes the design point it
actually used, and on that empty call it reads
{"frequency": null, "target_output_power": 0, "application": null, …}.
Compare chain.params against what you sent before you report anything. On a
real call it echoes your values back —
{"frequency": 2.4, "target_output_power": 30, "application": "wifi", …}.
Two siblings:
| Variant | Endpoint | Limit | Use when |
|---|---|---|---|
| Streaming | /api/rf-chain/design |
5/min | You want progress events. Returns Server-Sent Events, not a JSON body |
| Compare alternatives | /api/rf-chain/design-multi |
30/min | Your user asked for options or trade-offs rather than one answer |
design_rf_receiver — a superheterodyne receiver¶
POST /api/receiver/design — 30 requests/minute.
Picks limiter → LNA → image filter → mixer → local oscillator → IF filter → IF amp → digital step attenuator, plus connector and substrate, then computes the frequency plan, cascade NF, sensitivity, ADC interface and interference products.
curl -X POST https://api.pcbgenerator.com/api/receiver/design \
-H "Content-Type: application/json" \
-d '{"rfFrequencyHz": 9400000000, "bandwidthHz": 10000000, "requiredSnrDb": 12}'
Frequency is in hertz here. Required field: rfFrequencyHz — omit it and you
get 422 {"detail": "rfFrequencyHz is required to choose parts for a receiver"}.
To have the MCP tool check your user's requirements, pass them as targets, e.g.
{"noiseFigure": 3} (a number, or {min, typ, max}). The result then carries a
validation table with a pass, a fail or "not evaluated" for each one. Only send
requirements your user stated: one that is not in their words is dropped and named.
design_tr_module — a shared-antenna front end¶
POST /api/tr-module/design — 15 requests/minute.
Designs a transmit chain and a receive chain and the shared element between them (T/R switch or circulator + limiter), then computes isolation, leakage and stress budgets across the junction.
curl -X POST https://api.pcbgenerator.com/api/tr-module/design \
-H "Content-Type: application/json" \
-d '{"frequencyGhz": 9.4, "targetOutputPowerDbm": 40,
"application": "radar", "transmitDutyCyclePercent": 10}'
Frequency is in gigahertz here. Required: frequencyGhz and
targetOutputPowerDbm.
Reach for this whenever one antenna is shared, even if your user only described one direction. Designing the transmitter and the receiver as two separate calls gives you two chains with nothing joining them — no isolation budget, no leakage budget, no stress check on the part that carries full transmit power, and no shared-path insertion loss. Those budgets are the reason this engine exists. See Design a module.
run_link_budget — cascade maths on stages you already have¶
POST /api/link-budget/compute — 120 requests/minute. The cheapest call
here, by an order of magnitude, and the right one for what-ifs.
Takes an ordered list of stages you supply and returns cascaded gain, Friis noise figure, reciprocal-sum OIP3 and P1dB headroom. It selects nothing.
curl -X POST https://api.pcbgenerator.com/api/link-budget/compute \
-H "Content-Type: application/json" \
-d '{"stages": [{"name": "LNA", "gainDB": 15, "nfDB": 1.2},
{"name": "IF filter", "gainDB": -1.5, "nfDB": 1.5}],
"inputPowerDbm": -80}'
Measured: totalGainDB 13.5, cascadedNfDB 1.2428, finalOutputDbm −66.5.
Required: stages — omit it and you get 422 {"detail": "missing_stages"}.
⚠ The stage keys are gainDB and nfDB — capital DB. Spell them gainDb
/ nfDb and the same request still returns 200, with totalGainDB: 0.0 and
cascadedNfDB: null, because the stages parsed as stages with no figures in them.
Measured, both spellings, on the same two stages. A zero cascade from a chain that
obviously has gain is the signature; check your key casing before you report it.
Use it when your user brought their own parts, when they want to know what one change does, or when you would otherwise burn a 5/min design call to answer "what if the LNA had 2 dB more gain".
⚠ Every number in a link budget is a number you supplied. Nothing in it is grounded in the catalogue, so the result is exactly as good as its inputs. If the stage figures did not come from your user or from a design result you already have, do not present the answer as a computed fact about real hardware.
The compute / design split¶
The receiver and the T/R module each exist twice: a compute-only route that does maths on stages you supply, and a design route that picks catalogue parts first and then computes. This is the most common wrong turn agents take.
| Engine | Compute only | Limit | Picks parts and computes | Limit |
|---|---|---|---|---|
| Receiver | /api/receiver |
60/min | /api/receiver/design |
30/min |
| T/R module | /api/tr-module |
60/min | /api/tr-module/design |
15/min |
| Cascade | /api/link-budget/compute |
120/min | (none — it never selects) | — |
| Transmit chain | (none — it always selects) | — | /api/rf-chain/design-sync |
5/min |
Rule: if your user described an intent ("X-band, 10 MHz bandwidth, 12 dB
SNR"), you have no stages to give, so you want the /design route. If they
described hardware ("here are my four stages"), you want the compute-only route.
⚠ The compute-only routes are cheaper and faster, which makes them tempting. They
are the wrong tool for an intent, and they will not tell you so:
POST /api/receiver refuses without stages (422), but POST /api/tr-module
answers {} with a 200 — an empty question with a confident-looking shape
around it.
Units and names differ per route. Read the field name.¶
| Route | Frequency field | Unit |
|---|---|---|
/api/rf-chain/design-sync |
params.frequency |
GHz |
/api/receiver/design |
rfFrequencyHz |
Hz |
/api/tr-module/design |
frequencyGhz |
GHz |
9400000000 and 9.4 are the same frequency. A route that wanted GHz and got
9400000000 will not correct you.
Tie-breakers¶
- "Design a radar." →
design_tr_module. A radar shares one antenna, and the isolation, leakage and stress budgets are the point. - "Design a transmitter" but they mentioned receiving too. →
design_tr_module. Two independent chains are not a module. - "How good is this receiver?" with parts named. →
run_link_budgetif you have the stage figures;/api/receiverif you have full cascade stages and want the frequency plan and ADC interface too. - "What are my options?" →
compare_rf_chainsover MCP, or/api/rf-chain/design-multi(30/min) over HTTPS, rather than five separate 5/min design calls. - You are iterating on one variable. →
run_link_budgetat 120/min, then one design call to confirm. - You are unsure between two engines. → Ask your user one question. It costs less than a design call and far less than a confident answer to the wrong question.
Over MCP¶
The four engines are the same over the MagicON MCP server
(https://api.pcbgenerator.com/mcp/, no sign-in; see the
MCP guide). The Engine column in the table
above is the MCP tool name. Seventeen tools in all (nine were measured with tools/list
on production; run_ota_link, run_radar_performance and run_planar_filter were
added 2026-10-07, design_patch_antenna and run_glass_weave_analysis 2026-10-08,
lookup_component_by_mpn 2026-10-14, compare_rf_chains 2026-10-17, find_components_by_spec 2026-10-18, and appear there once that backend is deployed):
| Tool | Does |
|---|---|
design_rf_chain |
a transmit chain |
design_rf_receiver |
a superheterodyne receiver |
design_tr_module |
a shared-antenna front end |
run_link_budget |
cascade maths on stages you supply |
run_stackup_solver |
a PCB stackup |
run_thermal_analysis |
thermal, from the design in this session |
run_pdn_analysis |
power delivery, from the design and stackup in this session |
run_compliance_analysis |
standards checks on the solved stackup |
run_ota_link |
a one-way over-the-air link in free space |
run_radar_performance |
radar range equation and pulse limits |
run_planar_filter |
a planar PCB filter; name the laminate, not its Dk |
design_patch_antenna |
a patch antenna or planar array; name the laminate, not its Dk |
run_glass_weave_analysis |
which glass-weave style to use, from the design in this session |
lookup_component_by_mpn |
the catalog's summary of a part's headline figures (not the full datasheet): each figure with its page or "no page on file"; computes nothing |
compare_rf_chains |
ranked transmit-chain alternatives (cost / size / performance) |
find_components_by_spec |
catalog parts of one type that cover a frequency and meet the limits you state, best first, each figure with its page; computes nothing |
check_grounding |
checks your draft text; computes nothing |
The field names differ from the HTTPS routes¶
| Tool | Frequency | Unit | Power |
|---|---|---|---|
design_rf_chain |
frequency — top level, not inside params |
GHz | target_output_power |
design_rf_receiver |
rfFrequencyHz |
Hz | — |
design_tr_module |
frequencyGhz |
GHz | targetOutputPowerDbm |
Copying an HTTPS body into a tool call carries the wrong names over. Read the tool's own schema.
The compute / design split is inside the tools¶
Over HTTPS the receiver and the T/R module each have two routes. Over MCP each is one tool with two paths, and the arguments pick the path:
| Tool | Designs from an intent | Checks hardware your user described |
|---|---|---|
design_rf_receiver |
rfFrequencyHz |
stages[] — only with your user's own stage figures |
design_tr_module |
frequencyGhz + targetOutputPowerDbm |
txPeakPowerDbm + isolationDb |
The HTTPS trap above — POST /api/tr-module answering {} with a 200 — does
not carry over. Measured on production: design_tr_module with no arguments
refuses and names both ways to call it.
Chain the analysis tools, in order¶
Design first, then run_thermal_analysis, run_pdn_analysis and
run_compliance_analysis, with no figures re-sent: the session remembers the
design. PDN and compliance need a solved stackup. After design_rf_chain the
server solves one itself and says so; after a receiver or T/R design, call
run_stackup_solver first. Then pass your write-up to check_grounding before
your user reads it. Design a module has the procedure.
Limits, errors and state¶
- Limits are per calling IP, and exceeding one returns
429. Anything without its own limit falls back to 1000 requests/hour, counted per endpoint URL. 422means your request is missing or has a malformed field. Thedetailnames the field — for example"frequencyGhz is required to design a T/R module". Ask your user for it. Do not invent it.500is our fault. Retry once, then report it. A malformed design point is a422, never a500.- Over HTTPS, nothing persists. No session, no project id, no result to fetch later, and nothing to poll. If a second call needs a figure from the first, carry it yourself. Over MCP, one session remembers the results computed in it — see Over MCP. MCP has its own limit, 30 requests a minute per IP. Connecting and listing tools use about four (five from a client that first asks for a newer protocol version), and each tool call is one more.
Related¶
- Read a design result — what the fields mean once a result arrives.
- Design a module — the end-to-end procedure.
- API reference for LLMs — every public route, including the stackup solver, thermal, PDN, compliance and the component catalogue.
- OpenAPI schema — field-level request and response detail, generated from the running code.