Skip to main content
Endpoints with sessions are in beta.
defineEndpoint declares an MCP endpoint: a list of tools and how its sessions start. You declare it once; Bijection serves it at /mcp/<name> and handles its grants, limits and tokens. The AI agent itself (the model, the conversation, voice) runs in your own host. Three things take part:
  • An endpoint is code. It names its tools and how a session starts: the resource type one session acts for and the role a session holds.
  • A credential is a key that can only start sessions. It reads no data.
  • A session is one conversation. It holds the endpoint’s role on one object, such as one customer, until it expires.
Because a session holds ordinary grants of ordinary roles of your access model, your access rules decide everything it reads and changes. Its token works on its endpoint only: Bijection refuses it your app’s regular API. Use defineMcpServer instead when your app writes its own access rules: sessions need an access model.

Declaring an endpoint

Give a session a role, and give its credentials a role whose only business permission is the power to grant that role:
bijection/access.ts
see covers a customer’s identifier alone, so a credential can tell that a customer exists and reads none of its fields. The session’s role has no read.risk, so the fields behind it never reach the agent. maxDuration is the longest a session can last. The operation resource is how your access model decides who may use an operation, for your staff and for sessions alike. A session holds operation:invoker on each operation its tools request and operation:reader on each it may only follow, until it ends. A credential holds operation:agentIssuer on those operations, which is what lets it give its sessions those roles. An endpoint with no operation tools needs none of the three. Then declare the endpoint and export the module:
bijection/mcp.ts
Each tool takes the definition’s module:export path, the definition itself and the description the model reads. A tool must be a public query or operation with explicit validators: publishing it adds a description, never a way in. Keep the default export in bijection/mcp.ts. To export it from another file, pass that file’s path as module to endpointsModule. Add the tables to your schema, and mount the routes:
bijection/schema.ts
bijection/http.ts
Adding an endpoint changes nobody else’s permissions. Your access model keeps deciding who may use each operation; a session is one more principal holding grants, for exactly what its tools do: an operation tool reads and invokes its operation, a status tool only reads its requests, and no session previews.

Binding a tool to the session’s object

A tool’s function takes the object it is about as an ordinary argument, so your app and your staff call it too. For a session, bind names that argument: the model never sees it and cannot supply it, and the session fills it in. An operation that declares the object as its target needs no bind: its tool binds the target on its own.
bijection/mcp.ts
bijection/desk.ts
The model is offered order_details with order_number alone. A bound argument is a required top-level ID or string. A tool with no arguments can read the session instead, with endpointSession(ctx) from bijection/mcp. Three rules shape a tool’s function:
  • Select only what the role may read. Reading a whole document asks for every field. A tool that reads a field the session’s role lacks fails as a whole request, not as a tool error.
  • Keep an operation’s object type to what the session reads. An operation reads its target through the view or table it is declared on before it runs. Declare a view that selects only fields the session’s role may read; a view over the whole table is refused for a role that lacks one field.
  • Write under what you read. A function may write into the table it read, the tables below it in your access model, and grants. An operation that reads an order and writes a refund works when a refund belongs to its order; it is refused when both only belong to the customer.
  • Answer refusals as data. Return { outcome: "refused", reason } from an operation for the model to read. An error thrown after the function read protected data reaches the caller as a fixed refusal with no reason.
An operation tool answers with its request’s receipt: { kind: "accepted", invocation_id, result }, where result is what your operation returned.

Tenants and staff directories

Sessions work with any access model, including one whose staff are a workspace directory and one that restricts objects to a tenant. A session principal is never a person of the directory: it holds only what its own grants give it. When the object a session acts for is restricted to a tenant, the session must also pass that tenant. Name the role that carries the pass in ancestorRoles: it is granted with the session, on the object’s own tenant, and ends with it.
bijection/mcp.ts
bijection/access.ts
A credential’s role is granted on one tenant, so each tenant has its own credentials and one tenant’s credential starts nothing in another. The credential’s role must be able to read the field that names the object’s parent (customer:see above covers a customer’s store). Deployment validates the coordination tables, required indexes, public tool definitions, operation authorization and mounted routes before publishing the program. An incomplete installation names the missing declaration.

Seeing what a session may do

describe reads the declaration. inspect reads an existing session, its termination history and the current state of each recorded tool contract. Neither creates a session or needs its signing key; both use deployment administration. Every command prints its report as JSON with --json. check validates session admission, the tool contract and the arguments without executing the tool or consuming its rate allowance. A definite refusal returns denied and exit status 1. Otherwise it returns requires_execution: operation permission, data access, business conditions, request ownership and rate admission are decided for the session when the tool runs. Deployment administration reads none of your access model’s grants, so a check never predicts those decisions. A check is an observation, not a reservation or a promise that a later call succeeds. bijection mcp try support --key support.voice-prod.agentkey --for <customer id> starts a one-minute session and lists its tools. Naming a tool and arguments executes it through the ordinary endpoint, then ends the session.

Creating a credential

This does four things, in order. As your verified business identity it grants the credential its role, so you need the power to grant that role, and then the issuing role on each operation the endpoint’s tools use, so you need the power to grant that too. It installs the credential’s public key on the deployment, and it writes the private key to support.voice-prod.agentkey. Bijection keeps no copy. Store the file’s one line as a secret in your backend, then delete the file. A credential belongs to one deployment. Create one for each of development, staging and production. Use --on <key> when the credential’s role is granted on one object, such as one organization, rather than on the whole deployment. To revoke a credential:
Every token the credential signed stops working at its next request.

Starting a session

In your backend, after you have verified who is calling, start a session and hand the agent’s host its endpoint and token:
Bijection records your evidence and does not check it: only a credential holder can start a session, and you decide when a caller is verified. A session never changes whom it acts for. Before you know who is calling, start a session with actsFor: null: it holds no grant and only the tools in beforeVerification. Once the caller is verified, start another session. bijection/mcp/node runs in your own Node.js process. Don’t import it from your bijection/ folder. Call session.end() when the conversation ends: its grants are deleted and its token is refused from then on. Otherwise the session ends when it expires.

What a session can and cannot do

  • It may call the tools it was offered when it started. A tool you add later reaches new sessions only.
  • It may read and change what its role permits on its one object, through its tools.
  • Its token calls nothing but its endpoint. A direct call to one of your app’s functions is refused before the function runs, even a function behind one of its tools: the tool list, the bound arguments, the limits and the call log always apply.
  • It is never a person: it cannot approve, grant permissions, delegate, or take any decision that names who decided.
  • Its requests are limited each minute by limits.
When you deploy while a conversation is running, the session keeps every tool whose definition you left unchanged. A tool whose name, description or schema changed answers tool_changed for that session. When a tool call reads something the session may not, such as a field its role lacks, the request fails as a whole rather than returning a tool error. A host that was given only the endpoint and a token can call operation tools: within one session, the same operation with the same arguments is one request, so a repeated call never runs twice. A host that needs two identical requests uses session.connect({ store }), which gives each call its own identity.

Watching and revoking sessions

bijection mcp calls lists the tool calls sessions made and whether each completed, from your deployment’s audit log. It shows which session called which tool for which object, never the arguments. A call that did not complete was refused by your rules, failed, or was outside the session’s tools or limits. The console’s MCP endpoints page shows the same: each declared endpoint, the installed credentials and recent sessions, with a button to revoke a live one. A session is live, expired, ended (its host finished it with session.end()) or revoked (an operator revoked it, or its credential was removed). An ended or revoked session keeps that state, and when it happened, after its original expiry passes. Revoking a session ends it at once. Bijection refuses its token everything from then on, and a tool call still running is refused where it next reads or writes. An operation the session already requested, such as a refund awaiting review, stays requested.

Limits

  • A session is never given a marking’s pass: an object that carries a marking refuses the session unless one of its roles confers that pass.
  • In an app with a staff directory, a session cannot read people, so a tool cannot return a staff member’s name.
  • Up to four ancestorRoles in an endpoint.
  • Up to 16 endpoints in a module, 32 tools in an endpoint and 24 credentials in a deployment.
  • A session cannot keep working for a signed-in person after that person’s own session ends.