Headless Products
API-only products designed for AI agents and automation with MCP servers
Headless Products
Headless Products are API-only services designed for programmatic consumption by AI agents, automation systems, and developers - with no human UI. Unlike traditional SaaS with web interfaces, headless products optimize for machine-to-machine communication, particularly via APIs and Model Context Protocol (MCP).
Headless products represent the next evolution of software - services consumed entirely by autonomous agents, with machine-readable schemas, structured tool definitions, and zero human interaction required.
Characteristics
| Aspect | Value |
|---|---|
| Revenue Model | Usage-based (pay-per-execution, pay-per-call) |
| Pricing | Per API call, per agent action, per token |
| Primary Interface | MCP servers, REST API, GraphQL, tRPC |
| Target User | AI agents, automation systems, developers |
| No Human UI | No web application for end users |
| Agent-First | Designed for autonomous consumption |
| Example Products | MCP tools, agent platforms, automation APIs |
MDXLD Definition
---
$context: https://schema.org.ai
$type: Product
$id: https://acme.com/products/agent-tools
name: Acme Agent Toolkit
type: Headless
business: https://acme.com
description: Headless automation tools for AI agents
isActive: true
# Categorization
industries:
- AI & Automation
- Developer Tools
productCategories:
- Agent Platform
- Automation Tools
- Headless Services
# Interfaces (no human UI)
interfaces:
hasAPI: true
hasRPC: true
hasMCP: true # Primary interface for AI agents
hasSDK: true
hasCLI: true
hasWebUI: false # No web application
# Agent capabilities
agentCapabilities:
- Web scraping
- Data enrichment
- Document processing
- Image generation
- Email automation
- Webhook delivery
# Pricing (usage-based)
prices:
- $id: price_payg
name: Pay as You Go
type: usage
interval: execution
tiers:
- upTo: 1000
amount: 0.10
description: First 1K executions: $0.10 each
- upTo: 10000
amount: 0.05
description: 1K-10K executions: $0.05 each
- upTo: Infinity
amount: 0.02
description: 10K+ executions: $0.02 each
---
# {name}
{description}
<Hero
title={name}
subtitle="API-first tools for AI agents"
cta="View MCP Tools"
/>
## MCP Tools
<MCPTools product={$id} />
## API Reference
<APIReference product={$id} />
## Agent Integration
<AgentIntegration product={$id} />
## Pricing
<Pricing prices={prices} />Why Headless?
No UI Needed
Traditional products require human interfaces:
- Web dashboards
- Forms and inputs
- Visual feedback
- Navigation menus
Headless products skip all this - agents consume APIs directly:
// Traditional SaaS: User clicks through UI
User → Dashboard → Form → Submit → View Result
// Headless: Agent calls API directly
Agent → API Call → Process ResponseAgent-First Design
Optimized for AI agent consumption:
| Aspect | Traditional UI | Headless API |
|---|---|---|
| Interface | HTML/CSS/JS | JSON/RPC/MCP |
| Interaction | Clicks, forms | Function calls |
| Feedback | Visual UI | Structured data |
| Documentation | Screenshots, tutorials | API reference, schemas |
| Auth | Username/password | API keys, OAuth |
Component Structure
APISite (Developer Docs Only)
// Documentation site (no app UI)
<APISite product={headlessProduct}>
<Header />
<LandingPage>
<Hero />
<ToolsList /> // MCP tools available
<CodeExamples />
<Pricing />
</LandingPage>
<APIReference />
<MCPReference />
<Footer />
</APISite>HeadlessApp (Admin Dashboard)
// Admin/monitoring dashboard (not the product itself)
<HeadlessApp product={headlessProduct}>
<Shell>
<Sidebar />
<Dashboard>
<UsageMetrics />
<APIKeys />
<AgentLogs /> // Log of agent executions
<Billing />
</Dashboard>
</Shell>
</HeadlessApp>The dashboard is for monitoring and administration only - the actual product is consumed via API/MCP.
MCP Servers - The Foundation
Model Context Protocol (MCP) is the primary interface for headless products consumed by AI agents. MCP servers expose tools, resources, and prompts that agents can discover and use autonomously.
MCP Server Architecture
// MCP Server Definition
interface MCPServer {
name: string // Server identifier
version: string // Semantic version
description: string // What this server provides
tools: Tool[] // Available tools
resources: Resource[] // Available resources
prompts: Prompt[] // Available prompts
capabilities: ServerCapabilities // Server capabilities
}
// Example: Document Processing MCP Server
const docProcessingServer: MCPServer = {
name: 'document-processor',
version: '1.0.0',
description: 'Document analysis and transformation tools',
tools: [
convertPDFTool,
extractTextTool,
ocrImageTool,
generateSummaryTool
],
resources: [
{ uri: 'document://{id}', type: 'document' }
],
prompts: [],
capabilities: {
tools: { supported: true },
resources: { supported: true, subscribe: false },
prompts: { supported: false }
}
}Tool Definitions
Tools are the core primitives of MCP servers - discrete capabilities that agents can invoke:
interface Tool {
name: string // Unique tool identifier
description: string // Natural language description for AI
inputSchema: JSONSchema // JSON Schema for input validation
execute: (input: any) => Promise<ToolResult>
}
// Example: PDF to Text Converter
const convertPDFTool: Tool = {
name: 'convert_pdf_to_text',
description: 'Convert PDF document to plain text with metadata extraction',
inputSchema: {
type: 'object',
properties: {
url: {
type: 'string',
format: 'uri',
description: 'URL of PDF file to convert'
},
pages: {
type: 'array',
items: { type: 'number' },
description: 'Specific pages to extract (optional, defaults to all)'
},
includeMetadata: {
type: 'boolean',
default: true,
description: 'Include document metadata in response'
}
},
required: ['url']
},
execute: async ({ url, pages, includeMetadata }) => {
const doc = await fetchPDF(url)
const text = await extractText(doc, pages)
const metadata = includeMetadata ? await extractMetadata(doc) : null
return {
content: [{
type: 'text',
text: text
}],
metadata: metadata,
isError: false
}
}
}
// Example: Web Scraper Tool
const scrapeTool: Tool = {
name: 'scrape_url',
description: 'Extract structured content from web pages',
inputSchema: {
type: 'object',
properties: {
url: {
type: 'string',
format: 'uri',
description: 'Web page URL to scrape'
},
selector: {
type: 'string',
description: 'CSS selector for content extraction (optional)'
},
extractLinks: {
type: 'boolean',
default: false,
description: 'Extract all links from page'
}
},
required: ['url']
},
execute: async ({ url, selector, extractLinks }) => {
const page = await fetchPage(url)
const content = selector ? await extract(page, selector) : page.text
const links = extractLinks ? await getLinks(page) : []
return {
content: [{
type: 'text',
text: content
}],
metadata: { links, title: page.title },
isError: false
}
}
}Tool Categories
Organize tools by capability category:
interface ToolCategory {
category: string
description: string
tools: string[] // Tool names in this category
}
const toolCategories: ToolCategory[] = [
{
category: 'data',
description: 'Data operations and transformations',
tools: ['query_database', 'transform_data', 'validate_schema']
},
{
category: 'communication',
description: 'Email, SMS, and messaging',
tools: ['send_email', 'send_sms', 'post_slack_message']
},
{
category: 'file',
description: 'File operations and storage',
tools: ['upload_file', 'download_file', 'convert_pdf_to_text']
},
{
category: 'web',
description: 'Web scraping and HTTP operations',
tools: ['scrape_url', 'fetch_api', 'screenshot_page']
},
{
category: 'ai',
description: 'AI and ML operations',
tools: ['generate_image', 'transcribe_audio', 'classify_text']
}
]Agent Consumption
Agents discover and use tools via MCP:
// Agent discovers available tools
const server = await mcp.connect('document-processor')
const tools = await server.listTools()
console.log(tools.map(t => t.name))
// ['convert_pdf_to_text', 'extract_text', 'ocr_image', 'generate_summary']
// Agent invokes tool
const result = await server.callTool('convert_pdf_to_text', {
url: 'https://example.com/document.pdf',
pages: [1, 2, 3],
includeMetadata: true
})
// Process result
if (!result.isError) {
const text = result.content[0].text
const metadata = result.metadata
// Use extracted text and metadata
}Resources - Dynamic Content
Resources provide access to dynamic data that agents can read:
interface Resource {
uri: string // Resource URI (e.g., document://{id})
name: string // Human-readable name
description: string // What this resource contains
mimeType: string // Content type
}
// Example: Document resource
const documentResource: Resource = {
uri: 'document://invoice-{id}',
name: 'Invoice Document',
description: 'Access invoice documents by ID',
mimeType: 'application/pdf'
}
// Agent reads resource
const doc = await server.readResource('document://invoice-12345')Prompts - Reusable Templates
Prompts are reusable prompt templates that agents can invoke:
interface Prompt {
name: string // Prompt identifier
description: string // What this prompt does
arguments: PromptArgument[] // Required/optional arguments
}
const summaryPrompt: Prompt = {
name: 'summarize_document',
description: 'Generate executive summary of document',
arguments: [
{
name: 'document',
description: 'Document text to summarize',
required: true
},
{
name: 'length',
description: 'Summary length (short/medium/long)',
required: false
}
]
}
// Agent gets prompt
const prompt = await server.getPrompt('summarize_document', {
document: documentText,
length: 'medium'
})
// Returns structured prompt with messages
const summary = await agent.complete(prompt.messages)Learn more: Model Context Protocol
AI Agents - Autonomous Consumers
AI agents are the primary consumers of headless products. Unlike human users clicking through UIs, agents autonomously discover, plan, and execute tool sequences to accomplish goals.
Agent Architecture
interface Agent {
$id: string // Agent identifier
name: string // Agent name
role: string // Agent purpose/specialty
systemPrompt: string // Behavioral instructions
model: AIModel // LLM configuration
tools: string[] // Available MCP tools
memory: AgentMemory // Conversation history
capabilities: string[] // What agent can do
}
// Example: Document Processing Agent
const docAgent: Agent = {
$id: 'agent://doc-processor',
name: 'Document Processor',
role: 'Extract, transform, and analyze documents',
systemPrompt: `You are a document processing specialist.
Use available tools to convert, extract, and analyze documents.
Always validate inputs and handle errors gracefully.`,
model: {
provider: 'anthropic',
model: 'claude-3-5-sonnet-20241022',
temperature: 0.3,
maxTokens: 4096
},
tools: [
'convert_pdf_to_text',
'extract_text',
'ocr_image',
'generate_summary'
],
memory: {
type: 'session',
maxTokens: 10000
},
capabilities: [
'text',
'analysis',
'execution'
]
}Agent Workflows
Agents orchestrate multiple tool calls to accomplish complex tasks:
// Agent processes invoice workflow
async function processInvoice(invoiceUrl: string) {
// Step 1: Convert PDF to text
const extracted = await agent.useTool('convert_pdf_to_text', {
url: invoiceUrl,
includeMetadata: true
})
// Step 2: Extract structured data
const parsed = await agent.useTool('extract_invoice_data', {
text: extracted.content[0].text
})
// Step 3: Validate against schema
const validated = await agent.useTool('validate_invoice', {
data: parsed.invoice
})
// Step 4: Store in database
if (validated.isValid) {
await agent.useTool('store_invoice', {
invoice: validated.data
})
}
return validated
}Agent Teams
Multiple specialized agents working together:
interface AgentTeam {
$id: string
name: string
agents: string[] // Agent IDs
orchestration: 'sequential' | 'parallel' | 'hierarchical'
communication: 'broadcast' | 'directed' | 'shared_context'
}
// Example: Data Pipeline Team
const pipelineTeam: AgentTeam = {
$id: 'team://data-pipeline',
name: 'Data Pipeline Team',
agents: [
'agent://extractor', // Extracts data from sources
'agent://transformer', // Transforms and cleans data
'agent://validator', // Validates quality
'agent://loader' // Loads into destination
],
orchestration: 'sequential',
communication: 'shared_context'
}
// Orchestrate team execution
async function runPipeline(source: string) {
// Extractor agent
const raw = await extractor.extract(source)
// Transformer agent
const cleaned = await transformer.transform(raw)
// Validator agent
const validated = await validator.validate(cleaned)
// Loader agent (only if validation passes)
if (validated.isValid) {
await loader.load(validated.data)
}
return validated
}Agent Authentication
Agents authenticate using API keys or service accounts:
interface AgentAPIKey {
id: string
name: string // e.g., "Production Pipeline Agent"
key: string // sk_agent_...
type: 'agent' | 'service'
agentId: string // Associated agent
scopes: string[] // Allowed tools/operations
rateLimit: {
requestsPerMinute: number
requestsPerDay: number
}
createdAt: Date
expiresAt: Date | null
}
// Create agent key
const agentKey = await createAPIKey({
name: 'Document Processor Agent',
type: 'agent',
agentId: 'agent://doc-processor',
scopes: [
'tools:convert_pdf_to_text',
'tools:extract_text',
'tools:ocr_image',
'tools:generate_summary'
],
rateLimit: {
requestsPerMinute: 60,
requestsPerDay: 10000
},
expiresAt: null // Never expires
})
// Agent authenticates
const client = new MCPClient({
apiKey: agentKey.key,
serverUrl: 'https://api.acme.com/mcp'
})API Playground - Interactive Testing
The API Playground provides interactive testing for MCP tools and REST APIs:
Playground Features
interface APIPlayground {
/** Available endpoints/tools */
endpoints: Endpoint[]
/** Request builder */
requestBuilder: RequestBuilder
/** Response viewer */
responseViewer: ResponseViewer
/** Request history */
history: RequestHistory[]
/** Code generation */
codeGenerator: CodeGenerator
}
interface Endpoint {
id: string
method: 'GET' | 'POST' | 'PUT' | 'DELETE'
path: string
description: string
parameters: Parameter[]
requestBody?: JSONSchema
responses: ResponseExample[]
}Interactive Request Builder
// Playground UI state
interface PlaygroundState {
selectedEndpoint: string
request: {
method: string
url: string
headers: Record<string, string>
body: any
auth: {
type: 'api_key' | 'bearer' | 'basic'
credentials: Record<string, string>
}
}
response: {
status: number
statusText: string
headers: Record<string, string>
body: any
duration: number
} | null
loading: boolean
error: string | null
}
// Playground execution
async function executeRequest(state: PlaygroundState) {
const startTime = Date.now()
try {
const response = await fetch(state.request.url, {
method: state.request.method,
headers: {
...state.request.headers,
'Authorization': getAuthHeader(state.request.auth)
},
body: state.request.body ? JSON.stringify(state.request.body) : undefined
})
const body = await response.json()
const duration = Date.now() - startTime
return {
status: response.status,
statusText: response.statusText,
headers: Object.fromEntries(response.headers),
body,
duration
}
} catch (error) {
throw new Error(`Request failed: ${error.message}`)
}
}MCP Tool Testing
// Test MCP tool in playground
interface MCPToolTest {
tool: string // Tool name
input: Record<string, any> // Tool input parameters
expectedOutput?: any // Expected result
}
// Playground MCP testing
async function testMCPTool(test: MCPToolTest) {
const server = await mcp.connect()
// Get tool definition
const toolDef = await server.getTool(test.tool)
// Validate input against schema
const validation = validateAgainstSchema(test.input, toolDef.inputSchema)
if (!validation.valid) {
return {
success: false,
errors: validation.errors
}
}
// Execute tool
const startTime = Date.now()
const result = await server.callTool(test.tool, test.input)
const duration = Date.now() - startTime
return {
success: !result.isError,
result: result.content,
metadata: result.metadata,
duration,
matched: test.expectedOutput
? deepEqual(result.content, test.expectedOutput)
: undefined
}
}
// Example: Test document conversion in playground
const testResult = await testMCPTool({
tool: 'convert_pdf_to_text',
input: {
url: 'https://example.com/sample.pdf',
pages: [1],
includeMetadata: true
},
expectedOutput: {
type: 'text',
text: expect.stringContaining('Invoice')
}
})Code Generation
Generate code snippets in multiple languages:
interface CodeGenerator {
language: 'typescript' | 'python' | 'curl' | 'go' | 'rust'
request: Request
options: {
includeAuth: boolean
includeHeaders: boolean
includeComments: boolean
}
}
// Generate TypeScript client code
function generateTypeScript(request: Request): string {
return `
// Install MCP client
// npm install @modelcontextprotocol/sdk
import { Client } from '@modelcontextprotocol/sdk/client'
const client = new Client({
name: 'my-app',
version: '1.0.0'
})
// Connect to server
const transport = new StdioClientTransport({
command: 'npx',
args: ['-y', '@acme/mcp-server'],
env: {
ACME_API_KEY: process.env.ACME_API_KEY
}
})
await client.connect(transport)
// Call tool
const result = await client.callTool({
name: '${request.tool}',
arguments: ${JSON.stringify(request.input, null, 2)}
})
console.log(result)
`.trim()
}
// Generate Python client code
function generatePython(request: Request): string {
return `
# Install MCP client
# pip install mcp
from mcp import Client, StdioServerParameters
async def main():
server = StdioServerParameters(
command="npx",
args=["-y", "@acme/mcp-server"],
env={"ACME_API_KEY": os.environ["ACME_API_KEY"]}
)
async with Client("my-app", "1.0.0") as client:
await client.connect(server)
result = await client.call_tool(
"${request.tool}",
${JSON.stringify(request.input, null, 4)}
)
print(result)
`.trim()
}Request History
Track and replay previous requests:
interface RequestHistory {
id: string
timestamp: Date
request: Request
response: Response
duration: number
success: boolean
}
// Save to history
function saveToHistory(entry: RequestHistory) {
const history = getHistory()
history.unshift(entry)
setHistory(history.slice(0, 50)) // Keep last 50 requests
}
// Replay from history
async function replayRequest(historyId: string) {
const entry = getHistory().find(h => h.id === historyId)
if (!entry) throw new Error('Request not found in history')
return await executeRequest({
...entry.request,
// Update any expired credentials
auth: refreshAuth(entry.request.auth)
})
}Integration Patterns
Pattern 1: Direct MCP Integration
Agents connect directly to MCP server:
// Claude Desktop config (claude_desktop_config.json)
{
"mcpServers": {
"acme-tools": {
"command": "npx",
"args": ["-y", "@acme/mcp-server"],
"env": {
"ACME_API_KEY": "sk_..."
}
}
}
}
// Agent can now use tools
Human: Convert this PDF and extract the invoice data
Claude: [Uses convert_pdf_to_text and extract_invoice_data tools]Pattern 2: REST API Wrapper
Expose MCP tools via REST API:
// REST endpoint wrapping MCP tool
app.post('/api/v1/tools/:tool', async (req, res) => {
const { tool } = req.params
const input = req.body
// Authenticate
const apiKey = req.headers['x-api-key']
const agent = await authenticateAgent(apiKey)
// Check permissions
if (!agent.scopes.includes(`tools:${tool}`)) {
return res.status(403).json({ error: 'Insufficient permissions' })
}
// Execute tool via MCP
const result = await mcpServer.callTool(tool, input)
// Track usage for billing
await trackUsage({
agentId: agent.id,
tool,
timestamp: new Date(),
cost: calculateCost(tool, result)
})
res.json(result)
})Pattern 3: Workflow Orchestration
Chain multiple tools together:
interface Workflow {
id: string
name: string
steps: WorkflowStep[]
}
interface WorkflowStep {
id: string
tool: string
input: Record<string, any> | string // Static or template
output: string // Variable name
}
// Example: Invoice processing workflow
const invoiceWorkflow: Workflow = {
id: 'wf-invoice',
name: 'Invoice Processing',
steps: [
{
id: 'extract',
tool: 'convert_pdf_to_text',
input: { url: '{{input.invoiceUrl}}' },
output: 'extracted'
},
{
id: 'parse',
tool: 'extract_invoice_data',
input: { text: '{{extracted.content[0].text}}' },
output: 'invoice'
},
{
id: 'validate',
tool: 'validate_invoice',
input: { data: '{{invoice}}' },
output: 'validated'
},
{
id: 'store',
tool: 'store_invoice',
input: { invoice: '{{validated.data}}' },
output: 'result'
}
]
}
// Execute workflow
async function executeWorkflow(workflow: Workflow, input: any) {
const context: Record<string, any> = { input }
for (const step of workflow.steps) {
// Resolve input template
const resolvedInput = resolveTemplate(step.input, context)
// Execute tool
const result = await mcpServer.callTool(step.tool, resolvedInput)
// Store output
context[step.output] = result
}
return context
}Pattern 4: Event-Driven Triggers
Trigger workflows from external events:
interface Trigger {
id: string
type: 'webhook' | 'schedule' | 'event'
config: any
workflow: string // Workflow to execute
enabled: boolean
}
// Webhook trigger
const webhookTrigger: Trigger = {
id: 'trigger-new-invoice',
type: 'webhook',
config: {
url: '/webhooks/new-invoice',
method: 'POST',
auth: 'secret'
},
workflow: 'wf-invoice',
enabled: true
}
// Handle webhook
app.post('/webhooks/new-invoice', async (req, res) => {
const { invoiceUrl } = req.body
// Execute workflow asynchronously
executeWorkflow(invoiceWorkflow, { invoiceUrl })
.catch(error => console.error('Workflow failed:', error))
res.json({ status: 'processing' })
})Pattern 5: Agent-to-Agent Communication
Agents communicate through shared MCP servers:
// Agent A produces data
const extractorAgent = {
async run() {
const data = await this.tool('extract_data', { source })
// Store in shared resource
await this.tool('store_resource', {
uri: 'data://extracted/batch-123',
content: data
})
// Notify next agent
await this.tool('send_event', {
type: 'data_extracted',
data: { uri: 'data://extracted/batch-123' }
})
}
}
// Agent B consumes data
const transformerAgent = {
async onEvent(event: Event) {
if (event.type === 'data_extracted') {
// Read from shared resource
const data = await this.tool('read_resource', {
uri: event.data.uri
})
// Transform
const transformed = await this.tool('transform_data', {
data: data.content
})
// Store result
await this.tool('store_resource', {
uri: 'data://transformed/batch-123',
content: transformed
})
}
}
}Pricing Models
Per-Execution Pricing
Charge each time an agent invokes a tool:
interface PerExecutionPricing {
type: 'usage'
interval: 'execution'
amount: number // e.g., $0.10 per execution
tiers?: Array<{
upTo: number
amount: number
}>
}Example: $0.10 per web scrape, $0.05 per enrichment lookup
Per-Token Pricing
Charge based on API tokens or data processed:
interface PerTokenPricing {
type: 'usage'
interval: 'token'
inputTokens: number // $0.001 per 1K input tokens
outputTokens: number // $0.002 per 1K output tokens
}Example: Similar to OpenAI API pricing
Time-Based Pricing
Charge for compute time:
interface TimeBasedPricing {
type: 'usage'
interval: 'second'
amount: number // e.g., $0.001 per second
}Example: $0.001 per second of execution time
Hybrid Pricing
Combination of subscription + usage:
interface HybridPricing {
subscription: {
amount: number // $99/month
includedExecutions: number // 10,000 executions included
}
overage: number // $0.01 per additional execution
}Use Cases
Agent Tools
product: Agent Toolkit
type: Headless
tools:
- Web scraping
- Screenshot capture
- PDF generation
- Email sending
- File storage
- Webhook delivery
interfaces:
- MCP (primary)
- REST API
- tRPC
pricing:
- $0.01 per tool execution
- Volume discounts available
customers:
- AI agents (Claude, GPT, etc.)
- Automation platforms (Zapier, Make)
- Internal workflowsData Enrichment
product: Enrichment Engine
type: Headless
capabilities:
- Email → Company data
- Domain → Firmographics
- LinkedIn → Person data
- IP → Location data
interfaces:
- REST API
- MCP tools
- Batch processing
pricing:
- $0.10 per enrichment
- $0.05 per validation
- Real-time or batch
customers:
- Sales automation agents
- Marketing platforms
- CRM integrationsAutomation Platform
product: AutoFlow
type: Headless
workflows:
- Multi-step automations
- Conditional logic
- Error handling
- Retry mechanisms
- Event triggers
interfaces:
- Workflow API
- MCP tools
- Webhook triggers
pricing:
- $0.001 per workflow execution
- $0.10 per hour compute time
- Free tier: 1,000 executions/month
customers:
- Business process automation
- Integration platforms
- AI agent orchestrationTechnical Implementation
REST API
// Traditional REST endpoints
POST /v1/tools/scrape
{
"url": "https://example.com",
"selector": "article"
}
Response:
{
"content": "...",
"title": "...",
"metadata": { ... }
}MCP Server
// MCP server implementation
import { Server } from '@modelcontextprotocol/sdk/server'
const server = new Server({
name: 'acme-agent-toolkit',
version: '1.0.0'
})
// Register tools
server.tool('scrape_url', scrapeSchema, scrapeHandler)
server.tool('enrich_email', enrichSchema, enrichHandler)
server.tool('send_email', emailSchema, emailHandler)
// Start server
await server.listen({ transport: 'stdio' })tRPC
// Type-safe RPC interface
import { initTRPC } from '@trpc/server'
const t = initTRPC.create()
export const appRouter = t.router({
scrape: t.procedure
.input(z.object({ url: z.string() }))
.mutation(async ({ input }) => {
return await scrapeUrl(input.url)
}),
enrich: t.procedure
.input(z.object({ email: z.string() }))
.query(async ({ input }) => {
return await enrichEmail(input.email)
})
})Monitoring & Observability
Execution Logs
interface ExecutionLog {
id: string
tool: string // Tool/function name
input: any // Input parameters
output?: any // Result (if successful)
error?: string // Error message (if failed)
duration: number // Execution time (ms)
cost: number // Billable amount
agent?: string // Agent identifier
timestamp: Date
}
// Track all agent executions
<AgentLogs product={headlessProduct}>
<ExecutionTimeline />
<ErrorRate />
<CostAnalysis />
<AgentBreakdown />
</AgentLogs>Performance Metrics
interface PerformanceMetrics {
totalExecutions: number
successRate: number // % successful executions
avgDuration: number // Average execution time
p50Duration: number // Median
p99Duration: number // 99th percentile
errorRate: number // % failed executions
retryRate: number // % retried executions
}Agent Authentication
API Keys
interface AgentAPIKey {
id: string
name: string // e.g., "Claude Production Agent"
key: string // sk_agent_...
type: 'agent' | 'service'
scopes: string[] // Allowed tools/permissions
rateLimit: number // Requests per minute
createdAt: Date
}
// Agent authenticates with key
const client = new AcmeClient({
apiKey: 'sk_agent_...'
})OAuth for Agents
// Service account OAuth flow
const token = await oauth.clientCredentials({
client_id: 'agent_client_id',
client_secret: 'agent_secret',
scope: 'tools:execute'
})Example Configurations
Complete MCP Server Configuration
Full example of a production-ready MCP server:
// server.ts - Complete MCP server implementation
import { Server } from '@modelcontextprotocol/sdk/server'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio'
// Initialize server
const server = new Server(
{
name: 'acme-document-tools',
version: '1.0.0'
},
{
capabilities: {
tools: {},
resources: {},
prompts: {}
}
}
)
// Register tools
server.setRequestHandler('tools/list', async () => ({
tools: [
{
name: 'convert_pdf_to_text',
description: 'Convert PDF to plain text with metadata',
inputSchema: {
type: 'object',
properties: {
url: {
type: 'string',
format: 'uri',
description: 'PDF file URL'
},
pages: {
type: 'array',
items: { type: 'number' },
description: 'Specific pages (optional)'
}
},
required: ['url']
}
},
{
name: 'extract_invoice_data',
description: 'Extract structured data from invoice text',
inputSchema: {
type: 'object',
properties: {
text: {
type: 'string',
description: 'Invoice text content'
}
},
required: ['text']
}
}
]
}))
// Handle tool calls
server.setRequestHandler('tools/call', async (request) => {
const { name, arguments: args } = request.params
switch (name) {
case 'convert_pdf_to_text':
return await handlePDFConversion(args)
case 'extract_invoice_data':
return await handleInvoiceExtraction(args)
default:
throw new Error(`Unknown tool: ${name}`)
}
})
// Tool implementation
async function handlePDFConversion(args: any) {
const { url, pages } = args
try {
const pdf = await fetchPDF(url)
const text = await extractText(pdf, pages)
const metadata = await extractMetadata(pdf)
return {
content: [{
type: 'text',
text: text
}],
metadata: {
pages: metadata.pageCount,
author: metadata.author,
title: metadata.title
},
isError: false
}
} catch (error) {
return {
content: [{
type: 'text',
text: `Error: ${error.message}`
}],
isError: true
}
}
}
async function handleInvoiceExtraction(args: any) {
const { text } = args
const invoice = await extractStructuredData(text, {
schema: {
invoiceNumber: 'string',
date: 'date',
vendor: 'string',
total: 'number',
items: [{
description: 'string',
quantity: 'number',
price: 'number'
}]
}
})
return {
content: [{
type: 'text',
text: JSON.stringify(invoice, null, 2)
}],
metadata: { extracted: true },
isError: false
}
}
// Start server
const transport = new StdioServerTransport()
await server.connect(transport)Agent Configuration with Multiple MCP Servers
Configure an agent with access to multiple MCP servers:
// agent-config.ts
interface AgentConfiguration {
agent: Agent
mcpServers: MCPServerConfig[]
workflows: Workflow[]
triggers: Trigger[]
}
const productionConfig: AgentConfiguration = {
agent: {
$id: 'agent://invoice-processor',
name: 'Invoice Processing Agent',
role: 'Automated invoice processing and data extraction',
systemPrompt: `You are an invoice processing specialist.
Extract data from invoice PDFs, validate against business rules,
and store in the database. Always validate required fields.`,
model: {
provider: 'anthropic',
model: 'claude-3-5-sonnet-20241022',
temperature: 0.2,
maxTokens: 8192
},
tools: [
// Document tools
'convert_pdf_to_text',
'extract_invoice_data',
'validate_invoice',
// Data tools
'query_database',
'store_invoice',
// Communication tools
'send_email',
'post_slack_message'
],
memory: {
type: 'persistent',
maxTokens: 20000,
vectorStore: 'pinecone-invoices'
},
capabilities: ['text', 'analysis', 'execution']
},
mcpServers: [
{
id: 'document-tools',
name: 'Document Processing',
transport: {
type: 'stdio',
command: 'npx',
args: ['-y', '@acme/document-mcp'],
env: {
ACME_API_KEY: process.env.ACME_API_KEY
}
},
tools: [
'convert_pdf_to_text',
'extract_invoice_data',
'validate_invoice'
]
},
{
id: 'data-tools',
name: 'Database Operations',
transport: {
type: 'stdio',
command: 'npx',
args: ['-y', '@acme/data-mcp'],
env: {
DATABASE_URL: process.env.DATABASE_URL
}
},
tools: [
'query_database',
'store_invoice',
'update_record'
]
},
{
id: 'notification-tools',
name: 'Notifications',
transport: {
type: 'http',
url: 'https://api.acme.com/mcp/notifications'
},
tools: [
'send_email',
'send_sms',
'post_slack_message'
]
}
],
workflows: [
{
id: 'wf-process-invoice',
name: 'Process Invoice',
steps: [
{
id: 'convert',
tool: 'convert_pdf_to_text',
input: { url: '{{input.invoiceUrl}}' },
output: 'text'
},
{
id: 'extract',
tool: 'extract_invoice_data',
input: { text: '{{text.content[0].text}}' },
output: 'invoice'
},
{
id: 'validate',
tool: 'validate_invoice',
input: { data: '{{invoice}}' },
output: 'validated'
},
{
id: 'store',
tool: 'store_invoice',
input: { invoice: '{{validated.data}}' },
output: 'stored'
},
{
id: 'notify',
tool: 'post_slack_message',
input: {
channel: '#invoices',
message: 'Invoice {{invoice.invoiceNumber}} processed successfully'
},
output: 'notification'
}
]
}
],
triggers: [
{
id: 'webhook-new-invoice',
type: 'webhook',
config: {
path: '/webhooks/invoice-uploaded',
method: 'POST',
auth: { type: 'secret', value: process.env.WEBHOOK_SECRET }
},
workflow: 'wf-process-invoice',
enabled: true
},
{
id: 'schedule-retry-failed',
type: 'schedule',
config: {
cron: '0 */6 * * *', // Every 6 hours
timezone: 'UTC'
},
workflow: 'wf-retry-failed-invoices',
enabled: true
}
]
}
export default productionConfigHeadless Product MDXLD Schema
Complete product definition with all interfaces:
---
$context: https://schema.org.ai
$type: Product
$id: https://acme.com/products/invoice-automation
name: Invoice Automation Platform
type: Headless
business: https://acme.com
description: Headless invoice processing with AI agents and MCP tools
isActive: true
# Categorization
industries:
- Finance & Accounting
- Automation & AI
- B2B SaaS
productCategories:
- Document Processing
- AI Agents
- Headless Services
# Interfaces (no web UI)
interfaces:
hasAPI: true
hasRPC: true
hasMCP: true # Primary interface
hasSDK: true
hasCLI: true
hasWebUI: false # Headless - no web app
hasMobileApp: false
# MCP Server Configuration
mcpServers:
- $id: mcp://document-processor
name: Document Processing Server
version: 1.0.0
tools:
- convert_pdf_to_text
- extract_invoice_data
- validate_invoice
- ocr_image
resources:
- uri: document://{id}
type: application/pdf
capabilities:
tools: { supported: true }
resources: { supported: true }
prompts: { supported: false }
- $id: mcp://data-operations
name: Data Operations Server
version: 1.0.0
tools:
- query_database
- store_invoice
- update_record
- delete_record
capabilities:
tools: { supported: true }
resources: { supported: false }
prompts: { supported: false }
# Available AI Agents
agents:
- $id: agent://invoice-processor
name: Invoice Processor
role: Extract and validate invoice data
model:
provider: anthropic
model: claude-3-5-sonnet-20241022
tools:
- convert_pdf_to_text
- extract_invoice_data
- validate_invoice
- store_invoice
capabilities:
- text
- analysis
- execution
# Tool Definitions
tools:
- $id: tool://convert_pdf_to_text
name: convert_pdf_to_text
description: Convert PDF documents to plain text with metadata extraction
category: file
inputSchema:
type: object
properties:
url: { type: string, format: uri }
pages: { type: array, items: { type: number } }
includeMetadata: { type: boolean }
required: [url]
rateLimit:
requests: 100
window: 60
requiresConfirmation: false
- $id: tool://extract_invoice_data
name: extract_invoice_data
description: Extract structured invoice data from text
category: ai
inputSchema:
type: object
properties:
text: { type: string }
required: [text]
rateLimit:
requests: 50
window: 60
requiresConfirmation: false
# Pricing (usage-based)
prices:
- $id: price_free_tier
name: Free Tier
type: usage
interval: execution
includedQuantity: 100
amount: 0
currency: USD
description: 100 executions/month free
- $id: price_standard
name: Standard
type: usage
interval: execution
amount: 0.10
currency: USD
tiers:
- upTo: 1000
amount: 0.10
description: First 1K executions
- upTo: 10000
amount: 0.05
description: 1K-10K executions
- upTo: Infinity
amount: 0.02
description: 10K+ executions
- $id: price_enterprise
name: Enterprise
type: flat
interval: month
amount: 999
currency: USD
description: Unlimited executions + dedicated support
features:
- Unlimited tool executions
- SLA guarantee
- Dedicated support
- Custom tool development
---
# {name}
{description}
<Hero
title={name}
subtitle="AI-powered invoice processing via MCP"
cta="View API Documentation"
/>
## MCP Servers
<MCPServersView servers={mcpServers} />
## AI Agents
<AgentsView agents={agents} />
## Available Tools
<MCPToolsView tools={tools} />
## API Playground
<APIPlaygroundView endpoints={tools} />
## Integration Patterns
<IntegrationGuide product={$id} />
## Pricing
<Pricing prices={prices} />Examples
Claude Desktop MCP
// Claude Desktop config
{
"mcpServers": {
"acme-toolkit": {
"command": "npx",
"args": ["-y", "@acme/mcp-server"],
"env": {
"ACME_API_KEY": "sk_..."
}
}
}
}Claude can now use Acme tools directly:
Human: Scrape https://example.com and summarize the content
Claude: Let me scrape that URL for you.
[Uses scrape_url tool]
Based on the scraped content, here's a summary...Automation Workflow
// Zapier-style automation consuming headless product
const workflow = {
trigger: { type: 'webhook', url: '/hooks/new-lead' },
steps: [
{
name: 'Enrich email',
tool: 'acme.enrich_email',
input: { email: '{{trigger.email}}' }
},
{
name: 'Qualify lead',
tool: 'acme.score_lead',
input: { data: '{{steps.enrich.output}}' }
},
{
name: 'Send to CRM',
tool: 'salesforce.create_lead',
input: { data: '{{steps.qualify.output}}' }
}
]
}Comparison: SaaS vs Headless
| Aspect | SaaS Product | Headless Product |
|---|---|---|
| UI | Web application | No UI (API only) |
| User | Humans | Agents/systems |
| Auth | Login/password | API keys |
| Docs | Screenshots, videos | API reference, schemas |
| Pricing | Per seat/month | Per execution/usage |
| Onboarding | UI walkthrough | Code examples |
| Support | Help desk | Developer support |
| Monitoring | User analytics | Execution logs |
Next Steps
- Product Schema - Product type definition
- API Products - Usage-based API products
- MCPs - Model Context Protocol implementation
- REST APIs - API interface documentation