Connections
Introduction
Section titled “Introduction”An agent that triages issues, reads a mailbox or files a ticket needs a credential for someone else’s service. Handing the model a token puts the token in the prompt, the logs and the checkpoint. Connections keep it in a vault on the server instead.
A connection is one account at one external provider, such as GitHub or Gmail, linked with OAuth 2 (PKCE) or an API key. The credential is stored encrypted and refreshed before it expires. Callers use it through two tools, connections_search and connections_execute; they never receive the credential.
A user may connect several accounts of one provider. An administrator may also connect an organisation account that members use but cannot connect or remove.
Three ways to use them
Section titled “Three ways to use them”| You want | Use | Read |
|---|---|---|
| Connections inside the agent server you already run | connections option of PilotooModule.forRoot |
Server integration |
| Connections in your own NestJS app, without the agent server | @pilotoo/connections-core and @pilotoo/connections-server |
Using the library |
| One shared service that many agent servers, desktops and MCP clients call | Pilotoo Connect, or your own host with the public API | Pilotoo Connect, Tools API and MCP, Remote sources |
A complete example
Section titled “A complete example”A user links their GitHub account, then asks an agent about their issues.
1. Register the provider on the server
Section titled “1. Register the provider on the server”import { githubProvider, PilotooModule } from '@pilotoo/server';
PilotooModule.forRoot({ connections: { providers: [githubProvider()], tools: true, },});CONNECTIONS_ENCRYPTION_KEYS=v1:<32 random bytes, base64>CONNECTIONS_CALLBACK_URL=https://api.example.com/connections/oauth/callbackCONNECTIONS_RETURN_ORIGINS=https://app.example.comCONNECTIONS_ROLES=member,ownerCONNECTIONS_ADMIN_ROLES=ownerGenerate the key with node -e "console.log('v1:' + require('crypto').randomBytes(32).toString('base64'))".
2. An admin enables the provider
Section titled “2. An admin enables the provider”Register an OAuth app at GitHub with the callback URL above. Then, as a user with an admin role, enable the provider with the app’s client id and secret:
curl -X PUT https://api.example.com/admin/connections/providers/github \ -H "Authorization: Bearer $ADMIN_TOKEN" -H 'Content-Type: application/json' \ -d '{ "enabled": true, "clientId": "<client id>", "clientSecret": "<client secret>" }'The settings UI does the same on an app’s page in ConnectionsAdminSection; see Settings UI. The Setup step also shows a “How to set up” guide for each app that defines one, with the exact callback URL to register.
3. The user connects
Section titled “3. The user connects”In your settings screen, the user selects Connect on GitHub. A popup opens GitHub’s consent page and the callback page closes it.
<ConnectionsSection client={connections} onConnect={(provider) => connectProvider({ client: connections, provider, opener: browserOpener, allowedOrigin })}/>4. An agent uses it
Section titled “4. An agent uses it”List the two tools in an agent definition:
tools: [connections_search, connections_execute]The user asks “what issues are open in acme/api?”. The agent searches, then executes:
{ "tool": "connections_search", "arguments": { "query": "list issues" } }{ "tool": "connections_execute", "arguments": { "name": "github__list_issues", "arguments": { "owner": "acme", "repo": "api" } } }The server opens the user’s sealed token, calls GitHub and returns { "ok": true, "result": [...] }. The model never sees the token.
Who does what
Section titled “Who does what”| Role | Does | Through |
|---|---|---|
| Host developer | Defines which providers exist and registers their tools in code. | connections option, or connectionProviders |
| Tenant admin | Enables a provider, supplies its OAuth client, narrows scopes and tools, connects organisation accounts, can revoke any connection. | /admin/connections, ConnectionsAdminSection |
| User | Connects their own accounts, picks the default, disconnects. | /connections, ConnectionsSection |
| Caller | Finds and calls provider tools as the user: an agent run, an MCP client or a script. | connections_search, connections_execute |
Access is role-gated twice: CONNECTIONS_ROLES decides who may connect and use tools, CONNECTIONS_ADMIN_ROLES who administers. Both are empty by default, which means nobody. See Authentication for roles.
What the kit guarantees
Section titled “What the kit guarantees”- A credential is never returned by any route or tool, and never written to state, the checkpoint or the stream.
- Every refusal comes back as data,
{ ok: false, error: { code, message } }, never as a thrown error. - A connection belongs to one tenant. No read or write crosses tenants.
When something does not work
Section titled “When something does not work”| Situation | Result |
|---|---|
No CONNECTIONS_ENCRYPTION_KEYS |
Nothing can be connected; routes answer unavailable (501). |
No database and no connections.storage |
Same: the routes answer 501. |
| Provider not enabled for the tenant | provider_disabled; the tool is hidden from search. |
| Refresh token refused by the provider | The connection becomes needs_reauth; the user reconnects. |
| Caller holds no connection role | forbidden. |
Next steps
Section titled “Next steps”- Using the library:
connections-coreandconnections-serverin your own NestJS host. - Tools API and MCP: serve the tools to clients outside the agent runtime.
- Remote sources: take the tools from one or several Pilotoo Connect services.
- Pilotoo Connect: the standalone service.
- Providers: define your own, and what the admin supplies.
- Agent tools: search, execute, results and errors.