Pilotoo Connect
Introduction
Section titled “Introduction”Pilotoo Connect is a standalone service built on the connections library. A person signs in with Google, connects accounts (GitHub and Gmail), and creates personal access tokens. Claude, Cursor, a script or a Pilotoo server then use those accounts through the Tools API and MCP with a token. It is apps/connect-api (NestJS and PostgreSQL) and apps/connect-web (the web app), built into one Docker image.
Running it with Docker
Section titled “Running it with Docker”Build from the repository root:
docker build -f apps/connect-api/Dockerfile -t pilotoo-connect .docker run --env-file connect.env -p 4310:4310 pilotoo-connectThe image holds the API and the built web app, runs as an unprivileged user and listens on PORT (4310). Put it behind a proxy that terminates TLS; the app trusts one proxy hop. On boot it creates the pilotoo_app schema and its tables in the database you point it at.
DATABASE_URL=postgres://user:password@db:5432/pilotoo_connectCONNECT_PUBLIC_URL=https://connect.example.comCONNECT_SESSION_SECRET=<32 or more random characters>GOOGLE_CLIENT_ID=<web client id>GOOGLE_CLIENT_SECRET=<web client secret>CONNECTIONS_ENCRYPTION_KEYS=v1:<32 random bytes, base64>CONNECT_ALLOWED_EMAILS=ada@example.com,grace@example.comCONNECT_ADMIN_EMAILS=ada@example.comBoot fails naming every required setting that is missing, never a value.
Settings
Section titled “Settings”| Variable | Meaning |
|---|---|
DATABASE_URL |
Required. PostgreSQL. |
CONNECT_PUBLIC_URL |
Required. The public origin; https outside localhost. Sign-in and OAuth callbacks derive from it. |
CONNECT_SESSION_SECRET |
Required, 32 or more characters. Signs the session and login cookies. |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET |
Required. The Google OAuth web client used to sign in. |
CONNECTIONS_ENCRYPTION_KEYS |
Required. version:base64 32-byte keys, current first. Seals every credential. |
CONNECT_ALLOWED_EMAILS |
Comma-separated emails that may sign in. * admits every verified Google account. Unset admits nobody. |
CONNECT_ADMIN_EMAILS |
Comma-separated emails that also administer the connections. |
PORT |
Default 4310. |
CONNECT_TENANT |
Default connect. |
CONNECT_WEB_DIST |
Folder of the built web app. The Docker image sets it. |
CONNECT_OIDC_ISSUER |
Default https://accounts.google.com. |
CONNECTIONS_ROLES, CONNECTIONS_ADMIN_ROLES |
Default member and admin. |
CONNECT_LINK_CLIENTS |
JSON array of the products whose users may link their Connect account: [{"id","name","redirectUri","secret"}]. Unset, the link routes answer 404. |
CONNECTIONS_CALLBACK_URL and CONNECTIONS_RETURN_ORIGINS default to ${CONNECT_PUBLIC_URL}/connections/oauth/callback and its origin. The other CONNECTIONS_* variables are those of Server integration.
Setting up Google sign-in
Section titled “Setting up Google sign-in”In the Google Cloud console create an OAuth client of type Web application and add:
- Authorized JavaScript origin: your
CONNECT_PUBLIC_URL. - Authorized redirect URI:
${CONNECT_PUBLIC_URL}/auth/google/callback.
For local development use http://localhost:4310 in both. Run it with CONNECT_ENV_FILE pointing at an env file, and pnpm --filter @pilotoo/connect-api dev.
Enabling providers
Section titled “Enabling providers”Sign in as an admin and open Organisation. For each provider, enter the OAuth client id and secret of an app you registered at the provider. Each provider’s card has a “How to set up” guide with the console link, the exact callback URL (${CONNECT_PUBLIC_URL}/connections/oauth/callback) and the scopes. Members then connect their own accounts under Connections.
Gmail needs its own Google OAuth client, not the sign-in one. See Providers for GitHub and Gmail notes.
Connecting Claude, Cursor or a script
Section titled “Connecting Claude, Cursor or a script”Open Access tokens, create a token and copy it: it is shown once and only its hash is stored. A token acts as you, and revoking it makes its next use answer 401. Then point the client at the MCP endpoint:
claude mcp add --transport http connect https://connect.example.com/mcp --header "Authorization: Bearer pc_..."{ "mcpServers": { "connect": { "url": "https://connect.example.com/mcp", "headers": { "Authorization": "Bearer pc_..." } } } }A script calls POST /api/tools/search and POST /api/tools/execute with the same header. The Connect a client screen shows the endpoint to copy. Your Pilotoo servers and the desktop app use the same token as a remote source.
Linking another product
Section titled “Linking another product”A product listed in CONNECT_LINK_CLIENTS, such as Brain, can use a person’s connections on their behalf after they consent once:
- The product sends the person to
/auth/link/authorize?client_id=…&redirect_uri=…&state=…. Connect asks them to sign in if needed, then shows a consent page naming the product and the account. - On Allow, Connect redirects to the registered
redirectUriwith a one-timecodeand the samestate. On Cancel, witherror=access_denied. - The product’s server posts
{client_id, client_secret, code, redirect_uri}to/auth/link/tokenwithin a minute and receives a personal token named after the product. - To unlink, the product posts to
/auth/link/revokewith that token asAuthorization: Bearer. The person can also revoke it under Access tokens.
[{ "id": "brain", "name": "Brain", "redirectUri": "https://brain.example.com/api/connect/link/callback", "secret": "<at least 32 characters, shared with that product>" }]Activity
Section titled “Activity”The Activity screen lists your own tool calls, newest first: GET /activity?limit=&cursor= (limit 1 to 200, default 50).
Routes
Section titled “Routes”| Route | Who |
|---|---|
GET /auth/google/start (optional next, a path on this site), GET /auth/google/callback, POST /auth/logout |
Anonymous |
GET, POST /auth/link/authorize |
Signed in; an anonymous GET is sent to sign in first |
POST /auth/link/token |
A link client, by its secret |
POST /auth/link/revoke |
Authorization: Bearer pc_...: the token revokes itself |
GET /api/session, GET /health |
Anonymous |
GET /me, GET /activity |
Signed in |
GET /tokens, POST /tokens (body { name }), DELETE /tokens/:id |
Signed in |
/connections/** |
Signed in; the OAuth callback is anonymous |
/admin/connections/** |
Users in CONNECT_ADMIN_EMAILS |
POST /api/tools/search, POST /api/tools/list, POST /api/tools/execute, POST /mcp |
Session cookie or Authorization: Bearer pc_... |
Tokens are pc_ plus random bytes. They carry no read-only scope: asking for one is refused.
Next steps
Section titled “Next steps”- Remote sources: use this service from a Pilotoo server or the desktop.
- Providers: Connect ships GitHub and Gmail; another provider is added in code.