Architecture & Dependencies
A deeper technical companion to the Architecture flow page. It answers three questions precisely: what the moving parts are and what they depend on, whether any AI runs when a user imports a matter, and whether the system exposes a Model Context Protocol (MCP) service that an AI agent can use. Short version: a live user import is pure deterministic code — no AI, no MCP in the loop — while AI and MCP exist as separate, well-bounded capabilities described below.
1. The four building blocks
Think of it as a relay team — each part has exactly one job.
AderantImportPortal
Next.js 15 · React 19 · the UI
The face. The screens staff use to search matters, preview the transform, click Import, and review history. Loads per-org config server-side and brokers it through the Proxy; tenant secrets are stripped before any config reaches the browser. Has no MCP service by design.
ShareDoAderantAPIProxy
Express · the brain + the writer
Holds per-tenant secrets, transforms Aderant data into the Clio Operate shape, and is the only component that writes into Clio Operate. Exposes the main MCP service (7 tools, including the gated write tools).
AderantSQLAPITypeScript
Express · the on-prem reader
The only component allowed to touch the on-premises Aderant SQL Server. Read-only, column-whitelisted, parameterised. Exposes a read-only MCP service (5 tools). Tunnelled out because the database sits behind a firewall.
pms-sync-embed
Foundry SDK · runs inside Sharedo
The doorway into Sharedo. A widget that iframes the Portal, uses signed single-sign-on handoff so the Sharedo user is logged in automatically, and brokers API calls back through Sharedo.
2. How one import flows
The money path: a user picks a matter and it becomes a Clio Operate work item. Reads go to Aderant (left); writes go to Clio Operate (right). The Proxy is the only writer.
User + Widget
│ 1 search / select a matter
▼
Portal ───2 preview / import (with org config)──▶ Proxy
│ 3 read matter + parties
▼
SQL API ──▶ Aderant SQL (on-prem)
│ 4 transform (deterministic, sandboxed)
▼
Clio Operate API
│ 5 create ODS parties + work item + key dates
▼
Portal / Proxy audit
(6 history row or audit event)3. What runs during a user import — and what doesn't
This is the question most people actually want answered. When a user clicks Preview or Import, the runtime path is 100% deterministic. No language model is called, and the MCP service is not involved. The per-tenant field transform runs inside a QuickJS WebAssembly sandbox — sandboxed JavaScript with no network, no I/O, and no timers. Provided a transform does not call non-deterministic globals such as Date.now() or Math.random(), the same input produces the same output.
Runs during a user import
- Keystone — authenticates the session
- Supabase — loads the org's config & saved mapping
- SQL API → Aderant SQL — reads the matter and parties
- QuickJS sandbox — runs the saved transform (deterministic)
- Clio Operate API — writes the work item
Does NOT run during a user import
- No LLM / Synapse call
- No MCP tool invocation
- No Anthropic / OpenAI / OpenRouter call
- No non-deterministic step in platform code (a custom transform using Date.now()/Math.random() is the exception)
4. Where the AI actually lives (design-time only)
AI assistance exists, but it is used before any import — when a consultant or administrator authors a work-type mapping transform. The portal offers two admin-only helpers that call the Alterspective Synapse LLM service:
- Suggest — generate a draft JavaScript transform for a field mapping.
- Repair — fix a transform that is failing validation.
The administrator reviews the suggestion and saves it as mapping configuration. From then on, every import just executes that saved deterministic snippet. If Synapse were offline, imports would be completely unaffected — only the authoring assistant would be unavailable.
5. The MCP service (for AI agents)
Yes — the system exposes two Model Context Protocol services that an AI agent can use. They are a completely separate surface from the user import path: a different route (/mcp), different authentication (Keystone OAuth 2.1 bearer tokens), and different callers (agents, not the browser). The Portal deliberately has no MCP service — it is the human UI, and its capabilities are already exposed by the two backends.
Proxy MCP — 7 tools (read + gated write)
| Tool | Access | What it does |
|---|---|---|
get_status | public | Health of the proxy |
list_work_types | read | Sharedo work types in the caller's tenant |
search_matters | read | Search Aderant matters by name / code / client |
list_client_matters | read | All matters for a given client code |
preview_matter | read | Dry-run of what an import would produce |
import_matter | write | Irreversible — creates the work item + ODS parties |
reconcile_closures | read / write | Compare Aderant status vs Sharedo phase; optionally close drifted matters |
SQL API MCP — 5 tools (read-only)
| Tool | Access | What it does |
|---|---|---|
get_status | public | Health of the SQL agent |
list_tables | read | Discovered Aderant tables / views and their columns |
query_table | read | Read rows — columns whitelisted, values parameterised, paginated |
search_clients | read | Search clients by name or code |
search_matters | read | Search matters by name, code, or client |
import_matter) only proceeds when the caller has the write scope and the org's import_write_enabled flag is on and the call includes confirm: true. The tenant is resolved strictly from the token, never a free parameter, and secrets never leave the proxy.The elegant part: an agent calling import_matter ends up running the exact same deterministic import code a human triggers — the MCP tool simply calls the proxy's own HTTP API in-process. So AI can initiate an import, but no AI runs inside it. There is no arbitrary-SQL tool by design; every database read is whitelisted and parameterised.
6. Dependency map (key libraries)
| Job | Portal | Proxy | SQL API |
|---|---|---|---|
| Framework | next 15 · react 19 | express 4 | express 5 |
| MCP | — | @modelcontextprotocol/sdk | @modelcontextprotocol/sdk |
| Auth / JWT | jose · iron-session | jose | jose |
| Database | — | mssql · axios-ntlm | mssql |
| Tunnel | — | — | hyco-https (Azure Relay) |
| Config store | @supabase/supabase-js | @supabase/supabase-js | — |
| Transform sandbox | — | quickjs-emscripten | — |
| Logging | pino | pino · morgan | structured JSONL |
| Security middleware | Next headers / CSP | helmet · cors · rate-limit | helmet · cors |
| AI / observability | langfuse · @sentry/nextjs | @sentry/node | — |
The Sharedo widget (pms-sync-embed) is built on the Alterspective Foundry SDK and pulls its packages from GitHub Packages.
7. External systems we depend on
| System | Used by | For | If it's down… |
|---|---|---|---|
| Keystone (identity) | Portal, MCP | Standalone login (OIDC) + MCP token validation (OAuth 2.1) | Standalone/OIDC login and MCP calls fail; embedded Sharedo SSO (proxy-signed JWT) is unaffected |
| Supabase | Portal, Proxy | Per-org config, mappings, standalone portal history | Imports can't resolve the tenant |
| Clio Operate / Sharedo API | Proxy, Widget | The write target: parties, work items, key dates | Imports fail at the write step |
| Aderant SQL Server (on-prem) | SQL API | The source of truth: clients, matters, parties | Nothing to read — previews are empty |
| ngrok / Azure Relay | SQL API | Outbound tunnel so the cloud can reach on-prem | Cloud loses its link to on-prem data |
| Synapse LLM | Portal | AI-assisted mapping authoring (design-time only) | Authoring assistant unavailable; imports still work |
| GitHub Packages | Widget (build) | Foundry SDK packages | Widget can't build / deploy |