Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
8.2 KiB
AlgaPSA MCP Server
AlgaPSA exposes its functionality to AI agents over the Model Context Protocol (MCP) through a small, constant 3-tool surface (progressive disclosure) rather than one tool per API endpoint:
| Tool | Purpose |
|---|---|
search_api_registry |
Find the right API endpoint by natural-language query |
search_business_data |
Find tenant records (tickets, clients, …), ACL-scoped |
call_api_endpoint |
Execute a chosen endpoint |
There are two delivery forms.
1. Local connector (CE / free)
A workstation tool the user runs alongside an MCP client (Claude Desktop, Cursor). It calls the AlgaPSA API under the user's own API token, inheriting their RBAC/ABAC. No agent governance — the user's MCP client is the human-in-the-loop.
Setup:
- AlgaPSA → Settings → API Keys → create a key.
- Add to the MCP client config:
{ "mcpServers": { "alga-psa": { "command": "npx", "args": ["-y", "@alga-psa/mcp-connector"], "env": { "ALGA_INSTANCE_URL": "https://alga.example.com", "ALGA_API_TOKEN": "your-api-key" } } } }
Full details: packages/alga-mcp-connector/README.md.
2. Remote governed server (EE)
A networked MCP endpoint (POST /api/mcp, Streamable HTTP / JSON-RPC) that authenticates
agents via the tenant's identity provider and enforces governance: distinct agent
identity, RBAC, and an exportable audit trail. Enterprise-only.
Dark release. The admin UI (Settings → MCP Server) is gated behind the
mcp-serverPostHog feature flag and is off by default — it appears only when the tenant is Enterprise and the flag is enabled for them. This is a UI-only gate: the server endpoints below stay live regardless, so an operator can configure agents via the admin API even before the tab is rolled out. Seedocs/features/feature-flags.md.
Auth model — OAuth 2.1 resource server (IdP delegation)
AlgaPSA is an OAuth 2.1 resource server only; it does not issue tokens. Tokens come
from the tenant's IdP (Entra / Google / Keycloak). On an unauthenticated request the
server returns 401 + WWW-Authenticate pointing at the Protected Resource Metadata
(/.well-known/oauth-protected-resource, RFC 9728), which names the trusted IdP(s). The
server validates the bearer JWT (issuer, audience/resource, signature via JWKS) and maps
the configured subject claim to a provisioned agent.
Requirement: a remote MCP server needs the tenant to have an IdP that can issue tokens to a machine agent (client-credentials / service principal). A bare appliance with no IdP can still run the free local connector.
The easy path — provider presets, reuse, and hosted built-ins
Registering an IdP used to mean typing a raw issuer + JWKS URL + audience. Three layers now remove that friction, mirroring how AlgaPSA's own Google/Microsoft SSO works.
1. Provider presets (any edition). In Settings → MCP Server the trusted-IdP form offers Microsoft Entra, Google, or Custom instead of free text:
- Google — nothing to enter. Issuer is fixed (
https://accounts.google.com), the JWKS is fetched via OIDC discovery, and the subject claim defaults tosub. - Microsoft Entra — enter only the Entra tenant id. The issuer
(
https://login.microsoftonline.com/{tid}/v2.0) and JWKS are derived via discovery; the subject claim defaults toazp(app-only tokens). Use the concrete tenant id, notcommon— tokens are issued with the concretetid, socommonwon't match on verify. - Custom — the original raw issuer / JWKS / audience / claim path, unchanged.
POST /api/v1/mcp/idp-providers accepts { kind: 'google'|'microsoft'|'custom', entraTenantId? }
and resolves issuer + JWKS server-side.
2. Reuse an existing connection. If the tenant already linked Microsoft (SSO / email /
Teams), the form shows "You're already connected to Microsoft — enable agent access?" and
one-click pre-fills the Entra preset with the known tenant id (read from microsoft_profiles).
3. Hosted built-ins (SaaS, near-zero-config). On Nine Minds–hosted AlgaPSA, Google and
Microsoft are pre-trusted using the shared OAuth apps that already back SSO — so a hosted
tenant can provision agents with no IdP registration at all. When the shared-app secrets
are present, the built-in issuers are advertised in the PRM and accepted at token validation
exactly like a registered agent_idp_providers row. This covers interactive / human-delegated
agents (auth-code + PKCE through the shared app); the customer configures nothing in their own
directory.
Admin setup (the journey)
Either from the UI (Settings → MCP Server, EE only) or the admin API:
- Register the trusted IdP — pick Google / Microsoft Entra (preset) or Custom.
On hosted SaaS with built-ins, skip this entirely.
POST /api/v1/mcp/idp-providers - Give the agent a directory identity — see the distinction below. Interactive agents reuse the human's IdP login; unattended agents need their own client-credentials principal.
- Provision the agent — name, IdP issuer + subject, and the RBAC roles it may use.
One agent per
(issuer, subject)— re-binding an identity already claimed by an active agent returns a friendly409.POST /api/v1/mcp/agents - The agent's MCP client connects to
/api/mcp; on401it reads the PRM, gets a token from the IdP (resource = the/api/mcpURL), and connects. - Review/export audit —
GET /api/v1/mcp/audit?agentId=…or the UI audit viewer.
Agents operate only within their assigned roles (an agent without a permission is denied), and every tool call is audited (identity, tool, inputs, decision, status).
The key distinction — interactive vs unattended agents
The easy path makes interactive, human-delegated agents zero-config: the agent acts as a signed-in human, so it rides the existing Google/Microsoft login (or the hosted built-ins) and needs no new directory object.
Unattended machine agents (client-credentials, no human in the loop) are the irreducible
exception: a token with no user behind it must come from a directory identity the customer
owns — an Entra app registration or a Google service account. No preset removes that;
it's a property of OAuth, not of AlgaPSA. For these, create the app/service-account in your own
directory, then provision the agent with its client_id (Entra azp/appid) or service-account
sub (Google) as the subject. The subject-claim guidance in the form names the right claim per
provider.
Admin API reference (EE, session-admin or API-key auth)
| Method | Path | |
|---|---|---|
| GET/POST | /api/v1/mcp/idp-providers |
list / add trusted IdPs (POST takes kind/entraTenantId presets or raw custom fields) |
| GET | /api/v1/mcp/idp-suggestions |
suggested IdP from an existing connection (e.g. linked Microsoft → Entra tenant id) |
| GET/POST | /api/v1/mcp/agents |
list / provision agents (duplicate (issuer, subject) → 409) |
| GET | /api/v1/mcp/roles |
assignable MSP roles |
| GET | /api/v1/mcp/audit |
export agent audit (?agentId=, ?limit=) |
Edition matrix
| Capability | CE | EE |
|---|---|---|
| Local stdio connector (user-scoped) | ✓ | ✓ |
Registry endpoint (/api/v1/meta/mcp-registry) |
✓ | ✓ |
Remote MCP server (/api/mcp) + agent identity + IdP auth + audit |
— | ✓ |
Known MVP limitations
- PRM is instance-wide.
/.well-known/oauth-protected-resourcelists all trusted issuers across tenants. Correct for a single-tenant appliance; a multi-tenant SaaS needs a per-tenant PRM (tenant hint via host/path) — tracked as a follow-up. - Agent session keys are short-lived (5 min) and swept opportunistically on each agent
request; a periodic sweep job (
cleanupExpiredAgentKeys) is also available. - Dispatch runs as a short-lived agent-scoped key against
/api/v1(kernel-enforced); in-process dispatch is a later optimization. - Not yet in MVP (Phase 3): agent-specific ABAC policy, approval gates (human-in-the-loop), and quotas/rate-limits.