# Agent-native Apps

Serve people and agents from one application contract with HTML, Markdown, robots, llms.txt, OpenAPI, MCP, and WebMCP.

Agent-native apps make their content and operations discoverable without asking
an agent to scrape navigation chrome or reverse-engineer a visual interface.
Humans and agents still use the same domain handlers and authorization rules.

Cloudflare reports that automated agents and bots now drive more than half of
web requests. Its CEO Matthew Prince describes the resulting shift plainly:
“the majority of traffic on the Internet is non-human.” That is a reason to
design an explicit agent surface, not to make every bot trusted.

## Add agent readiness

```bash
ferrite add agent-ready
```

Declare one `Surface` containing the application identity, canonical origin,
human pages, routes, operations, JSON schemas, and read-only or idempotent
traits. Route the well-known handler before application-specific routing.

## Publish the discovery set

| Path | Purpose |
| --- | --- |
| `/robots.txt` | Crawler policy and discovery links |
| `/sitemap.xml` | Canonical human and machine URLs |
| `/llms.txt` | Concise app orientation and core links |
| `/llms-full.txt` | Broader Markdown context |
| `/index.md` or `Accept: text/markdown` | Clean page representation |
| `/openapi.json` | HTTP operation schemas |
| `/.well-known/agent-card.json` | App identity, skills, and interfaces |
| `/.well-known/agent-readiness` | Machine-readable readiness evidence |
| `POST /mcp` | Stateless MCP tools |
| HTML page | WebMCP tools in the signed-in browser |

Generate each representation from the same authored pages and operation
declarations. A second hand-written “agent API” will drift.

## Keep one authorization boundary

Public catalogue tools may be anonymous. Orders, tickets, evidence, staff
schedules, and administrative actions require the same subject, tenant, role,
ownership, and step-up checks as the UI. Server MCP does not inherit a browser
cookie. WebMCP must not export that cookie into agent context.

## Map an API operation

```rust filename="src/surface.rs"
Operation {
    name: "list_products".into(),
    method: "GET".into(),
    path: "/api/products".into(),
    description: "List products with current price and availability.".into(),
    input_schema: Some(json!({
        "type": "object",
        "properties": { "query": { "type": "string" } },
        "additionalProperties": false
    })),
    read_only: true,
    idempotent: true,
    ..Default::default()
}
```

The MCP tool, OpenAPI operation, and WebMCP registration call the same
`list_products` domain function.

## Verify the served behavior

```bash
node tools/agent-score/agent-score.mjs scan http://127.0.0.1:8787
```

The score checks real responses and a real MCP tool call. A metadata file that
claims an endpoint exists cannot make a missing endpoint pass.

Continue with [WebMCP & OpenAPI](/developers/webmcp-openapi/) and the
[Apps](/developers/apps/) that implement the complete pattern.
