Design perfboard and stripboard layouts, check the wiring and get a link to open them in the editor.
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Changes a project kept here, by a list of ops applied in order: add_part, update_part (move, turn, change value or ref), remove_parts, add_wire (from/to, or a `path` of holes made into one wire per leg), update_wire, remove_wires, set_board, add_cuts / remove_cuts (stripboard), set_pad (a note on a hole). If any op can't be done, none are. Returns what changed, where the pins of added or moved parts landed, and the board checked as validate_project does (with any expectNets remembered for it); when it has no errors, also its nets. get_project returns the whole file. The goal is a board that's right, looks neat and is easy to solder, not just the shortest wires: parts in tidy rows near what they connect to, connectors at the edges, straight wires with few corners and no crossing you can avoid, none over a part's body. Before giving the user the link, look at it (render_board with format "png"), rework what's messy and check it again.
A whole project file to start from instead of a projectId: it's kept here and the reply gives its new projectId.
The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project.
The nets the board should make: each a list of pins written REF.pin, e.g. [["U1.8", "U1.4", "R1.1", "J1.1"], ["U1.2", "U1.6", "C1.+"]]. A pin can also be named by its label ("U1.VCC", "D1.K") or as get_nets writes it ("U1.8 VCC"). List every net of two or more pins: a pin in none of them should connect to nothing. With a projectId it's remembered for that project, so later checks use it too; [] forgets it.
The server marks this tool as destructive. Running it may delete or overwrite data on the server or in any account you connected with your headers.
Tool list last changed Oct 25, 2026.
Changes a project kept here, by a list of ops applied in order: add_part, update_part (move, turn, change value or ref), remove_parts, add_wire (from/to, or a `path` of holes made into one wire per leg), update_wire, remove_wires, set_board, add_cuts / remove_cuts (stripboard), set_pad (a note on a hole). If any op can't be done, none are. Returns what changed, where the pins of added or moved parts landed, and the board checked as validate_project does (with any expectNets remembered for it); when it has no errors, also its nets. get_project returns the whole file. The goal is a board that's right, looks neat and is easy to solder, not just the shortest wires: parts in tidy rows near what they connect to, connectors at the edges, straight wires with few corners and no crossing you can avoid, none over a part's body. Before giving the user the link, look at it (render_board with format "png"), rework what's messy and check it again.
| Argument | Type | Description |
|---|---|---|
| ops* | array | |
| project | any | A whole project file to start from instead of a projectId: it's kept here and the reply gives its new projectId. |
| projectId | string | The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project. |
| expectNets | array | The nets the board should make: each a list of pins written REF.pin, e.g. [["U1.8", "U1.4", "R1.1", "J1.1"], ["U1.2", "U1.6", "C1.+"]]. A pin can also be named by its label ("U1.VCC", "D1.K") or as get_nets writes it ("U1.8 VCC"). List every net of two or more pins: a pin in none of them should connect to nothing. With a projectId it's remembered for that project, so later checks use it too; [] forgets it. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"ops"
],
"properties": {
"ops": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"required": [
"op"
],
"properties": {
"at": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "Other parts: pin 1's hole (a chip's or pin block's top-left pin)."
},
"op": {
"type": "string",
"const": "add_part"
},
"to": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "Two-lead parts: the hole of lead 2."
},
"ref": {
"type": "string",
"description": "Its reference designator. The next free one (R1, R2...) when left out."
},
"chip": {
"type": "object",
"required": [
"name",
"pinsPerSide",
"width"
],
"properties": {
"name": {
"type": "string",
"description": "What it is, e.g. \"LM358\", \"ESP32 DevKit\". Later add_part ops can place more of it by this name."
},
"pins": {
"type": "array",
"items": {
"type": "string"
},
"description": "Pin names in DIP order: pin 1 at the top of the left row (at rotation 0), down the left row, then up the right row, so the last pin is at the top right. \"\" for a pin without a name."
},
"board": {
"type": "boolean",
"description": "true: a dev board or module (drawn as a board, listed under Modules); else a DIP chip."
},
"width": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 2,
"description": "Columns from one pin row to the other, both included: 4 for a narrow (0.3\") DIP, 7 for a wide (0.6\") one; a dev board's row spacing in holes plus one."
},
"pinsPerSide": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 2,
"description": "Pins in each of its two rows."
}
},
"description": "Instead of `part`, a new dual-row chip or dev board of your own, placed by `at` (its top-left pin) and `rotation`."
},
"cols": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Pin blocks (header-pins): pins per row."
},
"from": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "Two-lead parts: the hole of lead 1. On a polarized part get_part's leadLabels say which that is: K for a diode or LED, - for an electrolytic."
},
"part": {
"type": "string",
"description": "The part's id from list_parts (\"resistor\", \"ne555\", \"header-pins\"), or the name of a custom part or chip the project already has. Give this, `custom` or `chip`."
},
"rows": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Pin blocks (header-pins): rows of pins."
},
"color": {
"type": "string",
"description": "Two-lead parts, e.g. an LED's \"#ef4444\"."
},
"value": {
"type": "string",
"description": "E.g. \"10k\", \"100n\"."
},
"custom": {
"type": "object",
"required": [
"name"
],
"properties": {
"cols": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Without shape: the body's width in holes. Default: just wide enough for its pins."
},
"name": {
"type": "string",
"description": "What it is, e.g. \"HC-SR04\", \"BC337\". Later add_part ops can place more of it by this name."
},
"pins": {
"type": "array",
"items": {
"type": "object",
"properties": {
"at": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "Without shape: the pin's hole [column, row] within the body, from its top-left hole. With shape: leave out, the package decides."
},
"label": {
"type": "string",
"description": "Its name, e.g. \"VCC\", \"TRIG\", \"B\". Wire to it by name (\"M1.VCC\")."
}
}
},
"description": "In pin order, pin 1 first; pin 1 is the hole add_part's `at` places it by. Without shape: every pin with its `at`. With shape: just their names, in the package's pin order (get_part gives it), as many as it has pins."
},
"rows": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Without shape: the body's height in holes. Default: just tall enough for its pins."
},
"color": {
"type": "string",
"description": "Without shape: the body's colour, \"#rrggbb\", e.g. a blue module board \"#1d4ed8\"."
},
"shape": {
"type": "string",
"description": "The id of a fixed-pin part from list_parts whose package this part comes in, e.g. \"transistor\" (TO-92) for a BC337 or \"mosfet\" (TO-220) for an IRLZ44N: its pins, outline and look, with this part's name and pin names. Any fixed-pin part but header-pins. Leave out for a body of your own with pins anywhere."
},
"refPrefix": {
"type": "string",
"description": "Letters of its refs: \"Q\" makes Q1, Q2. Default: the package's, else \"M\"."
}
},
"description": "Instead of `part`, a new part of your own for one the catalog doesn't have, placed by `at` and `rotation`."
},
"rotation": {
"anyOf": [
{
"type": "number",
"const": 0
},
{
"type": "number",
"const": 90
},
{
"type": "number",
"const": 180
},
{
"type": "number",
"const": 270
}
],
"description": "Other parts: 0 (default), 90, 180 or 270, clockwise."
}
}
},
{
"type": "object",
"required": [
"op",
"ref"
],
"properties": {
"at": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "A hole, [column, row]."
},
"by": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "Move it by [columns, rows]."
},
"op": {
"type": "string",
"const": "update_part"
},
"to": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "A hole, [column, row]."
},
"ref": {
"type": "string"
},
"cols": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1
},
"from": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "A hole, [column, row]."
},
"rows": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1
},
"color": {
"type": "string",
"description": "\"\" removes it."
},
"value": {
"type": "string",
"description": "\"\" removes it."
},
"newRef": {
"type": "string"
},
"rotation": {
"anyOf": [
{
"type": "number",
"const": 0
},
{
"type": "number",
"const": 90
},
{
"type": "number",
"const": 180
},
{
"type": "number",
"const": 270
}
],
"description": "Turns about `at`; a chip's widthPin and heightPin are swapped to match."
}
}
},
{
"type": "object",
"required": [
"op",
"refs"
],
"properties": {
"op": {
"type": "string",
"const": "remove_parts"
},
"refs": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1
}
}
},
{
"type": "object",
"required": [
"op"
],
"properties": {
"op": {
"type": "string",
"const": "add_wire"
},
"to": {
"anyOf": [
{
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2
},
{
"type": "string"
}
],
"description": "A hole [column, row], or a pin by name: \"U1.7\", \"U1.DISCH\", \"D1.K\", \"R2.1\" (the hole that pin is in)."
},
"via": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "A hole, [column, row]."
},
"description": "With from/to: the holes the wire bends at on its way, in order, to route it around things as one wire. A bend joins nothing, like a hole the wire passes over, so it's soldered only at its two ends."
},
"from": {
"anyOf": [
{
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2
},
{
"type": "string"
}
],
"description": "A hole [column, row], or a pin by name: \"U1.7\", \"U1.DISCH\", \"D1.K\", \"R2.1\" (the hole that pin is in)."
},
"path": {
"type": "array",
"items": {
"anyOf": [
{
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2
},
{
"type": "string"
}
],
"description": "A hole [column, row], or a pin by name: \"U1.7\", \"U1.DISCH\", \"D1.K\", \"R2.1\" (the hole that pin is in)."
},
"minItems": 2,
"description": "Instead of from/to: holes (or pins) to run through in order, made into one wire per leg. Each corner is a wire end, so it joins whatever is in that hole. For corners that only bend, use from/to with via."
},
"color": {
"type": "string"
},
"width": {
"type": "number",
"exclusiveMinimum": 0
},
"solder": {
"type": "boolean",
"description": "true: a solder path instead of a jumper wire, a trail of solder on the copper side, made as one path (a `path`'s corners and any `via` are its bends). Bare solder joins every hole it runs over, ends, bends and all, and every solder path it touches: run it only over holes it should connect. No color or width."
}
}
},
{
"type": "object",
"required": [
"op",
"wire"
],
"properties": {
"op": {
"type": "string",
"const": "update_wire"
},
"to": {
"anyOf": [
{
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2
},
{
"type": "string"
}
],
"description": "A hole [column, row], or a pin by name: \"U1.7\", \"U1.DISCH\", \"D1.K\", \"R2.1\" (the hole that pin is in)."
},
"via": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "A hole, [column, row]."
},
"description": "Its bends, replacing the ones it has; [] makes it straight. Left out, its bends stay."
},
"from": {
"anyOf": [
{
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2
},
{
"type": "string"
}
],
"description": "A hole [column, row], or a pin by name: \"U1.7\", \"U1.DISCH\", \"D1.K\", \"R2.1\" (the hole that pin is in)."
},
"wire": {
"anyOf": [
{
"type": "integer",
"maximum": 9007199254740991,
"minimum": 0
},
{
"type": "array",
"items": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "A hole, [column, row]."
},
"maxItems": 2,
"minItems": 2
}
],
"description": "A wire by its index in wires, or by its two end holes [[c, r], [c, r]] (either way round)."
},
"color": {
"type": "string"
},
"width": {
"type": "number",
"exclusiveMinimum": 0
}
}
},
{
"type": "object",
"required": [
"op",
"wires"
],
"properties": {
"op": {
"type": "string",
"const": "remove_wires"
},
"wires": {
"type": "array",
"items": {
"anyOf": [
{
"type": "integer",
"maximum": 9007199254740991,
"minimum": 0
},
{
"type": "array",
"items": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "A hole, [column, row]."
},
"maxItems": 2,
"minItems": 2
}
],
"description": "A wire by its index in wires, or by its two end holes [[c, r], [c, r]] (either way round)."
},
"minItems": 1,
"description": "Indexes are as they stand before this op, so list several in one op."
}
}
},
{
"type": "object",
"required": [
"op"
],
"properties": {
"op": {
"type": "string",
"const": "set_board"
},
"cols": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1
},
"rows": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1
},
"type": {
"enum": [
"perfboard",
"stripboard"
],
"type": "string"
},
"strips": {
"enum": [
"horizontal",
"vertical"
],
"type": "string",
"description": "A stripboard's strips."
}
}
},
{
"type": "object",
"required": [
"op",
"at"
],
"properties": {
"at": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "A hole, [column, row]."
},
"minItems": 1,
"description": "Stripboard holes to cut the strip at."
},
"op": {
"type": "string",
"const": "add_cuts"
}
}
},
{
"type": "object",
"required": [
"op",
"at"
],
"properties": {
"at": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "A hole, [column, row]."
},
"minItems": 1
},
"op": {
"type": "string",
"const": "remove_cuts"
}
}
},
{
"type": "object",
"required": [
"op",
"at"
],
"properties": {
"at": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "A hole, [column, row]."
},
"op": {
"type": "string",
"const": "set_pad"
},
"note": {
"type": "string",
"description": "A label on the hole, such as \"+9V\", \"GND\" or \"to battery\". Left out (or \"\") removes it."
}
}
}
]
},
"minItems": 1
},
"project": {
"anyOf": [
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
{
"type": "string"
}
],
"description": "A whole project file to start from instead of a projectId: it's kept here and the reply gives its new projectId."
},
"projectId": {
"type": "string",
"description": "The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project."
},
"expectNets": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string"
}
},
"description": "The nets the board should make: each a list of pins written REF.pin, e.g. [[\"U1.8\", \"U1.4\", \"R1.1\", \"J1.1\"], [\"U1.2\", \"U1.6\", \"C1.+\"]]. A pin can also be named by its label (\"U1.VCC\", \"D1.K\") or as get_nets writes it (\"U1.8 VCC\"). List every net of two or more pins: a pin in none of them should connect to nothing. With a projectId it's remembered for that project, so later checks use it too; [] forgets it."
}
}
}Which pins the board connects: every net with its name (from its pins, e.g. GND), its pins ("U1.8 VCC" for a chip's pin, "D1.K" or "C1.+" for a polarized lead, "R1.1" otherwise) and the wires on it (indexes into wires). Also pins connected to nothing, wires that connect no pins, junctions (holes where three or more things are joined) and crossings (where a wire goes over another wire or over a hole without joining it). Wires are insulated jumpers: a wire joins only the holes at its two ends, so crossings are information, not connections or shorts. On a stripboard the strips connect too.
| Argument | Type | Description |
|---|---|---|
| project | any | The whole project file (through version 8), or its JSON text (see perfboard://docs/project-file). Give this or projectId. Preserve instanceId and optional requirements fields. |
| projectId | string | The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"project": {
"anyOf": [
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
{
"type": "string"
}
],
"description": "The whole project file (through version 8), or its JSON text (see perfboard://docs/project-file). Give this or projectId. Preserve instanceId and optional requirements fields."
},
"projectId": {
"type": "string",
"description": "The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project."
}
}
}Everything needed to place parts: for each, which project file list it goes in, its pins (offsets from pin 1 at rotation 0) and pin labels, polarity, value unit, holes its body covers, and an example entry. Ask for every part you use in one call with `ids`.
| Argument | Type | Description |
|---|---|---|
| id | string | One part id, instead of `ids`. |
| ids | array | Part ids from list_parts, e.g. ["resistor", "ne555", "header-pins"]. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"type": "string",
"description": "One part id, instead of `ids`."
},
"ids": {
"type": "array",
"items": {
"type": "string"
},
"description": "Part ids from list_parts, e.g. [\"resistor\", \"ne555\", \"header-pins\"]."
}
}
}Where every placed part's pins land, as [column, row] holes, with pin numbers and labels (e.g. U1 pin 8 VCC), after rotation, plus holes a part's body covers. Use it to route wires to the right holes. The project file doesn't store these: they follow from each part's anchor, rotation and footprint.
| Argument | Type | Description |
|---|---|---|
| refs | array | Only these parts, e.g. ["U1", "R2"]. All parts when omitted. |
| project | any | The whole project file (through version 8), or its JSON text (see perfboard://docs/project-file). Give this or projectId. Preserve instanceId and optional requirements fields. |
| projectId | string | The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"refs": {
"type": "array",
"items": {
"type": "string"
},
"description": "Only these parts, e.g. [\"U1\", \"R2\"]. All parts when omitted."
},
"project": {
"anyOf": [
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
{
"type": "string"
}
],
"description": "The whole project file (through version 8), or its JSON text (see perfboard://docs/project-file). Give this or projectId. Preserve instanceId and optional requirements fields."
},
"projectId": {
"type": "string",
"description": "The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project."
}
}
}The whole project file of a project kept here, as the editor would save it (through version 8, preserving component identities and optional requirements), one entry per line.
| Argument | Type | Description |
|---|---|---|
| projectId* | string |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"projectId"
],
"properties": {
"projectId": {
"type": "string"
}
}
}Lists the parts a project can place. Without a query: every part, grouped by category, as its id with its name and pin count; call it this way once to see what there is. With a query: the parts whose id, name, category or keywords contain all its words, or the closest ones when none do. Each part's `id` is its definitionId in the project file; use get_part for its pins and how to place it.
| Argument | Type | Description |
|---|---|---|
| kind | string | standard-component: two-lead parts placed between two holes. advanced-component: fixed-footprint parts. ic: dual-row chips and modules. |
| query | string | Words to match, e.g. "capacitor", "555", "header", "relay". Leave it out to list every part. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"kind": {
"enum": [
"standard-component",
"advanced-component",
"ic"
],
"type": "string",
"description": "standard-component: two-lead parts placed between two holes. advanced-component: fixed-footprint parts. ic: dual-row chips and modules."
},
"query": {
"type": "string",
"description": "Words to match, e.g. \"capacitor\", \"555\", \"header\", \"relay\". Leave it out to list every part."
}
}
}Turns a project into a link that opens it in Perfboard Designer: the project travels inside the link, so it works without any server. Give the link to the user. Also returns `image`, the address of an SVG picture of the board (as the editor draws it), for showing it where images from links display, e.g. in Markdown (not in Claude or ChatGPT, which don't load them: show_board shows the board there). With store, the project is also stored on the Perfboard Designer server under a short id, and `stored` gives a short link to it, its file and its pictures (SVG and PNG): give the user both links. The project is validated first (against enabled saved requirements and expectNets too, given or remembered for its projectId); a project with errors gets the list of problems instead of a link, unless allowErrors is set.
| Argument | Type | Description |
|---|---|---|
| name | string | The project's name in the editor, e.g. "555 LED blinker". Defaults to the name it was given in new_project or came with from read_share_link. |
| store | boolean | Also store the project at https://projects.perfboarddesigner.com, for a short link. A stored project never changes (store again for a new id) and is deleted after a year unopened. |
| project | any | The whole project file (through version 8), or its JSON text (see perfboard://docs/project-file). Give this or projectId. Preserve instanceId and optional requirements fields. |
| storeAs | string | The id you'd like it stored under, e.g. "led-blinker" (made lowercase letters, digits and dashes); if another board has it, a few characters of this board's hash are added. Implies store. Defaults to the project's name. |
| editorUrl |
Starts a project kept here under a projectId: a blank board, or one of the example projects (perfboard://examples/...) to copy from. Returns the projectId and the project file. Then add parts and wires with edit_project, and pass the projectId to every other tool instead of the whole file.
| Argument | Type | Description |
|---|---|---|
| cols | integer | Holes across. 30 when left out. |
| name | string | The project's name, used by make_share_link. |
| rows | integer | Holes down. 20 when left out. |
| type | string | perfboard (default): a separate pad per hole. stripboard: copper strips joining every hole along each row (or column). |
| strips | string | A stripboard's strips: along rows (horizontal, default) or columns. |
| example | string | Start from an example instead of a blank board: "555-led-blinker" (555 LED blinker (perfboard)), "555-led-blinker-stripboard" (555 LED blinker (stripboard)). |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"cols": {
"type": "integer",
"maximum": 500,
"minimum": 1,
"description": "Holes across. 30 when left out."
},
"name": {
"type": "string",
"description": "The project's name, used by make_share_link."
},
"rows": {
"type": "integer",
"maximum": 500,
"minimum": 1,
"description": "Holes down. 20 when left out."
},
"type": {
"enum": [
"perfboard",
"stripboard"
],
"type": "string",
"description": "perfboard (default): a separate pad per hole. stripboard: copper strips joining every hole along each row (or column)."
},
"strips": {
"enum": [
"horizontal",
"vertical"
],
"type": "string",
"description": "A stripboard's strips: along rows (horizontal, default) or columns."
},
"example": {
"enum": [
"555-led-blinker",
"555-led-blinker-stripboard"
],
"type": "string",
"description": "Start from an example instead of a blank board: \"555-led-blinker\" (555 LED blinker (perfboard)), \"555-led-blinker-stripboard\" (555 LED blinker (stripboard))."
}
}
}Reads the project out of a Perfboard Designer share link (z=, json=, downloaded src=, or a stored short link). Returns a project file through version 8, preserving component identities and optional requirements, kept under the returned projectId: change it with edit_project.
| Argument | Type | Description |
|---|---|---|
| link* | string | The whole link, or just the part after #. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"link"
],
"properties": {
"link": {
"type": "string",
"description": "The whole link, or just the part after #."
}
}
}Draws the board as text, one cell per hole with column and row numbers: each part's pins by a key letter and pin number (a1, a2...), holes under a part's body, wire ends, the holes a wire runs over without joining them, strip cuts and holes with notes. Below it, which part each key is and every wire with its ends and net. Use it to see where there's free space and how wires run before placing parts or routing more. With format "png", a picture of the board as the editor draws it instead, to see how it looks: parts' bodies and where they reach, labels, wire colours. To show the user the board, use show_board.
| Argument | Type | Description |
|---|---|---|
| area | object | Only this part of the board: two opposite corner holes. The whole board when left out. |
| format | string | "text" (default): the board as text. "png": a picture of it, 50 px per hole, scaled down to fit 1000 px. |
| project | any | The whole project file (through version 8), or its JSON text (see perfboard://docs/project-file). Give this or projectId. Preserve instanceId and optional requirements fields. |
| projectId | string | The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"area": {
"type": "object",
"required": [
"from",
"to"
],
"properties": {
"to": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "A hole, [column, row]."
},
"from": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"maxItems": 2,
"minItems": 2,
"description": "A hole, [column, row]."
}
},
"description": "Only this part of the board: two opposite corner holes. The whole board when left out."
},
"format": {
"enum": [
"text",
"png"
],
"type": "string",
"description": "\"text\" (default): the board as text. \"png\": a picture of it, 50 px per hole, scaled down to fit 1000 px."
},
"project": {
"anyOf": [
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
{
"type": "string"
}
],
"description": "The whole project file (through version 8), or its JSON text (see perfboard://docs/project-file). Give this or projectId. Preserve instanceId and optional requirements fields."
},
"projectId": {
"type": "string",
"description": "The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project."
}
}
}Shows the user a picture of the board right in the conversation, as the editor draws it, with a button that opens it in Perfboard Designer. Only in clients that show MCP Apps (e.g. Claude, ChatGPT); elsewhere the user sees nothing, so give them make_share_link's link too. The picture goes to the user, not to you: to look at the board yourself, use render_board.
| Argument | Type | Description |
|---|---|---|
| name | string | The project's name, shown under the picture and in the editor. Defaults to the name it was given in new_project or came with from read_share_link. |
| project | any | The whole project file (through version 8), or its JSON text (see perfboard://docs/project-file). Give this or projectId. Preserve instanceId and optional requirements fields. |
| projectId | string | The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "The project's name, shown under the picture and in the editor. Defaults to the name it was given in new_project or came with from read_share_link."
},
"project": {
"anyOf": [
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
{
"type": "string"
}
],
"description": "The whole project file (through version 8), or its JSON text (see perfboard://docs/project-file). Give this or projectId. Preserve instanceId and optional requirements fields."
},
"projectId": {
"type": "string",
"description": "The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project."
}
}
}Checks a project file and lists every problem with where it is: entries the editor would leave out, unknown parts, pins off the board, two parts' pins or leads in one hole, overlapping parts, wires that connect nothing (a loose end, or no pins on their net), duplicate wires, a two-lead part with both leads on one net (shorted out), a wire passing over a pin or lead without ending there (so not joined to it), IC pins and two-lead parts' leads connected to nothing, supply rails shorted together, and on a stripboard, pins shorted by a strip or sitting in a cut hole. With expectNets, every connection missing from the board or extra on it is an error. Enabled saved requirements also check intended connections, missing components/pins and unused pins; unspecified pins produce an incomplete-coverage warning, not a full match. Wires crossing each other are fine (insulated jumpers) and only listed in notes. Fix all errors before making a link. A project sent whole is kept here: the reply's projectId stands for it in every other tool.
| Argument | Type | Description |
|---|---|---|
| project | any | The whole project file (through version 8), or its JSON text (see perfboard://docs/project-file). Give this or projectId. Preserve instanceId and optional requirements fields. |
| projectId | string | The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project. |
| expectNets | array | The nets the board should make: each a list of pins written REF.pin, e.g. [["U1.8", "U1.4", "R1.1", "J1.1"], ["U1.2", "U1.6", "C1.+"]]. A pin can also be named by its label ("U1.VCC", "D1.K") or as get_nets writes it ("U1.8 VCC"). List every net of two or more pins: a pin in none of them should connect to nothing. With a projectId it's remembered for that project, so later checks use it too; [] forgets it. |
| string |
| The editor's address. Defaults to https://perfboarddesigner.com/app/ (set PERFBOARD_EDITOR_URL in the server's environment to change it); use e.g. http://localhost:3000/app/ for a local copy. |
| projectId | string | The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project. |
| expectNets | array | The nets the board should make: each a list of pins written REF.pin, e.g. [["U1.8", "U1.4", "R1.1", "J1.1"], ["U1.2", "U1.6", "C1.+"]]. A pin can also be named by its label ("U1.VCC", "D1.K") or as get_nets writes it ("U1.8 VCC"). List every net of two or more pins: a pin in none of them should connect to nothing. With a projectId it's remembered for that project, so later checks use it too; [] forgets it. |
| allowErrors | boolean | Make the link even if validation finds errors. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "The project's name in the editor, e.g. \"555 LED blinker\". Defaults to the name it was given in new_project or came with from read_share_link."
},
"store": {
"type": "boolean",
"description": "Also store the project at https://projects.perfboarddesigner.com, for a short link. A stored project never changes (store again for a new id) and is deleted after a year unopened."
},
"project": {
"anyOf": [
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
{
"type": "string"
}
],
"description": "The whole project file (through version 8), or its JSON text (see perfboard://docs/project-file). Give this or projectId. Preserve instanceId and optional requirements fields."
},
"storeAs": {
"type": "string",
"description": "The id you'd like it stored under, e.g. \"led-blinker\" (made lowercase letters, digits and dashes); if another board has it, a few characters of this board's hash are added. Implies store. Defaults to the project's name."
},
"editorUrl": {
"type": "string",
"description": "The editor's address. Defaults to https://perfboarddesigner.com/app/ (set PERFBOARD_EDITOR_URL in the server's environment to change it); use e.g. http://localhost:3000/app/ for a local copy."
},
"projectId": {
"type": "string",
"description": "The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project."
},
"expectNets": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string"
}
},
"description": "The nets the board should make: each a list of pins written REF.pin, e.g. [[\"U1.8\", \"U1.4\", \"R1.1\", \"J1.1\"], [\"U1.2\", \"U1.6\", \"C1.+\"]]. A pin can also be named by its label (\"U1.VCC\", \"D1.K\") or as get_nets writes it (\"U1.8 VCC\"). List every net of two or more pins: a pin in none of them should connect to nothing. With a projectId it's remembered for that project, so later checks use it too; [] forgets it."
},
"allowErrors": {
"type": "boolean",
"description": "Make the link even if validation finds errors."
}
}
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"project": {
"anyOf": [
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
{
"type": "string"
}
],
"description": "The whole project file (through version 8), or its JSON text (see perfboard://docs/project-file). Give this or projectId. Preserve instanceId and optional requirements fields."
},
"projectId": {
"type": "string",
"description": "The id of a project kept here (from new_project, validate_project, edit_project or read_share_link), instead of sending the whole project."
},
"expectNets": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string"
}
},
"description": "The nets the board should make: each a list of pins written REF.pin, e.g. [[\"U1.8\", \"U1.4\", \"R1.1\", \"J1.1\"], [\"U1.2\", \"U1.6\", \"C1.+\"]]. A pin can also be named by its label (\"U1.VCC\", \"D1.K\") or as get_nets writes it (\"U1.8 VCC\"). List every net of two or more pins: a pin in none of them should connect to nothing. With a projectId it's remembered for that project, so later checks use it too; [] forgets it."
}
}
}