diff --git a/.github/styles/base/Dictionary.txt b/.github/styles/base/Dictionary.txt index 9adaa8a7c7..bc3b7f296f 100644 --- a/.github/styles/base/Dictionary.txt +++ b/.github/styles/base/Dictionary.txt @@ -103,6 +103,7 @@ certificate_admin charset chatbot chatbots +chatwise cidr cidrs cleartext @@ -215,6 +216,7 @@ DPPs drilldown dynatrace Dynatrace +eason ecs ElastiCache ElastiCache diff --git a/app/_data/entity_examples/gateway/routes/mcp-acl-route.yml b/app/_data/entity_examples/gateway/routes/mcp-acl-route.yml new file mode 100644 index 0000000000..ca9843dba9 --- /dev/null +++ b/app/_data/entity_examples/gateway/routes/mcp-acl-route.yml @@ -0,0 +1,5 @@ +name: mcp-acl-route +paths: + - /mcp +service: + name: mcp-acl-service diff --git a/app/_data/entity_examples/gateway/services/mcp-acl-service.yaml b/app/_data/entity_examples/gateway/services/mcp-acl-service.yaml new file mode 100644 index 0000000000..dc3fd91ce4 --- /dev/null +++ b/app/_data/entity_examples/gateway/services/mcp-acl-service.yaml @@ -0,0 +1,2 @@ +name: mcp-acl-service +url: http://host.docker.internal:3001/mcp \ No newline at end of file diff --git a/app/_data/products/gateway.yml b/app/_data/products/gateway.yml index aa574c8019..cfbe401141 100644 --- a/app/_data/products/gateway.yml +++ b/app/_data/products/gateway.yml @@ -1292,6 +1292,565 @@ releases: - 3.3 - 3.2 - Confluent Cloud + - release: "3.12" + latest: true + ee-version: "3.12.0.1" + eol: 2026-10-01 + distributions: + - amazonlinux2: + package: true + package_support: + fips: false + arm: true + graviton: true + docker: true + - amazonlinux2023: + package: true + package_support: + fips: false + arm: true + graviton: true + docker: true + default: true + - debian11: + package: true + package_support: + fips: false + arm: true + graviton: true + docker: true + - debian12: + package: true + package_support: + fips: false + arm: true + graviton: true + docker: true + default: true + - rhel8: + package: true + package_support: + arm: false + graviton: false + fips: true + docker: false + - rhel9: + package: true + package_support: + graviton: false + arm: true + fips: true + docker: true + docker_support: + fips: true + default: true + - ubuntu2004: + package: true + package_support: + graviton: false + arm: false + fips: true + docker: false + eol: April 2025 + - ubuntu2204: + package: true + package_support: + arm: true + graviton: true + fips: true + docker: true + docker_support: + fips: true + - ubuntu2404: + package: true + package_support: + arm: true + graviton: true + fips: true + docker: true + docker_support: + fips: true + default: true + third_party_support: + ai_providers: + - openai: + - cohere: + - azure_ai: + - anthropic: + - mistral: + - llama2: + format: + - Raw + - OLLAMA + - OpenAI + - bedrock: + - gemini: + + s3_api: + - s3 + - minio + + log_provider: + - splunk + - datadog + - loggly + + service_mesh: + - kongmesh: + versions: + - 2.0 + - istio: + versions: + - 1.16 + - 1.15 + - 1.14 + + identity_provider: + - auth0 + - cognito + - connect2id + - curity + - dex + - gluu + - google + - identityserver + - keycloak + - azure-ad + - microsoft-adfs + - microsoft-live-connect + - okta + - onelogin + - openam + - paypal + - pingfederate + - salesforce + - wso2 + - yahoo + + vault: + - vaultproject: + versions: + - 1.12 + - aws-sm: + - azure-key-vaults: + - gcp-sm: + - conjur: + versions: + - 1.22.2-12 + metrics: + - prometheus: + versions: + - 2.40 + - 2.37 + - statsd: + versions: + - 0.9 + - opentelemetry: + - zipkin: + versions: + - 2.23 + - 2.22 + + datastore: + - postgres: + versions: + - 17 + - 16 + - 15 + - 14 + - 13 + - Amazon RDS + - Amazon Aurora + - redis: + versions: + - 6 + - 7 + - AWS Elasticache + - valkey: + versions: + - 8 + - influxdb: + versions: + - 1 + - kafka: + versions: + - 3.3 + - 3.2 + - Confluent Cloud + + - release: "3.13" + unreleased: true + latest: false + ee-version: "3.13.0.0" + eol: 2026-12-08 + distributions: + - amazonlinux2: + package: true + package_support: + fips: false + arm: true + graviton: true + docker: true + - amazonlinux2023: + package: true + package_support: + fips: false + arm: true + graviton: true + docker: true + default: true + - debian11: + package: true + package_support: + fips: false + arm: true + graviton: true + docker: true + - debian12: + package: true + package_support: + fips: false + arm: true + graviton: true + docker: true + default: true + - rhel8: + package: true + package_support: + arm: false + graviton: false + fips: true + docker: false + - rhel9: + package: true + package_support: + graviton: false + arm: true + fips: true + docker: true + docker_support: + fips: true + default: true + - ubuntu2004: + package: true + package_support: + graviton: false + arm: false + fips: true + docker: false + eol: April 2025 + - ubuntu2204: + package: true + package_support: + arm: true + graviton: true + fips: true + docker: true + docker_support: + fips: true + - ubuntu2404: + package: true + package_support: + arm: true + graviton: true + fips: true + docker: true + docker_support: + fips: true + default: true + third_party_support: + ai_providers: + - openai: + - cohere: + - azure_ai: + - anthropic: + - mistral: + - llama2: + format: + - Raw + - OLLAMA + - OpenAI + - bedrock: + - gemini: + + s3_api: + - s3 + - minio + + log_provider: + - splunk + - datadog + - loggly + + service_mesh: + - kongmesh: + versions: + - 2.0 + - istio: + versions: + - 1.16 + - 1.15 + - 1.14 + + identity_provider: + - auth0 + - cognito + - connect2id + - curity + - dex + - gluu + - google + - identityserver + - keycloak + - azure-ad + - microsoft-adfs + - microsoft-live-connect + - okta + - onelogin + - openam + - paypal + - pingfederate + - salesforce + - wso2 + - yahoo + + vault: + - vaultproject: + versions: + - 1.12 + - aws-sm: + - azure-key-vaults: + - gcp-sm: + - conjur: + versions: + - 1.22.2-12 + metrics: + - prometheus: + versions: + - 2.40 + - 2.37 + - statsd: + versions: + - 0.9 + - opentelemetry: + - zipkin: + versions: + - 2.23 + - 2.22 + + datastore: + - postgres: + versions: + - 17 + - 16 + - 15 + - 14 + - 13 + - Amazon RDS + - Amazon Aurora + - redis: + versions: + - 6 + - 7 + - AWS Elasticache + - valkey: + versions: + - 8 + - influxdb: + versions: + - 1 + - kafka: + versions: + - 3.3 + - 3.2 + - Confluent Cloud + + - release: "3.13" + unreleased: true + latest: false + ee-version: "3.12.0.1" + eol: 2026-12-08 + distributions: + - amazonlinux2: + package: true + package_support: + fips: false + arm: true + graviton: true + docker: true + - amazonlinux2023: + package: true + package_support: + fips: false + arm: true + graviton: true + docker: true + default: true + - debian11: + package: true + package_support: + fips: false + arm: true + graviton: true + docker: true + - debian12: + package: true + package_support: + fips: false + arm: true + graviton: true + docker: true + default: true + - rhel8: + package: true + package_support: + arm: false + graviton: false + fips: true + docker: false + - rhel9: + package: true + package_support: + graviton: false + arm: true + fips: true + docker: true + docker_support: + fips: true + default: true + - ubuntu2004: + package: true + package_support: + graviton: false + arm: false + fips: true + docker: false + eol: April 2025 + - ubuntu2204: + package: true + package_support: + arm: true + graviton: true + fips: true + docker: true + docker_support: + fips: true + - ubuntu2404: + package: true + package_support: + arm: true + graviton: true + fips: true + docker: true + docker_support: + fips: true + default: true + third_party_support: + ai_providers: + - openai: + - cohere: + - azure_ai: + - anthropic: + - mistral: + - llama2: + format: + - Raw + - OLLAMA + - OpenAI + - bedrock: + - gemini: + + s3_api: + - s3 + - minio + + log_provider: + - splunk + - datadog + - loggly + + service_mesh: + - kongmesh: + versions: + - 2.0 + - istio: + versions: + - 1.16 + - 1.15 + - 1.14 + + identity_provider: + - auth0 + - cognito + - connect2id + - curity + - dex + - gluu + - google + - identityserver + - keycloak + - azure-ad + - microsoft-adfs + - microsoft-live-connect + - okta + - onelogin + - openam + - paypal + - pingfederate + - salesforce + - wso2 + - yahoo + + vault: + - vaultproject: + versions: + - 1.12 + - aws-sm: + - azure-key-vaults: + - gcp-sm: + - conjur: + versions: + - 1.22.2-12 + metrics: + - prometheus: + versions: + - 2.40 + - 2.37 + - statsd: + versions: + - 0.9 + - opentelemetry: + - zipkin: + versions: + - 2.23 + - 2.22 + + datastore: + - postgres: + versions: + - 17 + - 16 + - 15 + - 14 + - 13 + - Amazon RDS + - Amazon Aurora + - redis: + versions: + - 6 + - 7 + - AWS Elasticache + - valkey: + versions: + - 8 + - influxdb: + versions: + - 1 + - kafka: + versions: + - 3.3 + - 3.2 + - Confluent Cloud - release: "3.13" unreleased: true diff --git a/app/_data/series.yml b/app/_data/series.yml index 956aff1c2b..e168424155 100644 --- a/app/_data/series.yml +++ b/app/_data/series.yml @@ -31,4 +31,7 @@ mcp-conversion: url: /mcp/autogenerate-mcp-tools/ mcp-weather-api: title: Autogenerate and observe MCP tools for Weather API - url: /mcp/autogenerate-mcp-tools-for-weather-api/ \ No newline at end of file + url: /mcp/autogenerate-mcp-tools-for-weather-api/ +mcp-acls: + title: Control MCP tool access with Consumer and Consumer Group ACLs + url: /mcp/use-access-controls-for-mcp-tools/ \ No newline at end of file diff --git a/app/_how-tos/observe-mcp-traffic-with-acls.md b/app/_how-tos/observe-mcp-traffic-with-acls.md new file mode 100644 index 0000000000..ca03287b28 --- /dev/null +++ b/app/_how-tos/observe-mcp-traffic-with-acls.md @@ -0,0 +1,169 @@ +--- +title: Observe MCP Traffic with Access Control Enabled +content_type: how_to +related_resources: + - text: AI Gateway + url: /ai-gateway/ + - text: AI MCP Proxy + url: /plugins/ai-mcp-proxy/ + +description: Learn how to observe MCP tool activity after you apply access controls. Enable file-based logging, then review audit entries to confirm permitted tools and RPC calls. + + +products: + - gateway + - ai-gateway + - insomnia + +permalink: /mcp/observe-mcp-traffic-with-acls/ + +series: + id: mcp-acls + position: 2 + +works_on: + - on-prem + - konnect + +min_version: + gateway: '3.13' + +plugins: + - ai-mcp-proxy + +entities: + - service + - route + - plugin + +tags: + - ai + - openai + - mcp + +tldr: + q: How do I observe MCP tool usage with Kong AI Gateway? + a: | + Use the File Log plugin to write MCP tool activity to a local file. Inspect the entries to see which tools each Consumer or Consumer Group accessed. Confirm the RPC calls that Chatwise sends to your MCP server. + +tools: + - deck + +prereqs: + inline: + - title: ChatWise desktop application + content: | + Download and install [ChatWise](https://chatwise.app/) for your OS. + + After installation: + 1. Launch the app. + 2. In Settings > Providers, configure your AI provider endpoint and API key. + entities: + services: + - mcp-acl-service + routes: + - mcp-acl-route + konnect: + - name: KONG_STATUS_LISTEN + value: '0.0.0.0:8100' +--- + +## Configure MCP tools in Chatwise + +1. Open Chatwise and go to **Settings > MCP**: + + 1. Click **+** at the bottom of the window and choose **HTTP server (http)** from the **Type** dropdown. + 1. Enter a user-friendly name in the **Name** field. + 1. Enter `http://localhost:8000/mcp` in the **URL** field. + 1. Enable the **Run tools automatically** option. + 1. Click **+** next to the **HTTP headers** section and add: + + - **KEY**: `api-key` + - **VALUE**: `alice-key` + 1. Click the **Verify (view tools)** button. You should see the following tools: + + - `list_users` + - `get_user` + - `list_orders` + - `list_orders_for_user` + - `search_orders` + 1. Close **Settings**. + 1. In the chat window, click the hammer icon to enable tools. + 1. Toggle your MCP server on. You should see `1` next to the hammer icon. Click the icon to view the server name and the number of available tools. + +## Configure the File Log plugin + +Now, let's configure the File Log plugin: + +{% entity_examples %} +entities: + plugins: + - name: file-log + config: + path: /tmp/mcp.json +{% endentity_examples %} + +## Test MCP tools + +Let's generate MCP traffic and verify it appears in the logs. In Chatwise, enter the following: + +```text +How many orders are there in my marketplace? +``` + +You should see Chatwise successfully call the `list_users` tool with a response like: + +```text +There are 27 orders in your marketplace. +``` +{:.no-copy-code} + +Next, check the audit logs in your Docker container: + +```sh +docker exec -it kong-quickstart-gateway cat /tmp/mcp.json +``` + +You should see output similar to: + +```json +{ + "ai": { + "mcp": { + "rpc": [ + { + "method": "tools/call", + "latency": 6, + "id": "2", + "response_body_size": 5030, + "tool_name": "list_orders" + } + ], + "audit": [ + { + "primitive_name": "list_orders", + "consumer": { + "id": "6c95a611-9991-407b-b1c3-bc608d3bccc3", + "name": "admin", + "identifier": "consumer_group" + }, + "scope": "primitive", + "primitive": "tool", + "action": "allow" + } + ] + } + }, + "rpc": [ + { + "method": "tools/call", + "id": "1", + "latency": 3, + "tool_name": "list_orders", + "response_body_size": 5030 + } + ] + } + } +} +``` \ No newline at end of file diff --git a/app/_how-tos/use-access-controls-for-mcp-tools.md b/app/_how-tos/use-access-controls-for-mcp-tools.md new file mode 100644 index 0000000000..f96a4e4a55 --- /dev/null +++ b/app/_how-tos/use-access-controls-for-mcp-tools.md @@ -0,0 +1,337 @@ +--- +title: Control MCP tool access with Consumer and Consumer Group ACLs +content_type: how_to +related_resources: + - text: AI Gateway + url: /ai-gateway/ + - text: AI MCP Proxy + url: /plugins/ai-mcp-proxy/ + +description: Learn how to use the AI MCP Proxy plugin to restrict access to specific MCP tools based on Kong Consumers and Consumer Groups. Configure global and per-tool ACLs, define user roles, and validate access behavior using Insomnia’s MCP Client. + +products: + - gateway + - ai-gateway + - insomnia + +permalink: /mcp/use-access-controls-for-mcp-tools/ + +series: + id: mcp-acls + position: 1 + +works_on: + - on-prem + - konnect + +min_version: + gateway: '3.13' + +plugins: + - ai-mcp-proxy + +entities: + - service + - route + - plugin + +tags: + - ai + - openai + - mcp + +tldr: + q: How do I enforce control access to MCP tools using Kong AI Gateway? + a: | + Use the AI MCP Proxy plugin to control access to MCP tools with global and + per-tool ACLs based on Consumers and Consumer Groups. Use Insomnia’s MCP + Client feature to test and validate which tools each user can access. + +tools: + - deck + +prereqs: + inline: + - title: Mock API Server + content: | + Before using the [AI MCP Proxy](/plugins/ai-mcp-proxy/) plugin, you need an upstream MCP-compatible HTTP server to expose. For this tutorial, we’ll use a simple Express-based MCP server that simulates a marketplace system. It provides read-only access to sample users and their orders. + + The server exposes a single `/mcp` endpoint and registers tools instead of REST routes, including: + + * `list_users` + * `get_user` + * `list_orders` + * `list_orders_for_user` + * `search_orders` + + These tools operate on in-memory marketplace data, allowing you to test MCP behavior without connecting to a real backend. + + Run the following command to clone the repository, install dependencies, build the server, and start it: + + ```bash + git clone https://github.com/tomek-labuk/marketplace-acl.git && \ + cd marketplace-acl && \ + npm install && \ + npm run build && \ + node dist/server.js + ``` + + When the server starts, it listens at: + + ``` + http://localhost:3001/mcp + ``` + icon_url: /assets/icons/github.svg + + entities: + services: + - mcp-acl-service + routes: + - mcp-acl-route + konnect: + - name: KONG_STATUS_LISTEN + value: '0.0.0.0:8100' +--- +## Set up Consumer authentication + +Let's configure authentication so the {{site.base_gateway}} can identify each caller. We'll use the [Key Auth](/plugins/key-auth/) plugin so each user (or AI agent) presents an API key with requests: + +{% entity_examples %} +entities: + plugins: + - name: key-auth + route: mcp-acl-route + config: + key_names: + - apikey +{% endentity_examples %} + +## Create Consumer Groups for each AI usage tier + +Now, let's configure Consumer Groups that reflect access levels. These groups govern MCP tool permissions: +- `admin` - full access +- `developer` - limited access +- `suspended` - blocked from MCP tools + +{% entity_examples %} +entities: + consumer_groups: + - name: admin + - name: developer + - name: suspended +{% endentity_examples %} + +## Create Consumers + +Let's configure individual Consumers and assign them to groups. Each Consumer will use a unique API key and inherits group permissions which will govern access to MCP tools: + +{% entity_examples %} +entities: + 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-key +{% endentity_examples %} + +## Configure the AI MCP Proxy plugin + +Now, let's configure the AI MCP Proxy plugin to apply tool-level access rules. The plugin controls which users or AI agents can see or call each MCP tool. Access is determined by Consumer Groups and individual Consumers using allow and deny lists. A tool ACL replaces the default rule when present. + +The table below shows the effective permissions for the configuration: + + +{% table %} +columns: + - title: MCP Tool + key: tool + - title: Admin group + key: admin + - title: Developer group + key: developer + - title: Eason consumer + key: eason + - title: Suspended group + key: suspended + +rows: + - tool: "`list_users`" + admin: Yes + developer: No + eason: Yes + suspended: No + - tool: "`get_user`" + admin: Yes + developer: Yes + eason: No + suspended: No + - tool: "`list_orders`" + admin: Yes + developer: Yes + eason: No + suspended: No + - tool: "`list_orders_for_user`" + admin: Yes + developer: Yes + eason: No + suspended: No + - tool: "`search_orders`" + admin: Yes + developer: No + eason: No + suspended: No +{% endtable %} + + +The following plugin configuration applies the ACL rules for the MCP tools shown in the table above: + +{% entity_examples %} +entities: + plugins: + - name: ai-mcp-proxy + route: mcp-acl-route + 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 +{% endentity_examples %} + +## Validate the configuration + +Let's use Insomnia's MCP Client feature to validate our ACL configuration: + +1. Go to the Insomnia app. +1. Click **Create MCP Client** in the left sidebar. +1. Enter the preferred name and click **Create**. +1. In the `HTTP` field enter `http://localhost:8000/mcp`. +1. Go to the **Auth** tab. +1. Select **API Key** from the Auth type dropdown. + +Now let's verify access for each user by connecting with their API key: + +{% navtabs "validate-mcp-access" %} +{% navtab "Alice (admin group)" %} + +1. Enter `apikey` in the Key field. +1. Enter `alice-key` in the Value field. +1. Click the **Connect** button. +1. Once connected, Insomnia should list these tools in the sidebar: + + ```text + list_users + get_user + list_orders + list_orders_for_user + search_orders + ``` + + Alice belongs to the **admin** group and has access to all tools. +1. Click **Disconnect** to switch to another user. + +{% endnavtab %} +{% navtab "Bob (developer group)" %} + +1. Enter `apikey` in the Key field. +1. Enter `bob-key` in the Value field. +1. Click the **Connect** button. +1. Once connected, Insomnia should list these tools in the sidebar: + + ```text + get_user + list_orders + list_orders_for_user + ``` + {:.no-copy-code} + + Bob belongs to the **developer** group and is denied access to `list_users`. +1. Click **Disconnect** to update the key for the next user. + +{% endnavtab %} +{% navtab "Carol (suspended group)" %} + +1. Enter `apikey` in the Key field. +1. Enter `carol-key` in the Value field. +1. Click the **Connect** button. +1. The connection should fail with a `INVALID_PARAMS -32602` response.
+ Carol belongs to the **suspended** group, which is globally denied access to all tools. +1. Click **Disconnect** to switch to another user. + +{% endnavtab %} +{% navtab "Eason (no group)" %} + +1. Enter `apikey` in the Key field. +1. Enter `eason-key` in the Value field. +1. Click the **Connect** button. +1. Once connected, Insomnia should list this tool in the sidebar: + + ```text + list_users + ``` + {:.no-copy-code} + + Eason is not part of any group but is explicitly allowed access to `list_users` in the tool’s ACL. +1. Click **Disconnect** after validation. + +{% endnavtab %} +{% endnavtabs %} diff --git a/app/_kong_plugins/ai-mcp-proxy/examples/conversion-listener-acl.yaml b/app/_kong_plugins/ai-mcp-proxy/examples/conversion-listener-acl.yaml new file mode 100644 index 0000000000..4562c3dedd --- /dev/null +++ b/app/_kong_plugins/ai-mcp-proxy/examples/conversion-listener-acl.yaml @@ -0,0 +1,118 @@ +description: 'Set access control rules for MCP tools by consumer group' + +title: 'Set access control rules for MCP tools based on consumer groups' + +extended_description: | + Define which consumer groups can access specific MCP tools in conversion-listener mode. Use default rules that apply to all tools, then override access for individual tools as needed. + {:.info} + > For this configuration to work properly, you need to create the following {{site.base_gateway}} entities: + > ```yaml + > services: + > - name: mcp-service + > url: http://host.docker.internal:3000 + > routes: + > - name: mcp-route + > paths: + > - /marketplace + > plugins: + > - name: key-auth + > route: mcp-route + > 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 + > ``` + + In conversion-listener and conversion-only modes, the plugin defines MCP tools directly from HTTP endpoint configurations. Each tool can optionally specify access control rules per consumer group. + + Before using the [AI MCP Proxy](/plugins/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: + + ```bash + curl -s -o api.js "https://gist.githubusercontent.com/subnetmarco/5ddb23876f9ce7165df17f9216f75cce/raw/a44a947d69e6f597465050cc595b6abf4db2fbea/api.js" + npm install express + node api.js + ``` + +weight: 900 + +requirements: + - "A running and exposed API" + +config: + mode: conversion-listener + include_consumer_groups: true + default_acl: + - scope: tools + allow: + - developer + - admin + deny: + - suspended + tools: + - description: Get users + method: GET + path: "/marketplace/users" + annotations: + title: Get users + parameters: + - name: id + in: query + required: false + schema: + type: string + description: Optional user ID + acl: + allow: + - admin + - description: Get orders for a user + method: GET + path: "/marketplace/orders" + annotations: + title: Get users orders + parameters: + - name: userid + in: query + required: true + schema: + type: string + description: User ID to filter orders + acl: + allow: + - admin + - developer + server: + timeout: 60000 + max_request_body_size: 8192 + +tools: + - deck + - admin-api + - konnect-api + - kic + - terraform + +group: mcp-acls \ No newline at end of file diff --git a/app/_kong_plugins/ai-mcp-proxy/examples/conversion-listener-tool-acls.yaml b/app/_kong_plugins/ai-mcp-proxy/examples/conversion-listener-tool-acls.yaml new file mode 100644 index 0000000000..0984632655 --- /dev/null +++ b/app/_kong_plugins/ai-mcp-proxy/examples/conversion-listener-tool-acls.yaml @@ -0,0 +1,118 @@ +description: 'Set up consumer groups and key authentication for MCP tool access control' + +title: 'Configure consumer groups and key authentication for per-tool MCP access control' + +extended_description: | + Configure consumer groups and key authentication to control access to individual MCP tools based on consumer roles. This configuration applies access control rules at the tool level without a default policy. + + {:.info} + > For this configuration to work properly, you need to create the following {{site.base_gateway}} entities: + > ```yaml + > services: + > - name: mcp-service + > url: http://host.docker.internal:3000 + > routes: + > - name: mcp-route + > paths: + > - /marketplace + > + > plugins: + > - name: key-auth + > route: mcp-route + > 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-key + > ``` + + Before using the [AI MCP Proxy](/plugins/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: + + ```bash + curl -s -o api.js "https://gist.githubusercontent.com/subnetmarco/5ddb23876f9ce7165df17f9216f75cce/raw/a44a947d69e6f597465050cc595b6abf4db2fbea/api.js" + npm install express + node api.js + ``` + +weight: 900 + +requirements: + - "A running and exposed API" + +config: + mode: conversion-only + include_consumer_groups: true + tools: + - description: Get users + method: GET + path: "/marketplace/users" + annotations: + title: Get users + parameters: + - name: id + in: query + required: false + schema: + type: string + description: Optional user ID + acl: + allow: + - admin + - eason + deny: + - developer + - description: Get orders for a user + method: GET + path: "/marketplace/orders" + annotations: + title: Get users orders + parameters: + - name: userid + in: query + required: true + schema: + type: string + description: User ID to filter orders + acl: + allow: + - admin + - developer + server: + timeout: 60000 + max_request_body_size: 8192 + +tools: + - deck + - admin-api + - konnect-api + - kic + - terraform + +group: mcp-acls \ No newline at end of file diff --git a/app/_kong_plugins/ai-mcp-proxy/examples/conversion-listener.yaml b/app/_kong_plugins/ai-mcp-proxy/examples/conversion-listener.yaml index 39a6e114df..1db902b9c8 100644 --- a/app/_kong_plugins/ai-mcp-proxy/examples/conversion-listener.yaml +++ b/app/_kong_plugins/ai-mcp-proxy/examples/conversion-listener.yaml @@ -70,4 +70,4 @@ tools: - admin-api - konnect-api - kic - - terraform + - terraform \ No newline at end of file diff --git a/app/_kong_plugins/ai-mcp-proxy/examples/conversion-only.yaml b/app/_kong_plugins/ai-mcp-proxy/examples/conversion-only.yaml index 22b83f95b5..347c9f4d46 100644 --- a/app/_kong_plugins/ai-mcp-proxy/examples/conversion-only.yaml +++ b/app/_kong_plugins/ai-mcp-proxy/examples/conversion-only.yaml @@ -72,4 +72,4 @@ tools: - admin-api - konnect-api - kic - - terraform + - terraform \ No newline at end of file diff --git a/app/_kong_plugins/ai-mcp-proxy/examples/listener.yaml b/app/_kong_plugins/ai-mcp-proxy/examples/listener.yaml index e8743b366d..1187fdddeb 100644 --- a/app/_kong_plugins/ai-mcp-proxy/examples/listener.yaml +++ b/app/_kong_plugins/ai-mcp-proxy/examples/listener.yaml @@ -50,4 +50,4 @@ tools: - admin-api - konnect-api - kic - - terraform + - terraform \ No newline at end of file diff --git a/app/_kong_plugins/ai-mcp-proxy/examples/passthrough-listener-acls.yaml b/app/_kong_plugins/ai-mcp-proxy/examples/passthrough-listener-acls.yaml new file mode 100644 index 0000000000..8e7b2a6b17 --- /dev/null +++ b/app/_kong_plugins/ai-mcp-proxy/examples/passthrough-listener-acls.yaml @@ -0,0 +1,131 @@ +description: 'Set access control rules for passthrough-listener mode MCP servers' + +title: 'Configure default and per-tool access control for passthrough-listener mode MCP servers' + +extended_description: | + Configure default and per-tool access control for passthrough-listener mode MCP servers. + + + {:.info} + > For this configuration to work properly, you need to create the following {{site.base_gateway}} entities: + > + > ```yaml + > 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-key + > ``` + + Before using the [AI MCP Proxy](/plugins/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: + + ```bash + 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](/mcp/use-access-controls-for-mcp-tools/) for a detailed walkthrough guide. + +weight: 900 + +requirements: + - "A running and exposed API" + +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 + +tools: + - deck + - admin-api + - konnect-api + - kic + - terraform + +group: mcp-acls \ No newline at end of file diff --git a/app/_kong_plugins/ai-mcp-proxy/examples/passthrough-listener-tool-acls.yaml b/app/_kong_plugins/ai-mcp-proxy/examples/passthrough-listener-tool-acls.yaml new file mode 100644 index 0000000000..2bbdf2d600 --- /dev/null +++ b/app/_kong_plugins/ai-mcp-proxy/examples/passthrough-listener-tool-acls.yaml @@ -0,0 +1,127 @@ +description: 'Set per-tool access control for passthrough-listener mode MCP servers' + +title: 'Configure per-tool access control for passthrough-listener mode MCP servers' + +extended_description: | + Configure consumer groups and key authentication to control access to individual MCP tools based on consumer roles. This configuration applies access control rules at the tool level without a default policy. + + {:.info} + > For this configuration to work properly, you need to create the following {{site.base_gateway}} entities: + > ```yaml + > 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 + > route: mcp-acl-route + > 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-key + > ``` + + Before using the [AI MCP Proxy](/plugins/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: + + ```bash + git clone https://github.com/tomek-labuk/marketplace-acl.git && \ + cd marketplace-acl && \ + npm install && \ + npm run build && \ + node dist/server.js + ``` + + {:.warning} + > The `tools[n].name` fields must match the exact tools name from the upstream MCP server. If the names don't match, the ACL will fail to apply. + + Check [this how-to](/mcp/use-access-controls-for-mcp-tools/) for a detailed walkthrough guide. + +weight: 900 + +requirements: + - "A running and exposed API" + +config: + mode: passthrough-listener + include_consumer_groups: true + 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 + +tools: + - deck + - admin-api + - konnect-api + - kic + - terraform + +group: mcp-acls \ No newline at end of file diff --git a/app/_kong_plugins/ai-mcp-proxy/examples/passthrough-listener.yaml b/app/_kong_plugins/ai-mcp-proxy/examples/passthrough-listener.yaml index b22884b63f..62ac26aa55 100644 --- a/app/_kong_plugins/ai-mcp-proxy/examples/passthrough-listener.yaml +++ b/app/_kong_plugins/ai-mcp-proxy/examples/passthrough-listener.yaml @@ -40,4 +40,4 @@ tools: - admin-api - konnect-api - kic - - terraform + - terraform \ No newline at end of file diff --git a/app/_kong_plugins/ai-mcp-proxy/index.md b/app/_kong_plugins/ai-mcp-proxy/index.md index 73dfe8f35f..7839d43db2 100644 --- a/app/_kong_plugins/ai-mcp-proxy/index.md +++ b/app/_kong_plugins/ai-mcp-proxy/index.md @@ -54,6 +54,14 @@ related_resources: url: /mcp/autogenerate-mcp-tools/ - text: Autogenerate MCP tools for Weather API url: /mcp/weather-mcp-api/ + - text: Control MCP tool access with Consumer and Consumer Group ACLs + url: /mcp/use-access-controls-for-mcp-tools/ + +examples_groups: + - slug: basic + text: Basic use cases + - slug: mcp-acls + text: MCP ACLs search_aliases: - ai @@ -72,6 +80,8 @@ next_steps: url: /mcp/autogenerate-mcp-tools/ - text: Autogenerate MCP tools for Weather API url: /mcp/autogenerate-mcp-tools-for-weather-api/ + - text: Control MCP tool access with Consumer and Consumer Group ACLs + url: /mcp/use-access-controls-for-mcp-tools/ --- The AI MCP Proxy plugin lets you connect any Kong-managed Service to the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/). It acts as a **protocol bridge**, translating between MCP and HTTP so that MCP-compatible clients can either call existing APIs or interact with upstream MCP servers through Kong. @@ -154,7 +164,7 @@ sequenceDiagram > Before using the AI MCP Proxy plugin, ensure your setup meets these requirements: > - The upstream Service exposes a valid OpenAPI schema. > - That Service is configured and accessible in Kong. -> - An MCP-compatible client (such as [Claude](https://claude.ai/), [Cursor](https://cursor.com/), or [LMstudio](https://lmstudio.ai/)) is available to connect to Kong. +> - An MCP-compatible client (such as [Claude](https://claude.ai/), [Cursor](https://cursor.com/), or [LMstudio](https://lmstudio.ai/) is available to connect to Kong. > - The Kong AI Gateway instance supports the AI MCP Proxy plugin (is 3.12 or higher). ## Configuration modes @@ -210,11 +220,173 @@ rows: {% endtable %} +## ACL tool control {% new_in 3.13 %} + +When exposing MCP servers through {{site.base_gateway}}, you may need granular control over which authenticated API consumers can discover and invoke specific tools. The AI MCP Proxy plugin's ACL feature lets you define access rules at both the default level (applying to all tools) and per-tool level (for fine-grained exceptions) + +This way, consumers only interact with tools appropriate to their role, while maintaining a complete audit trail of all access attempts. Authentication is handled by standard Kong AuthN plugins (for example, [Key Auth](/plugins/key-auth/) or OIDC flows), and the resulting Consumer identity is used for ACL checks. + +{:.info} +> **ACL in `listener` Mode** +> +> Listener mode does not support direct ACL configuration. Instead, it inherits ACL rules from tagged conversion-listener or conversion-only plugins. +> +> To use ACLs with [`listener`](/gateway/entities/partial/) mode: +> 1. Configure conversion-listener or conversion-only plugins with ACL rules and tags +> 2. Configure listener mode to aggregate tools by matching tags +> 3. Listener mode enforces ACL rules from the conversion plugins. + +### Supported identifier types + +ACL rules can reference [Consumers](/gateway/entities/consumer/) and [Consumer Groups](/gateway/entities/consumer-group/) using these identifier types in `allow` and `deny` lists: + +* [`username`](/gateway/entities/consumer/#schema-consumer-username): Consumer username +* [`id`](/gateway/entities/consumer/#schema-consumer-username): Consumer UUID +* [`custom_id`](/gateway/entities/consumer/#schema-consumer-custom-id): Custom Consumer identifier +* [`consumer_groups.name`](/gateway/entities/consumer/#schema-consumer-custom-id): Consumer Group name + +The authenticated Consumer identity is matched against these identifiers. If the [Consumer](/gateway/entities/consumer/) or any of their [Consumer Groups](/gateway/entities/consumer-group/) match an ACL entry, the rule applies. + +### How default and per-tool ACLs work + +The plugin evaluates access using a two-tier system: + + +{% table %} +columns: + - title: ACL type + key: field + - title: Description + key: description +rows: + - field: | + [`default_acl`](./reference/#schema--config-default-acl) + description: | + Baseline rules that apply to all tools unless overridden. + - field: | + [`tools[].acl`](./reference/#schema--config-tools-acl) + description: | + When configured, these rules replace the default ACL for that specific tool. The per-tool ACL doesn't inherit or merge with `default_acl`—it is an all-or-nothing override. +{% endtable %} + + +{:.info} +> If a tool defines its own ACL, the plugin ignores `default_acl` for that tool: +> +> - Tools with no ACL configuration inherit the default rules (both `allow` and `deny` lists) +> - Tools with an ACL must explicitly list all allowed subjects (even if they were already in `default_acl`) + +### ACL evaluation logic + +Both default and per-tool ACLs use `allow` and `deny` lists. Evaluation follows this order: + +1. **Deny list configuration**: If a `deny` list exists and the subject matches any `deny` entry, the request is rejected (`INVALID_PARAMS -32602`). +2. **Allow list configuration**: If an `allow` list exists, the subject must match at least one entry; otherwise, the request is denied (`INVALID_PARAMS -32602`). +3. **No allow list configuration**: If no `allow` list exists and the subject is not in `deny`, the request is allowed. +4. **No ACL configuration**: If neither list exists, the request is allowed. + +All access attempts (allowed or denied) are written to the plugin's audit log. + +The table below summarizes the possible ACL configurations and their outcomes. + +{% table %} +columns: + - title: Condition + key: condition + - title: "Proxied to upstream service?" + key: proxy + - title: Response code + key: response +rows: + - condition: "Subject matches any `deny` rule" + proxy: No + response: INVALID_PARAMS -32602 + - condition: "`allow` list exists and subject is not in it" + proxy: No + response: INVALID_PARAMS -32602 + - condition: "Only `deny` list exists and subject is not in it" + proxy: Yes + response: 200 + - condition: "No ACL rules configured" + proxy: Yes + response: 200 +{% endtable %} + +### ACL tool control request flow + +The AI MCP Proxy plugin evaluates ACLs for both tool discovery and tool invocation. These are two distinct operations with different behaviors: + +**Tool Discovery (List tools)**: +1. MCP client requests the list of available tools +2. Kong AuthN plugin validates the request and identifies the Consumer +3. AI MCP Proxy loads the Consumer's group memberships +4. Plugin evaluates each tool against the `default_acl` +5. Plugin returns an HTTP 200 response with only the tools the Consumer is allowed to access +6. Plugin logs the discovery attempt + +**Tool invocation**: +1. MCP client invokes a specific tool +2. Kong AuthN plugin validates the request and identifies the Consumer +3. AI MCP Proxy loads the Consumer's group memberships +4. Plugin evaluates the tool-specific ACL if it exists, or the default ACL otherwise +5. Plugin logs the access attempt (allowed or denied) +6. Plugin returns `INVALID_PARAMS -32602` if denied, or forwards the request to the upstream MCP server if allowed + + +{% mermaid %} +sequenceDiagram + participant Client as MCP Client + participant Kong as Kong Gateway + participant Auth as AuthN Plugin + participant ACL as ai-mcp-proxy (ACL/Audit) + participant Up as Upstream MCP Server + participant Log as Audit Sink + + %% ----- List Tools ----- + rect + note over Client,Kong: List Tools (Default ACL Scope) + Client->>Kong: GET /tools + Kong->>Auth: Authenticate + Auth-->>Kong: Consumer identity + Kong->>ACL: Evaluate scoped default ACL + ACL-->>Log: Audit entry + alt Allowed + Kong-->>Client: Filtered tool list + else Denied + Kong-->>Client: INVALID_PARAMS -32602 + end + end + + %% ----- Tool Invocation ----- + rect + note over Client,Up: Tool Invocation (Per-tool ACL) + Client->>Kong: POST /tools/{tool} + Kong->>Auth: Authenticate + Auth-->>Kong: Consumer identity + Kong->>ACL: Evaluate per-tool ACL + ACL-->>Log: Audit entry + alt Allowed + Kong->>Up: Forward request + Up-->>Kong: Response + Kong-->>Client: Response + else Denied + Kong-->>Client: INVALID_PARAMS -32602 + end + end +{% endmermaid %} + + +## Migration path +For users already using the AI MCP Proxy plugin without ACL configuration, follow these steps to add ACL tool control: +1. **Add an AuthN plugin**: Enable an authentication plugin such as [Key Auth](/plugins/key-auth/) to work with Consumers and Consumer Groups. +2. **Add ACL fields to the plugin configuration**: Update the AI MCP Proxy plugin schema to include `default_acl` and per-tool `acl` fields. +3. **Configure ACL rules**: Add `allow` and `deny` lists to control access at the default and per-tool levels. +4. **Enable audit logging**: Set `logging.log_audits: true` to monitor access attempts and verify ACL enforcement. ## Scope of support -The AI MCP Proxy plugin provides support for key MCP operations and upstream interactions, while certain advanced features and non-HTTP protocols are not currently supported. The table below summarizes what is fully supported and what is outside the current scope. +The AI MCP Proxy plugin provides support for MCP operations and upstream interactions, while certain advanced features and non-HTTP protocols are not currently supported. The table below summarizes what is supported and what is outside the current scope. {% feature_table %} @@ -254,7 +426,4 @@ features: description: Applying guardrails to MCP AI plugin requests and responses supported: false {% endfeature_table %} - - - - + \ No newline at end of file diff --git a/app/_landing_pages/mcp.yaml b/app/_landing_pages/mcp.yaml index ebaffd1ab7..8a1147cb5d 100644 --- a/app/_landing_pages/mcp.yaml +++ b/app/_landing_pages/mcp.yaml @@ -47,14 +47,11 @@ rows: config: header: type: h2 - text: "MCP server options" + text: "Autogenerate MCP servers using Kong AI Gateway" blocks: - type: text text: | - {{site.base_gateway}} supports two ways to integrate MCP functionality: - - 1. **Autogenerate MCP tools from APIs**: Autogenerate secure, serverless MCP endpoints directly from any API schema without needing an LLM model. - 2. **Connect external MCP endpoints with LLM models and AI Proxy**: Proxy remote or hosted MCP endpoints that call LLM models while enforcing control at the edge. + Kong AI Gateway lets you create and manage MCP servers without writing custom code. Transform any API into an MCP server, apply security and governance controls, and integrate them with AI assistants. - header: columns: @@ -62,59 +59,43 @@ rows: - type: structured_text config: header: - type: h4 + type: h2 text: "Autogenerate MCP servers using AI MCP Proxy" blocks: - type: text text: | - Automatically turn any API into a secure MCP server using the AI MCP Proxy plugin. This approach does **not require an LLM** and provides full control over production workloads. - - Considerations for production use: - - Security and compliance can be fully managed since endpoints run under your control. - - Traffic can be monitored and scaled using {{site.base_gateway}} features. - - Costs are predictable because you control the underlying services. + Turn any API into an MCP server using the AI MCP Proxy plugin. This approach does **not require an LLM** and provides full control over production workloads. - Use {{site.base_gateway}} plugins to: - - **Secure access** with the [AI MCP OAuth2 plugin](/plugins/ai-mcp-oauth2) or other authentication methods. - - **Govern usage** with [rate limiting](/gateway/rate-limiting/) and [traffic control](/plugins/?category=traffic-control) {{site.base_gateway}} plugins. - - **Monitor behavior** using [{{site.base_gateway}} logging and monitoring tools](/plugins/?category=analytics-monitoring&category=logging). - - **Integrate APIs** directly into MCP workflows and AI assistants. + The AI MCP Proxy plugin: + - **Converts API schemas** into MCP-compatible tool definitions. + - **Aggregates multiple APIs** into a single MCP server endpoint. + - **Supports serverless deployments** for dynamic tool generation. + - **Integrates with AI assistants** like Claude Desktop and other MCP clients. - blocks: - - type: structured_text - config: - header: - type: h4 - text: "Connect external MCP servers with LLM models and AI Proxy" - blocks: - - type: text - text: | - Expose any remote MCP server that calls LLM models through the AI Proxy plugin, enforcing observability, and security at the edge. - - Considerations for production use: - - - Security, compliance, and data handling must be assessed for external MCPs. - - Latency, reliability, and versioning depend on the external LLM provider. - - Cost can grow quickly depending on request volume and model pricing. - - Use Kong AI Gateway plugins to: - - **Secure access** with [{{site.base_gateway}} plugins](/plugins/?category=authentication&category=security). - - **Govern usage** with [AI rate limiting](/plugins/ai-rate-limiting-advanced/) and [AI guardrails](/ai-gateway/#guardrails-and-content-safety). - - **Enforce load balancing** based on [tokens, cost, or LLM accuracy](/ai-gateway/load-balancing/). - - **Monitor behavior** using [logging](/ai-gateway/ai-audit-log-reference/) and [monitoring](/ai-gateway/monitor-ai-llm-metrics/) tools. - + - type: structured_text + config: + header: + type: h4 + text: "Apply security, governance, and observability controls to MCP servers" + blocks: + - type: text + text: | + Use available {{site.base_gateway}} [plugins](/plugins/) to: + - **Secure access** with the [AI MCP OAuth2 plugin](/plugins/ai-mcp-oauth2/) or other authentication methods. + - **Monitor MCP traffic** using [AI metrics](/ai-gateway/monitor-ai-llm-metrics/#mcp-traffic-metrics) and [AI audit logs](/ai-gateway/ai-audit-log-reference/#ai-mcp-logs). + - **Enforce access controls** for [MCP tool usage](/mcp/use-access-controls-for-mcp-tools/). + - **Govern usage** with rate limiting and traffic control plugins. - columns: - blocks: - type: card config: - icon: /assets/icons/deployment.svg + icon: /assets/icons/mcp.svg title: Autogenerate MCP tools from any API using AI MCP plugins description: | - Explore guides and examples to auto-generate MCP servers and tools without custom code. + Explore guides to auto-generate MCP servers and tools without custom code. ctas: - - text: Proxy and observe MCP Traffic with the AI MCP Proxy plugin + - text: Proxy MCP Traffic with the AI MCP Proxy plugin url: "/plugins/ai-mcp-proxy/" - - text: Secure your MCP servers with the AI MCP OAuth2 plugin - url: "/plugins/ai-mcp-oauth2/" - text: Autogenerate a serverless MCP url: "/mcp/autogenerate-mcp-tools/" - text: Autogenerate MCP tools from any API schema @@ -124,18 +105,18 @@ rows: - blocks: - type: card config: - icon: /assets/icons/mcp.svg - title: Secure and govern your MCP traffic via AI Proxy - description: | - Follow the tutorials below to learn how to secure, govern, and observe your MCP traffic using Kong AI Gateway and AI Proxy. + icon: /assets/icons/lock.svg + title: Secure and govern your MCP traffic + description: Apply security, governance, and observability to MCP servers that route LLM requests through AI Proxy plugins. ctas: - - text: Secure MCP traffic - url: "/mcp/secure-mcp-traffic/" - - text: Govern MCP traffic - url: "/mcp/govern-mcp-traffic/" - - text: Observe MCP traffic - url: "/mcp/observe-mcp-traffic/" - + - text: Secure MCP servers with the AI MCP OAuth2 plugin + url: "/plugins/ai-mcp-oauth2/" + - text: Monitor MCP traffic metrics + url: "/ai-gateway/monitor-ai-llm-metrics/#mcp-traffic-metrics" + - text: Review AI MCP audit logs + url: "/ai-gateway/ai-audit-log-reference/#ai-mcp-logs" + - text: Enforce access controls for MCP tools usage + url: "/mcp/use-access-controls-for-mcp-tools/" - header: type: h3 @@ -147,13 +128,13 @@ rows: blocks: - type: text text: | - Kong also provides a built-in MCP server that connects directly to your {{site.konnect_product_name}} Control Planes. It offers read-only tools for analytics, configuration inspection, and Control Plane metadata—ideal for AI-driven workflows with Claude or other compatible assistants. + Kong also provides a built-in MCP server that connects directly to your {{site.konnect_product_name}} Control Planes. It offers read-only tools for analytics, configuration inspection, and Control Plane metadata. This is ideal for AI-driven workflows with Claude or other compatible assistants. - With {{site.konnect_product_name}} MCP server, you can use natural language to: - - Query API traffic across gateways with filters and time windows. - - List and inspect Services, Routes, Consumers, and plugins. - - Explore Control Plane hierarchies and group relationships. - - Build and test workflows without a production setup. + With {{site.konnect_product_name}} MCP server, you can use natural language to: + - Query API traffic across gateways with filters and time windows. + - List and inspect Services, Routes, Consumers, and plugins. + - Explore Control Plane hierarchies and group relationships. + - Build and test workflows without a production setup. - column_count: 3 columns: - blocks: @@ -177,7 +158,6 @@ rows: description: "Browse the built-in MCP server tools for analytics, inspection, and AI-driven workflow testing." cta: url: /mcp/kong-mcp/tools - - header: type: h2 text: "MCP traffic observability" diff --git a/app/ai-gateway/ai-audit-log-reference.md b/app/ai-gateway/ai-audit-log-reference.md index f4f2b768aa..01d622ca28 100644 --- a/app/ai-gateway/ai-audit-log-reference.md +++ b/app/ai-gateway/ai-audit-log-reference.md @@ -310,7 +310,7 @@ rows: ### AI MCP logs {% new_in 3.12 %} -If you're using the [AI MCP plugin](/), AI Gateway logs include additional fields under the `ai.mcp` object. These fields are exposed when the AI MCP plugin is enabled and provide insight into Model Context Protocol (MCP) traffic, including session IDs, JSON-RPC request/response payloads, latency, and tool usage. +If you're using the [AI MCP plugin](/plugins/ai-mcp-proxy/), AI Gateway logs include additional fields under the `ai.mcp` object. These fields are exposed when the AI MCP plugin is enabled and provide insight into Model Context Protocol (MCP) traffic, including session IDs, JSON-RPC request/response payloads, latency, tool usage and {% new_in 3.13 %} access control audit entries. {:.info} > **Note:** Unlike other available AI plugins, the AI MCP plugin is not invoked as part of an AI request. @@ -347,6 +347,30 @@ rows: description: The error message if an error occurred during the request. - property: "`ai.mcp.rpc[].response_body_size`" description: The size of the JSON-RPC response body, in bytes. + - property: "`ai.mcp.audit`" + description: | + {% new_in 3.13 %} An array of access control audit entries. Each entry records whether access was allowed or denied for a specific MCP primitive or globally. + - property: "`ai.mcp.audit[].primitive_name`" + description: | + {% new_in 3.13 %} The name of the MCP primitive (for example, `list_users`). + - property: "`ai.mcp.audit[].primitive`" + description: | + {% new_in 3.13 %} The type of MCP primitive (for example, `tool`, `resource`, or `prompt`). + - property: "`ai.mcp.audit[].action`" + description: | + {% new_in 3.13 %} The access control decision: `allow` or `deny`. + - property: "`ai.mcp.audit[].consumer.name`" + description: | + {% new_in 3.13 %} The name of the consumer making the request. + - property: "`ai.mcp.audit[].consumer.id`" + description: | + {% new_in 3.13 %} The UUID of the consumer. + - property: "`ai.mcp.audit[].consumer.identifier`" + description: | + {% new_in 3.13 %} The type of consumer identifier (for example, `consumer_group`). + - property: "`ai.mcp.audit[].scope`" + description: | + {% new_in 3.13 %} The scope of the access control check. {% endtable %} @@ -458,22 +482,43 @@ The following example shows a structured AI Gateway log entry: The following example shows an MCP log entry: ```json -"ai": { - "mcp": { - "mcp_session_id": "session-id", - "rpc": [ - { - "id": "4", - "latency": 1, - "payload": { - "response": "$OPTIONAL_MCP_PAYLOAD_REQUEST", - "request": "$OPTIONAL_MCP_PAYLOAD_REQUEST" - }, - "method": "tools/call", - "tool_name": "tool 1", - "response_body_size": 100 - } - ] +{ + "ai": { + "mcp": { + "rpc": [ + { + "method": "tools/call", + "latency": 6, + "id": "2", + "response_body_size": 5030, + "tool_name": "list_orders" + } + ], + "audit": [ + { + "primitive_name": "list_orders", + "consumer": { + "id": "6c95a611-9991-407b-b1c3-bc608d3bccc3", + "name": "admin", + "identifier": "consumer_group" + }, + "scope": "primitive", + "primitive": "tool", + "action": "allow" + } + ] + } + }, + "rpc": [ + { + "method": "tools/call", + "id": "1", + "latency": 3, + "tool_name": "list_orders", + "response_body_size": 5030 + } + ] + } } } ``` \ No newline at end of file