Examples
Copy-paste connection snippets for the most common MCP clients, plus end-to-end agent examples in TypeScript and Python. All examples target the local dev URL; swap the host for the production URL when it goes live July 20, 2026.
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\\Claude\\claude_desktop_config.json (Windows):
{
"mcpServers": {
"cortex": {
"url": "http://localhost:3002/mcp",
"headers": {
"Authorization": "Bearer dev-mcp-token-CHANGE-ME"
}
}
}
}Restart Claude Desktop. Cortex tools appear in the slash-command picker.
Cursor
In Cursor → Settings → MCP → Add new MCP server:
{
"cortex": {
"url": "http://localhost:3002/mcp",
"headers": {
"Authorization": "Bearer dev-mcp-token-CHANGE-ME"
}
}
}Continue (VS Code / JetBrains)
mcpServers:
- name: cortex
transport:
type: streamable-http
url: http://localhost:3002/mcp
headers:
Authorization: Bearer dev-mcp-token-CHANGE-MEMCP Inspector
The fastest way to debug a misbehaving client is to bypass the client entirely:
npx @modelcontextprotocol/inspector \
--transport streamable-http \
--server-url http://localhost:3002/mcp \
--header "Authorization: Bearer dev-mcp-token-CHANGE-ME"The inspector renders every tool with its schema, lets you call them one at a time, and shows the raw JSON-RPC payloads on both sides.
TypeScript — full agent
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const URL = 'http://localhost:3002/mcp';
const TOKEN = process.env.CORTEX_TOKEN ?? '';
async function main(): Promise<void> {
const transport = new StreamableHTTPClientTransport(new URL(URL), {
requestInit: {
headers: { Authorization: `Bearer ${TOKEN}` },
},
});
const client = new Client(
{ name: 'cortex-example-agent', version: '0.1.0' },
{ capabilities: {} },
);
await client.connect(transport);
// 1. Recall recent memory about Sarah
const recall = await client.callTool({
name: 'memory.recall',
arguments: { query: "what's sarah's current role?", topK: 3 },
});
console.log('recall:', recall);
// 2. Check current trust level for outreach to Sarah
const trust = await client.callTool({
name: 'trust.check',
arguments: {
action_class: 'communicate',
counterparty_id: 'entity_01HXSARAH',
},
});
console.log('trust:', trust);
// 3. Draft an outreach message (returns pending_approval in Phase 0)
const draft = await client.callTool({
name: 'action.communicate',
arguments: {
to: 'entity_01HXSARAH',
message: 'Quick check — does Tuesday 2pm still work?',
tone: 'warm',
},
});
console.log('draft:', draft);
await client.close();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});Python — full agent
import asyncio
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
URL = "http://localhost:3002/mcp"
TOKEN = os.environ["CORTEX_TOKEN"]
HEADERS = {"Authorization": f"Bearer {TOKEN}"}
async def main() -> None:
async with streamablehttp_client(URL, headers=HEADERS) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
# 1. Recall recent memory about Sarah
recall = await session.call_tool(
"memory.recall",
{"query": "what's sarah's current role?", "topK": 3},
)
print("recall:", recall)
# 2. Check trust for outreach
trust = await session.call_tool(
"trust.check",
{
"action_class": "communicate",
"counterparty_id": "entity_01HXSARAH",
},
)
print("trust:", trust)
# 3. Draft an outreach message
draft = await session.call_tool(
"action.communicate",
{
"to": "entity_01HXSARAH",
"message": "Quick check — does Tuesday 2pm still work?",
"tone": "warm",
},
)
print("draft:", draft)
asyncio.run(main())cURL — the JSON-RPC underneath
Helpful when you want to confirm the wire shape independent of any SDK. This invokes memory.recall in stateless mode:
# Step 1: initialize (no mcp-session-id header — server assigns one)
curl -s http://localhost:3002/mcp \
-H "Authorization: Bearer dev-mcp-token-CHANGE-ME" \
-H "Content-Type: application/json" \
-H "MCP-Protocol-Version: 2025-03-26" \
-d '{
"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{
"protocolVersion":"2025-03-26",
"capabilities":{},
"clientInfo":{"name":"curl","version":"0"}
}
}' -i
# Step 2: call memory.recall using the session id from step 1's response header
curl -s http://localhost:3002/mcp \
-H "Authorization: Bearer dev-mcp-token-CHANGE-ME" \
-H "Content-Type: application/json" \
-H "mcp-session-id: <PASTE_SESSION_ID_HERE>" \
-d '{
"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{
"name":"memory.recall",
"arguments":{"query":"sarah","topK":3}
}
}'TypeScript — handler that verifies and calls back
The minimum-viable handler: an Express endpoint that verifies the Cortex signature, executes the action through your own channel, and calls back trigger.complete (or trigger.reverse later if the user undoes). Drop into any Node 22+ project; swap the channel implementation for Slack, email, SMS, whatever your app owns.
import express from 'express';
import { createHmac, timingSafeEqual } from 'node:crypto';
const app = express();
app.use(express.json({
verify: (req, _res, buf) => { (req as any).rawBody = buf.toString('utf8'); },
}));
const WEBHOOK_SECRET = process.env.CORTEX_WEBHOOK_SECRET!;
const PRINCIPAL_TOKEN = process.env.CORTEX_PRINCIPAL_TOKEN!;
const CORTEX_HOST = 'https://mcp.cortex.jakeselby.com';
const FIVE_MIN = 5 * 60 * 1000;
function verifyCortexDispatch(req: express.Request): { ok: true } | { ok: false; reason: string } {
const sig = String(req.headers['x-cortex-signature'] ?? '').replace(/^sha256=/, '');
const ts = String(req.headers['x-cortex-timestamp'] ?? '');
if (!sig || !ts) return { ok: false, reason: 'missing_headers' };
const tsMs = Date.parse(ts);
if (Number.isNaN(tsMs)) return { ok: false, reason: 'bad_timestamp' };
if (Math.abs(Date.now() - tsMs) > FIVE_MIN) return { ok: false, reason: 'stale' };
const expected = createHmac('sha256', WEBHOOK_SECRET)
.update(ts + '.' + (req as any).rawBody, 'utf8')
.digest('hex');
const a = Buffer.from(expected, 'hex');
const b = Buffer.from(sig, 'hex');
if (a.length !== b.length || !timingSafeEqual(a, b)) {
return { ok: false, reason: 'signature_invalid' };
}
return { ok: true };
}
app.post('/cortex', async (req, res) => {
const verified = verifyCortexDispatch(req);
if (!verified.ok) return res.status(401).json({ error: verified.reason });
const trigger = req.body as {
trigger_id: string;
action_class: string;
mode: 'act' | 'notify_after' | 'ask' | 'test';
payload: { body?: string; preview?: { body: string } };
counterparty?: { id: string; display_name: string };
};
// Ack within 30s — return 200 quickly, do the work async.
res.status(200).end();
// ... execute through your own channel (Slack / email / in-app / SMS / etc) ...
const externalRef = await sendThroughYourChannel(trigger);
// Close the loop with trigger.complete
await fetch(`${CORTEX_HOST}/v1/triggers/${trigger.trigger_id}/complete`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${PRINCIPAL_TOKEN}`,
'Content-Type': 'application/json',
'Idempotency-Key': `cb_${trigger.trigger_id}`,
},
body: JSON.stringify({
outcome: trigger.mode === 'ask' ? 'approved' : 'executed',
external_ref: externalRef,
executed_at: new Date().toISOString(),
}),
});
});
async function sendThroughYourChannel(trigger: {
counterparty?: { display_name: string };
payload: { body?: string };
}): Promise<string> {
// Replace with your real channel send. Returns an external reference your app can resolve.
console.log('sending to', trigger.counterparty?.display_name, ':', trigger.payload.body);
return 'msg_' + Math.random().toString(36).slice(2);
}
app.listen(3000, () => console.log('Cortex handler listening on :3000'));cURL — mock an inbound dispatch against your handler
Useful during local development before Cortex can dispatch for real. Below: sign a fake envelope with a chosen secret and POST it to your handler. The headers and canonical string match what Cortex sends in production.
# Configure
HANDLER_URL="http://localhost:3000/cortex"
WEBHOOK_SECRET="whsec_test_replace_me"
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
# Build the trigger body (one JSON line, no surrounding whitespace in signature)
BODY='{
"trigger_id":"trg_TESTHANDLER",
"decision_id":"dec_TEST",
"action_class":"communicate",
"mode":"ask",
"counterparty":{"id":"entity_test","display_name":"Test Recipient"},
"payload":{"body":"Hello from a mock dispatch","preview":{"mime":"text/plain","body":"..."}},
"reasoning":"Mock for handler integration",
"reversal":{"path":"undo in app within 60min","window_sec":3600,"callback_url":"https://mcp.cortex.jakeselby.com/v1/triggers/trg_TESTHANDLER/reverse"},
"expires_at":"2026-12-31T00:00:00Z",
"schema_version":"2026-07-20",
"links":{"decision_url":"https://app.cortex.jakeselby.com/decisions/dec_TEST","ledger_url":"https://app.cortex.jakeselby.com/ledger/led_TEST"}
}'
# Compute HMAC-SHA256 over (timestamp + "." + body)
SIG=$(printf "%s.%s" "$TS" "$BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" -binary | xxd -p -c 999)
curl -s "$HANDLER_URL" \
-H "X-Cortex-Signature: sha256=$SIG" \
-H "X-Cortex-Trigger-Id: trg_TESTHANDLER" \
-H "X-Cortex-Idempotency-Key: trg_TESTHANDLER" \
-H "X-Cortex-Schema-Version: 2026-07-20" \
-H "X-Cortex-Timestamp: $TS" \
-H "Content-Type: application/json" \
-d "$BODY" -i