Agents and MCP: give agents your system, not a guess

An agent does not notice that a documentation page is out of date. It follows it. If your system still mentions a property that was renamed a year ago, an agent will use it with confidence in many files. Loom gives agents the real system, checks what they write and records what they could not find.

Exposing a design system to agents is now the minimum that teams expect. The harder questions are what happens when the system is partly wrong, and who notices when agents bypass it. That is where Loom works.

An agent needs three things to stay on-system

Agent readiness has three layers: retrieval (finding the right part of the system), rules (knowing what is allowed) and a verifier (checking the result). Loom provides all three through one MCP server. MCP is the Model Context Protocol, an open standard that lets an AI assistant call tools.

An agent's loop with Loom

Diagram
  1. Search the systemsearch_system
  2. Read the contractget_entity
  3. Write the interfacein the agent's own editor
  4. Check the compositioncheck_composition
  5. Fix what was flaggedthe check names the fix
  6. Propose what is missingintake_need or propose_change
Each step names the MCP tool the agent calls. The agent repeats the loop until the check passes.

Retrieval finds the right component, not a similar one

search_system finds components, tokens and patterns and reports how confident it is. When nothing fits, it says "no strong match" instead of returning the closest guess. get_entity returns the full contract with the exact import, properties, states and accessibility notes. get_tokens returns token values and roles. Working

Every call in one recorded session

Recorded server output
ToolWhat the server answeredTime
search_system20 results for "delete confirm danger".145 ms
get_entityButton: Starts an action in the current view: save, publish, open a dialog, run a check.34 ms
check_compositionOff-system: 3 errors, 2 warnings across 6 nodes.48 ms
check_compositionOn-system: 0 errors, 0 warnings across 5 nodes.5 ms
audit_codeDrift found: 11 errors, 11 warnings — 7 colours, 9 dimensions, 1 non-system import, 1 re-implemented component.117 ms
get_guidelinesGuidelines for illustration: missing.11 ms
propose_changeDraft component-filedropzone-6af1d4b4 written to the drafts folder (status: proposed, labelled AI-generated, not yet human-reviewed).399 ms
check_compositionOff-system: 4 errors, 5 warnings across 6 nodes.69 ms
search_systemNo component matches "date range picker".17 ms
search_system51 results for "show an error when payment fails".14 ms
list_unmet_needs1 unmet need from 1 request; 0 over the threshold (3 requests from 2+ requesters in 30 days).5 ms
From the recorded agent session on Loom Base, our own design system (data/mcp-demo.json), read when this page is built.

Search can also use your own embeddings model for meaning-based matching. Partial What does not work yet: it has been tested against a local test model only, not a real provider.

Rules tell the agent what is allowed

get_rules lists every rule, whether Loom or your linter enforces it, its exceptions and its open questions. Conversion also writes an AGENTS.md file and rules for your system: 251 rules for our reference system. Working

Tools that read Markdown get one file

Some tools read a single file rather than call a server. get_design_md returns your system as one DESIGN.md file, in the open DESIGN.md format: tokens under your own names, components, patterns, rules, brand and voice, and how agents should use the system. It is generated from the same records as the other tools, and it says "not defined" wherever a record is missing. Here is one entry from Loom Base's own file:

One entry from a real DESIGN.md

Loom Base, MIT
# The Loom Base design system (@loom/base), exported by Loom from its records: 2312 tokens, 69 components, 11 patterns.

### Button
`import { Button } from "@loom/base/native";` · lifecycle beta · tier component
- **Use when:** To start an action that changes data or opens something on this page; To submit a form (set it as the form's last control); As a toggle (pressed) for an on/off f…
- **Do not use when:** Going to another page or URL → Link; Choosing one of several options → RadioGroup or Select; Turning a setting on or off that takes effect immediately → S…
- **Variants:** `tone`: primary | secondary | quiet | danger. primary: the one main action in a view; secondary: other actions; quiet: toolbars and dense areas; danger: removes …
- **Keyboard:** `Enter` PRESS; `Space` PRESS; `Tab` A disabled button is skipped; a busy one is not
Read from packages/base/DESIGN.md, which Loom exported from the system's records, when this page is built. Lines are shortened here.

The same file can be written into your repository from the command line, with a check that fails when the file is out of date. Working

What does not work yet: the file holds only the default mode's token values, and Loom does not yet deliver it to your repository as a pull request. For building interface, the other tools give more exact and more current answers than any single file.

The verifier checks the work before hand-off

check_composition checks a draft before it is written: raw values, rebuilt components, unlabelled controls, two primary actions in one region, style overrides and pattern rules. audit_code finds drift in existing files, including use of deprecated items. Both apply your governance: severities per area, promotions and exceptions. Working

Report a need instead of inventing a component

intake_need decides whether a need is reuse, extend or new. When nothing matches, the need is recorded for the unmet-needs radar. list_unmet_needs shows needs grouped and counted against the owner's threshold. propose_change writes a draft with the alternatives considered, labelled as AI-generated and not yet reviewed. Partial

What does not work yet: drafts created automatically once a need passes the threshold. Concept

Recording of real output

A recorded session: a scripted agent against Loom Base, our own design system (MIT), with real server output. The replay types each call as the agent sent it and shows each result after its recorded latency, shortened for the page. Server output is in English.

Agent session · recorded session

  1. Agent

    I need a destructive "delete workspace" action with a confirmation. What does the system have?

  2. Loom · search_system · 145 ms→ search_system({"query":"delete confirm danger","kind":"component","limit":5})

    20 results for "delete confirm danger" (lexical ranking). Top: Dialog (dialog, 0.8, beta), ConfirmAction (confirm-action, 0.46, beta), ToastRegion (toast-region, 0.41, beta), Tag (tag, 0.27, beta), Alert (alert, 0.25, beta)

    • Dialog (dialog, strong, confidence 0.8) — import { Dialog } from "@loom/base/native";• ConfirmAction (confirm-action, partial, confidence 0.46) — import { ConfirmAction } from "@loom/base/native";• ToastRegion (toast-region, partial, confidence 0.41) — import { ToastRegion } from "@loom/base/native";
  3. Loom · get_entity · 34 ms→ get_entity({"id":"Button"})

    Button: Starts an action in the current view: save, publish, open a dialog, run a check.

  4. Agent

    Here is my first draft. It reaches for an MUI Modal, guesses a variant prop, uses two primary buttons and hard-codes a colour and a margin.

  5. Loom · check_composition · 48 ms→ check_composition({"tsx":"import { Card, Button, Heading, Text } from \"@loom/base/native\";\nim…"})

    Off-system: 3 errors, 2 warnings across 6 nodes.

    - [warning] Text has style set: overriding a system component's styling is drift from its contract. → Customise through the component's slots, variants or overridable tokens wit…- [error] Button has no "variant" prop. → Did you mean "tone" ("primary" | "secondary" | "quiet" | "danger")? primary: the one main action in a view; secondary: other actions; q…- [error] <Modal> is not part of Loom Base (imported from "@mui/material"). → Closest system components: AILabel (ai-label), Dialog (dialog), Drawer (drawer). If none fits, draf…
  6. Loom · check_composition · 5 ms→ check_composition({"tsx":"import { Card, Button, Text, Stack, ConfirmAction } from \"@loom/bas…"})

    On-system: 0 errors, 0 warnings across 5 nodes.

    components: Card, Stack, Text, Button, ConfirmAction
  7. Loom · audit_code · 117 ms→ audit_code({"files":[{"path":"src/settings/SettingsPage.tsx","source":"import React from \"react\";\nimport { Button as MuiButton, Dialog…

    Drift found: 11 errors, 11 warnings — 7 colours, 9 dimensions, 1 non-system import, 1 re-implemented component.

    ✗ src/settings/settings.css:2 Hard-coded colour #fffdf8 (background). → Use var(--base-color-palette-cotton-0) ().✗ src/settings/settings.css:5 Hard-coded dimension 16px (padding). → Use var(--base-space-scale-6) (16px).✗ src/settings/settings.css:5 Hard-coded dimension 20px (padding). → Use var(--base-space-scale-7) (20px).
  8. Loom · get_guidelines · 11 ms→ get_guidelines({"topic":"illustration"})

    Guidelines for illustration: missing. 0 sections. Missing: Loom Base has no dedicated illustration guideline. Do not invent one: follow existing foundations, and use propose_change (kind "guideline") to draft it for review.

    missing: Loom Base has no dedicated illustration guideline. Do not invent one: follow existing foundations, and use propose_change (kind "guideline") to draft it for review.
  9. Agent

    Research uploads need a drag-and-drop file area. Nothing in the system does that, so I will draft a proposal rather than ship a one-off.

  10. Loom · propose_change · 399 ms→ propose_change({"kind":"component","title":"FileDropzone","need":"Researchers attach interview recordings and notes to a journey. Set…","…

    Draft component-filedropzone-6af1d4b4 written to drafts/component-filedropzone-6af1d4b4.json (status: proposed, labelled AI-generated, not yet human-reviewed). Intake: extend. 7 existing alternatives listed; impact: 5 declared dependents.

    impact: 5 declared dependents (partial graph)status: proposed; system source modified: false
  11. Loom · check_composition · 69 ms→ check_composition({"tsx":"import { Modal } from \"@mui/material\";\nimport { Button } from \"@loo…"})

    Off-system: 4 errors, 5 warnings across 6 nodes.

    - [warning] Raw <h1> used where the system provides Heading. → import { Heading } from "@loom/base/native";- [error] Button has no "variant" prop. → Did you mean "tone" ("primary" | "secondary" | "quiet" | "danger")? primary: the one main action in a view; secondary: other actions; q…- [error] Button has no "variant" prop. → Did you mean "tone" ("primary" | "secondary" | "quiet" | "danger")? primary: the one main action in a view; secondary: other actions; q…
  12. Agent

    The booking flow needs a date range picker. Does the system have one?

  13. Loom · search_system · 17 ms→ search_system({"query":"date range picker for booking","kind":"component","limit":5})

    No component matches "date range picker". Closest partial matches: ComboBox (combo-box, partial match, confidence 0.24, beta: covers "picker" but not "date range"); FormField (form-field, partial match, confidence 0.24, beta: covers "picker" but not "date range"); LooseThreads (loose-threads, partial match, confidence 0.24, beta: covers "picker" but not "date range"). Logged as an unmet need. If this is a real gap, draft it with propose_change instead of building it off-system.

    • ComboBox — partial match: covers "picker" but not "date range"• FormField — partial match: covers "picker" but not "date range"• LooseThreads — partial match: covers "picker" but not "date range"
  14. Loom · search_system · 14 ms→ search_system({"query":"show an error when payment fails","kind":"component","limit":3})

    51 results for "show an error when payment fails" (lexical ranking). Top: ErrorSummary (error-summary, 0.93, beta), AIStatus (ai-status, 0.74, beta), Alert (alert, 0.74, beta)

    • ErrorSummary (error-summary, strong, confidence 0.93) — import { ErrorSummary } from "@loom/base/native";• AIStatus (ai-status, strong, confidence 0.74) — import { AIStatus } from "@loom/base/native";• Alert (alert, strong, confidence 0.74) — import { Alert } from "@loom/base/native";
  15. Loom · list_unmet_needs · 5 ms→ list_unmet_needs({})

    1 unmet need from 1 request; 0 over the threshold (3 requests from 2+ requesters in 30 days). "date range picker" x1.

    • "date range picker": 1 request(s), 1 requester(s) — Below threshold: needs 2 more request(s) and 1 more client(s) or team(s) within 30 days.

Content from your repository is treated as data

Tool results quote your repository, docs and Figma. Loom marks that content as untrusted, neutralises it and tells the agent it is data, not instructions. This lowers the risk of prompt injection through your own files. It does not remove it. Working

Your model, your keys

Any agent that speaks MCP can use your system with the model you choose. Working For agents that Loom runs for you, provider setup for Anthropic Claude, OpenAI and any OpenAI-compatible gateway is in development. Concept

Loom's current tools do not call a model. They are deterministic checks, so they give the same answer whichever model produced the result.

It runs where you choose

The command line and the MCP server run on your own machines today. Partial What does not work yet: a packaged CI step and Loom cloud are planned.

Over a network, the server requires a secret token of at least 32 characters on every request and refuses to start without one. Working This is a shared secret, not the MCP authorisation standard (OAuth), so hosted assistants that need OAuth cannot connect yet.

Every run has a budget and a record

Every tool call is logged with its duration, token counts and a cost estimate. You can cap a run by calls, tokens or cost. Working Every draft an agent writes is labelled. Working

Choose a model on evidence, not on reputation

Contract tests for agents would run the same tasks and checks for different models, so you can choose the model that builds best with your system. Concept

An agent is only as good as the system it can read. We make sure it reads the real one.

Questions

We already built our own MCP server. Why use Loom's? Then you are ahead of most teams. Loom adds the verifier, the governance behind it (owners, severities, exceptions) and the record of unmet needs.

Which assistants work with it? Any MCP client that connects over standard input and output or local HTTP. Remote clients that need OAuth cannot connect yet.

How fast is it? In the recorded session on Loom Base, the 11 calls took between 5 and 399 milliseconds.

Does an agent ever merge its own work? Not today. Every change waits for a person. Autonomy modes that allow more are a concept.

Start with a conversation about your system.

We read your system, show you what we found, and agree with your team what to fix first.