Graph CRM MCP Server
Enables AI assistants like Claude to read and write contacts, relationships, and interactions in a personal CRM via a graph-based API.
README
Graph CRM
A personal, single-user CRM that visualizes contacts and their relationships as a graph. Node/Express + Prisma backend (SQLite by default), vanilla JS frontend (no build step), WebAuthn passkey login, and an MCP server exposing the full API so Claude can read/write the CRM directly.
Setup
npm install
cp .env.example .env
npx prisma migrate deploy
npm start # http://localhost:3000
First visit walks you through creating a passkey (Face ID / Touch ID / security key / device screen lock). See .env.example for optional configuration (custom port, RP_ID/ORIGIN if not running on localhost:3000, etc).
npm run dev # auto-restart on file changes
npx prisma migrate dev --name <name> # after editing prisma/schema.prisma
There's no test suite or linter — see CLAUDE.md for architecture notes if you're working on this codebase.
Docker
docker build -t graph-crm .
docker run -p 3000:3000 -v graph-crm-data:/app/data graph-crm
The /app/data volume holds everything stateful: the SQLite database, the session store, and generated secrets (session secret, passkey data lives in the DB itself). Without a mounted volume, all of that is lost when the container is removed.
If you're serving this behind a domain other than localhost:3000, set RP_ID and ORIGIN (see .env.example) — WebAuthn passkeys are bound to the origin they were created on and won't work if it changes.
Swapping the database backend
The app uses Prisma, so moving off SQLite doesn't require touching any application code — only prisma/schema.prisma and the connection string. Everything else (family.js, the REST API, mcp-server.js, the frontend) talks to Prisma's generated client, not to SQLite directly.
General steps, then Postgres/MySQL specifics below:
- Change the
providerinprisma/schema.prisma'sdatasourceblock. - Point
DATABASE_URLat the new database. - Delete
prisma/migrations/and generate a fresh initial migration against the new provider (npx prisma migrate dev --name init) — the existing migration history was written for SQLite's SQL dialect and won't replay cleanly on a different engine. There's no automatic data carry-over; if you need existing contacts, export them first (Settings → API keys → generate one → pull data via thelist_contacts/get_directoryendpoints or MCP tools, then re-import after switching). npx prisma generateto rebuild the client.
Postgres
docker run -d --name graph-crm-pg -e POSTGRES_PASSWORD=devpass -e POSTGRES_DB=graphcrm -p 5432:5432 postgres:16
prisma/schema.prisma:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
.env:
DATABASE_URL="postgresql://postgres:devpass@localhost:5432/graphcrm"
rm -rf prisma/migrations
npx prisma migrate dev --name init
npm start
For a hosted Postgres (Supabase, Neon, RDS, etc.), just swap the connection string — most give you a ready-made postgresql://... URL. Neon/Supabase's pooled connection strings work fine with Prisma; if you hit prepared-statement errors behind a pooler, add ?pgbouncer=true to the URL (Prisma's documented workaround).
MySQL
docker run -d --name graph-crm-mysql -e MYSQL_ROOT_PASSWORD=devpass -e MYSQL_DATABASE=graphcrm -p 3306:3306 mysql:8
prisma/schema.prisma:
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
.env:
DATABASE_URL="mysql://root:devpass@localhost:3306/graphcrm"
rm -rf prisma/migrations
npx prisma migrate dev --name init
npm start
Provider-specific things worth checking after switching
- The
Credential.publicKeyfield isBytes— MySQL maps this toLONGBLOB, Postgres toBYTEA; both work fine with Prisma's client, no schema changes needed. ApiKey.lastUsedAtand otherDateTime?fields are nullable on all providers. Postgres storestimestamptzunder Prisma's default mapping; MySQL'sDATETIMEhas no timezone awareness — only matters if you care about exact cross-timezone display oflastUsedAt/createdAt.- Both Postgres and MySQL enforce foreign keys and unique constraints the same way SQLite does here (
onDelete: Cascade,@@unique), so the cascade-delete behavior used throughoutfamily.js/server.js(deleting a contact cleans up their relationships, interactions, credentials, etc.) carries over unchanged. - Running Postgres/MySQL in Docker alongside the app: add both as services in a
docker-compose.yml(not included here — this repo ships a single-containerDockerfilesince SQLite needs no separate DB service) and pointDATABASE_URLat the DB service's hostname instead oflocalhost.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.