CORTEXDocsMCP Server
MCP Server

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.

36 toolsAPI key authOrg-scopedStreamable HTTP transport

Prerequisites

  1. A CORTEX account — sign up at cortex-ai.net.
  2. An Airis bot provisioned for your workspace — ask your CORTEX super-admin to create one at /super-admin/airis-bots.
  3. Your Cortex API key — the cortexApiKey shown 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:

bash
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:

json
{
  "mcpServers": {
    "cortex": {
      "type": "http",
      "url": "https://api.cortex-ai.net/api/mcp",
      "headers": {
        "X-Airis-Key": "YOUR_64_CHAR_KEY"
      }
    }
  }
}

UAT environment

bash
# 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:

text
> 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.

http
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":{...}}
401
Missing or invalid key
Check the X-Airis-Key header value and length (must be exactly 64 chars)
200
Success
JSON-RPC result in body
500
Internal server error
MCP handler threw — check tool inputs or contact support

Tools 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.

ToolDescriptionKey inputs
kanban.list_boardsList all boards in the org — id, name, isDefault, visibility, and URL.(none)
kanban.list_columnsList columns for a board (or org default). Returns column ids for create/move.boardId?
kanban.list_tasksList tasks with optional filters. Each task includes a url field.boardId? columnId? assignedUserId? priority? source? search? limit?
kanban.get_taskGet a single task. Pass includeTimeline: true for comments + activity log.taskId, includeTimeline?
kanban.create_taskCreate a task. Supports attachmentUrls for linking external files (SSRF-allowlisted).title, description? boardId? columnId? priority? assignedUserId? assigneeName? dueDate? attachmentUrls?
kanban.update_taskUpdate fields on an existing task. Only supplied fields change.taskId, title? description? priority? assignedUserId? assigneeName? dueDate? attachmentUrls?
kanban.move_taskMove a task to a different column / position. Triggers task.moved event.taskId, toColumnId, newPosition?
kanban.attach_imageAttach 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.

ToolDescriptionKey inputs
chatbot.list_configsList all chatbot configs (slim — id, name, type, active, channel count).(none)
chatbot.get_configGet full config including system prompt, business context, AI settings, and knowledge instructions.id
chatbot.update_configUpdate editable chatbot fields: role, personality, businessInfo, aiModel, temperature, etc.id + any updatable fields
chatbot.update_business_contextSwitch the bot's business context between INHERIT (org profile) and CUSTOM (inline JSON).id, source, customContext?
chatbot.update_knowledge_instructionsSet natural-language instructions that tell the bot how to use its knowledge files.id, knowledgeInstructions
chatbot.list_conversationsMonitor 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.

ToolDescriptionKey inputs
knowledge.list_filesList all knowledge files for a chatbot config — category, size, MIME type.chatbotConfigId
knowledge.get_statsReturn file count, chunk count, and embedding readiness for a chatbot config.chatbotConfigId
knowledge.delete_fileDelete a knowledge file — removes the binary, file row, and all RAG chunks.chatbotConfigId, fileId
knowledge.reingest_fileRe-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.

ToolDescriptionKey inputs
business_profile.getGet the business profile for the current org (null if not configured).(none)
business_profile.updateUpsert 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.

ToolDescriptionKey inputs
promotion.list_laddersList all promotion ladders with their tiers.(none)
promotion.get_ladderGet a single promotion ladder with all tiers.id
promotion.create_ladderCreate a promotion ladder with one or more tiers in a single call.name, tiers[], chatbotConfigId?, productId?, active?
promotion.update_ladderUpdate a ladder. Supplying tiers replaces all existing tiers atomically.id, name?, active?, tiers?
promotion.delete_ladderDelete 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.

ToolDescriptionKey inputs
playbook.listList snippets filtered by category, product, or active state.category?, productId?, activeOnly?
playbook.getGet a single sales playbook snippet.id
playbook.createCreate a snippet. weight (0–100) controls how likely it is to be selected.category, title, content, productId?, weight?, active?
playbook.updateUpdate fields on a snippet.id, category?, title?, content?, weight?, active?
playbook.deleteDelete 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.

ToolDescriptionKey inputs
campaign.listList all campaigns in the org.(none)
campaign.getGet a single campaign by id.id
campaign.createCreate a campaign. segmentRuleText is resolved immediately via NL→filter.name, segmentRuleText, contentMode?, scheduleMode?, scheduledAt?, cronExpr?
campaign.updateUpdate a campaign. Re-resolves segment if segmentRuleText changes.id + any updatable fields
campaign.deleteDelete a campaign.id
campaign.reresolve_segmentRe-run SegmentResolutionAgent on the campaign's existing natural-language rule.id

Security

Org isolation (structural)

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.

Cryptographic key strength

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.

SSRF protection on attachment URLs

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.

Key rotation

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.