Operation Describer
Normalises ApiEndpointCatalogue rows into enriched MCP/CLI descriptions with OpenAPI parameters, request bodies, responses, and SchemaRegistry filter metadata.
Overview
App\Services\Api\OperationDescriber turns a catalogue API endpoint into the description payload used by MCP tool schemas (describe-endpoint, curated argument derivation) and signals:api describe.
It merges:
- ApiEndpointCatalogue identity (route name, method, URI, ability, price weight, path params)
- OpenAPI (cached Scramble document) for parameters, request body, and responses
- SchemaRegistry filter/sort/search field lists when the catalogue resource maps to a
HasSchemamodel
Like OperationInvoker, this is a shared service rather than a registration registry.
Public surface
| Method | Purpose |
|---|---|
describe() |
Enrich one endpoint by route name, or null when unknown |
describeByMethodUri() |
Enrich by HTTP method + URI (path params neutralised) |
describeAll() |
List catalogue rows; pass $enriched = true to expand each |
search() |
Filter catalogue by route/resource/summary/URI substring |
Description shape
[
'route_name' => 'api.v1.catalogue_items.index',
'method' => 'GET',
'uri' => '/api/v1/catalogue_items',
'resource' => 'catalogue_items',
'operation' => 'index',
'summary' => '…',
'description' => '…',
'required_ability' => 'catalogue-items:read',
'price_weight' => 2,
'route_path_params' => [],
'parameters' => [/* path/query/header */],
'request_body' => null|array, // content keyed by media type
'responses' => [/* status => description + schema */],
'schema' => null|array{ // SchemaRegistry projection
model, model_class, filterable, sortable, searchable
},
]
Path matching strips the configured Scramble api_path prefix so catalogue URIs (/api/v1/...) align with Scramble paths (/v1/...), including write request bodies.
Consumers
- MCP
DescribeEndpointmeta-tool and curated tool argument schemas signals:api list(search filter) andsignals:api describe- Architecture gate
tests/Feature/Architecture/McpCliParityTest.php
Worked example
$description = app(OperationDescriber::class)->describe('api.v1.catalogue_items.index');
$description['required_ability']; // catalogue-items:read
$description['schema']['filterable']; // includes name, …
$description['parameters']; // OpenAPI query/path params
$description['responses']['200']['schema']; // typed success payload
Unknown route names return null. Endpoints without a schema-backed resource set schema to null (for example system health).