The web is evolving from a human-only interface to a hybrid ecosystem shared with autonomous AI agents, Large Language Models (LLMs), and smart crawlers. To thrive in this new era, websites must provide structured, machine-readable metadata alongside human-readable HTML.
This post details how we achieved a perfect 100/100 Level 5 Agent-Native score on IsItAgentReady.com by implementing emerging web standards on our static Astro + Cloudflare architecture.
Core Agent Readiness Pillars
1. Discoverability & Content Signals (robots.txt)
AI crawlers require explicit permissions and structured maps to index content responsibly.
- Sitemap Integration: Explicitly declaring
Sitemap: https://blog.induslevel.com/sitemap-index.xmlfor rapid discovery. - AI Content Signals (RFC draft): Adding
Content-Signal: ai-train=no, search=yes, ai-input=noto define exact post-access usage rules. - API Route Protection: Preventing bot pollution by disallowing
/api/endpoints.
User-agent: *
Allow: /
# AI Content Usage Permissions (RFC draft)
Content-Signal: ai-train=no, search=yes, ai-input=no
# Block API routes
Disallow: /api/
Sitemap: https://blog.induslevel.com/sitemap-index.xml
2. HTTP Link Relations (RFC 8288)
Agents rely on standard HTTP headers to navigate site structure without scraping DOM trees.
- RFC 8288 Headers: Configuring
public/_headersto exposeLink: <https://blog.induslevel.com/rss.xml>; rel="alternate"andrel="sitemap". - Identity Anchoring: Associating authorship via
rel="author"pointing to verified identity profiles.
3. API Catalog Discovery (RFC 9727)
Autonomous agents need to discover available API surfaces programmatically before attempting execution. Serving /.well-known/api-catalog with application/linkset+json.
import type { APIRoute } from 'astro';
export const GET: APIRoute = async () => {
const linkset = {
"linkset": [
{
"anchor": "https://blog.induslevel.com/api/newsletter",
"service-doc": "https://blog.induslevel.com/contact"
}
]
};
return new Response(JSON.stringify(linkset), {
headers: { 'Content-Type': 'application/linkset+json' },
});
};
4. A2A Agent Card & MCP Discovery
Exposing application capabilities directly to AI assistants like Claude and Google Antigravity.
// src/pages/.well-known/agent-card.json.ts
import type { APIRoute } from 'astro';
export const GET: APIRoute = async () => {
const card = {
"name": "Indus LeveL Blog Agent",
"version": "1.0.0",
"description": "Autonomous technical blog publishing agent and n8n workflow interface for Indus LeveL.",
"supportedInterfaces": [
{
"url": "https://n8n-server.induslevel.com/webhook/65dad80c-ccce-4d38-992e-bb7f8b4753e5",
"transportProtocol": "http"
}
],
"capabilities": [
{
"id": "cap-drafting",
"name": "Article Drafting",
"description": "Receives topic suggestions and generates technical blog post stubs via n8n workflows."
}
],
"skills": [
{
"id": "skill-technical-writing",
"name": "Technical Guide Generation",
"description": "Drafts expert guides on Linux hardening, virtualization, and cloud security."
}
]
};
return new Response(JSON.stringify(card), {
headers: { 'Content-Type': 'application/json' },
});
};
5. WebMCP Client-Side Tool Registration
Injecting client-side tool declaration scripts to expose our n8n drafting webhook directly to visiting LLM browser sessions.
<script>
function initWebMCP() {
if (navigator.modelContext && typeof navigator.modelContext.provideContext === 'function') {
navigator.modelContext.provideContext({
tools: [
{
name: 'request_article_draft',
description: 'Submit a topic suggestion to Waqar Azeem\'s n8n automation pipeline to draft a new technical guide stub.',
inputSchema: {
type: 'object',
properties: {
topic: { type: 'string', description: 'The technical topic or system setup you want a guide for.' },
level: { type: 'string', enum: ['Beginner', 'Intermediate', 'Advanced'], default: 'Intermediate' }
},
required: ['topic']
},
execute: async (args) => { ... }
}
]
});
}
}
document.addEventListener('astro:page-load', initWebMCP);
initWebMCP();
</script>
The Content Negotiation Journey: Bypassing Cloudflare Caching & WAF
Implementing Accept: text/markdown content negotiation so visiting AI agents receive raw markdown while human visitors see standard HTML turned out to be an incredible architectural challenge.
The Caching & Firewall Traps We Encountered
- Astro Middleware & Pages Interceptors Failed: We initially built an Astro middleware interceptor and Cloudflare Pages Functions (
functions/[[path]].ts). However, Cloudflare's edge CDN caches static pages based only on the URL path, completely ignoringVary: Acceptheaders on standard zones. Cloudflare returned cached HTML before our application code ever executed. - Cloudflare WAF JS Challenges: When automated tools like
curlrequested the site, Cloudflare's Bot Management inspected the TLS Client Hello fingerprint (JA3/JA4). Detecting an automated client, Cloudflare intercepted the request at the edge with a JavaScript WAF challenge page, preventing access to the markdown.
The Definitive Solution: A Standalone Cloudflare Worker
To intercept requests at the very edge in front of the CDN cache, WAF rules, and Pages runtime, we deployed a standalone Cloudflare Worker (markdown-negotiation-interceptor).
Because standalone Workers execute at the absolute perimeter of Cloudflare's network, it intercepts incoming agent traffic before Bot Protection or edge caching can ever evaluate or challenge the connection!
To ensure the Worker stays 100% maintenance-free and up-to-date with newly published articles without hardcoding text or creating circular routing loops, the Worker dynamically fetches our pre-compiled /index.md endpoint with Accept: */*.
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const acceptHeader = request.headers.get("accept") || "";
// Check if request comes from an AI agent requesting Markdown
if (acceptHeader.includes("text/markdown")) {
// Determine dynamic .md endpoint path
const mdPath = (url.pathname === '/' || url.pathname === '') ? '/index.md' : `${url.pathname.replace(/\/$/, '')}.md`;
const markdownUrl = new URL(mdPath, url.origin);
// Fetch the markdown endpoint without forwarding 'Accept: text/markdown' to prevent circular routing loops
const cleanRequest = new Request(markdownUrl, {
method: request.method,
headers: new Headers(request.headers)
});
cleanRequest.headers.set('Accept', '*/*');
const response = await fetch(cleanRequest);
if (response.ok) {
const newHeaders = new Headers(response.headers);
newHeaders.set("Content-Type", "text/markdown; charset=utf-8");
newHeaders.set("x-markdown-tokens", mdPath === '/index.md' ? "150" : "500");
return new Response(response.body, {
status: response.status,
headers: newHeaders
});
}
}
// Default pass-through for standard browsers (HTML)
return fetch(request);
}
};
Attaching the Route (With "Fail Open" Uptime Protection)
To deploy this Worker to our blog domain while guaranteeing 100% bulletproof uptime for human readers on Cloudflare's Free plan (which limits Worker executions to 100,000 per day), we configured our Worker Route with Fail open (proceed):
- Route:
blog.induslevel.com/* - Worker:
markdown-negotiation-interceptor - Failure mode:
Fail open (proceed)
If our blog traffic ever exceeds 100k daily visits, Cloudflare simply bypasses the Worker and continues serving the standard HTML blog to human readers without ever showing an error page!
By pairing this standalone Worker with our dynamic Astro markdown endpoints, we achieved a flawless, maintenance-free, 100% green Agent-Ready publishing platform!