agent-ready
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@agent-readyshow me the profile and latest posts from sam.example.com"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
agent-ready-kit
Make a small site readable by AI agents from one JSON data file. agent-ready validates the file against a strict schema and turns it into:
llms.txt, one per site language, in the format of llmstxt.org: an H1 with the name, a blockquote summary, the public profiles and detail paragraphs, then H2 sections of[name](url): noteslinks.schema.org JSON-LD: one
@graphwith the owner (PersonorOrganization) and oneSoftwareSourceCodeper product.A read-only MCP server with three tools,
get_profile,list_productsandlist_posts, served over stdio or from any runtime that speaks WebRequest/Response(Netlify Functions v2, Deno, Bun, Cloudflare Workers, Node).
All three read the same validated object, so a name or a URL can never differ between them (a test checks it). The design comes from the personal site chrissgon.dev, where one data module feeds the pages, llms.txt, the JSON-LD and the MCP endpoint.
Install
Requires Node.js 22 or later. The package is an ES module with TypeScript types. The package is @chrissgon/agent-ready-kit; its command is agent-ready.
npm install @chrissgon/agent-ready-kitOr run the CLI without installing it (the package has one command, so npx runs agent-ready):
npx @chrissgon/agent-ready-kit check --data site.json
npx @chrissgon/agent-ready-kit build --data site.json --out publicRelated MCP server: cryptbrew-mcp
The data file
One JSON file with four keys. Every object is strict: a field the schema does not declare fails validation. This is fixtures/person.json (fake example data), shortened:
{
"site": { "url": "https://sam.example.com", "langs": ["en", "pt"], "mcp": "https://sam.example.com/api/mcp" },
"owner": {
"type": "Person",
"name": "Sam Example",
"alternateName": "samexample",
"jobTitle": "Software Engineer",
"label": { "en": "Software engineer · Small open-source tools for the web", "pt": "Engenheiro de software · ..." },
"about": { "en": ["Sam builds small, well-tested tools for the web ..."], "pt": ["Sam cria ferramentas ..."] },
"profiles": [{ "network": "Code", "handle": "samexample", "url": "https://git.example.org/samexample" }]
},
"products": [
{
"id": "tidy-tables",
"name": "Tidy Tables",
"url": "https://tidytables.example.com",
"codeRepository": "https://git.example.org/samexample/tidy-tables",
"npm": "@samexample/tidy-tables",
"license": "MIT",
"programmingLanguage": ["CSS", "TypeScript"],
"summary": { "en": "Accessible data tables in one small stylesheet.", "pt": "Tabelas de dados ..." }
}
],
"posts": [
{
"id": "tables-for-everyone",
"title": { "en": "Tables for everyone", "pt": "Tabelas para todos" },
"date": "2026-08-14",
"lang": ["en", "pt"],
"url": "https://blog.example.com/tables-for-everyone"
}
]
}Field | Rule |
| https origin; a trailing slash is removed |
| language codes ( |
| optional https URL of your MCP endpoint, listed in |
|
|
| the name, and an optional handle |
| one line per site language: the |
| optional paragraphs per site language |
|
|
| optional slug |
| unique slug |
Every error names the field, one per line, and check exits with 1:
$ npx @chrissgon/agent-ready-kit check --data fixtures/forbidden-email.json
data: owner.email: forbidden field "email", the kit never publishes itOther examples: data: owner.nickname: unknown field, data: posts.1.id: duplicate id "same-id" (first at posts.0), data: owner.label.pt: missing text for site language "pt".
fixtures/org.json is a one-language Organization example.
What the kit never publishes
worksFor, address, homeLocation, birthDate and email are rejected anywhere in the data file, and generateJsonLd refuses them again if code adds them to the data at run time. The MCP tools return slices of the validated file and nothing else: no tool writes, sends, executes or searches free text, and an argument the tool does not declare is rejected.
Commands
agent-ready build --data <file> --out <dir> llms.txt per language (the first at <dir>/llms.txt, the others at
<dir>/<lang>/llms.txt) and <dir>/jsonld.json; prints the paths
agent-ready check --data <file> validate; prints a one-line summary
agent-ready mcp --data <file> serve the read-only MCP server on stdin/stdout
agent-ready --helpData goes to stdout and diagnostics to stderr. Exit codes: 0 ok, 1 invalid data, 2 wrong usage or unreadable file.
check on fixtures/person.json prints ok: fixtures/person.json: Person "Sam Example", 2 products, 3 posts, languages en, pt; build prints the files it wrote: out/llms.txt, out/pt/llms.txt and out/jsonld.json.
A local MCP client starts the server as a command:
{ "command": "npx", "args": ["-y", "@chrissgon/agent-ready-kit", "mcp", "--data", "/path/to/site.json"] }Use it from code
import { createMcpHandler, generateJsonLd, generateLlms, loadData, serializeJsonLd } from "@chrissgon/agent-ready-kit";
const data = await loadData("site.json"); // throws DataError with one line per problem
const llms = generateLlms(data); // default language; generateLlms(data, { lang: "pt" }) for another
const jsonld = serializeJsonLd(generateJsonLd(data)); // safe inside <script type="application/ld+json">
const handler = createMcpHandler(data); // (request: Request) => Promise<Response>Exports
Import from | Exports | Loads the MCP SDK |
| everything below, plus | yes |
|
| no |
|
| no |
|
| no |
|
| yes |
Pages that only need llms.txt or the JSON-LD import from /data, /llms and /jsonld, so they never load the MCP SDK.
llms.txt in parts, and in your language
generateLlmsParts returns the parts of llms.txt in order (head, about, products, writing, agents), each ending in one newline, or "" when the data has nothing for it. Joined with a blank line they are generateLlms; a site can put its own sections between them.
labels sets the headings and the fixed words inside the lines for a language; a missing label keeps its English default (DEFAULT_LLMS_LABELS). about has no default: set it to put the about paragraphs under their own H2.
import { generateLlms } from "@chrissgon/agent-ready-kit/llms";
generateLlms(data, {
lang: "pt",
labels: { about: "Sobre", products: "Produtos", writing: "Escrita", forAgents: "Para agentes", code: "Código", license: "Licença", languages: "idiomas" },
});JSON-LD
The owner's @id is <site.url>/#person (or #organization); every product's author points to it. A product's license becomes https://spdx.org/licenses/<id>.html; pass licenseUrl: (id) => ... for another page. lang picks the language of the descriptions.
The MCP server
Tool | Input | Output ( |
| optional |
|
| optional |
|
|
|
|
lang is one of the site's languages (default: the first) and picks the language of the texts; a post with no title in that language keeps its own. Optional fields are absent when the data has no value. Every tool carries readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false and an output schema. The server's instructions say: "Read-only. This server only holds 's public profile, products and posts; any other personal data does not exist here."
Check it with the MCP Inspector (the server command goes before --, the Inspector options after it):
npx -y @modelcontextprotocol/inspector@2.8.0 --cli npx -y @chrissgon/agent-ready-kit mcp --data site.json -- --method tools/list
npx -y @modelcontextprotocol/inspector@2.8.0 --cli npx -y @chrissgon/agent-ready-kit mcp --data site.json -- --method tools/call --tool-name list_posts --tool-arg limit=2In a Netlify Function (v2)
The handler is stateless: each POST gets a new server and transport, responses are JSON (no SSE stream), any method other than POST gets 405 with Allow: POST, a body over maxBodyBytes (default 64 KiB) gets 413 before it is parsed, and every response carries Cache-Control: no-store and X-Content-Type-Options: nosniff. That is the pattern proven in the chrissgon.dev spike on Netlify Functions v2.
// netlify/functions/mcp.mts
import type { Config } from "@netlify/functions";
import { validate } from "@chrissgon/agent-ready-kit/data";
import { createMcpHandler } from "@chrissgon/agent-ready-kit/mcp";
import site from "../../site.json" with { type: "json" };
export default createMcpHandler(validate(site), { name: "example.com", version: "1.0.0" });
export const config: Config = { path: "/api/mcp" };name and version are what the server reports to clients (default agent-ready and this package's version). A public endpoint costs something on every call; Netlify can rate-limit a function from its config (rateLimit: { windowLimit, windowSize, aggregateBy: ["ip", "domain"] }, see https://docs.netlify.com/manage/security/secure-access-to-sites/rate-limiting/).
In a static site
Run build before the site generator and publish its output at the site root, so llms.txt is served at /llms.txt and each other language at /<lang>/llms.txt:
npx @chrissgon/agent-ready-kit build --data site.json --out publicPut the JSON-LD in the page head, from public/jsonld.json or from code with serializeJsonLd(generateJsonLd(data)):
<script type="application/ld+json">{"@context":"https://schema.org","@graph":[ ... ]}</script>Development
Task | Command |
Install |
|
Type-check |
|
Test |
|
Build |
|
Packed tarball smoke test |
|
From a clone, node dist/cli.js <command> runs the CLI after npm run build.
Releasing
Releases are published by .github/workflows/publish.yml with npm trusted publishing (no token) and provenance. The owner bumps version in package.json and src/version.ts through a pull request, then pushes the tag v<version> on the merged commit. The workflow checks that the tag matches package.json and is on main, runs the secret scan, types, tests, build and the packed-tarball smoke test, and publishes with --access public; a prerelease version (0.2.0-beta.1) goes to the next dist-tag.
License
MIT, see LICENSE.
Related MCP Connectors
Public AI web-readiness scanner and machine-facing observability discovery service.
Live web checks for AI agents: sitemaps, robots.txt, URL status, broken links, feeds, citations.
Look up 133 agentic-web standards, live-probe any domain, validate manifests, generate boilerplate.
Public social-data API and live docs for AI coding agents.
Related MCP Servers
- AlicenseBqualityBmaintenanceEnables AI clients to connect locally over stdio, discover and read schemas for native page tools, and execute user-authorized operations supplied by websites and independent user scripts.13MIT

cryptbrew-mcpofficial
AlicenseAqualityBmaintenanceEnables AI agents to answer Cryptbrew product questions and check live API health without merchant authentication. Exposes tools for pricing, FAQs, invoice flow, and health probes over stdio or streamable HTTP.8MIT- AlicenseCqualityBmaintenanceEnables AI agents and CLI users to perform confirmed shop operations, manage products, orders, collections, webhooks, and promotions, and handle bounded metadata exports and private uploads through a local stdio server.8627 npmAGPL 3.0

si.sigit/cliofficial
FlicenseNot gradedqualityBmaintenanceServes sigit.si account, repository, issue, pull request, code-search, session, hook, and billing operations to AI agents over stdio, reusing the token stored by the CLI login and defaulting repository tools to the checkout the agent is pointed at. Tool lists can be trimmed with read-only mode or toolset selection, and a hosted HTTP endpoint offers the same tools.2-