CORTEX MCP Server
Connect Claude Code, Cursor, or any MCP-compatible AI agent directly to your CORTEX workspace. Manage kanban tasks, chatbot configurations, business profiles, promotion ladders, and marketing campaigns — all through 36 tools over a single POST /api/mcp endpoint.
Prerequisites
- A CORTEX account — sign up at cortex-ai.net.
- An Airis bot provisioned for your workspace — ask your CORTEX super-admin to create one at
/super-admin/airis-bots. - Your Cortex API key — the
cortexApiKeyshown on the Airis bot detail page. It is a 64-character hex string.
Treat the API key like a password. It grants full read/write access to your organisation's CORTEX workspace. Rotate it immediately if it is ever exposed.
Quick start
Claude Code
Register the CORTEX MCP server in Claude Code once:
claude mcp add --transport http cortex \
https://api.cortex-ai.net/api/mcp \
--header "X-Airis-Key: YOUR_64_CHAR_KEY"Replace YOUR_64_CHAR_KEY with the key from the Airis bot detail page. Claude Code stores the entry in ~/.claude.json — tools are available immediately in new sessions.
Cursor / other MCP clients
Any client that supports Streamable HTTP transport works. Add the server entry to your MCP config:
{
"mcpServers": {
"cortex": {
"type": "http",
"url": "https://api.cortex-ai.net/api/mcp",
"headers": {
"X-Airis-Key": "YOUR_64_CHAR_KEY"
}
}
}
}UAT environment
# Staging / UAT
claude mcp add --transport http cortex-uat \
https://uat-api.cortex-ai.net/api/mcp \
--header "X-Airis-Key: YOUR_UAT_KEY"Verify the connection
Ask the AI to list your kanban boards to confirm tools are loaded:
> List my kanban boards using the cortex MCP server.
→ kanban.list_boards returns [{id, name, isDefault, visibility, url}]Authentication
Every request must include the X-Airis-Key header. The server validates it against the database; on success, the organizationId is resolved from the bot row and injected into every tool handler — you never supply it in tool input.
POST /api/mcp HTTP/1.1
Host: api.cortex-ai.net
Content-Type: application/json
X-Airis-Key: <your-64-char-hex-key>
{"jsonrpc":"2.0","method":"tools/call","id":1,"params":{...}}401200500Tools overview
The server exposes 36 tools across 7 namespaces. All tools support both read and write operations. Every tool is stateless — the server constructs a fresh context per HTTP request.
kanban.* — Tasks & boards
Create, read, update, and move tasks across boards. Every task response includes a url field pointing to the canonical CORTEX UI page — send it verbatim, never fabricate a link.
| Tool | Description | Key inputs |
|---|---|---|
kanban.list_boards | List all boards in the org — id, name, isDefault, visibility, and URL. | (none) |
kanban.list_columns | List columns for a board (or org default). Returns column ids for create/move. | boardId? |
kanban.list_tasks | List tasks with optional filters. Each task includes a url field. | boardId? columnId? assignedUserId? priority? source? search? limit? |
kanban.get_task | Get a single task. Pass includeTimeline: true for comments + activity log. | taskId, includeTimeline? |
kanban.create_task | Create a task. Supports attachmentUrls for linking external files (SSRF-allowlisted). | title, description? boardId? columnId? priority? assignedUserId? assigneeName? dueDate? attachmentUrls? |
kanban.update_task | Update fields on an existing task. Only supplied fields change. | taskId, title? description? priority? assignedUserId? assigneeName? dueDate? attachmentUrls? |
kanban.move_task | Move a task to a different column / position. Triggers task.moved event. | taskId, toColumnId, newPosition? |
kanban.attach_image | Attach an external URL (e.g. LINE CDN image) to a task. Returns the persisted attachment record. | taskId, sourceUrl |
chatbot.* — Chatbot configs
Read and update chatbot configurations, switch business context sources, and monitor active conversations.
| Tool | Description | Key inputs |
|---|---|---|
chatbot.list_configs | List all chatbot configs (slim — id, name, type, active, channel count). | (none) |
chatbot.get_config | Get full config including system prompt, business context, AI settings, and knowledge instructions. | id |
chatbot.update_config | Update editable chatbot fields: role, personality, businessInfo, aiModel, temperature, etc. | id + any updatable fields |
chatbot.update_business_context | Switch the bot's business context between INHERIT (org profile) and CUSTOM (inline JSON). | id, source, customContext? |
chatbot.update_knowledge_instructions | Set natural-language instructions that tell the bot how to use its knowledge files. | id, knowledgeInstructions |
chatbot.list_conversations | Monitor active conversation threads — last activity, latest bot reply, handoff flag. No PII. | botId, since?, status? |
knowledge.* — RAG knowledge files
Manage the vector knowledge base (PDF, DOCX, XLSX, TXT) that chatbots use for retrieval-augmented generation.
| Tool | Description | Key inputs |
|---|---|---|
knowledge.list_files | List all knowledge files for a chatbot config — category, size, MIME type. | chatbotConfigId |
knowledge.get_stats | Return file count, chunk count, and embedding readiness for a chatbot config. | chatbotConfigId |
knowledge.delete_file | Delete a knowledge file — removes the binary, file row, and all RAG chunks. | chatbotConfigId, fileId |
knowledge.reingest_file | Re-run ingestion (extract → chunk → embed) for a file. Useful after updating knowledge instructions. | chatbotConfigId, fileId |
business_profile.* — Business identity
Read and upsert the org-level business profile. Chatbots with businessContextSource = 'inherit' pull from this profile automatically.
| Tool | Description | Key inputs |
|---|---|---|
business_profile.get | Get the business profile for the current org (null if not configured). | (none) |
business_profile.update | Upsert the business profile. socialLinks and targetAudience are deep-merged with existing values. | businessName? description? usp? brandVoice? socialLinks? ... |
promotion.* — Promotion ladders
Promotion ladders define tiered offer escalation (percent-off, free gift, bundle, etc.) that PromotionStrategyAgent uses when negotiating with customers.
| Tool | Description | Key inputs |
|---|---|---|
promotion.list_ladders | List all promotion ladders with their tiers. | (none) |
promotion.get_ladder | Get a single promotion ladder with all tiers. | id |
promotion.create_ladder | Create a promotion ladder with one or more tiers in a single call. | name, tiers[], chatbotConfigId?, productId?, active? |
promotion.update_ladder | Update a ladder. Supplying tiers replaces all existing tiers atomically. | id, name?, active?, tiers? |
promotion.delete_ladder | Delete a ladder and all its tiers. | id |
playbook.* — Sales playbook
Sales playbook snippets are reusable evidence and fact statements (warranty, testimonials, pricing justification, social proof) referenced by ObjectionHandlingAgent when composing rebuttals.
| Tool | Description | Key inputs |
|---|---|---|
playbook.list | List snippets filtered by category, product, or active state. | category?, productId?, activeOnly? |
playbook.get | Get a single sales playbook snippet. | id |
playbook.create | Create a snippet. weight (0–100) controls how likely it is to be selected. | category, title, content, productId?, weight?, active? |
playbook.update | Update fields on a snippet. | id, category?, title?, content?, weight?, active? |
playbook.delete | Delete a sales playbook snippet. | id |
campaign.* — Customer campaigns
Create and manage recurring or one-shot customer broadcasts. The segment audience is described in natural language (e.g. "VIP customers who bought in the last 30 days") and resolved by SegmentResolutionAgent to a type-safe filter — never raw SQL.
| Tool | Description | Key inputs |
|---|---|---|
campaign.list | List all campaigns in the org. | (none) |
campaign.get | Get a single campaign by id. | id |
campaign.create | Create a campaign. segmentRuleText is resolved immediately via NL→filter. | name, segmentRuleText, contentMode?, scheduleMode?, scheduledAt?, cronExpr? |
campaign.update | Update a campaign. Re-resolves segment if segmentRuleText changes. | id + any updatable fields |
campaign.delete | Delete a campaign. | id |
campaign.reresolve_segment | Re-run SegmentResolutionAgent on the campaign's existing natural-language rule. | id |
Security
organizationId is resolved from the bearer key and injected into every tool handler. Tool inputs never accept an organizationId parameter — cross-org access via crafted payloads is structurally impossible.
Keys are generated with crypto.randomBytes(32).toString('hex') — 256 bits of entropy. Validated at the guard layer by exact length (64 chars) plus database uniqueness constraint.
The attachmentUrls parameter in kanban.create_task, kanban.update_task, and kanban.attach_image validates every URL hostname against a static allowlist before any outbound request. Disallowed hosts return HTTP 400.
If a key is compromised, rotate it immediately at /super-admin/airis-bots/:id. The old key is invalidated as soon as the new one is saved.
Troubleshooting
"Invalid or missing X-Airis-Key header"
The key must be exactly 64 hex characters. Check for leading/trailing whitespace. Ensure the header name is X-Airis-Key.
"Invalid X-Airis-Key" (correct length but still 401)
The key was not found in the database. Confirm you are using the cortexApiKey from the correct environment (prod vs UAT — they have separate databases and separate keys).
Tool calls succeed but return empty data
The key is valid but the Airis bot belongs to an organisation with no data yet. Check the organizationId on the bot detail page.
"Attachment URL host not allowlisted"
The URL passed to attachmentUrls or kanban.attach_image is not on the SSRF allowlist. Use a URL hosted on an allowlisted domain (*.webapp.tools, *.line-scdn.net, *.fbcdn.net) or ask an admin to extend the list.
Claude Code shows no CORTEX tools
Run: claude mcp list — confirm the server is registered. If missing, re-run the claude mcp add command. If present but tools do not appear, restart Claude Code.