Switchboard
Ingests spreadsheet snapshot data from a Google Sheets-style source for reconciliation.
Ingests CRM data from a HubSpot-style system via thin webhooks and hydration, enabling customer 360 insights.
Ingests support ticket and SLA data from a Salesforce-style subscribe/replay event stream.
Ingests billing events from a Stripe-style envelope feed to track invoices and payments.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Switchboardgenerate the weekly revenue-risk report"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Switchboard
Connects business systems that don't talk to each other, cleans up their combined data, and puts a supervised AI assistant on top.
The problem, in plain English
Most companies run separate software for sales, billing, and customer support. Those systems don't share information. So every week, someone spends hours copying data between screens to answer basic questions like "which customers are we about to lose?" — and the answer is stale by the time it's assembled.
Switchboard is a working demonstration of the fix (how it was built — one engineer directing an agent fleet under an evidence-gated process — is described in How this was built, because the process is part of the claim):
Connect the three systems so information flows automatically instead of by hand.
Clean and combine the data so there's one trustworthy record per customer — even when the same company appears under different names and IDs in each system.
Put an AI assistant on top that writes the weekly revenue-risk report automatically — designed so any action beyond reading requires human approval. Today that means two independent layers: the assistant's server registers exactly one read-only tool (anything else is rejected by the protocol layer, and a test pins that), and the assistant's database connection runs as a read-only Postgres role — a write is refused by the database itself, also pinned by tests. The approval-gated action and richer behavioral safety testing are being built in Phase 3.
Anyone can verify the claims: one command (./scripts/demo.sh) runs the entire
system and produces the report. No accounts, no API keys, nothing to sign up for.
Note for reviewers: the "customer" is a fictional company and all data is synthetic — and that's enforced, not asserted: automated hygiene checks cover both the data generators (DEMO-prefixed ids/names, example.com emails only) and a scan of every tracked file in the repo for real-looking emails or PII-shaped records. Real client work can't be published, so this project shows the same engineering on data you can inspect freely.
Related MCP server: HubSpot RevOps MCP Server
The horizontal thesis: one pipeline, many businesses
Every vendor integration looks bespoke from the outside. It isn't. Strip the branding away and there are a small number of paradigms — ways a system agrees to tell you that something changed — and each one has its own failure mode. Switchboard implements four of them against one unchanged reliability spine:
Paradigm | Modelled on | What it hands you | Its loss boundary |
Spreadsheet snapshot-diff CDC | Google Sheets + Apps Script | a mutable grid; changes are inferred by re-reading it | the push channel is lossy and blind to API writes — reconcile against the sheet's own rows is the guarantee |
Cursor-paged envelope feed | Stripe | an opaque cursor over a retained window | 30-day retention: fall further behind and the events are gone from the source |
Thin webhook + hydration | HubSpot | metadata-only batches; the record must be fetched afterwards | a notification that exhausts its retries is unrecoverable — detected, never re-pulled |
Subscribe / replay event stream | Salesforce Pub/Sub | a subscription with a replay cursor | 72-hour window, plus stream resets that can kill a cursor of any age |
(A fifth, the 2a seq-ordered ledger feed, remains in the repo as the chaos proof's oracle — it is the one paradigm real vendors don't offer, which is why it is used to test the spine rather than to make claims about vendors.)
What that buys a reader in plain language: the expensive part of an integration is not the vendor — it's the reliability machinery underneath it, and that machinery is written once. Adding a source means writing a connector that speaks its paradigm; queueing, dead-lettering, quarantine, cursors, exactly-once storage, reconciliation and identity resolution are already there and do not change. The same is true vertically: no mart column is industry-specific, so the same pipeline serves a plumbing contractor, a SaaS company, or a brokerage — three profiles ship in the repo and are demonstrated below.
Each paradigm also admits what it cannot do. Two of the four can lose data permanently by the vendor's own design; the pipeline reports those losses with bounds and refuses to pass until a named human accepts them, rather than reporting a clean run.
What's built and working today (Phases 0–2b)
Simulated business systems across four integration paradigms — a HubSpot-style thin-webhook CRM (metadata-only batches + a hydration pump), a Stripe-style envelope feed for billing, a Salesforce-style subscribe/replay event bus for support, a Google-Sheets-style snapshot source, and the original ledger-feed mocks — the push sources each keeping an HMAC-keyed, hash-chained, append-only log of everything they emit: the tamper-evident measuring stick the reliability tests reconcile against. All share one mock core with on-demand fault injection (dropped, duplicated, out-of-order deliveries and API errors, deterministic from a seed), and all are generated from one correlated seed manifest, so the same fictional companies deliberately appear across systems under mismatched names, domains, and IDs — including seeded duplicates and planned near-misses the identity layer must get right. The log chain is keyed (
LEDGER_HMAC_KEY) so tamper-evidence holds against anyone who can write the file but doesn't hold the key; a dedicated adversarial test proves a forger without the key is caught. Secrets fail closed: there are demo defaults, but they only activate behind an explicitALLOW_DEV_SECRETS=1— a production deploy that forgets an env var refuses to run instead of silently authenticating against a value published in this repo.An ingestion service built for failure, now source-agnostic: one
/webhooks/:sourceendpoint with a per-source HMAC secret (WEBHOOK_SECRET_<SOURCE>, one per registered source — a billing event signed with another source's secret is rejected, by test) and timestamped signatures with a ±5-minute replay window (the timestamp is signed material, so a captured request can't be re-stamped — the same scheme Stripe, Slack, and HubSpot converge on), a single raw event store with(tenant_id, source, event_id)exactly-once storage, per-source retry queues with per-source dead-letter lanes and replay tools for both the DLQ and the quarantine, a quarantine for malformed data (nothing delivered is ever dropped, and event timestamps are bounded to a sanity window so a vendor clock bug can't permanently pin an entity's state), and per-source cursor backfill that catches anything webhooks lose.A runnable zero-loss check:
./scripts/chaos.shdrives all three chaos sources under injected failures simultaneously — the thin-webhook CRM through its own weather (duplicated requests, cross-batch holdovers, within-batch shuffle, a bounded redelivery budget) and the two ledger-feed sources through drops/dups/API errors — and proves each source reconciles clean under its own paradigm's oracle: object store vs raw thin events vs hydrated snapshots for the CRM, tamper-evident log vs raw for the feeds (the settle wait is backoff-aware and bounded at 240s so retry-backoff spikes finish instead of flaking). It has a negative control that must FAIL —CHAOS_SKIP_BACKFILL=1is required to red — which is what separates a check from a green light. Two limits the headline used to omit, both already in KNOWN-ISSUES and now stated where the claim is made: reconcile proves id-set parity, not payload parity, and the oracle is a ledger written by this codebase, whereas in production the vendor is the oracle. It was called "a zero-data-loss proof" here; a proof's strength is bounded by its oracle, and a headline stronger than the register beneath it is the one credibility failure a repo whose pitch is disclosure discipline cannot afford.Identity resolution (dbt): three deterministic tiers — exact email match, then normalized domain + company name, then a
manual_reviewqueue (never a silent guess) — with every resolved link recording which tier matched and the evidence, so resolution is auditable, not a black box. CRM merge events collapse duplicate companies and re-point their history (recursive follow-to-terminal with a cycle guard; dbt tests assert no cycles and all chains terminate). Design rationale: identity-resolution ADR.A unified
customer_360mart: one row per resolved entity joining deals, invoices, payments, tickets, SLA breaches, CSAT and spreadsheet rows across all four ingest lanes. Entities visible only in billing or support still get a row, flagged incomplete — more useful than hiding them.An identity-correctness oracle: the seed manifest plans, per entity, exactly which tier must match;
scripts/verify-identity.tschecks the entire assignment (tier partition, merge collapse, deal conservation, mart rowcount, cross-system joins) on every demo run and CI build.An AI-tool server (Model Context Protocol — the open standard for connecting AI assistants to business data) exposing exactly one read-only tool, with an automated safety test proving undeclared tools are rejected.
A worker that generates the Monday revenue-risk report — with a timeout and fallback so the report generates even when the AI service is down, and per-call cost logging.
CI: the
ciworkflow runs on every push — typecheck, all 1041 tests, the dbt build — 101 dbt build steps (15 models, 3 seeds, 83 data tests) — the agent action-safety eval, and the identity oracle, against a real Postgres service container (ci.yml). The heavier chaos + demo proof runs on a nightly schedule and manual dispatch, with the fault seed as a workflow input so any red run is reproducible by re-entering its seed (chaos.yml). The badges above track those workflows and report the live state of each. Moving to real runners was worth it: there were three red runs before the first green one, each for a different reason and none of them findable by a local suite — a fail-closed secrets gate that could only fail where no secrets exist, a drain-gate race that only opens on a slow machine, and a leftover mock server inherited across steps sharing a process table. Each is narrated with its run ID in the known-issues ledger.1041 automated tests, green in CI and locally — including a seeded property-based suite (fast-check) that generatively attacks the ingest boundary, dedup, HMAC, batch-failure isolation, and ledger crash-safety under arbitrary torn writes. That count is not maintained by hand: CI runs
scripts/verify-doc-counts.tsagainst the realnpm testlog and against the known-issues scoreboard, so a build whose numbers drift from this page goes red. Test-first is sometimes provable from git history for hardening work since 2a.2: in the phase-2b close range four fixes land as explicit RED→GREEN commit pairs and eleven bundle their tests into a single commit — every one of them test-backed, but only the four provable as pairs fromgit logalone. For earlier phases it is narrated, not provable. The whole pipeline runs from one command; operational docs included (runbook, identity ADR, scaling ceilings, real-vendor delta, deletion/GDPR design, and a public known-issues ledger — the open defects, deferred debt, and known-failing invariants, with where each gets paid).
Measured results (every number is a script output, reproducible)
Claim | Evidence | Result |
Zero lost events under faults |
| the exact per-seed split moves with |
Loss detection has teeth |
| correctly FAILS per paradigm: the ledger-feeds list every unrecovered dropped event, and the CRM reds on dropped webhooks (missing/drifted objects) plus un-hydrated events |
End-to-end pipeline equality |
| ledger = raw = journal where a ledger exists (hubcrm, support); journal = raw plus a four-paradigm |
Seeded duplicates collapse | dbt build ( | 22 staged companies → 20 canonical entities; merged-away ids absent from the mart, their deals re-pointed |
Identity tiers match the plan |
| 30 external entities: 19 tier-1, 5 tier-2, 6 manual-review — exact set equality per source, including both planned near-misses |
Unified mart is conservative | dbt + oracle |
|
Suite |
| 1041 tests green across nine workspaces (incl. 6 seeded fast-check properties); 101 dbt build steps (15 models, 3 seeds, 83 data tests) — |
What's coming (built in phases, in public)
Phase 3 — Agent depth: one carefully-bounded write action behind human approval with a full audit trail, plus an evaluation suite for report quality.
Phase 4 — Operations: monitoring dashboards, alerting, a live deployment, and a demo video.
How this was built
One engineer, directing a fleet of AI coding agents under an evidence-gated process. That is worth stating plainly, because "built end-to-end by one engineer" would be the same species of overstatement this repo's known-issues ledger exists to refuse. The engineering claim here is not that a human typed every line; it is that nothing was allowed to land on the strength of an agent's own account of it.
The loop, per unit of work:
Brief — a written task brief stating the requirement, the risk rules, and what would count as evidence.
Implementer — an agent builds it and writes a report.
Framed review — a second agent reviews against the brief and the spec.
Fix loop — findings answered, with the fix's own evidence.
Cold, unframed review — before every push, a fresh reviewer is given the repository and a commit range, barred from this project's own briefs, reports and reviews, and instructed to attack the claims rather than confirm them. All of it is in the repo:
.superpowers/sdd/carries 33 task briefs, 52 reports, 24 framed per-task reviews, 11 cold-review documents (10 distinct cold reviews plus one fix response), and 79 commit-range diff packages — counted at commit6a82842.
Cold review earns its place by what it actually caught. Three findings, none of which a framed reviewer had produced:
A disclosure that died during the exact incident it existed for. A source that was both unreachable and carrying an unacknowledged permanent data-loss gap printed the unreachable error and nothing else — no loss line, no acknowledgement prompt. The exit code still failed, so the gate held while the human got nothing. The implementer's own note on it: "that is the failure mode migration 010 exists to prevent, and I had put the read below the two
continues myself." The class recurred often enough to be named in the phase-close sweep as the phase's most-recurring defect species.A fix whose test passed with and without the fix. A pin placed its fixture outside the window where the bug lives, so buggy and fixed code both answered identically — while the report claimed it "pins exactly this." That incident is why every later task brief carries a standing rule to revert-check every new pin, and why later reports carry an explicit "revert-check evidence" table: the fix is reverted and the test must go red. Honest limit: that discipline is documented per-pin from the mid-phase A-slice onward and comprehensively from Task E; for earlier work it is narrated, not proven. Two further vacuous pins were caught the same way, including a CI data test that had been passing because no fixture row could ever trip it.
Real company names shipped as synthetic data. The SaaS vertical profile's invented "flavor words" included two exact matches for real (defunct) companies. The reviewer found them with citations — against a rule the same range had written itself two files earlier. Replaced with vetted inventions.
Two other cold reviews reported that a range broke its own CI gate (the reviewer reproduced the CI composition on a scratch database rather than taking the green local suite's word), and that a task's headline deliverable was unreachable from every shipped operator surface while the runbook claimed it was reported. Both were true.
Fixes were researched before they were written, not after. Four research
documents in .superpowers/sdd/ (close-fix-research.md,
debt-burn-research.md, f2-wire-research.md, market-unification-research.md)
carry per-claim citations to primary sources actually opened — PostgreSQL,
AWS, GitHub Actions, Stripe, HubSpot and Salesforce developer documentation,
RFCs, and vendor knowledge bases — with a stated adversarial method (each
candidate fix treated as a hypothesis, with a refutation attempted before it was
endorsed) and with failed fetches disclosed inline rather than quietly dropped.
What this does not claim: that the process is free of misses. Several of the findings above were caught late, after the work had already been reported complete by an agent and accepted by a framed review. The argument for the process is that they were caught at all, in public, and written down — which is the same argument this repository makes about its data.
For engineers
Architecture (current): six mock source servers across five paradigms (shared
@switchboard/mock-core: PRNG faults, HMAC signing, keyed hash-chain ledger,
correlated seed manifest) → Express 5/TypeScript ingest (/webhooks/:source,
per-source HMAC verify, per-source pg-boss queues + DLQs, per-source cursors) →
single raw.raw_events ((tenant_id, source, event_id) unique) → dbt: 9 staging views
(distinct on latest-state, event-time ordered) → identity layer (merge_edges →
recursive canonical walk → 3-tier identity_resolution with provenance →
manual_review incremental) → customer_360 mart → MCP server (official TS SDK,
READ_TOOLS allowlist + rejection-text eval) → report worker (scripted MCP client
calls + LLM narrative — true agentic tool selection lands in Phase 3;
deterministic template fallback when ANTHROPIC_API_KEY is unset).
Read the engineering trail — the process is part of the artifact:
Design spec (rev 2) — architecture, build-vs-buy decisions, what was deliberately cut, revised after a 12-finding adversarial review
Phase 2 amendment — the 13 locked design decisions behind the width work (single raw table, per-source secrets, merge semantics, CI split)
Identity-resolution ADR — why deterministic tiers and not ML, and how merges collapse without rewriting raw
Connector-paradigms ADR — the four paradigms, why each mock is faithful to a documented vendor behavior, and the honest fidelity deltas (no OAuth, HTTP/JSON where the vendor uses gRPC, the two disclosed merge-modeling inferences)
Journals — what was planned vs. what actually happened, including the misses: Phase 0 · Phase 1 · Phase 2a
Prerequisites: Docker (for Postgres) and Node.js ≥ 22.
Run it:
npm install
./scripts/demo.sh # end-to-end: 560 events, 4 faithful sources → per-paradigm reconcile + identity checks → report
./scripts/chaos.sh # seeded faults across two paradigms → zero-loss proofThe first run also pulls the Postgres image and builds the dbt container, so budget
a few minutes for it. Once those are cached, demo.sh takes roughly 20 seconds and
chaos.sh roughly 20 seconds typical — the latter bounded at 240s, since it waits
on retry backoff it deliberately induced.
Tests require the install above and the database up:
docker compose up -d postgres
DATABASE_URL=postgres://switchboard:switchboard@localhost:5433/switchboard npm testThe spreadsheet-as-CDC connector is deliberately not in
demo.sh; its proof is its own oracle suite (with the database up, as above):
cd ingest && npx vitest run test/sheet-oracle.test.ts test/sheet-mart-oracle.test.ts
— drop-heavy convergence, blank-row tolerance, quarantine custody, and the mart joins.
One pipeline, three verticals
The core is vertical-agnostic by construction: no mart column is
industry-specific, connectors are paradigm-specific (webhook, cursor feed, event
bus, spreadsheet) — never industry-specific — and a vertical profile swaps only
vocabulary and value ranges. The seed generator ships three vertical profiles
(plumbing | saas | realestate, default generic) on the same skeleton: same
entity counts, same id schemes, same seeded duplicates and merge pairs, same
tier-1/2/3 identity expectations. Same seed, same pipeline — different business.
Deterministic and reproducible (a test runs these exact commands and diffs the
output against this section):
PROFILE=plumbing node --import tsx -e 'import("@switchboard/mock-core").then(({generateManifest})=>{const m=generateManifest(42,process.env.PROFILE);for(const c of m.crm.companies.slice(0,2))console.log("company",c.id,c.name,"·",c.domain);const d=m.crm.deals[0];console.log("deal ",d.id,d.name,"· $"+(d.amount_cents/100).toFixed(2));const t=m.support.tickets[0];console.log("ticket ",t.id,t.subject)})'company DEMO-C-0001 DEMO Rooter Plumbing 1 · rooter-1.example.com
company DEMO-C-0002 DEMO Drainworks Plumbing 2 · drainworks-2.example.com
deal DEMO-D-0001 DEMO Job 1: Sewer Line Repair · $6807.11
ticket DEMO-T-0001 DEMO Clogged Drain Call 1PROFILE=saas node --import tsx -e 'import("@switchboard/mock-core").then(({generateManifest})=>{const m=generateManifest(42,process.env.PROFILE);for(const c of m.crm.companies.slice(0,2))console.log("company",c.id,c.name,"·",c.domain);const d=m.crm.deals[0];console.log("deal ",d.id,d.name,"· $"+(d.amount_cents/100).toFixed(2));const t=m.support.tickets[0];console.log("ticket ",t.id,t.subject)})'company DEMO-C-0001 DEMO Cloudbriar Software 1 · cloudbriar-1.example.com
company DEMO-C-0002 DEMO Datawren Software 2 · datawren-2.example.com
deal DEMO-D-0001 DEMO Team Plan Upgrade 1 · $108251.78
ticket DEMO-T-0001 DEMO API Rate Limit Ticket 1PROFILE=realestate node --import tsx -e 'import("@switchboard/mock-core").then(({generateManifest})=>{const m=generateManifest(42,process.env.PROFILE);for(const c of m.crm.companies.slice(0,2))console.log("company",c.id,c.name,"·",c.domain);const d=m.crm.deals[0];console.log("deal ",d.id,d.name,"· $"+(d.amount_cents/100).toFixed(2));const t=m.support.tickets[0];console.log("ticket ",t.id,t.subject)})'company DEMO-C-0001 DEMO Harborview Realty 1 · harborview-1.example.com
company DEMO-C-0002 DEMO Summit Realty 2 · summit-2.example.com
deal DEMO-D-0001 DEMO Buyer Representation 1 · $337597.19
ticket DEMO-T-0001 DEMO Escrow Question Request 1The demo scripts and every identity/oracle proof run on generic, whose output
is byte-frozen against the pre-profile baseline; all data in every profile is
synthetic (DEMO markers, *.example.com domains), enforced per profile by the
hygiene tests.
Stack: TypeScript / Node 22 · Express 5 · Postgres 16 · dbt · pg-boss · MCP TypeScript SDK · Anthropic SDK · Docker Compose · GitHub Actions. Planned in later phases: OpenTelemetry + Grafana (Phase 4).
License
Apache License 2.0 — see LICENSE and NOTICE. Copyright 2026 Michael Christine.
Apache 2.0 rather than MIT for the express patent grant: MIT is silent on patents, which is the ambiguity counsel tends to flag when a business evaluates taking a dependency on someone else's code.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityBmaintenanceMCP server that gives AI assistants real-time access to Stripe business metrics like MRR, churn, and revenue forecasts via natural language queries.7MIT
- Alicense-qualityCmaintenanceA read-only MCP server that connects to HubSpot to audit CRM data, diagnose RevOps maturity, identify at-risk deals, and provide step-by-step guidance for fixing issues.168MIT
- AlicenseAqualityBmaintenanceOne MCP server for the SaaS back office. Stripe, HubSpot, and Google Sheets exposed as typed, read-only-by-default tools for Claude and any MCP client.1MIT
- Alicense-qualityCmaintenanceA connector that surfaces ~50 tools from 10+ integrated business systems (CRM, finance, support) via MCP, enabling an AI assistant to securely query and operate on correlated office data.MIT
Related MCP Connectors
Connect e-commerce and marketing data to AI assistants via MCP.
Your AI copilot for customer onboarding — projects, KPIs, tasks, and safe writes.
Revenue-first analytics installed and verified by AI agents through Talivia
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/TattedLawyer/switchboard-ai-integration'
If you have feedback or need assistance with the MCP directory API, please join our Discord server