Skip to content
Developer Preview — known limitations are marked in red and will be fixed for production.

MCP gateway

Agents never call Polarion, GitLab, GitHub or any other system directly. Every tool call goes through the MCP gateway in the Agent Runner. The gateway decides what an agent may see and do, holds what needs a person, and records everything on the run.

Each run gets a run token when it starts. The token stands for one agent on one task with one set of granted tools. It is closed when the run ends.

  • Calls without a live run token get HTTP 401.
  • The agent loop sends the token as a bearer header. In a sandbox, Claude Code and Codex get it for the run’s duration; the files that hold it are removed after the run.
  • Run tokens live in the runner’s memory only.

tools/list returns only what this run may use:

  • Polarion tools the agent’s approved skills allow, plus the tools every agent has (see Tools).
  • Tools of connected MCP servers, named <connection>__<tool>, for every connection that passes three checks: the pool agent ai_uses the connection, the connection is active, and the engagement grants it in this project. A connection that needs a credential is left out if the secret is missing.

Each external tool’s description starts with the connection’s name and says whether it is limited to a scope, needs human approval or is blocked. Tools that need approval get a required why argument: the agent’s reason for the approver. The gateway removes it before the call.

Tools are always offered with the reviewed definition from the connection’s tool policy, never with what the server currently advertises. See Tool drift.

flowchart TB
  C["<b>Tool call</b><br/><small>agent, with its run token</small>"]:::run --> K["<b>Gateway checks</b><br/><small>token valid · tool granted · inside project scope</small>"]:::mute
  K -- fails --> X["<b>Refused</b><br/><small>recorded on the run</small>"]:::bad
  K -- passes --> P{"<b>Policy of the tool</b>"}:::mute
  P -- read --> R["<b>Runs</b><br/><small>recorded</small>"]:::ok
  P -- approve --> SR{"<b>Standing rule?</b>"}:::mute
  P -- block --> B["<b>Blocked</b><br/><small>recorded</small>"]:::bad
  SR -- yes --> RA["<b>Runs</b><br/><small>auto-approved · recorded</small>"]:::ok
  SR -- no --> H["<b>Held</b><br/><small>approval card for a person</small>"]:::you
  H -- approve --> RH["<b>Runs exactly as held</b>"]:::ok
  H -- deny --> N["<b>Not run</b><br/><small>note goes to the agent</small>"]:::bad
  classDef run fill:#ece5fb,stroke:#7c3aed,stroke-width:1.2px,color:#2b1d4f
  classDef you fill:#fdf0d8,stroke:#b7791f,stroke-width:1.2px,color:#4a3210
  classDef ok fill:#e3f2e7,stroke:#1f7a3d,stroke-width:1.2px,color:#143d22
  classDef bad fill:#fbe4e2,stroke:#b3261e,stroke-width:1.2px,color:#4d1612
  classDef mute fill:#f1f4f6,stroke:#8a96a3,stroke-width:1.2px,color:#2a3440

Every tool of a connection has one policy, set when the connection is reviewed:

Policy What happens
read The call runs and is recorded.
approve The call is held: stored with its exact arguments and the agent’s reason, and the task goes to the supervisor.
block The call is refused and recorded as blocked.

When a server is registered, policies are suggested from the server’s own hints: read-only tools get read, destructive tools get block, everything else (including tools without hints) gets approve. A person reviews and can change every policy before the connection is activated.

Before any call, the gateway also checks the scope (below). Write calls within one run are serialized.

When a call is held:

  1. The gateway stores it in PocketBase (approvals): project, task, agent, connection, tool, arguments, reason, status pending. The same call already pending for the task is not stored twice.
  2. The task goes to waiting_input, assigned to the agent and the supervisor. The agent is told to stop.
  3. The supervisor sees the held calls in the task panel and approves or denies them (a reason is required to deny). The decision is posted as a Polarion comment written with the decider’s own session.
  4. On approval, the runner checks that the connection is still granted and the tool still has policy approve, then runs exactly the stored call with the connection’s credential. The agent posts the result on the task as itself.
  5. When nothing is pending for the task any more, the agent is woken with the trigger approval.

Changes agents want to make to Polarion items written by people (update_field, update_fields, add_image, set_images) are held the same way and applied as the agent’s bot user when approved. See Decisions.

When approving, the supervisor can choose Always allow. The rule is stored on the engagement’s grants (tool, who, when), written with the supervisor’s own session. Later calls of that tool by that agent in that project run without asking. They are still recorded, as approvals with status approved and reason “standing approval”.

  • Standing approvals are per project, agent, connection and tool.
  • They are never offered for changes to human-written Polarion items.
  • You remove one on the Team page. A copy in PocketBase (standing_rules) restores the rule when the agent is hired into the project again.

An MCP connection is a work item of type Agent Connection (aiConnection) in the Agent Pool. Register one with the wizard in Agency → MCP servers: the runner reads the server’s tool list, you review the suggested policies, and a draft connection is created.

Status Meaning
draft Being prepared; not usable
in_review Submitted for security review
active Approved; can be granted and is served by the gateway
disabled Switched off; agents lose its tools

Credentials are stored in the runner’s secret store by name; the connection only holds the name. See Connections.

Some systems hold many separate things (repositories, projects). A connection marked scoped must be limited per work project.

  • scopeArguments names the tool arguments that carry the scope, e.g. project_id. owner/repo joins two arguments into one value.
  • For each call, every scope argument the tool has must be given and must contain one of the engagement’s scope values. Otherwise the call is refused as out of scope.
  • A scoped connection without a scope in the engagement is locked: every call is refused, and the agent is told to ask for one.

Scope questions. The agent asks with ask_human and marks the question with scope_for = the connection. The answer options come only from the connection’s scope discovery (scopeOptions: a read tool, its arguments and the result field), run with the connection’s credential. The agent’s own suggestions are dropped. Without discovery, the question is free text. The answer is written into the engagement’s grants by the task panel, as the person who answered, and unlocks the connection.

MCP servers change their tools over time. The gateway compares each active server with its reviewed policy (results cached for 15 minutes; Check server now in the MCP server panel forces a fresh check).

Change on the server Effect on agents
Tool added Listed for review. Never offered before a person adds it to the policy.
Tool changed (description, inputs, read/destructive hints) Held: not offered until the policy is reviewed again.
Tool removed Held: not offered until the policy is reviewed again.

A person reviews the changes in the MCP server panel and saves the policy; it is written to Polarion under their name with the comment “Tool policy re-reviewed”. The Agency shows how many tools are held. If a server cannot be reached, nothing is held (calls fail anyway).

Sandbox agents use plain git. For every granted connection with a gitRemote, the run configures git to send that host’s URLs to the gateway’s git proxy (on the sandbox entrance) and sets the run token as git’s auth header. The header is removed after the run. Commits are authored as “<Agent> (AI agent)”.

The git proxy:

  • refuses runs without a live run token and connections that are not granted or are locked;
  • allows only repositories in the engagement’s scope for that connection (exact match);
  • allows clone and fetch;
  • allows push only to branches matching gitPushBranches (default agent/*, feature/*), never to other refs, never deletes a branch, and refuses pushes over 50 MB;
  • adds the connection’s credential on the way out (gitAuth: basic with a user such as x-access-token or oauth2, or bearer). The credential never enters the sandbox.

Every fetch, push and refusal goes into the run ledger. Merging stays a decision for a person: a merge is an MCP tool call under its policy, typically approve.

Where What
agentRun description Table of gateway calls: tool, decision, result, time, argument summary
agentRun ledger Every artifact read, created, changed, requested or blocked, in Polarion and connected systems
Task comments Approval decisions (as the person) and results of approved calls (as the agent)
PocketBase approvals Held and auto-approved calls with arguments, reason, decider and result
Administration → Gateway Actions per day and server, blocked attempts, standing-rule audit