npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sf-context-engine

v1.3.0

Published

Index Salesforce metadata and source evidence into SQLite. Six MCP tools provide dependency analysis, matched snippets, and Apex predicate inspection.

Readme


sf-context-engine indexes your entire Salesforce DX project into a SQLite dependency graph and serves it through an MCP server. Works with any MCP-compatible clientClaude Code, Cursor, Windsurf, Claude Desktop, Zed, and more. One tool call replaces dozens of file searches.

  • 12 typed parsers — objects, fields, flows, Apex, LWC, layouts, profiles, permissions, reports, and more
  • 18,600+ dependency relationships across 41 ref types — lookups, triggers, embeds, grants, formula refs, query predicates
  • Sub-millisecond queries on a portable SQLite file with FTS5 full-text search
  • ~1.4s full index, ~120ms incremental — content-hash based, only re-parses what changed

Why?

Without sf-context-engine, every Salesforce question triggers a cascade:

You:  "What LWCs are on the Opportunity record page?"
LLM:  glob flexipages/*Opportunity*          → 4 files
      read 2,000+ lines of XML each          → 8K tokens burned
      grep for componentName                  → partial list
      realize Quick Actions launch LWCs too   → more searching
      grep quickActions/*Opportunity*         → 3 more files
      read each for lightningWebComponent     → finally finds the LWC
      ...still hasn't checked permissions

6+ tool calls. 10K+ tokens. 30+ seconds. Incomplete answer.

With sf-context-engine:

You:  "What LWCs are on the Opportunity record page?"
LLM:  describe_object("Opportunity")  → complete answer, one call

Fields, LWC components, flows, Apex, layouts, permissions, reports, relationships — all from a single graph traversal in under 5ms.

Quick Start

# Install in your Salesforce DX project
npm install sf-context-engine
npm run build          # if installing from source

# Initialize for Claude Code (default)
npx sf-context-engine init

# Or wire a specific MCP client
npx sf-context-engine init --client cursor
npx sf-context-engine init --client codex
npx sf-context-engine init --client auto

# Build the index
npx sf-context-engine index

# Enrich with org-level dependencies (Tooling API)
npx sf-context-engine enrich

# Verify
npx sf-context-engine status

That's it. Start your configured client — the MCP tools are available as soon as the index exists.

Upgrading from v1.2 or earlier: run npx sf-context-engine index once after updating. The database schema migrates automatically, and the first index run backfills source text and dependency evidence. Restart the MCP client afterward.

What init does

  1. Verifies sfdx-project.json exists (you're in a Salesforce DX project)
  2. Creates .sf-context/ with a SQLite database
  3. Prompts for an org alias (or pass --org-alias myOrg)
  4. Wires one or more client configs depending on --client
  5. Wires SessionStart + SubagentStart hooks into .claude/settings.local.json when claude-code is selected
  6. Copies bundled Claude Code skills when claude-code is selected
  7. Adds .sf-context/ to .gitignore

Supported init targets

| --client value | What gets configured | |------------------|----------------------| | claude-code (default) | Project .mcp.json + .claude/settings.local.json hooks | | cursor | Global Cursor MCP config at ~/.cursor/mcp.json | | codex | Global Codex MCP config at ~/.codex/config.toml | | kilo | Project Kilo MCP config at .kilocode/mcp.json | | claude-desktop | Claude Desktop config at ~/Library/Application Support/Claude/claude_desktop_config.json | | auto | Claude Code project files plus any detected installed clients above |

Using with other MCP clients

The MCP server is standard stdio and works with any client that supports MCP. If your client doesn't use the built-in init --client ... wiring, point it at the package CLI's serve subcommand:

Cursor / Windsurf / Zed:

Add to your MCP config (the exact location varies by client):

{
  "mcpServers": {
    "sf-context-engine": {
      "command": "node",
      "args": ["node_modules/sf-context-engine/dist/cli/index.js", "serve"],
      "env": {
        "SF_CONTEXT_PROJECT_ROOT": "/path/to/your/salesforce-project"
      },
      "cwd": "/path/to/your/salesforce-project"
    }
  }
}

Claude Desktop:

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "sf-context-engine": {
      "command": "node",
      "args": ["node_modules/sf-context-engine/dist/cli/index.js", "serve"],
      "env": {
        "SF_CONTEXT_PROJECT_ROOT": "/path/to/your/salesforce-project"
      },
      "cwd": "/path/to/your/salesforce-project"
    }
  }
}

Any MCP client (generic):

Run node node_modules/sf-context-engine/dist/cli/index.js serve. The server uses stdio transport and expects either:

  • cwd to be your Salesforce DX project root
  • or SF_CONTEXT_PROJECT_ROOT=/path/to/project

Note: claude-code is the only client target with context injection today. Other clients get the same 6 MCP tools, but not the SessionStart/SubagentStart hot-tier hooks.

Note: Cursor, Codex, and Claude Desktop use client-level config files, so init pins those entries to the current project root. Re-run init from another project to retarget them.

Note: init prefers the project's local node_modules/sf-context-engine install when wiring MCP clients. If you run init from an ephemeral npx cache, it falls back to npx --yes sf-context-engine serve so the generated config still works.

MCP Tools

Six tools, all available through any configured MCP client after init:

describe_object

The flagship tool. Returns the complete profile of any Salesforce object by walking the full dependency graph:

| Section | What you get | |---------|-------------| | Fields | Every field with type, label, required flag, lookup target | | Validation Rules | Full formulas, error messages, active/inactive status | | Record Types | Names, labels, active status | | Lightning Pages | FlexiPages with embedded LWC/field/action counts | | LWC Components | Direct page embeds + indirect via Quick Actions, with Apex call chains | | Quick Actions | What each action launches — LWC, Flow, or record form | | Flows | Record-triggered (separated from other references), with trigger type | | Apex | Classes with auto-classified roles (Service, Batch, Controller, etc.) | | Page Layouts | Field counts, related lists, surfaced actions | | Security | Profile/permission set CRUD grants in a scannable table | | Reports | Every report referencing this object's fields | | Relationships | Lookup/master-detail connections in both directions | | List Views | All list views with labels |

Use the sections parameter to request only what you need and save tokens:

describe_object("Opportunity", sections: ["flows", "apex", "lwc"])
→ ~640 tokens instead of ~3,700

find_dependencies

Impact analysis for any metadata component. Supports multi-hop traversal, cursor pagination, and call-site evidence:

find_dependencies("Account.Industry__c", direction: "downstream", depth: 2)
→ Hop 1: VRs referencing this field, layouts displaying it, FLS grants
→ Hop 2: profiles granting those permissions, reports using those layouts

For indexed Apex and LWC paths, edges include caller/callee method names, passed arguments, line numbers, and source snippets. Apex field edges distinguish selects_field, filters_on, groups_by, and orders_by instead of treating every field occurrence as a generic reference.

Use page_size and the returned next_cursor for large dependency graphs. Pagination is returned in both the text response and MCP structuredContent.

inspect_apex

Method- and statement-level Apex inspection with exact source evidence:

inspect_apex("CaseKnowledgeService", method: "findArticles")
→ method signature and line range
→ static SOQL projection, WHERE predicate, filter fields, and security mode
→ calls with target methods and passed arguments
→ DML, constants, and dynamic-query proof limitations

When a dynamic query predicate cannot be proven from static source, the tool reports that limitation explicitly instead of inferring runtime filtering.

search_metadata

Full-text search across all 3,200+ indexed items:

search_metadata("Sharepoint", metadata_type: "ApexClass")
search_metadata("Budget", parent_name: "Opportunity", sub_type: "Currency")

Prefix matching by default — Account finds AccountService, AccountTrigger, etc. Results include matched source snippets with file and line locations, plus cursor pagination and MCP structuredContent.

get_object_list

Quick overview of the org's data model:

get_object_list(filter: "Budget")
→ Table: Object | Label | Fields | VRs | Record Types

get_index_status

Index health, freshness, and tool usage statistics for the current session.

What Gets Indexed

12 Typed Parsers + Generic Fallback

Every parser extracts both structure (metadata) and connections (dependencies):

| Parser | Source | Key Extractions | |--------|--------|----------------| | Object | .object-meta.xml | Sharing model, features | | Field | fields/*.field-meta.xml | Type, required, formula, lookup target | | Validation Rule | validationRules/*.validationRule-meta.xml | Formula, error message, field refs | | Flow | .flow-meta.xml | Trigger object/type, CRUD ops, Apex calls, subflows, email alerts | | Apex Class | *.cls source code | Methods, SOQL projections/predicates/security modes, field usage, call sites/arguments, DML targets, constants, annotations; auto-classifies role | | LWC | *.js + .js-meta.xml + HTML | Apex imports, schema refs, child components, object targets | | Quick Action | .quickAction-meta.xml | LWC/Flow launches, target objects, field refs | | FlexiPage | .flexipage-meta.xml | Embedded LWCs, Dynamic Forms fields, Quick Actions | | Layout | .layout-meta.xml | Fields, related lists, actions | | Permission Set | .permissionset-meta.xml | FLS, CRUD, Apex class access, custom permissions | | Profile | .profile-meta.xml | FLS, CRUD, layout assignments, app/RT visibility | | Report/ReportType | .report-meta.xml | Report type, field refs from columns/filters/groupings | | Generic | Any -meta.xml | Name, type, label for 40+ additional types |

41 Dependency Types

Relationships     lookup, master_detail
Flow automation   triggers_on, lookups, creates, updates, invokes, calls_subflow,
                  sends_alert, references
Apex code         queries, calls, instantiates, extends, implements, dml_on,
                  selects_field, filters_on, groups_by, orders_by
LWC               calls (apex), references (schema), composes (child), targets (object)
UI surface        page_for, embeds, launches, surfaces_action, displays_field,
                  layout_for, action_on, shows_related_list
Security          grants_field_access, grants_object_access, grants_class_access,
                  grants_permission, grants_tab_access, grants_app_access,
                  grants_recordtype_access, assigns_layout
Validation        validates, formula_ref
Reporting         reports_on, uses_report_type, based_on, joins

CLI

| Command | Description | |---------|-------------| | sf-context-engine init [--client <client>] | Wire up Claude Code by default, or target Cursor, Codex, Kilo, Claude Desktop, or auto. | | sf-context-engine index | Parse force-app/ into SQLite. Incremental by default. | | sf-context-engine index --full | Force full reindex. | | sf-context-engine status | Index health, item/dep counts, tool usage stats. | | sf-context-engine audit | Coverage analysis, orphan deps, file comparison. | | sf-context-engine enrich | Query Tooling API (MetadataComponentDependency) for field-level org dependencies. Requires authenticated org. | | sf-context-engine serve | Start the MCP server over stdio for generic MCP hosts. |

Observability

Every MCP tool call is logged to .sf-context/logs/YYYY-MM-DD.jsonl:

{"ts":"2026-03-29T07:25:08.250Z","level":"info","event":"tool_call","tool":"describe_object","params":{"objectName":"Account"},"duration_ms":2,"response_chars":14665,"estimated_tokens":3667}

The status command shows aggregated tool usage:

Tool usage (today):
  describe_object          3 calls  ~  8,200 tokens     2ms avg
  search_metadata          5 calls  ~  1,400 tokens     0ms avg
  find_dependencies        2 calls  ~  3,100 tokens     1ms avg
  Total                   10 calls  ~ 12,700 tokens     1ms avg

The audit command compares the index against files on disk:

--- File Coverage ---
  Files on disk:       3,266
  Files in index:      3,266
  Missing from index:  0
  Stale in index:      0

Architecture

force-app/  ──▶  12 TYPED PARSERS  ──▶  SQLite (.sf-context/index.db)
                 + generic fallback       ├── metadata_items (3,200+ rows)
                                          ├── dependencies  (18,600+ rows)
                 ~1.4s full               ├── metadata_fts  (FTS5)
                 ~120ms incremental       └── index_runs

Tooling API ──▶  enrich command    ──▶  Org-level deps merged into SQLite
                 MetadataComponentDep     ├── Field-level deps for Apex & LWC
                 ~12s per org             └── context: org:field / org:*_object

                SessionStart Hook  ◀──── reads index, injects ~1K tokens
                SubagentStart Hook ◀──── reads index, injects ~136 tokens

                MCP Server (stdio) ◀──── reads index, serves 6 tools
  • SQLite with WAL mode — sub-millisecond queries, zero setup, single portable file
  • Incremental reindex via SHA-256 content hashing — only re-parses changed files
  • Crash-resilient MCP server — uncaught exception handlers, graceful degradation without an index
  • Separate hook process — SessionStart/SubagentStart work even if MCP fails to start

Roadmap

v1.0 — Offline Index + MCP (current)

  • [x] 12 typed parsers + generic fallback (43 metadata types)
  • [x] 18,600+ dependency relationships across 41 ref types
  • [x] MCP server with 6 tools, source evidence, graph-walking, multi-hop traversal
  • [x] FTS5 full-text search with prefix matching and filters
  • [x] Incremental reindex via content hashing
  • [x] Claude Code integration (SessionStart + SubagentStart hooks, .mcp.json wiring)
  • [x] CLI: init, index, status, audit, serve
  • [x] Observability: structured logging, tool call timing, token estimation
  • [x] 101 tests across 14 test files

v1.x — Multi-Client Support

  • [x] init --client cursor — wire into Cursor MCP config
  • [x] init --client codex — wire into Codex MCP config
  • [x] init --client kilo — wire into Kilo MCP config
  • [x] init --client claude-desktop — wire into claude_desktop_config.json
  • [x] init --client auto — detect installed clients and configure all of them
  • [ ] Client-specific context injection (equivalent to Claude Code hooks for other clients)
  • [x] Standalone MCP server mode (sf-context-engine serve) for generic MCP clients

v2.0 — Org Enrichment (in progress)

  • [ ] sf sobject describe for complete schema data (fields, picklists, record types not in source)
  • [x] MetadataComponentDependency (Tooling API) for org-level dependency graph — enrich command
  • [x] Merge org data into local index — field-level deps for Apex & LWC, marked with org:* context
  • [ ] Drift detection: index vs. live org comparison

Future

  • [ ] Large org scaling / domain clustering
  • [ ] Plugin system for custom parsers

Requirements

  • Node.js >= 18
  • Salesforce DX project with retrieved metadata in force-app/
  • Any MCP-compatible client — Claude Code, Cursor, Windsurf, Claude Desktop, Zed, or any tool supporting the Model Context Protocol

Contributing

Contributions welcome. Please open an issue or email [email protected] to discuss what you'd like to change.

License

MIT - Frederik Pardon