labs | 04 | discoverable
lab 04 | ~8 min | masterclass

A human finds you through a search bar. An agent finds you through a manifest.

You have an MCP server with good schemas. But how does an agent that has never heard of you find out it exists? The agentic web (the part of the web meant for AI agents, not people) has a discovery layer for this. It is a small file at /.well-known/ai-agent.json (a manifest at a known web address that tells agents what you offer) plus an agent card listing your skills. This is the front door. SEO (search engine optimization, the work of ranking in Google) pointed humans and crawlers at your hero section. An agent reads the manifest or it leaves. Publish the door, or you do not have one.

step 1

Write /.well-known/ai-agent.json.

This is the manifest (the small description file) a passing agent fetches first. It is short on purpose. Every field helps an agent decide whether to call you, the same lesson as Lab 03 but for the whole site instead of one tool. Save it as ai-agent.json.

ai-agent.json
{
  "schema_version": "1",
  "name": "toolsmith-byo",
  "description": "Stores and searches short notes per user. Call it to read, search, or write a user's notes.",
  "capabilities": {
    "mcp": {
      "endpoint": "https://toolsmith.example.com/mcp/"
    }
  },
  "auth": {
    "type": "oauth2",
    "resource_metadata": "https://toolsmith.example.com/.well-known/oauth-protected-resource"
  },
  "contact": "agents@toolsmith.example.com"
}

Read it the way an agent does. name and description are what an agent matches a task against, so the description should be one plain sentence about what you do, not marketing. capabilities.mcp.endpoint is the web address where it connects to get your tools. auth points at a second file that spells out how to log in, which the agent reads before it tries to act. That is exactly what Lab 05 serves. Every field either moves an agent toward calling you or leaves it guessing. Leave one out and you have narrowed the door.

step 2

Serve it and verify.

Place the file under public/.well-known/ so it serves at the exact path agents expect, and make sure it is sent as application/json (the content type that says "this is JSON data," not a web page). On a framework with no folder for static files, add a route that returns the same bytes. Then fetch it back the way a stranger would. If curl does not return it, no agent can either.

terminal | fetch the manifest
curl -sS https://toolsmith.example.com/.well-known/ai-agent.json | python -m json.tool
powershell | fetch the manifest
curl.exe -sS https://toolsmith.example.com/.well-known/ai-agent.json | python -m json.tool
200, content-type application/json, the manifest comes back
HTTP/2 200
content-type: application/json

{
  "schema_version": "1",
  "name": "toolsmith-byo",
  "description": "Stores and searches short notes per user. ...",
  "capabilities": { "mcp": { "endpoint": "https://toolsmith.example.com/mcp/" } },
  "auth": { "type": "oauth2", "resource_metadata": ".../.well-known/oauth-protected-resource" },
  "contact": "agents@toolsmith.example.com"
}

Two things to confirm, both easy to get wrong. The path is /.well-known/ai-agent.json exactly, dot-prefix and all. And it must be sent as application/json, not text/html, or strict agents skip it. One more: an agent often fetches this from a different site than yours (a different origin), and browsers block cross-site reads by default. So set the header Access-Control-Allow-Origin: * on the file, which tells the browser any site may read it, or agents running in a browser fail without a word.

step 3

Add an agent card.

The manifest says you exist and where your tools live. The agent card says what you are good at, listed as named skills with their inputs and outputs. This follows the A2A convention (agent-to-agent, the standard for one agent handing work to another): a peer agent reads your card before it decides to send you a job, which is exactly the handoff in Lab 07. Save it at public/.well-known/agent-card.json.

agent-card.json
{
  "name": "toolsmith-byo",
  "description": "Stores and searches short notes per user.",
  "skills": [
    {
      "id": "get_notes",
      "description": "Return all stored notes for one user.",
      "input": "user_id: string",
      "output": "notes: string[]"
    },
    {
      "id": "search_notes",
      "description": "Find notes across all users whose text contains the query.",
      "input": "query: string",
      "output": "matches: string[]"
    },
    {
      "id": "add_note",
      "description": "Store a new note for a user. Returns a confirmation.",
      "input": "user_id: string, note: string",
      "output": "confirmation: string"
    }
  ],
  "url": "https://toolsmith.example.com/mcp/"
}

Same skills you wired in Lab 03, now laid out as a menu a stranger can read without calling anything. Each id matches a real tool. Each input and output lets a peer decide whether your skill fits its task before it spends a call. Link the card from the manifest so one fetch leads to the next: add "agent_card": "https://toolsmith.example.com/.well-known/agent-card.json" next to capabilities. Now the trail is: manifest, then card, then a real call.

Your site is invisible to the only visitor that matters next.Web A(gent).0

Every dollar you spent on SEO tuned you for a human with a search bar and a crawler that indexes text. An agent does not read your hero section, your testimonials, or your pricing table. It fetches /.well-known/ai-agent.json, and if it is not there, you are not on the map. The agentic web is opt-in: being found is a file you publish, not a thing you get for free.

Here is what that looks like from the other side. A peer agent has a task. It goes to your origin (your site's base address, like https://yourname.com), reaches for the manifest, and finds nothing:

discovering agent, at an origin with no manifest no ai-agent.json at this origin, I cannot determine capabilities, moving to the next provider.

It did not bounce off your login wall or fail a call. It never knew there was a door. That is the failure that leaves no trace on your side: you simply never come up as an option.

The Web A(gent).0 thesis is that this is the one window to build cooperation into the standards before the defaults harden. The teams that publish the manifest get used by agents. The teams that wait get routed around. This is not hypothetical for this deck. The Web A(gent).0 keynote shipped with its own ai-agent.json and agent card, because a talk about the agentic web that an agent cannot discover would be the joke telling itself.

hand to agent

Hand this to your coding agent.

You wrote the manifest and the card by hand so you could see the fields. Now make your agent do it for a real project, then prove it can read its own door. Paste this verbatim:

prompt | paste into your coding agent
Generate a /.well-known/ai-agent.json for <project> that describes its MCP
endpoint, auth pointer, and contact, plus a companion agent-card listing its
named skills with input/output. Serve both as static files with the right
content-type. Then fetch them back and tell me, as a discovering agent would,
exactly what you conclude I offer and how you would call me.

The last sentence is the real test. If your agent reads the files back and cannot say what you offer or how to call you, the manifest is wrong, and you found out in one turn instead of in production.

checkpoint

A passing agent can now discover what you are and how to reach you with no prior knowledge: a manifest at a known path, an agent card listing real skills, both served as JSON from a path strangers can fetch. The door is published. The only thing left is the lock. Next: make sure an agent has to log in before it can act.