This page walks through installing the Plugin on Kong Gateway, then configuring it on a route in two common patterns: governing MCP tool calls, and authorizing and masking a REST API response.
The PlainID Integration (plainid-authz) installs once on Kong Gateway and then applies per route, so you can bring MCP servers and REST APIs under the same Policies without changing either upstream service. Because the Plugin reads Policies from PlainID at request time, you can adjust who can call what, or what they see back, without continuously managing your Kong configuration.
Prerequisites
Before you start, ensure you have:
- Kong Gateway 3.15 or later, either self-hosted or on Konnect.
- A PlainID PDP endpoint and a Client ID. If you plan to use masking, you also need a Client Secret.
- If you plan to use masking, Download the JSON Filtering Authorizer container from the Platform. See the Managing the JSON Filtering Authorizer documentation for more information.
Install the Plugin
You can install plainid-authz in either of the following ways:
Adding it to Your Kong image
To add it to your Kong image:
- Copy the plugin into your Kong image and enable it through
KONG_PLUGINS:
FROM kong/kong-gateway:3.15
USER root
COPY plainid-authz /usr/local/share/lua/5.1/kong/plugins/plainid-authz
USER kong
ENV KONG_PLUGINS=bundled,plainid-authz
- Build and run the image:
docker build -t kong-plainid:latest .
docker run -d --name kong \
-e KONG_PLUGINS=bundled,plainid-authz \
-p 8000:8000 kong-plainid:latest
A Helm chart or a lua_package_path directory works the same way, if you deploy Kong that way instead.
Registering the Plugin Schema on Konnect
If managing Kong through Konnect, register the plugin once at the control plane level:
- Open Gateway Manager and select your control plane.
- Go to Plugins > Custom Plugins.
- Select + New Custom Plugin.
- Upload
schema.lua.
After the plugin is installed or registered, you configure it per route.
See Kong Konnect's documentation for more information.
Govern MCP tool calls
This example puts three plugins on a route in front of an MCP server, so that each one handles a distinct step:
- Verifying who is calling,
- Deciding what they can do
- Swapping in the credential the upstream service expects.
Code Example:
services:
- name: snowflake-mcp
url: https://<account>.snowflakecomputing.com/api/v2/.../mcp-servers/<server>
routes:
- name: snowflake
paths: [/snowflake]
plugins:
# 1. Validate the caller's token.
- name: ai-mcp-oauth2
config:
authorization_servers: [https://<your-idp>/v2.0]
passthrough_credentials: true
# 2. Ask PlainID which tools this caller may use.
- name: plainid-authz
config:
plainid_url: https://<pdp-host>/api
client_id: <your-client-id>
authentication_method: token
mcp_resource_type: MCP-TOOL
# 3. Replace the caller's token with the upstream's credential.
- name: request-transformer
config:
replace:
headers:
- Authorization:Bearer <snowflake-token>
With this configuration, Kong Gateway checks each tool call against PlainID before it reaches the MCP server. An Agent querying the server only sees the tools its Policies allow. If the Agent tries to call a tool it isn't authorized to use, Kong Gateway blocks the call and returns an error, and the request never reaches the upstream server.
Authorize and Mask a REST API response
This example uses plainid-authz on its own to authorize each call and mask fields in the response.
services:
- name: cases-api
url: https://<your-api-host>
routes:
- name: cases
paths: [/cases]
plugins:
- name: plainid-authz
config:
plainid_url: https://<pdp-host>/api
client_id: <your-client-id>
client_secret: <your-client-secret>
# PlainID resolves the identity from the caller's own token.
token_forward_headers: [Authorization]
# Mask fields in permitted responses.
masking_enabled: true
masking_url: http://<authorizer-host>:5002
masking_asset_type: <your-asset-type>
Your API returns its usual response, unchanged:
{ "data": { "cases": [
{ "caseId": "acc123", "caseType": "Business",
"contactDetails": { "contactName": "John Doe", "contactDoB": "1974-11-09" } }
] } }
plainid-authz masks fields per Policy before Kong Gateway returns the response, so different callers can receive different values for the same request:
{ "data": { "cases": [
{ "caseId": "acc123", "caseType": "Business",
"contactDetails": { "contactName": "*****", "contactDoB": "1974-11-09" } }
] } }
Array order and object structure stay the same. Only the field values change, so existing clients continue to parse the response normally.
Use masking_root to scope masking to a specific part of the response body if you only want part of the document to go through the Authorizer.
Configuration reference
| Key | Description |
|---|---|
plainid_url |
The URL of your PlainID PDP endpoint. |
client_id |
The client ID PlainID issued for this integration. |
client_secret |
The client secret for this integration. Required when masking_enabled is true. |
authentication_method |
How the Plugin authenticates to PlainID, for example token. |
mcp_resource_type |
The resource type PlainID uses to evaluate MCP tool calls, for example MCP-TOOL. |
token_forward_headers |
Which incoming headers the Plugin forwards to PlainID so it can resolve the caller's identity. |
masking_enabled |
Turns on response masking for this route. |
masking_url |
The URL of your JSON Filtering Authorizer instance. |
masking_asset_type |
The Asset Type PlainID uses to evaluate masking Policies for this route. |
masking_root |
Optional. Limits masking to a specific part of the response body. |