headlo-mcp
MCP server for Headlo — gives Claude Desktop and Claude Code access to your Headlo collections, records, pages, and components.
Use it as a standalone server, or install as a library to add your own tools and intercept built-in ones.
Quickstart
Claude Desktop
Edit claude_desktop_config.json (Mac: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\):
{
"mcpServers": {
"headlo": {
"command": "npx",
"args": ["headlo-mcp"],
"env": {
"HEADLO_API_TOKEN": "hl_pat_your_token_here"
}
}
}
}
Restart Claude Desktop. You should see the Headlo tools available.
Claude Code
claude mcp add headlo -e HEADLO_API_TOKEN=hl_pat_your_token_here -- npx headlo-mcp
Remote MCP (no install)
If you don't need to extend the server, point Claude directly at the Headlo API:
claude mcp add headlo https://api.headlo.com/v1/mcp --header "Authorization: Bearer hl_pat_your_token_here"
Extending the server
Install as a library to add your own tools or intercept built-in ones:
npm install headlo-mcp @modelcontextprotocol/sdk
Add custom tools
import { createHeadloServer } from 'headlo-mcp'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { z } from 'zod'
const server = createHeadloServer()
// your own tool alongside the built-ins
server.tool('my_crm_lookup', 'Look up a contact in my CRM', { email: z.string() }, async ({ email }) => {
const contact = await myCRM.find(email)
return { content: [{ type: 'text', text: JSON.stringify(contact) }] }
})
await server.connect(new StdioServerTransport())
Intercept built-in tool calls
Pass a wrap map to run code before or after any built-in tool:
import { createHeadloServer } from 'headlo-mcp'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
const server = createHeadloServer({
wrap: {
// validate before creating a record, sync to CRM after
create_record: async (args, next) => {
await mySchema.validate(args)
const result = await next(args)
await myCRM.push(result)
return result
},
// log every CAP session to your analytics
cap_capture_expert: async (args, next) => {
const result = await next(args)
await myAnalytics.track(args.cap_id, result)
return result
},
}
})
await server.connect(new StdioServerTransport())
next(args) calls the original Headlo handler. You can modify args before passing them, or modify the result before returning it.
Environment variables
| Variable | Required | Description |
|---|---|---|
HEADLO_API_TOKEN |
Yes | Your Headlo API token (hl_pat_...) |
HEADLO_API_URL |
No | API base URL (default: https://api.headlo.com) |
HEADLO_ANON_KEY |
No | Anon key for public tool calls |
Built-in tools
Context
| Tool | Description |
|---|---|
get_context |
List all sites and workspaces — call this first |
Collections
| Tool | Description |
|---|---|
list_collections |
List all collections in a workspace |
create_collection |
Create a new collection with a schema |
update_collection |
Update a collection label or schema |
Records
| Tool | Description |
|---|---|
list_records |
List records in a collection (includes drafts) |
get_record |
Get a single record by ID |
create_record |
Create a new record |
update_record |
Update a record (partial — only provided fields change) |
delete_record |
Delete a record |
Pages
| Tool | Description |
|---|---|
list_pages |
List all pages for a site |
create_page |
Create a new page |
update_page |
Update a page title, layout, or status |
Modules
| Tool | Description |
|---|---|
list_modules_editor |
List all modules on a page |
create_module |
Add a module to a page slot |
update_module |
Update a module's record, options, or template |
delete_module |
Remove a module from a page |
Public
| Tool | Description |
|---|---|
list_page_modules |
List modules on a page (anon auth) |
get_module |
Get a single module (anon auth) |
CAP (Context Accumulation Protocol)
CAP is Headlo's expert intake system — structured question flows backed by pre-researched knowledge that produce better AI answers than generic prompts.
| Tool | Description |
|---|---|
create_expert_protocol |
Create a new CAP with intake questions and knowledge probes for a question on the Ask network |
cap_capture_expert |
Run a CAP as a live multi-turn intake session — call with empty message to start, pass answers in subsequent calls |
cap_edit_expert |
Conversationally edit an existing CAP — add/remove questions, edit options |
Running a CAP session (multi-turn):
// Turn 1 — load the CAP (empty message)
const t1 = await cap_capture_expert({ cap_id: 'abc123def456', message: '' })
// → { response: "Question 1 of 3: ...", session_state: {...}, complete: false }
// Turn 2 — answer the first question, pass session_state back
const t2 = await cap_capture_expert({ cap_id: 'abc123def456', message: 'Downtown', session_state: t1.session_state })
// → { response: "Question 2 of 3: ...", session_state: {...}, complete: false }
// Turn 3 — final answer
const t3 = await cap_capture_expert({ cap_id: 'abc123def456', message: 'Coffee shops', session_state: t2.session_state })
// → { response: "...", complete: true, answer: "..." }
Intercepting CAP calls with middleware:
const server = createHeadloServer({
wrap: {
cap_capture_expert: async (args, next) => {
const result = await next(args)
// log every completed session to your analytics
if (result.complete) await myAnalytics.track(args.cap_id, result)
return result
},
}
})
Onboarding
| Tool | Description |
|---|---|
setup_agency |
Create a new agency/workspace |
create_site |
Create a new site |
save_branding |
Save logo and brand color |
get_onboarding_progress |
Get current onboarding step |
License
Elastic License 2.0 — © Headlo
Source available. Free for internal use. Production self-hosting requires a commercial license.
Built by Headlo.