diff --git a/kong/mcp/ai-mcp-proxy.yaml b/kong/mcp/ai-mcp-proxy.yaml index 4175726..53b44fd 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,260 +15,822 @@ config: mode: conversion-listener include_consumer_groups: true tools: - - name: list-offices - description: Retrieves a paginated list of offices in the classic-models organization. - annotations: - title: List all offices - read_only_hint: true - idempotent_hint: true - destructive_hint: false - open_world_hint: false - # Verified against ReferenceDataPermission.check() — read_only, - # product_manager, support pass for SAFE_METHODS; customer has NO - # access at all (not in the allow-list, unlike every other domain - # built this session). Not guessed — this domain is internal staff - # data, the backend enforces that explicitly. - acl: - allow: - - admin - - read_only - - product_manager - - support - method: GET - scheme: http - host: ${REST_HOSTNAME} - path: /workforce/v1/offices/ - - name: get-office - description: Retrieves a single office by office code. - annotations: - title: Get an office - read_only_hint: true - idempotent_hint: true - destructive_hint: false - open_world_hint: false - acl: - allow: - - admin - - read_only - - product_manager - - support - method: GET - scheme: http - host: ${REST_HOSTNAME} - path: /workforce/v1/offices/{officecode}/ - parameters: - - name: officecode - in: path - required: true - description: The office's unique code. - schema: {} - - name: get-office-employees - description: Retrieves all employees working in a specific office. - annotations: - title: Get office employees - read_only_hint: true - idempotent_hint: true - destructive_hint: false - open_world_hint: false - acl: - allow: - - admin - - read_only - - product_manager - - support - method: GET - scheme: http - host: ${REST_HOSTNAME} - path: /workforce/v1/offices/{officecode}/employees/ - parameters: - - name: officecode - in: path - required: true - description: The office's unique code. - schema: {} - - name: create-office - description: Creates a new office in the organization. - annotations: - title: Create an office - read_only_hint: false - idempotent_hint: false - destructive_hint: false - open_world_hint: false - # Writes are admin-only under ReferenceDataPermission (check() - # returns False for non-admin on any non-SAFE method). - acl: - allow: - - admin - method: POST - scheme: http - host: ${REST_HOSTNAME} - path: /workforce/v1/offices/ - request_body: - required: true + - annotations: + title: List all offices + read_only_hint: true + idempotent_hint: true + destructive_hint: false + open_world_hint: false + description: Retrieve a paginated list of all company office locations worldwide. + method: GET + name: list-offices + 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: /workforce/v1/offices/ + acl: + allow: + - admin + - read_only + - product_manager + - support + scheme: http + host: ${REST_HOSTNAME} + responses: + '200': content: application/json: schema: type: object + properties: + 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: Company office locations + properties: + officecode: + type: string + maxLength: 10 + city: + type: string + maxLength: 50 + phone: + type: string + maxLength: 50 + addressline1: + type: string + maxLength: 50 + addressline2: + type: string + nullable: true + maxLength: 50 + state: + type: string + nullable: true + maxLength: 50 + country: + type: string + maxLength: 50 + postalcode: + type: string + maxLength: 15 + territory: + type: string + maxLength: 10 + required: + - addressline1 + - city + - country + - officecode + - phone + - postalcode + - territory + - annotations: + title: Get a specific office + read_only_hint: true + idempotent_hint: true + destructive_hint: false + open_world_hint: false + description: Retrieve detailed information about a specific office by its code. + method: GET + name: get-office + parameters: + - description: A unique value identifying this office. + in: path + name: officecode + required: true + schema: + type: string + path: /workforce/v1/offices/{officecode}/ + acl: + allow: + - admin + - read_only + - product_manager + - support + scheme: http + host: ${REST_HOSTNAME} + responses: + '200': + content: + application/json: + schema: + type: object + description: Company office locations properties: officecode: type: string + maxLength: 10 city: type: string + maxLength: 50 phone: type: string + maxLength: 50 addressline1: type: string + maxLength: 50 addressline2: type: string + nullable: true + maxLength: 50 state: type: string + nullable: true + maxLength: 50 country: type: string + maxLength: 50 postalcode: type: string + maxLength: 15 territory: type: string + maxLength: 10 required: - - officecode - - city - - phone - - addressline1 - - country - - postalcode - - territory - - name: list-employees - description: Retrieves a paginated list of employees in the classic-models organization. - annotations: - title: List all employees - read_only_hint: true - idempotent_hint: true - destructive_hint: false - open_world_hint: false - acl: - allow: - - admin - - read_only - - product_manager - - support - method: GET - scheme: http - host: ${REST_HOSTNAME} - path: /workforce/v1/employees/ - - name: get-employee - description: Retrieves a single employee by employee number. - annotations: - title: Get an employee - read_only_hint: true - idempotent_hint: true - destructive_hint: false - open_world_hint: false - acl: - allow: - - admin - - read_only - - product_manager - - support - method: GET - scheme: http - host: ${REST_HOSTNAME} - path: /workforce/v1/employees/{employeenumber}/ - parameters: - - name: employeenumber - in: path - required: true - description: The employee's unique number. - schema: {} - - name: get-employee-reports - description: Retrieves all employees reporting to a specific manager. - annotations: - title: Get employee reports - read_only_hint: true - idempotent_hint: true - destructive_hint: false - open_world_hint: false - acl: - allow: - - admin - - read_only - - product_manager - - support - method: GET - scheme: http - host: ${REST_HOSTNAME} - path: /workforce/v1/employees/{employeenumber}/reports/ - parameters: - - name: employeenumber - in: path - required: true - description: The manager's employee number. - schema: {} - - name: get-employee-customers - description: Retrieves all customers assigned to a specific sales representative. - annotations: - title: Get employee's customers - read_only_hint: true - idempotent_hint: true - destructive_hint: false - open_world_hint: false - acl: - allow: - - admin - - read_only - - product_manager - - support - method: GET - scheme: http - host: ${REST_HOSTNAME} - path: /workforce/v1/employees/{employeenumber}/customers/ - parameters: - - name: employeenumber - in: path - required: true - description: The sales rep's employee number. - schema: {} - - name: create-employee - description: Adds a new employee to the organization. - annotations: - title: Create an employee - 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: /workforce/v1/employees/ - request_body: - required: true + - addressline1 + - city + - country + - officecode + - phone + - postalcode + - territory + - annotations: + title: Get employees by office + read_only_hint: true + idempotent_hint: true + destructive_hint: false + open_world_hint: false + description: Retrieve all employees working in a specific office. This endpoint supports office management + and organizational charts. + method: GET + name: get-office-employees + parameters: + - description: The office code + in: path + name: officecode + required: true + schema: + type: string + - 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: /workforce/v1/offices/{officecode}/employees/ + acl: + allow: + - admin + - read_only + - product_manager + - support + scheme: http + host: ${REST_HOSTNAME} + responses: + '200': content: application/json: schema: type: object + properties: + 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: Employee information and hierarchy + properties: + employeenumber: + type: integer + maximum: 2147483647 + minimum: -2147483648 + lastname: + type: string + maxLength: 50 + firstname: + type: string + maxLength: 50 + extension: + type: string + maxLength: 10 + email: + type: string + maxLength: 100 + jobtitle: + type: string + maxLength: 50 + officecode: + type: string + reportsto: + type: integer + maximum: 2147483647 + minimum: -2147483648 + nullable: true + required: + - email + - employeenumber + - extension + - firstname + - jobtitle + - lastname + - officecode + - annotations: + title: Create a new office + read_only_hint: false + idempotent_hint: false + destructive_hint: false + open_world_hint: false + description: Add a new office location to the company's network. + method: POST + name: create-office + path: /workforce/v1/offices/ + request_body: + content: + application/json: + schema: + properties: + addressline1: + type: string + addressline2: + type: string + city: + type: string + country: + type: string + officecode: + type: string + phone: + type: string + postalcode: + type: string + state: + type: string + territory: + type: string + required: + - addressline1 + - city + - country + - officecode + - phone + - postalcode + - territory + type: object + required: true + acl: + allow: + - admin + scheme: http + host: ${REST_HOSTNAME} + responses: + '201': + content: + application/json: + schema: + type: object + description: Company office locations + properties: + officecode: + type: string + maxLength: 10 + city: + type: string + maxLength: 50 + phone: + type: string + maxLength: 50 + addressline1: + type: string + maxLength: 50 + addressline2: + type: string + nullable: true + maxLength: 50 + state: + type: string + nullable: true + maxLength: 50 + country: + type: string + maxLength: 50 + postalcode: + type: string + maxLength: 15 + territory: + type: string + maxLength: 10 + required: + - addressline1 + - city + - country + - officecode + - phone + - postalcode + - territory + - annotations: + title: List all employees + read_only_hint: true + idempotent_hint: true + destructive_hint: false + open_world_hint: false + description: Retrieve a paginated list of all employees in the organization with their details. + method: GET + name: list-employees + 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: /workforce/v1/employees/ + acl: + allow: + - admin + - read_only + - product_manager + - support + scheme: http + host: ${REST_HOSTNAME} + responses: + '200': + content: + application/json: + schema: + type: object + properties: + 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: Employee information and hierarchy + properties: + employeenumber: + type: integer + maximum: 2147483647 + minimum: -2147483648 + lastname: + type: string + maxLength: 50 + firstname: + type: string + maxLength: 50 + extension: + type: string + maxLength: 10 + email: + type: string + maxLength: 100 + jobtitle: + type: string + maxLength: 50 + officecode: + type: string + reportsto: + type: integer + maximum: 2147483647 + minimum: -2147483648 + nullable: true + required: + - email + - employeenumber + - extension + - firstname + - jobtitle + - lastname + - officecode + - annotations: + title: Get a specific employee + read_only_hint: true + idempotent_hint: true + destructive_hint: false + open_world_hint: false + description: Retrieve detailed information about a specific employee by their employee number. + method: GET + name: get-employee + parameters: + - description: A unique value identifying this employee. + in: path + name: employeenumber + required: true + schema: + type: integer + path: /workforce/v1/employees/{employeenumber}/ + acl: + allow: + - admin + - read_only + - product_manager + - support + scheme: http + host: ${REST_HOSTNAME} + responses: + '200': + content: + application/json: + schema: + type: object + description: Employee information and hierarchy properties: employeenumber: type: integer + maximum: 2147483647 + minimum: -2147483648 lastname: type: string + maxLength: 50 firstname: type: string + maxLength: 50 extension: type: string + maxLength: 10 email: type: string + maxLength: 100 + jobtitle: + type: string + maxLength: 50 officecode: type: string reportsto: type: integer + maximum: 2147483647 + minimum: -2147483648 + nullable: true + required: + - email + - employeenumber + - extension + - firstname + - jobtitle + - lastname + - officecode + - annotations: + title: Get employees by manager + read_only_hint: true + idempotent_hint: true + destructive_hint: false + open_world_hint: false + description: Retrieve all employees reporting to a specific manager. This endpoint supports organizational + hierarchy and team management. + method: GET + name: get-employee-reports + parameters: + - description: The employee number of the manager + in: path + name: employeenumber + required: true + schema: + type: integer + - 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: /workforce/v1/employees/{employeenumber}/reports/ + acl: + allow: + - admin + - read_only + - product_manager + - support + scheme: http + host: ${REST_HOSTNAME} + responses: + '200': + content: + application/json: + schema: + type: object + properties: + 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: Employee information and hierarchy + properties: + employeenumber: + type: integer + maximum: 2147483647 + minimum: -2147483648 + lastname: + type: string + maxLength: 50 + firstname: + type: string + maxLength: 50 + extension: + type: string + maxLength: 10 + email: + type: string + maxLength: 100 + jobtitle: + type: string + maxLength: 50 + officecode: + type: string + reportsto: + type: integer + maximum: 2147483647 + minimum: -2147483648 + nullable: true + required: + - email + - employeenumber + - extension + - firstname + - jobtitle + - lastname + - officecode + - annotations: + title: Get customers by sales rep + read_only_hint: true + idempotent_hint: true + destructive_hint: false + open_world_hint: false + description: Retrieve all customers assigned to a specific sales representative. This endpoint supports + sales rep performance tracking and customer management. + method: GET + name: get-employee-customers + parameters: + - description: The employee number of the sales representative + in: path + name: employeenumber + required: true + schema: + type: integer + - 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: /workforce/v1/employees/{employeenumber}/customers/ + acl: + allow: + - admin + - read_only + - product_manager + - support + scheme: http + host: ${REST_HOSTNAME} + responses: + '200': + content: + application/json: + schema: + type: object + properties: + 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 information and contact details + properties: + customernumber: + type: integer + maximum: 2147483647 + minimum: -2147483648 + customername: + type: string + maxLength: 50 + contactlastname: + type: string + maxLength: 50 + contactfirstname: + type: string + maxLength: 50 + phone: + type: string + maxLength: 50 + addressline1: + type: string + maxLength: 50 + addressline2: + type: string + nullable: true + maxLength: 50 + city: + type: string + maxLength: 50 + state: + type: string + nullable: true + maxLength: 50 + postalcode: + type: string + nullable: true + maxLength: 15 + country: + type: string + maxLength: 50 + creditlimit: + type: string + format: decimal + pattern: ^-?\d{0,8}(?:\.\d{0,2})?$ + nullable: true + salesrepemployeenumber: + type: integer + maximum: 2147483647 + minimum: -2147483648 + nullable: true + required: + - addressline1 + - city + - contactfirstname + - contactlastname + - country + - customername + - customernumber + - phone + - annotations: + title: Create a new employee + read_only_hint: false + idempotent_hint: false + destructive_hint: false + open_world_hint: false + description: Add a new employee to the organization with their job details and office assignment. + method: POST + name: create-employee + path: /workforce/v1/employees/ + request_body: + content: + application/json: + schema: + properties: + email: + type: string + employeenumber: + type: integer + extension: + type: string + firstname: + type: string + jobtitle: + type: string + lastname: + type: string + officecode: + type: string + reportsto: + type: integer + required: + - email + - employeenumber + - extension + - firstname + - jobtitle + - lastname + - officecode + type: object + required: true + acl: + allow: + - admin + scheme: http + host: ${REST_HOSTNAME} + responses: + '201': + content: + application/json: + schema: + type: object + description: Employee information and hierarchy + properties: + employeenumber: + type: integer + maximum: 2147483647 + minimum: -2147483648 + lastname: + type: string + maxLength: 50 + firstname: + type: string + maxLength: 50 + extension: + type: string + maxLength: 10 + email: + type: string + maxLength: 100 jobtitle: type: string + maxLength: 50 + officecode: + type: string + reportsto: + type: integer + maximum: 2147483647 + minimum: -2147483648 + nullable: true required: - - employeenumber - - lastname - - firstname - - extension - - email - - officecode - - jobtitle + - email + - employeenumber + - extension + - firstname + - jobtitle + - lastname + - officecode diff --git a/kong/mcp/tools-policy.yaml b/kong/mcp/tools-policy.yaml new file mode 100644 index 0000000..fb7fcb3 --- /dev/null +++ b/kong/mcp/tools-policy.yaml @@ -0,0 +1,32 @@ +# 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: workforce-mcp + +tools: + list-offices: + allow: [admin, read_only, product_manager, support] + get-office: + allow: [admin, read_only, product_manager, support] + get-office-employees: + allow: [admin, read_only, product_manager, support] + create-office: + allow: [admin] + list-employees: + allow: [admin, read_only, product_manager, support] + get-employee: + allow: [admin, read_only, product_manager, support] + get-employee-reports: + allow: [admin, read_only, product_manager, support] + get-employee-customers: + allow: [admin, read_only, product_manager, support] + create-employee: + allow: [admin]