Enable CMDB Asset Discovery (Service Cloud ITSM)
Turns on Asset Discovery for CMDB by enabling the service-cloud-itsm-discovery-integration
feature, then grants a user access to the Discovery page by assigning the IT Service Discovery
Manager permission set (and its permission-set license). This is the final layer of CMDB setup —
it runs only after the base CMDB feature is enabled, users have CMDB access, and the CMDB Foundation
content bundle is installed. Every call runs through the Salesforce-hosted Headless-360 MCP server
(server key headless-360) via its four meta-tools (discover, describe, dispatch_readonly,
dispatch). The org is derived from the OAuth JWT bound to the current MCP session — the skill never
handles an org id, alias, or credentials — so this works identically against production and sandbox
with no per-user MCP install.
This skill covers the Discovery layer only — enabling the feature and granting Discovery page access to a user. The earlier CMDB layers are separate skills — see the end of this file.
Where this sits in the CMDB stack
CMDB is enabled in ordered layers, each gated on the prior one:
Discovery is recommended last, but it does not require the base CMDB feature to already be
on: the enable cascade-enables its dependency (the base CMDB feature) as part of turning Discovery
on, provided that feature's own prerequisites (e.g. a provisioned CMDB tenant) are met. The
enableBlockedReasons array in the pre-check is the authoritative blocker signal — a base CMDB feature
that is merely NOT_ENABLED appears under dependencyStatuses with empty enableBlockedReasons
and is not a blocker. So never tell the user a direct enable "will error out"; tell them it will
turn on CMDB first, then Discovery. Only a non-empty enableBlockedReasons (e.g. tenant not
provisioned) is a genuine unmet prerequisite that stops the enable.
Enabling the feature lifts the org-level gate; the Discovery permission set gives a user the Discovery page. This skill does both: it turns Discovery on for the org (Step 2) and then assigns the target user the license-backed
ItSrvcDscvrMgrPermissionSet("IT Service Discovery Manager", backed by PSLItSrvcDscvrMgrPsl) so they can actually open and use the Discovery page (Steps 4–7). That permission set is distinct from the four Configuration-Item permission sets (Reader / Owner / Type Reader / Type Manager) thatservice-itsm-agentic-setup-cmdb-access-assignassigns for CMDB data — a user holding only those will not have Discovery page access. The assignment step is idempotent: if the user already holds the Discovery permission set and its license, it is skipped and reported as already-done.
Scope
- In scope: pre-checking, enabling, and verifying the
service-cloud-itsm-discovery-integrationfeature; and — as a follow-up — assigning the IT Service Discovery Manager permission set (and its permission-set license) to the target user so they can access the Discovery page. - Out of scope: enabling the base CMDB feature / provisioning the CMDB tenant (Layer 2 —
service-itsm-agentic-setup-cmdb-configure), assigning the four Configuration-Item permission sets for CMDB data access (Layer 3 —service-itsm-agentic-setup-cmdb-access-assign), bundle installation (Layer 4 —service-itsm-agentic-setup-cmdb-bundle-deploy), CMDB record CRUD, Service Graph Connector configuration, identification rules, creating or editing permission sets.
Mechanism
All operations dispatch through headless-360 MCP tools. Reads go through
mcp__headless-360__dispatch_readonly, writes through mcp__headless-360__dispatch — both take raw
HTTP: {"url": "<path>", "method": "GET|POST", "body"?: {...}, "queryParams"?: {...}} — not
{operation_id, arguments}. See references/mcp-invocation.md for the exact url / method /
body of every call. The four tools:
mcp__headless-360__discover— semantic search over the indexed operation catalog. The Setup/Connect routes and the/query//sobjects/...REST routes this skill uses are not always ranked first (or indexed), so a miss does not mean the route is absent — dispatch the exact path directly (seereferences/mcp-invocation.md).mcp__headless-360__describe— pull the full input schema and canonical route before any POST.mcp__headless-360__dispatch_readonly— the dispatcher for every read (GET).mcp__headless-360__dispatch— the dispatcher for every write (POST/PATCH).
The skill never handles credentials — the org is bound to the current OAuth session. If a dispatch*
call returns an auth error, tell the user to re-authenticate the headless-360 MCP connection (and
confirm the session points at the intended org), then stop.
The Discovery permission set
Resolve the permission set's Id and its LicenseId at runtime (Step 5) rather than hardcoding IDs —
IDs differ per org.
Clarifying questions
Ask only what you cannot infer from conversation:
- Which org? Confirm the target org and state plainly that this org will be modified (enabling the discovery feature is a write). For production, get explicit confirmation.
- Which user gets Discovery page access? The user to assign the IT Service Discovery Manager role. If the request is "enable discovery for me" / "set up discovery", default to the current (running) user. Accept a username/email for someone else.
Do not re-ask for anything the user already provided; pre-populate and note "(from conversation)".
Workflow
All steps are sequential and gated — do not advance past a failed check. Always read before you write: run the read-only pre-check before the enable, and the assignment checks before the assign.
Step 1 — Pre-check discovery feature status (read)
The feature api name is service-cloud-itsm-discovery-integration.
status == ENABLED→ feature already on; skip to verification (Step 3), then proceed to the access follow-up (Steps 4–7).status == NOT_ENABLEDwithenableBlockedReasons: []→ clear to enable (Step 2). Before confirming, inspectdependencyStatuses: if the base CMDB feature (service-cloud-itsm-cmdb-integration) is listed there asNOT_ENABLED, that is not a blocker — enabling Discovery will cascade-enable the base CMDB feature first, then Discovery. Tell the user exactly that ("this will turn on CMDB first, then Asset Discovery"). Do not warn that it "will error out" or offer to "let it report the dependency error" — neither happens.enableBlockedReasonsnon-empty → STOP and relay each reason to the user in plain language. These are genuine unmet prerequisites the org still needs (e.g. the CMDB tenant is not provisioned, so the base feature cannot be enabled). Point the user to the earlier CMDB setup skills (see "Common failures") and do not attempt the enable.403 FUNCTIONALITY_NOT_ENABLEDon this GET → the base CMDB gate itself is still closed; the org needsservice-itsm-agentic-setup-cmdb-configurefirst. Stop and route the user there.
Step 2 — Enable Asset Discovery (write — confirm with the user first)
Skip this step if Step 1 already reported ENABLED.
Step 3 — Verify the feature (read — do NOT trust the POST response alone)
status == ENABLED is the definitive confirmation that the feature is on. Once confirmed, continue
to the access follow-up below — the feature being on does not by itself give any user the Discovery page.
Step 4 — Resolve the target user (read)
For "the current user" / "me" / "set up discovery" (do NOT use USER_ID() — Apex-only, rejected by
the REST query API; do NOT rely on /chatter/users/me or /connect/user-profiles/me — they 403 when
Chatter/Communities are off). Read the API root and parse the identity URL:
The response identity field is a URL ending in /<orgId>/<userId> (the user Id is the last path
segment and starts with 005). Use that Id directly, or confirm it with a User query.
For a named user (username / email supplied):
- Exactly one active user → capture the
Id. - Zero results → STOP; ask the user to confirm the username.
- More than one → STOP; list the candidates (Name + Username) and ask which one.
Step 5 — Resolve the Discovery permission set + check existing assignment (read — idempotency)
Resolve the permission set and its backing license:
Capture Id (the permission set) and LicenseId (the PSL to assign). totalSize == 0 means the org
is not licensed for Discovery — stop and report. Then check whether the user already has both:
If both already exist, the role is already assigned — skip Step 6 and record it as already-done.
Step 6 — Assign the license, then the permission set (write — confirm first)
Skip whatever Step 5 shows already assigned. Assign the PSL first, then the permission set:
201→ assigned.400 DUPLICATE_VALUE→ the user already had it; treat as success (idempotent), not a failure.- A license-limit / no-seats error → STOP for the assignment; tell the user the Discovery license has
no available seats (see
references/mcp-invocation.mdfor the seat query). Do not retry.
Step 7 — Verify the assignment (read — do NOT trust the POST response alone)
Re-run the two Step 5 assignment queries. The user has Discovery page access only when both the
PermissionSetAssignment and the PermissionSetLicenseAssign return totalSize == 1.
Rules / Constraints
Verification checklist
- Step 1: pre-check showed
enableBlockedReasons: []before enabling (orstatus == ENABLEDalready)? - Step 2: enable returned
success: true(or skipped because already enabled)? - Step 3: verification GET shows
status == ENABLED? - Step 4: target user resolved to exactly one record?
- Step 5: Discovery permission set + license resolved; existing assignment checked (idempotency)?
- Step 6: for the target user, both the permission set and its license are assigned (or already were)?
- Step 7: assignment confirmed by a post-write read (not the POST response alone)?
- Confirmed the target org, user, and each write with the user first?
Output expectations
Keep internal jargon out of user-facing output (no record IDs, HTTP status codes, error codes, object,
endpoint or developer names) — say "IT Service Discovery Manager access", not the developer name. If any
step fails, stop and tell the user — in plain language — which part didn't succeed and what it means for
them, then point to the relevant fix. Translate any raw error (e.g. a 403 or FUNCTIONALITY_NOT_ENABLED)
into what it means ("CMDB isn't fully set up yet"), rather than echoing the code.


