TL;DR: Answer a few questions about an agent or MCP server and get every card it needs. faf-cli writes the .fafa from the answers and projects it onto the A2A Agent Card, the MCP Server Card, the MCP Registry server.json, an AI Catalog and an ARD manifest, in Node or in a browser.

In Plain English

Old state. Agents and MCP servers are found through cards: small files other machines read. There are several, they overlap, and they ask the same things in different words. Keep three by hand and you get three that disagree.

Fix. Answer a few questions once — name, short name, domain, what it does, version, where it runs, what it can do. faf-cli writes a .fafa from those answers and projects every card from that one file.

New state. One source, every card. Your cards carry nothing of ours unless you ask for it.

npm install -g faf-cli@7.15.0 faf cards --target a2a,mcp,registry,catalog

What 7.15.0 is

Lesson: the cards all describe the same thing; only the wording differs. So write the thing once and let the projector speak each dialect.

answersToFafa turns a handful of answers into a .fafa. buildPack takes that file and writes the cards you asked for. Identifiers are built for you: a urn:air for the catalog and ARD, a reverse-DNS name for the MCP pair, and the well-known URLs each card is served from.

import { buildPack } from 'faf-cli'; const pack = buildPack(answers, { cards: ['a2a', 'server_card', 'ai_catalog'] });

The same projector runs in a browser: import { buildPack } from 'faf-cli/pack' — one module, no Node built-ins, types included.

The cards it writes

  • A2A Agent Card — served at /.well-known/agent-card.json, how other agents find yours.
  • MCP Server Card — describes a remote MCP server so clients can connect.
  • MCP Registry server.json — the registry's own entry. Publishing it stays your step.
  • AI Catalog — one list of every card on your domain, at /.well-known/ai-catalog.json.
  • ARD manifest — what agent search engines read from your domain.
  • The .fafa — the file the rest are built from. It is ours, it is IANA-registered, and you keep it.

Neutral by default

A card faf-cli writes for you carries no extension of ours and no FAF media type unless you pass one. The .fafa is listed in your catalog only if you ask for it. What you publish describes your agent, not our format.

faf cards still adds FAF's context extension to FAF's own card — that path is unchanged, and the output is byte for byte what it was.

Bounds

  • Specs move, and two are early. The MCP Server Card says "Experimental"; ARD says "Proposal". The cards are written to what those specs say today.
  • Publishing is yours. We write the server.json; you publish it to the registry with the registry's own tooling.
  • Some things can't map exactly. Identity and trust differ between cards, and the projector never invents what a spec doesn't define.
  • A schema URL upstream is missing. A Server Card carries a $schema, and the spec names one URL for it. That URL returns 404 today. We write it as the spec names it; it resolves when upstream publishes the file.

Checked

Every card type is run through its own spec's validator before release: the AI Catalog CLI, ARD's conformance tool, and the published schemas for the Server Card, the registry server.json and the .fafa. Twenty-four files across eight situations, no failures. The suite is 2037 tests, green.

Try it

Install:

npm install -g faf-cli@7.15.0 faf cards --check

Try (no install):

npx --yes faf-cli@7.15.0 --version

--check prints the cards without writing them. Same CLI under the shorter name: npm i -g faf@7.15.0. More: docs.faf.one/cards · release notes · repo.

Technical details

  • Version: 7.15.0 (September 15, 2026)
  • Packages: faf-cli and faf (same bits) · Homebrew
  • New exports: answersToFafa · buildPack · projectPack · projectA2ACard · projectServerCard · projectServerJson · projectAiCatalog · projectArd
  • Browser: faf-cli/pack — no Node built-ins, types included
  • Tests: 2037 passing
  • Unchanged: faf cards and buildA2ACard output