Ana içeriğe geç

MCP Gateway

Overview​

MCP (Model Context Protocol) is the standard AI agents use to discover and call external tools. In Apinizer, MCP is a first-class API proxy type — you create an MCP Gateway the same way you'd create a REST, SOAP, or LLM Gateway, and configure its behavior on a dedicated routing tab. An MCP Gateway works in one of two directions:

  • Expose Tools — publishes your existing API proxy operations as MCP tools that any MCP-compatible client can discover and call
  • Passthrough — forwards MCP calls through to an external MCP server, applying tool filtering and output masking along the way

The MCP Gateway menu item takes you to a card-based list of your MCP Gateways, the same layout used for LLM Gateways — open a card to reach that proxy's routing, policies, and trace/traffic/analytics tabs.

Proxy Information Fields​

Each MCP Gateway's own Overview tab shows the proxy information panel every proxy type has, plus three MCP-specific fields:

FieldDescription
Routing ModeShows Expose Tools or Passthrough; for Expose Tools it also shows how many tools are published and which source API proxy they come from.
MCP Protocol VersionThe protocol version this proxy serves, applied on the next redeploy — see Protocol Versions.
Client AuthenticationNone or Required — shows Required when the proxy or its attached API Proxy Group has an active authentication policy. Other policy types (e.g. IP restriction, logging) do not require client authentication; such a proxy shows None.
Info

Coming from an older release? MCP used to be configured on a separate "Inbound Server" screen with its own authentication settings, reachable at a dedicated path. That model has been replaced entirely — see Migrating from the Previous Model. New to the MCP protocol itself? See AI Fundamentals for a primer.

Quick Start​

Create an MCP Gateway

Create a new MCP Gateway the same way you'd create any other API proxy: give it a name and a single client-facing path.

Choose a Routing Mode

Open the proxy's Routing tab. Select Configure on the Routing Mode panel, pick Expose Tools or Passthrough in the drawer, then select Save. The tab shows the sections for the saved mode.

Configure the Mode

For Expose Tools, select which of your API proxy operations should be published as tools. For Passthrough, add one or more MCP servers directly on the routing tab (endpoint, transport, and authentication) and, optionally, restrict which of their discovered tools are allowed through.

Add Authentication

Attach any of Apinizer's regular authentication policies (API Key, JWT, OAuth2, ...) to the proxy — the same way you would on any other proxy type.

Save and Deploy

Deploy the proxy. Its client path becomes the single endpoint MCP clients connect to, for both discovery and tool calls.

Connect a Client

Open the proxy's Overview tab and use the Client Endpoints section to copy the MCP endpoint plus a ready-to-run snippet for your client — see Client Endpoints (Overview).

The Routing tab saves as you go

The Routing tab has no Save button at the bottom and no "unsaved changes" warning. Every change is written to the server the moment you make it.

  • Every section that holds settings — Routing Mode, Tool Output Filter, and Discovery — server.json — is shown read-only, with a Configure button that opens a right-side drawer. Change the setting in the drawer, then select Save; Cancel discards the edit.
  • Each drawer — Add / Edit Tool, Add / Edit Server, and Configure for Routing Mode, the Tool Output Filter and server.json — has its own Save button. It writes the change and closes only after the server accepted it. A rejected change leaves the drawer open with your text intact.
  • The few controls still shown directly on the tab are saved as soon as they change: forwarding the client token, the allowed-tool-names list, the Generate automatically / Custom selection in Discovery — server.json, and deleting a row.
  • Deleting an exposed tool or a backend server row asks for confirmation first. Select Delete to remove the row — the removal is saved immediately; Cancel leaves everything as it was.
  • The tab's controls are disabled for the moment a save is in flight.
  • If a save is rejected, the tab returns to the last saved state. What you see is always what the server has.
  • A saved change still needs a deploy to reach the gateway.

Creating One from an Existing API Proxy​

If you already run a REST or SOAP API Proxy, you don't have to enter its endpoints as tool rows one by one: the Convert to MCP Gateway action generates a ready MCP Gateway next to that proxy.

The action is available in two places:

  • the row menu in the API Proxy list
  • the proxy's detail screen: More actions (⋯) at the top right, then Convert > Convert to MCP Gateway

It appears only for REST and SOAP proxies; MCP, A2A, AI, gRPC and WebSocket proxies don't offer it. It also requires the AI Gateway license module — without it the generated proxy would be unreachable afterward, since MCP Gateways live under the AI Gateway menu group.

The source proxy is left untouched

Despite the name, converting replaces nothing: the source proxy does not change — its type, routing, policies, credentials, access lists and deploy state all stay as they were, and it keeps serving traffic exactly as before. The generated MCP Gateway runs in Expose Tools mode and loops every tool call back to the source proxy, so all of that proxy's policies still apply to MCP calls.

Before anything is saved, the dialog lists the tools that will be created: tool name, method, endpoint and where the input schema comes from. The name and relative-path fields are pre-filled with the suggested values (<source name> MCP and <source relative path>-mcp); you can change both.

How the tools are generated:

  • Only active endpoints become tools. A deactivated endpoint is skipped.
  • The tool name is derived from the specification's operationId, then its summary, then <METHOD>_<path>; it is then normalized to the MCP naming convention and made unique within the catalog (_2, _3 … suffixes).
  • For a REST source no schema is stored — the gateway derives an operation-specific schema from the source proxy's specification on every tools/list call. Those rows are marked Automatic in the preview.
  • For a SOAP source a schema is stored, carrying a single body string argument, because automatic WSDL-to-MCP schema mapping is lossy. Those rows are marked From WSDL; you can refine the schema later on the Routing tab.
  • If the source proxy has no active endpoint, the conversion is rejected.
  • If the target name or relative path is already taken, the conversion is rejected — change it in the dialog and try again.
The new gateway arrives undeployed

The generated MCP Gateway is created undeployed. Review the tool list, then deploy it to an environment the same way you would any other proxy.

To do the same from a CI/CD pipeline, use the Create MCP Gateway from an API Proxy endpoint.

Modes​

Expose Tools​

Publishes selected operations from your existing API proxies as MCP tools. Each exposed tool maps to one API proxy operation, can override the tool's auto-generated input schema, and can optionally set Required Scopes. Enter role names there: the caller must hold all of them, whichever authentication policy the proxy uses. The check is fail-closed — a caller who does not hold all of them, or holds no roles at all, is denied the tool. If the field is empty, any authenticated client may call the tool. A caller missing a required role is denied that particular tool while the rest of the catalog behaves normally. With the Standard MCP OAuth profile, the client asks for the OAuth Scope Name of each role — see Scopes and tool access.

How a Tool Name Is Published​

The Tool Name you type on a row is normalized to the MCP naming convention before it appears in tools/list: lowercased, every character other than a letter or digit replaced with an underscore, repeated underscores collapsed, and the result truncated to 64 characters. For example Check Availability becomes check_availability and hotelDetails becomes hoteldetails. If two rows normalize to the same value, the second gets a _2 suffix and the third _3, so no tool ever disappears from the catalog.

Leave the field blank and the name is derived from the source proxy's technical id — fill it in to get a readable one.

You edit the name in the drawer that opens from the right of the row. The drawer's Save button writes the change to the server and closes the drawer once the server accepted it. The order is: Save → deploy. Skip the deploy and the table shows the new name while the gateway keeps serving the old one.

The new name appears only after a deploy

The gateway always serves the last deployed configuration. Changing a tool name and saving does not by itself change the tools/list response; the new name reaches clients only after you redeploy the proxy to that environment.

Passthrough mode does not apply this normalization — there the names come from the backend MCP server and Apinizer relays them verbatim. So a tools/list response containing a name with uppercase letters (hotelDetails, say) did not come from your Expose Tools configuration: it came either from a Passthrough configuration or from a deployment that has not been refreshed yet.

Deprecated Operations​

When the source API proxy's specification marks an operation as deprecated, the tool stays in tools/list and callers can still call it. The gateway starts the tool description with [Deprecated] , so the model and the user can see it.

A disabled endpoint is a different case. Its tool also stays in the list. A call to it returns a tool error (isError is true) that says the method is not found or disabled. It is not a JSON-RPC error.

Passthrough​

Forwards MCP calls to one or more external MCP servers, defined directly on the proxy's Routing tab — there's nothing to create or reference elsewhere first.

Automatic Tool Discovery

Once a server's endpoint is saved, a Discover / Reparse Tools action fetches its tool catalog and pins it as the approved baseline.

Fetch Tools Before Saving

Fetch tools in the server drawer lists what the server offers right now, without saving the row — see Checking a Server Before You Save It.

Tool Allow-List

Leave the allow-list empty to pass every discovered tool through, or select specific tools to restrict what's reachable through this proxy.

Health Probe

Each server is probed periodically and reports Healthy, Down, or Unknown status with its last response time.

Egress Protection

Discovery and tool calls reach only public https addresses unless you turn on Allow private-network egress for a server — see Security and Governance.

Backend Failure Responses​

When the MCP server fails during a Passthrough call, the gateway returns a JSON-RPC error with code -32603. The error.message field keeps the error message defined for this error type, ERR-262 (default: Tool execution failed.). The error.data field tells the client why the call failed:

{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32603,
"message": "Tool execution failed.",
"data": { "reason": "BACKEND_AUTH_FAILED", "phase": "discovery", "httpStatus": 401 }
}
}
  • phase is discovery when the gateway could not get the tool list from the server. It is call when the tool call itself failed.
  • httpStatus appears only when the server sent an HTTP error status.
  • backendErrorCode appears only when the server sent a JSON-RPC error. It holds the server's error code.
reasonMeaningWhat to check
CONNECTION_CONFIGURATION_ERRORThe connection definition blocks the call.Egress protection (private address), mTLS key store, catalog drift block.
BACKEND_UNREACHABLEThe worker cannot reach the server.Server address, DNS, firewall. Do not use localhost — it points to the worker pod.
BACKEND_TIMEOUTThe server did not answer in time.Server load and network latency.
BACKEND_TLS_ERRORThe TLS handshake failed.Server certificate and trust store.
BACKEND_AUTH_FAILEDThe server or its OAuth2 token endpoint rejected the credential.Authentication settings of the server row. If token passthrough is on, the client token.
BACKEND_HTTP_ERRORThe server sent another HTTP error status.httpStatus and the server logs.
BACKEND_TOOL_ERRORThe server sent a JSON-RPC error. The tool itself failed.backendErrorCode and the server logs.
BACKEND_PROTOCOL_ERRORThe response is not a valid MCP response, or the protocol version does not match.The MCP Protocol Version of the server row. Make sure the address is an MCP endpoint.
BACKEND_CONNECTION_ERRORAnother transport error occurred.Worker log.

The response never contains the server address, the exception text, or the server's error body. The worker log keeps the full detail in a MCP PASSTHROUGH warning line.

Both modes' tool results pass through the same output filtering used elsewhere in the gateway: a deny-pattern match blocks the whole response (not just the matched portion), and PII masking covers the platform's built-in personal-data types.

MCP Servers Are Configured Inline​

There's no standalone "MCP connection" screen to visit first — an MCP server is defined at the exact place it's used:

  • On a Passthrough proxy's Routing tab, where it can be one of several aggregated servers (see Multi-Target Aggregation).
  • Inside the MCP Call (LLM) / MCP Call (Fixed) policy, as a single server a model calls as part of any LLM Gateway's own tool-call loop — no MCP Gateway required for that path at all.

Each definition carries its own endpoint, transport, authentication, discovered-tool catalog, health status, and approved-catalog fingerprint — nothing is shared by reference between proxies or policies, so there's no separate object to look up, and no cross-proxy blast radius when one server's credentials change.

Checking a Server Before You Save It​

The Add / Edit Server drawer has a Fetch tools button next to the save row. It asks the server for its tool list there and then, using exactly the address, credential and mTLS settings currently typed in the drawer, and lists what came back — tool name and description — with a count badge.

  • Nothing is saved by this. In Passthrough mode the gateway resolves the backends' catalogs at request time anyway, so the list is a confidence check ("the address and the credential work, and this is what the server offers"), not a catalog the proxy then depends on.
  • When you're editing a server that's already saved, you don't have to retype its token: leave the masked field untouched and Apinizer uses the stored credential for the check.
  • The button stays disabled until an endpoint is entered. It also stays disabled when you do not have manage permission on the API proxy, because the check needs that permission. If the call fails, the drawer keeps your text and states the reason the server gave — an HTTP status (MCP server returned HTTP 404), a refused connection, a blocked egress target, or a reply that is not an MCP tools/list result. Fix the address, the credential or the network path and select it again.
  • The check runs from the Manager, not from a gateway worker, so the address has to be reachable from there. With Allow private-network egress on, the check can also reach loopback (127.0.0.1, localhost), RFC1918, link-local and in-cluster addresses, and plain http works. With it off, only public https addresses are accepted. Turning it on also opens the cloud metadata address, so enable it only for trusted servers.
  • A common mistake is entering the address of a non-MCP proxy (an LLM Gateway, for example). Such an address answers, but not with an MCP handshake, so the check fails with a protocol error rather than a connection error.

The Backend MCP Server List​

The Backend MCP Server section lists every server on its own card: the name, the endpoint, and badges for the protocol version, the authentication scheme, private-network egress and the capability cache. Configure opens that server's drawer; the bin icon removes it.

Under each card sits that server's own tool panel. Select Fetch tools on the card and Apinizer asks that one server — with its saved address and credential, so there is no token to retype — what it offers right now, then lists every tool it answered with, name and description. The button needs manage permission on the API proxy; without it, the button is disabled.

  • The list is never saved. It is live discovery, exactly like the drawer's check: the gateway asks the backend again on every request, so what you see is the answer of the moment, not a catalog the proxy keeps.
  • Every tool carries an allowed or blocked badge, read from the Allowed Tool Names list in the Client Access & Forwarding section above the server list. An empty allow-list means every discovered tool is allowed. A tool the allow-list keeps out stays visible and is badged blocked on purpose — otherwise you could not tell a tool missing from the server apart from a tool merely missing from your allow-list.
  • A caller-specific identity rule (see Security and Governance) can still hide an allowed tool from an individual caller. The badge reports the proxy-wide decision, not a per-caller one.
  • When the server can't be reached, the panel says so and prints the reason the server gave — an HTTP status, a refused connection, a blocked egress target — so you can correct the address or the credential without leaving the page.

Routing Mode Panel​

The Routing Mode panel at the top of the Routing tab is a read-only summary: the active mode's card is highlighted, the other is dimmed, and the advertised protocol version is shown next to the panel title.

Select Configure to change either of them in a right-side drawer — pick the mode, pick the protocol version, then select Save; Cancel discards the edit. The mode decides which sections the tab shows (Exposed Tools for Expose Tools, Backend MCP Server for Passthrough), and those sections move only once the save succeeds, so browsing the two descriptions in the drawer never rearranges the page underneath you. Each mode keeps its own settings when you switch, so you can move back and forth without losing what you already entered.

Picking Passthrough in the drawer also shows a Backend MCP Server list right below the two mode cards, because Passthrough is only a valid configuration once at least one backend server exists. Select Add Backend MCP Server to open the server drawer on top of the mode drawer and fill it in there; the server is saved as soon as you select Save in it, and you're returned to the mode drawer with your selection intact. Existing servers are listed with Edit and Delete next to each one. While the list is empty, the mode drawer's own Save stays disabled and a warning explains why — so you can no longer save Passthrough first and meet the "Passthrough needs at least one backend MCP server" refusal afterwards.

Tool Output Filter​

The Tool Output Filter panel is read-only in the same way: a badge shows whether the filter is Active or Disabled, a second badge shows whether PII masking is on, and the deny patterns are listed below (a dash means there are none).

Select Configure to open the drawer, where you switch the filter on or off, switch Mask PII on or off, and add or remove deny patterns; Save writes all of it in one step and Cancel discards it. A deny-pattern match blocks the whole response, so a pattern that is too broad also blocks legitimate ones — prefer specific patterns.

Discovery Document​

By default, an MCP Gateway's server.json document — described in Protocol Versions and in Client Endpoints below — is generated automatically from the proxy's own settings and its request-authentication policy chain, and stays in sync with them across saves and redeploys.

On the Routing tab's Discovery — server.json panel, switch to Custom to take the document over completely:

  • The panel shows the published document read-only. Select Configure to open it in a right-side drawer, edit it there, then select Save — Cancel discards the edit, and Save stays disabled while the text is not valid JSON.
  • The drawer is seeded with the document the gateway generates today, so switching over doesn't mean starting from a blank file — you only edit what you actually want to change.
  • The drawer's Save writes the document straight to the server and closes only once it was accepted — there is no second Save button to press afterwards. A rejected document leaves the drawer open with your text intact.
  • The text must still be valid JSON to save; a syntax error is flagged inline and blocks saving. A document missing a required MCP Registry member (name, description, version, or remotes) only produces a non-blocking warning — it's your document, and Apinizer won't reject it on your behalf.
  • ${VARIABLE_NAME} environment variables inside the custom text are resolved when the document is served, so the same hand-written text can still carry a different remotes[].url per environment.
  • To give the document back to the gateway, switch the same select button to Generate automatically. That discards the custom text and saves the change immediately; the gateway resumes generating the document from the next deploy on. There is no separate "back to automatic" link.

Because server.json is served completely unauthenticated, whatever you type is exactly what an anonymous caller receives — keep it free of secrets, and keeping it accurate afterward is entirely your own responsibility.

Client Endpoints (Overview)​

The Overview tab's Client Endpoints section is where you copy the exact addresses and ready-to-run requests a client needs, scoped to an environment you pick from a selector at the top of the section. Every credential shown here — in the address list, the samples, and the numbered steps below them — is derived from the proxy's own request-authentication policy chain, not a fixed template: the section shows exactly what a caller has to send for the policies you've actually attached, nothing more and nothing assumed.

  1. MCP Endpoint — the single POST JSON-RPC address every MCP client calls for initialize, tools/list, and tools/call, shown with a copy button.
  2. server.json — the unauthenticated GET address described in Protocol Versions, shown with a copy button, an Open link that loads it directly in a new browser tab, and a badge showing whether the document is Generated or Custom (see Discovery Document).
  3. Token Endpoint — shown only when the attached policy chain actually issues a token (JWT or OAuth2 managed by this gateway): the POST address to call first to obtain one, with its own copy button.
  4. Legacy SSE Stream — shown only when the proxy's negotiated protocol version is 2024-11-05; the GET address for that transport's push channel, with its own copy button.
  5. Ready-to-run snippets — a tabbed set covering tools/list, tools/call (with a tool picker so you can generate a call for any exposed tool without typing its name or arguments by hand), initialize, server.json, and a Client config tab with drop-in .mcp.json and Claude Desktop configuration blocks. Each sample carries whichever credential the attached policy chain actually needs — a Basic policy produces -u "<username>:<password>", an API key policy sends the configured header or query parameter, and a JWT/OAuth2/OIDC policy prefixes the sample with the token request described below.

Below the addresses, whenever the proxy has at least one request-authentication policy attached, an Authentication panel spells out the exact numbered steps for that chain — several policies stacked together (for example mTLS plus Basic) each contribute their own step, because the caller has to satisfy all of them:

  • Basic — send the consumer's username and password as HTTP Basic (-u "<username>:<password>", or an Authorization: Basic <base64(username:password)> header).
  • API key — send the key in the configured request header, or as a query-string parameter if that's how the policy is set up.
  • JWT / OAuth2 issued by this gateway — first POST the Token Endpoint above (grant_type=client_credentials or grant_type=password, depending on the policy), then call the MCP endpoint with Authorization: Bearer <access_token>.
  • OIDC — obtain an access token from the external identity provider configured on the policy, then send it the same way as a bearer token; Claude.ai / Claude Desktop "Custom connectors" can drive this automatically when the provider supports OAuth 2.0 Dynamic Client Registration.
  • mTLS — present the client certificate on the TLS handshake (--cert client.crt --key client.key); there's no header to copy.

Three cases can't be fully expressed in a static client configuration file, and the panel warns instead of showing a sample that would not work:

  • HTTP Digest needs a challenge/response round-trip that MCP clients such as Claude Desktop and Cursor can't perform — prefer Basic or a token policy for MCP.
  • An API key sent as a query parameter is appended to the URL in curl samples, but .mcp.json / Claude Desktop configuration has no field for it.
  • mTLS can't be presented by mcp-remote or Claude Desktop — terminate mTLS on a local bridge/proxy, or pair it with a token policy.

If the attached policy has no client-side recipe at all (for example JOSE message-level validation, or SAML), the panel says so directly instead of guessing — check the Policies tab and use a policy an MCP client can actually satisfy.

For example, given an MCP Endpoint of https://api.apinizer.com/apigateway/aigw/petstore-mcp/ protected by an OAuth2 policy (client-credentials grant, managed by this gateway), its server.json is published at https://api.apinizer.com/apigateway/aigw/petstore-mcp/.well-known/mcp/server.json, following the MCP Registry's server.json schema:

{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
"name": "com.apinizer/aigw-petstore-mcp",
"description": "Apinizer MCP Gateway: Petstore MCP",
"version": "1.0.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://api.apinizer.com/apigateway/aigw/petstore-mcp/",
"headers": [
{
"name": "Authorization",
"description": "Bearer <access_token> obtained from https://api.apinizer.com/apigateway/auth/token",
"isRequired": true,
"isSecret": true
}
]
}
],
"_meta": {
"com.apinizer": {
"protocolVersion": "2026-07-28",
"authRequired": true,
"auth": [
{
"scheme": "bearer",
"tokenEndpoint": "https://api.apinizer.com/apigateway/auth/token",
"grantType": "client_credentials"
}
]
}
}
}

The remotes[] array is what makes the document actionable — it carries the transport, the URL, and the header(s) a caller must actually send, derived from every active policy in the request-authentication chain; the _meta["com.apinizer"] block underneath repeats the same recipe machine-readably as auth (one entry per policy, in chain order), next to the negotiated protocolVersion and a boolean authRequired flag. Nothing about the proxy's internal id, name, or routing mode is published to this unauthenticated endpoint.

The tools/list snippet looks like:

curl -X POST https://api.apinizer.com/apigateway/aigw/petstore-mcp/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Below the snippets, a collapsible Exposed tools table lists every tool the proxy currently publishes — its name, description, source API proxy, and whether it has an input schema — for a quick check before you copy a snippet.

Warning

If the source API proxy behind an exposed tool isn't deployed to the environment you've selected, that tool's input schema shows empty and a tools/call against it returns Tool backend proxy unavailable. Deploy the source proxy to the selected environment to resolve it.

Outbound Tool Call​

When an LLM Gateway's model wants to call a tool (tool_use / function calling), the component that actually forwards that call to an external MCP server is the MCP Call (LLM) policy, attached to the LLM Gateway's response flow (the tool-call step). As with Passthrough, the target server is defined inline, on the policy's own screen. For a fixed, admin-chosen tool call that runs on the request or error flow instead — see MCP Call (Fixed) below.

Add the policy

Attach the MCP Call (LLM) policy to an LLM Gateway's response flow (the tool-call step).

Define the server

In the MCP Server (Inline) section, enter the endpoint, protocol version, authentication scheme (see Backend Authentication), and capability-cache settings. It carries a single endpoint — there's no failover/multi-server list here; to call more than one external server, add a separate policy instance for each.

Discover tools

The Discover / Reparse Tools button connects to the server, confirms the connection works, and fetches its tool catalog — it runs before you save, so there's no separate "test connection" step.

Restrict allowed tools (optional)

Leave it empty to allow every discovered tool; if no tools have been discovered yet, the call is denied fail-closed. To restrict, pick from the Allowed Tools list.

This server definition is subject to the same SSRF protection as Passthrough mode (see Security and Governance). The policy screen's MCP Connection field is kept for backward compatibility: it's disabled once an inline server is defined, and only one of the two is ever used at runtime.

This policy can also be added and updated through the APIops REST API — see API Reference: Policies.

MCP Call (Fixed)​

The MCP Call (Fixed) policy invokes a single, admin-chosen tool on an external MCP server independently of the model. Unlike MCP Call (LLM), it does not wait for the model to produce a tool call — it runs in the request flow or the error flow of any proxy type.

FieldDescription
Target ToolThe tool to invoke, selected from the server's discovered tool catalog. A tool not in the catalog is rejected fail-closed.
Arguments TemplateJSON body sent to the tool. ${VARIABLE_NAME} environment variables are resolved first; #{...} context variables next. The resolved text must be valid JSON; an invalid template is treated as a dispatch failure.
Wait ModeFire and Forget (default) — dispatches asynchronously without blocking the flow. Sync to Variable — waits for the result and writes it to the named output variable.
Output Variable NameRequired only when Wait Mode is Sync to Variable.
Call Timeout (ms)Per-call HTTP timeout. Default: 30 000 ms.

Failure behavior. Two failure categories apply:

  • Configuration problems — inline server not configured, target tool blank or its environment variable unresolved, tool absent from the catalog, or the caller's identity denied by access rules — block the request with HTTP 500 / ERR-288.
  • Dispatch failures — timeout, remote error, invalid arguments JSON, or an argument constraint violation — are logged only and never block the request or error flow. In Sync to Variable mode the output variable stays empty; check it before using it downstream.

The tool result is written to the output variable without personal-data masking. Argument constraints on this policy are configured through the Management REST API only, not on the policy screen.

This policy can also be added and updated through the APIops REST API — see API Reference: Policies.

Response Flow Only​

The MCP Call (LLM) policy acts on the tool calls that the model returns. These calls exist only in the response. For this reason the proxy accepts this policy, and the A2A Call (LLM) policy, only in the response flow. The platform names them "MCP Tool Call" and "A2A Agent Call" in the error. A save that puts one of them in the request flow or the error flow is rejected with the message "MCP Tool Call and A2A Agent Call policies can be placed only in the response flow". The check covers proxy-level and method-level flows and policy groups, and it applies to every save path, including the APIops REST API and import. The platform does not move the policy to another flow for you. The MCP Call (Fixed) and A2A Call (Fixed) policies are not part of this check.

Backend Authentication​

The same authentication schemes are available on an MCP server row of a Passthrough proxy and on the inline server of the MCP Call (LLM) / MCP Call (Fixed) policies. The same schemes exist on A2A agents (see A2A Gateway).

SchemeWhat the gateway sends
NoneNo credential.
BearerA fixed bearer token in the Authorization header.
OAuth2 Client CredentialsA token that the gateway gets from the token endpoint with the client ID and secret.
mTLS (Client Certificate)The client certificate of the selected KeyStore. No Authorization header.
API Key (Header)The API key in the header you name, for example X-API-Key. No Authorization header. Authorization, Proxy-Authorization, Host, Cookie, Accept, Accept-Encoding, content and connection headers, MCP-Protocol-Version and Mcp-Session-Id cannot be used as the header name.
Basic AuthenticationThe username and password as Basic credentials in the Authorization header. The username cannot contain a colon. Use an https endpoint.
OAuth2 Token Exchange (RFC 8693)A token for the target. The gateway exchanges the verified token of the caller at the token endpoint of an external authorization server. Only the new token is sent.

Secrets in connections. The API key, the Basic password, the bearer token and the client secret of an MCP or A2A connection are hidden from a user who can only view the connection. The screen shows a "set" mark instead of the value. A user who can edit the connection sees the value. If you leave a secret field empty when you save, the stored value stays.

OAuth2 Token Exchange works as follows. The Apinizer Credential AS also accepts this grant (see Token Exchange).

  • The caller token must come from an authentication policy of the proxy (JWT, OAuth2 or OIDC) that verified it in the same request. A Basic credential or an unverified header is not used.
  • A request without a verified caller token is refused. The gateway never falls back to its own credential.
  • Token Exchange Audience is optional. When you leave it empty, the authorization server uses its default. The gateway sends the client ID and secret with Basic client authentication.
  • The gateway keeps the exchanged token in a shared cache. The cache entry lives until 30 seconds before the earlier of the token expiry and the caller token expiry. When neither expiry is known, the gateway uses the token for that call only.
  • The cache key includes the caller token, the token endpoint, the client, the scope and the audience. One caller never gets the token of another.
  • When the target answers 401 or 403, an MCP server entry is removed from the cache and the call is tried once more. A2A agents are not tried again.
  • Token forwarding (passthrough) does not apply to this scheme.
  • Fetch tools, Discover / Reparse Tools and the connection test cannot get a token, because they carry no caller token. The connection test only checks the settings. The health status of such a server shows Unknown.

Discover Auth​

The Discover Auth button sits next to the endpoint on the server drawer and on the MCP policy screens. It asks the target what it needs and suggests the form values. Apply to form puts the suggestion in the form. Nothing is saved, and no credential is sent.

  1. The gateway sends an anonymous request to the endpoint. For a server without a fixed protocol version it starts with server/discover, and it tries initialize when that fails.
  2. When the target answers 401 with a resource_metadata address, the gateway reads the protected resource metadata (RFC 9728) and then the authorization server metadata (RFC 8414, then OpenID Connect).
  3. The form shows the suggested scheme, the token endpoint, the scopes, the grant types and the client authentication methods. You enter the client ID and secret (or the key or password) and save.

What you should know about the result:

  • The gateway does not suggest a token endpoint when the issuer in the metadata differs from the authorization server address. A note explains why.
  • A note appears when the resource in the metadata differs from the endpoint, when the authorization server has no client credentials grant, when it supports token exchange, and when the target needs a client certificate.
  • A value that would be read as a variable, and a token endpoint that is not https, are dropped. A note tells you.
  • When the target answers without credentials, the current scheme stays, because the server may protect only the tool calls.
  • The discovery runs in the Manager, not in a gateway worker. It accepts https addresses; plain http is accepted only when Allow private-network egress is on. It never follows a redirect, and the whole run has a 30-second limit.
  • Without Allow private-network egress, private and reserved addresses (loopback, link-local, cloud metadata, RFC1918) are refused. With it on, none of them is blocked and plain http is accepted. Only a system administrator can turn that setting on.
  • Discover Auth needs the manage permission of AI development or API management in the project.

Protocol Versions​

An MCP Gateway uses one protocol behavior, set per proxy on the Routing tab (Routing Mode panel → Configure → MCP Protocol Version → Save) and applied on the next redeploy. This page calls the versions up to 2025-11-25 legacy and 2026-07-28 modern.

VersionBehavior
2024-11-05Legacy HTTP+SSE transport — a GET to the proxy's SSE sub-path opens a bounded push channel.
2025-03-26, 2025-06-18, 2025-11-25Streamable HTTP. The three behave the same on the inbound side. Responses carry an MCP-Protocol-Version header confirming the negotiated version.
2026-07-28Default. Modern protocol. The client sends the protocol version with every request, so it needs no initialize handshake. See Modern Protocol (2026-07-28).

A blank value uses 2026-07-28. Convert to MCP Gateway creates a proxy with this default.

If a connecting client requests a version Apinizer doesn't recognize during initialize, the proxy falls back to the nearest earlier version it does support and logs a warning, rather than rejecting the request outright.

Modern Protocol (2026-07-28)​

Only a proxy set to 2026-07-28 reads the modern members of a request. Every other proxy handles every request as before.

  • Version in each request. A modern client writes the protocol version in the request metadata (_meta). The gateway serves the request without a session.
  • server/discover. Returns the supported versions and the capabilities of the gateway. A legacy request gets the normal "method not found" answer.
  • Unsupported version. The gateway answers with the JSON-RPC error -32022. The error data lists the supported versions and the version that the client asked for.
  • Unsupported version: HTTP status. The -32022 answer comes with HTTP 400.
  • Standard headers. A modern request must carry the MCP-Protocol-Version header (equal to the version in _meta), the Mcp-Method header (equal to the method) and, on tools/call, the Mcp-Name header (equal to the tool name). When one of them is missing or does not match the body, the gateway answers HTTP 400 with the JSON-RPC error -32020. Only a legacy request, one without _meta, is not checked. The gateway sends Mcp-Method and Mcp-Name to a modern backend server.
  • No _meta in the request. The gateway handles the request as a legacy request. An initialize request on a 2026-07-28 proxy gets a legacy version in the answer.

A modern tools/call can also end in an input request or a task. Both need an environment that has a JWT signing key, because the gateway signs the values that it gives to the client. Without the key, the gateway refuses these calls with the JSON-RPC error -32603.

Input Requests (input_required)​

In Passthrough mode, a modern backend server can answer a tool call with input_required instead of a result. The answer lists what the server needs from the user. The client collects the values and sends the same tools/call again, with the answers and the requestState value that it received.

  • The gateway passes the answer to the client. It signs the requestState value together with the caller, the client, the proxy, the backend server, the tool name and the arguments. The value is valid for 10 minutes.
  • When a different caller, tool or argument set uses the value, the gateway rejects the call with -32602.
  • The gateway passes the answers and the backend state to the backend server unchanged.

Tasks​

A task lets a client start a long tool call and read the result later. The gateway supports the Tasks extension (io.modelcontextprotocol/tasks):

  • A client must declare the extension in the request metadata of the same request. A modern client that did not declare it gets the error -32021 ("Missing required client capability") from tasks/get, tasks/update and tasks/cancel. A legacy request gets "method not found".
  • tools/call can answer with resultType: "task" and a taskId. The client reads the state with tasks/get. The gateway also uses tasks/update to pass user input to a backend task and tasks/cancel to cancel.
  • A task id that does not exist, has expired or belongs to another caller gets the same error (-32602, "Task not found").

Three kinds of task exist:

KindWhen it appearsWhere the state lives
Backend task (Passthrough)The backend server answers with a task, and the client declared the extension. The gateway signs the task id and passes it on. A client that did not declare the extension gets an error instead.The backend server. The gateway keeps no state. The finished result passes the output filter of the proxy.
Gateway task (Expose Tools)A client that declared the extension calls a tool, and the call is not finished in 10 seconds. The same call goes on in the background and is not started again.The gateway.
Approval taskA call waits for approval. See Tool Risk Policy and Approval.The gateway.

Gateway task rules:

  • A client that did not declare the extension always gets a normal synchronous answer from a slow call. The gateway never turns that call into a task.
  • The gateway writes the task record before it answers. If it cannot write the record, it waits for the call and answers synchronously.
  • A gateway task is limited to 150 seconds. A task that still runs after that becomes failed. The gateway does not run it again, for example after a worker restart. The suggested poll interval is 2 seconds.
  • The gateway keeps a finished task for 7 days, and then removes it. It removes the stored arguments when the task finishes.
  • Background calls count against the same limit of concurrent tool calls as other calls. When the limit is full, the gateway does not start a task and answers with the session-limit error.
  • tasks/cancel marks the task as cancelled. It does not undo what the call already did. A call that is already running can complete its side effects.

Elicitation​

Elicitation lets a backend server ask the user for more input during a tool call. The gateway supports it only between two parties of the same era:

ClientBackend serverForm modeURL mode
Modern (2026-07-28)ModernSupported. The backend answers with input_required, and the gateway passes it to the client (Input Requests).Same path. The gateway passes the content of inputRequests unchanged.
Legacy (up to 2025-11-25)LegacySupported in Passthrough mode when Relay elicitation requests is on for that backend server (off by default).Not supported in this version.
ModernLegacyRefused with ERR-310.Refused with ERR-310.
LegacyModernRefused with ERR-310.Refused with ERR-310.
AnyExpose Tools modeNot applicable. The tools of an Apinizer API proxy do not ask for input.Not applicable.

The gateway does not handle the form mode and the URL mode in different ways. It relays the content of the request and of the answer as the backend and the client sent it. Whether a client or a backend supports the URL mode depends on their protocol version and on the elicitation capability that the client declares. The gateway tells a legacy backend only that the client can answer elicitation requests (elicitation: {}), which means the form mode. It does not announce the URL mode, because the capability of the client does not reach the backend. Between legacy parties, the URL mode is not supported in this version.

Known limit: the gateway does not produce the Mcp-Param-* headers that the tools of a backend server define with x-mcp-header.

A call that does not use elicitation is not affected by these limits.

Relay elicitation requests is a switch on the backend server drawer (Passthrough). When you turn it on:

  • The gateway tells the backend server that the client can answer questions. Without the switch, the gateway sends no such capability and nothing changes for the server.
  • The question goes to the legacy client in an event stream. The client answers with a separate request. This request can reach another worker. The gateway sends the answer to the backend server.
  • The tool call can wait up to 5 minutes for the answer. The wait holds the request for that time.
  • The gateway relays only the elicitation request. Other requests from the server get "method not found", and the call continues. A ping gets an empty answer.
  • The relayed question carries a signed id that is bound to the caller and the proxy. The answer of another caller is refused.

Error Messages for MCP Calls​

Error codeWhenJSON-RPC error
ERR-309A tool call needs approval, and the client did not declare the Tasks extension. The error data holds the approvalId.-32021
ERR-310The tool asked for user input, and the gateway cannot relay it between the protocol versions of the client and the server.-32603

The gateway returns these errors as JSON-RPC errors in an HTTP 200 response, as it does for the other MCP refusals. You can change the default text on the Error Messages screen. See Error Messages.

The server.json document is published, unauthenticated, at the proxy's client path plus /.well-known/mcp/server.json, following the MCP Registry's server.json schema — required so a client can see not just that the gateway exists but where to connect and with which transport, before it has credentials to authenticate. By default it's generated from the proxy's own settings and its request-authentication policy chain; you can hand-write it entirely instead — see Discovery Document. It's a best-effort discovery aid: whenever the proxy's request policy chain contains an authentication policy, each entry in the document's remotes[] array carries the header(s) that chain actually requires, and the same recipe is repeated machine-readably as _meta["com.apinizer"].auth, next to a boolean _meta["com.apinizer"].authRequired — but the actual scheme enforced is whatever policy chain you've configured (see Authentication). The Overview tab's Client Endpoints section surfaces this same address with a copy button and an Open link, and — for a 2024-11-05 proxy — the legacy SSE address as well, so you don't have to build either address by hand.

Deployment Information​

An MCP Gateway's Deployment Information table (see Deployment and Specification Information) carries two MCP-specific columns in addition to the fields every proxy type shows:

ColumnDescription
server.jsonA link to the server.json document published for that environment.
ProtocolThe MCP protocol version negotiated for that environment's deployment.

Clicking Show in the Specs column opens a dialog with four read-only tabs for that environment — tools/list, initialize, server.json, and Client config — instead of an OpenAPI document. An MCP Gateway has no REST/SOAP contract to display, so the dialog shows the same catalog, handshake, and server.json document a connecting client would actually see, plus a ready-to-use client configuration block.

Multi-Target Aggregation​

A Passthrough proxy isn't limited to a single backend: define up to 10 MCP servers on its Routing tab, behind one client-facing endpoint. Their tool catalogs are merged into a single list; if two servers expose a tool with the same name, the collision is resolved deterministically by prefixing the tool name with its source server (serverName__toolName). If one server is slow or unreachable, the others still respond — a single failing target doesn't take down the whole catalog.

Security and Governance​

Authentication​

Authentication for an MCP Gateway is whatever policy chain you attach to it — API Key, JWT, OAuth2, Basic, and so on — the same policies every other proxy type uses. There's no separate per-server auth-mode selector anymore; the proxy's own policy chain runs before a request ever reaches MCP handling. The one deliberate exception is server.json itself, which stays reachable without authentication — it only advertises the requirement (through remotes[].headers and _meta["com.apinizer"].auth/authRequired), it never enforces it; enforcement is always the policy chain's job. The exact client-side recipe — which header, which token endpoint, which curl flag — is derived per policy type and spelled out step by step in the Client Endpoints section.

Standard MCP Client Profile​

Standard MCP clients (for example MCP Inspector or Claude Code) find the authorization server by themselves. They read the protected resource metadata of the MCP server, read the metadata of the authorization server, get a token for this MCP resource and then call the tools. The Standard MCP OAuth profile makes the gateway work this way. The default profile is Legacy. It keeps the behavior of earlier versions.

You select the profile in the Routing Mode panel on the Routing tab (Configure → Client Authentication Profile). The screen shows the prerequisites and the reason for each problem. It does not refuse the save or the deploy when the authentication chain is not ready yet. You can select the profile first and add or finish the policy later. While the chain has a problem, the gateway does not publish the protected resource metadata, so MCP clients cannot sign in. The deploy still needs an access URL for the environment.

Upgrade all workers first

Upgrade all workers of the environment before you select the Standard profile. An older worker does not publish the protected resource metadata, and it accepts a standard token on a Legacy proxy.

Prerequisites​

  • The authentication chain of the proxy uses tokens from one authorization server: an OAuth2 or JWT policy with Manage From ACL (the Apinizer Credential AS), an OAuth2 or JWT policy with Manage From This Policy and the Browser login (authorization_code) switch on (the Apinizer /auth authorization server), or an OIDC policy (one identity provider).
  • The environment has an access URL. It defines the canonical resource.
  • In Expose Tools mode, the proxy has a service client, and each tool has a Downstream identity (see below).

The screen reports these problems:

ProblemMeaning
No active authentication policyAdd an OAuth2 or JWT policy with Manage From ACL, or an OIDC policy.
Policy issues proxy key tokens without browser loginTurn on the Browser login (authorization_code) switch in the policy, or select Manage From ACL.
OIDC policy without an issuerSet the issuer of the identity provider.
OIDC policy does not accept a Bearer tokenTurn on Bearer JWT authentication in the policy.
OIDC policy does not verify the JWT signatureTurn on local JWT validation and signature validation (JWKS).
Policy asks for a credential that is not a tokenRemove the policy (Basic, API key, Digest, mTLS, SAML or JOSE policies, for example).
Tokens from more than one authorization serverKeep only one.
A JWT policy and an OAuth2 policy in the same chainKeep only one.

The chain is read from the policies of the proxy itself. A proxy group policy runs only for a request that comes through the group path.

Canonical resource​

The canonical resource is the environment access URL, the Apinizer root context and the proxy path, without a trailing slash. The gateway builds it from the configuration. It never uses the Host or X-Forwarded-* headers of a request. Tokens are issued for this value and are accepted only with this value in aud.

Protected resource metadata​

The gateway publishes the document (RFC 9728) without authentication at the proxy path plus /.well-known/oauth-protected-resource. It contains the resource, the one authorization server (authorization_servers), the scopes that clients can ask for (scopes_supported) and bearer_methods_supported (header). The gateway publishes it only when the authentication chain accepts the Bearer token of a single authorization server and the Standard profile fits the chain. When the gateway has nothing true to publish, the address answers 404. This includes a chain that still has a problem from the table above. Check the prerequisites panel on the Routing tab. A Legacy proxy does not publish it, and the request goes through the normal authentication chain.

The document is under the proxy path only. If you need the address in the RFC 9728 "path insertion" form, the ingress must provide it. A browser-based client such as MCP Inspector needs the CORS settings of the proxy to be open.

The gateway answers an unauthorized request with a standard WWW-Authenticate header that names this document:

SituationAnswer
No token401 with Bearer resource_metadata="…".
Invalid token401 with error="invalid_token" and resource_metadata.
A tool needs a scope the token does not have (Expose Tools)403 with error="insufficient_scope", the scope the client can ask for, and resource_metadata.

Authorization server metadata​

  • Apinizer Credential AS (Manage From ACL). The issuer is <access URL>/credential. The canonical metadata (RFC 8414) is at https://<host>/.well-known/oauth-authorization-server/credential. The older /credential/.well-known/openid-configuration and /credential/.well-known/oauth-authorization-server addresses keep working. The metadata lists the token endpoint, the keys, introspection and revocation, the client_credentials and token exchange grants, and the client authentication methods. The issuer comes from the configured access URL, and it is equal to the authorization_servers value of the protected resource metadata. When the access URL of the environment is defined, the metadata also advertises authorization_endpoint, the authorization_code grant, PKCE S256 and the none client authentication method.
  • Apinizer /auth authorization server (Manage From This Policy). When the Browser login (authorization_code) switch is on in the policy, the issuer is <access URL>/auth. The canonical metadata is at https://<host>/.well-known/oauth-authorization-server/auth. The older /auth/.well-known/oauth-authorization-server address keeps working. When the switch is off, the proxy cannot use the Standard profile. The screen reports this.
  • Identity provider. The identity provider publishes its own metadata. The policy issuer is the address that the protected resource metadata names.

Getting a token​

  • Machine to machine (Credential AS). The client sends a client_credentials request to /credential/token with one resource parameter (RFC 8707) that equals the canonical resource of the proxy. The token is for this resource only (aud). Its format (JWT or opaque) follows the policy of the proxy. This request gets no refresh token. A request without resource, with another grant type or with an unknown resource works as before and gives a legacy token. The Standard proxy refuses a legacy token, and a Legacy proxy refuses a standard token.
  • Browser login (Apinizer authorization server). The client follows the authorization code + PKCE flow with a public API client. The authorize and token endpoints are under /credential in Manage From ACL mode and under /auth in Manage From This Policy mode. resource is required and must equal the canonical resource of the proxy. The aud of the access token is this resource. If it is a JWT, its header has typ: at+jwt. The refresh token rotates on every use, and the replay of a used refresh token revokes the token family. The access of the user and the access of the application are both required: access of the user ∩ access of the application. For the setup, the limits and the check with curl, see MCP Gateway Browser Sign-In Without Keycloak.
  • Identity provider. The client registers with the identity provider and gets a token there. The aud claim of the token must contain the canonical resource. Some identity providers ignore the resource parameter. For example, Keycloak needs an Audience mapper that adds the canonical resource to aud. The gateway verifies the JWT locally with the keys (JWKS) of the provider. It reads the token only from the Authorization header. It does not accept an opaque token from the provider. The gateway does not read roles from the scope claim, and it does not read an array in scp.
Note

Client ID metadata documents (CIMD) and dynamic client registration (DCR) are not in this release. The metadata does not advertise them (client_id_metadata_document_supported is absent), and a client_id in the form of an https URL is refused as an unregistered client (invalid_client). With an identity provider, the provider registers the client. At the Apinizer authorization server, the client is an API client that you create beforehand: a confidential client for a machine client, and a public client for browser login.

Scopes and tool access​

In the Standard profile, the scope in the token is a wire scope. A role gets its wire scope in its OAuth Scope Name field. A client asks for the scope name, not for the role name. A caller can use a tool only when both are true: the token contains the wire scope of the role that the tool needs, and the user holds that role now. A role without an OAuth scope name opens no tool. The scope name must be unique among the roles that a client of the project can hold. The Identity Access Rules apply in addition.

Calls to the tool target​

In the Standard profile, the gateway does not pass the Authorization header of the caller to the target of an Expose Tools tool. It creates the token for the target itself. You set this for each tool in Downstream identity:

  • Service. The gateway calls the target as the service client of the proxy. The user is recorded only for audit.
  • Delegated user. The gateway calls the target as the signed-in user, acting through the service client. The call carries both. The target must accept delegated tokens, and the service client must be in its Allowed agents list. The gateway uses the token exchange grant of the Credential AS in-process. See Token Exchange. A user from an identity provider is delegated only when the provider maps the user to an existing API client. Otherwise the call is refused.

A tool argument or a client header cannot set the identity of the call: the gateway removes the Authorization value of the caller and any argument that is defined as a header.

User context in logs and limits​

For a Standard profile call, the traffic log carries the user and the client of the token:

Log fieldValue
usubThe stable user ID: the sub of an identity provider token. For a Credential AS client_credentials token, the client itself. For a browser-login token, the username of the signed-in user (in Manage From ACL mode, the username of the consumer).
uidsThe identity source: the issuer of an identity provider token, apinizer for a Credential AS token and for a browser-login token from Manage From ACL mode (/credential), or apinizer-policy for a browser-login token from Manage From This Policy mode (/auth).
ocidThe OAuth client that got the token (azp, else client_id).

The result class of a tool call (mcprc) is separate. See Logging and Analytics. A Limit Plan can use the OAuth client with the context value OAuth Client ID (standard MCP token). The user stays the authenticated identity, so the user chain of the Limit Plan works as for other proxies.

In the Standard profile, the prerequisites panel on the Routing tab shows the canonical resource, the authorization server (issuer) and the Browser login (authorization_code) row. The row reports one of three states: on (users of the identity source of the policy sign in on the login page), available (you turn it on in the API client of each application), or not offered by this authorization server.

Step-by-step examples: MCP Gateway Sign-In with Keycloak (external identity provider) and MCP Gateway Browser Sign-In Without Keycloak (Apinizer authorization server).

Identity-Based Access Control​

Optionally, restrict tool visibility by the caller's consumer or API client, role, or organization. The rules apply in both modes. In Expose Tools mode a caller must also pass the tool's own required-scope check (see Expose Tools). Each rule allows or denies specific tool names for the principal it matches; once at least one rule is configured, a caller not covered by any rule sees nothing in the tool list (default-deny) and can't call any tool either. A name in a deny list always wins. You set the rules in the Identity Access Rules drawer on the Routing tab, or through the Management REST API:

{
"identityAcl": [
{
"principalType": "ROLE",
"principalName": "partner-readonly",
"allow": ["search", "fetch"],
"deny": []
}
]
}

Argument Constraints​

Attach validation rules to a tool's arguments. The gateway checks the rules before it sends the call, and it rejects the call when a rule fails.

You set the rules on the Routing tab:

  • Expose Tools: open the tool in the tool drawer and use its Argument constraints editor.
  • Passthrough: use the Argument constraints panel. Add a tool and enter its name exactly as tools/list shows it. The match is case-sensitive. A tool that two servers use appears as server__tool.

Each rule has an Argument path, a Rule type and a Value:

RuleValueThe call is rejected when
Regex (full match)A regular expressionThe argument does not match the whole expression.
Maximum lengthA whole number, 0 or greaterThe text of the argument is longer.
Allowed valuesValues separated by commasThe argument is not one of the values.
RequiredNoneThe argument is missing.
  • The argument path is a list of property names separated by dots, for example user.email. Array indexes (items.0.name) and wildcards (*) are not supported.
  • Regex, maximum length and allowed values check an argument only when it is present. Add a Required rule to make an argument mandatory.
  • The gateway skips a saved rule that is not valid (an empty path, a regular expression that does not compile) and does not block the traffic. The screen does not save such a rule, so you see the problem before the save. Environment variables (${var}) are resolved at run time and are not checked on the screen.
  • Regular-expression rules run under a hard ceiling (a 4096-character input cap and a 200ms evaluation deadline) so a crafted value can't turn a rule into a denial-of-service vector.

The same rules are available as JSON in the Management REST API:

{
"argumentConstraints": [
{
"toolName": "search",
"rules": [
{ "argumentPath": "query", "ruleType": "MAX_LENGTH", "value": "500" },
{ "argumentPath": "region", "ruleType": "ENUM", "value": "eu,us,apac" }
]
}
]
}

Limiting Tool Call Volume​

The MCP routing has no call quota of its own. You limit call volume in two places, and each place has one job:

  • Limits for an identity (per consumer, API client, application or organization) — set them in a Limit Plan.
  • Protection of the proxy (the total of all callers) — add the Quota or Throttling policy to the proxy.

Both can count MCP tool calls separately for each tool. Select the context value MCP Tool Name (tools/call) as the counting variable. It is the canonical tool name, the same name that the gateway uses to run the call, so my_tool, MY_TOOL and my-tool use one counter. Do not read $.params.name from the request body for this. The body holds the name as the client wrote it, and each spelling then gets its own counter.

A callQuota value saved by an earlier version is ignored, and the next save of the routing removes it.

Tool Risk Policy and Approval​

The tool risk policy gives every tool call a risk tier and sets what the gateway does for each tier. It works in both modes and is off by default. While it is off, every call is allowed and no tier is computed.

Risk tiers​

A tool gets one of three tiers: Low, Medium or High. The gateway takes the first rule that matches:

  1. Your setting. In Expose Tools mode, the Risk tier field of the tool. In Passthrough mode, a row in Tool risk tiers for the tool name as tools/list shows it.
  2. Trusted tool annotations. When Trust tool annotations is on for the backend server: a read-only tool is Low, a destructive tool is High, and any other tool is Medium.
  3. Untrusted tool annotations. When Trust tool annotations is off (the default), the annotations can only raise the tier. A destructive tool is High. A read-only mark does not lower the tier. When a tool is marked both read-only and destructive, it is High.
  4. Default. In Expose Tools mode, the HTTP method of the operation: GET and HEAD are Low, DELETE is High and other methods are Medium. In Passthrough mode, Medium.

A tool without annotations keeps the default tier. Turn Trust tool annotations on only for a server that you control.

Actions​

For each tier, you choose one of three actions:

ActionWhat the gateway does
AllowThe call goes on.
Require approvalThe call waits until a manager approves it.
DenyThe gateway rejects the call.

When you turn the policy on, the screen starts with Low = Allow, Medium = Allow and High = Require approval. You can change each one.

Exemptions are identity rules (consumer or API client, role or organization). For a matching caller, Require approval becomes Allow. Deny does not change. The exemption checks only the identity, so it applies to every tool.

The risk check runs after the scope and identity rules, and the argument constraints, and just before the call is sent.

Approval flow​

  1. The call needs approval. The gateway writes an approval request and answers the client at once:
    • A client that declared the Tasks extension gets a task in the state "waiting for approval".
    • Any other client gets the error -32021 with an approvalId (ERR-309).
  2. A manager approves or rejects the request in Pending tool approvals (see below).
  3. After the approval, the client reads the task with tasks/get, or sends the same call again. The gateway then runs the call one time. Nothing runs the call by itself.
  4. A new attempt of the same call before the decision does not create a second request. The same caller can hold at most 20 open approval requests on one proxy. A further call is refused.

Rules for the approval:

  • 15 minutes. The request is valid for 15 minutes from the moment of the request. The decision and the single run must both happen in that time. After that the request expires.
  • Rejected. For 15 minutes after the rejection, the same call is refused with a policy error. After that, a new attempt creates a new request.
  • Bound to the call. The approval belongs to the caller, the client, the proxy, the tool and the exact arguments. It also belongs to the operation that the tool resolves to: in Expose Tools mode the target proxy, the HTTP method and the path; in Passthrough mode the backend server and its tool name. If any of these has changed when the call runs, the gateway does not run it, and the task fails.
  • Checked again at run time. The gateway checks the scope, the identity rules and the risk policy again when it runs the approved call. A policy that now denies the tool stops the call.
  • Not an approval. An answer to an elicitation or the opening of a link is never an approval. Only a manager in the Manager makes the decision.
  • Anonymous proxies. When the proxy has no authentication, the gateway cannot tie the approval to an identity. Every call with the same arguments uses the same approval. Use the risk policy with an authentication policy.

Pending tool approvals​

The Pending tool approvals panel on the Routing tab lists the requests that wait for a decision. It shows the tool, the risk tier, the caller, the client ID, the operation (a summary of the resolved target), the request time and the expiry time. Select Approve or Reject and confirm.

  • The panel shows the operation summary and the tool. It does not show the argument values.
  • You need the manage permission of AI development or API management in the project.
  • The approval and rejection decisions made in the Manager are written to the audit log.
  • The gateway records the other outcomes (a policy rejection, an expired request, a changed target or arguments) in the state of the task record, in the Tool approval field of the traffic log, and in a warning line of the gateway log. These outcomes are not in the audit log.

Traffic log and alarms​

  • The traffic detail of a call shows Tool approval with the state: Pending, Approved, Rejected or Expired. The same value is a log field named mcpap. The Elasticsearch template carries it after the upgrade.
  • Two alarm trigger types watch the approvals: MCP Tool Approval Pending Count (the requests that wait now) and MCP Tool Approval Rejected Count (the rejections of the last hour). Both use the Project scope. See Alarms.

Catalog Drift Protection​

Each inline MCP server remembers a fingerprint of its tool catalog captured at the moment it was last approved (an explicit Discover / Reparse, or the first discovery at deploy — see Catalog Discovery at Deploy). A periodic health check compares the live catalog against that fingerprint; when they diverge, the server either just logs and surfaces the drift (the default) or blocks every tool call through it until an operator re-approves the new catalog. This guards against a backend server silently changing what a tool does, or what it expects, underneath an already-approved integration.

Catalog Discovery at Deploy​

An inline MCP server of an MCP Call (LLM) or MCP Call (Fixed) policy that has no tool catalog and no approved fingerprint yet gets its first catalog when you deploy the proxy.

  • On deploy, the Manager asks the server for its tool list once, before the worker receives the proxy.
  • All probes of one deploy run in parallel. One total time limit of 30 seconds applies to the whole deploy.
  • A successful first result is saved as the tool catalog and becomes the approved baseline. Later changes are checked against it (see above).
  • A server that already has a catalog or an approved fingerprint is not probed again. A drift that was detected is not approved by a deploy.
  • A server that returns no tools, cannot be reached, or does not answer within 30 seconds does not stop the deploy. The deploy result shows a WARNING line for it, and its tool calls stay refused until a catalog is discovered. Use Discover / Reparse Tools and deploy again.
  • A server whose authentication scheme is OAuth2 token exchange is not probed at deploy. There is no caller token at deploy time, and the scheduled health check skips it for the same reason. The same applies to an inline A2A agent with this scheme. No WARNING line is written for it. Use Discover / Reparse Tools to get its tool catalog.
  • The servers in the Routing tab of a Passthrough proxy are not probed at deploy.

Token Passthrough​

By default, Apinizer never forwards a caller's own token to a backend MCP server. The gateway credential on the server row is used instead. In a zero-trust setup, the backend MCP server must authorize the real caller. For this, turn on caller forwarding in Passthrough mode.

Forward client token to backend server (Routing tab → Backend MCP Server → Client Access & Forwarding → Configure):

  • When on, the caller's Authorization: Bearer token goes to the backend MCP server on every call: initialize, tools/list and tools/call. The gateway credential of the server row is not sent.
  • Accepted token audiences is optional. When filled, only a JWT whose aud claim matches an entry is forwarded. We recommend it: it makes sure a token issued for this MCP server reaches only this MCP server (RFC 8707 resource indicators).
  • When no token can be forwarded (the caller sent none, or the audience did not match), the gateway credential of the server row is used. The call is never sent without authentication.

Forwarded client headers (Routing tab → Backend MCP Server → Client Access & Forwarding → Configure):

  • The gateway copies the listed headers from the client request to the backend MCP server on every call, for example app-identifier or x-tenant-id. Names are case-insensitive.
  • A header the client does not send is not forwarded. Header forwarding works with or without token forwarding.
  • These headers cannot be forwarded: Authorization, Proxy-Authorization, Host, Connection, Keep-Alive, Transfer-Encoding, TE, Trailer, Upgrade, Content-Length, Content-Type, Content-Encoding, Accept, Accept-Encoding, Mcp-Session-Id, MCP-Protocol-Version. Use token forwarding for the caller token. The list can hold at most 20 headers.
  • A header value with a line break, or longer than 8 KB, is not forwarded.

Required headers. Select Required on a header row to make the header mandatory:

  • The gateway checks every JSON-RPC request in Passthrough mode: initialize, tools/list, tools/call and other methods. The discovery document and the SSE endpoint are not checked.
  • When a required header is missing, the gateway does not call the backend MCP server. It returns HTTP 400 with Content-Type: application/json. A blank header value counts as missing. When more than one required header is missing, the first one in the table is reported.
  • The traffic log shows the request as Blocked.
  • The check works with or without token forwarding. A present header is still forwarded.

The Error message column shows Default or Custom. Select the edit icon to change the response body. The body must be valid JSON. Reset to default restores the default body:

{"jsonrpc":"2.0","id":{{jsonRpcId}},"error":{"code":-32600,"message":"Missing required header: {{headerName}}"}}

You can use two placeholders in the body:

  • {{headerName}} — the header name as configured.
  • {{jsonRpcId}} — the id of the JSON-RPC request, written as JSON. A number stays a number, a string gets quotes, and a missing id becomes null. Do not put this placeholder in quotes.

With forwarding on, the tool list cache is kept per caller. One caller's tool list is never returned to another caller.

Note

Fetch tools on the server row uses the gateway credential of the row. When client token forwarding is on and the row has no credential (Authentication Scheme = None), the row shows Client token required instead of fetching: the tool list appears when a client calls the gateway with its own token. Test such a server with a real client call.

Guardrail Policies​

Five of Apinizer's Advanced Guardrails — Personal Data Masking, Prompt Protection, Data-Loss Protection (DLP), Off-Topic Protection, and Retry-Storm (Loop) Protection — can be attached to an MCP Gateway the same way as on any other proxy type. They run through the proxy's regular policy chain and scan the JSON-RPC tool-call arguments (params.arguments) on the request side and the tool result content on the response side. This is a separate mechanism from the built-in output filtering described above (deny-pattern matching and PII masking on tool results) — a guardrail policy is configured, scoped, and reported on independently. Two of these five — Prompt Protection and Off-Topic Protection — can additionally call out to an external LLM judge for a second opinion, the same way they do on an LLM Gateway. The remaining AI policy types (Semantic Cache, Token Rate Limit, Prompt Decorator, Prompt Templates, RAG Injection, Context-Integrity Protection) depend on an actual LLM invocation and are rejected if you try to attach them to an MCP Gateway; see Advanced Guardrails: MCP and A2A Gateways.

Egress Protection​

Danger

Outbound MCP calls — discovery, tool calls, the OAuth2 token endpoint, and health probes — accept only https and refuse every private or reserved address (loopback, link-local, cloud metadata, carrier-grade-NAT, multicast, RFC1918, IPv6 ULA) by default.

The per-server setting Allow private-network egress lifts this. When it is on, no address class is blocked — loopback, link-local, the cloud metadata address 169.254.169.254, 100.64.0.0/10, 0.0.0.0/8, multicast, RFC1918 and IPv6 ULA are all reachable, and plain http is allowed. Turning it on also opens the cloud metadata address, so enable it only for servers you trust.

Even with it on, only http and https URLs are accepted, the URL must be valid, the host must resolve, and the connection is pinned to the resolved addresses (DNS rebinding defence).

This same protection is shared with A2A Gateway outbound calls.

Environment Variables in Configuration​

Most of the text you type into an MCP Gateway's configuration accepts an environment variable reference in ${VARIABLE_NAME} form, resolved per environment when the proxy runs. That lets one configuration move from test to production without editing it — a tool that is named differently in each environment, an allowed-audience value, or a per-environment scope name is written once as a variable.

Fields that accept a variable:

WhereFields
Outbound tool callTool name, arguments template
Access rulesAllowed tool list, identity rule consumer/role/organization name, allow and deny lists
Argument constraintsArgument path and rule value
Exposed toolsRequired scopes
Token passthroughAccepted audience list

The arguments template additionally accepts #{...} context variables, which are evaluated per request after the environment variables have been substituted.

Caution

Resolution is fail-closed. If a variable is not defined in the environment the proxy is running in, the text stays as written — and because no real tool, scope, or audience is literally named ${VARIABLE_NAME}, the call is denied rather than falling through to an unintended match. A caller cannot send the literal text ${VARIABLE_NAME} as a tool name to slip past an access rule either; such a request is rejected outright.

Note

Tool detection patterns and output deny-patterns do not accept variables. Those are regular expressions, and Apinizer probes each one at save time for patterns that could stall the gateway. A pattern arriving from an environment variable would reach the engine unprobed, so the check that protects you would be the thing disabled. The same reasoning applies to a manually overridden tool input schema, which is validated when you save it.

Logging and Analytics​

Every MCP call is recorded in your traffic logs with the request's correlation ID, so a single agent turn can be followed end to end; an inbound gateway request additionally records the tool name and JSON-RPC id. Full per-call detail for an outbound tool call — which server it resolved to, every tool invoked in a batch, and each call's duration and outcome — is captured in the request's trace execution detail rather than as flat log columns, so a multi-turn agentic exchange doesn't collapse into "whatever the last turn did." These calls also appear in trace groups alongside the rest of a request's chain, and roll up into your usage reports.

An MCP Gateway's own detail page carries this same trace/traffic/analytics view under its Trace, Traffic, and Analytics tabs — so you don't have to leave the proxy to inspect its recent calls or trends.

On the Traffic tab — and the general API Traffic list — selecting Detailed View for an MCP call opens the same right-side drawer used for LLM Gateway calls, instead of a separate dialog. The drawer's last tab is named for whatever the call actually carries: when the record includes AI usage data, that tab appears as LLM Insights; otherwise it takes the name MCP Details (or A2A Details for A2A traffic) and shows the tool name, the JSON-RPC id, the outbound tool names/call count recorded for that request, and — for a call that the tool risk policy held for approval — the Tool approval state. If a call carries neither AI usage data nor any of these audit fields — a discovery request, for example — this last tab doesn't appear at all. REST, SOAP, and every other proxy type keep opening their call detail in the original dialog.

An inbound MCP tools/call row now carries the address it was routed to in the Routing column — the source API Proxy path reached through the gateway in Expose Tools mode, or the MCP server host:port in Passthrough mode — tagged with a tool call badge in place of the generic direct badge. Every JSON-RPC refusal the gateway returns for a call (HTTP 200 with a JSON-RPC error body, as the MCP spec requires) is also classified for the traffic list: client/policy refusals — an unknown tool, an insufficient scope, an argument-rule violation, or an output-filter block — are recorded as Blocked, while gateway/backend faults — an unavailable tool backend proxy, a failed tool execution, or a session limit — are recorded as Error, with the error type kept alongside. The row's Routing badge reads refused at gateway or gateway error to match. This means a refused call shows up under the traffic list's Blocked/Error filters and in analytics like any other refused request, even though the HTTP status code returned to the client stays 200. See Routing Status Badges for the full badge list.

The same rule now extends to every MCP call the gateway answers itself, not just tools/call: an initialize, tools/list, or ping handled in Expose Tools mode shows the proxy's own MCP endpoint URL in the Routing column instead of an empty address. In Passthrough mode, tools/list is a real call to the backend MCP server — live discovery, not a cached list — so its row shows the target MCP server's endpoint URL (with any query string and embedded credentials stripped before logging), the same way a Passthrough tools/call does.

The new MCP log fields are mcpap (tool approval state), usub, uids and ocid (user context of the Standard profile) and mcprc (result class of a tool call: OK, TOOL_ERROR, JSONRPC_ERROR, TRANSPORT or POLICY_REJECT). The Elasticsearch, MongoDB, GELF and JSON log connectors write them. The column list of the SQL/JDBC traffic-log connector does not change in this release, so these fields are not stored there.

Outbound Tool Names: an Audit Trail Independent of Trace​

Which outbound tool(s) a request tried to reach is also recorded on the main traffic log row itself, regardless of whether trace is on or off — unlike the rich per-call detail above, this record never disappears just because trace is disabled (the default). Every outbound tool call dispatched during the request is tracked through two fields:

  • A deduplicated name list — repeated tool names within the same request are kept once, in first-seen order, comma-separated; capped at 256 characters, and a name is never cut mid-string — a name that would no longer fit is dropped whole and the truncation is marked with ,… (never a silent cut).
  • A raw call counter — the total number of outbound tool calls dispatched during the request, duplicates included; this stays accurate even when the name list above had to be capped.
Rejected calls are recorded too

This audit trail also includes tool calls that a guard or a quota rejected — its purpose is to answer "which tool was this trying to reach," not just to record the calls that succeeded; a rejected call is at least as interesting from a security standpoint as a successful one.

Elasticsearch and MongoDB traffic-log connectors carry these fields automatically. If your installation uses the SQL/JDBC traffic-log connector, see 2026.09.0 — Log Table Update Scripts.

Migrating from the Previous Model​

  • The separate MCP "Inbound Server" screen is gone; MCP is now configured directly on an MCP Gateway's Routing tab.
  • Per-server authentication mode (None / API Key / OAuth2) no longer exists — authentication is whatever policy chain you attach to the proxy, the same as any other proxy type.
  • The old dedicated inbound path is gone; clients must be repointed at the MCP Gateway's own client path.
  • Existing inbound server definitions aren't carried forward automatically — recreate your exposed tool list as an MCP Gateway.
  • Outbound MCP connections are no longer a standalone, shared resource. The connection screen is gone; an MCP server is now defined inline, directly on a Passthrough proxy's Routing tab or inside the MCP Call (LLM) / MCP Call (Fixed) policy that uses it (see MCP Servers Are Configured Inline). This is auto-migrated on upgrade: any proxy or policy that referenced an outbound MCP connection under the old model gets that connection copied inline automatically — there's nothing to recreate. If the same connection was shared by more than one proxy or policy, each one ends up with its own independent copy (credential included) after the upgrade; keep that in mind when you next rotate the credential. Discovery, health probing, catalog drift protection, and token passthrough all still work the same way; they're just scoped to the server's own definition instead of a shared record.

Export/Import​

Like any other proxy type, an MCP Gateway exports and imports through the Export/Import Wizard as an API Proxy. When it exposes another API Proxy's endpoints as tools (Expose Tools mode), that source proxy surfaces as its own dependency, labeled MCP Source API Proxies, and on import is either mapped to its counterpart in the target project or created from the copy carried in the package. See Export Import for the resolution order and the errors that can come back.

Next Steps​