SEO & AI Engine Optimization Framework · May 2026

Model Context Protocol (MCP) for SEO and AI-assisted optimization

A comprehensive installation, audit, and architectural reference for implementing Model Context Protocol (MCP) servers on websites. MCP is the open protocol launched by Anthropic in November 2024 and…

Agent Addressable Sites — Exposing Tools, Resources, and Prompts So AI Agents Can Read, Search, Book, Buy, and Transact on a Website Without a Human in the Loop

A comprehensive installation, audit, and architectural reference for implementing Model Context Protocol (MCP) servers on websites. MCP is the open protocol launched by Anthropic in November 2024 and adopted across the major AI agent ecosystems through 2025 and 2026. It standardizes how AI agents (Claude, ChatGPT through compatible clients, agentic frameworks) connect to external data sources and tools. Originally built for agent-to-application integration (Asana, Slack, GitHub, file systems), MCP is rapidly extending to agent-to-website integration. Sites that expose MCP servers become directly addressable by AI agents performing tasks on behalf of users: booking, buying, comparing, scheduling, inquiring. Sites that do not become invisible to that surface. This document specifies how to build, host, validate, and operate an MCP server for any site type, with a 30-point audit rubric and stack-specific implementation patterns. Dual purpose: installation manual and architectural audit.

Cross stack implementation note: code samples are written in TypeScript using the official @modelcontextprotocol/sdk and Python using the official mcp library. For React, Vue, Svelte frontends, MCP runs server side and is independent of the frontend framework. For Next.js, Nuxt, Astro, and other Node-capable stacks, see Section 10. For PHP/WordPress, Shopify, Webflow, see Section 10.6 for hosted MCP patterns. The doctrine in framework-contentfirst.md continues to apply: the site's substrate is server rendered HTML; the MCP server is a parallel surface for agents.

Doctrine prerequisite: framework-contentfirst.md is the architectural axiom. MCP layers on top. A site that is invisible to AI crawlers because its substrate is not in the first byte will also fail with agents, because agents typically still verify against the site's HTML before trusting MCP responses. Build Content First first. Build MCP second.


1. Document Purpose

This framework systematizes Model Context Protocol implementation for client websites. The document covers what MCP is, why sites must expose MCP servers in 2026, the protocol mechanics, what tools and resources to expose by vertical, where to host the MCP server, how to announce it for discovery, how to authenticate write operations, how to validate end to end with real agent clients, and the audit rubric that determines whether a site is genuinely agent addressable.

The framing assumption: within 12 to 24 months, AI agents acting on behalf of users will be the dominant inbound channel for many transactional intent queries. A user telling Claude or ChatGPT to "book a fishing guide on Lake Taneycomo for Saturday at dawn" will result in the agent querying available MCP servers directly, comparing real availability and pricing, booking the trip, and confirming back to the user. The site whose MCP server returns availability gets the booking. The site without an MCP server gets nothing. This is the next surface after AI citations.

MCP for websites is not yet a saturated topic. No major SEO platform has shipped an opinionated framework for it. Adopting early establishes durable agent-addressability advantage that compounds as agentic AI usage grows.

1.1 Required Understanding

Before reading this framework, the builder should be familiar with:

1.2 Document Scope

Covers: the MCP protocol mechanics, the three primitives (tools, resources, prompts), transport layers (stdio, HTTP, SSE), hosting options, vertical specific tool design, discovery and announcement patterns, authentication and security, validation methodology, retrofit and greenfield strategies, audit rubric. Touches but does not exhaust: backend API design (treated as infrastructure), payment processing (treated as integration), CRM and booking system integration (covered in framework-conversiontracking.md), AI agent UX (covered in framework-agenticaisearch.md).


2. Client Variables Intake

mcp_intake:

  site_type: ""                           # "local_business" | "service_business" | "ecommerce" | "saas" | "content_site" | "b2b" | "nonprofit"
  primary_intent_categories: []           # "booking" | "purchase" | "inquiry" | "information" | "comparison" | "subscription"
  has_existing_api: false                 # is there already a backend API
  api_authentication: ""                  # "none" | "api_key" | "oauth2" | "session" | "custom"
  booking_system: ""                      # "none" | "owner_rez" | "calendly" | "acuity" | "custom" | "square_appointments"
  ecommerce_platform: ""                  # "none" | "shopify" | "woocommerce" | "stripe" | "square" | "custom"
  primary_stack: ""                       # "static_html" | "nextjs" | "astro" | "wordpress" | "shopify" | "webflow" | "custom_node" | "custom_python"
  hosting_environment: ""                 # "bubbles" | "vercel" | "netlify" | "cloudflare_workers" | "shared_hosting" | "vps"
  expected_agent_traffic: ""              # "low" | "medium" | "high"
  high_value_tools_required: []           # which tools matter most for this site
  retrofit_or_greenfield: ""              # "retrofit_existing" | "greenfield_build"
  mcp_server_hosting_preference: ""       # "same_origin" | "subdomain" | "separate_service" | "edge_worker"

The site type and primary intent categories drive which tools to expose. The hosting environment and stack drive the implementation pattern. High agent traffic expectation drives rate limiting and caching design.


3. What MCP Is and Why Sites Matter

3.1 Protocol Origins

Model Context Protocol was released by Anthropic in November 2024 as an open specification published at modelcontextprotocol.io. The protocol uses JSON-RPC 2.0 as its message format and supports multiple transport layers including stdio (local processes), HTTP, and Server-Sent Events (SSE) for streaming.

The design intent was to solve a real problem: every AI assistant connecting to every tool required a custom integration. With MCP, any compliant agent can connect to any compliant server through a single protocol. The agent does not need to know in advance what tools the server provides; the server advertises its capabilities at connection time.

Through 2025 and 2026, adoption expanded significantly. Anthropic's Claude (desktop, web, mobile) ships with native MCP client support. Multiple major AI platforms have implemented MCP client capabilities. Hundreds of MCP servers exist for development tools, productivity applications, financial services (Stripe, PayPal, Square), cloud platforms (Cloudflare, Vercel, Netlify), and increasingly for content systems.

The phase change happening in 2026: MCP is moving from "developer tool integration" to "consumer agent infrastructure." This is where websites become relevant.

3.2 The Agentic Web Thesis

Traditional web architecture assumes a human is in the loop:

The human types a query into a search engine. The search engine returns links. The human clicks a link. The human reads the page. The human fills a form, calls a number, or completes a checkout.

Agentic web architecture removes the human from the middle of the loop:

The human states an intent to an AI agent. The agent decomposes the intent into queries and tasks. The agent queries MCP servers and APIs to gather information and compare options. The agent executes transactions (books, buys, schedules, subscribes) via MCP tool calls. The agent reports the completed outcome back to the human.

The human's involvement compresses to stating intent and confirming outcomes. The intermediate steps (research, comparison, form filling, checkout) become agent automation.

For sites, the implication is direct. A site that only serves humans (HTML pages with forms and phone numbers) is partially invisible to agents. The agent can read the HTML and report what it sees, but cannot complete the transaction without human intervention. A site that exposes MCP tools for the transactional actions becomes a venue where the agent can complete the task end to end.

The transactional sites that adopt MCP early capture the agent-mediated transactions. Sites that do not adopt MCP lose that share of intent to competitors that did. This is the core thesis driving urgency in 2026.

3.3 Current Adoption State (2026)

The state of MCP adoption as of 2026:

adoption_state_2026:

  protocol_stability:
    status: "stable for tools and resources, evolving for advanced features"
    spec_url: "https://modelcontextprotocol.io/specification"
    breaking_changes_expected: "minimal for tools/resources, possible for prompts and sampling"

  client_implementations:
    claude_desktop: "native, mature, the reference implementation"
    claude_web: "native via supported connector list"
    chatgpt: "MCP support added 2025"
    cursor: "native, developer focused"
    cline: "native, developer focused"
    continue: "native, developer focused"
    custom_agents: "via SDK, growing ecosystem"

  server_ecosystem:
    total_public_servers: "approximately 500-1000+ across directories and registries"
    categories:
      developer_tools: "largest category (GitHub, GitLab, databases, file systems)"
      productivity: "Asana, Slack, Notion, Linear, Jira"
      financial: "Stripe, PayPal, Square, Plaid"
      cloud_platforms: "Cloudflare, Vercel, Netlify, AWS via wrappers"
      data_sources: "search APIs, knowledge bases, vector stores"
      websites_for_specific_businesses: "sparse — this is the gap this framework addresses"

  consumer_use_cases_emerging:
    booking: "limited but growing"
    shopping: "early agent commerce platforms"
    research: "fully mainstream via agent search"
    scheduling: "limited consumer adoption, heavy enterprise"
    subscription_management: "early"

  agent_traffic_observable:
    detectable_via: "user agent strings, MCP server logs"
    volume_by_site: "still relatively low for most consumer sites in 2026"
    growth_trajectory: "compound monthly as agents become default consumer interface"

The pattern: protocol is stable, client adoption is broad, server ecosystem for business websites is sparse. This is the early adopter window. The exact moment to systematize.

3.4 Why Sites Need to Expose MCP

Five categories of value an MCP server delivers to a site:

One. Agent mediated transactions. Direct booking, purchase, inquiry, subscription, scheduling. The agent completes the task on the user's behalf. The site captures the transaction without requiring the human to visit and fill a form.

Two. Real time data exposure. Availability, pricing, inventory, hours, location, status. The agent queries current state instead of relying on stale HTML cached weeks ago by a search index.

Three. Disintermediation of aggregators. Third party booking platforms (OpenTable, Booking.com, Yelp, OTAs in hospitality) extract margin by sitting between the customer and the business. If the agent can transact with the business directly via MCP, the aggregator margin disappears. The business captures more revenue per transaction.

Four. Citation depth. Agents cite sources for their actions. A booking sourced via MCP from greenoughsguideservice.com cites that domain in the user-facing summary, reinforcing brand presence and increasing direct return visits.

Five. Future proofing. The agent share of consumer intent is growing. Sites without MCP today will need it eventually. Sites that build it early have working infrastructure when the wave hits, instead of scrambling to catch up.


4. MCP Server Architecture

4.1 Protocol Mechanics

MCP is JSON-RPC 2.0 over a chosen transport. The client (agent) and server exchange messages. Three primary message categories:

Requests — client to server, expecting a response. Examples: tools/list, tools/call, resources/list, resources/read.

Responses — server to client, completing a request.

Notifications — fire and forget, no response expected. Examples: notifications/initialized, notifications/cancelled.

At connection time, the client and server perform a capability handshake. The server declares what it supports (tools, resources, prompts, logging, etc.) and at what versions. The client adapts to the declared capabilities.

After handshake, the client can:

Call tools/list to discover available tools. Call tools/call with a tool name and arguments to invoke it. Call resources/list to discover available resources. Call resources/read with a resource URI to fetch its content. Call prompts/list to discover available prompt templates. Call prompts/get with a prompt name and arguments to retrieve a parameterized prompt.

The server is responsible for implementing these handlers and returning correctly shaped responses.

4.2 Tools, Resources, and Prompts

The three primitives, and what each is for:

mcp_primitives:

  tools:
    purpose: "Functions the agent can call to do something"
    characteristics:
      - "Takes arguments per a JSON Schema"
      - "Returns a result (text, structured data, error)"
      - "May have side effects (booking, purchase, send email)"
      - "Agent decides when and whether to call based on user intent"
    examples_for_sites:
      - "get_availability(date, party_size)"
      - "book_appointment(date, time, party_size, contact)"
      - "submit_inquiry(message, contact)"
      - "search_inventory(query, filters)"
      - "add_to_cart(product_id, quantity)"
      - "checkout(cart_id, payment_method)"

  resources:
    purpose: "Static or quasi-static data the agent can read"
    characteristics:
      - "Identified by URI"
      - "Returned content with MIME type"
      - "Idempotent (reading does not change state)"
      - "Cacheable by the agent"
    examples_for_sites:
      - "site://services — list of services offered"
      - "site://hours — operating hours"
      - "site://location — address and geo"
      - "site://faq — frequently asked questions"
      - "site://policies — refund, cancellation, terms"
      - "site://about — company info, history, credentials"

  prompts:
    purpose: "Pre-configured prompt templates the agent can use"
    characteristics:
      - "Parameterized templates"
      - "Help the agent ask better questions about a domain"
      - "Optional — many MCP servers do not implement prompts"
    examples_for_sites:
      - "plan_a_visit(party_size, dates, interests)"
      - "get_a_quote(service_type, requirements)"
      - "compare_options(criteria)"

For most websites, tools and resources are the essential primitives. Prompts are optional and often skipped in initial implementations.

4.3 Transport Layers

MCP supports multiple transports:

transport_options:

  stdio:
    use_case: "Local server invoked by a desktop client"
    characteristics:
      - "Server runs as a subprocess of the client"
      - "Communication via stdin/stdout"
      - "No network exposure"
    fit_for_websites: "Poor. Not how a hosted website serves agents."

  http_streamable:
    use_case: "Remote server accessible over the network"
    characteristics:
      - "Standard HTTP POST for client to server messages"
      - "Server-Sent Events (SSE) optional for server to client streaming"
      - "Supports authentication via standard HTTP mechanisms"
    fit_for_websites: "The right choice. Run the MCP server as an HTTP endpoint."

  websocket:
    use_case: "Bidirectional streaming for advanced scenarios"
    characteristics:
      - "Real time bidirectional communication"
      - "More complex than HTTP+SSE"
    fit_for_websites: "Acceptable for advanced cases. HTTP streamable is usually sufficient."

For website MCP servers, HTTP streamable transport is the standard pattern. The server exposes an HTTP endpoint (typically POST to a single path like /mcp or /sse) where agents send JSON-RPC requests and receive responses, optionally streamed.

4.4 Hosting Options

Where the MCP server lives matters for latency, security, and operational complexity:

hosting_options:

  same_origin_same_server:
    pattern: "MCP server runs on the same host as the website at a path like /mcp"
    pros:
      - "Simplest authentication (same session, same domain)"
      - "Lowest operational complexity"
      - "Shares connection to the business data layer"
    cons:
      - "Couples MCP availability to site availability"
      - "Performance load on the same server as the site"
    fit:
      - "Bubbles deployments where Joseph controls the server"
      - "Small sites with modest agent traffic"

  same_origin_different_server:
    pattern: "MCP server on a different port or behind a reverse proxy path"
    pros:
      - "Isolates MCP load from site rendering load"
      - "Can scale independently"
      - "Same authentication domain"
    cons:
      - "More complex deployment"
      - "Requires reverse proxy configuration"
    fit:
      - "Bubbles with FastAPI sidecar pattern (already in use on port 9090 for SSI schema injection)"
      - "Sites expecting medium agent traffic"

  subdomain:
    pattern: "mcp.example.com hosts the MCP server"
    pros:
      - "Clear separation of surfaces"
      - "Easy DNS-based scaling"
      - "Cookie isolation if needed"
    cons:
      - "CORS considerations"
      - "Requires DNS and certificate work"
    fit:
      - "Multi-site or multi-region operations"
      - "Sites planning heavy agent integration"

  edge_worker:
    pattern: "Cloudflare Worker, Vercel Edge Function, Deno Deploy"
    pros:
      - "Global low-latency distribution"
      - "Automatic scaling"
      - "Pay-per-request economics"
    cons:
      - "Cold starts (mostly mitigated in modern edge)"
      - "Limited runtime capabilities vs full server"
      - "May complicate access to business data layer"
    fit:
      - "Sites already on edge architecture"
      - "Read-heavy MCP servers (resources more than tools)"

  third_party_hosted:
    pattern: "MCP-as-a-service platforms"
    pros:
      - "Zero infrastructure responsibility"
      - "Built-in observability and rate limiting"
    cons:
      - "Vendor lock-in"
      - "Less control over data access patterns"
      - "Recurring cost"
    fit:
      - "Clients without technical operations capability"
      - "Quick prototype phases"

For Joseph's Bubbles deployments, the recommended pattern is same origin different server, extending the existing FastAPI sidecar on port 9090. The sidecar already handles SSI schema injection. Adding MCP endpoints to the same sidecar is the lowest friction path.

4.5 Lifecycle and Connection Flow

A typical MCP connection from agent to website:

1. Agent receives user intent: "Book me a fishing trip on Saturday."
2. Agent searches its known MCP server registry for relevant servers.
3. Agent connects to https://greenoughsguideservice.com/mcp (HTTP POST or SSE).
4. Server returns initialize response with capabilities.
5. Agent calls tools/list to discover available tools.
6. Server returns: get_availability, get_pricing, book_appointment, submit_inquiry.
7. Agent calls tools/call: get_availability with date=2026-05-17.
8. Server queries booking system and returns: "Available 6am, 9am, 2pm."
9. Agent presents options to user. User selects 6am.
10. Agent calls tools/call: book_appointment with full details.
11. Server validates, processes payment via Square, creates booking, returns confirmation.
12. Agent reports outcome to user with confirmation number.

The connection may be short lived (one tool call) or long lived (multiple calls in a session). HTTP streamable transport supports both patterns naturally.


5. Tools to Expose by Vertical

The tools an MCP server exposes determine its usefulness to agents. Generic tools (search, info) are common starting points. Vertical-specific tools deliver the high-leverage outcomes.

5.1 Local Business

local_business_mcp_tools:

  essential:
    get_hours:
      description: "Operating hours including holiday exceptions"
      arguments: { date: "optional ISO date" }
      returns: "Open/closed status and hours for the date or today"

    get_location:
      description: "Physical address, geo coordinates, parking, accessibility notes"
      arguments: {}
      returns: "Address, coordinates, parking info, accessibility info"

    get_contact:
      description: "Phone, email, contact form URL"
      arguments: {}
      returns: "Contact methods with hours of availability"

    list_services:
      description: "Services offered with descriptions and price ranges"
      arguments: { category: "optional service category filter" }
      returns: "List of services with names, descriptions, price ranges"

  high_value:
    check_availability:
      description: "Check booking availability for a specific date/service"
      arguments: { service_id: "string", date: "ISO date", party_size: "integer optional" }
      returns: "Available time slots"

    request_quote:
      description: "Submit a request for a detailed quote"
      arguments: { service_id, requirements: "string", contact: "object" }
      returns: "Quote request confirmation with estimated response time"

  transactional:
    book_appointment:
      description: "Create a booking with deposit/payment"
      arguments: { service_id, date, time, party_size, contact, payment_token }
      returns: "Booking confirmation number, calendar URL, payment receipt"

  resources:
    - "site://services"
    - "site://hours"
    - "site://location"
    - "site://faq"
    - "site://policies/cancellation"
    - "site://reviews"

5.2 Service Business (guides, contractors, professional services)

service_business_mcp_tools:

  essential:
    list_services:
      description: "Services offered, descriptions, pricing model, typical timeline"
      returns: "Services with metadata"

    list_service_areas:
      description: "Geographic service areas"
      returns: "List of areas with travel/availability notes"

    get_credentials:
      description: "Licenses, certifications, insurance, years in business"
      returns: "Credentials with verification source where available"

  high_value:
    check_availability:
      description: "Availability for a date range"
      arguments: { service_type, start_date, end_date, location }
      returns: "Available windows"

    request_quote:
      description: "Submit a quote request"
      arguments: { service_type, scope: "string", location, timeline, contact }
      returns: "Quote ID, estimated response time, what-to-expect summary"

    schedule_consultation:
      description: "Book a no-cost consultation call"
      arguments: { date, time, contact, topic }
      returns: "Consultation confirmation with calendar invite link"

  transactional:
    book_service:
      description: "Book and pay for a defined service"
      arguments: { service_id, scheduling, location, contact, payment_token }
      returns: "Service booking confirmation"

  resources:
    - "site://services"
    - "site://service-areas"
    - "site://credentials"
    - "site://about"
    - "site://past-work"
    - "site://testimonials"

5.3 Ecommerce

ecommerce_mcp_tools:

  essential:
    search_products:
      description: "Search the product catalog with optional filters"
      arguments: { query: "string", filters: "object optional", limit: "integer" }
      returns: "List of products with id, name, price, availability, image_url"

    get_product:
      description: "Get details for a specific product"
      arguments: { product_id: "string" }
      returns: "Full product details including variants, inventory, shipping options"

    check_inventory:
      description: "Real time inventory check"
      arguments: { product_id, variant_id: "optional", quantity: "integer" }
      returns: "Available, low_stock, or out_of_stock with estimated restock date"

  high_value:
    get_shipping_estimate:
      description: "Estimate shipping cost and timeline"
      arguments: { product_ids, destination_zip, shipping_method: "optional" }
      returns: "Shipping options with cost and estimated delivery"

    get_recommendations:
      description: "Personalized or category-based product recommendations"
      arguments: { context: "object describing user intent" }
      returns: "Recommended product list"

  transactional:
    add_to_cart:
      description: "Add a product to a session cart"
      arguments: { product_id, variant_id: "optional", quantity, session_token: "optional" }
      returns: "Cart state with line items and totals"

    checkout:
      description: "Complete checkout for a cart"
      arguments: { cart_id, contact, shipping_address, payment_token }
      returns: "Order confirmation with order number and tracking placeholder"

    track_order:
      description: "Check order status"
      arguments: { order_number, contact_verification }
      returns: "Order status with shipping tracking if shipped"

  resources:
    - "site://catalog/featured"
    - "site://catalog/categories"
    - "site://policies/shipping"
    - "site://policies/returns"
    - "site://policies/warranty"

5.4 Content Site (publisher, blog, knowledge base)

content_site_mcp_tools:

  essential:
    search_content:
      description: "Search articles by query"
      arguments: { query: "string", category: "optional", date_range: "optional", limit }
      returns: "Article list with title, URL, excerpt, author, date"

    get_article:
      description: "Get full article content"
      arguments: { article_id_or_slug }
      returns: "Article body, metadata, related articles"

    list_categories:
      description: "Topic categories or tags"
      returns: "Category list with article counts"

  high_value:
    get_latest:
      description: "Latest published content, optionally filtered"
      arguments: { category: "optional", limit, since: "optional ISO date" }
      returns: "List of recent articles"

    subscribe_newsletter:
      description: "Subscribe to newsletter or topical feed"
      arguments: { email, topics: "array optional" }
      returns: "Subscription confirmation"

  resources:
    - "site://categories"
    - "site://authors"
    - "site://archives"
    - "site://about/editorial-policy"

5.5 SaaS

saas_mcp_tools:

  essential:
    list_features:
      description: "Product features with descriptions and tier availability"
      returns: "Feature list with plan availability"

    list_pricing:
      description: "Pricing plans with included features"
      returns: "Plans with prices, features, limits"

    compare_plans:
      description: "Side by side plan comparison"
      arguments: { plan_ids: "array of plan IDs to compare" }
      returns: "Comparison table data"

  high_value:
    start_trial:
      description: "Start a no-cost trial"
      arguments: { email, plan_id, company_name: "optional" }
      returns: "Trial confirmation with login URL"

    schedule_demo:
      description: "Book a demo call with sales"
      arguments: { contact, company, use_case, preferred_times }
      returns: "Demo confirmation with calendar invite"

  transactional:
    subscribe:
      description: "Create a paid subscription"
      arguments: { plan_id, contact, payment_token, billing_period }
      returns: "Subscription confirmation with account URL"

  resources:
    - "site://features"
    - "site://pricing"
    - "site://docs/index"
    - "site://changelog"
    - "site://status"

5.6 B2B Service / Lead Generation

b2b_mcp_tools:

  essential:
    list_services:
      description: "Service offerings with target customer types"
      returns: "Service list"

    get_case_studies:
      description: "Filterable case study list"
      arguments: { industry: "optional", outcome_type: "optional" }
      returns: "Case studies with industry, problem, outcome"

  high_value:
    request_consultation:
      description: "Request a discovery consultation"
      arguments: { contact, company, role, interest_area, current_situation }
      returns: "Consultation request confirmation, next steps"

    request_proposal:
      description: "Submit a detailed RFP"
      arguments: { contact, company, scope: "detailed string", timeline, budget_range }
      returns: "Proposal request acknowledgment with expected response time"

  resources:
    - "site://services"
    - "site://case-studies"
    - "site://industries-served"
    - "site://team"
    - "site://about"

5.7 Nonprofit

nonprofit_mcp_tools:

  essential:
    get_mission:
      description: "Mission statement and current focus areas"
      returns: "Mission, focus areas, recent impact"

    list_programs:
      description: "Active programs and initiatives"
      returns: "Program list with description, status, target population"

  high_value:
    donate:
      description: "Make a tax-deductible donation"
      arguments: { amount, designation: "optional", contact, payment_token }
      returns: "Donation confirmation, receipt URL, tax acknowledgment"

    volunteer_signup:
      description: "Express interest in volunteering"
      arguments: { contact, interests, availability }
      returns: "Volunteer onboarding confirmation"

    sign_petition:
      description: "Sign an active advocacy petition"
      arguments: { petition_id, contact }
      returns: "Signature confirmation"

  resources:
    - "site://mission"
    - "site://programs"
    - "site://impact"
    - "site://financials"
    - "site://board"

6. Discovery and Announcement

Agents need to know an MCP server exists before they can use it. Discovery patterns in 2026:

6.1 The /.well-known/mcp.json Convention

The emerging convention is a /.well-known/mcp.json file at the site root that describes the MCP server. Analogous to /.well-known/openid-configuration for OAuth or /.well-known/security.txt for security contact:

{
  "name": "Greenough's Guide Service MCP Server",
  "version": "1.0.0",
  "description": "Fishing guide service on Lake Taneycomo and Table Rock Lake",
  "transport": {
    "type": "http",
    "endpoint": "https://greenoughsguideservice.com/mcp"
  },
  "auth": {
    "type": "oauth2",
    "authorization_endpoint": "https://greenoughsguideservice.com/oauth/authorize",
    "token_endpoint": "https://greenoughsguideservice.com/oauth/token",
    "public_tools": ["get_availability", "get_pricing", "list_services"]
  },
  "capabilities": {
    "tools": true,
    "resources": true,
    "prompts": false
  },
  "contact": {
    "support_email": "support@greenoughsguideservice.com",
    "url": "https://greenoughsguideservice.com/contact"
  }
}

The convention is still stabilizing. Until it is fully standardized, also reference the MCP server from robots.txt and llms.txt.

6.2 robots.txt Reference

User-agent: *
Allow: /

# AI crawler policy
User-agent: GPTBot
Allow: /

User-agent: ClaudeBot
Allow: /

# MCP server announcement
MCP-Server: https://example.com/mcp
MCP-Discovery: https://example.com/.well-known/mcp.json

Sitemap: https://example.com/sitemap.xml

The MCP-Server directive is not yet part of the official robots.txt specification but is a practical signal that some agent registries pick up.

6.3 llms.txt Reference

# Greenough's Guide Service

> Trophy trout guide on Lake Taneycomo and trophy bass on Table Rock Lake,
> based in Branson, Missouri. Year-round service.

## MCP Server

This site exposes an MCP server for AI agents:

- Endpoint: https://greenoughsguideservice.com/mcp
- Discovery: https://greenoughsguideservice.com/.well-known/mcp.json
- Public tools: get_availability, get_pricing, list_services, check_weather

For booking-capable tools, OAuth authentication is required.

## Site Map

- [Services](https://greenoughsguideservice.com/services)
- [Rates](https://greenoughsguideservice.com/rates)
- [Booking](https://greenoughsguideservice.com/book)

6.4 Schema.org Integration

Add potentialAction properties to Organization or relevant schema that reference the MCP server:

{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "@id": "https://greenoughsguideservice.com/#localbusiness",
  "name": "Greenough's Guide Service",
  "potentialAction": [
    {
      "@type": "ReserveAction",
      "target": {
        "@type": "EntryPoint",
        "urlTemplate": "https://greenoughsguideservice.com/mcp",
        "actionPlatform": "https://modelcontextprotocol.io",
        "encodingType": "application/json",
        "contentType": "application/json-rpc"
      },
      "result": { "@type": "Reservation" }
    }
  ]
}

This is exploratory pattern as of 2026. Schema.org has not formally adopted MCP-specific markup. The pattern above approximates discovery via standard schema mechanisms.

6.5 Public Registries

A growing set of public MCP server registries list servers for agent discovery. Submit the server to the major registries:

mcp.so — community directory mcpservers.org — community directory Smithery — registry with installer tooling Anthropic's directory — if Claude Desktop should discover the server natively Cloudflare's MCP catalog — if hosted on Cloudflare infrastructure

Maintain registry listings as the server evolves. Out of date listings reduce trust.


7. Authentication and Security

Tools that take action (booking, purchase, contact submission) require authentication. Read-only tools and resources can be public.

7.1 Tier the Tools

tool_security_tiers:

  public_tier:
    description: "Read-only data. Safe to expose without authentication."
    examples:
      - "get_hours"
      - "get_location"
      - "list_services"
      - "search_products"
      - "get_availability"
    auth: "none"
    rate_limit: "moderate (e.g. 100 req/min per IP)"

  identified_tier:
    description: "Requires user/agent identity but no transaction"
    examples:
      - "submit_inquiry"
      - "request_quote"
      - "subscribe_newsletter"
    auth: "captcha or signed token; OAuth optional"
    rate_limit: "strict (e.g. 10 req/hour per identity)"

  transactional_tier:
    description: "Takes action with real consequences"
    examples:
      - "book_appointment"
      - "checkout"
      - "subscribe (paid)"
      - "donate"
    auth: "OAuth 2.1 with user consent; payment authorization separate"
    rate_limit: "very strict; per user identity, not per IP"

7.2 OAuth 2.1 for Transactional Tools

MCP transactional tools use OAuth 2.1. The user authorizes the agent to act on their behalf. The flow:

1. Agent presents user with consent: "Greenough's wants to book a trip for you."
2. User confirms.
3. Agent redirects through OAuth to obtain a token scoped to the booking.
4. Agent calls book_appointment with the token in the Authorization header.
5. Server validates the token and processes the booking.
6. Token expires after the transaction completes.

The OAuth implementation does not need to be complex. Short-lived scoped tokens for specific tool calls. The user does not need an account on the site; the OAuth is consent for the specific transaction, not account creation.

7.3 Rate Limiting

Rate limits prevent abuse and protect the business data layer:

rate_limiting_recommendations:

  public_tier:
    per_ip: "100 req/min"
    per_session: "500 req/hour"
    burst_allowance: "150% for 30 seconds"

  identified_tier:
    per_identity: "10 req/hour"
    per_endpoint: "specific limits per tool"
    backoff: "exponential after 3 violations"

  transactional_tier:
    per_user: "5 attempted bookings/hour"
    per_payment_method: "10 attempts/day across all tools"
    fraud_detection: "integrate with payment processor's risk scoring"

7.4 What Not to Expose

Specific tools and data that should never be exposed via public MCP:

Admin functions. Site management, user account administration, content editing. Customer PII without explicit user consent. Even if the agent is acting on the user's behalf, do not return other customers' data. Pricing logic internals. Expose final prices, not the discount logic that produces them. Inventory in absolute terms when scarcity drives price. "12 left in stock" is fine; "exactly 12 units in warehouse 3 bay 7" is not. Internal system identifiers. Use external-facing identifiers (slugs, public IDs) not database primary keys. Audit logs, error logs, system telemetry. Internal observability data.


8. Implementation Patterns by Stack

8.1 Node.js with @modelcontextprotocol/sdk

The reference implementation for TypeScript/JavaScript:

// mcp-server.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  ListResourcesRequestSchema,
  ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import express from "express";
import { createServer } from "http";

// Initialize the MCP server
const mcpServer = new Server(
  {
    name: "greenoughs-guide-service",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
      resources: {},
    },
  }
);

// List available tools
mcpServer.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "get_availability",
        description: "Check guide service availability for a specific date and party size",
        inputSchema: {
          type: "object",
          properties: {
            date: {
              type: "string",
              format: "date",
              description: "Date to check in ISO 8601 format",
            },
            party_size: {
              type: "integer",
              minimum: 1,
              maximum: 4,
              description: "Number of anglers",
            },
          },
          required: ["date", "party_size"],
        },
      },
      {
        name: "list_services",
        description: "List all available guide services with descriptions and pricing",
        inputSchema: {
          type: "object",
          properties: {},
        },
      },
      // additional tools...
    ],
  };
});

// Handle tool calls
mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  if (name === "get_availability") {
    const slots = await queryAvailability(args.date, args.party_size);
    return {
      content: [
        {
          type: "text",
          text: JSON.stringify({
            date: args.date,
            available_slots: slots,
            party_size: args.party_size,
          }),
        },
      ],
    };
  }

  if (name === "list_services") {
    const services = await queryServices();
    return {
      content: [
        {
          type: "text",
          text: JSON.stringify({ services }),
        },
      ],
    };
  }

  throw new Error(`Unknown tool: ${name}`);
});

// List resources
mcpServer.setRequestHandler(ListResourcesRequestSchema, async () => {
  return {
    resources: [
      {
        uri: "site://services",
        name: "Services",
        description: "All guide services offered",
        mimeType: "application/json",
      },
      {
        uri: "site://hours",
        name: "Operating Hours",
        description: "Guide service operating hours by season",
        mimeType: "application/json",
      },
    ],
  };
});

// Read resources
mcpServer.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  const { uri } = request.params;

  if (uri === "site://services") {
    const services = await queryServices();
    return {
      contents: [
        {
          uri,
          mimeType: "application/json",
          text: JSON.stringify(services),
        },
      ],
    };
  }

  if (uri === "site://hours") {
    const hours = await queryHours();
    return {
      contents: [
        {
          uri,
          mimeType: "application/json",
          text: JSON.stringify(hours),
        },
      ],
    };
  }

  throw new Error(`Unknown resource: ${uri}`);
});

// Express HTTP wrapper for MCP server
const app = express();
app.use(express.json());

app.post("/mcp", async (req, res) => {
  try {
    const response = await mcpServer.handleRequest(req.body);
    res.json(response);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Discovery endpoint
app.get("/.well-known/mcp.json", (req, res) => {
  res.json({
    name: "Greenough's Guide Service MCP Server",
    version: "1.0.0",
    description: "Fishing guide service on Lake Taneycomo and Table Rock Lake",
    transport: {
      type: "http",
      endpoint: "https://greenoughsguideservice.com/mcp",
    },
    capabilities: {
      tools: true,
      resources: true,
      prompts: false,
    },
  });
});

const httpServer = createServer(app);
httpServer.listen(9091, () => {
  console.log("MCP server listening on port 9091");
});

8.2 Python with mcp library

The reference implementation for Python:

# mcp_server.py
from mcp.server import Server
from mcp.types import Tool, Resource, TextContent
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import json

mcp_server = Server("greenoughs-guide-service")


@mcp_server.list_tools()
async def list_tools() -> list[Tool]:
    return [
        Tool(
            name="get_availability",
            description="Check guide service availability for a specific date and party size",
            inputSchema={
                "type": "object",
                "properties": {
                    "date": {
                        "type": "string",
                        "format": "date",
                        "description": "Date to check in ISO 8601 format",
                    },
                    "party_size": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 4,
                        "description": "Number of anglers",
                    },
                },
                "required": ["date", "party_size"],
            },
        ),
        Tool(
            name="list_services",
            description="List all available guide services with descriptions and pricing",
            inputSchema={"type": "object", "properties": {}},
        ),
    ]


@mcp_server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    if name == "get_availability":
        slots = await query_availability(arguments["date"], arguments["party_size"])
        return [
            TextContent(
                type="text",
                text=json.dumps({
                    "date": arguments["date"],
                    "available_slots": slots,
                    "party_size": arguments["party_size"],
                }),
            )
        ]

    if name == "list_services":
        services = await query_services()
        return [TextContent(type="text", text=json.dumps({"services": services}))]

    raise ValueError(f"Unknown tool: {name}")


# FastAPI wrapper for HTTP transport (extending Joseph's existing FastAPI sidecar on port 9090)
app = FastAPI()


@app.post("/mcp")
async def mcp_endpoint(request: Request):
    body = await request.json()
    response = await mcp_server.handle_request(body)
    return JSONResponse(content=response)


@app.get("/.well-known/mcp.json")
async def mcp_discovery():
    return {
        "name": "Greenough's Guide Service MCP Server",
        "version": "1.0.0",
        "description": "Fishing guide service on Lake Taneycomo and Table Rock Lake",
        "transport": {
            "type": "http",
            "endpoint": "https://greenoughsguideservice.com/mcp",
        },
        "capabilities": {"tools": True, "resources": True, "prompts": False},
    }

8.3 Bubbles Deployment (Joseph's Stack)

On Bubbles, the existing FastAPI sidecar on port 9090 handles SSI schema injection. Extending it to also serve MCP is the lowest friction path. Add the endpoints from Section 8.2 to the existing sidecar codebase.

nginx configuration to expose the MCP endpoints under the site origin:

# /etc/nginx/sites-available/example.com
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;

    # ... existing TLS, root, etc. ...

    # Proxy MCP endpoints to the FastAPI sidecar
    location /mcp {
        proxy_pass http://127.0.0.1:9090/mcp;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_buffering off;
        proxy_read_timeout 300s;
    }

    location /.well-known/mcp.json {
        proxy_pass http://127.0.0.1:9090/.well-known/mcp.json;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
    }

    # Rate limit zone for MCP endpoints
    location ~ ^/mcp {
        limit_req zone=mcp_zone burst=20 nodelay;
        proxy_pass http://127.0.0.1:9090;
        # ... same proxy headers ...
    }
}

# /etc/nginx/nginx.conf or appropriate include
limit_req_zone $binary_remote_addr zone=mcp_zone:10m rate=10r/s;

After deployment, run nginx -t && systemctl reload nginx to apply.

8.4 As Cloudflare Worker

For sites that benefit from edge distribution:

// worker.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";

const mcpServer = new Server(
  { name: "example-mcp", version: "1.0.0" },
  { capabilities: { tools: {}, resources: {} } }
);

// ... tool and resource handlers ...

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);

    if (url.pathname === "/mcp" && request.method === "POST") {
      const body = await request.json();
      const response = await mcpServer.handleRequest(body);
      return new Response(JSON.stringify(response), {
        headers: { "Content-Type": "application/json" },
      });
    }

    if (url.pathname === "/.well-known/mcp.json") {
      return new Response(JSON.stringify({
        name: "Example MCP Server",
        version: "1.0.0",
        transport: { type: "http", endpoint: `${url.origin}/mcp` },
        capabilities: { tools: true, resources: true },
      }), { headers: { "Content-Type": "application/json" } });
    }

    return new Response("Not found", { status: 404 });
  },
};

8.5 WordPress

WordPress sites can expose MCP via a custom plugin that registers REST API endpoints. The plugin acts as a thin adapter between WordPress data (posts, products via WooCommerce, etc.) and the MCP protocol:

<?php
// mcp-server-plugin.php
/**
 * Plugin Name: MCP Server
 * Description: Exposes site as an MCP server for AI agents
 * Version: 1.0.0
 */

add_action('rest_api_init', function () {
    register_rest_route('mcp/v1', '/mcp', [
        'methods' => 'POST',
        'callback' => 'mcp_handle_request',
        'permission_callback' => '__return_true',
    ]);

    register_rest_route('mcp/v1', '/.well-known/mcp.json', [
        'methods' => 'GET',
        'callback' => 'mcp_discovery',
        'permission_callback' => '__return_true',
    ]);
});

function mcp_handle_request($request) {
    $body = $request->get_json_params();
    $method = $body['method'] ?? null;

    if ($method === 'tools/list') {
        return ['tools' => mcp_get_tools()];
    }

    if ($method === 'tools/call') {
        $name = $body['params']['name'];
        $args = $body['params']['arguments'];
        return mcp_call_tool($name, $args);
    }

    return new WP_Error('unknown_method', 'Unknown MCP method', ['status' => 400]);
}

function mcp_get_tools() {
    return [
        [
            'name' => 'search_articles',
            'description' => 'Search published articles',
            'inputSchema' => [
                'type' => 'object',
                'properties' => [
                    'query' => ['type' => 'string'],
                    'limit' => ['type' => 'integer', 'maximum' => 20],
                ],
                'required' => ['query'],
            ],
        ],
    ];
}

function mcp_call_tool($name, $args) {
    if ($name === 'search_articles') {
        $posts = get_posts([
            's' => $args['query'],
            'numberposts' => $args['limit'] ?? 10,
            'post_status' => 'publish',
        ]);

        $results = array_map(function ($post) {
            return [
                'title' => $post->post_title,
                'url' => get_permalink($post),
                'excerpt' => get_the_excerpt($post),
                'published' => $post->post_date,
            ];
        }, $posts);

        return [
            'content' => [
                ['type' => 'text', 'text' => json_encode(['results' => $results])],
            ],
        ];
    }
}

function mcp_discovery() {
    return [
        'name' => get_bloginfo('name') . ' MCP Server',
        'version' => '1.0.0',
        'transport' => [
            'type' => 'http',
            'endpoint' => rest_url('mcp/v1/mcp'),
        ],
        'capabilities' => ['tools' => true, 'resources' => false, 'prompts' => false],
    ];
}

8.6 Shopify

Shopify sites should use Shopify's app framework to expose MCP. Build a private app with the appropriate scopes, expose MCP endpoints via the app's backend, and reference the app's endpoint in /.well-known/mcp.json.

// shopify-app-mcp.js (simplified)
import { shopifyApp } from "@shopify/shopify-app-express";
import { Server } from "@modelcontextprotocol/sdk/server/index.js";

const shopify = shopifyApp({
  api: { /* ... */ },
  auth: { /* ... */ },
});

const mcpServer = new Server(/* ... */);

mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;
  const session = await getShopifySession();
  const client = new shopify.api.clients.Graphql({ session });

  if (name === "search_products") {
    const response = await client.query({
      data: {
        query: `query SearchProducts($query: String!, $limit: Int!) {
          products(query: $query, first: $limit) {
            edges { node { id title handle priceRange { minVariantPrice { amount } } } }
          }
        }`,
        variables: { query: args.query, limit: args.limit ?? 10 },
      },
    });
    return { content: [{ type: "text", text: JSON.stringify(response.body.data) }] };
  }
});

app.post("/mcp", shopify.validateAuthenticatedSession(), async (req, res) => {
  const response = await mcpServer.handleRequest(req.body);
  res.json(response);
});

8.7 Webflow and Other Hosted Platforms

Hosted platforms without server-side execution (Webflow, Squarespace, Wix) cannot directly host an MCP server. The pattern is to deploy a sidecar service on a separate origin (Vercel, Cloudflare Worker, AWS Lambda) and reference it from the Webflow site's /.well-known/mcp.json (which can be hosted as a static file in Webflow's asset system or proxied through Cloudflare).

The sidecar fetches site data from the Webflow CMS API, transforms it into MCP responses, and serves agents directly.


9. Validation Methodology

After implementing the MCP server, validation is essential. A server that returns malformed responses, breaks on edge cases, or fails authentication will damage agent trust quickly.

9.1 MCP Inspector

Anthropic ships an open source MCP Inspector tool that connects to an MCP server and exercises every tool and resource. Run it during development and as part of CI:

# Install
npm install -g @modelcontextprotocol/inspector

# Run against a local or deployed server
mcp-inspector https://example.com/mcp

The inspector returns a report of each tool's discoverability, each resource's accessibility, schema validity, and response time.

9.2 Claude Desktop Configuration

Test the server against Claude Desktop as a real agent client:

// claude_desktop_config.json
{
  "mcpServers": {
    "greenoughs-guide-service": {
      "command": "node",
      "args": ["/path/to/mcp-server.js"]
    }
  }
}

For HTTP-transported servers (the typical website case), configure Claude Desktop to connect via the deployed endpoint. Once connected, interact with the server through Claude: "Can you check fishing availability for next Saturday?" If Claude successfully uses the tools and returns sensible results, the server is functional end to end.

9.3 Custom Test Harness

Production sites benefit from automated test harnesses that exercise the MCP server on every deploy:

// mcp-test.ts
import { describe, it, expect } from "vitest";
import { McpClient } from "@modelcontextprotocol/sdk/client/index.js";

describe("MCP Server Integration", () => {
  let client: McpClient;

  beforeEach(async () => {
    client = new McpClient({ transport: "http", endpoint: "http://localhost:9091/mcp" });
    await client.connect();
  });

  it("lists expected tools", async () => {
    const { tools } = await client.listTools();
    expect(tools.map(t => t.name)).toContain("get_availability");
    expect(tools.map(t => t.name)).toContain("list_services");
  });

  it("returns availability for valid date", async () => {
    const result = await client.callTool("get_availability", {
      date: "2026-05-17",
      party_size: 2,
    });
    expect(result.content[0].type).toBe("text");
    const data = JSON.parse(result.content[0].text);
    expect(data.date).toBe("2026-05-17");
    expect(data.available_slots).toBeInstanceOf(Array);
  });

  it("rejects invalid date", async () => {
    await expect(
      client.callTool("get_availability", { date: "not-a-date", party_size: 2 })
    ).rejects.toThrow();
  });

  it("enforces rate limits", async () => {
    const requests = Array(20).fill(0).map(() =>
      client.callTool("get_availability", { date: "2026-05-17", party_size: 2 })
    );
    const results = await Promise.allSettled(requests);
    const rejected = results.filter(r => r.status === "rejected");
    expect(rejected.length).toBeGreaterThan(0);
  });
});

9.4 Real Agent Workflow Validation

The acid test: have a real agent attempt a complete workflow end to end. Using Claude Desktop or a custom agent:

Test 1: "Check availability for fishing on May 17, 2026 for 2 anglers."
  Expected: Agent calls get_availability, returns specific time slots.

Test 2: "What services do they offer?"
  Expected: Agent calls list_services, returns service catalog with prices.

Test 3: "Book the 6am slot for half day trout fishing for 2 people. My name is Test Customer, email test@example.com."
  Expected: Agent handles OAuth consent, calls book_appointment, returns confirmation.

Test 4: "What time does the office open tomorrow?"
  Expected: Agent calls get_hours, returns hours for the date.

Document the actual agent transcript for each test. If the agent gets confused, returns wrong information, or fails to complete the workflow, the server has gaps to fix.

9.5 Production Monitoring

After launch, monitor MCP server health:

mcp_monitoring:

  uptime:
    check: "HTTP GET /.well-known/mcp.json every 60 seconds"
    alert_threshold: "2 consecutive failures"

  response_time:
    measure: "p50, p95, p99 latency per tool"
    alert_threshold: "p95 > 2 seconds"

  error_rate:
    measure: "5xx responses per minute"
    alert_threshold: "> 1% over 5 minute window"

  rate_limit_hits:
    measure: "429 responses per minute"
    alert_threshold: "unexpected spike indicates abuse or legitimate burst"

  agent_traffic_volume:
    measure: "requests per day, by detected agent user agent"
    track_over_time: "weekly growth"

  tool_invocation_distribution:
    measure: "calls per tool per day"
    use: "identify unused tools and high-value tools"

10. Common Patterns and Anti-patterns

10.1 Patterns That Work

working_patterns:

  expose_real_time_state:
    pattern: "Tools return current state, not cached HTML"
    why: "Agents trust MCP responses more than crawled HTML for transactional decisions"

  small_focused_tools:
    pattern: "Many tools each doing one thing well"
    why: "Agents pick the right tool more reliably than they parse a kitchen-sink endpoint"

  descriptive_tool_descriptions:
    pattern: "Tool descriptions read like user-facing help text"
    why: "Agents use the description to decide whether the tool fits the intent"

  consistent_response_shape:
    pattern: "All tools return predictable structure"
    why: "Agents become reliable when responses are predictable"

  graceful_degradation:
    pattern: "Tools return useful partial data when full data unavailable"
    why: "Agents can still help users even when systems are degraded"

  human_readable_text:
    pattern: "Return text responses in natural language, not just JSON dumps"
    why: "Agents combine MCP responses with their own narrative; readable text composes better"

10.2 Anti-patterns to Avoid

anti_patterns:

  one_giant_query_tool:
    symptom: "Single tool with a free-form query parameter expected to handle everything"
    fix: "Decompose into specific tools (get_availability, list_services, etc.)"
    severity: "high"

  cryptic_error_messages:
    symptom: "Errors like 'ERR_GUIDE_42'"
    fix: "Return errors that explain what went wrong and what the agent should do next"
    severity: "high"

  authentication_required_for_public_data:
    symptom: "Agents cannot get hours or services without authentication"
    fix: "Public tier tools should be reachable without auth"
    severity: "high"

  inconsistent_field_names:
    symptom: "get_availability returns 'slots'; check_availability returns 'available_times'"
    fix: "Standardize field names across tools"
    severity: "medium"

  no_pagination:
    symptom: "Tools return unbounded result sets"
    fix: "Add limit/offset or cursor-based pagination"
    severity: "medium"

  schema_drift:
    symptom: "Tool responses do not match advertised schema"
    fix: "Validate responses against schema before returning; treat drift as a bug"
    severity: "high"

  blocking_long_running_tools:
    symptom: "book_appointment takes 30 seconds to return"
    fix: "Use SSE to stream progress, or return a job ID and provide a status check tool"
    severity: "medium"

  no_versioning_strategy:
    symptom: "MCP server changes break existing agent integrations"
    fix: "Version the MCP server; communicate changes via the discovery endpoint"
    severity: "medium"

  exposing_internal_ids:
    symptom: "Tools return database primary keys as identifiers"
    fix: "Use external slugs or UUIDs"
    severity: "medium"

  no_rate_limiting:
    symptom: "Server becomes unresponsive under burst traffic"
    fix: "Implement rate limits at multiple tiers (IP, identity, tool)"
    severity: "critical"

  missing_discovery_endpoint:
    symptom: "Agents cannot find the server because /.well-known/mcp.json is absent"
    fix: "Always serve the discovery endpoint"
    severity: "critical"

  cors_blocking_legitimate_clients:
    symptom: "Browser-based agents fail with CORS errors"
    fix: "Set appropriate Access-Control-Allow-Origin headers"
    severity: "high"

11. The MCP Audit Rubric

A 30 point rubric scoring an MCP implementation. World class implementation: 27+/30.

# Criterion Pass/Fail
MCP1 /.well-known/mcp.json served at root with correct schema
MCP2 MCP endpoint reachable via HTTP POST, returns valid JSON-RPC responses
MCP3 tools/list returns at least three meaningful tools
MCP4 tools/call works end to end for each advertised tool
MCP5 resources/list returns at least three meaningful resources (if site has data to expose)
MCP6 Each tool description is human readable and explains intent
MCP7 Each tool input schema is valid JSON Schema
MCP8 Tool responses follow consistent shape across all tools
MCP9 Public tier tools require no authentication
MCP10 Transactional tier tools use OAuth 2.1 or equivalent
MCP11 Rate limits implemented at IP, identity, and tool tiers
MCP12 Error responses are descriptive and actionable
MCP13 All tools tested via MCP Inspector with zero failures
MCP14 Server tested against Claude Desktop with successful end-to-end workflow
MCP15 Automated test suite covers happy path and error cases for every tool
MCP16 Uptime monitoring configured with alerts
MCP17 Response time p95 under 2 seconds per tool
MCP18 Server logs structured for observability
MCP19 MCP server announced in robots.txt
MCP20 MCP server announced in llms.txt
MCP21 MCP server listed in at least one public registry (mcp.so, mcpservers.org, Smithery)
MCP22 Schema.org potentialAction references MCP endpoint where applicable
MCP23 Tools cover the high-value transactions for the site's primary intent
MCP24 No internal IDs or sensitive data exposed in responses
MCP25 CORS configured to permit legitimate browser-based agents
MCP26 Versioning strategy in place for future protocol changes
MCP27 Documentation page exists describing the MCP server publicly
MCP28 Tested against real agent workflow (Claude or equivalent) end to end
MCP29 Production monitoring captures agent traffic volume and patterns
MCP30 Audit log of agent actions retained for transactional tools

Score: 30. Tiers:

27 to 30: World class MCP implementation. Ready for production agent traffic. 22 to 26: Good foundation, some refinement needed. 17 to 21: Functional but missing important pieces. Schedule retrofit. Below 17: Implementation is incomplete. Address gaps before announcing to registries.


12. Retrofit and Greenfield Strategies

12.1 Greenfield Build

For new sites, add MCP to the build plan from the start:

Week 1: Content First Architecture (framework-contentfirst.md) applied
Week 2: Technical SEO foundation in place
Week 3: Schema implementation
Week 4: MCP server architecture decision (hosting, primitives)
Week 5: MCP server tools implementation for public tier
Week 6: MCP server resources implementation
Week 7: Authentication and transactional tools
Week 8: Validation, monitoring, registry submission

The MCP server can launch with public tier tools and resources only, with transactional tools added in a subsequent release once OAuth and payment integration are confirmed working.

12.2 Retrofit Existing Site

For existing sites without MCP:

retrofit_phases:

  phase_1_assessment:
    duration: "1 week"
    activities:
      - Audit site for transactional intent (booking, purchase, inquiry)
      - Identify existing backend APIs that can back MCP tools
      - Score current state against MCP Audit Rubric (will be near zero)
      - Decide hosting pattern (same origin vs subdomain vs edge)

  phase_2_public_tier:
    duration: "2 to 4 weeks"
    activities:
      - Implement /.well-known/mcp.json discovery
      - Implement public tier tools (list_services, get_hours, etc.)
      - Implement public resources
      - Validate with MCP Inspector
      - Announce in robots.txt and llms.txt

  phase_3_identified_tier:
    duration: "2 to 4 weeks"
    activities:
      - Implement identified tier tools (submit_inquiry, request_quote)
      - Add rate limiting per identity
      - Implement abuse detection
      - Validate end to end with Claude Desktop

  phase_4_transactional_tier:
    duration: "4 to 8 weeks"
    activities:
      - Implement OAuth 2.1
      - Implement transactional tools (book, purchase, subscribe)
      - Integrate with payment processor
      - Implement audit logging
      - Validate complete workflow with real agent

  phase_5_production_readiness:
    duration: "2 weeks"
    activities:
      - Production monitoring setup
      - Documentation page
      - Registry submissions
      - Internal training
      - Soft launch with limited agent traffic

Total retrofit timeline: 11 to 19 weeks depending on site complexity and existing API readiness.


13. The Forward State

Where MCP is headed beyond 2026:

Deeper Schema integration. Schema.org is likely to formalize MCP-aware markup, allowing sites to express MCP capabilities directly in JSON-LD. This will make discovery automatic for any agent that crawls schema.

Agent identity standards. A standard for verifying that an inbound agent represents a specific user, allowing sites to grant per-user authorization tokens rather than per-agent. Likely an extension of OAuth or a new lightweight protocol.

Transaction confirmation protocols. Beyond MCP, emerging protocols for atomic transactions where the agent confirms with the user mid-flow. Important for high-value purchases.

Cross-site agent flows. Agents booking across multiple sites in a single intent ("book the flight, hotel, and car for next weekend in Branson"). MCP servers will need to coordinate or expose enough state for agents to compose multi-site workflows.

Agent-native commerce protocols. Specialized protocols on top of MCP for commerce-specific patterns (cart, checkout, refund, dispute). Possibly an "MCP Commerce" extension.

Identity-bound agent reputation. Agents accumulate reputation across sites. Sites may differentiate behavior based on agent reputation scores. Reputation infrastructure is being designed in 2026.

Regulatory frameworks. Governments will eventually regulate agent commerce. Sites that have working MCP infrastructure will adapt; sites that did not will scramble to comply.

The framework will need updates as these emerge. Treat MCP for Websites as a living domain.


14. End of Framework Document

This is the first comprehensive framework for Model Context Protocol implementation on commercial websites. The protocol is stable. The client ecosystem is broad. The server ecosystem for business websites is sparse. The window to establish agent addressability advantage is open in 2026 and will close as the rest of the market catches up.

Apply this framework after framework-contentfirst.md is in place. Build the MCP server in tiers: public, identified, transactional. Validate at every tier with real agents. Monitor production traffic. Iterate.

The websites that win the agentic web of the next decade are the ones that started building agent surfaces in 2026.

Companion documents:


Document version: 1.0 Created: 2026-05-11 Maintained by: ThatDeveloperGuy

This document is the first systematic treatment of MCP for websites. Apply after Content First Architecture. Build agent addressability before competitors realize the surface exists.

Owner: Joseph W. Anady — ThatDeveloperGuy — SDVOSB Contact: 505-512-3662 | joseph.w.anady@icloud.com

Want this framework implemented on your site?

ThatDevPro ships these frameworks as productized services. SDVOSB-certified veteran owned. Cassville, Missouri.

See Engine Optimization service ›