siliconsmith-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| --root | No | Root folder for storing projects. Takes precedence over SILICONSMITH_ROOT and CLAUDE_PROJECT_DIR. | |
| SILICONSMITH_ROOT | No | Environment variable for the root folder for storing projects. Used when --root is not provided, and takes precedence over CLAUDE_PROJECT_DIR. | |
| --default-frontend | No | Default frontend for create_project when the frontend argument is omitted. Supported values are amaranth, myhdl, or verilog. | |
| CLAUDE_PROJECT_DIR | No | Project folder set by Claude Code and used as a fallback root when --root and SILICONSMITH_ROOT are not set. | |
| SILICONSMITH_IMAGE | No | Docker toolchain image to use instead of the default Siliconsmith toolchain image. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
Siliconsmith designs small digital chips for Tiny Tapeout with open-source tools. Start with explain('chip-design-loop'). The loop: create_project, write_spec (spec.yaml: clock, pins, requirements R1, R2, ...), write_test (docstring 'Covers: R1'), write_rtl, emit_verilog, then run_tests on icarus and verilator; use waves=True and inspect_waves when a failure is unclear. Once the tests pass, synthesize (real chip gates, size). Call status to see what has passed. Never edit a test to make a design pass; stop after 8 tries. Only the owner approves the spec, on the command line: never try. Use only the tools this server lists. Every project tool takes the project name first. Write whole files, never diffs. Your design is the core module named after the project, using the Tiny Tapeout pins: clk, rst_n (active low), ena, ui_in, uio_in in; uo_out, uio_out, uio_oe out. The tt_um_ wrapper is generated; do not edit it. Bad arguments come back as tool errors that say what to do.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| toolchain_infoA | Check that Docker and the toolchain image work, and report the version of every tool. Call this first if anything else fails with a toolchain error. |
| create_projectA | Create a new chip project folder // shaped like a Tiny Tapeout Verilog project, with a working starter design, a Tiny Tapeout wrapper (tt_um_) and a cocotb test stub. Arguments: name (lowercase letters, digits and underscores, starting with a letter, at most 31 characters; it becomes the Verilog module name), frontend ('amaranth', 'myhdl' or 'verilog'; optional when the server has a default), author (goes into file headers and info.yaml), description (one line), title (optional, defaults to the name). The design you write is the 'core' module named . Its ports use the Tiny Tapeout pin names: clk, rst_n (active low), ena, ui_in[7:0], uio_in[7:0] in; uo_out[7:0], uio_out[7:0], uio_oe[7:0] out. Amaranth and MyHDL projects keep their source in hdl/.py; Verilog projects keep it in src/.v. Every other tool takes the project name as its first argument. |
| list_filesA | List the files in a project (paths relative to the project folder, with sizes in bytes). Symlinks and dotfiles are never listed. Build output (build/, sim_build/) is hidden unless include_build is true. At most 500 files are returned. |
| read_fileA | Read a text file from a project. path is relative to the project folder, for example 'test/test.py' or 'hdl/counter.py'. The text is returned in details.content. Give start_line and end_line (1-based, inclusive) to read part of a file. At most 64 KiB of text is returned per call; when a file is longer the result is cut and next_hints says which lines to ask for next. Binary files are refused. |
| write_rtlA | Write a design source file or a doc, replacing the whole file. Always send the full new content: diffs and patches are not accepted. Allowed paths: hdl//*.py for Amaranth and MyHDL projects (the entry file is hdl/.py); src/.v for Verilog projects; docs//*.md (except the generated docs/verification.md). Tests go through write_test instead. Content must be UTF-8 text of at most 256 KiB. A .py file gets a syntax check (it is never run); the file is saved even when the check fails, and then ok is false with file:line:col and the message. |
| write_testA | Write a cocotb 2.x test file under test/ (test/**/*.py, but not conftest.py), replacing the whole file. Always send the full new content. The starter test is test/test.py. cocotb 2.x idioms: Clock(dut.clk, 10, unit="ns"), int(dut.x.value), cocotb.start_soon. Give each test a docstring line such as 'Covers: R1' naming the requirement ids from spec.yaml. Content must be UTF-8 text of at most 256 KiB. The file gets a syntax check (it is never run here); it is saved even when the check fails, and then ok is false with file:line:col and the message. |
| write_specA | Check and save spec.yaml, the short spec of the chip. It is the only source of the clock, the pin meanings and the requirements, and the owner reads it to judge what you plan to build. Send the full file as YAML text in content; it is saved exactly as you wrote it (comments are kept) only if it is valid, and an invalid file is not saved. Format (version 1; unknown keys are rejected): version: 1 # optional, must be 1 title: "One line name" summary: "What the chip does and why, in plain English." clock_hz: 10000000 # required, integer > 0 (Tiny Tapeout pins manage up to ~66 MHz) tiles: "1x1" # optional, default "1x1"; allowed: 1x1, 1x2, 2x2, 3x2, 3x4, 4x2, 4x4, 5x4, 6x2, 6x4, 8x2, 8x4 reset: "rst_n, active-low, synchronous" # plain English; write 'none' if there is no reset pins: # optional; bit numbers 0-7 as integer keys ui: {0: "enable", 1: "mode"} # inputs ui_in[bit] uo: {0: "count bit 0"} # outputs uo_out[bit] uio: {} # bidirectional uio[bit] requirements: # at least one - id: R1 # R followed by a number, unique: R1, R2, R10 text: "The counter adds 1 each clock while enable is high." limit: {min: 0, typ: 1, max: 2, unit: "V"} # optional; at least one of min/typ/max open_questions: # optional; write your assumptions here - "Assumed 10 MHz; please confirm." Tiles are the chip area rented on Tiny Tapeout, and bigger tiles cost the owner money: keep "1x1" unless the design cannot fit. Never change tiles yourself: ask the owner, or in a headless run with nobody to ask, keep the current tile and write the assumption to open_questions. A bad tiles value lists the allowed ones. After a valid save the tool copies the clock and tiles into src/config.json and info.yaml for you (you cannot edit those files); a clock above 66 MHz is saved with a warning. On errors ok is false and details.errors lists {path, message} (for example pins.ui.8 or requirements[1].id). Fix them and call again. Then write tests whose docstrings say 'Covers: R1' for the requirement ids. |
| emit_verilogA | Turn the project's design into Verilog and check it. For Amaranth and MyHDL this runs your hdl/.py in a container and writes the generated core to src/.v; a Verilog project's src/.v is used as it is. The tool then checks the core's ports against the Tiny Tapeout pins (names, directions, widths), regenerates the tt_um_ wrapper in src/project.v, and lints everything with Verilator (-Wall; latches are errors) and Yosys |
| run_testsA | Run the project's cocotb tests (every test/test*.py) against the design on Icarus Verilog or Verilator. It first does what emit_verilog does (elaborate, check ports, regenerate the wrapper, lint); only if that is ok does it simulate the Tiny Tapeout testbench test/tb.v. ok is true only if at least one test ran (skipped tests do not count) and none failed. The summary names the first failing test, its file:line, the assertion, and expected vs actual. test_filter is a regex that cocotb searches in '.' (for example 'test.test_wraps_at_255$'); a filtered run never counts as a full run. waves=True keeps a wave file under build/waves/ for inspect_waves. details.tests lists every test with outcome and the requirement ids it covers; details.coverage says which spec.yaml requirements have a passing test. The first Verilator run takes about half a minute; later runs reuse the build. gl=True runs the tests at gate level (Icarus only; with Verilator it is an error). The tool first does what synthesize does, with the same checks and the same time limits (a design that fails stops there, and so does one far over the size budget; the summary says gate-level simulation could not run. A design only slightly too big is simulated, with a note), then runs the SAME test files on the resulting sky130 netlist, with the cell models of the chip library (a netlist has no RTL names: a test may only use the pins of tb, such as uo_out, and not internal signals). This catches what RTL simulation cannot: logic that behaves differently once it is real gates, such as a missing reset or an uninitialized flip-flop. The summary's first line says "Gate-level simulation" so it is never mistaken for an RTL run. A gate-level run never changes the RTL results or the RTL wave files: its waves are kept apart in build/waves/icarus-gl/ (inspect_waves reads them). It can take up to 25 minutes in the worst case; a small design takes seconds to a minute. details.gl holds the netlist hash. |
| inspect_wavesA | Show how signals changed in a wave file that run_tests kept (run it with waves=True; the result gives the path, build/waves//tb.fst; a gate-level run, gl=True, keeps its own in build/waves/icarus-gl/tb.fst, where the signal names are those of the sky130 netlist). signals are names like 'uo_out' or 'user_project.uo_out' (a suffix of the full hierarchical name; the match nearest the top wins). start_ns and end_ns limit the time range. The table has one row per time where a requested signal changed: hex for buses, 0/1 for bits, x/z kept. At most max_rows rows come back (default 50, hard limit 1000); a note says how many more there are. details.rows has every returned row as strings. |
| synthesizeA | Turn the design into real chip gates and say how big it is. Synthesis is the step where a program (Yosys) replaces your RTL with the small ready-made logic gates and flip-flops of the sky130 chip library, the same way Tiny Tapeout's own flow does. The tool first runs the same checks as emit_verilog (a lint problem stops it, with file and line), then synthesizes with the clock from spec.yaml recorded as Tiny Tapeout does (this recipe optimizes for small area, so the clock does not change the gates; timing is checked at layout). The summary gives the number of cells (flip-flops, which store bits, and logic gates), the total cell area in um^2, the most used cell types, and the estimated utilization: how much of your tile's usable area the cells would fill. Utilization is an ESTIMATE; real placement (layout, milestone M2) gives the real number, and it needs headroom (above 90% is risky, above 100% will not fit). The tile size comes from |
| statusA | Show the validation sequence for the project: for each step (spec valid, spec approved, Verilog check, simulation on Icarus and on Verilator, requirement coverage, synthesis, and the later milestones) whether it is pass, fail, stale (a file it depends on changed since it ran), not run, or not available. It also writes the same table to docs/verification.md. It reads the ledger that emit_verilog, run_tests and synthesize keep; it never runs a simulation. Approving the spec is the owner's step on the command line; no tool can do it, so do not try. |
| explainA | Explain a topic in plain English from the packaged skills and glossary. topic can be a skill name ('chip-design-loop', 'tt-rules', 'amaranth-style', 'myhdl-style', 'cocotb2-tests': you get the overview and the list of sections), a section heading, a glossary term ('latch', 'slack', 'GDS'), or a few keywords. The best match comes back with up to 4 other suggestions. 'list' or an empty topic returns the catalogue. An unknown topic is not an error; it returns suggestions. The summary is the start of the text; details.text has all of it and details.source says where it came from. Start with explain('chip-design-loop'). |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 13 tools
Most tools target a clearly distinct stage of the chip design loop (spec, RTL, emit, sim, synth, waves, status) and the write_* family is separated by file kind. The main soft spots are emit_verilog vs. synthesize (both run the same lint/check pass) and run_tests(gl=True) vs. synthesize (the gate-level path re-runs synthesis), though the descriptions explicitly clarify the boundaries.
The dominant pattern is verb_noun (create_project, list_files, read_file, write_rtl, write_test, write_spec, emit_verilog, run_tests, inspect_waves), which is predictable. The deviations are bare single words (synthesize, status, explain, toolchain_info) — still unambiguous but not a uniform pattern.
13 tools is comfortably in the well-scoped range, and each maps to a real step (scaffold, edit, verify, synthesize, simulate, inspect, report). No obvious filler or redundant duplicates.
The full design loop is covered: project creation, file read/write, spec validation, Verilog emission and lint, RTL and gate-level simulation, synthesis sizing, wave inspection, and a status/coverage ledger. Minor gaps exist — no delete/rename/move file operation, no build-artifact listing without a flag, and spec approval and layout/PnR are intentionally outside the tool surface.