arizuko › howto › Add a connector
connectors
A connector gives an agent a tool that calls an external API. The credential of that API stays on the host and never enters the guest. You write one TOML block, store the secret, and grant the scope to the folders that get the tool. This page adds one connector for a real API.
Connectors explains what a connector is and why the credential stays on the host.
The far side decides the transport
If the far side is an MCP server that answers over HTTP, use transport = "mcp" and declare no tools, because the server publishes its own list. If it is a normal REST API, use transport = "rest" and one [[connector.tool]] for each endpoint that you expose. The steps below use the REST case, because it has more choices.
One block in connectors.toml declares the connector
routd reads connectors.toml in the instance directory, next to docker-compose.yml. Make the file if it does not exist.
[[connector]]
name = "statuspage"
transport = "rest"
url = "https://api.statuspage.io/v1"
secrets = ["STATUSPAGE_TOKEN"]
headers = { Authorization = "OAuth {secret:STATUSPAGE_TOKEN}" }
[[connector.tool]]
name = "incident_list"
description = "List open incidents for a status page."
scope = "ext:statuspage:incident:read"
method = "GET"
path = "/pages/{page_id}/incidents/unresolved"
[[connector.tool]]
name = "incident_create"
description = "Open an incident on a status page."
scope = "ext:statuspage:incident:write"
method = "POST"
path = "/pages/{page_id}/incidents"
Two details decide whether the first call works. The Authorization value is a literal string, so you must write the correct scheme word: OAuth here, not Bearer. And {page_id} is a path placeholder, so it becomes a required argument of both tools. You do not declare it.
The secret goes into the secrets table, not into .env
At each call, the connector reads the keys in secrets from the secrets table. Set the key for the folder that uses it:
arizuko secret -i <instance> set main/infra STATUSPAGE_TOKEN --value 'sp_live_REPLACE_ME'
A person can store an own key. For turns that the person starts, that key wins over the folder key:
arizuko user-secret -i <instance> set 'slack:user/U123' STATUSPAGE_TOKEN --value 'sp_live_REPLACE_ME'
The connector reads only this row. The .env of the instance is the environment of the daemons. The connector never sends a STATUSPAGE_TOKEN from .env. The two places can hold different values under one name.
A folder sees the tool only with the grant
A folder without the scope of a tool does not see the tool in tools/list. Read and write are two scopes, so you can grant them separately:
arizuko group -i <instance> grant folder:main/infra 'main/infra/**' 'ext:statuspage:incident:read'
arizuko group -i <instance> grant folder:main/infra 'main/infra/**' 'ext:statuspage:incident:write'
routd loads connectors at start
routd reads the connectors when it starts, so restart the instance before you look for the tool:
sudo systemctl restart arizuko_<instance>
Then ask the agent in the granted folder for its tools. The tool name is <connector>_<tool>, here statuspage_incident_list. If the tool is missing, check the grant first. A missing scope gives no tool and no error message, by design.
Four problems have a known cause
- The tool is missing
- The folder does not hold the scope, or the block did not load.
routdrefuses a connector at load when itstransportis notmcporrest, or when arestblock has no[[connector.tool]]. The error names the connector. - The API returns 401
- Check that the secret is set for the folder or the user in the
secretstable, not in.env. When a key has no value, the connector sends no placeholder. It drops the whole header, so the request has no credential. - The agent says that the answer is empty
- On success, a connector returns only the response body, with no status code. An endpoint that answers 204 with no body therefore looks like nothing happened. For a status of 400 or higher, the agent gets an error with the status and the body.
- The call reaches a host outside the egress list of the folder
- This is expected. The request leaves from
routdon the host, not from the network of the agent, so the egress allowlist does not apply. The grant is the limit here.
A Connect flow needs an OAuth provider
If the service uses a "Connect" flow and not a pasted key, use an OAuth provider. arizuko then runs the OAuth flow and refreshes the token, and the connector reads the stored token.