Agent architecture is not application architecture: the agentix pattern
Application architecture structures code. Agent architecture decides who may do what at run time. The agentix pattern - one MCP server per system, one agent per step - is our answer.
This post is also available in Deutsch.
Recently we saw a setup in which one MCP server talked to about ten different applications. It was a Swiss army knife: one process, every credential, every tool, written for exactly one agent and reusable by nobody. It worked, and it is not what MCP is meant for. This post explains why, separates two kinds of architecture that are easy to mix up, and proposes a pattern for the second one. Where something is opinion rather than fact, the text says so.
Two questions, not one
Application architecture decides how code is structured: layers, services, data ownership, ports and adapters, who calls whom. Those calls are fixed at design time, reviewed in a pull request and deployed as units that fail independently.
Agent architecture decides who may do what at run time, when a model chooses the next step and that choice is not deterministic. Its subjects are capability boundaries, blast radius, the trust boundary between model output and real effects, handover contracts, approvals and cost.
The two are orthogonal. A well-layered application can host one agent that holds every credential, and a messy monolith can sit behind well-scoped agents. They meet at the MCP server: in application terms an adapter that translates a protocol into calls on a system, in agent terms a capability boundary where a model’s request becomes an effect.
The agentix pattern
We call it the agentix pattern because open-agentix is built around it, not because its parts are new. Least privilege, bounded contexts, ports and adapters and workflow orchestration all predate agents. What we add is a specific combination, written as rules you can check.
Definition. In the agentix pattern every system an agent may touch sits behind exactly one MCP server, which owns its credentials and exposes its capabilities as typed tools, separated into read and write. Every business process is a versioned plan of steps; each step is executed by its own narrowly scoped agent that holds only the tools its step needs, hands over a typed artifact, and reaches any system only through a deterministic policy gate that records every decision under the run id.
The rules and why
R1. One MCP server per system. One server per system or bounded context, and it is the only door to that system. Tools have typed schemas, reads and writes are separate tools, credentials live only there. Why: one door means one place to review, rotate a key and look in the audit trail, and a small server can be reused by every agent that needs that system. One server per tool, the other extreme, multiplies deployments and credentials without adding a boundary. If one system has very different risk classes, say reading invoices and issuing refunds, keep one server but publish separate read and write tool sets and attach policy per tool. Split the server only when the credentials themselves differ.
R2. Business logic becomes 1..n agents, one per step. Express the process as steps. By default one step is one agent; never build a god agent that holds every server. Split when the risk class, data class, privilege, model, failure handling, cost or approval need differs. Keep together when steps share context and privilege: every split costs latency, tokens and coordination, and loses context the next agent would have used.
R3. Agents never talk to systems directly. Every tool call passes a deterministic policy gate (allow, deny, approval) and lands in the audit trail. A model may ask; the decision comes from code you can read and test, outside the prompt.
R4. Handovers are explicit, typed and minimal. Agents pass a schema-typed artifact to the next step, not shared memory and not open chat. A typed handover can be validated, logged and replayed; free text from a step that read hostile input is a path for prompt injection into the next.
R5. Orchestration is data. The order of steps is a versioned plan, not another agent that knows everything. A plan can be diffed, reviewed and pinned; an orchestrator agent with all tools is a god agent with extra steps.
R6. Budgets and identity per step. Each agent has its own limits (steps, tool calls, tokens, cost, time) and its own identity in the audit trail, so a loop stops one step and “who did this?” has a better answer than “the pipeline”.
R7. Observability by run id. Every model call, tool call, policy decision, approval and cost line carries the run id and the agent id. Without that, nobody can show that R1 to R6 held.
A worked example: ticket triage
A ticket about a failed payment arrives. Someone should look up the ticket and the customer, decide whether this needs an engineering issue, and create one if so.
If text in the ticket manipulates the research agent, it can only read. The analysis agent holds nothing to misuse. The action agent can create one kind of issue, after a person approves, and cannot read the CRM. As a plan, sketched in the shape of the planned Agent Plan (not a shipped format):
kind: AgentPlan
name: payment-ticket-triage
version: 1.0.0
steps:
- agent: research
tools: [jira.issue.get, jira.issue.search, crm.customer.get]
output: { schema: findings.json }
budget: { maxToolCalls: 10, maxCostUsd: 0.10 }
- agent: analysis
tools: []
input: findings.json
output: { schema: decision.json } # { action: "create" | "none", summary, priority }
- agent: action
when: decision.action == "create"
tools:
- name: jira.issue.create
approval: required
maxCallsPerRun: 1
input: decision.json
Best practices for MCP server design
Each item says whether the MCP documentation states it (docs) or whether it is our recommendation (ours). Sources are listed at the end.
- Single responsibility: one system or capability per server (ours, consistent with the docs, which describe servers that “expose specific capabilities” and give one-system examples).
- Small, typed tool surface: every tool has an input schema with types and required fields (docs: tools are “schema-defined interfaces”; limits and enums are ours).
- Read and write separated: separate tools, destructive ones named as such (ours; the docs separate read-only resources from model-controlled tools, but not read from write tools).
- Idempotent and bounded: writes safe to retry, results limited in size (ours).
- Explicit errors the agent and the audit trail can tell apart (ours).
- No ambient credentials: secrets resolved inside the server, never in prompts; never pass a client’s token through to a downstream API (docs for the token rule, ours for the rest).
- Least privilege on scopes: start with minimal scopes, elevate when needed (docs).
- Per-tool policy and approval: approval or pre-approval per tool call (docs name approval dialogs and permission settings as options; deterministic policy per tool is ours).
- Versioning of tools and scopes; no silent semantic changes (docs for scopes, ours for tools).
- Audit: every call attributable to a run and an agent (docs mention activity logs and correlation ids; run and agent ids are ours).
Anti-patterns
- The god agent: one agent with every server, “because it is simpler”, until the first injection.
- The Swiss army knife server: one MCP server for many systems. Many credentials, no reuse.
- MCP-per-endpoint sprawl: a server for every API call. Many doors, no boundary.
- Shared credentials: the audit trail can no longer say who acted.
- Agent-to-agent free chat: nothing to validate, nothing to replay.
- The orchestrator agent that holds everything: R5 broken in the most common way.
- Policy in the prompt: “never delete anything” is a wish, not a control.
Decision checklist
- Can I name each step of this process in one sentence?
- Which tools of which servers does each step need, and which only read?
- Do neighbouring steps differ in risk, data class, privilege, model, failure handling, cost or approval? Then split; otherwise keep them together.
- What does each step hand over, and can I write a schema for it?
- Which calls need a person, and who may decide?
- Can I reconstruct a run from its run id alone?
What the documentation says, and what is ours
The MCP documentation describes a host that creates one client per server, servers that “expose
specific capabilities” with examples per system (file system, database, GitHub, Slack, calendar),
tools where each “performs a single operation”, optional user consent before tool execution, and
security guidance that forbids token passthrough and recommends minimal scopes. The Claude Code
documentation describes subagents that run in their own context window with “specific tool
access”, a tools allowlist and an optional per-subagent model and MCP server list. R1, R2 and R3
are consistent with that. Neither source prescribes our rules or endorses this pattern.
Where we go further, or differ: the MCP docs do not say one server per system; one of their own examples is a combined “Calendar/Email Server”. Claude Code subagents return a summary to the main conversation, which itself delegates. Our R4 (typed handovers) and R5 (a plan instead of an orchestrating agent) are stricter choices for unattended, audited runs, not a correction of those docs.
Trade-offs and opinion
More agents mean more handovers, more model calls, more latency and more to maintain. A task with one tool and one reader does not need three agents. Mitigations: keep steps that share privilege together, use small models for narrow steps and plain code where no model is needed, and keep handovers short. The rules borrow from least privilege, microservices, bounded contexts and ports and adapters without being the same thing: microservices split deploy units, R2 splits authority. Fact: tool calls can be intercepted, and a smaller grant reaches less. Opinion: that one step per agent is the right default, one server per system the right granularity, and the extra cost usually worth paying.
Where open-agentix stands
Implemented in 0.1.0: agents.md pipelines of 1..n agents with immutable versions, tool
allowlists with argument constraints and approval: required per agent, model and budget per
agent, the deterministic policy gate, the MCP gateway, the hash-chained audit trail, and steps and
costs per run and agent. On main, not yet released: tenants, connections scoped to tenant, team
or agent with secret references only, and role bindings for a single agent.
Not there yet:
- Typed handovers (R4): the previous output is passed on as text;
format: jsonis parsed but not validated against a schema. Input and output schemas are planned. - Conditional plans (R5): a pipeline is an ordered list today;
whenis planned. - Named read/write profiles per server (R1) come with the planned catalog governance; until then, per-agent grants and policy patterns give the same effect.
- Per-step credentials and isolated workers (R6) are on the roadmap for v0.2.
- Agent Check and Agent Plan generation, where a model proposes the split for human review, are planned and advisory by design.
References
All accessed 2026-10-04. We paraphrase; quotes are short.
- Model Context Protocol, What is MCP?
- Model Context Protocol, Architecture overview
- Model Context Protocol, Understanding MCP servers
- Model Context Protocol, Security best practices
- Claude Code documentation, Create custom subagents
The short version of the pattern lives in the docs. If you think a rule is wrong, or know a case where a god agent is the better design, tell us in GitHub Discussions. We would rather correct the pattern than defend it.