Using the library
Introduction
Section titled “Introduction”Connections ship as two packages. @pilotoo/connections-core has no framework: the model, the vault cipher, the OAuth client, the credential resolver, the sharing policy, the provider catalog, the ConnectionStorage port and the built-in GitHub and Gmail providers. @pilotoo/connections-server is the NestJS adapter: the user and admin routes, PostgreSQL storage, maintenance, the two tools and the public tools API. @pilotoo/server re-exports the common names, so a Pilotoo host needs neither directly.
Mounting connections in a NestJS app
Section titled “Mounting connections in a NestJS app”connectionProviders returns the providers to add to your module; connectionControllers are the controllers.
import { Module } from '@nestjs/common';import { APP_GUARD } from '@nestjs/core';import { createToolRegistry } from '@pilotoo/agent-runtime';import { githubProvider, gmailProvider } from '@pilotoo/connections-core';import { connectionControllers, connectionProviders } from '@pilotoo/connections-server';
import { DatabaseService } from './database.service';import { IdentityGuard } from './identity.guard';
@Module({ controllers: [...connectionControllers], providers: [ { provide: 'ENV', useValue: process.env }, { provide: 'TOOL_REGISTRY', useFactory: createToolRegistry }, DatabaseService, // exposes `requiredPool`, a pg Pool { provide: APP_GUARD, useClass: IdentityGuard }, ...connectionProviders( { providers: [githubProvider(), gmailProvider()], publicApi: true }, { env: 'ENV', postgres: DatabaseService, toolRegistry: 'TOOL_REGISTRY' }, ), ],})export class AppModule {}The second argument names what the host supplies, as injection tokens:
| Port | Resolves to |
|---|---|
env |
A NodeJS.ProcessEnv: settings, roles, the vault keys and the maintenance interval are read from it. |
postgres |
An object with requiredPool, a pg Pool. null when the host has no database; then give storage in the options. |
toolRegistry |
The ToolRegistry the opt-in tools register into (from @pilotoo/agent-runtime). |
The first argument is ConnectionsHostOptions; see Server integration for tools, storage and http, and Tools API and MCP for publicApi.
Supplying identity
Section titled “Supplying identity”Every route reads the caller from request.identity, an Identity of { subject, tenant, roles }. Your guard sets it, and lets through routes marked anonymous, which is only the OAuth callback.
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';import { Reflector } from '@nestjs/core';import { ANONYMOUS_ROUTE, type IdentifiedRequest } from '@pilotoo/connections-server';
@Injectable()export class IdentityGuard implements CanActivate { constructor(private readonly reflector: Reflector) {}
async canActivate(context: ExecutionContext): Promise<boolean> { const request = context.switchToHttp().getRequest<IdentifiedRequest>(); const identity = await resolveCaller(request); // yours if (identity) request.identity = identity; else if (!this.reflector.getAllAndOverride<boolean>(ANONYMOUS_ROUTE, [context.getHandler(), context.getClass()])) throw new UnauthorizedException(); return true; }}A route without an identity and without the anonymous mark never runs. The roles in the identity are matched against CONNECTIONS_ROLES and CONNECTIONS_ADMIN_ROLES.
Without NestJS
Section titled “Without NestJS”@pilotoo/connections-core alone gives you the services (ConnectionService, ConnectionAdminService, ConnectionCredentialResolver, ProviderCatalog), the AesGcmCredentialCipher and the tool sources. Implement ConnectionStorage for your database and build the services yourself; the Postgres implementation in connections-server is the reference.
import { createCompositeToolSource, createRemoteToolSource, githubProvider } from '@pilotoo/connections-core';Next steps
Section titled “Next steps”- Tools API and MCP: expose the tools over HTTP and MCP.
- Remote sources: call a connections service instead of keeping a vault.
- Providers: the
ProviderDefinitionyou pass inproviders.