Configure default and per-tool access control for passthrough-listener mode MCP servers
Configure default and per-tool access control for passthrough-listener mode MCP servers.
For this configuration to work properly, you need to create the following Kong Gateway entities:
services: - name: mcp-acl-service url: http://host.docker.internal:3001/mcp routes: - name: mcp-acl-route paths: - "/mcp" service: name: mcp-acl-service plugins: - name: key-auth config: key_names: - apikey consumer_groups: - name: admin - name: developer - name: suspended consumers: - username: alice groups: - name: admin keyauth_credentials: - key: alice-key - username: bob groups: - name: developer keyauth_credentials: - key: bob-key - username: carol groups: - name: suspended keyauth_credentials: - key: carol-key - username: eason keyauth_credentials: - key: eason-keyCopied!
Before using the AI MCP Proxy plugin, you’ll need an upstream HTTP API to expose.
Use this mock API to test the plugin without relying on an external service. It simulates a small marketplace with sample users and orders exposed through /marketplace/users and /marketplace/{userId}/orders endpoints:
git clone https://github.com/tomek-labuk/marketplace-acl.git && \
cd marketplace-acl && \
npm install && \
npm run build && \
node dist/server.js
Check this how-to for a detailed walkthrough guide.
Prerequisites
- A running and exposed API
Add this section to your kong.yaml configuration file:
_format_version: "3.0"
plugins:
- name: ai-mcp-proxy
config:
mode: passthrough-listener
include_consumer_groups: true
default_acl:
- scope: tools
allow:
- developer
- admin
deny:
- suspended
logging:
log_payloads: false
log_statistics: true
log_audits: true
tools:
- description: List users
name: list_users
acl:
allow:
- admin
- eason
deny:
- developer
- description: Get user
name: get_user
acl:
allow:
- admin
- developer
- description: List orders
name: list_orders
acl:
allow:
- admin
- developer
- description: List orders for users
name: list_orders_for_user
acl:
allow:
- admin
- developer
- description: Search orders by name (case-insensitive substring)
name: search_orders
acl:
allow:
- admin
deny:
- developer
Make the following request:
curl -i -X POST http://localhost:8001/plugins/ \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '
{
"name": "ai-mcp-proxy",
"config": {
"mode": "passthrough-listener",
"include_consumer_groups": true,
"default_acl": [
{
"scope": "tools",
"allow": [
"developer",
"admin"
],
"deny": [
"suspended"
]
}
],
"logging": {
"log_payloads": false,
"log_statistics": true,
"log_audits": true
},
"tools": [
{
"description": "List users",
"name": "list_users",
"acl": {
"allow": [
"admin",
"eason"
],
"deny": [
"developer"
]
}
},
{
"description": "Get user",
"name": "get_user",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "List orders",
"name": "list_orders",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "List orders for users",
"name": "list_orders_for_user",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "Search orders by name (case-insensitive substring)",
"name": "search_orders",
"acl": {
"allow": [
"admin"
],
"deny": [
"developer"
]
}
}
]
},
"tags": []
}
'
Make the following request:
curl -X POST https://{region}.api.konghq.com/v2/control-planes/{controlPlaneId}/core-entities/plugins/ \
--header "accept: application/json" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer $KONNECT_TOKEN" \
--data '
{
"name": "ai-mcp-proxy",
"config": {
"mode": "passthrough-listener",
"include_consumer_groups": true,
"default_acl": [
{
"scope": "tools",
"allow": [
"developer",
"admin"
],
"deny": [
"suspended"
]
}
],
"logging": {
"log_payloads": false,
"log_statistics": true,
"log_audits": true
},
"tools": [
{
"description": "List users",
"name": "list_users",
"acl": {
"allow": [
"admin",
"eason"
],
"deny": [
"developer"
]
}
},
{
"description": "Get user",
"name": "get_user",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "List orders",
"name": "list_orders",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "List orders for users",
"name": "list_orders_for_user",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "Search orders by name (case-insensitive substring)",
"name": "search_orders",
"acl": {
"allow": [
"admin"
],
"deny": [
"developer"
]
}
}
]
},
"tags": []
}
'
Make sure to replace the following placeholders with your own values:
-
region: Geographic region where your Kong Konnect is hosted and operates. -
KONNECT_TOKEN: Your Personal Access Token (PAT) associated with your Konnect account. -
controlPlaneId: Theidof the control plane.
See the Konnect API reference to learn about region-specific URLs and personal access tokens.
echo "
apiVersion: configuration.konghq.com/v1
kind: KongClusterPlugin
metadata:
name: ai-mcp-proxy
namespace: kong
annotations:
kubernetes.io/ingress.class: kong
konghq.com/tags: ''
labels:
global: 'true'
config:
mode: passthrough-listener
include_consumer_groups: true
default_acl:
- scope: tools
allow:
- developer
- admin
deny:
- suspended
logging:
log_payloads: false
log_statistics: true
log_audits: true
tools:
- description: List users
name: list_users
acl:
allow:
- admin
- eason
deny:
- developer
- description: Get user
name: get_user
acl:
allow:
- admin
- developer
- description: List orders
name: list_orders
acl:
allow:
- admin
- developer
- description: List orders for users
name: list_orders_for_user
acl:
allow:
- admin
- developer
- description: Search orders by name (case-insensitive substring)
name: search_orders
acl:
allow:
- admin
deny:
- developer
plugin: ai-mcp-proxy
" | kubectl apply -f -
Prerequisite: Configure your Personal Access Token
terraform {
required_providers {
konnect = {
source = "kong/konnect"
}
}
}
provider "konnect" {
personal_access_token = "$KONNECT_TOKEN"
server_url = "https://us.api.konghq.com/"
}
Add the following to your Terraform configuration to create a Konnect Gateway Plugin:
resource "konnect_gateway_plugin_ai_mcp_proxy" "my_ai_mcp_proxy" {
enabled = true
config = {
mode = "passthrough-listener"
include_consumer_groups = true
default_acl = [
{
scope = "tools"
allow = ["developer", "admin"]
deny = ["suspended"]
} ]
logging = {
log_payloads = false
log_statistics = true
log_audits = true
}
tools = [
{
description = "List users"
name = "list_users"
acl = {
allow = ["admin", "eason"]
deny = ["developer"]
}
},
{
description = "Get user"
name = "get_user"
acl = {
allow = ["admin", "developer"]
}
},
{
description = "List orders"
name = "list_orders"
acl = {
allow = ["admin", "developer"]
}
},
{
description = "List orders for users"
name = "list_orders_for_user"
acl = {
allow = ["admin", "developer"]
}
},
{
description = "Search orders by name (case-insensitive substring)"
name = "search_orders"
acl = {
allow = ["admin"]
deny = ["developer"]
}
} ]
}
tags = []
control_plane_id = konnect_gateway_control_plane.my_konnect_cp.id
}
Add this section to your kong.yaml configuration file:
_format_version: "3.0"
plugins:
- name: ai-mcp-proxy
service: serviceName|Id
config:
mode: passthrough-listener
include_consumer_groups: true
default_acl:
- scope: tools
allow:
- developer
- admin
deny:
- suspended
logging:
log_payloads: false
log_statistics: true
log_audits: true
tools:
- description: List users
name: list_users
acl:
allow:
- admin
- eason
deny:
- developer
- description: Get user
name: get_user
acl:
allow:
- admin
- developer
- description: List orders
name: list_orders
acl:
allow:
- admin
- developer
- description: List orders for users
name: list_orders_for_user
acl:
allow:
- admin
- developer
- description: Search orders by name (case-insensitive substring)
name: search_orders
acl:
allow:
- admin
deny:
- developer
Make sure to replace the following placeholders with your own values:
-
serviceName|Id: Theidornameof the service the plugin configuration will target.
Make the following request:
curl -i -X POST http://localhost:8001/services/{serviceName|Id}/plugins/ \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '
{
"name": "ai-mcp-proxy",
"config": {
"mode": "passthrough-listener",
"include_consumer_groups": true,
"default_acl": [
{
"scope": "tools",
"allow": [
"developer",
"admin"
],
"deny": [
"suspended"
]
}
],
"logging": {
"log_payloads": false,
"log_statistics": true,
"log_audits": true
},
"tools": [
{
"description": "List users",
"name": "list_users",
"acl": {
"allow": [
"admin",
"eason"
],
"deny": [
"developer"
]
}
},
{
"description": "Get user",
"name": "get_user",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "List orders",
"name": "list_orders",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "List orders for users",
"name": "list_orders_for_user",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "Search orders by name (case-insensitive substring)",
"name": "search_orders",
"acl": {
"allow": [
"admin"
],
"deny": [
"developer"
]
}
}
]
},
"tags": []
}
'
Make sure to replace the following placeholders with your own values:
-
serviceName|Id: Theidornameof the service the plugin configuration will target.
Make the following request:
curl -X POST https://{region}.api.konghq.com/v2/control-planes/{controlPlaneId}/core-entities/services/{serviceId}/plugins/ \
--header "accept: application/json" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer $KONNECT_TOKEN" \
--data '
{
"name": "ai-mcp-proxy",
"config": {
"mode": "passthrough-listener",
"include_consumer_groups": true,
"default_acl": [
{
"scope": "tools",
"allow": [
"developer",
"admin"
],
"deny": [
"suspended"
]
}
],
"logging": {
"log_payloads": false,
"log_statistics": true,
"log_audits": true
},
"tools": [
{
"description": "List users",
"name": "list_users",
"acl": {
"allow": [
"admin",
"eason"
],
"deny": [
"developer"
]
}
},
{
"description": "Get user",
"name": "get_user",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "List orders",
"name": "list_orders",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "List orders for users",
"name": "list_orders_for_user",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "Search orders by name (case-insensitive substring)",
"name": "search_orders",
"acl": {
"allow": [
"admin"
],
"deny": [
"developer"
]
}
}
]
},
"tags": []
}
'
Make sure to replace the following placeholders with your own values:
-
region: Geographic region where your Kong Konnect is hosted and operates. -
KONNECT_TOKEN: Your Personal Access Token (PAT) associated with your Konnect account. -
controlPlaneId: Theidof the control plane. -
serviceId: Theidof the service the plugin configuration will target.
See the Konnect API reference to learn about region-specific URLs and personal access tokens.
echo "
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: ai-mcp-proxy
namespace: kong
annotations:
kubernetes.io/ingress.class: kong
konghq.com/tags: ''
config:
mode: passthrough-listener
include_consumer_groups: true
default_acl:
- scope: tools
allow:
- developer
- admin
deny:
- suspended
logging:
log_payloads: false
log_statistics: true
log_audits: true
tools:
- description: List users
name: list_users
acl:
allow:
- admin
- eason
deny:
- developer
- description: Get user
name: get_user
acl:
allow:
- admin
- developer
- description: List orders
name: list_orders
acl:
allow:
- admin
- developer
- description: List orders for users
name: list_orders_for_user
acl:
allow:
- admin
- developer
- description: Search orders by name (case-insensitive substring)
name: search_orders
acl:
allow:
- admin
deny:
- developer
plugin: ai-mcp-proxy
" | kubectl apply -f -
Next, apply the KongPlugin resource by annotating the service resource:
kubectl annotate -n kong service SERVICE_NAME konghq.com/plugins=ai-mcp-proxy
Prerequisite: Configure your Personal Access Token
terraform {
required_providers {
konnect = {
source = "kong/konnect"
}
}
}
provider "konnect" {
personal_access_token = "$KONNECT_TOKEN"
server_url = "https://us.api.konghq.com/"
}
Add the following to your Terraform configuration to create a Konnect Gateway Plugin:
resource "konnect_gateway_plugin_ai_mcp_proxy" "my_ai_mcp_proxy" {
enabled = true
config = {
mode = "passthrough-listener"
include_consumer_groups = true
default_acl = [
{
scope = "tools"
allow = ["developer", "admin"]
deny = ["suspended"]
} ]
logging = {
log_payloads = false
log_statistics = true
log_audits = true
}
tools = [
{
description = "List users"
name = "list_users"
acl = {
allow = ["admin", "eason"]
deny = ["developer"]
}
},
{
description = "Get user"
name = "get_user"
acl = {
allow = ["admin", "developer"]
}
},
{
description = "List orders"
name = "list_orders"
acl = {
allow = ["admin", "developer"]
}
},
{
description = "List orders for users"
name = "list_orders_for_user"
acl = {
allow = ["admin", "developer"]
}
},
{
description = "Search orders by name (case-insensitive substring)"
name = "search_orders"
acl = {
allow = ["admin"]
deny = ["developer"]
}
} ]
}
tags = []
control_plane_id = konnect_gateway_control_plane.my_konnect_cp.id
service = {
id = konnect_gateway_service.my_service.id
}
}
Add this section to your kong.yaml configuration file:
_format_version: "3.0"
plugins:
- name: ai-mcp-proxy
route: routeName|Id
config:
mode: passthrough-listener
include_consumer_groups: true
default_acl:
- scope: tools
allow:
- developer
- admin
deny:
- suspended
logging:
log_payloads: false
log_statistics: true
log_audits: true
tools:
- description: List users
name: list_users
acl:
allow:
- admin
- eason
deny:
- developer
- description: Get user
name: get_user
acl:
allow:
- admin
- developer
- description: List orders
name: list_orders
acl:
allow:
- admin
- developer
- description: List orders for users
name: list_orders_for_user
acl:
allow:
- admin
- developer
- description: Search orders by name (case-insensitive substring)
name: search_orders
acl:
allow:
- admin
deny:
- developer
Make sure to replace the following placeholders with your own values:
-
routeName|Id: Theidornameof the route the plugin configuration will target.
Make the following request:
curl -i -X POST http://localhost:8001/routes/{routeName|Id}/plugins/ \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '
{
"name": "ai-mcp-proxy",
"config": {
"mode": "passthrough-listener",
"include_consumer_groups": true,
"default_acl": [
{
"scope": "tools",
"allow": [
"developer",
"admin"
],
"deny": [
"suspended"
]
}
],
"logging": {
"log_payloads": false,
"log_statistics": true,
"log_audits": true
},
"tools": [
{
"description": "List users",
"name": "list_users",
"acl": {
"allow": [
"admin",
"eason"
],
"deny": [
"developer"
]
}
},
{
"description": "Get user",
"name": "get_user",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "List orders",
"name": "list_orders",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "List orders for users",
"name": "list_orders_for_user",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "Search orders by name (case-insensitive substring)",
"name": "search_orders",
"acl": {
"allow": [
"admin"
],
"deny": [
"developer"
]
}
}
]
},
"tags": []
}
'
Make sure to replace the following placeholders with your own values:
-
routeName|Id: Theidornameof the route the plugin configuration will target.
Make the following request:
curl -X POST https://{region}.api.konghq.com/v2/control-planes/{controlPlaneId}/core-entities/routes/{routeId}/plugins/ \
--header "accept: application/json" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer $KONNECT_TOKEN" \
--data '
{
"name": "ai-mcp-proxy",
"config": {
"mode": "passthrough-listener",
"include_consumer_groups": true,
"default_acl": [
{
"scope": "tools",
"allow": [
"developer",
"admin"
],
"deny": [
"suspended"
]
}
],
"logging": {
"log_payloads": false,
"log_statistics": true,
"log_audits": true
},
"tools": [
{
"description": "List users",
"name": "list_users",
"acl": {
"allow": [
"admin",
"eason"
],
"deny": [
"developer"
]
}
},
{
"description": "Get user",
"name": "get_user",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "List orders",
"name": "list_orders",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "List orders for users",
"name": "list_orders_for_user",
"acl": {
"allow": [
"admin",
"developer"
]
}
},
{
"description": "Search orders by name (case-insensitive substring)",
"name": "search_orders",
"acl": {
"allow": [
"admin"
],
"deny": [
"developer"
]
}
}
]
},
"tags": []
}
'
Make sure to replace the following placeholders with your own values:
-
region: Geographic region where your Kong Konnect is hosted and operates. -
KONNECT_TOKEN: Your Personal Access Token (PAT) associated with your Konnect account. -
controlPlaneId: Theidof the control plane. -
routeId: Theidof the route the plugin configuration will target.
See the Konnect API reference to learn about region-specific URLs and personal access tokens.
echo "
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: ai-mcp-proxy
namespace: kong
annotations:
kubernetes.io/ingress.class: kong
konghq.com/tags: ''
config:
mode: passthrough-listener
include_consumer_groups: true
default_acl:
- scope: tools
allow:
- developer
- admin
deny:
- suspended
logging:
log_payloads: false
log_statistics: true
log_audits: true
tools:
- description: List users
name: list_users
acl:
allow:
- admin
- eason
deny:
- developer
- description: Get user
name: get_user
acl:
allow:
- admin
- developer
- description: List orders
name: list_orders
acl:
allow:
- admin
- developer
- description: List orders for users
name: list_orders_for_user
acl:
allow:
- admin
- developer
- description: Search orders by name (case-insensitive substring)
name: search_orders
acl:
allow:
- admin
deny:
- developer
plugin: ai-mcp-proxy
" | kubectl apply -f -
Next, apply the KongPlugin resource by annotating the httproute or ingress resource:
kubectl annotate -n kong httproute konghq.com/plugins=ai-mcp-proxy
kubectl annotate -n kong ingress konghq.com/plugins=ai-mcp-proxy
Prerequisite: Configure your Personal Access Token
terraform {
required_providers {
konnect = {
source = "kong/konnect"
}
}
}
provider "konnect" {
personal_access_token = "$KONNECT_TOKEN"
server_url = "https://us.api.konghq.com/"
}
Add the following to your Terraform configuration to create a Konnect Gateway Plugin:
resource "konnect_gateway_plugin_ai_mcp_proxy" "my_ai_mcp_proxy" {
enabled = true
config = {
mode = "passthrough-listener"
include_consumer_groups = true
default_acl = [
{
scope = "tools"
allow = ["developer", "admin"]
deny = ["suspended"]
} ]
logging = {
log_payloads = false
log_statistics = true
log_audits = true
}
tools = [
{
description = "List users"
name = "list_users"
acl = {
allow = ["admin", "eason"]
deny = ["developer"]
}
},
{
description = "Get user"
name = "get_user"
acl = {
allow = ["admin", "developer"]
}
},
{
description = "List orders"
name = "list_orders"
acl = {
allow = ["admin", "developer"]
}
},
{
description = "List orders for users"
name = "list_orders_for_user"
acl = {
allow = ["admin", "developer"]
}
},
{
description = "Search orders by name (case-insensitive substring)"
name = "search_orders"
acl = {
allow = ["admin"]
deny = ["developer"]
}
} ]
}
tags = []
control_plane_id = konnect_gateway_control_plane.my_konnect_cp.id
route = {
id = konnect_gateway_route.my_route.id
}
}