Content
# sfdc-mcp
Run Salesforce from inside Claude Code. One sentence in, multi-step org work out.
## 60-second demo
> "이번 분기 마감 임박한 Opportunity 중 2주째 활동 없는 것 5개
> 찾아서 담당 SE에게 재할당하고 Slack DM 보내줘"
SOQL → 5건 → 재할당(DML) → Slack 메시지 → "5건 처리 완료".
Salesforce UI 한 번도 안 열고, 전부 IDE 안에서.
## Status
✅ Week 1 — `query` tool.
✅ Week 2 — `records.create/update/delete` + `apex.execute` + dry-run + audit JSONL.
🚧 Week 4~5 — `flow.trigger` + `notify.slack`.
## Quickstart (Claude Code CLI)
```bash
# 1. sf CLI 로그인
sf org login web --alias mydev
# 2. clone + build
git clone https://github.com/<you>/sfdc-mcp && cd sfdc-mcp
npm install && npm run build
# 3. 프로젝트 루트의 .mcp.json (이미 포함됨)
# SFDC_MCP_ORG 값을 본인 alias로 바꾸기
# 4. 그냥 claude 실행
claude
> "내 org에 Account 몇 개 있어?"
```
서버 상태 확인:
```bash
claude mcp list
# sfdc: node ./dist/index.js - ✓ Connected
```
## Tools
### Tier 1 — Runtime
| Tool | Status |
|---|---|
| `query` (SOQL) | ✅ |
| `records.create / update / delete` | ✅ |
| `apex.execute` (anonymous) | ✅ |
### Tier 1.5 — Metadata (23 tools)
| Group | Tools | Status |
|---|---|---|
| **Describe** (read-only) | `describeObject`, `describeGlobal`, `listFields` | ✅ |
| **Create** | `createObject`, `createField` | ✅ |
| **Update** (read-modify-write) | `updateField`, `updateObject`, `addPicklistValues` | ✅ |
| **Delete** | `deleteField` | ✅ |
| **Permissions** | `grantFieldFls`, `grantObjectPerms`, `upsertPermissionSet` | ✅ |
| **Declarative** | `upsertValidationRule`, `upsertRecordType`, `upsertLayoutAssignment`, `upsertListView`, `upsertCustomLabel` | ✅ |
| **Code** | `upsertApexClass`, `upsertApexTrigger`, `upsertFlow` | ✅ |
| **Bundle** | `deploy`, `validateDeploy`, `retrieve` | ✅ |
### Tier 2 — Workflow (planned)
| Tool | Status |
|---|---|
| `flow.trigger` | ⏳ |
| `notify.slack` | ⏳ |
All write tools default to `dry-run`. Execution requires `confirm: true` and is logged to `~/.sfdc-mcp/audit.jsonl`.
## Configuration
| Env var | Default | Purpose |
|---|---|---|
| `SFDC_MCP_ORG` | (sf default) | Org alias / username |
| `SFDC_MCP_API_VERSION` | `60.0` | Salesforce API version |
## Why metadata tools?
Salesforce's own [Hosted MCP Servers](https://developer.salesforce.com/docs/platform/hosted-mcp-servers/guide/hosted-mcp-servers-overview.html) (Beta, GA Feb 2026) cover **runtime** operations only — SObject CRUD, Flow invocation, Invocable Apex. Metadata creation/modification (CustomObject, CustomField, ValidationRule, PermissionSet, Layout) is not in their scope. The Salesforce DX MCP Server (`salesforcecli/mcp`) only offers project-level `deploy_metadata` / `retrieve_metadata` and requires a local SFDX project on disk.
`sfdc-mcp` fills the gap: **fine-grained, in-place metadata operations** with read-modify-write merging, dry-run preview with diff, and per-call audit logging. Useful when an agent needs to add a field + grant FLS + create a validation rule in one conversation, without ever leaving the chat.
## Integration tests (scratch org)
Phase 1~6 metadata tools have a runnable integration suite. Use a **scratch or dev org** — it creates and cleans up artifacts prefixed `SfdcMcpIT_`.
```bash
# All phases (with cleanup at end)
SFDC_MCP_ORG=<alias> npm run test:integration
# Single phase (1=describe, 2=update, 3=permissions, 4=declarative, 5=apex, 6=bundle)
SFDC_MCP_ORG=<alias> npx tsx scripts/integration-metadata.ts 2
# Verbose (print full tool responses)
SFDC_MCP_ORG=<alias> VERBOSE=1 npm run test:integration
# Cleanup only (if a previous run failed mid-way)
SFDC_MCP_ORG=<alias> npm run test:integration:cleanup
```
Each step prints `✓` or `✗` with elapsed ms, and a final `passed/total` summary. Non-zero exit on any failure.
## License
MIT.