Field notes

An open-source MCP connector holds the account the protocol left out

MCP says nothing about whose account a tool call runs as. Kortix is open source and pins each connector call to a named account under a rule in your repo.

The Kortix Team
Kortix··6 min read

Every open source MCP connector has to answer a question the protocol never asks: whose account a tool call runs as. An MCP server publishes tools. The client-side entry that holds the account for those tools, and the rule for when they may run, is the connector. Kortix is the open-source AI Operating System, and its connectors follow a rule written in the project.

Two teams can install the same MCP server this afternoon and end up with different exposure tonight. The server never decides whose account a call uses. The client does, and Claude's setup form makes that visible: an owner chooses between signing in now, when a tool needs it, or never, and an API key typed into the request headers rides on every call. Anthropic's connector setup guide says a shared credential "gives everyone who uses it that credential's access."

What the protocol settles

MCP gives a client one call to list tools and one to run them. tools/list returns each tool's name and the JSON Schema for its input; tools/call invokes one with arguments the model wrote. The tools specification is plain about the interaction: "Tools in MCP are designed to be model-controlled." The model finds a tool and invokes it; what a person sees first is what the client chose to render.

Authorization is thinner than a sign-in screen suggests. "Authorization is OPTIONAL for MCP implementations," the specification says. It defines a token exchange at the transport: metadata discovery, client registration, an OAuth flow. The tools chapter hands duties to both sides: servers validate inputs and enforce access control, clients confirm sensitive operations with a person.

Both lists are instructions to an implementer. Neither answers the two questions a security review asks: which person's account the call acts as, and which rule decides that a write may proceed. Those belong to the client.

Three questions a connector has to answer

Which servers an agent may reach. A project can hold a dozen connectors while an agent should reach two. Kortix answers with a grant per agent: agents.<name>.connectors lists connector slugs, or all; omitted means none. A release agent can hold a repository connector while a support agent holds an inbox.

Whose account each call runs as. An MCP server sees a token, not a person. Kortix keeps an account object per connector. Each account carries an owner type: shared with the project, or private to one member. A call resolves to one account by a stated rule, and the transcript records which ran.

What holds a write. Some actions should run whenever the agent asks, some should wait for a person, a few should never run. Kortix keeps that decision in the connector's file; policy rules match an action name or its arguments.

What the manifest holds, and what lives in the platform

The connectors, the per-agent grants and the policies are in kortix.yaml, in the project repository. The account is not: it is a live connection on the connector, made by authorizing in the web app under Add account or with kortix connectors connect <slug> --owner project, pinned with kortix connectors accounts <slug> --default <label> and renamed with kortix connectors connections rename <connection-id> <label>. Its label, owner type and pin live in the platform. The starter manifest Kortix ships, at packages/starter/templates/base/kortix.yaml in Kortix on GitHub, calls the agents: map governance only, with v2 deny-by-default, because an omitted grant resolves to none.

A connector entry is short: slug, provider, URL, transport, rules.

connectors:
  - slug: linear
    provider: mcp
    url: https://mcp.linear.app/mcp/readonly
    transport: http
    policies:
      - match: "*"
        action: always_run
agents:
  triage:
    connectors: [linear]

provider: mcp tells Kortix to call a server it does not host over HTTP; sse is the other value, and the connectors documentation lists every field. The URL is Linear's read-only endpoint, which Linear's docs say exposes read tools and nothing else; Kortix names a server added from its URL after the domain, which is where linear comes from. The rule matches every action that endpoint offers and lets each run; a policy is only as narrow as the surface behind it. A second entry pointing at the read-write URL would carry sensitive: true, so unnamed actions would wait for a person.

The last two lines are the grant people forget. Erase connectors: [linear] and the connector stays installed and unreachable. Actions are addressed as <slug>.<action>. Kortix connects 3,000+ apps in a click, plus MCP, OpenAPI, Postman, GraphQL and raw HTTP. The manifest never holds a credential, which makes keeping secrets out of the sandbox the other half of this story.

Whose account the call runs as

An account is the identity a call carries, and one field decides how far it reaches: the owner type. A project account (owner_type: project) is open to everyone in the project and every agent whose grant lists the connector, triggers included. It can be narrowed to people, groups or agents. A member account (owner_type: member) is one person's, and it works only inside that person's private sessions. A cron trigger or a service-account key has nobody behind it, so Kortix will not route that call through a member account. Work that has to run while nobody is watching needs a project account.

Naming an account is optional, and the default is strict. Leave the field out, or write me or project, and Kortix resolves the call only when the answer is unambiguous: one account is reachable, or several are and exactly one is the default. Two plausible answers get account_required and the accounts it could see. Nothing is substituted, so a missing login fails the call.

The result names the account that ran it: connection id, label, owner type. Read the owner type first. A label is whatever someone typed at setup, so a project account can carry a person's name and serve every scheduled run. owner_type: member on scheduled work means a wrong policy; an unattended run never uses a private account.

Where the rule lives

Four places can answer for a call, and Kortix stops at the first. The project's policies: list goes first and speaks in full names, so a rule on one entry cannot loosen the project's decision. The connector's policies: comes next, relative to it. sensitive: true is third and holds every action no earlier rule named, reads included. policy.default_mode answers what is left.

A rule ends in one of three verbs. always_run sends the call, require_approval parks it, block refuses it, and the Tools tab shows them as Allow, Ask and Block. A parked call pauses the agent's turn until a person answers. One approval answers a single request as it was made; an argument that changed afterwards needs a fresh decision.

A project that leaves policy.default_mode at allow_all runs everything that reaches it, so it is the first line to change on a project that can reach money, mail or production. risk runs reads and parks writes and destructive actions for a person; narrower rules trim from there. A rule can test arguments too, so a message to one domain runs while others wait.

Every action is recorded. Reading, exporting and streaming the audit log depend on the plan. A project account's label tells you less than its owner type does.

The other direction of the same protocol

A provider: mcp connector is Kortix calling someone else's server. Kortix is also an MCP server, at https://api.kortix.com/v1/mcp. A client like Claude, Cursor or Codex can call Kortix and reach every account and project you can open, acting as you with your permissions. A connector action that a policy holds comes back pending, with a link for a person to approve. The MCP server documentation covers the client setup.

Both directions end at the same question: if you cannot say which account a tool call will use before it runs, you do not know what your agent can do.

Put the rule in a file you own, and name the account the call runs as.

Free to start, free to self-host.

Get started

Run your whole company from one repo you own.

Start with one job and grow from there.

Get started