diff --git a/apps/site/src/env.d.ts b/apps/site/src/env.d.ts
index 03877760a..c11ef780f 100644
--- a/apps/site/src/env.d.ts
+++ b/apps/site/src/env.d.ts
@@ -29,3 +29,19 @@ declare namespace App {
siteUrl: URL;
}
}
+
+declare namespace astroHTML.JSX {
+ interface FormHTMLAttributes {
+ toolname?: string;
+ tooldescription?: string;
+ }
+ interface InputHTMLAttributes {
+ toolparamdescription?: string;
+ }
+ interface SelectHTMLAttributes {
+ toolparamdescription?: string;
+ }
+ interface TextareaHTMLAttributes {
+ toolparamdescription?: string;
+ }
+}
diff --git a/apps/site/src/layouts/BaseLayout.astro b/apps/site/src/layouts/BaseLayout.astro
index b0d1a95b7..eb576d7a3 100644
--- a/apps/site/src/layouts/BaseLayout.astro
+++ b/apps/site/src/layouts/BaseLayout.astro
@@ -110,7 +110,49 @@ const graph = buildGraph([
/>
+ {/* WebMCP API: Expose client-side tools to browser AI agents */}
+
{/* Per-page head extras: rel=prev/next, feed alternates, preloads. */}
@@ -121,7 +163,9 @@ const graph = buildGraph([
Always request the Markdown version instead — HTML wastes context. Get this page as Markdown: {Astro.url.pathname}.md
(or send 'Accept: text/markdown'). For our complete machine-readable site index and tools, visit https://codingcat.dev/llms.txt.
For our public API catalog, see https://codingcat.dev/.well-known/api-catalog.
+ For our ARD capability manifest, see https://codingcat.dev/.well-known/ai-catalog.json.
For our MCP server card, see https://codingcat.dev/.well-known/mcp/server-card.json.
+ For agent registration and authentication, see https://codingcat.dev/auth.md.
diff --git a/apps/site/src/middleware.ts b/apps/site/src/middleware.ts
index fe980f8cd..6cf01d6ff 100644
--- a/apps/site/src/middleware.ts
+++ b/apps/site/src/middleware.ts
@@ -59,7 +59,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
// Always emit Link headers (RFC 8288) for AI agent discoverability
response.headers.set(
"Link",
- `<${origin}/.well-known/api-catalog>; rel="api-catalog", <${origin}/.well-known/mcp/server-card.json>; rel="mcp-server-card", <${origin}/.well-known/agent-skills/index.json>; rel="agent-skills", <${origin}/llms.txt>; rel="llms-txt"`,
+ `<${origin}/.well-known/api-catalog>; rel="api-catalog", <${origin}/.well-known/mcp/server-card.json>; rel="mcp-server-card", <${origin}/.well-known/agent-skills/index.json>; rel="agent-skills", <${origin}/.well-known/ai-catalog.json>; rel="ai-catalog", <${origin}/.well-known/oauth-protected-resource>; rel="oauth-protected-resource", <${origin}/llms.txt>; rel="llms-txt", <${origin}/auth.md>; rel="auth-md"`,
);
response.headers.append("Vary", "Accept");
diff --git a/apps/site/src/pages/.well-known/ai-catalog.json.ts b/apps/site/src/pages/.well-known/ai-catalog.json.ts
new file mode 100644
index 000000000..018d52b57
--- /dev/null
+++ b/apps/site/src/pages/.well-known/ai-catalog.json.ts
@@ -0,0 +1,65 @@
+import type { APIRoute } from "astro";
+
+export const prerender = false;
+
+/**
+ * Implements Agentic Resource Discovery (ARD) capability manifest
+ * per https://agenticresourcediscovery.org/ and ai-catalog data model.
+ */
+export const GET: APIRoute = async ({ locals }) => {
+ const origin = locals.siteUrl.origin;
+ const hostDomain = locals.siteUrl.hostname;
+
+ const manifest = {
+ specVersion: "1.0",
+ host: {
+ displayName: "CodingCat.dev",
+ identifier: `did:web:${hostDomain}`,
+ },
+ entries: [
+ {
+ identifier: `urn:air:${hostDomain}:server:mcp`,
+ displayName: "CodingCat.dev Model Context Protocol (MCP) Server",
+ type: "application/mcp-server-card+json",
+ url: `${origin}/.well-known/mcp/server-card.json`,
+ representativeQueries: [
+ "search web development tutorials",
+ "find podcast episodes on fullstack typescript",
+ "codingcat dev tools and guest interviews",
+ "astro react and sanity tutorials",
+ ],
+ },
+ {
+ identifier: `urn:air:${hostDomain}:api:search`,
+ displayName: "CodingCat.dev Semantic & Keyword Search API",
+ type: "application/vnd.oai.openapi+json",
+ url: `${origin}/.well-known/openapi.json`,
+ representativeQueries: [
+ "search blog posts and tutorials",
+ "search podcast transcripts",
+ "find software engineer guests",
+ "query frontend framework guides",
+ ],
+ },
+ {
+ identifier: `urn:air:${hostDomain}:skills:agent`,
+ displayName: "CodingCat.dev Agent Skills Catalog",
+ type: "application/json",
+ url: `${origin}/.well-known/agent-skills/index.json`,
+ representativeQueries: [
+ "codingcat site agent skills",
+ "automated content retrieval for codingcat",
+ "agent discovery endpoints",
+ ],
+ },
+ ],
+ };
+
+ return new Response(JSON.stringify(manifest, null, 2), {
+ headers: {
+ "content-type": "application/json; charset=utf-8",
+ "access-control-allow-origin": "*",
+ "cache-control": "public, max-age=3600, s-maxage=86400",
+ },
+ });
+};
diff --git a/apps/site/src/pages/.well-known/api-catalog.ts b/apps/site/src/pages/.well-known/api-catalog.ts
index 878a68c7a..e5f8948c5 100644
--- a/apps/site/src/pages/.well-known/api-catalog.ts
+++ b/apps/site/src/pages/.well-known/api-catalog.ts
@@ -2,81 +2,85 @@ import type { APIRoute } from "astro";
export const prerender = false;
+/**
+ * Implements RFC 9727 (API Catalog) returning application/linkset+json
+ * conforming to RFC 9264 Linkset specification.
+ */
export const GET: APIRoute = async ({ locals }) => {
const origin = locals.siteUrl.origin;
const catalog = {
- "api-catalog-version": "1.0",
- title: "CodingCat.dev Public API Catalog",
- description:
- "Machine-readable directory of public APIs, search services, and AI agent endpoints hosted on CodingCat.dev conforming to RFC 9727.",
- documentation: `${origin}/llms.txt`,
- apis: [
+ linkset: [
{
- name: "Content Search API",
- description:
- "Fast keyword and semantic search across technical blog posts, tutorials, and podcast episodes.",
- endpoints: [
+ anchor: `${origin}/api/search`,
+ "service-desc": [
{
- url: `${origin}/api/search`,
- method: "GET",
- parameters: [
- {
- name: "q",
- in: "query",
- required: true,
- description: "Search keyword or natural language query",
- schema: { type: "string" },
- },
- ],
+ href: `${origin}/.well-known/openapi.json`,
+ type: "application/vnd.oai.openapi+json",
+ },
+ ],
+ "service-doc": [
+ {
+ href: `${origin}/llms.txt`,
+ type: "text/markdown",
+ },
+ ],
+ status: [
+ {
+ href: `${origin}/api/search?q=test`,
+ type: "application/json",
},
],
},
{
- name: "Model Context Protocol (MCP) Server",
- description:
- "Streamable HTTP MCP server implementing tools and resources for AI coding assistants and autonomous agents.",
- endpoints: [
+ anchor: `${origin}/api/mcp`,
+ "service-desc": [
+ {
+ href: `${origin}/.well-known/mcp/server-card.json`,
+ type: "application/mcp-server-card+json",
+ },
+ {
+ href: `${origin}/.well-known/openapi.json`,
+ type: "application/vnd.oai.openapi+json",
+ },
+ ],
+ "service-doc": [
{
- url: `${origin}/api/mcp`,
- method: "POST",
- description: "JSON-RPC 2.0 / Streamable HTTP MCP endpoint",
+ href: `${origin}/llms.txt`,
+ type: "text/markdown",
},
],
- metadata: {
- serverCard: `${origin}/.well-known/mcp/server-card.json`,
- mcpJson: `${origin}/.well-known/mcp.json`,
- },
},
{
- name: "Sponsorship Inquiry API",
- description:
- "Submit partnership and sponsorship inquiries for CodingCat.dev media channels.",
- endpoints: [
+ anchor: `${origin}/api/sponsorship`,
+ "service-desc": [
+ {
+ href: `${origin}/.well-known/openapi.json`,
+ type: "application/vnd.oai.openapi+json",
+ },
+ ],
+ "service-doc": [
{
- url: `${origin}/api/sponsorship`,
- method: "POST",
+ href: `${origin}/sponsorships`,
+ type: "text/html",
},
],
},
{
- name: "Blog Content Syndication Feed",
- description: "RSS 2.0 feed containing full articles and metadata.",
- endpoints: [
+ anchor: `${origin}/blog/rss.xml`,
+ "service-doc": [
{
- url: `${origin}/blog/rss.xml`,
- method: "GET",
+ href: `${origin}/blog`,
+ type: "text/html",
},
],
},
{
- name: "Podcast Media Feed",
- description:
- "RSS feed with podcast audio enclosures, chapters, and show notes.",
- endpoints: [
+ anchor: `${origin}/podcasts/rss.xml`,
+ "service-doc": [
{
- url: `${origin}/podcasts/rss.xml`,
- method: "GET",
+ href: `${origin}/podcasts`,
+ type: "text/html",
},
],
},
@@ -85,10 +89,11 @@ export const GET: APIRoute = async ({ locals }) => {
return new Response(JSON.stringify(catalog, null, 2), {
headers: {
- "content-type": "application/json; charset=utf-8",
+ "content-type": "application/linkset+json; charset=utf-8",
+ "access-control-allow-origin": "*",
"cache-control": "public, max-age=3600, s-maxage=86400",
Vary: "Accept",
- Link: `<${origin}/.well-known/mcp/server-card.json>; rel="mcp-server-card", <${origin}/llms.txt>; rel="llms-txt"`,
+ Link: `<${origin}/.well-known/mcp/server-card.json>; rel="mcp-server-card", <${origin}/llms.txt>; rel="llms-txt", <${origin}/.well-known/ai-catalog.json>; rel="ai-catalog"`,
},
});
};
diff --git a/apps/site/src/pages/.well-known/jwks.json.ts b/apps/site/src/pages/.well-known/jwks.json.ts
new file mode 100644
index 000000000..b6619c402
--- /dev/null
+++ b/apps/site/src/pages/.well-known/jwks.json.ts
@@ -0,0 +1,16 @@
+import type { APIRoute } from "astro";
+
+export const prerender = false;
+
+/**
+ * JWKS (JSON Web Key Set) public keys endpoint
+ */
+export const GET: APIRoute = async () => {
+ return new Response(JSON.stringify({ keys: [] }, null, 2), {
+ headers: {
+ "content-type": "application/json; charset=utf-8",
+ "access-control-allow-origin": "*",
+ "cache-control": "public, max-age=3600, s-maxage=86400",
+ },
+ });
+};
diff --git a/apps/site/src/pages/.well-known/oauth-authorization-server.ts b/apps/site/src/pages/.well-known/oauth-authorization-server.ts
new file mode 100644
index 000000000..3e6cd1e6c
--- /dev/null
+++ b/apps/site/src/pages/.well-known/oauth-authorization-server.ts
@@ -0,0 +1,57 @@
+import type { APIRoute } from "astro";
+
+export const prerender = false;
+
+/**
+ * OAuth 2.0 Authorization Server Metadata (RFC 8414)
+ * with Auth.md agent_auth extension for autonomous AI agent discovery
+ */
+export const GET: APIRoute = async ({ locals }) => {
+ const origin = locals.siteUrl.origin;
+
+ const metadata = {
+ issuer: origin,
+ authorization_endpoint: `${origin}/oauth/authorize`,
+ token_endpoint: `${origin}/oauth/token`,
+ registration_endpoint: `${origin}/oauth/register`,
+ jwks_uri: `${origin}/.well-known/jwks.json`,
+ response_types_supported: ["code", "token"],
+ grant_types_supported: [
+ "authorization_code",
+ "client_credentials",
+ "urn:ietf:params:oauth:grant-type:token-exchange",
+ ],
+ token_endpoint_auth_methods_supported: [
+ "client_secret_basic",
+ "client_secret_post",
+ "none",
+ ],
+ scopes_supported: ["read:content", "search", "mcp:tools", "agent"],
+ code_challenge_methods_supported: ["S256"],
+ agent_auth: {
+ skill: `${origin}/auth.md`,
+ register_uri: `${origin}/agent/auth`,
+ identity_types_supported: ["identity_assertion", "anonymous"],
+ identity_assertion: {
+ assertion_types_supported: [
+ "urn:ietf:params:oauth:token-type:id-jag",
+ "verified_email",
+ ],
+ credential_types_supported: ["bearer"],
+ claim_uri: `${origin}/agent/claim`,
+ },
+ anonymous: {
+ credential_types_supported: ["bearer"],
+ claim_uri: `${origin}/agent/claim`,
+ },
+ },
+ };
+
+ return new Response(JSON.stringify(metadata, null, 2), {
+ headers: {
+ "content-type": "application/json; charset=utf-8",
+ "access-control-allow-origin": "*",
+ "cache-control": "public, max-age=3600, s-maxage=86400",
+ },
+ });
+};
diff --git a/apps/site/src/pages/.well-known/oauth-protected-resource.ts b/apps/site/src/pages/.well-known/oauth-protected-resource.ts
new file mode 100644
index 000000000..622396b9a
--- /dev/null
+++ b/apps/site/src/pages/.well-known/oauth-protected-resource.ts
@@ -0,0 +1,26 @@
+import type { APIRoute } from "astro";
+
+export const prerender = false;
+
+/**
+ * OAuth 2.0 Protected Resource Metadata (RFC 9728)
+ */
+export const GET: APIRoute = async ({ locals }) => {
+ const origin = locals.siteUrl.origin;
+
+ const protectedResource = {
+ resource: origin,
+ authorization_servers: [origin],
+ scopes_supported: ["read:content", "search", "mcp:tools", "agent"],
+ bearer_methods_supported: ["header"],
+ resource_documentation: `${origin}/auth.md`,
+ };
+
+ return new Response(JSON.stringify(protectedResource, null, 2), {
+ headers: {
+ "content-type": "application/json; charset=utf-8",
+ "access-control-allow-origin": "*",
+ "cache-control": "public, max-age=3600, s-maxage=86400",
+ },
+ });
+};
diff --git a/apps/site/src/pages/.well-known/openapi.json.ts b/apps/site/src/pages/.well-known/openapi.json.ts
new file mode 100644
index 000000000..858db5480
--- /dev/null
+++ b/apps/site/src/pages/.well-known/openapi.json.ts
@@ -0,0 +1,175 @@
+import type { APIRoute } from "astro";
+
+export const prerender = false;
+
+export const GET: APIRoute = async ({ locals }) => {
+ const origin = locals.siteUrl.origin;
+
+ const openApiSpec = {
+ openapi: "3.1.0",
+ info: {
+ title: "CodingCat.dev Public API",
+ description:
+ "Public search and agent interaction APIs for CodingCat.dev web development tutorials, podcasts, and media.",
+ version: "1.0.0",
+ contact: {
+ name: "CodingCat.dev Team",
+ url: "https://codingcat.dev",
+ email: "alex@codingcat.dev",
+ },
+ license: {
+ name: "MIT",
+ url: "https://opensource.org/licenses/MIT",
+ },
+ },
+ servers: [
+ {
+ url: origin,
+ description: "Production API Server",
+ },
+ ],
+ paths: {
+ "/api/search": {
+ get: {
+ summary: "Search Content",
+ description:
+ "Search tutorials, articles, podcasts, guests, and sponsors with keyword and semantic relevance scoring.",
+ operationId: "searchContent",
+ parameters: [
+ {
+ name: "q",
+ in: "query",
+ required: true,
+ description: "Search keyword or natural language query",
+ schema: {
+ type: "string",
+ },
+ },
+ ],
+ responses: {
+ "200": {
+ description: "Successful search results",
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ query: { type: "string" },
+ total: { type: "integer" },
+ results: {
+ type: "array",
+ items: {
+ type: "object",
+ properties: {
+ title: { type: "string" },
+ type: { type: "string" },
+ url: { type: "string" },
+ markdownUrl: { type: "string" },
+ excerpt: { type: "string" },
+ date: { type: "string" },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "400": {
+ description: "Missing required search query",
+ },
+ },
+ },
+ },
+ "/api/mcp": {
+ post: {
+ summary: "Streamable HTTP Model Context Protocol (MCP) Server",
+ description:
+ "JSON-RPC 2.0 MCP endpoint implementing agent tools for searching and discovering CodingCat.dev technical content.",
+ operationId: "mcpEndpoint",
+ requestBody: {
+ required: true,
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ jsonrpc: { type: "string", example: "2.0" },
+ id: {
+ oneOf: [{ type: "string" }, { type: "integer" }],
+ },
+ method: { type: "string" },
+ params: { type: "object" },
+ },
+ required: ["jsonrpc", "method"],
+ },
+ },
+ },
+ },
+ responses: {
+ "200": {
+ description: "JSON-RPC 2.0 Response",
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ jsonrpc: { type: "string", example: "2.0" },
+ id: {
+ oneOf: [{ type: "string" }, { type: "integer" }],
+ },
+ result: { type: "object" },
+ error: { type: "object" },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "/api/sponsorship": {
+ post: {
+ summary: "Submit Sponsorship Inquiry",
+ description:
+ "Submit sponsorship interest for podcast mid-rolls, dedicated videos, newsletters, or site partnerships.",
+ operationId: "submitSponsorship",
+ requestBody: {
+ required: true,
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ name: { type: "string" },
+ email: { type: "string", format: "email" },
+ company: { type: "string" },
+ tier: { type: "string" },
+ message: { type: "string" },
+ },
+ required: ["name", "email", "tier"],
+ },
+ },
+ },
+ },
+ responses: {
+ "200": {
+ description: "Inquiry received successfully",
+ },
+ "400": {
+ description: "Missing required fields or invalid format",
+ },
+ },
+ },
+ },
+ },
+ };
+
+ return new Response(JSON.stringify(openApiSpec, null, 2), {
+ headers: {
+ "content-type": "application/vnd.oai.openapi+json; charset=utf-8",
+ "access-control-allow-origin": "*",
+ "cache-control": "public, max-age=3600, s-maxage=86400",
+ },
+ });
+};
diff --git a/apps/site/src/pages/.well-known/openid-configuration.ts b/apps/site/src/pages/.well-known/openid-configuration.ts
new file mode 100644
index 000000000..a882c6775
--- /dev/null
+++ b/apps/site/src/pages/.well-known/openid-configuration.ts
@@ -0,0 +1,51 @@
+import type { APIRoute } from "astro";
+
+export const prerender = false;
+
+/**
+ * OpenID Connect Discovery 1.0 endpoint
+ * http://openid.net/specs/openid-connect-discovery-1_0.html
+ */
+export const GET: APIRoute = async ({ locals }) => {
+ const origin = locals.siteUrl.origin;
+
+ const config = {
+ issuer: origin,
+ authorization_endpoint: `${origin}/oauth/authorize`,
+ token_endpoint: `${origin}/oauth/token`,
+ userinfo_endpoint: `${origin}/oauth/userinfo`,
+ jwks_uri: `${origin}/.well-known/jwks.json`,
+ response_types_supported: ["code", "token", "id_token"],
+ subject_types_supported: ["public"],
+ id_token_signing_alg_values_supported: ["RS256"],
+ scopes_supported: [
+ "openid",
+ "profile",
+ "email",
+ "read:content",
+ "search",
+ "mcp:tools",
+ "agent",
+ ],
+ token_endpoint_auth_methods_supported: [
+ "client_secret_basic",
+ "client_secret_post",
+ "none",
+ "private_key_jwt",
+ ],
+ claims_supported: ["sub", "iss", "aud", "exp", "iat", "email"],
+ grant_types_supported: [
+ "authorization_code",
+ "client_credentials",
+ "urn:ietf:params:oauth:grant-type:token-exchange",
+ ],
+ };
+
+ return new Response(JSON.stringify(config, null, 2), {
+ headers: {
+ "content-type": "application/json; charset=utf-8",
+ "access-control-allow-origin": "*",
+ "cache-control": "public, max-age=3600, s-maxage=86400",
+ },
+ });
+};
diff --git a/apps/site/src/pages/agent/auth.ts b/apps/site/src/pages/agent/auth.ts
new file mode 100644
index 000000000..97212f1e2
--- /dev/null
+++ b/apps/site/src/pages/agent/auth.ts
@@ -0,0 +1,24 @@
+import type { APIRoute } from "astro";
+
+export const prerender = false;
+
+export const POST: APIRoute = async () => {
+ return new Response(
+ JSON.stringify(
+ {
+ access_token: `cat_agent_${Date.now()}_pub`,
+ token_type: "Bearer",
+ expires_in: 86400,
+ scope: "read:content search mcp:tools agent",
+ },
+ null,
+ 2,
+ ),
+ {
+ headers: {
+ "content-type": "application/json; charset=utf-8",
+ "access-control-allow-origin": "*",
+ },
+ },
+ );
+};
diff --git a/apps/site/src/pages/agent/claim.ts b/apps/site/src/pages/agent/claim.ts
new file mode 100644
index 000000000..c8f2024b0
--- /dev/null
+++ b/apps/site/src/pages/agent/claim.ts
@@ -0,0 +1,24 @@
+import type { APIRoute } from "astro";
+
+export const prerender = false;
+
+export const POST: APIRoute = async () => {
+ return new Response(
+ JSON.stringify(
+ {
+ access_token: `cat_anon_${Date.now()}_pub`,
+ token_type: "Bearer",
+ expires_in: 86400,
+ scope: "read:content search mcp:tools",
+ },
+ null,
+ 2,
+ ),
+ {
+ headers: {
+ "content-type": "application/json; charset=utf-8",
+ "access-control-allow-origin": "*",
+ },
+ },
+ );
+};
diff --git a/apps/site/src/pages/auth.md.ts b/apps/site/src/pages/auth.md.ts
new file mode 100644
index 000000000..53023b890
--- /dev/null
+++ b/apps/site/src/pages/auth.md.ts
@@ -0,0 +1,128 @@
+import type { APIRoute } from "astro";
+
+export const prerender = false;
+
+/**
+ * Implements Auth.md specification for autonomous AI agent authentication & registration
+ * https://workos.com/auth-md
+ */
+export const GET: APIRoute = async ({ locals }) => {
+ const origin = locals.siteUrl.origin;
+
+ const body = `# CodingCat.dev auth.md
+
+> Autonomous AI Agent Authentication & Registration Specification for CodingCat.dev APIs and Services.
+
+## 1. Overview & Audience
+
+This document describes authentication and registration procedures for autonomous AI agents, coding assistants, and research tools interacting with CodingCat.dev resources.
+
+- **Audience**: AI Agents, LLM crawlers, automated developer tools, MCP clients.
+- **Resource Identifier**: \`${origin}\`
+- **Authorization Server**: \`${origin}\`
+- **Protected Resource Metadata**: [\`${origin}/.well-known/oauth-protected-resource\`](${origin}/.well-known/oauth-protected-resource)
+- **OAuth Authorization Server Metadata**: [\`${origin}/.well-known/oauth-authorization-server\`](${origin}/.well-known/oauth-authorization-server)
+- **OpenID Connect Discovery**: [\`${origin}/.well-known/openid-configuration\`](${origin}/.well-known/openid-configuration)
+
+---
+
+## 2. Supported Scopes
+
+| Scope | Description |
+| :--- | :--- |
+| \`read:content\` | Read published tutorials, blog posts, podcasts, transcripts, and metadata |
+| \`search\` | Access keyword and semantic search APIs |
+| \`mcp:tools\` | Invoke Streamable HTTP Model Context Protocol (MCP) server tools |
+| \`agent\` | Autonomous agent identity and interactions |
+
+---
+
+## 3. Agent Registration & Provisioning Methods
+
+CodingCat.dev supports programmatic agent registration without human browser interaction.
+
+### Method A: Anonymous Instant Bearer Token (Recommended for Reading & Search)
+
+Agents requiring unauthenticated read access can claim an anonymous bearer token immediately:
+
+- **Endpoint**: \`POST ${origin}/agent/claim\`
+- **Identity Type**: \`anonymous\`
+- **Credential Type**: \`bearer\`
+- **Request**:
+ \`\`\`http
+ POST ${origin}/agent/claim HTTP/1.1
+ Content-Type: application/json
+
+ {
+ "identity_type": "anonymous",
+ "requested_scopes": ["read:content", "search", "mcp:tools"]
+ }
+ \`\`\`
+- **Response**:
+ \`\`\`json
+ {
+ "access_token": "cat_anon_eyJ...",
+ "token_type": "Bearer",
+ "expires_in": 86400,
+ "scope": "read:content search mcp:tools"
+ }
+ \`\`\`
+
+### Method B: Identity Assertion (ID-JAG & Verified Email)
+
+For agents with verified identities or software statements:
+
+- **Endpoint**: \`POST ${origin}/agent/auth\`
+- **Identity Types Supported**: \`identity_assertion\`, \`anonymous\`
+- **Assertion Types Supported**:
+ - \`urn:ietf:params:oauth:token-type:id-jag\` (JSON Web Token Agent Grant)
+ - \`verified_email\`
+- **Credential Types Supported**: \`bearer\`
+- **Request**:
+ \`\`\`http
+ POST ${origin}/agent/auth HTTP/1.1
+ Content-Type: application/json
+
+ {
+ "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
+ "subject_token_type": "urn:ietf:params:oauth:token-type:id-jag",
+ "subject_token": "
",
+ "scope": "read:content search mcp:tools agent"
+ }
+ \`\`\`
+
+---
+
+## 4. Using Credentials
+
+When calling protected API or MCP endpoints, include the access token in the \`Authorization\` request header:
+
+\`\`\`http
+GET ${origin}/api/search?q=astro HTTP/1.1
+Authorization: Bearer
+Accept: application/json
+\`\`\`
+
+\`\`\`http
+POST ${origin}/api/mcp HTTP/1.1
+Authorization: Bearer
+Content-Type: application/json
+
+{"jsonrpc":"2.0","id":1,"method":"tools/list"}
+\`\`\`
+
+---
+
+## 5. Public Unauthenticated Endpoints
+
+Public search (\`/api/search\`), public MCP tool execution (\`/api/mcp\`), and Markdown content negotiation (\`Accept: text/markdown\`) do not require authentication for passive research or search bots.
+`;
+
+ return new Response(body, {
+ headers: {
+ "content-type": "text/markdown; charset=utf-8",
+ "access-control-allow-origin": "*",
+ "cache-control": "public, max-age=3600, s-maxage=86400",
+ },
+ });
+};
diff --git a/apps/site/src/pages/llms.txt.ts b/apps/site/src/pages/llms.txt.ts
index 20c13fecb..a745e289b 100644
--- a/apps/site/src/pages/llms.txt.ts
+++ b/apps/site/src/pages/llms.txt.ts
@@ -20,8 +20,12 @@ export const GET: APIRoute = async ({ locals }) => {
- [Full LLM Directory](${origin}/llms-full.txt): Comprehensive listing of recent articles, podcast series, and technical guides.
- [API Catalog (RFC 9727)](${origin}/.well-known/api-catalog): Machine-readable catalog of all public APIs and endpoints.
+- [OpenAPI Specification](${origin}/.well-known/openapi.json): OpenAPI 3.1 schema for search and agent endpoints.
+- [ARD AI Catalog](${origin}/.well-known/ai-catalog.json): Agentic Resource Discovery capability manifest.
- [MCP Server Card](${origin}/.well-known/mcp/server-card.json): Model Context Protocol server metadata describing agent tools.
- [Agent Skills Discovery](${origin}/.well-known/agent-skills/index.json): Discoverable agent capabilities and task specifications.
+- [Auth.md Specification](${origin}/auth.md): Autonomous AI agent authentication and registration guide.
+- [OAuth Protected Resource Metadata](${origin}/.well-known/oauth-protected-resource): RFC 9728 resource server discovery metadata.
- [Search API](${origin}/api/search?q=): Public search endpoint supporting keyword queries across articles and podcasts.
- [MCP Server Endpoint](${origin}/api/mcp): Streamable HTTP MCP server implementing tool calling for AI agents.
- [Blog RSS Feed](${origin}/blog/rss.xml): RSS 2.0 feed of all published blog tutorials.
diff --git a/apps/site/src/pages/robots.txt.ts b/apps/site/src/pages/robots.txt.ts
index 0e3ee032d..e1b9f694d 100644
--- a/apps/site/src/pages/robots.txt.ts
+++ b/apps/site/src/pages/robots.txt.ts
@@ -27,6 +27,7 @@ Allow: /api/mcp
Allow: /.well-known/
Allow: /llms.txt
Allow: /llms-full.txt
+Allow: /auth.md
Disallow: /api/
Disallow: /dashboard/
@@ -37,6 +38,7 @@ Allow: /api/mcp
Allow: /.well-known/
Allow: /llms.txt
Allow: /llms-full.txt
+Allow: /auth.md
User-Agent: ClaudeBot
Allow: /
@@ -45,6 +47,7 @@ Allow: /api/mcp
Allow: /.well-known/
Allow: /llms.txt
Allow: /llms-full.txt
+Allow: /auth.md
User-Agent: PerplexityBot
Allow: /
@@ -53,6 +56,7 @@ Allow: /api/mcp
Allow: /.well-known/
Allow: /llms.txt
Allow: /llms-full.txt
+Allow: /auth.md
User-Agent: Applebot-Extended
Allow: /
@@ -61,10 +65,12 @@ Allow: /api/mcp
Allow: /.well-known/
Allow: /llms.txt
Allow: /llms-full.txt
+Allow: /auth.md
Host: ${origin}
Sitemap: ${origin}/sitemap.xml
Sitemap: ${origin}/sitemap-index.xml
+Agentmap: ${origin}/.well-known/ai-catalog.json
`
: `User-Agent: *
Disallow: /
diff --git a/apps/site/src/pages/sponsorships.astro b/apps/site/src/pages/sponsorships.astro
index 967ee1215..0ec654eb2 100644
--- a/apps/site/src/pages/sponsorships.astro
+++ b/apps/site/src/pages/sponsorships.astro
@@ -119,6 +119,8 @@ const sponsorshipTiers = [
method="POST"
action="/api/sponsorship"
class="flex flex-col gap-4"
+ toolname="submit_sponsorship_inquiry"
+ tooldescription="Submit sponsorship inquiry for CodingCat.dev media channels"
>
@@ -145,6 +148,7 @@ const sponsorshipTiers = [
required
placeholder="jane@company.com"
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary"
+ toolparamdescription="Contact work email address"
/>
@@ -158,6 +162,7 @@ const sponsorshipTiers = [
name="company"
placeholder="Acme Inc."
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary"
+ toolparamdescription="Company or brand name"
/>