@iivanov/salesforce-lens
v0.1.9
Published
Salesforce Lens — local stdio MCP server. Turns the Salesforce Lens audit + Omnistudio Explorer surface into conversational MCP tools, authenticating against the local `sf` / `sfdx` CLI cache.
Maintainers
Readme
Salesforce Lens — local stdio MCP server
A Model Context Protocol server that turns the Salesforce Lens project into a conversational tool. The user says "can we run an audit of my Salesforce org?", the assistant opens a clickable picker over the available orgs, then over the available audits, and runs whatever the user picks — all inside Cursor / Claude Desktop / Claude Code, with no extra services to deploy.
This is a local-only stdio MCP. It is published to npm as @iivanov/salesforce-lens and your MCP client launches it on demand via npx. There is no remote / HTTP transport — the server holds its own jsforce.Connection, talks JSON-RPC over stdin/stdout, and authenticates against the local sf / sfdx CLI auth cache.
Quickstart
npx -y @iivanov/salesforce-lens@latest --stdioThat command is for sanity-checking only — stdio MCPs are not interactive. The expected use is to wire it into your MCP client config and let the client spawn the binary on demand.
Auth
Salesforce auth comes from the local sf / sfdx CLI auth cache. The MCP server reads it with @salesforce/core (AuthInfo / ConfigAggregator) and builds a jsforce.Connection lazily on the first tool call that needs Salesforce. tools/list, the audit catalog, and the report generator all stay responsive even when no auth has been resolved yet.
You don't have to declare an org upfront. Just ask the assistant to run an audit and it'll open a radio-button picker (via the choose_org tool) over the orgs in your local sf CLI cache so you click instead of typing.
Prerequisites:
- Node.js ≥ 18
- Salesforce CLI (
sforsfdx) installed and authenticated:sf org login web --set-default
Connecting clients
Cursor (~/.cursor/mcp.json)
{
"mcpServers": {
"salesforce-lens": {
"command": "npx",
"args": ["-y", "@iivanov/salesforce-lens@latest", "--stdio"]
}
}
}Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json)
Same shape — mcpServers.salesforce-lens with command: "npx" and the same args. Restart Claude Desktop with Cmd+Q after editing.
Claude Code CLI
claude mcp add salesforce-lens \
--scope user \
-- npx -y @iivanov/salesforce-lens@latest --stdiomacOS Cursor / Claude Desktop don't always inherit your shell PATH, so
npxmay not be reachable from a launch-services context. If the client logscommand not found: npx, setcommandto the absolute path you'd get fromwhich npx(e.g./usr/local/bin/npxor~/.nvm/versions/node/<version>/bin/npx). If you'd rather invokenodedirectly, install the package globally (npm i -g @iivanov/salesforce-lens) and pointcommandat the absolutenodepath withargs: ["<bin>/salesforce-lens-mcp", "--stdio"].
Working from a clone of this monorepo instead of the published package? Swap
command: "npx"/args: ["-y", "@iivanov/salesforce-lens@latest", ...]forcommand: "/usr/local/bin/node"/args: ["/ABSOLUTE/PATH/TO/salesforce-lens-vite/mcp-server/src/index.js", "--stdio"].
How it feels in chat
There is a single discoverable entry point — the audit_my_salesforce_org prompt. Open it from the MCP client's prompt picker (or just say "can we run an audit of my Salesforce org?").
When the client supports MCP form elicitation (Cursor and Claude Desktop both do), the experience is point-and-click:
get_session_status— skip auth if a session already exists.choose_orgopens a radio / dropdown picker of yoursfCLI orgs. You click one; the MCP logs in for you.choose_auditopens a picker grouped by category (Automation, Apex, Security, ...) listing all 32 audits. You click one; the MCP runs it.- If the picked audit needs parameters (e.g.
field-usageneedsobject), a second picker pops up for the param.
- If the picked audit needs parameters (e.g.
- The assistant summarises the result in plain English and offers to run another.
When the client doesn't support form elicitation, the same choose_* tools degrade to a numbered markdown menu and the assistant asks you to reply with just a number — no retyping audit names. The two-step "pick + run" flow stays the same.
Environment variables
No env vars are required. The recommended flow is to leave the env block out of your client config entirely and pick an org conversationally via choose_org on first use. The variables below exist for power users who want to bypass the picker.
| Variable | When | Meaning |
|------------------------------------|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| SF_TARGET_ORG | optional | Skip the org picker by hard-pinning an alias or username. Falls back to target-org / defaultusername from the SFDX global config when unset. |
| SALESFORCE_LENS_AUTO_LOGIN_ALIAS | optional | Legacy alias of SF_TARGET_ORG, kept for backwards compatibility. |
| MCP_DEBUG | optional | Prints a startup banner + verbose lazy-resolve diagnostics on stderr. |
Tools
31 tools total across four areas:
- Auth & session (10 tools) — pick an org, bridge a session, log out.
- Platform Audits (3 tools) — list/run/pick from the 30+ Platform Audit handlers.
- Omnistudio Explorer (13 tools) — full coverage of the OmniScript / IP / DataMapper / FlexCard / Apex / Vlocity Action / Vlocity Layout surface, plus org-wide compliance sweeps.
- Industry / cloud-licenses (3 tools) and Branded report generator (2 tools) — wrap any result set in a self-contained Salesforce-styled HTML or markdown report.
The choose_* tools (choose_org, choose_audit, choose_omni_artifact) are the preferred entry points — they open form pickers and degrade to numbered menus on clients without elicitation support.
Interactive (preferred)
choose_org— ListssfCLI orgs and opens a picker (form elicitation). On pick, logs in automatically. Falls back to a numbered markdown menu when the client doesn't support elicitation.choose_audit— Lists all audits grouped by category and opens a picker. On pick, runs the audit and returns the result. If the audit needs params, opens a second picker for those. Falls back to a numbered markdown menu when the client doesn't support elicitation.
Auth & session (lower-level)
get_config— Which auth methods are available (CLI / OAuth / manual).get_session_status— Whether the MCP server currently has a session, and for which org.set_session_id— Bridge an existing Salesforce access token + instance URL.logout— Clear the in-process session.cli_list_orgs— Raw CLI org list (usechoose_orginstead).cli_login— Reuse a CLI org by alias / username (usechoose_orginstead).cli_auth_url_login— Login via an SFDX auth URL (orsf org display sfdxauthurl --json).login_username_password— Username + password (+ token, env). Last resort.bridge_session— Reuse a raw Salesforce access token + instance URL.
Audits (lower-level)
list_audits— Returns the audit catalog grouped by category. Useful when you want to inspect / discuss the catalog without running anything.run_audit— Runs one audit byname(with optionalparams). Useful when the user already knows exactly which audit they want and skips the picker.
The full audit catalog (32 audits across 14 categories) lives in src/auditCatalog.js — that's where each entry binds an audit name to the imported handler in server-js/.
Omnistudio Explorer tools
These mirror the surfaces of the web Omnistudio Explorer (lists, per-record detail panels, core overview endpoints, compliance audits). Every tool calls a transport-agnostic helper from server-js/industries/omnistudio/* directly — no HTTP, no proxying. Slow streaming panels (Apex callers, method-usage) and org-wide audit sweeps fold their progress events into a progress: [...] array in the response.
The single source of truth is src/omnistudioCatalog.js — one entry per artifact type, one entry per core endpoint.
| Tool | What it does |
|----------------------------|---------------------------------------------------------------------------------------------------------------|
| omni_connection | Instance + user identity for the active session. |
| omni_package_type | Detects core vs vlocity_cmt/ins/ps package install. |
| omni_usage_counts | Per-type active/total counts. Pass { stream: true } to fold per-step progress events into the response. |
| omni_sharing_settings | Object-level internal + external sharing model for the 4 primary artifact objects. |
| omni_bootstrap | One-call composition: connection + package-type + (optional) usage-counts. Mirrors the web bootstrap shape. |
| omni_settings | OmniInteractionConfig SObject rows grouped by category (Runtime / OmniAnalytics / Preferences / Misc). |
| omni_list_artifacts | Lists records for any of the 7 artifact types. Honors activeOnly on the versioned types; silent elsewhere. |
| omni_list_panels | Returns the panel registry for a given type (id, label, slow flag, streaming flag). |
| omni_get_panel | Loads one panel for a specific record. Auto-collects progress for streaming panels. |
| omni_audit_catalog | Which types support compliance audits today + what they check. |
| omni_audit_one | Audits a single OmniScript / IP / DataMapper. DataMappers on core orgs return core_dm_audit_unsupported. |
| omni_audit_sweep | Runs the org-wide compliance audit for one type, with progress events folded in. |
| choose_omni_artifact | Interactive picker — type → record → panel. Falls back to a numbered menu on clients without elicitation. |
Branded report generator
Two tools render any audit/explorer result set into a polished, self-contained Salesforce-styled report. The renderer is in src/report/ (styles.js, renderHtml.js, renderMarkdown.js) and is pure — no IO, no external assets, no scripts. The report never includes the Salesforce trademarked logo; it uses an inline SVG "Salesforce Lens" wordmark and a footer disclaimer flagging the tool as an unofficial open-source project.
| Tool | What it does |
|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| generate_branded_report | Wraps arbitrary sections[] into HTML or markdown. Sections render based on data shape: array of objects → table, object → key/value list, primitive → code block. Compliance fast-path: data.violations renders as a labeled table with a totals header. Optional outputPath writes to disk; otherwise inline. |
| audit_and_report | Convenience: runs the requested org-wide compliance sweeps and renders the result. { audits: [{ type }], title?, outputPath?, format? }. |
Form elicitation: enabling the picker UX
The choose_* tools call MCP elicitation/create to ask the client to render a real input form. The client must advertise the capability during initialize:
{
"capabilities": {
"elicitation": { "form": {} }
}
}Cursor (current) and Claude Desktop (current) both advertise this. Older clients (or some Claude Code versions) may not — the choose_* tools detect this and degrade to a numbered markdown menu where the user replies with just a digit.
Troubleshooting
command not found: npx— macOS Cursor / Claude Desktop don't always inherit your shell PATH. Setcommandto the absolute path fromwhich npx, or install globally (npm i -g @iivanov/salesforce-lens) and point at the absolutenodebinary +args: ["<bin>/salesforce-lens-mcp", "--stdio"].No org found/ picker is empty — runsf org listto confirm at least one authenticated org is present, andsf org login web --set-defaultif not.- Picker doesn't open, just a numbered menu — the MCP client doesn't advertise
elicitation.form. The two-step "pick + run" UX still works; reply with the digit shown in the menu. - Verbose diagnostics — set
MCP_DEBUG=1in the client config'senvblock to log the startup banner and lazy-resolve traces on stderr.
Reporting issues
Issues and feature requests live on the monorepo: https://github.com/ivelin-ivanov/salesforce-lens-vite/issues. Contributing / development docs (running from source, the audit catalog, publishing the package) live in the root README.md of the repository.
