AI Agent Readiness
Every Quickback Worker ships agent-discovery files and an auto-generated MCP server. Let Claude, ChatGPT, Cursor, and Perplexity find and call your API out of the box.
Every compiled Quickback Worker advertises itself to AI agents and MCP clients — no user wiring required. One config flag controls the whole discovery surface.
What the compiler generates
When agents is enabled (the default), the Worker serves:
| Route | What it is |
|---|---|
GET /robots.txt | AI-bot policy with the Cloudflare Content Signals preamble and explicit Allow: rules for GPTBot, ClaudeBot, PerplexityBot, Google-Extended, CCBot, Applebot-Extended, Bytespider, MistralAI, Cohere, DuckAssist. |
GET /llms.txt | Agent-facing summary of the API — project name, authentication, resource list, endpoint conventions — derived from your own config. |
GET /.well-known/oauth-protected-resource | RFC 9728 metadata declaring this Worker as a protected resource. |
GET /.well-known/oauth-authorization-server | RFC 8414 metadata pointing at the sign-in and token endpoints. |
GET /.well-known/api-catalog | RFC 9727 catalog linking at /openapi.json. |
GET /.well-known/mcp.json | MCP Server Card — discoverable metadata for the MCP server below. |
POST /mcp | Auto-generated MCP-over-HTTP server. One tool per OpenAPI operation, JWT auth forwarded through the same middleware as the REST API. |
Default behavior
import { defineConfig } from '@quickback/compiler';
export default defineConfig({
name: 'my-api',
// …
// agents: true is the default — no need to write it.
});Run quickback compile and every endpoint above ships in the Worker.
Opting out
export default defineConfig({
// …
agents: false, // disables everything
});Fine-grained control
Pass an object to toggle individual surfaces:
export default defineConfig({
// …
agents: {
robotsTxt: true, // default
llmsTxt: true, // default
mcp: true, // default
oauthDiscovery: true, // default
apiCatalog: true, // default
allowAiCrawlers: true, // default — flip to false to Disallow in robots.txt
},
});The MCP server
Tools
Every operation in your generated OpenAPI spec becomes one MCP tool. The tool name is the operation's operationId (e.g. listCustomers, createInvoice, sendInvoice). Each tool's inputSchema is a flat JSON Schema combining path params, query params, and the request body.
tools/call re-enters the same Hono app via app.request(...) — so every existing middleware runs exactly as it would for a direct REST call: authentication, firewall, access control, guards, masking. No bypass.
Access-filtered tools/list
tools/list only returns tools the calling identity could actually invoke. Each generated tool entry carries the operation's access metadata (roles, userRole, or / and combinators) and tools/list filters against ctx before responding:
- Unauthenticated callers see only tools whose access declares the
PUBLICpseudo-role, or operations that have no security requirement at all (e.g. sign-in / sign-up). - Authenticated callers see tools whose role gate intersects their
ctx.rolesorctx.userRole. Admin-only endpoints don't appear for non-admins. - Function-form access (escape hatch) is opaque at list time — surfaced to any authenticated caller, then evaluated for real on
tools/call. - Record predicates are dropped from the list-time check (no record yet) and applied normally on the actual call.
This is recon-mitigation, not a security boundary. Hiding a tool from the list never weakens the underlying gate — tools/call still runs the full middleware chain and rejects unauthorized invocations the same way a direct REST call would.
The unauthenticated GET /mcp discovery payload returns server info only; it does not enumerate tool names. Inventory is exclusively available via the access-filtered tools/list.
Authentication
MCP clients pass their credentials through the standard Authorization: Bearer <jwt> header. The generated MCP handler forwards the header verbatim into the internal request, and the same JWT middleware that guards /api/v1/* validates it.
Mint a JWT from an authenticated session:
curl -X POST https://my-api.example.com/api/v1/token \
-H "Cookie: better-auth.session_token=..." \
-H "Content-Type: application/json"Connecting clients
Claude Desktop — add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"my-api": {
"url": "https://my-api.example.com/mcp",
"headers": {
"Authorization": "Bearer <jwt>"
}
}
}
}Cursor — use the same config shape under .cursor/mcp.json.
Quick sanity check with curl:
# List available tools
curl -X POST https://my-api.example.com/mcp \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# Call a tool
curl -X POST https://my-api.example.com/mcp \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"listCustomers","arguments":{"limit":10}}}'Transport
The server speaks the Streamable HTTP MCP transport — JSON-RPC 2.0 over POST. A plain GET /mcp returns the server info document for sanity checks.
The MCP route does not emit its own CORS headers. The Worker's existing cors() middleware applies uniformly, so browser-origin access is governed by the same allowlist as the rest of the API (auth.trustedOrigins + the deploy origin). Server-to-server clients (Claude Desktop, Cursor, MCP Inspector) connect with a Bearer token and don't need browser CORS at all. If you want a browser-based MCP client (ChatGPT, Claude.ai) to connect cross-origin, add its origin to auth.trustedOrigins like any other web client.
Verification
After you deploy, scan both the REST and MCP surfaces:
# Agent-readiness scan (external)
open https://isitagentready.com/?url=https://my-api.example.com
# MCP Inspector (official tool)
npx @modelcontextprotocol/inspector https://my-api.example.com/mcp