ElementsAI

MCP

Two directions — expose Flows as gated mcp.tool endpoints on :6535, and consume external servers with ai.mcpServer allowlists.

Model Context Protocol (MCP) connects OKE to Cursor, Claude Desktop, and other agents in two directions: your app exposes selected Flows as tools, and your Flows call tools on external MCP servers.

For developers wiring Cursor to a backend or letting an agent open a GitHub issue — opt-in gates inbound; allowlists outbound.

The one rule

Inbound: on(mcp.tool("name").gate(...), flow) — ungated tools are not exposed. Outbound: ai.mcpServer with a required tools allowlist — the runtime never trusts raw tools/list.

Smallest Example — expose a Flow

Bind a gated MCP tool

src/flows/bookings/create.ts
import { on, flow, mcp } from "okengine";
import { z } from "zod";
import { member } from "@/core/gate";

export const create = on(
  mcp
    .tool("bookings.create", {
      in: z.object({
        guest: z.string().min(1),
        night: z.string(),
      }),
      out: z.object({ id: z.string(), guest: z.string(), night: z.string() }),
    })
    .gate(member),
  flow({
    do: async (input, fx) => {
      return { id: fx.id(), ...input };
    },
  }),
);

Deny-by-default: on(mcp.tool("…"), flow) without .gate(...) fails gate posture at boot.

Connect a client

App MCP listens on port 6535, path /mcp (not the backend :6530 HTTP port). Bearer auth is required.

{
  "mcpServers": {
    "notes": {
      "url": "http://127.0.0.1:6535/mcp",
      "headers": {
        "Authorization": "Bearer <token>"
      }
    }
  }
}

GET /health on the same port probes liveness. Override with ports.mcp in config when needed.

Call the tool

The client lists bookings.create (and other gated tools). Invocations run the Flow under the same gate chain as HTTP.

Smallest Example — consume a server

Declare an outbound server

src/core/mcp.ts
import { ai, vault } from "okengine";

const githubToken = vault.secret("GITHUB_MCP_TOKEN");

export const github = ai.mcpServer("github", {
  url: "https://mcp.example/github",
  auth: { bearer: githubToken },
  tools: ["create_issue", "list_repos"],
});

export const createIssue = github.tool("create_issue"); // mcp:github/create_issue

Exactly one of url (Streamable HTTP) or command (+ optional args for stdio). Bearer must be a vault.secret handle or contract name — never a token literal in source.

Use in ask / agent tools

await fx.ask(triage, input, {
  tools: [github.tool("create_issue")],
  maxSteps: 2,
});

Capability ref is mcp:github/create_issue. Model-facing names use server__tool (github__create_issue).

Progressive Patterns

Chain policies like HTTP — first denial wins:

on(
  mcp.tool("admin.wipe").gate(member, gate.scope("admin")),
  flow({ do: async (_input, fx) => fx.json.empty() }),
);

Inbound reference

PieceDetail
Triggermcp.tool(name, { in, out, errors? }) from okengine
Gates.gate(...) required for exposure
Port6535 (ports.mcp)
PathPOST /mcp · GET /health
AuthBearer required (Bearer token required)

Empty name throws TypeError: mcp.tool(name): name is required.

Outbound reference — ai.mcpServer

OptionTypeRequiredMeaning
urlstringXOR commandStreamable HTTP endpoint
commandstringXOR urlstdio executable (no shell string)
argsstring[]noArguments for command
auth.bearersecret / namenoVault contract for Bearer
toolsstring[]yesAllowlist — never raw tools/list
MethodReturnsMeaning
server.tool(name){ name: "mcp:server/tool" }Capability ref for ask / agent / fx.call

Declare errors

MessageFix
ai.mcpServer: name is requiredPass a non-empty server id
name "…" must not contain "/" or "__"Use a simple id (github, not org/repo)
tools allowlist is requiredPass tools: ["…"]
declare exactly one of url or commandPick HTTP or stdio
tool "…" is not in the allowlistAdd the name to tools before .tool(...)

Ports

PortSurface
6530Backend HTTP
6535App MCP (Flows as tools)
6536Docs MCP (read-only)

Mnemonic: O·K·E = 6·5·3.

Troubleshooting

Learn more

  • Agents — MCP refs in tool bags
  • Gate — policies on mcp.tool
  • Vault — bearer secret contracts
  • AI — element overview
  • Security — ports 6530 · 6533 · 6535 · 6536

Next

On this page