mdxui

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

AspectValue
Revenue ModelUsage-based (pay-per-execution, pay-per-call)
PricingPer API call, per agent action, per token
Primary InterfaceMCP servers, REST API, GraphQL, tRPC
Target UserAI agents, automation systems, developers
No Human UINo web application for end users
Agent-FirstDesigned for autonomous consumption
Example ProductsMCP 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 Response

Agent-First Design

Optimized for AI agent consumption:

AspectTraditional UIHeadless API
InterfaceHTML/CSS/JSJSON/RPC/MCP
InteractionClicks, formsFunction calls
FeedbackVisual UIStructured data
DocumentationScreenshots, tutorialsAPI reference, schemas
AuthUsername/passwordAPI 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 workflows

Data 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 integrations

Automation 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 orchestration

Technical 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 productionConfig

Headless 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

AspectSaaS ProductHeadless Product
UIWeb applicationNo UI (API only)
UserHumansAgents/systems
AuthLogin/passwordAPI keys
DocsScreenshots, videosAPI reference, schemas
PricingPer seat/monthPer execution/usage
OnboardingUI walkthroughCode examples
SupportHelp deskDeveloper support
MonitoringUser analyticsExecution logs

Next Steps

On this page