fundgraph

fundgraph

An MCP server that gives investment teams an entity-resolved knowledge graph of people and organizations, enabling graph-based retrieval like warm introductions and relationship analysis from scattered data sources.

Category
访问服务器

README

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.

fundgraph dashboard

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:4321

First 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.

The dashboard

warm path review queue
  • 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.
  • 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, 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) fundgraph ingest export.mbox none — streamed, so multi-GB archives are fine
Calendar export fundgraph ingest calendar.ics none
Contacts (Google Contacts, Attio, Affinity, any CSV) fundgraph ingest contacts.csv none
Granola (macOS) fundgraph ingest-granola none — reads the local cache
Attio workspace (live) fundgraph ingest-attio ATTIO_API_KEY — see below
Live Gmail/Calendar/Drive via gog fundgraph ingest-gog gmail gog already authenticated (local, or remote via FUNDGRAPH_GOG_SSH=user@host)
Live Gmail/Calendar/Drive via Google APIs fundgraph ingest-google gmail a Desktop OAuth client JSON in GOOGLE_OAUTH_CREDENTIALS

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.

  1. 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.
  2. Unzip. You'll get Takeout/Mail/All mail Including Spam and Trash.mbox, Takeout/Calendar/*.ics, and Takeout/Contacts/contacts.csv.
  3. 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 sync

The 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

Attio connector

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.

Design principles

  1. Everything resolves to two entities: people and organizations. Deals, funds, docs hang off those two.
  2. 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.
  3. 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.
  4. 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.
  5. 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 mcp

Tools: meeting_prep (one call: profile + relationship history + receipts + your warm paths to them), 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@domain into 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-mentioned factor. 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.

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 suite

The 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):

  • Privacy layers — per-user private sources contributing to shared answers without exposing underlying data ("a warm path exists via X" without X's emails)
  • 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
  • Merge/split tooling — merging two entities discovered to be the same person; undo for bad merges
  • Access control — role-based visibility for multi-user teams
  • Scheduled sync — periodic re-pull from live sources

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选