REST connector
The REST connector turns an HTTP API into a fixed set of tools. The agent can call only the tools you declare, on the methods and path prefixes you allow, and never sees the credential.
A complete example
Section titled “A complete example”# The REST connector over examples/mock-orders (S16). Create it in the dev org:# make mock-orders # in another terminal# deedglass connector create --config examples/connectors/orders.yaml# deedglass connector credentials set orders --from-env MOCK_ORDERS_TOKEN# deedglass connector test orders# Never register it in the Acme demo org: that org's "orders" is the MCP-wrapped Postgres server.type: restname: ordersdescription: The mock orders API (examples/mock-orders).config: base_url: http://127.0.0.1:8090 # dev only (DEEDGLASS_ALLOW_PRIVATE_NETWORKS=1); prod needs https auth: { kind: bearer } # bearer | header | basic | query | none allowed_methods: [GET, PATCH] allowed_path_prefixes: [/v1/orders] timeout_ms: 10000 # max 60000 max_response_bytes: 4194304 # max 16 MiB redirects: same_host # none | same_host (writes never follow one) send_action_id: true test: { method: GET, path: /v1/health } tools: - name: get description: Read one order. method: GET path: /v1/orders/{id} args: { id: { in: path, type: string, pattern: "^[0-9]{1,12}$", required: true } } - name: update_status description: Set an order's status. method: PATCH path: /v1/orders/{id} idempotency_header: Idempotency-Key # value = the action id args: id: { in: path, type: string, pattern: "^[0-9]{1,12}$", required: true } status: { in: body, type: string, enum: [pending, shipped, cancelled], required: true } readback: # S19: after a write, read the order back (L1) tool: get # a read tool of this connector (checked when saved) args: { id: "{{args.id}}" } # whole-value templates only: {{args.<path>}} or {{result.body.<path>}} expect: { "body.status": "{{args.status}}" } # exact, per-field comparison consistency: strong # strong (1 attempt) | eventual (attempts × interval_ms) attempts: 1 # 1..5; eventual defaults to 3 interval_ms: 300 # 100..2000 on_not_found: gap # gap | violation postcondition: 'observation.status == 200 && observation.body.id == int(args.id)' # optional CEL, for checks expect can't expressThe rules it enforces
Section titled “The rules it enforces”- Only
allowed_methodson paths underallowed_path_prefixes. Path arguments are validated against their patterns and can’t add segments. - Production needs
https. Every request goes through the egress door, which refuses private, link-local and metadata addresses unless a dev override is on. - Response bodies are capped (
max_response_bytes, 16 MiB at most). Writes never follow a redirect. - With
idempotency_header, each write sends the action id, so a retried action can’t apply twice. - A
readbackreads the record after a write and compares the fields you name: L1 Confirmed.
The full key list and every check are in the connectors overview.
What it doesn’t do
Section titled “What it doesn’t do”- It doesn’t discover an API. Every tool is declared.
- L1 compares only the fields you name in
expect. - An API that answers consistently but falsely can’t be caught by reading it back.