MCP-executor recipe (V1.1 preview)
ADR-0019's Tier 2 architecture: when you already host an MCP server, Cortex acts as an MCP client and invokes one of your server's tools instead of POSTing a webhook. Same envelope; different transport.
Why MCP-executor
- You already expose internal capabilities as an MCP server — Cortex just adds itself as another client.
- No additional HTTP endpoint to operate, harden, or expose to the public internet.
- Symmetric protocol: Cortex pulls from your MCP server when its substrate needs state, and pushes via the same protocol when it decides.
Architecture
Instead of POSTing a JSON envelope to an HTTPS URL, Cortex acts as an MCP client and invokes a tool you advertise on your own MCP server — conventionally cortex.dispatch. The tool's arguments are the same TriggerEnvelope shape documented at Envelope & headers. The tool's return value is the equivalent of trigger.complete:
typescriptserver.ts — your MCP server exposes cortex.dispatch
import { McpServer } from "@modelcontextprotocol/sdk/server/index.js";
import { z } from "zod";
const server = new McpServer({ name: "your-mcp-server", version: "1.0.0" });
// The shape Cortex will dispatch into your server.
const triggerEnvelopeSchema = z.object({
trigger_id: z.string(),
decision_id: z.string(),
action_class: z.string(),
mode: z.enum(["act", "notify_after", "ask", "test"]),
counterparty: z.object({ id: z.string(), display_name: z.string() }).optional(),
payload: z.record(z.unknown()),
reasoning: z.string(),
reversal: z.object({ path: z.string(), window_sec: z.number().optional(), callback_url: z.string() }),
expires_at: z.string(),
schema_version: z.string(),
});
server.tool(
"cortex.dispatch",
"Receive a dispatched trigger from the Cortex cognitive substrate.",
triggerEnvelopeSchema,
async (input) => {
// 1. Execute through your channel
const externalRef = await runYourChannel(input);
// 2. Return the equivalent of trigger.complete inline.
// Cortex records the outcome from the tool result; no separate HTTP callback needed.
return {
content: [
{
type: "text",
text: JSON.stringify({
outcome: input.mode === "ask" ? "approved" : "executed",
external_ref: externalRef,
executed_at: new Date().toISOString(),
}),
},
],
};
},
);Registering with Cortex
Once V1.1 lights up, register your MCP server URL instead of an HTTPS handler URL:
json
{
"name": "handler.register",
"arguments": {
"url": "https://your-mcp-server.example.com/mcp",
"action_classes": ["communicate", "schedule"],
"tier": "mcp-executor"
}
}Trade-offs vs Tier 1 webhook
| Dimension | Tier 1 (webhook) | Tier 2 (MCP-executor) |
|---|---|---|
| Transport | HTTPS POST + HMAC | MCP tools/call |
| Auth model | Per-handler webhook_secret (HMAC) | Bearer token / OAuth (whatever your MCP server uses) |
| Callback shape | Separate POST /v1/triggers/{id}/complete after async execution | Inline — the tool's return value is the callback |
| Retry on failure | Cortex retries with exponential backoff | Cortex retries the MCP call |
| Idempotency | X-Cortex-Idempotency-Key header | trigger_id in tool arguments |
| Available | July 20, 2026 | V1.1 |