crm-mcp-agent
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., "@crm-mcp-agentwhat's the performance of our email campaign last month?"
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.
crm-mcp-agent
The SQL work of a CRM/lifecycle marketer, done by an agent over MCP — behind a governance kernel that decides how far the agent may go, how it is stopped, and what gets written down.
English · 한국어 · 日本語 · 简体中文 · 繁體中文 · Español · Português (Brasil) · Deutsch · Français · Русский · Italiano · Bahasa Indonesia · Türkçe
Quickstart · Architecture · Design decisions · Governance kernel · Credits
Apache-2.0 covers source code only. Data files, fixtures, and any other non-code content are governed by the records inCREDITS.md, which take precedence for those files. Content not listed there is unrecorded, not free to reuse.
All data in this repository is 100% synthetic, at every commit. Every row is produced by a seeded generator: names are combinatorial from small fixed token lists, phone numbers all use the unusable 010-0000-XXXX exchange, and every email address is on the example.com domain reserved for documentation by RFC 2606. There is no real customer, campaign, or company data here, and no code path that talks to anything other than the local SQLite file the generator writes.
What this is
This is a prototype for one narrow question: can an agent, talking to a small purpose-built MCP server, do the ad-hoc segment and campaign lookups a CRM marketer normally does by hand-writing SQL against a customer data platform — and can the write side be made safe enough to expose at all? It ships a deterministic synthetic CDP, five read-only MCP tools with a hard non-PII boundary, and a pure-standard-library governance kernel that every write-side call must pass through. It is a prototype, not a product, and explicitly not an integration with any marketing-automation vendor: there is no vendor SDK, account, or credential anywhere in it, and execute_campaign is a simulator that appends a receipt to a local ledger — it will not call an outward API at any milestone. What is real here is the mechanism: the tiering, the fingerprint-bound approvals, the kill switch, the caps derived from the audit log, and 45 adversarial tests whose job is to break all of it.
Related MCP server: atomic-crm-mcp
Highlights
108 tests in 0.772 s, measured on this snapshot: 53 unit tests plus 55 adversarial and scenario tests — 33 PII red-team attacks, 12 governance red-team attacks, and 10 end-to-end governance scenarios.
Exactly one third-party dependency, and it is pinned to a major version:
mcp>=1,<2. Everything else — generator, governance kernel, guards, agent loop, tests — is standard library. Verified againstmcp1.28.1 on Python 3.14.6.Determinism is proven, not asserted. The publication gate generates the synthetic CDP twice with the same seed and compares SHA-256 digests; they are byte-identical. Generation never reads the wall clock — the 180-day window is anchored to a fixed calendar date.
The synthetic CDP, measured at seed 42: 5,000 customers, 99,922 events, 40 campaigns, 1,225 daily campaign-result rows, 12 rule-based segments, and 8,078 segment memberships across 7 tables.
Five read-only MCP tools (
segment_query,campaign_history,campaign_performance,audience_overlap,budget_status) and three write-side tools (propose_campaign,execute_campaign,read_audit_log), each mapped to one of 4 authority tiers.A non-PII guard with three independent legs so one bug is not a leak: deny-by-default allowlists (PII columns appear in no allowlist), a recursive output-side scrubber that fails the call closed on any phone/email/RRN-shaped string, and no column-injection surface at all — field and operator names are only ever dict keys into hardcoded SQL fragments, and only values are bound parameters.
A governance kernel in 8 stdlib modules with rails checked cheapest-and-most-absolute first: kill switch → circuit breaker → rate caps → approval broker → append-only decision log. Fail-closed throughout: unreadable kill state reads as engaged, garbled breaker state reads as tripped.
Grants that cannot be replayed. An approval is bound to
SHA-256(tool + "\n" + canonical_json(args)), consumed by a single atomic UPDATE so racing consumers cannot both win, and expires on a TTL (600 s default, 3,600 s ceiling). Caps for the irreversible tier are deliberately tight: 3 per day, 10 per week.Caps are re-derived from the audit log on every check, so the counter cannot drift out of sync with the record — the log is the counter.
19 numbered design decisions in
docs/DECISIONS.md, including the ones that argue against the obvious choice.
Use it
Two surfaces, and one owner console:
Surface | What it is | Authority |
MCP server | A FastMCP stdio server. Point any MCP client at it. Opens SQLite with | Read-only (T0) |
Write tools |
| T1 / T3, kernel-gated |
| The human's side of the kernel: 10 subcommands including | Owner only |
An agent loop (python3 -m agent.loop) runs one governed cycle: analyse with read-only tools → propose a draft → request the gated execute → after a human grants, execute (simulated) → report. Honest label: the default planner is a deterministic scripted planner, not an LLM. The property being demonstrated is not planning quality — it is that whatever plans, the write path stays behind the kernel. --auto-grant collapses the human gate for tests and demos and says so loudly; --planner ollama is an opt-in local-model variant that validates the model's choice against the same closed sets and falls back to scripted.
Governance state (approval database, decision log, ledgers, breaker and kill-switch files) lives outside the repository under a git-ignored directory, relocatable with CRM_MCP_GOV_DIR. The synthetic database path is set with CRM_MCP_DB_PATH; see .env.example. There are no secrets to configure, because there is no paid API and no network call at runtime.
Quickstart
Prerequisites: Python 3.11 or newer (measured on 3.14.6) and the mcp package pinned below major version 2 — mcp>=1,<2. The pin is a real prerequisite, not decoration: mcp is pre-1.0-style in its API churn, and an unpinned install can pick up a future 2.x whose FastMCP surface no longer matches server/mcp_server.py. Install it exactly as pinned.
git clone <your-fork-url> crm-mcp-agent
cd crm-mcp-agent
python3 -m venv .venv
.venv/bin/pip install "mcp>=1,<2" # the pin is required
python3 data/synth_cdp.py --seed 42 --out data/cdp.db # generator is stdlib-only
.venv/bin/python -W error::ResourceWarning -m unittest discover # 108 tests
.venv/bin/python -m server.mcp_server # stdio MCP server
.venv/bin/python -m gov.cli status # kill / breaker / caps / pendingThe database is git-ignored and must be regenerated after a clone; the same seed always reproduces it. Note that the generator needs no virtualenv at all — only the MCP server does.
Architecture
flowchart TB
subgraph DATA["Synthetic data — stdlib only"]
GEN["data/synth_cdp.py — seeded RNG, fixed 180-day window"] -->|writes| DB[("data/cdp.db — SQLite, git-ignored")]
end
subgraph READ["Read path (T0)"]
DB -->|"mode=ro"| SRV["server/mcp_server.py — FastMCP, stdio"]
GRD["server/guards/pii_guard.py"] -.->|"allowlists + output scrubber + no injection surface"| SRV
SRV --> CLI2["MCP client / agent"]
end
subgraph GOVK["Governance kernel — gov/, 8 stdlib modules"]
K["kernel.guard(tool, args)"]
KILL["kill switch — file present = deny all"] --> K
BRK["circuit breaker — garbled reads as tripped"] --> K
CAP["rate caps — re-derived from the audit log"] --> K
BRO["approval broker — fingerprint-bound, single-use, TTL"] --> K
K -->|"allow / approval_required / deny"| W["server/tools_write.py"]
K -->|every non-T0 decision| LOG[("decision-log.jsonl — append-only")]
OWN([human owner via gov.cli]) -->|grant / deny / trip / kill / phase| BRO
W -->|simulated receipts and draft ledgers| CLI2
end
CLI2 --> K
LOG --> CAPLoad-bearing properties:
Tiering is the whole design. T0 read-only is auto-allowed and unaudited; T1 draft is self-approved but audited and capped; T2 (reversible, reserved) requires an owner-promoted phase or else escalates onto the T3 path; T3 irreversible/outward requires a fresh human grant per call. Nothing can promote itself.
Ordering is a safety property. The rails are checked cheapest and most absolute first, and the cap check runs before the approval broker — so spamming a capped tool cannot flood a human with approval prompts. A denied policy call never creates a pending approval, which means a hard block cannot be approved into existence.
The log is the counter. Caps are recomputed from the append-only decision log on every check rather than kept in a separate tally, which removes an entire class of desynchronisation bug at the cost of a re-read.
The guard has two code paths on purpose. An allowlist alone fails if a new field is added carelessly; a scrubber alone fails if the regex misses a shape. Both run, and the red-team suite includes positive controls that prove the scrubber actually fires rather than silently passing.
mode=rois defence in depth, not the mechanism. The primary guarantee is that no write tool touches the CDP at all; the read-only connection is there so a bug cannot become a mutation.
Project layout
data/schema.sql 7 tables: customers, events, campaigns, campaign_results,
segments, segment_membership, customer_features
data/synth_cdp.py deterministic generator: seeded RNG, fixed calendar anchor
server/mcp_server.py FastMCP stdio server, 5 read-only tools, mode=ro connection
server/tools_write.py 3 write-side tools, every call routed through the kernel
server/guards/pii_guard.py allowlists + recursive output scrubber + injection refusal
gov/policy.py tool to tier map, risk by tier, T2 promotion phase
gov/kernel.py guard(tool, args) — the one decision point
gov/broker.py fingerprint-bound, single-use, TTL'd approval grants
gov/caps.py per-tool day/week caps, counted from the audit log
gov/breaker.py circuit breaker; unreadable state means tripped
gov/audit.py append-only decision log
gov/cli.py the owner console: 10 subcommands
agent/loop.py one governed cycle; scripted planner by default
tests/ 6 files, 53 unit tests
eval/test_pii_redteam.py 33 PII attacks incl. positive controls
eval/test_gov_redteam.py 12 governance attacks, all must be refused
eval/scenarios/ 10 end-to-end governance scenarios
docs/DECISIONS.md 19 numbered decisions with their trade-offsHow this was built
The adversarial suite is the deliverable, not the appendix. Of 108 tests, 45 exist to break this system rather than to confirm it: 33 try to get personal data out of a read-only tool, and 12 try to defeat the governance rails. The governance attacks are the interesting half — grant replay, cross-proposal and cross-tool fingerprint tampering, extra-argument tampering, TTL-expiry abuse, cap outspend, propose-spam, kill-switch bypass while holding a valid grant, breaker garbling, unknown-tool probes, approval-id guessing, and PII laundering through the agent-loop report path. Every one must be refused for the suite to pass. Writing the attack first and the rail second is what makes the rail credible.
Positive controls, because a silent no-op passes every negative test. The PII red-team includes tests that assert the scrubber fires on known-bad input. Without them, a guard accidentally disabled would still make the whole suite green — a failure mode that is invisible precisely when it matters most.
Ground truth independent of the guard. The final sweep calls all five read-only tools with benign arguments and substring-checks their JSON output against the actual names, phones, and emails in the underlying database. That check does not use the regex scrubber, so it cannot be fooled by a scrubber bug — it compares against reality.
Determinism verified by re-execution, not by claim. The generator's promise is that the same seed reproduces the same dataset anywhere, any day. The publication gate proves it by generating twice and comparing digests. One of the design decisions exists specifically to protect that: generation never touches the wall clock, and the entire event window is anchored to a fixed date, so a test written in January cannot pass differently in July.
AI-augmented in bounded lanes, with a deterministic arbiter. The implementation was produced by an agent relay — one agent building or auditing a lane, a second cross-checking the behaviour and the evidence, the author adjudicating. The arbiter was never a model's opinion: it was unittest discover and its exit code. This matters more than usual for a governance kernel, because a plausible-sounding rail that does not actually hold is worse than no rail. Several decisions in docs/DECISIONS.md exist because a first design sounded safe and the red-team disagreed — the cap-before-broker ordering and the never-approvable-deny rule both came from attacks, not from planning.
Stated deviations instead of quiet ones. docs/DECISIONS.md contains a section on deviations from the modelled daemon contract, written down rather than smoothed over, and separate entries on why --auto-grant exists and why it is dangerous, why T2 exists with no tool yet, and why the default planner is scripted rather than an LLM. Honest labels are cheaper to write than to retrofit.
A fail-closed publication gate. This public snapshot is produced by an out-of-repo sanitizing pipeline that never writes to the private source. It archives a ref, applies exclusions, overlays publication-only documentation, then refuses to commit unless every gate is green: secret scanning, credential-shaped-file detection, absolute-home-path and email-shape checks, a fixed-string employer/client wordlist expanded over delimiter variants, exclusion verification, a syntax build, the full 108-test suite, and a claims gate that re-runs the command behind each number here — including regenerating the synthetic database to confirm the row counts and the digest equality.
Development
.venv/bin/python -W error::ResourceWarning -m unittest discover # 108 tests
.venv/bin/python -m unittest discover -v # same, verbose
python3 -m compileall -q agent data eval gov server # syntax gate
python3 data/synth_cdp.py --seed 42 --out data/cdp.db # regenerate data
python3 -m gov.cli status # rails snapshot
python3 -m gov.cli report 7 # digest the log
python3 -m agent.loop # one governed cycle-W error::ResourceWarning is deliberate: an unclosed SQLite connection becomes a test failure rather than a warning nobody reads.
When adding a write-side tool: give it a tier in gov/policy.py first, then add the red-team attack that tries to bypass its gate, then implement it. When changing a rail, add the attack that the change is supposed to defeat.
Localization
The English README is canonical; 12 translations live under docs/i18n/ and are listed in docs/i18n/README-INDEX.md. Keep commands, paths, numbers, links, and measured claims synchronized across all of them — the claims gate will not let this file disagree with the code, and a translation must not disagree with this file. Note that the PII guard's regex shapes are Korean-specific (phone format, resident-registration-number shape), which is a property of the domain rather than of the documentation language.
Credits
See CREDITS.md for the four-tier register covering the synthetic dataset and every other non-code file, the fail-closed rule for unlisted content, and what a fork must remove. Its terms take precedence over the code licence for those files. The single third-party runtime dependency retains its own upstream licence wherever it is installed; requirements.txt is the authoritative record of it.
License
Source code is licensed under the Apache License 2.0; modification notices are recorded in NOTICE. Data files and other non-code content are not licensed by Apache-2.0 and remain governed by CREDITS.md.
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
- AlicenseAqualityDmaintenanceAn MCP server that acts as a gatekeeper for database and configuration changes, requiring proposals, dry-run simulations, and confirmation tokens before applying any modifications.Last updated81MIT
- Flicense-qualityFmaintenanceMCP server for Atomic CRM that enables agents to read and write CRM data via SQL queries, with OAuth authentication and Row Level Security enforced.Last updated4
- Flicense-qualityCmaintenanceA governed MCP server for integrating AI agents with customer data, featuring role-based access control, field redaction, and human-in-the-loop approval for secure support operations.Last updated1

Outfitofficial
Alicense-qualityAmaintenanceAn MCP server that enforces agent persona permissions by acting as a gateway, scoping tool access and denying unauthorized capabilities.Last updated286MIT
Related MCP Connectors
Autopilot MCP server for GEO analyses, reports, content, audits, memories and agents.
An MCP Server that provides identity verification and anti-fraud tools for AI agents via deepidv.
An MCP server giving access to Grafana dashboards, data and more.
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/euuuuuuan/crm-mcp-agent-public'
If you have feedback or need assistance with the MCP directory API, please join our Discord server