The web is shifting from a read-only relationship with AI to a read-write one. While robots.txt controls what AI crawlers can see and llms.txt helps them understand your site, MCP (Model Context Protocol) enables them to interact with your product. An AI agent with MCP access can search your product catalogue, check pricing, submit a contact form, or query your API -- all without a human writing code or clicking buttons.
MCP was developed by Anthropic and released as an open protocol. It defines how AI models discover, authenticate with, and call tools exposed by external servers. Since its release, MCP has been adopted across the AI ecosystem: Claude Desktop, ChatGPT plugins, VS Code extensions, and dozens of AI coding assistants now support MCP connections.
This guide walks through the complete implementation: the mcp.json discovery manifest, a Next.js API route implementation, tool definition patterns, authentication, and testing with Claude Desktop and MCP Inspector. Use the AgentReady scanner to check if your site already has MCP configured.
What is MCP?
MCP (Model Context Protocol) is a standardised protocol for connecting AI models to external tools and data sources. Think of it as a universal plugin system for AI. Instead of each AI platform having its own proprietary plugin format, MCP provides a single standard that works across platforms.
How MCP works
The flow is straightforward:
- Discovery: An AI agent finds your
mcp.jsonmanifest athttps://yourdomain.com/mcp.json - Connection: The agent connects to your MCP endpoint (e.g.,
/api/mcp) - Tool listing: The agent sends a GET request to list available tools
- Tool execution: The agent sends a POST request to call a specific tool with parameters
- Response: Your server executes the tool and returns the result
MCP vs REST APIs
You might wonder why you need MCP if you already have a REST API. The key difference is the audience:
| Aspect | REST API | MCP Server |
|---|---|---|
| Designed for | Human developers | AI agents |
| Discovery | Documentation site | mcp.json manifest (machine-readable) |
| Tool descriptions | Written for developers | Natural language for AI comprehension |
| Input schemas | OpenAPI/Swagger | JSON Schema with AI-friendly descriptions |
| Error handling | HTTP status codes | Structured error messages AI can interpret |
| Auth | API keys, OAuth | Bearer tokens (simple by design) |
In practice, your MCP server often wraps your existing API or database queries, adding an AI-friendly layer on top.
The mcp.json Manifest
The mcp.json file is the entry point for AI agents. Place it at public/mcp.json in your Next.js project so it is served at /mcp.json.
{
"name": "your-product",
"description": "One-line description of what your product does",
"endpoint": "https://yourdomain.com/api/mcp",
"protocol": "mcp-http",
"auth": {
"type": "bearer",
"header": "Authorization"
},
"tools": [
{
"name": "get_services",
"description": "Get a list of all services offered",
"scope": "read"
},
{
"name": "search_content",
"description": "Search articles, guides, and blog posts by keyword",
"scope": "read"
},
{
"name": "create_contact",
"description": "Submit a contact enquiry with name, email, and message",
"scope": "write"
}
]
}
Manifest fields
| Field | Required | Description |
|---|---|---|
name | Yes | Machine-friendly identifier (lowercase, hyphens) |
description | Yes | One-line human-readable description |
endpoint | Yes | Full URL to your MCP API route |
protocol | Yes | Protocol type (mcp-http for HTTP-based) |
auth | No | Authentication requirements |
tools | Yes | Array of available tools with name, description, and scope |
Building the MCP Endpoint in Next.js
Your MCP server is a single API route that handles two types of requests:
- GET: Returns server information and available tools (public, no auth needed)
- POST: Executes a tool with parameters (may require auth)
Basic implementation
// app/api/mcp/route.ts
import { NextRequest, NextResponse } from 'next/server'
// Define your tools
const TOOLS = [
{
name: 'get_services',
description: 'Get a list of all services offered by the company',
inputSchema: {
type: 'object',
properties: {},
required: [],
},
},
{
name: 'search_content',
description: 'Search articles, guides, and blog posts by keyword',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Search keyword or phrase',
},
limit: {
type: 'number',
description: 'Maximum number of results (default: 5)',
},
},
required: ['query'],
},
},
{
name: 'get_pricing',
description: 'Get current pricing information for all plans',
inputSchema: {
type: 'object',
properties: {},
required: [],
},
},
{
name: 'create_contact',
description: 'Submit a contact enquiry',
inputSchema: {
type: 'object',
properties: {
name: { type: 'string', description: 'Full name' },
email: { type: 'string', description: 'Email address' },
message: { type: 'string', description: 'Message or enquiry' },
},
required: ['name', 'email', 'message'],
},
},
]
// GET: Return server info and tools
export async function GET() {
return NextResponse.json({
name: 'your-product',
description: 'Your product description',
version: '1.0.0',
tools: TOOLS,
})
}
// POST: Execute a tool
export async function POST(req: NextRequest) {
try {
const body = await req.json()
const { tool, parameters } = body
if (!tool) {
return NextResponse.json(
{ error: 'Missing tool name' },
{ status: 400 }
)
}
// Route to the appropriate handler
switch (tool) {
case 'get_services':
return NextResponse.json(await handleGetServices())
case 'search_content':
return NextResponse.json(
await handleSearchContent(parameters)
)
case 'get_pricing':
return NextResponse.json(await handleGetPricing())
case 'create_contact':
return NextResponse.json(
await handleCreateContact(parameters)
)
default:
return NextResponse.json(
{ error: `Unknown tool: ${tool}` },
{ status: 404 }
)
}
} catch (error) {
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
)
}
}
// Tool handlers
async function handleGetServices() {
return {
services: [
{
name: 'AI Agent Development',
description: 'Custom voice and chat agents',
priceRange: '10,000 - 20,000 GBP',
},
{
name: 'Web Application',
description: 'Full-stack web applications',
priceRange: '3,000 - 15,000 GBP',
},
{
name: 'Fractional CPO',
description: 'Ongoing product leadership',
priceRange: '2,500 - 3,000 GBP/month',
},
],
}
}
async function handleSearchContent(params: {
query: string
limit?: number
}) {
const limit = params.limit || 5
// In production, query your database or search index
return {
results: [
{
title: 'AI Crawlers Guide',
url: '/guides/ai-crawlers-guide.html',
snippet: 'Complete reference for all AI crawlers...',
},
],
total: 1,
query: params.query,
}
}
async function handleGetPricing() {
return {
plans: [
{ name: 'Quick Win', price: '1,500 - 3,500 GBP', type: 'one-time' },
{ name: 'Project', price: '3,000 - 20,000 GBP', type: 'one-time' },
{ name: 'Retainer', price: '2,500 - 3,000 GBP/month', type: 'recurring' },
],
}
}
async function handleCreateContact(params: {
name: string
email: string
message: string
}) {
// Validate inputs
if (!params.email.includes('@')) {
return { error: 'Invalid email address', success: false }
}
// In production, save to database and send notification
return {
success: true,
message: `Thank you ${params.name}. We will be in touch shortly.`,
}
}
Adding authentication
For tools that modify data or access sensitive information, add Bearer token authentication:
// Add at the top of the POST handler
export async function POST(req: NextRequest) {
const body = await req.json()
const { tool, parameters } = body
// Tools that require auth
const protectedTools = ['create_contact', 'get_analytics']
if (protectedTools.includes(tool)) {
const authHeader = req.headers.get('Authorization')
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return NextResponse.json(
{ error: 'Authentication required' },
{ status: 401 }
)
}
const token = authHeader.slice(7)
if (token !== process.env.MCP_API_TOKEN) {
return NextResponse.json(
{ error: 'Invalid token' },
{ status: 403 }
)
}
}
// ... rest of the handler
}
Tool Design Best Practices
Write descriptions for AI, not developers
Tool descriptions should be clear, specific natural language that helps an AI model decide when to use the tool. Compare:
// Bad: Developer-oriented
"name": "get_svc_list",
"description": "Returns JSON array of service objects"
// Good: AI-oriented
"name": "get_services",
"description": "Get a list of all services offered by p0stman, including AI agent development, web applications, and fractional CPO retainers, with pricing ranges for each"
Use clear input schemas
Every parameter should have a description that tells the AI what value to provide:
{
"name": "search_content",
"description": "Search published articles, guides, case studies, and blog posts",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search keyword or phrase to find relevant content"
},
"category": {
"type": "string",
"enum": ["guides", "case-studies", "blog", "all"],
"description": "Filter results by content category (default: all)"
},
"limit": {
"type": "number",
"description": "Maximum number of results to return (default: 5, max: 20)"
}
},
"required": ["query"]
}
}
Start with read-only tools
Begin with 2-3 safe, read-only tools that provide genuine value:
- get_services -- list what you offer
- search_content -- search your content library
- get_pricing -- return current pricing
- get_case_studies -- list client work and results
Only add write tools (create_contact, book_demo, submit_form) once your read tools are working well and you have authentication in place.
Return structured, useful responses
AI models work best with structured JSON responses. Include relevant context, not just raw data:
// Bad: Raw data
{ "services": ["AI Agents", "Web Apps", "Mobile Apps"] }
// Good: Structured with context
{
"services": [
{
"name": "AI Agent Development",
"description": "Custom voice and chat agents using Gemini, Claude, and GPT",
"typicalTimeline": "4-8 weeks",
"priceRange": "10,000 - 20,000 GBP",
"url": "https://yourdomain.com/ai-agents"
}
],
"note": "All prices exclude VAT. Contact us for a custom quote."
}
WebMCP: Browser-Side Tool Registration
WebMCP is a complementary browser-side API that lets your website register tools directly with browser-based AI assistants. Available in Chrome 146+ via navigator.modelContext, it provides a lightweight alternative for public tools that do not need server authentication.
// components/web-mcp-registration.tsx
"use client"
import { useEffect } from "react"
export function WebMCPRegistration() {
useEffect(() => {
const nav = navigator as any
if (!nav.modelContext?.addTool) return
// Register public tools
nav.modelContext.addTool({
name: "get_p0stman_services",
description: "Get the list of services offered by p0stman",
handler: async () => ({
services: [
{ name: "AI Agent Development", price: "from 10,000 GBP" },
{ name: "Web Applications", price: "from 3,000 GBP" },
{ name: "Fractional CPO", price: "2,500 GBP/month" },
],
}),
})
nav.modelContext.addTool({
name: "navigate_to_contact",
description: "Navigate the user to the contact page to get in touch",
handler: async () => {
window.location.href = "/contact"
return { success: true, message: "Navigating to contact page" }
},
})
}, [])
return null
}
Add this component to your root layout. It gracefully no-ops on browsers that do not support the API.
Testing Your MCP Server
curl testing
Start with basic curl commands to verify your endpoints work:
# Test GET (server info and tools)
curl https://yourdomain.com/api/mcp
# Test a tool call
curl -X POST https://yourdomain.com/api/mcp \
-H "Content-Type: application/json" \
-d '{"tool": "get_services", "parameters": {}}'
# Test a tool with parameters
curl -X POST https://yourdomain.com/api/mcp \
-H "Content-Type: application/json" \
-d '{"tool": "search_content", "parameters": {"query": "AI agents"}}'
# Test with authentication
curl -X POST https://yourdomain.com/api/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token-here" \
-d '{"tool": "create_contact", "parameters": {"name": "Test", "email": "test@example.com", "message": "Hello"}}'
MCP Inspector
The MCP Inspector is an open-source tool for testing MCP protocol compliance. It connects to your server, lists tools, and lets you call them interactively. Install it from the MCP GitHub repository and point it at your endpoint.
Claude Desktop testing
Claude Desktop supports MCP server connections. To test with Claude Desktop, add your server to its configuration file:
// ~/.config/claude/claude_desktop_config.json (macOS)
{
"mcpServers": {
"your-product": {
"url": "https://yourdomain.com/api/mcp",
"transport": "http"
}
}
}
Restart Claude Desktop and your tools will appear in the conversation. Ask Claude to use your tools naturally: "What services does [your product] offer?" and Claude will call your get_services tool.
Real Example: p0stman.com MCP Server
The p0stman.com MCP server exposes tools for querying services, searching content, and interacting with the studio. Here is the production mcp.json:
{
"name": "p0stman",
"description": "AI-native product studio - voice agents, websites, and apps",
"endpoint": "https://p0stman.com/api/mcp",
"protocol": "mcp-http",
"auth": {
"type": "bearer",
"header": "Authorization"
},
"tools": [
{
"name": "get_services",
"description": "Get all services offered by p0stman including AI agents, web apps, mobile apps, and fractional CPO retainers with pricing",
"scope": "read"
},
{
"name": "get_case_studies",
"description": "Get case studies of client work including project description, tech stack, and results",
"scope": "read"
},
{
"name": "search_guides",
"description": "Search p0stman's library of AI and development guides by keyword",
"scope": "read"
}
]
}
You can test this live: curl https://p0stman.com/api/mcp
MCP in the AI Readiness Stack
MCP is the action layer of your AI readiness strategy. While other components handle discovery and comprehension, MCP enables AI agents to take action on your behalf:
- robots.txt -- controls crawler access (Layer 1: Discovery)
- llms.txt -- explains what your site does (Layer 2: Comprehension)
- Sitemap -- helps crawlers find content (Layer 1: Discovery)
- MCP server -- enables programmatic interaction (Layer 3: Action)
- A2A / agent.json -- agent-to-agent communication (Layer 4: A2A)
Run a complete audit of all layers with the AgentReady scanner.
Frequently Asked Questions
What is MCP (Model Context Protocol)?
MCP is an open protocol developed by Anthropic that enables AI models to interact with external tools and data sources. It provides a standardised way for AI systems to call functions, read resources, and take actions on your website or application, similar to how APIs work for traditional software but designed specifically for AI agent consumption.
What is the mcp.json manifest file?
mcp.json is a JSON file placed at /mcp.json on your domain that describes your MCP server endpoint, available tools, authentication requirements, and protocol version. It serves as the discovery mechanism for AI agents looking to interact with your product programmatically, similar to how robots.txt serves as a discovery mechanism for crawlers.
How does MCP differ from a regular REST API?
MCP is specifically designed for AI agent consumption, not human developers. Tools have natural language descriptions that help AI models understand when and how to use them. The protocol includes standardised request/response formats, tool discovery via mcp.json, and conventions for error handling that AI models can interpret without custom integration code.
Do I need authentication for my MCP server?
It depends on your tools. Public read-only tools like "get services" or "search content" can be unauthenticated. Tools that modify data, access user accounts, or perform actions should require Bearer token authentication. Many sites offer a mix of public and authenticated tools.
How do I test my MCP server?
Test with curl for basic validation, the MCP Inspector tool for protocol compliance, and Claude Desktop for real-world AI agent testing. Claude Desktop can be configured to connect to your MCP server and use your tools in conversation by adding your endpoint to its config file.
What tools should I expose via MCP?
Start with 2-3 read-only tools that provide genuine value: get_services, search_content, get_pricing. Then add action tools like create_contact or book_demo once you have authentication in place. Each tool should have a clear name, descriptive natural language description, and well-defined input schema. Avoid exposing internal admin functionality.
What is WebMCP and how does it relate to MCP servers?
WebMCP is a browser-side API (navigator.modelContext) available in Chrome 146+ that lets web pages register tools directly with browser-based AI assistants. It complements server-side MCP by providing lightweight, no-auth tools that work in the browser context without requiring a server round-trip. Use both for maximum coverage.
How does MCP relate to the A2A protocol?
MCP enables tool use -- AI agents calling specific functions on your server. A2A (Agent-to-Agent) enables task delegation -- one AI agent sending a task to another. They serve different purposes and can coexist: MCP for granular tool calls, A2A for high-level task routing between agents. Both use discovery files (mcp.json and .well-known/agent.json respectively).
By Paul Gosnell