Sources: APIs & integrations
The station's tools: the tenant's APIs, and the catalogue that search queries.
The APIs
apis:
- name: cuisine
openapi_url: https://api.teranga.example.sn/openapi.json
base_url: https://api.teranga.example.sn
auth: {type: api_key, key_name: X-API-Key, key_location: header, key_env: TERANGA_KEY}
operations:
- {id: getMenu, access: read}
- {id: getDeliveryOptions, access: read}
- {id: checkDeliverable, access: read}
- {id: getDeliveryPrice, access: read}
- {id: placeOrder, access: write}
- {id: createDelivery, access: write, reversible: false}
- {id: deleteCustomer, access: write, exposed: false}
operationsis an allowlist. An operation that is not in it cannot be reached, even if the OpenAPI describes it. The list is required and never empty. Do not list a write that nothing uses, except asexposed: falseto document it.
| attribute | effect |
|---|---|
id | the OpenAPI operationId. The same operation declared twice is refused. |
access | required. read changes nothing at the tenant and runs at once. write changes something and is reserved: only a submit, the submit guard (submit_guard.validate) or the sign-in (to send and check a code) calls it. Declared, never guessed from the HTTP verb: a search is often a POST. |
reversible | on a write only: the operation of the same API that undoes it, or false. false on an operation a submit calls: the MCP door announces the submit as destructive. Nothing else reads it yet. |
exposed: false | listed, checked against the OpenAPI at provisioning, but never reachable. Naming it elsewhere is refused. |
- Core refuses the contradictions at load. A write called at once (by a skill's
invoke, acheckorupdateguard) would change the tenant's record with no submit and no person to confirm. A submit that goes through a read files nothing, and the receipt would say otherwise. - The key never appears in the file.
key_envnames an environment variable. The model does not see it and does not send it: so it cannot widen what the key allows. - Separate reads and writes into two entries when the tenant has two keys, or simply so that the boundary shows in the config:
apis:
- name: rh-lecture
operations:
- {id: getTimesheets, access: read}
- {id: getOvertimeReport, access: read}
auth: {type: api_key, key_name: X-RH-Key, key_location: header, key_env: RH_READ_KEY}
# …
- name: rh-ecriture
operations:
- {id: approveTimesheets, access: write}
auth: {type: api_key, key_name: X-RH-Key, key_location: header, key_env: RH_WRITE_KEY}
# …
One identity per key
Today, an API's key is the station's key: everyone talks to the tenant under the same
identity. Two managers using the same station are, for the HR tool, the same manager.
Per-person identity comes with the target version (on_behalf_of: identity).
The catalogue
catalog:
from_skill: takeMealSelection # the skill with kinds that returns the whole catalogue
mode: live # live | indexed
live: each search queries the tenant's search (under thequery_argparameter), and shows its results in its order. Always up to date, no index.indexed: the catalogue is read once and indexed, then read again when the station is provisioned or resynchronised; nothing watches the source. Semantic search; the skill must return the whole catalogue, without pagination.