mudko
← back

Docs

Once you generate the file bundle (via the free toolsor as a paid customer), here's how to wire it onto common hosts so a scanner returns level 5.

Where each file goes

Read this before you upload. The bundle has files in two places: inside .well-known/ and at the site root. Mixing them up is the #1 deploy failure.

🚨 DO NOT FLATTEN the archive

The .well-known/ folder is a literal directory required by IETF RFC 8615 — not a label, not optional. If you drag everything into one folder before uploading, your site will fail in subtle ways (extensionless files at root cause Apache 500s; agents probing /.well-known/ find nothing).

Preserve the directory structure exactly as it is in the ZIP.

Source → destination
THIS ZIP                                    YOUR WEB ROOT
─────────────────────────                   ─────────────────────────
.well-known/                                .well-known/                        ← KEEP this folder
├── agent-card.json              ━━━━━▶     ├── agent-card.json
├── api-catalog                  ━━━━━▶     ├── api-catalog
├── oauth-authorization-server   ━━━━━▶     ├── oauth-authorization-server
├── oauth-protected-resource     ━━━━━▶     ├── oauth-protected-resource
├── openid-configuration         ━━━━━▶     ├── openid-configuration
├── service-doc                  ━━━━━▶     ├── service-doc
├── mcp/                                    ├── mcp/
│   └── server-card.json         ━━━━━▶     │   └── server-card.json
└── agent-skills/                           └── agent-skills/
    ├── index.json               ━━━━━▶         ├── index.json
    └── <skill>/SKILL.md         ━━━━━▶         └── <skill>/SKILL.md
webmcp.js                        ━━━━━▶     webmcp.js                           ← root, NOT in .well-known/
robots.txt                       ━━━━━▶     robots.txt                          ← root, OVERWRITES existing
llms.txt                         ━━━━━▶     llms.txt                            ← root
Where is "web root" on your host?
  • Vercel / Next.js: apps/web/public/ (or public/)
  • Netlify / Cloudflare Pages: public/ in your repo
  • Astro / SvelteKit / Eleventy: public/ (or static/)
  • cPanel shared hosting: public_html/ (or public_html/<addon-domain>/ if it's an addon domain)
  • WordPress: same folder as index.php — use FTP, NOT a plugin upload UI (those mangle directory structure)
  • GitHub Pages / static / S3 / R2: alongside index.html

Common mistakes

Read this before you deploy. These are the failures we see most often.

1. Uploading only the .well-known/ folder

The kit bundle has files at two levels: .well-known/* AND root-level files (webmcp.js, robots.txt,llms.txt). Many users upload just the folder via FTP and miss the rest.

Symptom:Scanner shows agent-card pass but webmcp-bridge + llms-txt fail. Stuck at L1 because the host's default robots.txt is still being served.

Fix: Upload every file in the bundle preserving the directory structure. If you used the ZIP, extract it and upload all top-level entries.

2. Not adding the <script> tag

/webmcp.jsonly registers tools when the page loads it. The kit can't edit your HTML for you.

Fix: Add this line inside <head> on every page (or the shared template):

<script src="/webmcp.js"></script>
3. Default robots.txt not overwritten

Shared hosts (cPanel, GoDaddy, Bluehost) ship a default robots.txt with rules for MSNBot, Slurp, Teoma, etc. — circa 2010 search engines. Without overwriting, isitagentready.com countscontentSignals as failing and you stay at L1.

Fix: Upload the kit's robots.txt directly to your site root (public_html/robots.txt on cPanel) and overwrite the existing one. Confirm with: curl https://yoursite.com/robots.txt | grep Content-Signal.

4. /api/mcp is declared but not implemented

The kit-generated mcp/server-card.json declareshttps://yoursite.com/api/mcpas a JSON-RPC endpoint. The kit doesn't implement the server — it's a static-file generator. Agents that try to call your MCP server will hit 500 (or 404 on most hosts).

Three fixes:

  • Free: deploy the Cloudflare Worker template— bind it to /api/mcp/* on your domain. Five-minute job.
  • Pro tier and above (consult-gated, see pricing): we host the MCP server on a CNAME with a real callable surface.
  • Skip it for now — isitagentready.com today only checks the card exists, not the endpoint. Most level computations don't require live MCP.
5. Apache returns 500 instead of 404 for missing files

Many shared hosts have a broken .htaccessthat 500s when a file is missing. Scanners interpret 500 as “endpoint broken” rather than “not implemented”, dragging your level down on optional checks.

Fix: Add to public_html/.htaccess:

ErrorDocument 404 /404.html

Then create a minimal /404.html. This routes all unknown paths through a proper 404 instead of a 500.

6. Markdown content negotiation (Apache one-liner for L3)

The L3 (“Agent-Readable”) check requires that requests with Accept: text/markdown get markdown back. Static /index.md files alone don't pass this — your server has to honor the header.

Fix (Apache + .htaccess):

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{HTTP_ACCEPT} text/markdown
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^$ /index.md [L,T=text/markdown]
  RewriteRule ^([^.]+)$ /$1.md [L,T=text/markdown]
</IfModule>

You also need actual markdown siblings (/index.md, optionally one per page). The kit doesn't generate them — write a one-line summary and you're done.

Verify: curl -H "Accept: text/markdown" https://yoursite.com/ should return markdown, not HTML.

What gets generated

  • .well-known/agent-card.json — A2A 0.3 agent card
  • .well-known/mcp/server-card.json — MCP 2025-06-18 server card
  • .well-known/api-catalog + oauth-* + openid-configuration — RFC 9727 + OAuth discovery
  • .well-known/agent-skills/ — skills index + per-tool SKILL.md
  • /webmcp.js — in-page WebMCP bridge
  • /robots.txt + /llms.txt
Vercel + Next.js (App Router)
Easiest
  1. Drop the generated files into apps/web/public/ (or your repo's public/).
  2. Add a sitemap: apps/<app>/src/app/sitemap.ts (Next.js generates /sitemap.xml).
  3. Add the Link header to every response via next.config.ts headers().
  4. Add a markdown sibling: src/app/index.md/route.ts returns text/markdown.
// next.config.ts
async headers() {
  return [{
    source: "/:path*",
    headers: [{
      key: "Link",
      value: '</.well-known/api-catalog>; rel="api-catalog"',
    }],
  }];
}
Netlify
  1. Place generated files under public/.well-known/ — Netlify serves the contents of public/ at /.
  2. Add a _headers file to set the Link header.
  3. Add a netlify.toml redirect for the markdown sibling if you don't have one.
# public/_headers
/*
  Link: </.well-known/api-catalog>; rel="api-catalog"
Cloudflare Pages
  1. Files under public/ are served at /. Place .well-known/ there.
  2. Add a _headers file (same syntax as Netlify).
  3. For markdown negotiation, add a Cloudflare Worker that responds to /*.md with the markdown variant.
# public/_headers
/*
  Link: </.well-known/api-catalog>; rel="api-catalog"
Static host (GitHub Pages, S3, etc.)
  1. Upload .well-known/ alongside index.html.
  2. Most static hosts cannot set Link headers — set them via your CDN (CloudFront, Fastly) instead, or add a meta-equiv tag in index.html: <meta http-equiv="Link" content="</.well-known/api-catalog>; rel=\"api-catalog\"">.
cPanel / Apache
  1. Upload .well-known/ to public_html/.
  2. Add the Link header in .htaccess.
# .htaccess
Header set Link "</.well-known/api-catalog>; rel=\"api-catalog\""

Verify

After deploying, run a scan against your domain:

curl 'https://mudko.com/api/scan?url=https://yoursite.com'

Or use the UI scanner. Target: level 5.