Skip to content

REST tools

A provider can offer operations of any REST API that has an OpenAPI 3.0 or 3.1 document as BNW tools. Each shared operation becomes its own tool.rest capability. Other nodes invoke it like any tool, and agents see it as a native tool when its schema is small enough. The API itself is called by the provider’s node, with the provider’s credentials, on the provider’s terms.

Like the MCP and inference adapters, the REST adapter (bnw-rest) defines no replicated objects. The capability’s signed descriptor says what the tool takes. This node’s registry (rest-providers.json) says which operation of which API answers it, and that registry is never shared.

Terminal window
# 1. Read the document (a file or an HTTPS URL). It is kept on this node, named by hash.
bnw rest import https://api.example.com/openapi.json
# 2. Share operations by operationId or "METHOD /path" (needs the running node).
bnw provider secret set PETS_API_KEY # the value, from standard input
bnw rest share <SPEC_HASH> listPets getPet \
--server https://api.example.com/v1 \
--auth api-key --api-key-name X-API-Key --secret-env PETS_API_KEY \
--allow-remote-execution --access contacts --mode ask

bnw rest import prints the document’s servers, its security schemes, and every operation. Operations are marked changes data, schema too large for agents, or cannot be shared, the last with the reason. In the web client, Provide a capability → REST API does the same. It takes the document’s address (fetched by the node), the document pasted in (up to 64 KiB), or the hash of one already imported.

Sharing again updates the capabilities of operations already shared from the same server; nothing is published twice. bnw rest list shows the connected APIs, bnw rest call <CAPABILITY_ID> input.json tests one directly (a real call, without an invocation), and bnw rest remove disconnects one.

  • Input. One JSON object: the operation’s path, query, and header parameters as properties, and the request body under body. If two parameters share a name, every parameter is prefixed with its location (path.id, query.id) for that operation. The schema comes from the document with local $refs resolved, and it is published with the capability.
  • Output. {"status": <HTTP status>, "headers": {...}, "body": ...}. The body is JSON when the API answers JSON, and text otherwise. Only content-type, location, retry-after, and etag headers are passed on. Any status is an answer, including 404 or 500. A 401, binary content, or an answer over 1 MiB is a failed execution.

Operations that cannot be called faithfully are not offered: non-JSON request bodies, required cookie parameters, object-valued path or query parameters, external or recursive $refs, and input schemas over 64 KiB.

Credentials are always named, never given: their values live in the provider’s secrets file (bnw provider secret set) or environment.

--auth Sends
bearer --secret-env NAME Authorization: Bearer <token>
api-key --api-key-name N --api-key-in header|query --secret-env NAME the key in that header or query parameter
basic --username U --secret-env NAME HTTP Basic
oauth --oauth-scheme S --client-id ID [--client-secret-env NAME] [--scope ...] an OAuth access token

OAuth endpoints come from the document’s security scheme, never from the request:

  • Client credentials. Tokens are fetched when needed and reused until a minute before they expire.
  • Authorization code. Uses PKCE (S256). Sign in once with bnw rest authorize <CAPABILITY_ID>, or on the capability’s setup page. On a node without a browser, open the URL elsewhere and paste back the address the browser ends up at. Use --port for APIs whose client allows only a fixed redirect URI.

Tokens are sealed to the provider device. Refreshes are serialized across tasks and processes, so a rotating refresh token is never spent twice. Operations shared together use the first one’s sign-in. When the API refuses the sign-in, the tools show as needing sign-in, their offers stop renewing, and new invocations wait.

  • Fixed destination. The server is chosen when sharing. Callers fill in parameters, never the host. Each path value is percent-encoded as one segment, and . and .. are refused. The finished URL must still be on the registered origin and under its base path. Header parameters are limited to those the document declares, never Host, Authorization, Cookie, or hop-by-hop headers, and values with control characters are refused. Redirects are never followed.
  • Public addresses only. Unless the server was registered as localhost, every address its name resolves to must be public. The address that was checked is the one connected to, so a second DNS answer cannot redirect the call. A server on the local network needs --allow-private-network.
  • Consent. Decrypted inputs go to a server off this computer only with --allow-remote-execution. Operations other than GET, HEAD, and OPTIONS may change data and need --allow-side-effects; consider --mode ask for them.
  • Pinned operations. Sharing records a fingerprint of the operation: method, path, server, input schema, body media type, header parameters, and security. It is re-derived from the stored document before every call. If the document or server changed, the tool stops until the operation is reviewed and shared again.
  • Early refusal. Unknown inputs, missing required inputs, and malformed values are refused before the at-most-once claim, so a bad request never reaches the API.
  • OpenAPI support. Swagger 2.0 is not read; convert it to OpenAPI 3 first. The OpenID Connect, implicit, and password flows and cookie authentication are not supported.
  • Bodies. Request bodies must be JSON, and responses are passed on as JSON or text, not files.
  • Web client. A pasted document can be up to 64 KiB. Larger ones import by address, or from a file with the CLI.