fundgraph
Ingests email data from Gmail exports (mbox files) or live via gog/Google APIs to build the knowledge graph of people, organizations, and relationships.
Ingests live Gmail, Calendar, and Drive data via Google APIs or Google Workspace/Takeout exports to build the fund's knowledge graph.
Ingests Granola (macOS) local cache for meeting notes as a data source for entity resolution and knowledge graph building.
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., "@fundgraphFind the warmest path from Dana Whitfield to Priya Nair"
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.
fundgraph
Open-source agentic data layer for investment teams. An entity-resolved knowledge graph over your fund's scattered data — email, calendar, meeting notes, docs, CRM — with a relationship-intelligence dashboard and a single MCP endpoint for Claude, ChatGPT, or Cursor.

Agents can't operate over millions of documents by guessing with vector search: they fetch the wrong things and don't know what exists. fundgraph gives them a deterministic map of reality instead — who exists, who knows whom, and how strongly — so retrieval is structured graph traversal, not similarity roulette.
systems of record fundgraph consumers
───────────────── ────────────────────────── ──────────────────────
gmail ─┐ ┌─ metadata layer web dashboard
calendar ─┤ ingest │ (what was ingested, Claude / ChatGPT / Cursor
drive ─┼────────▶ │ when, who's mentioned) via one MCP endpoint
granola ─┤ ├─ entity resolution
crm ─┤ │ (blocking → candidates →
mbox/ics/csv │ matching → human review)
│ └─ knowledge graph
│ (people + orgs, weighted edges,
│ warm-path traversal)Quickstart
Requires Node 20+. No database setup — embedded Postgres (PGlite) under ./data/; set DATABASE_URL to use real Postgres.
npm install
npm start # → http://localhost:4321First run shows onboarding: load the bundled (fictional) sample dataset with one click, or drop in your own export. Embedded mode is single-process (a lockfile enforces this): stop the web server before running CLI ingests, or use DATABASE_URL to run several processes.
Related MCP server: Graphiti MCP Server
The dashboard
|
|
Explore — search, click a node, get a brief: strongest relationships with the signals behind each score ("3 meetings, 2 emails, 1 co-authored doc"), recent shared documents, one-click Markdown export.
Radar — which relationships need attention now, judged against each pair's own learned cadence.
Warm path — the best route to an introduction, maximizing end-to-end relationship strength, with introducers ranked by their weaker leg.
Reviews — matches scoring 0.70–0.95 wait for a human; the system never merges identities on a guess. Decisions are audited and survive rebuilds.
Data — drag-and-drop ingestion, live connectors, team members and their privacy layers, per-source breakdown, audit trail.
Settings — what "a strong relationship" means differs by firm: signal weights, recency half-life, and saturation are editable live; saving rebuilds the graph instantly.
Ingesting your data
Source | Command | Setup needed |
Gmail export (Takeout) |
| none — streamed, so multi-GB archives are fine |
Calendar export |
| none |
Contacts (Google Contacts, Attio, Affinity, any CSV) |
| none |
Granola (macOS) |
| none — reads the local cache |
Attio workspace (live) |
|
|
Live Gmail/Calendar/Drive via gog |
| gog already authenticated (local, or remote via |
Live Gmail/Calendar/Drive via Google APIs |
| a Desktop OAuth client JSON in |
From a Google Workspace / Takeout export
Works on any account, including one you no longer actively use — you only need to be able to sign in once.
At takeout.google.com (signed in as that account) choose Mail, Calendar, and Contacts. For Mail, use "All Mail data included" or select specific labels; export as
.zip.Unzip. You'll get
Takeout/Mail/All mail Including Spam and Trash.mbox,Takeout/Calendar/*.ics, andTakeout/Contacts/contacts.csv.Ingest — order doesn't matter, entity resolution links them:
fundgraph ingest "Takeout/Mail/All mail Including Spam and Trash.mbox"
for f in Takeout/Calendar/*.ics; do fundgraph ingest "$f"; done
fundgraph ingest Takeout/Contacts/contacts.csv
fundgraph syncThe mbox is streamed and ingested in batches, so archive size is not bounded by
memory (measured ~420 messages/sec — a 100k-message account takes a few
minutes). Contacts exports use Google's own column names
(E-mail 1 - Value, Organization Name, split first/last), which the CSV
adapter handles directly; multiple addresses on one contact become one entity.
From an Attio workspace

In the dashboard (no terminal): open the Data tab → Attio workspace → paste your access token → Connect & sync. The key is verified against Attio before anything is stored, the first pull runs immediately, and the panel then shows the workspace, last sync, and a Sync now button for later refreshes.
Or from the CLI: export ATTIO_API_KEY=... && fundgraph ingest-attio && fundgraph sync.
To create the token: in Attio go to Workspace settings → Developers → Create
an integration, and grant read scopes for record and object_configuration
(add note to include notes).
A key pasted into the dashboard is stored in your local database and is
write-only across the API — no endpoint ever returns it, status shows a
masked hint (····1234) only, and it never reaches the audit log. It is stored
in plain text at the same trust level as the graph itself, so for shared or
server deployments prefer the ATTIO_API_KEY environment variable (which the
dashboard will detect and use without storing anything). Disconnect deletes
the stored key and leaves already-ingested data in place.
Pulls people, companies, and notes. A person's linked company becomes their org
hint, and all of a contact's addresses are attached to one entity — so an Attio
contact and their emails in Gmail resolve to the same person. Pass
--no-notes to skip notes (or if your token lacks the scope, notes are skipped
with a warning rather than failing the pull).
Then fundgraph sync (resolve + rebuild edges).
What gets read: live connectors (Granola, gog, Google APIs, Attio people/companies) read metadata and participant identities only. File exports (.mbox, .ics, .csv notes, .jsonl) also capture a size-capped plain-text body per document — stored locally in your database and mined only when you explicitly run unstructured extraction. Set FUNDGRAPH_NO_BODIES=1 to skip body capture entirely and keep the old metadata-only behavior.
Adapters emit a common JSONL shape (see sample/seed.jsonl); to add a source, emit that shape and fundgraph ingest file.jsonl. Ingestion is idempotent: re-ingesting updates in place, and review history is preserved.
Fixing what resolution missed
Resolution is deliberately conservative — conflicting evidence queues for review rather than merging — so real data always leaves a few duplicates (a work address and a personal one for the same person, resolved apart). Merge them:
fundgraph merge "Daniel Hull" "daniel@80x.ai" # keep the first, absorb the second
fundgraph unmerge "daniel@80x.ai" # reversible
fundgraph merges # what's been mergedOr in the dashboard: open a profile → Merge a duplicate…. Documents,
relationships, and addresses move to the survivor; the loser is kept as a
tombstone rather than deleted, so the merge stays reversible and unmerging gives
back exactly what the merge took (leaving an address behind would misroute
future mentions). Like review decisions, merges are human input — they're
recorded and replayed after a full reresolve instead of being lost.
fundgraph also flags automated senders (no-reply robots, notification
services) and hides them from relationship views — on a real inbox they're
otherwise half the graph. Role addresses like team@ or a client's hello@ are
treated as hints only and need broadcast behaviour (never replies, never in a
meeting) to be flagged, because a shared mailbox usually has a human behind it.
Nothing is deleted, every flag carries its reason, and fundgraph automated --list shows the lot.
Relationship radar — the timing layer

Strength answers who do I know well. Radar answers who should I contact now. Each pair's natural cadence is learned from real contact history, so overdue means overdue for them: three weeks of silence is unremarkable with a quarterly contact and alarming with a weekly one.
fundgraph radar # whole graph, most actionable first
fundgraph radar "Maya Chen" # one person's relationshipsEvery row carries its receipts — "last contact 16d ago · usually every 10d ·
6d overdue · 3 touches" — and statuses (active, due, overdue, cold,
dormant, new) plus a warming/steady/cooling trend comparing the last 90 days
with the 90 before. With no contact in either window the trend is null rather
than a fabricated "steady". Entirely deterministic: intervals and dates, no
model in the loop. Radar respects privacy layers, and agents get it as the
relationship_radar MCP tool.
Privacy layers

A relationship graph is only useful if people are willing to put their inbox in it — and nobody wants to hand their personal email to the whole team. So each member connects their own sensitive sources into a private layer that lives inside the shared graph:
Evidence is private. Connection strengths, signals, and documents from a member's layer are visible only to them. Another member's brief on the same person shows a
withheldDocumentscount and nothing else.Existence is shared. If the only route to someone runs through a colleague's private layer, you're told the route exists, which hop is locked, and who to ask — with no strength attached. That's the whole point of a relationship graph: "Seb can reach Priya, ask him."
Layers combine, they don't replace. Your own evidence is summed with the shared layer before saturation, so private data reinforces public data.
fundgraph members add "Seb Hopkins" seb@commixcapital.com
fundgraph ingest seb-inbox.mbox --as "Seb Hopkins" # → Seb's private layer
fundgraph path "Tom Hopkins" "Priya Nair" --as "Tom Hopkins"In the dashboard, the Viewing as switch in the header changes layer; the
Data tab manages members. For agents, FUNDGRAPH_VIEWER=<member> binds an MCP
server to one person's view.
What "existence is shared" actually means. A person the firm already knows
(they appear in any shared document) stays visible to everyone, and a colleague's
private correspondence with them surfaces as a locked hop — that is the feature.
But an entity that appears only inside one member's private layer is hidden
entirely by default, because the name itself can be the secret ("Project
Nightjar"). Set privateEntityVisibility: "reveal" in Settings to opt into the
fully-shared-names model instead; it is a deliberate choice, not a default.
Removing a member forces an explicit choice: delete their documents, or move
them into the shared layer where everyone will see them. Enforcement is
server-side on every query and npm test includes a leak probe that stuffs
markers into a private layer and greps every endpoint's response as another
member, but this is a cooperative model for a trusted
team on one local database, not a hostile-tenant boundary: anyone with
filesystem access to ./data or the ability to pass an arbitrary ?as= can
read any layer. Real multi-tenant isolation needs authentication, which is on
the roadmap below.
Design principles
Everything resolves to two entities: people and organizations. Deals, funds, docs hang off those two.
Two-layer data model. A metadata layer tracks what was ingested and who was mentioned; the knowledge graph holds resolved entities and weighted connections. The graph is a read model — rebuilt deterministically, never hand-edited.
Four-stage entity resolution: blocking → candidate generation → probabilistic matching → human review. Deterministic auto-merge at ≥0.95 confidence; 0.70–0.95 queues for a human; conflicting evidence (same name, different work domain) always asks. Without this, one person appears as 100+ duplicates across sources.
Never let an LLM score a relationship. Connection strength is computed from observable signals — meeting frequency, email reciprocity, co-authorship, recency decay — because models will confidently hallucinate a 3/10 relationship as a 10/10.
Graph-based retrieval, not pure vector. "Who can intro me to X?" is a weighted shortest-path query, answered with the evidence behind each hop.
MCP — agents on the graph
claude mcp add fundgraph -- node /path/to/fundgraph/src/cli.js mcpTools: meeting_prep (one call: profile + relationship history + receipts + your warm paths to them), company_memory (every recorded deal signal for a company — investments and passes with their reasoning — with document provenance), find_warm_path, find_introducers, entity_brief, search_entities, strongest_connections, graph_stats, review_queue, review_resolve.
CLI
fundgraph web [port] dashboard (default 4321)
fundgraph ingest <file> .jsonl | .mbox | .ics | .csv
fundgraph ingest-granola [path] Granola local cache (macOS)
fundgraph ingest-gog <service> live pull via gog: gmail | calendar | drive
fundgraph ingest-google <service> live pull via Google APIs
fundgraph sync [--extract] resolve + rebuild edges (--extract mines bodies first)
fundgraph extract [--limit N] LLM mention extraction over unprocessed bodies
fundgraph reresolve rebuild entities from scratch (decisions replayed)
fundgraph entities | brief | path | intros | review | stats
fundgraph mcp MCP server (stdio)Unstructured extraction
Headers and attendee lists are a fraction of what a fund knows. The bodies — "our
IC chair Alistair Penhale has asked…", "Sam Okafor at Halcyon co-invested with us
on three deals" — name people and organizations no structured field ever sees.
fundgraph extract mines them with an LLM and feeds the results through the
same resolution, review, and edge pipeline as everything else:
export ANTHROPIC_API_KEY=... # or `ant auth login`
fundgraph extract # mine all unprocessed bodies
fundgraph sync --extract # or as part of a sync(Or press Extract pending documents on the dashboard's Data tab.)
Extraction never gets to bend the graph's rules:
Structured output, not free text — the model can only return typed mention candidates; a prompt-injected document can at worst distort which candidates come back, never make the pipeline do something.
Deterministic grounding — every candidate must literally appear in the document text. Names not in the text are dropped; emails are kept only if the exact address string is present (a model can never "complete"
name@domaininto existence); low-confidence candidates are dropped.Same trust model as any mention — extracted mentions carry
origin='extracted', a confidence, and a verbatim source quote; they resolve through blocking → matching → human review like structured mentions, and co-occurrence is damped by the merely-mentionedfactor. Connection strength stays deterministic (principle 4): the LLM proposes candidates; it never scores a relationship.Idempotent + resumable — each document records a hash of (prompt version, model, body); re-runs skip clean documents, re-extract changed ones, and retry failures. Three consecutive failures abort the run.
Extraction also mines fund memory: when a document records an investment
decision (an IC memo's INVEST or PASS, a board pack, a round discussion), a
deal record is kept — company, stage, status, the stated reasoning, and the
document it came from. fundgraph memory <company> or the company_memory
MCP tool answers the question every fund eventually asks: "have we seen this
company before, and why did we say no?" Deals hang off organizations
(principle 1) and link to entities at query time, so rebuilds never orphan
them; passes are first-class, because a recorded no is the memory that saves
the next diligence cycle.
Configuration: FUNDGRAPH_EXTRACT_MODEL (default claude-opus-5;
claude-haiku-4-5 is the budget option), FUNDGRAPH_EXTRACT_EFFORT
(default low), FUNDGRAPH_EXTRACT_MIN_CONFIDENCE (default 0.6).
Details, cost notes, and the threat model: docs/extraction.md.
How connection strength works
Each co-occurrence contributes weight(kind) × decay(age): meetings 3, calendar events 2, direct emails 2.5 (cc'd 1), co-authored docs 1.5, merely-mentioned participants halved — 180-day half-life. Strength is 1 − e^(−W/6), saturating toward 1. Warm paths maximize the product of hop strengths (hop-bounded Dijkstra over −ln(strength)). Every number is tunable in Settings, per database.
Testing
npm test # resolution smoke suite + API suite + extraction suiteThe extraction suite runs the full pipeline against a scripted fake model — grounding, idempotency, failure isolation, and resolution integration are all covered offline; no API key needed.
Both suites run on throwaway databases. The codebase has been through three adversarial multi-agent review passes; all 27 confirmed findings are fixed with regression coverage (see CHANGELOG).
Status & roadmap
Working today: everything above. Not yet built (PRs welcome):
Bodies from live connectors — file exports capture bodies today; the Granola/gog/Google/Attio live pulls are still metadata-only
Batch extraction — large backfills through the Anthropic Batches API at 50% token cost
Authentication — privacy layers are enforced on every query but assume a trusted team on one machine; real multi-tenant isolation needs login and per-user sessions
Scheduled sync — periodic re-pull from live sources
License
MIT
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
AlicenseAqualityAmaintenanceMCP server for the Graphite Financial Knowledge Graph, enabling natural language queries about companies, supply chains, executives, regulations, and patents via MCP-compatible clients.Last updated7MIT- Flicense-qualityDmaintenanceThis MCP server extracts entities and relationships from text and stores them in Neo4j, supporting multiple isolated knowledge graph projects that share the same database.Last updated101
- Alicense-qualityDmaintenanceAn MCP server that provides AI agents with structured, real-time data on cryptocurrency investment funds, enabling deeper due diligence and portfolio intelligence.Last updated3MIT
Related MCP Connectors
Knowledge coverage map and health score. Ingest docs into a governed knowledge graph via MCP.
Identity resolution MCP server for phone/email lookups across 31+ services. Global + India coverage.
Remote MCP server to enrich company profiles with structured B2B data and confidence scores.
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/clippycommits/fundgraph'
If you have feedback or need assistance with the MCP directory API, please join our Discord server

