Skip to main content
Glama
Kelley-Austin

SObjectActions

sfka-invocableMCP

제네릭하고 특정 객체에 종속되지 않는 invocable Apex 액션(27개의 MCP 도구)으로, 탐색(describe, picklists, list flows, access check, record summary), 조회(read, find, count, aggregate, search, related), 쓰기(create, upsert, update, clone, delete, undelete, validate dry-run, assign owner, change record type), intent shortcuts(log activity, check, close case, convert lead, post to Chatter, add note, attach file), 그리고 run flow를 포함합니다. 이 액션들은 Salesforce에 호스팅된 MCP 서버(McpServerDefinition = SObjectActions)의 도구로 노출됩니다. 동일한 액션은 Flow, Agentforce 에이전트 액션 및 REST API(/services/data/vXX.X/actions/custom/apex/<ClassName>)에서도 호출할 수 있습니다.

모든 액션은 objectApiName 문자열과 함께 레코드 또는 레코드 Id를 받으므로, 한 번의 배포로 추가 코드 없이 모든 표준/사용자 객체를 지원합니다.


빠른 시작 (반복 가능)

scripts/setup.sh <org-alias> [--no-fixtures] [--no-eca] [--no-tests] [--no-smoke] [--assign user@example.com]

테스트 픽스처, 27개 액션 + echo flow + permission set, MCP 서버 정의, External Client App을 배포하고, SObjectActions_User를 할당합니다. 45개 전체 단위 테스트와 45개 항목을 검사하는 REST smoke test를 실행한 뒤, consumer key와 남은 두 가지 수동 단계(Setup에서 서버 활성화, 객체 CRUD/FLS 부여)를 출력합니다. 멱동적이며, Enhanced Notes / record types가 있는 조직과 없는 조직 모두에서 검증했습니다.

대안: unlocked package SObject Actions MCP (Apex + flow + permission set; scripts/package.sh install <org> <04t>는 Salesforce가 패키지에 허용하지 않는 mcp/eca/도 배포합니다). 또한 scripts/scratch.sh(새로운 scratch org용 전체 설치)와 .github/workflows/validate.yml(PR에 대한 check-only 배포 + 테스트 + 문서 drift 확인, secret SF_AUTH_URL 필요)이 있습니다.

force-app/ (패키지 가능: classes, flows, permission sets), mcp/ (McpServerDefinition), eca/ (External Client App), test-fixtures/ (선택).

Related MCP server: Salesforce-Hosted-Custom-Mcp-Server

Documentation map

Document

What is it for

README.md (이 파일)

사용 가이드: 배포, 활성화, 컨벤션, 도구별 참조, 보안, 한도, 오류, 테스트

docs/TOOLS.md

생성된 도구 매니페스트: 각 도구의 입력, 출력, annotation (scripts/gen-tool-manifest.py)

docs/tools.json

동일한 매니페스트를 기계가 읽을 수 있는 JSON으로 (agent 프롬프트, 문서 사이트, CI diff용)

docs/ARCHITECTURE.md

클래스들이 어떻게 연결되는지, 공용 헬퍼, 설계 규칙, 도구 추가하는 방법

docs/CLIENT_AUTH.md

외부 클라이언트 인증 방법 (ECA, PKCE, refresh token, Postman, headless fallback)

docs/postman/SObjectActions.postman_collection.json

생성된 Postman collection: OAuth 사전 설정, 도구별 MCP + REST 요청

docs/DEMO_SCRIPT.md

30분 발표용 스크립트, 23-슬라이드 덱을 슬라이드별로 설명

docs/DEMO_SCRIPT_15MIN.md

동일 발표의 15분 버전: 9-/458, 데모 순간 하나

docs/DEMO_NOTES.md

발표 뒤 참고 자료: 카탈로그 설명, 질문 목록, 언급하면 안 되는 주장

CHANGELOG.md

릴리스 히스토리

목차

  1. 구성

  2. 배포

  3. MCP 서버 활성화

  4. 공통 컨벤션

  5. 툴 참조

  6. Flow에서 호출

  7. REST에서 호출

  8. 보안 모델

  9. 한도 및 벌크 동작

  10. 오류 카탈로그

  11. 테스트

  12. 확장


Tool families

Family

Tools

Discover

checkAccess, describeObject, picklistValues, listFlows, recordSummary

Read

readRecords, findRecords, countRecords, aggregateRecords, searchRecords, relatedRecords

Write

validateRecords (dry run), createRecords, upsertRecords, updateRecords, cloneRecords, deleteRecords, undeleteRecords

Intent shortcuts

logActivity, closeCase, check, convertLead, postChatter, addNote, attachFile

Automation

runFlow

각 도구 입력/출력 전체 참조: docs/TOOLS.md.

구성

모든 소는 force-app/main/default/.에 있습니다.

경로

용도

classes/SObjectCreateAction.cls

호출 가능한 Create Records (Generic) -> MCP 도구 createRecords

classes/SObjectReadAction.cls

호출 가능한 Read Records (Generic) -> MCP 도구 readRecords

classes/SObjectUpdateAction.cls

호출 가능한 Update Records (Generic) -> MCP 도구 updateRecords

classes/SObjectDeleteAction.cls

호출 가능한 Delete Records (Generic) -> MCP 도구 deleteRecords

classes/SObjectUpsertAction.cls

호출 가능한 Upsert Records (Generic) -> MCP 도구 upsertRecords

classes/SObjectFindAction.cls

호출 가능한 Find Records (Generic) -> MCP 도구 findRecords

classes/SObjectDescribeAction.cls

호출 가능한 Describe Object (Generic) -> MCP 도구 describeObject

classes/SObjectSearchAction.cls

호출 가능한 Search Records (Generic) -> MCP 도구 searchRecords (SOSL)

classes/SObjectRelatedAction.cls

호출 가능한 Get Related Records (Generic) -> MCP 도구 relatedRecords

classes/SObjectCountAction.cls

호출 가능한 Count Records (Generic) -> MCP 도구 countRecords

classes/SObjectUndeleteAction.cls

호출 가능한 Undelete Records (Generic) -> MCP 도구 undeleteRecords

classes/SObjectAccessAction.cls

호출 가능한 Check Access (Generic) -> MCP 도구 checkAccess

classes/SObjectCloneAction.cls

호출 가능한 Clone Records (Generic) -> MCP 도구 cloneRecords

classes/SObjectValidateAction.cls

호출 가능한 Validate Records (Generic, dry run) -> MCP 도구 validateRecords

classes/SObjectAggregateAction.cls

호출 가능한 Aggregate Records (Generic) -> MCP 도구 aggregateRecords

classes/SObjectRunFlowAction.cls

호출 가능한 Run Flow (Generic) -> MCP 도구 runFlow

classes/SObjectAssignOwnerAction.cls

Assign Owner (Generic) -> assignOwner

classes/SObjectChangeRecordTypeAction.cls

Change Record Type (Generic) -> changeRecordType

classes/SObjectPicklistAction.cls

Get Picklist Values (Generic) -> picklistValues

classes/SObjectLogActivityAction.cls

Log Activity -> logActivity

classes/SObjectCloseCaseAction.cls

Close Case -> closeCase

classes/SObjectConvertLeadAction.cls

Convert Lead -> convertLead

classes/SObjectPostChatterAction.cls

Post to Chatter -> postChatter

classes/SObjectAddNoteAction.cls

Add Note -> addNote

classes/SObjectAttachFileAction.cls

Attach File -> attachFile

classes/SObjectListFlowsAction.cls

List Flows -> listFlows

classes/SObjectSummaryAction.cls

Get Record Summary (Generic) -> recordSummary

flows/SObjectActions_EchoFlow.flow-meta.xml

runFlow 테스트 픽스처로 사용되는 아주 작은 자동 실행 플로우

test-fixtures/ (별도 패키지 디렉터리)

선택 사항: SObjectActions_Fixture__c(레코드 유형 2개 + 종속 선택 목록 + 권한 세트) — 테스트에서만 사용되고 동적으로 참조됨

classes/SObjectActionUtil.cls

공통 헬퍼: 타입 확인, JSON -> SObject, 필드 검증, 레이블 조회, 중복 안전 DML

classes/SObjectActionsTest.cls

create/read/update/delete에 대한 14개 테스트

classes/SObjectActionsExtTest.cls

upsert/find/describe에 대한 6개 테스트

classes/SObjectActionsExt2Test.cls

search/related/count/undelete/access 대한 7개 테스트

classes/SObjectActionsExt3Test.cls

clone/validate/aggregate/runFlow/urls 대한 7개 테스트

classes/SObjectActionsExt4Test.cls

인트/유틸리티 도구에 대한 11개 테스트(총 커버리지 약 97.5%)

mcp/main/default/mcpServerDefinitions/SObjectActions.mcpServerDefinition-meta.xml

MCP 서버定義: 27개의 Apex 액션을 액션으로 연결 (자체 패키지 디렉터리: 패키징 불가)

scripts/smoke-test.sh

REST 를 통해 테스트 스크립트, 엔드투엔드 스모크 테스트(45개 검사)

scripts/apex/smoke.apex

익명 Apex 스모크 스크립트

scripts/gen-tool-manifest.py

소스에서 docs/TOOLS.mddocs/tools.json 재생성

scripts/gen-postman.py

docs/tools.json에서 Postman 컬렉션 재생성

scripts/setup.sh

한 번의 명령으로 설치 + 검증할 수 있는 최고의 유틸리티 (모든 org)

scripts/scratch.sh, scripts/package.sh

Scratch org 부트스트랩; unlocked 패키지 생성/버전/설치

permissionsets/SObjectActions_User

모든 액션 클래스에 대한 액세스를 할 수 있음(객체 CRUD 없음)

ec/main/default/externalClientApps/SobjectActionsClient (+ oauth 설정, global oauth, 보안 정책)

MCP용 OAuth 클라ient: MCP + refresh 스코프, PKCE, JWT 토큰, 공통 콜백 (자체 패키지 디렉터리: 글로벌 OAuth 설정은 패키징 불가)

.github/workflows/validate.yml

CI: 테스트를 포함한 check-only 배포 및 문서 드리프트 검사

API 버전: 67.0 (sfdx-project.json). 호스팅된 MCP 서버와 McpServerDefinition 메타데이터를 사용할 수 있는 org가 필요합니다(Summer '26 또는 이후 버전, 최신 릴리스 노트에서 확인).


배포

# deploy everything and run the test class
sf project deploy start -o <alias> -d force-app/main/default \
  -l RunSpecifiedTests -t SObjectActionsTest -t SObjectActionsExtTest -t SObjectActionsExt2Test -t SObjectActionsExt3Test -t SObjectActionsExt4Test

# Test fixtures (record types + dependent picklist used by two tests; deploy first for full per-class coverage)
sf project deploy start -o <alias> -d test-fixtures && sf org assign permset -n SObjectActions_Fixture -o <alias>
# MCP server definition and External Client App (separate dirs)
sf project deploy start -o <alias> -d mcp -d eca

# Apex only (skip the MCP definition)
sf project deploy start -o <alias> -d force-app/main/default/classes \
  -l RunSpecifiedTests -t SObjectActionsTest -t SObjectActionsExtTest -t SObjectActionsExt2Test -t SObjectActionsExt3Test -t SObjectActionsExt4Test

참고:

  • McpServerDefinition 개발자 이름은 영숫자여야 하며, 문자로 시작해야 하고 2~40자여야 합니다(밑줄은 허용되지 않음). 이름은 SObjectActions입니다.

  • apiIdentifier 값은 aa:apex-<ClassName> 형식이며, 클래스가 배포되면 API Catalog에서 자동으로 확인됩니다. 클래스와 정의를 함께 배포하거나 클래스를 먼저 배포하세요.


MCP 서버 활성화

  1. 설정 > MCP 서버 > SObject Actions > 외부 클라이언트 앱 SObject Actions MCP Client(이 저장소에서 배포됨) 연결 > 활성화.

  2. 클라이언트 인증 세부 정보: docs/CLIENT_AUTH.md.

  3. 사용자에게 Apex 클래스에 접근할 수 있는 권한 세트와 작업 대상 객체에 대한 CRUD/FLS 권한을 할당하세요. 도구는 인증된 사용자로 실행됩니다.

  4. 설정에 표시된 서버 URL을 MCP 클라이언트(Claude, Agentforce, Cursor 등)에 지정하세요. tools/listcheckAccess, describeObject, searchRecords, findRecords, countRecords, aggregateRecords, readRecords, relatedRecords, recordSummary, picklistValues, validateRecords, createRecords, upsertRecords, updateRecords, cloneRecords, assignOwner, changeRecordType, deleteRecords, undeleteRecords, logActivity, closeCase, convertLead, postChatter, addNote, attachFile, listFlows, runFlow를 반환합니다.

정의에 설정된 도구 어노테이션:

도구

readOnly

destructive

idempotent

createRecords

false

false

false

readRecords

true

false

true

updateRecords

false

false

true

deleteRecords

false

true

false

upsertRecords

false

false

true

findRecords

true

false

true

describeObject

true

false

true

searchRecords

true

false

true

relatedRecords

true

false

true

countRecords

true

false

true

undeleteRecords

false

false

true

checkAccess

true

false

true

cloneRecords

false

false

false

validateRecords

true

false

true

aggregateRecords

true

false

true

runFlow

false

false

false

assignOwner

false

false

true

changeRecordType

false

false

true

picklistValues

true

false

true

logActivity

false

false

false

closeCase

false

false

true

convertLead

false

false

false

postChatter

false

false

false

addNote

false

false

false

attachFile

false

false

false

listFlows

true

false

true

recordSummary

true

false

true

일반적인 에이전트 순서: describeObject(정확한 API 이름 확인) -> findRecords / readRecords -> createRecords / upsertRecords / updateRecords -> deleteRecords.


공통 규약

objectApiName

모든 작업에 필요합니다. 대소문자를 구분하지 않는 API 이름: Account, Case, Task, My_Object__c, ...

Activity(다형 Task/Event) Activity는 직접 생성하거나 조회할 수 없으므로 "Task 또는 Event"의 별칭으로 처리됩니다.

입력 형식

구체적인 유형 결정 방식

record / records(SObject)

SObject의 실제 유형에서 결정하며, Task/Event가 아닌 유형은 거부됩니다.

recordsJson

각 요소 반드시 {"attributes":{"type":"Task"}} 또는 "Event"를 포함해야 합니다. 누락 시 오류 발생.

recordId / recordIds

Id 접두어(00T = Task, 00U = Event)에서 결정됩니다. 다른 접두어는 거부됩니다.

따라서 objectApiName = "Activity"인 경우 단일 요청에 Task와 Event를 함께 포함할 수 있습니다.

레코드 입력(create / update)

원하는 조합을 제공할 수 있으며, 다음 순서로 병합됩니다:

필드

유형

대상

설명

record

SObject

흐름

objectApiName 유형과 일치해야 합니다.

records

List<SObject>

흐름

동일함.

recordsJson

String

MCP / REST

{field: value} 매핑의 JSON 객체 또는 배열

recordsJson 규칙:

  • 필드 이름은 객체에 존재해야 합니다(직접 필드 API 이름 또는 관계 이름, 외부 ID upsert의 Account 등). 알 수 없는 이름은 조용히 무시되지 않고 Unknown field(s) on <Object>: <names> 오류로 요청 전체가 실패합니다.

  • 값은 플랫폼 JSON 역직렬화에 의해 변환됩니다: 날짜는 YYYY-MM-DD, 날짜/시간은 ISO-8601(2030-01-01T10:00:00.000Z), 부울은 true/false, 숫자는 따옴표 없이 사용합니다.

  • attributes.type이 있는 경우 objectApiName(ActivityTransaction인 경우 Task/Event)과 일치해야 합니다.

Id 입력(read / delete)

  • recordId(읽기만) 및/또는 recordIds(읽기 + 삭제). 빈 항목은 건너뜁니다.

  • 15자 또는 18자 Id 허용. 잘못된 문자열은 요청을 실패시킵니다(Invalid record Id: ...).

  • 각 Id의 유형은 objectApiName과 일치해야 합니다(Activity인 경우 Task/Event).

allOrNone(create / update / delete)

  • 기본값 false: 부분 성공. 실패한 각 row는 errors에서 row <n>: <message>로 보고됩니다.

  • true: 어떤 실패가 있어도 요청 전체가 롤백됩니다. dangerfailureCount = 행 수이고, errors에는 DML 예외 메시지가 담깁니다.

레이블

recordLabelrecordIds와 인덱스가 일치합니다. 레이블 출처:

객체

레이블

Case

CaseNumber - Subject(Subject가 비어 있지 않으면 생략)

기타 모든 객체

객체의 describe 이름 필드(Name, Task/Event의 Subject, CaseNumber 등)

이름 필드 없음 / 읽기 권한 없음

레코드 Id

생성/업데이트 레이블은 DML 후 다시 쿼리됩니다(따라서 CaseNumber 같은 자동 번호가 채워집니다). 삭제 시 레이블은 삭제 전에 캡처됩니다.

공통 출력

필드

유형

의미

isSuccess

Boolean

요청의 모든 행이 성공한 경우에만 true(읽기: 모든 Id를 찾은 경우)

successCount / failureCount(CUD)

Integer

행 수

foundCount / notFoundCount(읽기)

Integer

행 수

recordIds`

객체<String>

영향받은/찾은 Id, 입력 순서대로

recordLabels

List<String>

recordIds와 정렬

errors

List<String>

실패한 각 행마다 row <n>: <message>, 또는 단일 요청 수준 오류 하나

message

String

한 줄 요약(예: 2 created, 1 failed.)

recordUrls

List<String>

recordIds와 정렬된 Lightning 레코드 URL (create/read/update/upsert/clone/find/search/related)

요청 수준 검증 오류(잘못된 객체 이름, 잘못된 형식의 JSON 등)는 isSuccess=false, failureCount=1, errors 하나의 항목으로 설정됩니다. 해당 요청은 DML을 실행하지 않고 동일 호출의 다른 요청은 영향을 받지 않습니다.


도구 참조

createRecords / SObjectCreateAction

Invocable 레이블: Create Records (Generic), 카테고리 SObject Actions.

입력: objectApiName(필수), record, records, recordsJson, allOrNone. 출력: isSuccess, successCount, failureCount, recordIds, recordLabels, errors, message.

MCP 호출 예시:

{ "objectApiName": "Account",
  "recordsJson": "[{\"Name\":\"Acme\",\"Industry\":\"Energy\"},{\"Name\":\"Globex\"}]" }
{ "objectApiName": "Case",
  "recordsJson": "{\"Subject\":\"Printer on fire\",\"Status\":\"New\",\"Origin\":\"Web\",\"AccountId\":\"001...\"}" }

-> recordLabels: ["00001234 - Printer on fire"]

{ "objectApiName": "Activity",
  "recordsJson": "[{\"attributes\":{\"type\":\"Task\"},\"Subject\":\"Call\",\"WhatId\":\"001...\"},{\"attributes\":{\"type\":\"Event\"},\"Subject\":\"Meet\",\"DurationInMinutes\":30,\"ActivityDateTime\":\"2030-01-01T10:00:00.000Z\"}]" }

샘플 결과:

{ "isSuccess": true, "successCount": 2, "failureCount": 0,
  "recordIds": ["00T...", "00U..."], "recordLabels": ["Call", "Meet"],
  "errors": [], "message": "2 created, 0 failed." }

부분 실패(allOrNone=false):

{ "isSuccess": false, "successCount": 1, "failureCount": 1,
  "recordIds": ["003..."], "recordLabels": ["Good"],
  "errors": ["row 2: Required fields are missing: [LastName] [LastName]"],
  "message": "1 created, 1 failed." }

readRecords / SObjectReadAction

**vocable 레이블: Read Records (Generic).

입력:

필드

유형

설명

objectApiName

String(필수)

Activity는 혼합 Task/Event Id에 대해 허용됩니다.

recordId

String

단일 Id

recordIds

List<String>

대량 동작; 중복된 Id는 하나로 통합됩니다.

fields

List<String>

선택 사항. 필드 API 이름을 나타내고(관계 경로 허용: Owner.Name, Account.Name) 비어 있으면 실행 사용자가 접근할 수 있는 모든 필드를 의미합니다. Id 및 레이블 필드는 항상 포함됩니다.

출력:

only, no preamble.

Let's finalize.

Let's now write final text.

Potential issue: The first section's recordsJson note says "JSON array of found records (serialized SObjects, includes attributes.type) - MCP-facing". Translate "MCP에 노출되는 값" rather than "MCP-facing". What does "MCP-facing" mean? The final answer "MCP용" maybe. Let's use "MCP 대응". Actually "Flow-facing" in next row: "Flow향". We can say "MCP용" and "Flow용". Good.

First two cells:

  • "First / all found records as SObjects - Flow-facing" -> "첫 번째/모든 찾은 레코드를 SObject로 변환 - Flow용".

OK.

Now let's final| 필드 | 설명 | |---|---| | isSuccess | 요청한 모든 Id를 찾았고 표시할 수 있으면 true | | foundCount, notFoundCount | | | recordIds, recordLabels | 찾은 레코드, 입력 순서 | | recordsJson | 찾은 레코드의 JSON 배열(직렬화된 SObject, attributes.type 포함) - MCP 대응 | | record, records | 첫 번째/전체 찾은 레코드를 SObject로 - Flow 대응 | | notFoundIds | 존자하지 않거나 sharing 권한상 볼 수 없는 Id | | errors, message | |

예시:

{ "objectApiName": "Account", "recordId": "001..." }
{ "objectApiName": "Case", "recordIds": ["500...","500..."], "fields": ["Status","Priority","Account.Name"] }
{ "objectApiName": "Activity", "recordIds": ["00T...","00U..."], "fields": ["Subject","ActivityDate"] }

샘플 결과:

{ "isSuccess": true, "foundCount": 1, "notFoundCount": 0,
  "recordIds": ["500..."], "recordLabels": ["00001234 - Printer on fire"],
  "recordsJson": "[{\"attributes\":{\"type\":\"Case\"},\"Id\":\"500...\",\"CaseNumber\":\"00001234\",\"Subject\":\"Printer on fire\",\"Status\":\"New\",\"Account\":{\"attributes\":{\"type\":\"Account\"},\"Name\":\"Acme\"}}]",
  "notFoundIds": [], "errors": [], "message": "1 found, 0 not found." }

직접 필드 이름은 리 전에 검즉됩니다 (Unknown field on Account: Foo__c). 관계 경로는 SOQL 자체가 검중하며, 잘못된 경로는 errors에 QueryException로 나타납니다. 사용자가 볼 수 없는 레코드는 (오류 없이) notFoundIds에 보고됩니다.

updateRecords / SObjectUpdateAction

호출 라벨: 레코드 업데이트 (Generic).

입력: objectApiName (필수), record, records, recordsJson, allOrNone. 모든 행에는 Id가 포함되어야 합니다. Id가 없는 행이 있으면 전체 요청이 실패합니다. (row <n>: Id is required for update.).

출력: create와 동일한 형테 (successCount, recordIds, recordLabels, ...). Label은 호출의 모드 업데이트가 적영된 이후의 레코드 상태를 반영합니다.

예시:

{ "objectApiName": "Account",
  "recordsJson": "[{\"Id\":\"001...\",\"Name\":\"Acme Corp\",\"Phone\":\"555-0100\"}]" }
{ "objectApiName": "Case", "recordsJson": "{\"Id\":\"500...\",\"Status\":\"Closed\"}" }
{ "objectApiName": "Activity",
  "recordsJson": "[{\"attributes\":{\"type\":\"Task\"},\"Id\":\"00T...\",\"Status\":\"Completed\"}]" }

필드를 비우려면 null을 전달하세요: {"Id":"001...","Description":null}.

deleteRecords / SObjectDeleteAction

호출 라벨: 레코드 삭제 (Generic). 도구는 destructive로 표시됩니다.

입력: objectApiName (필수), recordIds, record, records, record allOrNone. SObject레 전달되는 레코드에는 Id가 포◤되어야 합니다.

출력: recordIds, successCount, failureCount, recordIds, recordLabels (삭제 전에 캡션), errors, message.

예시:

{ "objectApiName": "Account", "recordIds": ["001...", "001..."] }
{ "objectApiName": "Activity", "recordIds": ["00T...", "00U..."] }

삭제된 레코드는 사이클 빈으로 이동합니다 (표즁 Database.delete 의 맨스트 스). Cascade 삭제는 플랫폼의 master-detail / ookup 규칙을 따릅니다.

upsertRecords / ``SObjectUpsertAction`

호출 라벨: 레코드 Upsе р트 (Generic).

입력: objectaApiName (필수), externalIdField (선택, 기존 Id), record, records, recordsJson, allOrNone. externalIdField는 객체의 external Id / idLookup 필드여야 합니다. dates is supported (Task/Event via att objects.type); 외부 Id 필드는 구체적 타입에 조체해야 합니다.

출력: records, failureCount, createdCount, updatedCount, recordIds, recordLabels, wasCreated[] (recordIds와 정렬), errors, message.

{ "objectApiName": "Account", "externalIdField": "External_Key__c",
  "recordsJson": "[{\"External_Key__c\":\"ERP-1001\",\"Name\":\"Acme\"},{\"External_Key__c\":\"ERP-1002\",\"Name\":\"Globex\"}]" }
{ "objectApiName": "Contact",
  "recordsJson": "[{\"Id\":\"003...\",\"Email\":\"a@b.com\"},{\"LastName\":\"New Person\"}]" }

-> wasCreated: [false, true], message: "1 created, 1 updated, 0 failed."

행은 구체적 객 object type 으로 그룹되며, 각 그룹은 하의 Database.upsert입니다. allOrNone=true는 savepoint를 사용하므로 어느 그룹에서 실패해도 전제 요청이 rollback됩니다.

findRecords / SObjectFindAction

호출 라벨: 레코드 검찾 (Generic). 구조화된 filter만 지원합니다. 원시 SOQL/WHERER은 허용되지 않습니다.

입력:

Field

Notes

objectApiName

Must be queryable. Task/Event를 사용, Activity는 제외.

filtersJson

{"field","op","value"}의 JSON 배열(또는 단일 객체). Op: =, !=, <, <=, >, >=, LIKE, IN, NOT IN. value=/!=에서 null 가능. IN/NOT IN은 배열이 필요합니다. 필터는 직접 필터 가능한 필드(관계 경로 제외)만 가능합니다.

filterLogic`

모든 필터에 적용 AND (기본값) 또는 OR.

fields

반환할 추가 필드. 관계 경로 허용(Owner.Name). Id + label 필드는 항상 포함됩니다.

orderBy

"Field" 또는 `"Field ASC

DESC"`.

limitCount

1–200, 기본값 50.

값은 바인딩 전에 필드 타입으로 변환됩니다(날짜 YYYY-MM-DD, 날짜시간 ISO-8601, 숫자, 부울, Id). 모든 값은 bind 변수로 전달됩니다(Database.queryWithBinds, USER_MODE).

출력: isSuccess, resultCount, recordIds, recordLabels, recordsJson, records (Flow), soql (실행된 쿼리, 값은 :b0, :b1...로 마스킹됨), errors, message (resultCount == limitCount이면 "..." (limit reached)"`).

예시:

{ "objectApiName": "Case",
  "filtersJson": "[{\"field\":\"Status\",\"op\":\"IN\",\"value\":[\"New\",\"Working\"]},{\"field\":\"CreatedDate\",\"op\":\">=\",\"value\":\"2026-08-01T00:00:00Z\"}]",
  "fields": ["Status","Priority","Account.Name"], "orderBy": "CreatedDate DESC", "limitCount": 25 }
{ "objectApiName": "Account",
  "filtersJson": "[{\"field\":\"Name\",\"op\":\"LIKE\",\"value\":\"Acme%\"},{\"field\":\"Industry\",\"op\":\"=\",\"value\":\"Energy\"}]",
  "filterLogic": "OR" }
{ "objectApiName": "Task",
  "filtersJson": "[{\"field\":\"WhatId\",\"op\":\"=\",\"value\":\"001...\"},{\"field\":\"IsClosed\",\"op\":\"=\",\"value\":false}]" }

describeObject / SObjectDescribeAction

호출라벨: 객체 설명 (Generic). 하나의 도구에 두 가지 모드가 있습니다.

설명 모드 (objectApiName 설정):

Input

Notes

objectApiName

Activity로 지정하면 Task를 설명합니다.

includeFields

기본값 true

fieldNameContains

정 대 소문자를 구분하지 않는 필터 (API 이름 또는 레이블)

출력: objectApiName, objectLabel, keyPrefix, isCustom, only Create/Updateable/Deleteable/Queryable, labelFields (예: Case의 경우 ["CaseNumber","Subject"]), requiredFields (create 가능, null 불가, default 없음), fieldsJson (접근 가능한 필드만: apiName, label, type, required, createable, updateable, externalId, nameField, length, referenceTo[], relationshipName, picklistValues[]), recordTypesJson (active, available, non-master: id, developerName, name, isDefault), childRelationshipsJson (relationshipName, childObject, field), resultCount (반환된 필드 수).

목록 모드 (objectApiName 비어 있음):

Input

Input

Notes

objectNameContains

정 API 이름 또는 레이블에 대해 대소문자 구분 없는 필터

customOnly

기본값 false

출력: objectsJson (접근 가능한 객체의 apiName, label, keyPrefix, isCustom, createable, queryable; custom settings 및 prefix 없는 system object 제외), resultCount.

예시:

{ "objectApiName": "Case", "fieldNameContains": "status" }
{ "objectApiName": "My_Object__c" }
{ "objectNameContains": "invoice", "customOnly": true }

searchRecords / SObjectSearchAction

호출 라벨: 레코드 검색 (Generic). SOSL 전문 검색이며, 용어는 바인딩됩니다 (FIND :term).

Input

Notes

searchTerm (필수)

최소 2자; *? 와일드카드 허용

objectApiNames

기본값 Account, Contact, Lead, Opportunity, Case; 각 객체는 검색 가능해야 합니다. Activity는 허용되지 않습니다 (Task/Event 사용)

searchIn

ALL (default), NAME, EMAIL, PHONE, SIDEBAR

fields

추가 필드. 해당 필드가 객체에 존자하는 경우에만 적용됩니다

limitCount

만들기원천 object, 1–200, 기본값 20

출력: resultCount, recordIds, recordLabels, recordObjectNames (정렬됨), recordsObject, records.

{ "searchTerm": "acme*", "objectApiNames": ["Account","Contact"], "searchIn": "NAME", "fields": ["Phone","Email"] }

호출 라벨: 관련 레코드 가져오기 (Generic).

Input

Notes

parentRecordId (필수)

부모 object는 Id에서 추론됩니다

relationshipName (필수)

부모의 하위 relationship name (Contacts, Cases, Opportunities, Tasks, Events, My_Children__r); 대소문자 구분 안함; describeObject.childRelationshipsJson 사용

fields, orderBy, limitCount

parent `findRecords와 같이 동일 (기본 50, 최대 200)

출력: parentObjectApiName, childObjectApiName, resultCount, recordIds, recordLabels, recordsJson, records:

{ "parentRecordId": "001...", "relationshipName": "Cases", "fields": ["Status","Priority"], "orderBy": "CreatedDate DESC", "limitCount": 10 }

countRecords / SObjectCountAction

호출 라벨: 레코드 계수 (Generic).

Input

Notes

objectApiName (필수)

Task/Event, not Activity

filtersJson, filterLogic

`findRecords와 동일

groupByField

optional grouping field; up to 200 groups, sorting by count desc; null group is reported as null

출력: totalCount, recordValues[], groupCounts[] (aligned), groupsJson ([{value,count}]), soql.

{ "objectApiName": "Case", "filtersJson": "[{\"field\":\"IsClosed\",\"op\":\"=\",\"value\":false}]", "groupByField": "Priority" }

undeleteRecords / SObjectUndeleteAction

호출 라벨: 레코드 복구 (Generic). Zicap에서 복원합니다.

입력: objectApiName (필수; Task/Event 혼합의 경우 Activity), recordIds (필수), allOrNone. 출력: successCount, failureCount, recordIds, recordLabels (복원 후), errors, message. 한 요청에 중복된 Id는 병합됩니다. 이미 복원되었거나 삭제된 레코드는 행 단위로 실패합니다.

{ "objectApiName": "Account", "recordIds": ["001..."] }

checkAccess / SObjectAccessAction

호출 가능 레이블: Check Access (Generic). 모든 입력은 선택 사항이며, 입력이 없으면 "who am I"로 동작합니다.

입력

참고

objectApiName

CRUD 확인 (Activity -> Task)

fields

objectApiName 필요; 각 필드는 {apiName, exists, readable, editable, createable}로 보고됨

recordIds

최대 200개; UserRecordAccess 사용 -> {recordId, hasRead, hasEdit, hasDelete, hasTransfer, maxAccessLevel} (보이지 않거나 존재하지 않으면 None)

출력: userId, userName, loginUsername, profileId, profileName, userType, organizationId, timeZone, objectApiName, canCreate/canRead/canUpdate/canDelete, fieldAccessJson, recordAccessJson, message.

{ "objectApiName": "Opportunity", "fields": ["Amount","StageName"], "recordIds": ["006..."] }

cloneRecords / SObjectCloneAction

호출 가능 레이블: Clone Records (Generic).

입력

참고

objectApiName (필수)

Task/Event 혼합의 경우 Activity

recordIds (필수)

원본; 찾을 수 없거나 보이지 않는 Id는 행 단위로 실패

overridesJson

모든 복제본에 적용되는 JSON 객체 (필드 이름 검증됨)

excludeFields

복사하지 않을 필드 (예: OwnerId, 외부 Id)

allOrNone

생성 가능하고, 읽기 가능하며, 자동 번호가 아니고, 수식이 아닌 모든 필드를 복사합니다. 하위 레코드는 복제되지 않습니다. 출력: sourceRecordIds (정렬됨), recordIds, recordLabels, recordUrls, 개수, errors.

{ "objectApiName": "Opportunity", "recordIds": ["006..."], "overridesJson": "{\"Name\":\"Renewal 2027\",\"StageName\":\"Prospecting\"}", "excludeFields": ["OwnerId"] }

validateRecords / SObjectValidateAction

호출 가능 레이블: Validate Records (Generic, dry run). 저장점(savepoint) 내에서 insert/update를 수행하고 항상 롤백합니다. 트리거, 유효성 검사 규칙, 필수 필드, FLS 및 공유는 실제로 모두 실행됩니다.

입력: objectApiName (필수), operation (CREATE 기본값 | UPDATE), record, records, recordsJson. 출력: isSuccess (모든 행이 저장될 수 있는지), successCount, failureCount, rowResultsJson ([{row, valid, errors[]}]), errors, message (... Nothing was saved.).

참고: DML은 여전히 가버너 한도에 포함되며, 트랜잭션에서 소비된 자동 번호는 재사용되지 않습니다.

{ "objectApiName": "Contact", "recordsJson": "[{\"LastName\":\"Ok\"},{\"FirstName\":\"No last name\"}]" }

aggregateRecords / SObjectAggregateAction

호출 가능 레이블: Aggregate Records (Generic).

입력

참고

objectApiName (필수)

Task/Event, Activity 아님

aggregationsJson (필수)

[{"function","field"}]; 함수 COUNT, COUNT_DISTINCT, SUM, AVG, MIN, MAX; SUM/AVG는 숫자 필드 필요; 필드는 집계 가능해야 함

filtersJson, filterLogic

findRecords와 동일

groupByFields

0-3개의 그룹화 가능한 필드

limitCount

그룹에만 적용, 1-2000, 기본값 200 (그룹화되지 않은 쿼리는 LIMIT를 사용할 수 없음)

출력: resultCount, rowsJson (각 행: 그룹 필드 값 + FUNCTION_Field 키, 예: SUM_Amount), soql.

{ "objectApiName": "Opportunity",
  "aggregationsJson": "[{\"function\":\"SUM\",\"field\":\"Amount\"},{\"function\":\"COUNT\",\"field\":\"Id\"}]",
  "filtersJson": "[{\"field\":\"IsClosed\",\"op\":\"=\",\"value\":false}]",
  "groupByFields": ["StageName"] }

runFlow / SObjectRunFlowAction

호출 가능 레이블: Run Flow (Generic).

입력

참고

flowApiName (필수)

활성화된 자동 실행 플로우

inputsJson

입력 변수 -> 값의 JSON 객체

outputVariableNames

반환할 "출력 가능"으로 표시된 변수

출력: interviewId, outputsJson, errors (플로우 오류는 Could not start flow ... 또는 오류 메시지로 표시됨), message. 플로우는 동일한 트랜잭션에서 플로우가 선언한 실행 모드로 실행됩니다.

{ "flowApiName": "SObjectActions_EchoFlow", "inputsJson": "{\"inputText\":\"hi\",\"inputNumber\":1}", "outputVariableNames": ["outputText","outputNumber"] }

assignOwner / SObjectAssignOwnerAction

입력: objectApiName, recordIds, newOwnerId (005/00G) 또는 newOwnerName (정확한 사용자 전체 이름 / 사용자 이름, 또는 큐 이름 / 개발자 이름; 모호한 이름은 거부됨), allOrNone. 출력: 확인된 ownerId/ownerName, 레코드별 개수, recordIds, recordLabels, errors.

{ "objectApiName": "Case", "recordIds": ["500..."], "newOwnerName": "Tier 2 Support" }

changeRecordType / SObjectRecordTypeAction

입력: objectApiName, recordIds, recordType (Id, DeveloperName 또는 Name), allOrNone. 오류에는 사용 가능한 개발자 이름이 나열됩니다. 출력: 확인된 recordTypeId/recordTypeName, 레코드별 결과.

picklistValues / SObjectPicklistAction

입력: objectApiName, fieldApiName, includeInactive. 출력: values[], labels[], valuesJson ({value,label,active,default,validFor[]}), isRestricted, isDependent, controllingField, defaultValue. 값은 조직 전체 필드 정의를 반영합니다 (레코드 유형별 값 집합은 적용되지 않음).

logActivity / SObjectLogActivityAction

완료된 Task를 기록합니다. 입력: subject (필수), relatedRecordId (WhatId), personRecordId (Contact/Lead WhoId), description, activityDate (기본값 오늘), activityType, status (기본값 첫 번째 완료 상태), priority, ownerId, extraFieldsJson. 출력: recordId, recordUrl, status.

{ "subject": "Call with CFO", "relatedRecordId": "001...", "personRecordId": "003...", "description": "Discussed renewal", "activityType": "Call" }

closeCase / SObjectCloseCaseAction

입력: caseIds, status (닫힌 상태여야 함; 기본값 첫 번째 닫힌 상태), comment (+ commentIsPublic), extraFieldsJson, allOrNone. 출력: 사용된 status, 케이스별 개수, recordLabels (CaseNumber - Subject).

convertLead / SObjectConvertLeadAction

입력: leadId, convertedStatus (기본값 첫 번째 변환된 상태), accountId / contactId (기존 레코드에 병합), createOpportunity (기본값 true), opportunityName, ownerId, sendEmailToOwner. 출력: accountId, contactId, opportunityId + URL.

postChatter / SObjectPostChatterAction

입력: recordId (피드가 활성화된 레코드 또는 User), text, mentionUserIds. 출력: feedItemId. 객체에 피드 추적이 없으면 명확한 메시지와 함께 실패합니다.

addNote / SObjectAddNoteAction

입력: title, body (일반 텍스트 또는 간단한 HTML), recordIds, shareType (V 기본값 / I / C). ContentNoteContentDocumentLink를 생성합니다. 조직에서 향상된 메모(Enhanced Notes)가 비활성화된 경우 메모를 .html 파일로 저장합니다 (storedAsFile=true). 출력: noteId, 연결된 recordIds, storedAsFile.

attachFile / SObjectAttachFileAction

입력: fileName, textContent 또는 base64Content, title, recordIds, shareType. 출력: contentVersionId, contentDocumentId, 연결된 recordIds. 큰 base64 페이로드에는 힙 제한이 적용됩니다 (동기식 약 6MB).

listFlows / SObjectListFlowsAction

목록 모드: nameContains, processType (기본값 AutoLaunchedFlow; ALL), includeInactive, limitCount -> flowsJson. 상세 모드: flowApiName -> variablesJson (apiName, dataType, isInput, isOutput, isCollection, objectType, description). runFlow와 함께 사용합니다.

recordSummary / SObjectSummaryAction

입력: recordId, fields (기본값 모든 접근 가능 필드), relationshipNames (최대 10개; 기본값 존재하는 일반적인 관계), recentActivityLimit (0-20, 기본값 5). 출력: objectApiName, recordLabel, recordUrl, ownerName, recordJson, relatedCountsJson ({Contacts: 3, Cases: 1, ...}), recentActivityJson ([{id,type,subject,date,status,ownerName}]). 레코드 1개에 SOQL 1회 + 관계당 1회 + 활동에 2회가 소요됩니다.


Flow에서 호출

Action 요소를 추가하고 SObject Actions 카테고리를 검색한 후 작업을 선택합니다.

  • Object API Name을 리터럴 또는 텍스트 변수로 설정합니다.

  • create/update의 경우 레코드 변수를 Record에, 레코드 컬렉션을 Records에 할당합니다. Flow의 일반 SObject 입력은 작업 요소에서 객체 유형을 선택하도록 요구합니다. objectApiName과 일치해야 합니다 (또는 Activity와 함께 Task/Event).

  • 출력 Created Record Ids / Record / Records / Errors를 Flow 변수로 읽습니다.

  • 부분 성공을 원하면 All Or None을 비워 두거나, 롤백하려면 {!$GlobalConstant.True}로 설정합니다.

오류 경로: 요청 수준 문제는 예외를 발생시키지 않습니다. SuccessErrors를 확인하세요. 예기치 않은 플랫폼 예외(한도 등)만 Flow 오류 커넥터에 도달합니다.


REST에서 호출

POST /services/data/v67.0/actions/custom/apex/SObjectCreateAction
Authorization: Bearer <token>
Content-Type: application/json

{ "inputs": [
  { "objectApiName": "Account", "recordsJson": "[{\"Name\":\"Acme\"}]" },
  { "objectApiName": "Contact", "recordsJson": "[{\"LastName\":\"Smith\",\"AccountId\":\"001...\"}]" }
] }

SObjectReadAction, SObjectUpdateAction, SObjectDeleteAction에도 동일한 형태가 적용됩니다. inputs의 각 요소는 응답 outputValues의 한 요소에 매핑됩니다.


보안 모델

  • 모든 DML 및 SOQL은 AccessLevel.USER_MODE로 실행됩니다. 객체 CRUD, 필드 수준 보안 및 실행 중인 사용자의 공유가 플랫폼에 의해 적용됩니다.

    • 쓰기 불가능한 필드의 생성/업데이트 -> 플랫폼에서 행 오류 발생.

    • 접근 불가능한 객체/필드 읽기 -> 반환되지 않음 (기본 필드 목록에는 접근 가능한 필드만 포함되며, 명시적으로 접근 불가능한 필드는 쿼리 오류 발생).

    • 사용자의 공유 범위 밖의 레코드 -> 읽기 시 notFoundIds, 업데이트/삭제 시 행 오류.

  • 클래스는 global with sharing입니다 (MCP 검색에 필요).

  • 원시 호출자 입력에서 Database.query 문자열이 생성되지 않습니다. 객체 이름은 describe를 통해, 필드 이름은 필드 맵을 통해, Id는 Id.valueOf를 통해 검증됩니다. readRecords.fields의 관계 경로는 SELECT 목록에만 배치되며 WHERE 절에는 절대 배치되지 않습니다.

  • 도구가 일반적이므로 권한 집합으로 접근을 제어하세요: Apex 클래스를 호출할 수 있는 사람과 객체에 대한 CRUD/FLS를 결정합니다. 에이전트 사용 사례에서 삭제가 절대 발생하지 않아야 하는 경우 서버에서 deleteRecords를 제외하는 것을 고려하세요.


한도 및 대량 동작

  • 호출 가능 입력은 대량 처리됩니다. 한 번의 호출에서 모든 요청의 모든 레코드는 가능한 가장 적은 수의 DML 문으로 결합됩니다 (일반적인 경우 호출당 하나의 insert / update / delete).

  • 한 번의 호출에서 동일한 레코드가 두 번 업데이트/삭제되는 중복 IdDuplicate id in list 오류 대신 순차 DML 배치로 분할됩니다.

  • 레이블 조회: 호출당 구체적인 객체 유형별 SOQL 1회 (create/update/delete); 읽기는 요청당 구체적인 유형별 SOQL 1회.

  • 트랜잭션당 적용되는 가버너 한도: SOQL 100개, DML 문 150개, DML 행 10,000개, 힙 6MB (동기식). 매우 큰 recordsJson 페이로드 또는 넓은 객체에서 fields 없이 수백 개의 Id를 읽는 readRecords는 힙/CPU 한도에 근접할 수 있습니다. 대량 읽기에는 명시적 fields 목록을 전달하세요.

  • 한 번의 호출에서 여러 객체 유형을 혼합하는 것은 괜찮지만, 설정 객체와 비설정 객체 (예: User + Account)를 단일 호출에 혼합하면 플랫폼의 혼합 DML 규칙이 적용됩니다.

  • 서로 다른 SObject 유형의 DML 청크당 레코드 수는 플랫폼에 의해 DML 문당 최대 10개의 고유 유형으로 제한됩니다.


오류 카탈로그

메시지

원인

해결 방법

objectApiName is required.

입력 값이 누락됨

API 이름을 제공하세요

Unknown object API name: X

오타/존재하지 않는 이름

철자와 오브젝트 접근 권한을 확인하세요

Activity is polymorphic. ...

Activity를 Task와 Event로 구분할 방법 없이 사용함

Task/Event를 사용하거나 JSON 행마다 attributes.type을 추가하세요

Record of type X does not match objectApiName Y.

잘못된 유형의 SObject 입력

입력 유형을 일치시키세요

attributes.type X does not match objectApiName Y.

JSON 행이 다른 유형으로 지정됨

attributes.type을 제거하거나 수정하세요

recordsJson is not valid JSON: ...

형식이 잘못된 문자열

적절히 이스케이프된 JSON 객체 또는 배열인지 확인하세요

recordsJson must be a JSON object or array of objects.

스칼라/기타 JSON

{} 또는 []로 감싸세요

Unknown field(s) on X: a, b

오브젝트에 없는 필드 이름

API 이름을 수정하세요 (__c 접미사, 네임스페이스)

Could not build X from JSON: ...

값 유형 변환 실패(잘못된 날짜 형식 등)

ISO-8601 날짜/날짜시간을 사용하고 올바른 유형을 지정하세요

No records supplied. ...

작업 대상이 없음

record, records, recordsJson 또는 Id를 제공하세요

Invalid record Id: ...

유효한 15/18자리 Id가 아님

Id를 수정하세요

Id X is a T and does not match objectApiName Y.

잘못된 접두어

objectApiName 또는 Id를 수정하세요

row n: Id is required for update.

Id가 없는 업데이트 행

Id를 추가하세요

Every record must include Id for delete.

Id가 없는 SObject 삭제 입력

Id를 추가하세요

Unknown field on X: f (read/find)

fields / orderBy / externalIdField에 잘못된 항목

API 이름을 수정하세요

Field X on Y is not an external Id / idLookup field ...

잘못된 externalIdField

외부 Id 필드를 사용하세요 (또는 Id)

Unknown filter field on X: f (relationship paths are not allowed in filters).

잘못된 점(.) 포함 필터 필드

직접 필드를 사용하세요

Field X is not filterable.

긴 텍스트/암호화 필드 등

다른 필드로 필터링하세요

Unsupported op "X"

잘못된 op

=, !=, <, <=, >, >=, LIKE, IN, NOT IN을 사용하세요

Value "x" is not valid for field F (TYPE)

유형 변환 실패

필드 유형/ISO 날짜 형식과 일치시키세요

limitCount must be between 1 and 200.

범위를 벗어남

조정하세요

row n: <platform message> [Field]

DML 실패(검증 규칙, 필수 필드, FLS, 공유 설정)

데이터 또는 권한을 수정하세요


테스트

세 가지 계층으로 구성하며, 가장 저렴한 것부터입니다.

# 1. Unit tests (Apex, ~98% coverage)
sf apex run test -o <alias> -n SObjectActionsTest -n SObjectActionsExtTest -n SObjectActionsExt2Test -n SObjectActionsExt3Test -n SObjectActionsExt4Test -r human -w 10 -c

# 2. Anonymous Apex smoke: create -> read -> update -> delete, prints every result
sf apex run -o <alias> -f scripts/apex/smoke.apex

# 3. REST smoke through the Invocable Actions API (the exact path MCP tools use).
#    45 assertions across all 27 tools incl. Case labels, Activity Task/Event mix,
#    validation errors. Creates and removes its own records. Needs jq.
scripts/smoke-test.sh <alias> [apiVersion]

MCP 계층 자체를 테스트하려면 위 안내대로 서버를 활성화하고, External Client App으로 MCP 클라이언트를 연결한 다음 tools/list를 실행하고 예를 들어 readRecords {"objectApiName":"Account","recordId":"0011..."} 호출합니다.

테스트 범위: 생성(SObject + JSON 입력, Case 라벨, Activity 해석, 검증 매트릭스, 부분 및 all-or-none), 조회(전체/명시적 필드, 관계 경로, Activity 혼합, 조회 결과 없음, 검증), 업데이트(JSON/SObject/SObject/Activity 혼합, Id 누락, 유령 Id, all-or-none 롤백, 요청 간 중복 Id), 삭제(Ids/SObjects/Activity 혼합, 라벨, 검증, 부분, all-or-none, 중복 Id), 유틸리티 대체 동작.

테스트는 테이블 개수가 아닌 레코드 Id 기준으로 검증하므로, Account에 기존 트리거나 자동화가 있는 조직에서도 통과합니다.


확장

원래 설계 목록의 모든 항목이 구현되어 있습니다. 자연스러운 다음 추가 사항은 레코드 유형 인식 선택 목록(Named Credential을 통한 UI API 호출), sendEmail(단일 이메일/템플릿), approval submit/recall, 공유/공유 해제(수동 공유) 작업입니다.

  • 사용자 정의 라벨 규칙: SObjectActionUtil.labelFields()를 확장합니다(Case가 현재 특별 사례입니다).

  • 서버의 새 도구 추가: mcp/main/default/mcpServerDefinitions/SObjectActions.example.mcpServerDefinition-meta.xmlapiIdentifier = aa:apex-<ClassName>과 함께 <tools> 블록을 추가하고 다시 배포하세요. 필요하면 Set up에서 서버를 다시 활성화하세요.

F
license - not found
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to interact with Salesforce organizations through natural language by exposing Salesforce APIs (REST, Bulk v2, GraphQL, Tooling, Auth) as MCP tools for querying data, managing records, and executing SOQL queries.
    12
    19
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to interact with Salesforce through MCP, supporting queries, records, metadata, and bulk operations with flexible OAuth authentication.
    MIT

View all related MCP servers

Related MCP Connectors

  • Search, document and execute authenticated API calls across 700+ apps via one MCP server

  • An AI concierge that turns static forms into adaptive AI conversations. From any MCP client.

  • Operator-as-agent MCP hub. 6 tools. First $5 free, then $0.001/call.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Kelley-Austin/sfka-mcp-demo'

If you have feedback or need assistance with the MCP directory API, please join our Discord server