The MCP gateway
Put your tool servers behind your project's MCP gateway, grant tools to AI agents one by one, and see what the gateway checks on every call.
Your project has a gateway for the Model Context Protocol (MCP), the protocol AI agents use to call tools. It is at https://acme.authfi.io/mcp. Agents connect to it instead of to each tool server, and the gateway decides, call by call, whether this agent may call this tool with these arguments.
This guide shows you how to connect a tool server and grant its tools. It then describes what the gateway checks, returns and records. For a first call, start with Connect agents to tools.
Before you begin
You need:
- Administrator access to the AuthFI console.
- A registered agent with an access token for the gateway. See Give an AI agent an identity.
- The URL of the tool server, and the bearer token it expects if it needs one.
Connect a tool server
- In the console, open Integrations > MCP Gateway and select the Servers tab.
- Choose Connect a server.
- Fill in the dialog, then choose Register.
The console confirms that the server is registered. The gateway then reads the server's tools and lists each one as namespace.tool, for example github.create_issue. You see them on the Tools tab.
Grant tools
Nothing is callable until it is granted.
- On the Tools tab, choose Say who may call a tool.
- Choose the kind of caller: "An AI agent", "A person" or "A group".
- Under "Caller", choose the agent. Only active agents are listed.
- Under "May call", tick the tools. Use "Filter tools" to find them.
- Choose Grant 1 tool. The button counts the tools you ticked.
The console confirms that the caller may now call the tools. On the Tools tab, the "Who may call it" column shows the grant.
A grant is on one tool. Granting github.create_issue does not grant github.delete_repo. A grant to a group reaches every member of it, now and later.
You can also grant from the agent's own page: open the agent under Identity > AI Agents and choose Give it a tool.
Point the agent at the gateway
On the Overview tab, find "Where the agents connect" and copy the "Gateway" URL. For the example project it is https://acme.authfi.io/mcp. Configure the agent to call that URL, not the tool server.
Check that it works
List the tools as the agent. The gateway takes JSON-RPC over HTTP POST, with the agent's access token as a Bearer credential.
POST
/mcpcurl https://acme.authfi.io/mcp -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'$ACCESS_TOKEN is the agent's access token. The result contains the tools of every server you added. Each tool looks like this:
{
"name": "payments.refund",
"description": "Refund a payment",
"inputSchema": { "type": "object" },
"annotations": { "io.authfi/governance": "may_require_approval" }
}A tool this agent may call is marked no_policy_restriction.
After the agent calls a tool, open the Tape tab. The call is listed with its "Caller", "Tool" and "Verdict".
How tools are marked in the list
tools/list returns every tool, each marked with what would happen if this agent called it.
An agent can use the mark to avoid tools it cannot call. The decision itself is made on each call, with its arguments.
What is checked on a call
For every tools/call, the gateway checks, in order:
- The token is a valid agent access token for this project.
- The agent has not been revoked.
- The agent is granted this tool.
- If the agent is acting for a person, that person is granted it too.
- The arguments pass the project's rules.
Only then does the gateway forward the call, with the tool server's own credential.
When a call is denied
A denied call is an ordinary tool result with isError set, so the model reads it and can change course.
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"isError": true,
"content": [{ "type": "text", "text": "Denied by policy: agent:agt_7f3a9c21 is not granted payments.refund" }]
}
}When a call needs approval
If a rule sends the call to a person, the result says so. It carries an approval ID and tells the model how to continue.
{
"result": {
"isError": true,
"content": [
{
"type": "text",
"text": "Approval required. A human must approve this action in the AuthFI console (approval 3f0c2b6e-…). Retry this call with an argument \"_authfi_approval_id\": \"3f0c2b6e-…\" once it is approved."
}
]
}
}A person approves or denies the request on the Approvals page of the console. The agent then makes the same call again and adds the approval ID:
{
"jsonrpc": "2.0",
"id": 8,
"method": "tools/call",
"params": {
"name": "payments.refund",
"arguments": { "payment": "pay_4821", "amount": 1200, "_authfi_approval_id": "3f0c2b6e-…" }
}
}The gateway checks the approval, removes _authfi_approval_id, and forwards the call. The tool server never sees the approval ID. An approval is good for 15 minutes and for that call.
For approvals outside the gateway, see Ask before a sensitive action.
How credentials are kept
The tool server's credential is sealed when you enter it and is never shown again. The gateway attaches it to each call it forwards. The agent never holds it, so the agent has nothing to leak, and revoking the agent needs no change at the tool server.
With "Each user's own" credential, each person connects their own account. On the Servers tab, the person chooses Connect my account on the server, enters "Your token" and chooses Connect. The gateway then makes each call with the account of the person the agent is acting for. A call with no person, or for a person who has not connected their account, is denied.
How an agent signs in to the gateway
An agent sends its access token as a Bearer credential. An agent access token requested with no resource is issued for the gateway by default.
A request with no token, or with a token that is expired or revoked, gets a 401, as RFC 9728 describes:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://acme.authfi.io/.well-known/oauth-protected-resource"The document at that URL names the gateway and where to get a token for it:
{ "resource": "https://acme.authfi.io/mcp", "authorization_servers": ["https://acme.authfi.io"] }Protocol reference
What is recorded
Every call, allowed or denied, is an entry in the audit record. The entry holds the agent, the person it acted for, the tool, the decision and its reason.
The Tape tab of Integrations > MCP Gateway lists the last 100 calls.
Its columns are "When", "Caller", "Tool", "Verdict", "Why" and "Acted for". Filter the list with "every call", "refused" or "allowed".