sfgraph
Provides tools to interact with Salesforce orgs, including live-syncing metadata and data to a local knowledge graph, enabling AI agents to analyze Apex, LWC, Flow, Vlocity, OmniStudio, security, and integrations without leaving the local machine.
Click on "Deploy 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., "@sfgraphshow me all Apex triggers and their related objects"
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.
@ryanstark24/sfgraph
A local, privacy-first knowledge graph for Salesforce orgs. sfgraph live-syncs your org to a SQLite + vector index on your machine and exposes 28 MCP tools to Cursor, Claude Code/Desktop, and VS Code, so the AI you already use can reason about Apex, LWC, Flow, Vlocity, OmniStudio, security, and integrations without your code or schema ever leaving your laptop.
┌──────────────────────────────────────────────────────────────────────┐
│ Cursor / Claude / VS Code ←──── MCP stdio ────→ sfgraph │
│ │
│ read-only Salesforce APIs ──→ your org │
│ local SQLite + sqlite-vec ←── OS data dir │
└──────────────────────────────────────────────────────────────────────┘Privacy in one line. Nothing leaves your machine — graph, vectors, logs all live under the platform's user-data directory (~/Library/Application Support/sfgraph/ on macOS, ~/.local/share/sfgraph/ on Linux, %APPDATA%\sfgraph\ on Windows; see docs/DATA_LOCATIONS.md). Salesforce auth is delegated to the sf CLI (token stays in ~/.sfdx/). Every connection is wrapped in a read-only Proxy. Full threat model: docs/PRIVACY.md.
Install
1. Prerequisites
How | |
Node.js ≥ 20 | nodejs.org or |
|
|
At least one |
|
Verify:
node --version # v20+ (v22 LTS recommended)
sf org list # at least one org marked as default2. Install sfgraph
npm install -g @ryanstark24/sfgraphOr run on-demand via npx @ryanstark24/sfgraph <command> without installing.
After install, sfgraph is on your PATH.
3. Wire it into your editor
sfgraph installIdempotent. Copies 20 skill playbooks into ~/.claude/skills/ + ~/.cursor/rules/ and adds a sfgraph entry to your editor's MCP config. Existing MCP entries are preserved. Use --target=claude|cursor|vscode to wire only one, or --dry-run to preview. Start with sf-graph-router — it routes intent to the right skill and enforces grounding answers in the org graph before generating Salesforce code.
Using a different IDE or LLM client?
sfgraph install writes config for Claude / Cursor / VS Code automatically. For any other MCP-compatible client (Windsurf, Zed, Continue, Cline, an OpenAI- or Gemini-based agent with MCP support, your own custom host, etc.), add this entry to the client's MCP config file manually:
{
"mcpServers": {
"sfgraph": {
"command": "npx",
"args": ["-y", "@ryanstark24/sfgraph", "mcp"]
}
}
}On Windows, use "npx.cmd" instead of "npx".
Pinning the Node binary. Some hosts (sandboxed Electron apps, IDE extensions) ship with a bundled Node whose ABI differs from your shell's. If that bundled Node lacks a matching better-sqlite3 prebuilt, the MCP child fails to load. Pin to your shell's Node:
{
"mcpServers": {
"sfgraph": {
"command": "/Users/you/.nvm/versions/node/v22.21.1/bin/node",
"args": ["/usr/local/bin/sfgraph", "mcp"]
}
}
}Use which node and which sfgraph to fill in the paths. Same effect as sfgraph install --local --pin-node "$(which node)" but written by hand into a client we don't have a built-in target for.
Where each known client keeps its MCP config:
Client | Config path |
Claude Desktop |
|
Claude Code (CLI) |
|
Cursor |
|
VS Code |
|
Windsurf |
|
Zed |
|
Continue (VS Code) |
|
Cline (VS Code) |
|
After editing the file, fully restart the client so it re-reads the MCP server list. Then ask the agent something like "list orgs from sfgraph" to confirm the tools are visible.
The skill playbooks (sf-impact-from-diff, sf-security-audit, etc.) are Claude/Cursor-specific. On other clients, the agent still has direct access to all 28 MCP tools — it just routes by tool name instead of by skill trigger.
4. Verify the install
sfgraph doctorEnd-to-end self-check: Node ABI, native bindings, code-signing (macOS), data dir, org DBs, sf CLI, IDE MCP configs. Each failed check prints a copy-paste fix.
If you see a bindings file not found / ABI mismatch (common after a Node upgrade or on a brand-new Node release with no prebuilts yet):
sfgraph rebuild-bindingsRelated MCP server: lore
First ingest
The first sync of an org takes 2–6 minutes on a typical 50K-node sandbox. Subsequent syncs on Source-Tracking-enabled orgs are incremental (<30 s).
# Default org from `sf config target-org`
sfgraph ingest
# Or pick an org explicitly
sfgraph ingest --org my-prodThe graph lands in <data-dir>/<orgId>.sqlite (macOS: ~/Library/Application Support/sfgraph/, Linux: ~/.local/share/sfgraph/, Windows: %APPDATA%\sfgraph\). From this point every MCP tool reads only from that file — no network calls.
Keep it fresh. Re-run sfgraph ingest whenever you want current data. Skills warn the agent when the graph is older than 7 days.
For tuning, large-org options, multi-org ingest, and rebuild flags, see docs/CLI.md.
Use it from your editor
Restart your IDE so it picks up the new MCP entry. Then in any project ask the agent:
"What does this PR break?"
"Who reads
Account.Status__c?""What changed in prod since last week?"
"Show me how
accountTileflows from UI to DB."
The agent routes to the right tool automatically via the installed skill playbooks. A short worked example:
User: I'm about to merge this PR. Anything I should worry about?
Agent: *invokes sf-impact-from-diff*
→ impact_from_git_diff(diff="…", depth=3)
→ test_gap_intelligence_from_git_diff(diff="…")
Your diff touches 3 nodes. 9 dependents at 3 hops:
• 4 covered by tests (green)
• 5 at-risk (no IS_TEST_FOR):
- LWC:opportunityTile
- ApexMethod:BillingSvc.run(2)
- ApexMethod:BillingSvc.dryRun(0)
- Flow:Order_Status_Update
- LWC:invoiceTile
Recommend adding test coverage for BillingSvc.run(2) before merging.More worked examples: docs/SAMPLES.md.
Optional: web visualiser
sfgraph serve # http://localhost:7777A 3D force-graph explorer for the ingested org. Loopback-only by default. See docs/WEB.md.
Reliability
Wedge isolation (Phase 1.5)
A slow or hung source no longer blocks neighbors. When the per-source watchdog (90s first-yield, 5min inactivity) fires, the source's slot is released and the next queued source runs. The wedge runs to completion in the background; late records are drained with attributes.lateYield: true.
You will see warnings of the form wedge:<source>:<reason>:... in the ingest run summary — these are now informational (the run continues), not fatal.
Socket-leak caveat (honest disclosure). The underlying HTTP request to Salesforce is NOT cancelled (jsforce 3.10.15 does not expose AbortController). Wedged sockets are reaped by Node's idle-timeout (~10min). Worst-case memory: 4 wedges × ~1MB ≈ 4MB per ingest, garbage-collected at process exit. The cap is SFGRAPH_MAX_BACKGROUND_WEDGES (default 4).
Detect-deletions drop-ratio guard (Phase 1.5)
When run with --detect-deletions --rebuild, sfgraph refuses to wipe a label whose drop ratio exceeds SFGRAPH_DETECT_DELETIONS_MAX_DROP_RATIO (default 0.30). A wedge-induced empty stream emits a wedge:detect-deletions:refuse:label=<L>:reason=empty-stream warning instead of silently destroying the label. Refused labels keep their previous last_seen_at so the staleness clock keeps ticking — staleness reports will still surface them.
Diagnostics
When ingest reports skips you don't understand, use the diagnose subcommand:
sfgraph diagnose <orgId>diagnose forces source / Tooling / Metadata / Data pool concurrency to 1 and writes a structured JSON report capturing per-source timing, wedge events, capability probes, and detect-deletions refusals. By default it writes to a temporary graph DB so your main org graph is untouched.
Note: wall-clock is NOT comparable to a production run — diagnose names wedges, it does not predict prod throughput.
Default report path (platform-aware, under the same data dir as the graph):
Platform | Path |
macOS |
|
Linux |
|
Windows |
|
Flags:
Flag | Default | Effect |
| (auto) | Override the default report path. |
|
| Overall diagnose timeout (10 min). |
|
| Stream per-source timing to stdout in addition to the JSON report. |
|
| Write to the real org graph DB instead of a temp DB. |
MCP staleness signal
Every MCP tool response carries a _meta.staleness block:
{
generation: number, // monotonic per-org sync counter
in_progress: boolean, // true if an ingest is currently rewriting the graph
started_at: string | null, // ISO timestamp of the in-progress ingest
last_sync_at: string | null // ISO timestamp of the most recent completed sync
}Reader-side contract. MCP clients should check staleness.in_progress === true to warn users that the graph is being rewritten and results may reflect partial state. Tools that don't carry an orgId argument (e.g. ping, list_orgs) omit the block instead of guessing.
Environment variables
Authoritative inventory — every SFGRAPH_* env var read at runtime, sorted alphabetically. Verified via grep -rn "process.env.SFGRAPH_" packages/ --include="*.ts".
Name | Type | Default | Purpose | Since |
| bool ( | unset | Bypass the "graph DB must live under data dir" safety check. | 1.0 |
| string |
| Apex class parser strategy ( | 1.0 |
| int |
| Skip-count threshold above which | 1.0 |
| int |
| Tooling SOQL adaptive bisection depth cap. | 1.0 |
| path | platform default | Override OS cache directory. | 1.0 |
| path | platform default | Override OS config directory. | 1.0 |
| path | platform default | Override OS data directory (where | 1.0 |
| int | varies | Data API pool concurrency. | 1.0 |
| bool ( | unset | Verbose ingest logging (per-source counters, dispatch table, etc.). | 1.0 |
| bool ( | unset | Print pool-counter snapshots during ingest. | 1.0 |
| float |
| Per-label drop-ratio threshold above which | 1.5 |
| int | model default | Embedding model dimensionality override. | 1.0 |
| string | model default | Embedding model identifier override. | 1.0 |
| path | (auto) | Local path to a custom embedding model file. | 1.0 |
| bool ( | unset | Disable | 1.0 |
| bool ( | unset | Skip the | 1.0 |
| bool ( | unset | Include managed-namespace components globally (Apex body, generic metadata, LWC source). | 1.0 |
| bool ( | unset | LWC-only override for managed-namespace inclusion (independent of the global flag). | 1.0 |
| bool ( | unset | Include platform telemetry SObjects ( | 1.0 |
| int (ms) | (impl default) | Per-wedge late-yield drain budget — how long the background runner gets to drain late records before being abandoned. | 1.5 |
| path | platform default | Override OS log directory. | 1.0 |
| int |
| Cap on simultaneous background wedges per ingest. | 1.5 |
| int | varies | Metadata API pool concurrency. | 1.0 |
| int |
|
| 1.0 |
| bool ( | unset | Disable automatic retry on watchdog wedge / skip cascade. | 1.0 |
| bool ( | unset | Skip the pre-ingest liveness probe. | 1.0 |
| bool ( | unset | Force serial source execution (debug aid; bypasses the sliding-window merger). | 1.0 |
| csv | unset | Skip specific LWC bundle | 1.0 |
| csv | unset | Skip specific SObjects by | 1.0 |
| int | (impl default) | Skip-count threshold for | 1.0 |
| int |
| Concurrency of the sliding-window source merger in | 1.0 |
| path | platform default | Override OS temp directory. | 1.0 |
| int |
| Tooling API pool concurrency. | 1.0 |
| int | (impl default) | Cap on nodes visited by dependents / dependencies traversal in the analysis layer. | 1.0 |
| int (ms) |
| Per-source first-yield watchdog timeout. | 1.5 |
| int (ms) |
| Per-source inactivity watchdog timeout (5 min). | 1.5 |
Honest disclosures — known limitations
sfgraph aims to be honest about gaps. Read this section before relying on it for security or compliance audits.
Security model gaps. Profile / PermissionSet / SharingRules are ingested as first-class nodes with
GRANTS_*edges. However, PermissionSetGroup, MutingPermissionSet, ProfileSessionSetting, ProfilePasswordPolicy are ingested as opaque generic nodes WITHOUTGRANTS_*orDENIES_*edges — they exist as nodes but their security semantics are not modeled. Audits that rely on these edges will not surface findings for those types until a future Security phase.Security analysis caps. The analysis layer caps results at 5000 per label (
SECURITY_PER_LABEL_CAP). On orgs with more than 5k Profiles or PermissionSets, analysis is truncated with atruncated: trueflag — but graph storage is complete.Generic-type whitelist. sfgraph dispatches ~80 of the ~327 metadata types Salesforce returns from
describeMetadata()to the parsed extractor path. The rest are recorded only as opaque generic nodes when matched by the whitelist; everything else is filtered out. SetSFGRAPH_INCLUDE_ALL_GENERIC=1to override (every discovered type runs through the generic extractor — longer ingest, more opaque nodes). The full type list is documented indocs/COVERAGE.md.LWC empty-bundle behavior change (Phase 1.5). Prior versions yielded a stub
RawMemberwithfiles: {}on per-bundle resource-fetch failure, creating empty bundle nodes in the graph. Phase 1.5 emits awedge:lwc:bundleFetchFailed:...warning and no record. Users who upgrade may see previously-recorded empty LWC bundles disappear from their graph on the next re-ingest. This is correct.Socket leak on wedged HTTP requests. When the per-source watchdog fires, sfgraph releases the slot but the underlying jsforce HTTP request is NOT cancelled (no
AbortControllerexposed by jsforce 3.10.15). The socket is reaped by Node's idle-timeout (~10min). Worst case:SFGRAPH_MAX_BACKGROUND_WEDGES(default 4) × ~1MB ≈ 4MB transient memory per ingest, GC'd at process exit. Tracked as future hardening; an upstream jsforce PR or fork is needed for true in-flight HTTP cancellation.
Coverage
sfgraph mixes deep parsing (Apex, LWC, Flow, Object, Profile/PermissionSet, NamedCredential, Vlocity, OmniStudio) with opaque-node fallback for the long tail of metadata types. Coverage is dynamic, not hardcoded — at ingest start, conn.metadata.describe(apiVersion) asks the org for its full supported type list, which automatically includes types added by managed packages or future Salesforce releases. Each type is routed to a named extractor, the generic opaque-node path, or filtered out.
See docs/COVERAGE.md for the full status matrix: every type, the edges it emits, known limitations, and the source file that implements it.
Documentation
Full CLI reference — every command, every flag | |
The 28 MCP tools — schemas, examples, algorithms | |
The 20 skill playbooks installed into your editor | |
Worked agent-conversation examples | |
Metadata coverage matrix and SObject classification logic | |
Local web visualiser | |
Diagnose and fix common install / ingest issues | |
Architecture decisions, analysis pipeline, TS rewrite rationale | |
Storage model + ingestion pipeline deep-dive | |
Read-only enforcement, sanitizer, telemetry threat model | |
What lives where on your machine | |
Build, test, contribute | |
Per-release notes |
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Salesforce-grounded retrieval, diagnoses, and a vetted-Force marketplace for MCP clients.
Query your org's data in natural language — read-only MCP access to SQL, NoSQL, files & warehouses.
Give your AI agent persistent, governed memory for every project. At task start it recalls the approved decisions, conventions, risks and architecture (semantic search, ranked by importance); at close it proposes what was learned as typed memories that you review and approve — governance, not a notes dump. Agents propose, humans govern: edits go back to pending and deletion is human-only by design. Connect Claude Code, Cursor, Claude Desktop or any MCP client in two minutes with just your API key — hosted (nothing to install) or locally via `uvx solucortex-mcp`. Built by SoluAI and dogfooded daily: SoluCortex is developed using its own living memory.
Private-by-default, local-first memory/context/task orchestrator for MCP apps and agents.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceDev intelligence layer that builds a knowledge graph from any codebase and exposes 7 MCP tools for graph-powered reasoning, impact analysis, and preflight safety and governance checks.222 PyPI32Apache 2.0
- AlicenseNot gradedqualityFmaintenanceLiving typed knowledge graph for software projects, exposed over MCP so coding assistants can capture and query modules, capabilities, flows, events, rules and decisions across sessions. SQLite-backed, schema-validated, ships as a Claude Code plugin.MIT
- FlicenseNot gradedqualityDmaintenanceAI-native code intelligence graph that builds a persistent knowledge graph of your codebase in Neo4j and exposes it to AI assistants via MCP, enabling contextual code analysis, impact analysis, and dependency tracking.23-
- AlicenseAqualityDmaintenanceEnables AI tools like Claude Desktop and Cline to interact with Salesforce, providing tools for SOQL queries, Apex execution, metadata management, and more.1717 npm43MIT