From 67a080ac3b07c9c079288567bbb5279ac5588f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Tailland?= Date: Sat, 29 Aug 2026 08:48:40 +0200 Subject: [PATCH] refactor(mcp): generate the tool definitions from the spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Produced by k8s-platform/tools/generate-mcp-tools.py: deck file openapi2mcp does the conversion, and the wrapper re-injects the five things Kong's generator cannot emit — per-tool ACLs, the MCP behavioural annotations, the response schemas the plugin uses for structuredOutput, the real upstream host, and JSON-only request bodies. Each is a documented gap; see k8s-platform/MCP-TOOL-GENERATION.md. tools-policy.yaml carries the ACLs and doubles as the allow-list: an operation becomes a tool only if the policy names it. Kong would otherwise expose every operation in the spec, DELETE included, and can express no authorization at all from a bearer-token spec — silently, exit 0, no warning. Same tools as before, same ACLs. What changed: query parameters are now declared and callable, each tool carries its response schema so calls return structured content instead of raw JSON, and request bodies are no longer tripled across three identical content types. Co-Authored-By: Claude Opus 5 --- kong/mcp/ai-mcp-proxy.yaml | 275 +++++++++++++++++++++++++++---------- kong/mcp/tools-policy.yaml | 20 +++ 2 files changed, 224 insertions(+), 71 deletions(-) create mode 100644 kong/mcp/tools-policy.yaml diff --git a/kong/mcp/ai-mcp-proxy.yaml b/kong/mcp/ai-mcp-proxy.yaml index b522d9d..7c0fb3e 100644 --- a/kong/mcp/ai-mcp-proxy.yaml +++ b/kong/mcp/ai-mcp-proxy.yaml @@ -1,3 +1,10 @@ +# GENERATED — do not edit. Edit openapi.yaml or tools-policy.yaml, then: +# k8s-platform/tools/generate-mcp-tools.py +# +# Produced by `deck file openapi2mcp`, then post-processed to add the ACLs, +# the MCP behavioural annotations, the response schemas, the real upstream +# host and the JSON-only bodies that Kong's generator does not emit. Each of +# those is a documented gap — see k8s-platform/MCP-TOOL-GENERATION.md. apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: @@ -8,87 +15,213 @@ config: mode: conversion-listener include_consumer_groups: true tools: - - name: list-payments - description: Retrieves a paginated list of payments in the classic-models CRM. - annotations: - title: List all payments - read_only_hint: true - idempotent_hint: true - destructive_hint: false - open_world_hint: false - acl: - allow: - - admin - - read_only - - product_manager - - customer - - support - method: GET - scheme: http - host: ${REST_HOSTNAME} - path: /payments/v1/payments/ - - name: get-payment - description: Retrieves a single payment by customer number and check number. - annotations: - title: Get a payment - read_only_hint: true - idempotent_hint: true - destructive_hint: false - open_world_hint: false - acl: - allow: - - admin - - read_only - - product_manager - - customer - - support - method: GET - scheme: http - host: ${REST_HOSTNAME} - path: /payments/v1/payments/{customernumber}/{checknumber}/ - parameters: - - name: customernumber - in: path - required: true - description: The customer's unique number. - schema: {} - - name: checknumber - in: path - required: true - description: The payment's check number. - schema: {} - - name: create-payment - description: Records a new payment in the CRM. - annotations: - title: Create a payment - read_only_hint: false - idempotent_hint: false - destructive_hint: false - open_world_hint: false - acl: - allow: - - admin - method: POST - scheme: http - host: ${REST_HOSTNAME} - path: /payments/v1/payments/ - request_body: - required: true + - annotations: + title: List all payments + read_only_hint: true + idempotent_hint: true + destructive_hint: false + open_world_hint: false + description: Retrieve a paginated list of all customer payment records with amounts and dates. + method: GET + name: list-payments + parameters: + - description: A page number within the paginated result set. + in: query + name: page + required: false + schema: + type: integer + - description: Number of results to return per page. + in: query + name: page_size + required: false + schema: + type: integer + path: /payments/v1/payments/ + acl: + allow: + - admin + - read_only + - product_manager + - customer + - support + scheme: http + host: ${REST_HOSTNAME} + responses: + '200': content: application/json: schema: type: object properties: - customernumber: + count: type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=4 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=2 + results: + type: array + items: + type: object + description: Customer payment records + properties: + id: + type: integer + readOnly: true + checknumber: + type: string + maxLength: 50 + paymentdate: + type: string + format: date + amount: + type: string + format: decimal + pattern: ^-?\d{0,8}(?:\.\d{0,2})?$ + customernumber: + type: integer + maximum: 2147483647 + minimum: -2147483648 + required: + - amount + - checknumber + - customernumber + - id + - paymentdate + - annotations: + title: Get a specific payment + read_only_hint: true + idempotent_hint: true + destructive_hint: false + open_world_hint: false + description: Retrieve detailed information about a specific payment by customer number and check number. + method: GET + name: get-payment + parameters: + - description: The check number + in: path + name: checknumber + required: true + schema: + type: string + - description: The customer number + in: path + name: customernumber + required: true + schema: + type: integer + path: /payments/v1/payments/{customernumber}/{checknumber}/ + acl: + allow: + - admin + - read_only + - product_manager + - customer + - support + scheme: http + host: ${REST_HOSTNAME} + responses: + '200': + content: + application/json: + schema: + type: object + description: Customer payment records + properties: + id: + type: integer + readOnly: true checknumber: type: string + maxLength: 50 paymentdate: type: string + format: date amount: type: string + format: decimal + pattern: ^-?\d{0,8}(?:\.\d{0,2})?$ + customernumber: + type: integer + maximum: 2147483647 + minimum: -2147483648 required: - - customernumber - - checknumber - - paymentdate - - amount + - amount + - checknumber + - customernumber + - id + - paymentdate + - annotations: + title: Create a new payment + read_only_hint: false + idempotent_hint: false + destructive_hint: false + open_world_hint: false + description: Record a new customer payment with check number, amount, and payment date. + method: POST + name: create-payment + path: /payments/v1/payments/ + request_body: + content: + application/json: + schema: + properties: + amount: + type: string + checknumber: + type: string + customernumber: + type: integer + paymentdate: + type: string + required: + - amount + - checknumber + - customernumber + - paymentdate + type: object + required: true + acl: + allow: + - admin + scheme: http + host: ${REST_HOSTNAME} + responses: + '201': + content: + application/json: + schema: + type: object + description: Customer payment records + properties: + id: + type: integer + readOnly: true + checknumber: + type: string + maxLength: 50 + paymentdate: + type: string + format: date + amount: + type: string + format: decimal + pattern: ^-?\d{0,8}(?:\.\d{0,2})?$ + customernumber: + type: integer + maximum: 2147483647 + minimum: -2147483648 + required: + - amount + - checknumber + - customernumber + - id + - paymentdate diff --git a/kong/mcp/tools-policy.yaml b/kong/mcp/tools-policy.yaml new file mode 100644 index 0000000..0120e24 --- /dev/null +++ b/kong/mcp/tools-policy.yaml @@ -0,0 +1,20 @@ +# Which operations of openapi.yaml become MCP tools, and who may call each. +# +# This file is the allow-list as well as the ACL: an operation that is not +# named here does not become a tool. Kong's generator exposes every operation +# it finds and can express no authorization at all from a bearer-token spec — +# see k8s-platform/MCP-TOOL-GENERATION.md, limits 1 and 5. +# +# `allow` lists consumer groups, which come from realm_access.roles in the end +# user's own token. Kong applies them at tools/list, so a caller never sees a +# tool it may not call. + +mcp_name: payments-mcp + +tools: + list-payments: + allow: [admin, read_only, product_manager, customer, support] + get-payment: + allow: [admin, read_only, product_manager, customer, support] + create-payment: + allow: [admin]