The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Architecture Pattern MCP listing page.
An MCP (Model Context Protocol) server that provides architecture design expertise to AI coding agents. Given a requirements string and a domain, it analyses the problem, selects matching architecture patterns (from 40 built-in patterns), generates a concrete architecture design with components, relationships, API contracts, data models, and event contracts, and evaluates it against quality attributes (maintainability, scalability, reliability, security, performance).
Server starts on streamable-http at http://localhost:8060/mcp (dev compose host port; systemd uses 8050). Then connect your agent below.
Or add to your project for the whole team:
OpenCode uses HTTP transport. Start the server first, then configure opencode:
Note:
GENERATOR_API_KEYis read from the server's config file (~/.config/architecture-pattern-mcp/config.json), not from opencode's environment.
Add to ~/.codex/config.toml:
Or via CLI:
AI coding agents (Claude Code, OpenCode, Codex CLI) can load a SKILL that teaches them how and when to use this server's tools — including timeout-aware entry-point selection, output interpretation, and the full workflow recipe.
The SKILL lives in skills/architecture-pattern-mcp/:
For agents that support file-based skills (OpenCode, Claude Code): point the agent's skill loader at skills/architecture-pattern-mcp/SKILL.md. The skill tells the agent:
requirements, domain, and style as separate structured argumentsfinal_quality_score, attempts > 1, and evaluation.recommendationsdesign_architecture directlyAll tools accept requirements (free text) and domain (e.g. data-processing, microservices, e-commerce) as arguments. The examples below show the exact tool call shape so you can use them in any MCP client or API consumer.
In Claude Code (or any MCP client), paste the natural-language instruction:
Your agent calls design_architecture internally. The server returns a full architecture design: components (Kafka source, JSON parser filter, geolocation enricher, InfluxDB sink, S3 sink), quality attribute scores (scalability: 9.1, maintainability: 8.2, …), and specific recommendations.
Or call tools directly from your agent:
submit_architecture_design_job + get_architecture_design_statusONLY for clients with short request timeouts (Cursor, Claude Desktop, TS-SDK). The default is design_architecture with heartbeat defence. submit_architecture_design_job returns a job_id immediately; poll get_architecture_design_status until done:
In Python (via the MCP HTTP API directly — see examples/architecture_client_async.py):
See examples/architecture_client_async.py for the complete runnable example. Run it with:
Or get details on a specific pattern:
| Tool | Description |
|---|---|
analyze_architecture | Analyse requirements and domain → recommended style, patterns, quality metrics. Long-running (LLM call). Not idempotent. |
generate_architecture | Generate an architecture design from requirements and selected patterns. Long-running (LLM call). Not idempotent. |
evaluate_architecture | Score an existing design against quality attributes. Long-running (LLM call). Not idempotent. |
design_architecture | Default tool for full architecture design (analyse → generate → evaluate → refine, up to 3 attempts). Long-running (5–10 min); use this unless your client has a short request timeout. |
submit_architecture_design_job | Start a background design job and return a job_id immediately. ONLY for clients with short request timeouts (Cursor, Claude Desktop, TS-SDK). For other clients use design_architecture. Poll get_architecture_design_status every 10–30 s. |
get_architecture_design_status | Poll job status. Returns the current status, progress message, and the full design output when completed. |
cancel_architecture_design | Cancel a running job (best-effort; takes effect at the next pipeline stage boundary; may take up to one LLM call). |
list_architecture_patterns | List all 40 patterns; filter by category and/or domain |
get_architecture_pattern | Get full JSON for a specific pattern by name |
Domain and Style are structured parameters — pass them as separate tool arguments, not embedded in the requirements text.
Example prompts:
This server also exposes four user-invoked workflow prompts (slash commands in MCP clients). Unlike tools, the LLM does not autonomously invoke prompts — the user selects one and fills in its arguments. Each prompt encodes a tested tool-orchestration recipe.
| Prompt | Args | What it does |
|---|---|---|
/design_architecture_workflow | requirements* | Full analyze → generate → evaluate pipeline |
/explore_pattern_catalog | domain, category | Live catalog discovery with embedded pattern names |
/evaluate_my_architecture | focus | Guide evaluation criteria + finding prioritisation |
/compare_architecture_styles | style_a*, style_b*, requirements* | Two designs side-by-side; ~2× token cost |
* = required argument
Clients that only support the tools protocol (no native prompts/list or prompts/get) can access all four workflow prompts via the generated list_prompts and get_prompt tools, which route through the server's middleware chain exactly as native prompt calls do.
Valid category values: messaging, structural, cloud, data, ai_cognitive, specialized, api_gateway, coordination, dataflow, presentation.
Each pattern includes: name, category, context, benefits, tradeoffs, quality_attributes (scalability/maintainability/reliability/security/performance/simplicity, scores 1–10), suitable_domains, component_types, technology_stack, design_principles, best_practices.
Prerequisites: Python 3.12+, uv
Or use the installed console script (after make install):
The TEI embedder (Qwen3-Embedding-0.6B) is required for domain-scoped pattern retrieval. Without it, the server falls back to the default pattern. Docker compose starts it automatically; local users must run it separately on port 8080.
The retrieval indexes (FAISS + BM25) are built at server startup so a misconfigured or unreachable TEI sidecar prevents startup (fail-fast) rather than breaking the user's first design request. Docker compose's service_healthy dependency ordering guarantees TEI is ready before the app starts.
The server reads ~/.config/architecture-pattern-mcp/config.json (override with --config-path):
{env:VAR:-default} syntax expands environment variables at load time.
The generator LLM is accessed through the LlamaIndex LiteLLM integration (llama-index-llms-litellm). All provider settings therefore follow LiteLLM's model syntax: <provider>/<model> (e.g. openai/gpt-4o-mini, anthropic/claude-sonnet-4-5, openrouter/minimax/minimax-m2).
The server composes the LiteLLM model string from your configuration as generator.provider + generator.config.model:
| Config / env | Example | Resulting LiteLLM model string |
|---|---|---|
provider: "openai", model: "gpt-4o-mini" | GENERATOR_PROVIDER=openai, GENERATOR_MODEL=gpt-4o-mini | openai/gpt-4o-mini |
provider: "anthropic", model: "claude-sonnet-4-5" | GENERATOR_PROVIDER=anthropic, GENERATOR_MODEL=claude-sonnet-4-5 | anthropic/claude-sonnet-4-5 |
provider: "openrouter", model: "minimax/minimax-m2" | GENERATOR_PROVIDER=openrouter, GENERATOR_MODEL=minimax/minimax-m2 | openrouter/minimax/minimax-m2 |
If the configured model already contains a provider prefix (e.g. openai/gpt-4o-mini), that prefix is stripped and replaced by the configured provider.
<provider>/<model> syntax: LiteLLM Providers documentationGENERATOR_BASE_URL (generator.config.base_url) — it is passed as the LiteLLM api_baseGENERATOR_API_KEY is passed as the LiteLLM api_key; temperature, top_p, top_k, and stream map to the corresponding LiteLLM parameters| Variable | Default | Description |
|---|---|---|
GENERATOR_API_KEY | (required) | API key for your LLM provider (passed to LiteLLM as api_key) |
GENERATOR_PROVIDER | openai | LiteLLM provider prefix: openai, anthropic, openrouter, … — see LiteLLM Providers |
GENERATOR_BASE_URL | https://api.openai.com/v1 | API base URL (passed to LiteLLM as api_base) |
GENERATOR_MODEL | gpt-4o-mini | Model name; final model string is <GENERATOR_PROVIDER>/<GENERATOR_MODEL> (LiteLLM syntax) |
GENERATOR_TEMPERATURE | 0.1 | Sampling temperature |
GENERATOR_TOP_P | 1.0 | Top-p sampling |
GENERATOR_TOP_K | 20 | Top-k sampling |
GENERATOR_STREAM | false | Enable streaming responses |
EMBEDDER_PROVIDER | tei | Embedder provider |
EMBEDDER_BASE_URL | http://127.0.0.1:8080 | TEI embedder URL |
EMBEDDER_BATCH_SIZE | 16 | Embedding batch size |
EMBEDDER_QUERY_INSTRUCTION | (empty) | Query instruction prefix |
EMBEDDER_TEXT_INSTRUCTION | (empty) | Text instruction prefix |
RETRIEVAL_BM25_TOP_K | 0 | BM25 stage-1 recall cap (0=full corpus) |
RETRIEVAL_DENSE_TOP_K | 0 | Dense stage-1 recall cap (0=full corpus) |
RETRIEVAL_DENSE_WEIGHT | 0.7 | Stage-1 fusion leg weight on the dense leg. Pairs with RETRIEVAL_BM25_WEIGHT; both must be > 0 and sum to 1.0 (±1e-3, startup validation). Either weight < 0.05 logs a startup warning. Distinct from the Stage-2 selection blend weights (RETRIEVAL_ANALYSIS_BLEND_WEIGHT / RETRIEVAL_FUSION_BLEND_WEIGHT). Note: config keys unknown to an older image fail fast at startup. |
RETRIEVAL_BM25_WEIGHT | 0.3 | Stage-1 fusion leg weight on the BM25 leg. See RETRIEVAL_DENSE_WEIGHT. |
RETRIEVAL_TOP_K_PATTERNS | 5 | Number of patterns to select |
RETRIEVAL_MIN_FUSION_SCORE | 0.0 | Relevance floor on the rank_fusion blend value (range [0, 2/60] ≈ [0, 0.033]). Default 0.0 (gate disabled). Values above the blend maximum are rejected at startup. |
RETRIEVAL_RERANK_TOP_N | 10 | Rerank top N (slug-cut after CE) |
RETRIEVAL_USE_LEAN_WIRE_SCHEMA | false | Use lean response schema |
RETRIEVAL_STYLE_SCORE_THRESHOLD | 50.0 | Min analysis score for style recommendation |
REASONING_ENABLED | true | Server-side reasoning MCP integration (see Structured Reasoning) |
REASONING_SPAWN_TIMEOUT_SECONDS | 10 | Subprocess spawn timeout per reasoning tool |
REASONING_STEP_TIMEOUT_SECONDS | 20 | Per-thought tool-call timeout |
REASONING_MAX_TOTAL_STEPS | 8 | Hard cap on reasoning steps per phase |
REASONING_QUIET_STDERR | true | Silence reasoning-subprocess stderr (ASCII progress boxes, [info] banners); set false to debug spawn failures |
REASONING_FAIL_FAST | true | Fail server startup when a reasoning tool is unreachable |
REASONING_SHANNONTHINKING_CMD | (embedded) | JSON list command for shannonthinking (e.g. ["npx","-y","server-shannon-thinking@latest"]) |
REASONING_CODE_REASONING_CMD | (embedded) | JSON list command for code-reasoning |
RETRIEVAL_ANALYSIS_BLEND_WEIGHT | 0.7 | Weight on analysis score in blend |
RETRIEVAL_FUSION_BLEND_WEIGHT | 0.3 | Weight on fusion score in blend |
RETRIEVAL_WEIGHT_SMOOTHING_ALPHA | 0.7 | Weight smoothing alpha |
RETRIEVAL_VERBOSE_TIMING | false | Log phase timings at INFO level |
RETRIEVAL_MAX_TRIES | 3 | Max design loop attempts |
RETRIEVAL_MIN_QUALITY_SCORE | 50.0 | Early-stop quality threshold |
RERANKER_BASE_URL | (default reranker URL) | TEI reranker endpoint (host:port); model is fixed to gte-reranker-modernbert-base |
RERANKER_TIMEOUT | 30.0 | Reranker timeout (seconds) |
RERANKER_MAX_BATCH_SIZE | 48 | Max texts per TEI /rerank request; must be ≤ min(MAX_CLIENT_BATCH_SIZE, MAX_CONCURRENT_REQUESTS) of the reranker sidecar. HybridPatternRetriever chunks large pools automatically. |
PATTERN_DIRECTORY | ~/.config/architecture-pattern-mcp/pattern | Pattern files directory |
VALIDATION_MAX_RETRIES | 2 | Max self-healing retry attempts |
VALIDATION_RETRY_ON_FAIL | true | Retry on validation failure |
Before each LLM phase call (ANALYZE / GENERATE / EVALUATE / RETRY), the server
optionally runs a bounded ThoughtGenerator loop: it authors each reasoning
step with the generator's own LLM (LlamaIndex LiteLLM; one completion per
step) and submits it to the
shannonthinking and/or
code-reasoning MCP servers —
structured thinking scratchpads that validate, number, and record each step.
The resulting trace is injected into the phase prompt as a
<reasoning_context> block. Contract: each thought = 1 LLM completion + 1
MCP tool call, capped by REASONING_MAX_TOTAL_STEPS (default 8).
Key properties:
build-mcps stage bakes both npm packages
(server-shannon-thinking@0.1.1, @mettamatt/code-reasoning@0.8.1) into
the image at /usr/local/lib/node_modules/...; the runtime invokes them
directly via node (no network, no npx).npx -y <pkg> (first call downloads).keep_alive=False); nothing persists between calls.REASONING_FAIL_FAST=true to make startup fail instead.Local (non-Docker) development needs Node.js; either install the packages
globally (npm install -g server-shannon-thinking @mettamatt/code-reasoning)
or let the npx fallback download them on first use.
Latency note: expect roughly +1–6 s per reasoning step. Worst case adds a couple of minutes per design run; the trace cache keeps typical overhead well below that.
Set LOGGING_LEVEL=DEBUG to capture the authored thought and tool response
for every per-step reasoning call. Docker/systemd stacks default to INFO;
export LOGGING_LEVEL=DEBUG before make docker-up.
| ARCHITECTURE_PATTERN_JOBS_DB | ~/.config/architecture-pattern-mcp/jobs.db | SQLite path for async job trio. Override for test isolation |
| TASKS_HEARTBEAT_ENABLED | true | Emit progress notifications during long tool calls |
| TASKS_HEARTBEAT_INTERVAL_SECONDS | 30 | Heartbeat interval in seconds (keep below client idle timeout) |
| TRANSPORT | streamable-http | Transport mode: stdio, streamable-http |
| HOST | 0.0.0.0 | HTTP bind host |
| PORT | 8050 | HTTP bind port |
| LOGGING_LEVEL | INFO | Logging level |
| LOGGING_FORMAT | json | Logging format: json, text |
| CONFIG_PATH | ~/.config/architecture-pattern-mcp/config.json | Config file path |
| Flag | Description |
|---|---|
--transport {stdio,streamable-http} | Override transport mode |
--host | Override HTTP bind host (default: 0.0.0.0) |
--port | Override HTTP port (default: 8050) |
--config-path | Path to config file |
--health | Run health check and exit |
Pattern files are loaded from ~/.config/architecture-pattern-mcp/pattern/ (configurable via PATTERN_DIRECTORY). Drop a JSON file alongside the 40 built-in patterns.
Minimal pattern structure:
Required fields: category, name, context, benefits, tradeoffs, quality_attributes.
Valid category values: messaging, structural, cloud, data, ai_cognitive, specialized, api_gateway, coordination, dataflow, presentation.
Full JSON Schema with all enums: docs/pattern-schema.json
design_architecture (and to a lesser extent analyze_architecture, generate_architecture, evaluate_architecture) run multi-stage LLM pipelines that can take 5–10 minutes per call. This is inherent to the workload, not a bug: the generator LLM must process a large input payload — the selected pattern definitions from the 36-pattern catalog, your requirements, and the full output of every previous stage — and produce a large, strictly structured JSON document (components, relationships, API contracts, data models, event contracts, quality scores) one token at a time. The design_architecture pipeline repeats generate → evaluate up to three times, so a single call can comprise 9+ LLM round trips.
MCP clients (AI coding agents, MCP SDKs) sit between the server and the LLM. Many of them implement a client-side idle timeout: if no data is received on the HTTP connection for some period (typically 30–120 seconds), the client aborts the request. The server is still working — the LLM is still generating — but the client closes the connection and reports a timeout error to the agent.
This is a client-side behaviour, not a server-side one. The server processes the full request correctly; the client simply gives up before the response arrives.
Affected clients (hardcoded short timeouts):
| Client | Timeout | Notes |
|---|---|---|
| Claude Desktop (TS-SDK) | 60 s | Hardcoded; does not reset on progress notifications |
| Cursor (TS-SDK) | 60 s | Same as Claude Desktop |
| Other TS-SDK based agents | varies | Most cap at 60–120 s |
These clients cannot be reconfigured to accept longer timeouts — the timeout is baked into the SDK.
Clients covered by the heartbeat defence:
| Client | Timeout | Defence |
|---|---|---|
| Claude Code | ~300 s | Heartbeat every 30 s resets idle timer |
| OpenCode | ~300 s | Heartbeat every 30 s resets idle timer |
| Codex CLI | ~300 s | Heartbeat every 30 s resets idle timer |
| Other HTTP-transport agents | varies | Most reset on any received data |
Works for these because their idle timers are reset by any incoming data — the heartbeat progress notifications sent from a parallel async task on the server are received by the client, resetting its clock.
Every long-running tool emits progress notifications from a parallel coroutine every 30 seconds (configurable via TASKS_HEARTBEAT_INTERVAL_SECONDS). As long as the client resets its idle timer on any received data, the request stays alive for the full duration of the pipeline.
TS-SDK clients (Claude Desktop, Cursor, etc.) do not reset their timeout on progress notifications.
For full control and compatibility with timeout-limited clients, three tools provide a durable job handle:
submit_architecture_design_job returns a job_id in milliseconds. The pipeline runs in a background task. Poll get_architecture_design_status(job_id) every 10–30 seconds. When status is completed, the full design is in the result field. Cancellation is best-effort — the job exits at the next pipeline stage boundary.
This is the only fix that works for TS-SDK clients (Claude Desktop, Cursor).
The job store is SQLite at ~/.config/architecture-pattern-mcp/jobs.db (configurable via ARCHITECTURE_PATTERN_JOBS_DB).
make clientThe example client in examples/architecture_client.py is a direct Python HTTP client — it is not an MCP agent. It calls the server over HTTP without any MCP SDK, and therefore has no client-side idle timeout. It makes a single blocking request and waits for the full response, regardless of how long it takes.
make client is a development/demo tool. It demonstrates that the server correctly completes long requests — the timeout issue is purely a client-side problem. For production use with MCP agents, covers the majority of clients; async job trio is the universal fallback.
/mcp, OpenCode opencode mcp list, Codex codex mcp listMCPArchitectServer initializedcurl http://127.0.0.1:8080/health inside the containerThe server waits for the TEI embedder to become healthy:
GENERATOR_API_KEY is set and not expiredGENERATOR_BASE_URL matches your provider's endpoint.json extensioncategory, name, context, benefits, tradeoffs, quality_attributesdocs/pattern-schema.jsonCommon make targets:
| Target | Description |
|---|---|
make install | Install package in editable mode with dev dependencies |
make lint | Run ruff linting |
make lint-fix | Auto-fix lint issues and format |
make typecheck | Run pyright type checking |
make unit-tests | Run unit tests with uv (tests/unit/) |
make client | Run the example MCP client demo (requires server running) |
make docker-build | Build the MCP server Docker image |
make docker-build-all | Build MCP server + TEI embedder images |
make docker-publish | Push image to Docker Hub + GHCR (version + latest) |
make docker-up | Build and start all services |
make docker-down | Stop all services |
| Development workflow: |
All three images are published to two registries simultaneously:
| Image | Docker Hub | GHCR | Tags |
|---|---|---|---|
| MCP server | olkowa/architecture-pattern-mcp | ghcr.io/olk/architecture-pattern-mcp | $(DOCKER_TAG), latest |
| TEI embedder | olkowa/pattern-tei-embed | ghcr.io/olk/pattern-tei-embed | $(DOCKER_TAG), latest |
| TEI reranker | olkowa/pattern-tei-rerank | ghcr.io/olk/pattern-tei-rerank | $(DOCKER_TAG), latest |
All three images share the same $(DOCKER_TAG) (the version from pyproject.toml), so tei:1.0.3 always ships with mcp:1.0.3. Blob deduplication keeps re-tagging unchanged TEI images cheap.
Bandwidth note: the TEI embedder image is ~5 GB (ONNX fp32 weights baked in). First push to each registry is ~5 GB upload. Subsequent pushes are incremental — only changed layers are transferred.
Docker Hub — already authenticated locally (docker login).
GitHub Container Registry — requires a classic PAT with write:packages scope. 2FA is not an issue — PATs bypass it. After login the token is discarded; the credential persists in ~/.docker/config.json until you log out.
On subsequent publishes repeat steps 1–3. If your PAT has expired, generate a new one at the link above.
GHCR packages default to private. After the first make docker-publish-all, flip all three packages to public:
| Package | Settings URL |
|---|---|
| MCP server | https://github.com/users/olk/packages/container/architecture-pattern-mcp/settings |
| TEI embedder | https://github.com/users/olk/packages/container/pattern-tei-embed/settings |
| TEI reranker | https://github.com/users/olk/packages/container/pattern-tei-rerank/settings |
Set each to Public and save.
If the push fails mid-way (e.g., GHCR auth was not configured), Docker Hub layers are already uploaded. After fixing auth, re-running make docker-publish-all is safe — each registry reports a cache hit for already-uploaded layers and completes the remaining push. For targeted retries, individual images can be pushed with make docker-publish-tei or make docker-publish-tei-rerank.
The server can run as a systemd service on any systemd-based Linux host. It starts the Docker Compose stack automatically at boot.
The systemd/ directory contains three files:
| File | Purpose |
|---|---|
systemd/architecture-pattern-mcp.service | The systemd unit |
systemd/docker-compose.yml | Production compose variant (no build:, absolute paths) |
systemd/README.md | Full runbook with install, verify, and troubleshooting |
The production compose file is a deployment variant of docker/docker-compose.yml:
it has no build: sections (images must be pre-built), uses absolute paths, and
lives under /etc/architecture-pattern-mcp/ on the host. The systemd-managed
project uses the distinct name apmcp-systemd so it can coexist with the dev
compose if needed.
TEI sidecars are NOT defined in this stack — the
pattern-tei-embedembedder andpattern-tei-rerankreranker containers live in the sharedpattern-tei-infrastack. This stack owns thepattern-tei-sharedDocker network and exposes the sidecars athttp://pattern-tei-embed:8080/v1(embedder) andhttp://pattern-tei-rerank:8080(reranker). The systemd MCP stack joins that network and reaches them by those DNS names.Prerequisite — one-time TEI infra setup:
Start
architecture-pattern-mcp.serviceonly AFTERpattern-tei-infra.serviceisactive (running). Seepattern-tei-infra/README.mdfor full details.
docker compose version).<user> is in the docker group.make docker-build-all from the repo).systemctl status shows active (exited) within seconds, but the containers
take up to ~2 minutes to become healthy (TEI embedder start_period: 120s).
The unit does not wait for healthchecks.
For full troubleshooting, networking details, and the coexistence guide, see
systemd/README.md.
MIT License. See LICENSE.