Skip to content

App Connect

App Connect is a multi-tenant API gateway and integration platform. It lets the Nexivo platform connect to any third-party service — CRMs, ticketing systems, ERPs, and more — by registering an App Connector with a target URL and authentication config. The gateway then transparently proxies requests from AI agents (and other internal services) to those upstream APIs, handling auth injection, path rewriting, and OpenAPI-based tool discovery automatically.

Source

IdeaProjects/NHDS/app-connect — Java 25 / Spring Boot 4.0.6 / Spring Cloud Gateway WebMVC


Tech Stack

Layer Technology
Framework Spring Boot 4.0.6
Java 25 (virtual threads enabled)
Gateway Spring Cloud Gateway Server WebMVC (servlet, non-reactive)
Route engine Apache Camel 4.20.0 (YAML DSL)
Database PostgreSQL + Spring Data JPA + Flyway
Caching / Messaging Redis Pub/Sub (cross-instance route refresh)
Auth Spring Security OAuth2 Client + Keycloak Admin Client
Observability OpenTelemetry + Prometheus + Spring Actuator

Core Concepts

graph TD
    APP[App\nOpenAPI spec + MCP config] --> AC[AppConnector\nTenant-scoped instance]
    APP --> RES[Resource\nCamel route template]
    RES --> RQ[ResourceQuery\nParameterised Camel route]
    APP --> EV[AppEvent\nEvent definition]
    AC --> MCP[MCPServer\nOAuth2-secured MCP endpoint]
Concept Description
App A reusable blueprint for a third-party service — holds the OpenAPI spec, default auth config, and MCP configuration
AppConnector A tenant-specific instantiation of an App — has its own URI, auth credentials, and Keycloak service account
Resource A named entity exposed by the app (e.g. contacts, tickets) with a Camel YAML route template
ResourceQuery A parameterised query on a Resource (e.g. search-by-email) — each has its own Camel YAML route
AppEvent An event definition that can be associated with an App or Connector (inbound/outbound event schema)
MCPServer An MCP (Model Context Protocol) server endpoint registered per tenant; used by Herald and Atlas to discover AI tools

Gateway Routing

Every AppConnector gets a dynamic Spring Cloud Gateway route at:

/app-connections/{connectorId}/**

Requests are processed through a fixed filter chain before being forwarded to the connector's configured upstream URI:

sequenceDiagram
    participant Client
    participant GW as App Connect Gateway
    participant Auth as Auth Filter
    participant Upstream as Connector URI

    Client->>GW: GET /app-connections/{id}/contacts?q=acme
    GW->>GW: Validate tenant header (if scoped)
    GW->>Auth: Inject auth credentials
    Auth->>Auth: Basic → Authorization: Basic …<br>OAuth2 → fetch/refresh token<br>Token → Bearer / header / query param<br>API Key → custom header
    GW->>Upstream: GET /contacts?q=acme + auth headers
    Upstream-->>GW: 200 JSON
    GW-->>Client: 200 JSON (response logged)

Filter chain (applied in order):

  1. Logging — request and response body logged
  2. Path rewrite/app-connections/{id}/segment/segment
  3. Header filtering — only Accept and Content-Type forwarded to upstream
  4. Auth injection — credentials added based on connector's authConfig

Routes are rebuilt at startup and on any connector create/update/delete by publishing a routes:refresh message to Redis, which triggers all running instances to reload.


Authentication Types

App Connect supports four auth strategies on a per-connector basis:

Type How it works
Basic Encodes username:passwordAuthorization: Basic …
OAuth2 Manages token lifecycle (fetch + refresh) via clientId, clientSecret, tokenUrl
Token Attaches a pre-configured token via Bearer header, custom header, or query parameter
API Key Injects a named header with a fixed key value

Auth config is stored as JSONB on both App and AppConnector entities, allowing the connector to override the app's default.


Resource Queries (Apache Camel)

Resources and their queries are executed as dynamically loaded Apache Camel YAML routes. Each ResourceQuery.config field contains a Camel YAML DSL route definition. When first requested, CamelResourceRouteManager installs the route, rewrites its ID to {connectorId}/{resourceAlias}/{queryAlias}, and converts the from URI to a direct: endpoint.

Execution flow:

sequenceDiagram
    participant Caller
    participant SVC as AppConnectorResourcesService
    participant Camel as CamelResourceRouteManager
    participant Route as Camel YAML Route

    Caller->>SVC: GET /app-connectors/{id}/resources/{alias}?q={query}&param=value
    SVC->>Camel: ensureQueryRouteLoaded(connectorId, resourceAlias, queryAlias)
    Camel->>Route: Install route if not present
    SVC->>SVC: Resolve auth headers from connector AuthConfig
    SVC->>Camel: Execute route with connectorUri + params + auth headers
    Camel->>Route: Run YAML DSL (HTTP call to upstream)
    Route-->>SVC: Response body (JSON string)
    SVC-->>Caller: JSON response

This means any HTTP interaction pattern can be expressed as a Camel YAML route without deploying new code.


REST API

Apps — /apps

Method Path Purpose
GET /apps List all registered apps
POST /apps (multipart) Create app — body: config JSON + openapiSpec file
POST /apps/{uuid}/connectors Create a connector from an app's default auth config

App Connectors — /app-connectors

Method Path Purpose
POST /app-connectors (multipart) Create connector — config JSON + optional openapiSpec + logo
GET /app-connectors List connectors for the current tenant
GET /app-connectors/{id} Get connector details
PUT /app-connectors/{id} Update name, URI, or auth config
DELETE /app-connectors/{id} Delete connector (also removes Keycloak service account)
PUT /app-connectors/{id}/openapi (multipart) Replace OpenAPI spec; re-syncs to Tool Management Service
POST /app-connectors/{id}/resources-refresh Force-reload Camel routes for connector's resources

Resources & Queries — /app-connectors/{id}/resources

Method Path Purpose
GET /{id}/resources List resources (connector's own + inherited from parent App)
GET /{id}/resources/{alias}/queries List queries for a resource
GET /{id}/resources/{alias}/schema OpenAPI schema for the resource
GET /{id}/resources/{alias}?q={queryAlias}&… Execute a resource query

Events — /app-connectors/{id}/events

Method Path Purpose
GET /{id}/events List events (connector's own + inherited from parent App)

MCP Servers — /mcp-servers

Method Path Purpose
GET /mcp-servers/discover?serverUrl=… Discover OAuth endpoints from an MCP server's well-known metadata
POST /mcp-servers/register-client?registrationEndpoint=…&redirectUri=… Dynamic Client Registration (RFC 7591)
POST /mcp-servers Register an MCP server for the tenant
GET /mcp-servers List MCP servers for the tenant
GET /mcp-servers/{id} Get MCP server details
DELETE /mcp-servers/{id} Delete MCP server

MCP Server Management

App Connect is the registry for MCP (Model Context Protocol) servers — the mechanism by which AI agents (Atlas, Herald) discover and call external tools at runtime.

Registration flow:

sequenceDiagram
    participant Admin
    participant AC as App Connect
    participant MCP as MCP Server

    Admin->>AC: GET /mcp-servers/discover?serverUrl=https://mcp.example.com
    AC->>MCP: GET /.well-known/oauth-protected-resource
    MCP-->>AC: authorization_servers list
    AC-->>Admin: OAuth endpoints (tokenUrl, authorizationUri)

    Admin->>AC: POST /mcp-servers/register-client
    AC->>MCP: POST {registrationEndpoint} (RFC 7591 DCR)
    MCP-->>AC: clientId + clientSecret
    AC-->>Admin: Credentials

    Admin->>AC: POST /mcp-servers (serverUrl, clientId, clientSecret, agentId, allowedTools, …)
    AC->>AC: Store MCPServer record (tenantId scoped)

Each MCPServer record holds the server URL, OAuth2 credentials, the agentId it is associated with, an allowedTools list (JSON array), and a timeout (default 90 s).

Herald and Atlas query App Connect to resolve MCP server configs for a given agentId at conversation start.


Keycloak Integration

When an AppConnector is created, App Connect provisions a Keycloak service account client asynchronously:

  1. AppConnectorCreatedEvent published synchronously on creation.
  2. AppConnectorCreatedListener picks it up on a background thread (tenant context preserved).
  3. A Keycloak confidential client is created — clientId derived from {tenantId}-{connectorName}.
  4. The generated clientId and clientSecret are written back to the AppConnector entity.
  5. ConnectorStatus transitions: PENDINGACTIVE (success) or ERROR (failure).

On delete, AppConnectorDeletedListener removes the Keycloak client.


Tool Management Sync

Whenever an App or AppConnector OpenAPI spec is created or updated, App Connect calls the Tool Management Service (http://tool-management-service) via a multipart REST request. This keeps the AI agents' tool catalogue up to date without manual intervention.


Domain Model

AppConnector

Field Notes
id UUID — primary key
name Display name
uri Upstream base URL
authConfig JSONB — polymorphic: Basic / OAuth2 / Token / API Key
tenantId Multi-tenancy scoping
app Parent App definition (many-to-one)
openapiSpec OpenAPI YAML/JSON (optional)
clientId / clientSecret Keycloak-provisioned service account
status PENDING · ACTIVE · INACTIVE · ERROR

MCPServer

Field Notes
id UUID
serverUrl MCP server endpoint
accessToken / refreshToken OAuth2 tokens
clientId / clientSecret / tokenUrl / scope OAuth2 credentials
agentId Associates server with a specific AI agent
allowedTools JSONB array of permitted tool names
timeout Request timeout in seconds (default 90)
tenantId Multi-tenancy scoping
active Enable / disable without deletion

Configuration

Variable Default Purpose
spring.datasource.url jdbc:postgresql://postgres:5432/app_connects PostgreSQL URL
spring.data.redis.host redis Redis host for route refresh pub/sub
spring.data.redis.port 6379 Redis port
keycloak.realm nexivo Keycloak realm
keycloak.serverUrl https://auth.dev.cognitry.io/ Keycloak server
keycloak.clientId admin-cli Keycloak admin client
keycloak.clientSecret (required) Keycloak admin secret
services.tool-management http://tool-management-service Tool Management Service base URL
server.port 8080 HTTP port
DB_POOL_MAX 50 Max DB pool size
DB_POOL_MIN 10 Min DB pool size