Install
$ agentstack add mcp-dziksu-structsmith ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
StructSmith
Model, document and share software architecture — locally, and with your AI client.
Dark-theme desktop view with consistent ownership colours across the canvas and model tree.
Container view: the canvas, model tree and ownership inspector use the same visual language.
A local-first, open-source tool for modelling software architecture — a self-hosted alternative to Structurizr with a modern React Flow editor and MCP built in, so your AI client works on exactly the same model you do.
> The diagram is not the source of truth. The semantic architecture model is. > React Flow only visualises and lays out that model.
Useful for software architecture, the C4 model, presales, solution architecture, architecture workshops, documenting systems, designing integrations — and for working on architecture together with an AI assistant.
- MIT licensed, no account, no cloud, no telemetry — it works fully offline
- One container, one SQLite file
- REST API, MCP and the UI all sit on the same domain layer
Quick start
Stable releases and automatically generated release notes are available under GitHub Releases. After the first automated release, latest tracks the latest published release; use :vX.Y.Z instead of :latest to pin a specific published version.
Run the public image
With Docker installed, run:
docker run -d --name structsmith \
-p 127.0.0.1:8090:8080 \
-v structsmith-data:/data \
--restart unless-stopped \
ghcr.io/dziksu/structsmith:latest
Then open . No repository clone or local build is needed. Your workspaces persist in the structsmith-data Docker volume.
Build from source with Docker Compose
git clone https://github.com/dziksu/StructSmith.git structsmith
cd structsmith
docker compose up -d --build
Then open .
Local development
git clone https://github.com/dziksu/StructSmith.git structsmith
cd structsmith
bun install --frozen-lockfile
bun run dev
bun run dev starts both processes: the Bun/Express API on :3000 and the Vite dev server on , which proxies /api and /mcp to the backend. The SQLite database is created and migrated automatically — no Docker, Postgres, Redis, Java or Python required for development.
The static project website lives in apps/site. Run it separately on with:
bun run dev:site
bun run build:site creates the GitHub Pages artifact in apps/site/dist. Changes to the site, shared public assets, or its workflow are published automatically from main by the GitHub Pages action. Before the first deployment, select GitHub Actions as the source in the repository's Settings → Pages; later pushes need no manual publishing step. The build prerenders the complete page with React's server renderer and inlines its CSS into index.html; the published page has no client-side React runtime or JavaScript bundle.
Endpoints
| URL | Purpose | | --- | --- | | http://localhost:8090/ | Web UI | | http://localhost:8090/api/... | REST API | | http://localhost:8090/mcp | MCP (Streamable HTTP) | | http://localhost:8090/health | Health check |
In development the same endpoints live on http://localhost:3000 (and :5173 for the UI).
Connecting an AI client (MCP)
MCP is a core feature, not an add-on: it starts with the backend and is served from the same process. The transport is Streamable HTTP (the deprecated SSE transport is not implemented).
Quick install by client
Start StructSmith first, then use the command for your client. The examples assume the public Docker image is available at http://localhost:8090.
Codex CLI, Codex Desktop and the Codex IDE extension share the same MCP configuration:
codex mcp add structsmith --url http://localhost:8090/mcp
In Codex Desktop you can instead open Settings → MCP servers → Add server, choose Streamable HTTP, and paste the endpoint. Restart the current session after changing MCP configuration.
Claude Code:
claude mcp add --transport http structsmith http://localhost:8090/mcp
GitHub Copilot CLI:
copilot mcp add --transport http structsmith http://localhost:8090/mcp
VS Code with GitHub Copilot — add .vscode/mcp.json to the project where you want to use StructSmith:
{
"servers": {
"structsmith": {
"type": "http",
"url": "http://localhost:8090/mcp"
}
}
}
Then run MCP: List Servers and start structsmith; use Copilot Chat in Agent mode.
Claude Desktop needs a local STDIO bridge to reach a StructSmith instance on localhost. See the [AI client installation guide](docs/AI_CLIENTS.md#claude-desktop) for a copy-ready configuration. A public HTTPS deployment can instead be added under Customize → Connectors → Add custom connector, but Claude connects to it from Anthropic's cloud — localhost will not work there.
For Cursor, Windsurf, JetBrains IDEs and other MCP clients, point a native Streamable HTTP connection at the endpoint or use this common configuration shape:
{
"mcpServers": {
"structsmith": {
"type": "http",
"url": "http://localhost:8090/mcp"
}
}
}
For full client-specific instructions, token authentication, local-development ports and troubleshooting, see [Install StructSmith in AI clients](docs/AI_CLIENTS.md). The MCP page in StructSmith also generates copy-ready snippets using the live URL, including custom ports.
Manual Codex configuration
Codex can also load StructSmith automatically from a trusted project's .codex/config.toml:
[mcp_servers.structsmith]
url = "http://localhost:8090/mcp"
default_tools_approval_mode = "writes"
tool_timeout_sec = 120
For clients that only speak stdio:
bun run mcp:stdio
The UI shows the live endpoint, the tool list and the read-only state under MCP in the top bar.
What the AI can do
Tools cover workspaces, the model, elements, relationships, views, view-owned boundaries, presentation settings, saved layout, presales records, snapshots and export. The preferred way to make a larger change is a single call to model_apply_operations, which is atomic, revision-guarded and takes an automatic snapshot first:
- Start with
workspace_list, thenworkspace_inspectfor one complete, validated context packet.
View membership, boundaries and settings are always included; request includeLayouts when coordinates or relationship bend points are needed.
- Call
modeling_guidefor allowed values, C4 rules, relationship lifting and the recommended
workflow instead of reading StructSmith source code.
- Run
model_preview_operationsbefore a large batch. It uses the real operation engine and
validator, then rolls the transaction back.
- Apply the accepted batch with
model_apply_operationsand finish withmodel_validate. - References copied from the UI are one-line
StructSmithRefJSON payloads. Pass their
workspaceId, type and targetId to reference_resolve to fetch the exact object and context.
{
"workspaceId": "example-client-portal",
"label": "Add asynchronous invoice processing",
"operations": [
{ "op": "createElement", "ref": "queue",
"data": { "kind": "container", "role": "queue", "name": "Invoice Queue", "technology": "SQS" } },
{ "op": "createElement", "ref": "worker",
"data": { "kind": "container", "role": "worker", "name": "Invoice Worker" } },
{ "op": "createRelationship",
"data": { "sourceElementId": "backend-api", "targetElementId": "@queue",
"description": "Publishes invoice jobs to", "interactionStyle": "async" } },
{ "op": "createRelationship",
"data": { "sourceElementId": "@queue", "targetElementId": "@worker",
"description": "Delivers jobs to", "interactionStyle": "async" } },
{ "op": "setViewElements", "viewId": "containers-view-id", "elementIds": ["@queue", "@worker"] },
{ "op": "autoLayoutView", "viewId": "containers-view-id",
"direction": "LR", "algorithm": "dagre" }
]
}
ref gives a new entity a local alias; later operations reference it as @alias. The whole batch runs in one SQLite transaction — it either lands completely or not at all.
Boundaries are owned by a view and never become model elements or relationship endpoints. The same element can belong to different boundaries in different views or layers. An element with no boundary in the active layer remains an ordinary item in that view.
Resources expose the model in an AI-friendly shape (no React internals, no CSS, no viewport data):
architecture://guide
architecture://workspaces
architecture://workspace/{workspaceId}
architecture://workspace/{workspaceId}/inspection
architecture://workspace/{workspaceId}/model
architecture://workspace/{workspaceId}/views
architecture://workspace/{workspaceId}/view/{viewId}
architecture://workspace/{workspaceId}/records
Prompt templates: review_architecture, create_presales_architecture, identify_architecture_risks, identify_unknowns, review_security, review_scalability.
When an AI changes the model, the browser is notified over SSE (GET /api/events) and the diagram updates on its own — no refresh needed.
The model
Workspace
├── Elements person · softwareSystem · container · component ·
│ deploymentNode · infrastructureNode · custom
├── Relationships sync · async · event · data · dependency · custom
├── Views landscape · systemContext · container · component ·
│ │ deployment · custom
│ └── Boundaries deployment · security · compliance · ownership · custom
├── Records assumption · risk · unknown · requirement · decision · note
└── Snapshots
StructSmith models itself — this diagram is the container view of the example self-model, exported straight from the tool with export_mermaid:
flowchart LR
architect(["Architect"])
ai_client["AI ClientClaude, Cursor, any MCP client"]
subgraph structsmith["StructSmith"]
direction LR
web_ui["Web UIReact, Vite, React Flow"]
rest_api["REST APIBun, Express"]
mcp_server["MCP ServerMCP SDK, Streamable HTTP"]
domain["Domain Servicesno Express, no SQL"]
event_bus["Event Busin-process, SSE"]
repositories["RepositoriesDrizzle ORM"]
sqlite["SQLiteWAL, bun:sqlite"]
end
architect -->|"Models architecture in"| web_ui
ai_client -->|"Reads and changes the model through"| mcp_server
web_ui -->|"Calls"| rest_api
rest_api -->|"Delegates to"| domain
mcp_server -->|"Delegates to the same layer as REST"| domain
domain -->|"Reads and writes through"| repositories
repositories -->|"Persists to"| sqlite
domain -.->|"Publishes model changes to"| event_bus
event_bus -.->|"Notifies the SSE stream in"| rest_api
rest_api -.->|"Pushes workspace.updated to"| web_ui
Three rules the implementation is built around:
- Positions belong to views, not to elements. One element can appear on five diagrams
without five copies of the data; moving a node never changes the architecture.
- Roles are not C4 levels.
kind = container,role = database,
technology = PostgreSQL — roles drive icons, styling and filtering only.
- Views show implied relationships. If a view shows a system but not its containers,
traffic to those containers is lifted to the system, the way Structurizr does it.
Every workspace has a revision. Mutating REST and MCP calls may pass expectedRevision; a mismatch returns 409 Conflict, so a user and an AI editing at the same time cannot silently overwrite each other.
REST API
GET /api/workspaces POST /api/workspaces
GET /api/workspaces/:id PATCH /api/workspaces/:id
DELETE /api/workspaces/:id POST /api/workspaces/import
GET /api/workspaces/:id/model GET /api/workspaces/:id/document
GET /api/workspaces/:id/validate GET /api/workspaces/:id/activity
GET /api/workspaces/:id/export/mermaid
POST /api/workspaces/:id/commands # atomic batch of operations
POST /api/workspaces/:id/elements PATCH/DELETE /api/elements/:id
GET/POST /api/views/:id/boundaries PATCH/DELETE /api/boundaries/:id
POST /api/workspaces/:id/relationships PATCH/DELETE /api/relationships/:id
GET/POST /api/workspaces/:id/views GET/PATCH/DELETE /api/views/:id
PATCH /api/views/:id/layout # batched, debounced layout write
POST /api/views/:id/elements POST /api/views/:id/auto-layout
GET/POST /api/workspaces/:id/records PATCH/DELETE /api/records/:id
GET/POST /api/workspaces/:id/snapshots POST /api/snapshots/:id/restore
GET /api/events # SSE: workspace.updated
GET /api/mcp-info GET /api/presets GET /api/settings
Errors always use the same envelope:
{ "error": { "code": "WORKSPACE_NOT_FOUND", "message": "...", "details": {} } }
Editor
- Desktop-first three-pane layout: explorer, canvas, inspector — all resizable
- Custom React Flow nodes with icon, name, technology and a kind/role badge; external
elements are visually distinct
- Semantic, nested boundaries owned by a view, so the same model element can be grouped
differently on deployment, security, compliance and ownership diagrams
- Explorer separates the active view tree from the reusable element library; elements can be
added or dragged into a view or one of its boundaries
- Manual layout (debounced batch save) and automatic dagre, force, radial and grid layouts;
compound dagre layout keeps boundary members together
- Views: the same element on many diagrams, each with its own structure, boundaries and layout
- Presales records linked to elements, with a subtle risk indicator on the canvas
- Deterministic validator with error / warning / info levels
- Export: semantic JSON, Mermaid, PNG, SVG. Import: native JSON
- Snapshots with restore; undo/redo (
⌘Z/⌘⇧Z) rides on them - Command palette (
⌘K),Fto fit the view,Delete,Escape - Light / dark / system themes, English and Polish UI
Adding a language
The UI is fully translated through i18next. Drop a JSON file next to apps/web/src/i18n/locales/en.json, register it in apps/web/src/i18n/index.ts and add it to supportedLanguages. No copy is hard-coded in components.
Configuration
| Variable | Default | Meaning | | --- | --- | --- | | PORT | 3000 (8080 in Docker) | HTTP port | | HOST | 0.0.0.0 | Bind address | | DATABASE_PATH | ./data/architecture.db | SQLite file | | MIGRATIONS_DIR | ./migrations | Migration folder | | AUTH_MODE | none | none or token | | APP_TOKEN | – | Bearer token required when AUTH_MODE=token | | MCP_READ_ONLY | false | When true, MCP exposes no mutating tools | | SEED_EXAMPLE | true | Seed the example workspace on first boot | | APP_NAME | StructSmith | Product name shown in the UI |
In token mode, /api and /mcp require Authorization: Bearer ; /health stays public. There is no user system — this is a local/self-hosted tool.
> [!WARNING] > The defaults (AUTH_MODE=none, HOST=0.0.0.0) are meant for localhost. As shipped, > anyone who can reach the port can read and modify every workspace. Before exposing > StructSmith beyond your own machine, set AUTH_MODE=token, put TLS in front of it, and > publish the container port as 127.0.0.1:8090:8080. See [SECURITY.md](SECURITY.md).
Project layout
apps/
web/ React + Vite UI (React Flow, TanStack Router/Query, Zustand, shadcn-style UI)
server/ Bun + Express (REST, MCP transport, SSE, static UI)
docs/ Client setup and
…
## Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [dziksu](https://github.com/dziksu)
- **Source:** [dziksu/StructSmith](https://github.com/dziksu/StructSmith)
- **License:** MIT
- **Homepage:** https://dziksu.github.io/StructSmith/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.