Skip to main content

Tool Reference

The contract of every StratoLens MCP tool: permission, arguments, output fields and errors. Assistants read the schemas from tools/list on their own; this page is for checking what a tool can answer, writing your own MCP client, or understanding an error.

Read-only, as the signed-in user

Every tool is read-only and runs with the signed-in user's StratoLens permissions and data scope. Fields can be added between releases, so clients should ignore fields they don't recognise.

Endpoint and Protocol

Endpoint
POST https://<host>/api/mcp. Only POST is supported; other methods get 405.
Transport
MCP Streamable HTTP, stateless (no sessions). Responses are JSON, framed as server-sent events when the client accepts text/event-stream.
Methods
initialize, tools/list, tools/call
Server name
stratolens
Instructions
The initialize result tells the assistant which tool to use for which question (see Tool Routing).
Result format
A successful result is one text item holding JSON. A failed result is marked as an error and holds { "error": "<message>", "code": "<code>" }. A tool never returns an empty result in place of a failure.
Example tools/call requestJSON
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_scan_changes",
    "arguments": { "changeTypes": ["deleted"], "limit": 20 }
  }
}

Per-tool examples below show only the arguments object.

Conventions

  • Strict arguments. Unknown arguments are rejected. Arguments that don't match the schema are rejected before StratoLens runs the tool, with a message starting "Input validation error:"; such calls are not counted against the rate limit. tools/list publishes each schema with enums and defaults.
  • Free-text arguments (IDs, names, search text, timestamps) are 1 to 1,024 characters.
  • An empty array is treated as if the argument were not given.
  • Links. Rows and results carry link, an absolute URL to the matching StratoLens page, or null when no public address is configured or no page can show the row.
  • Recommendation timestamps. lastUpdatedScanId and lastUpdatedAt name the latest scan that produced recommendations, not the scan that last changed a given row.
  • Check order for every call that passes argument validation: permission (forbidden), data scope (scope_unresolved), rate limit (rate_limited), the tool's own checks, the 60 s time limit (timeout), the 200 KB result limit (result_too_large).

Paging

Every tool that takes offset pages the same way. limit is an integer 1-200, default 50; offset is an integer of 0 or more, default 0. The result has items plus totalCount (every match), offset, nextOffset (null on the last page) and truncated (true when this page doesn't hold every match, so also on later pages). Page with offset = nextOffset until it is null.

An offset past the end returns an empty page, not an error. Counts and totals cover every match and are the same on every page. Sort orders end in a stable ID tie-break, so paging the same data neither repeats nor skips rows (except get_activity_log, see its notes). Where a summary tool pages its per-subscription list, the paging fields sit inside subscriptions.

Hidden items

get_security_findings, get_cost_anomalies, get_orphaned_resources, get_access_optimizations, get_sizing_recommendations, get_service_retirements and get_commitment_recommendations leave out items an administrator hid on the page and count them (hiddenCount, hiddenResourceCount or hiddenPrincipalCount). With includeHidden true they return them with hidden: true.

Common errors

Any tool can return these. Per-tool Errors below list only the tool's own checks, in order.

Errors

  • forbiddenMissing permission <id>
  • scope_unresolvedYour data scope could not be resolved, so no data can be returned.
  • rate_limitedRate limit of <n> tool calls per minute reached. Retry in <s> s.
  • timeoutThe tool did not finish within 60 s. Narrow the query with filters or a smaller limit and retry.
  • result_too_largeResult is <n> KB, over the 200 KB budget. Narrow the query with filters or a smaller limit.
  • failedThe tool failed unexpectedly. The server log has the detail; retry, or narrow the query.

Scan ID errors

Every tool that resolves a scanId:

Errors

  • not_foundNo completed scan exists yet. Run a scan in StratoLens first.(scanId omitted or latest, on a fresh install)
  • not_foundScan not found: <id>. Use list_scans to find a valid scanId.(unknown ID)

Tool Routing

The server instructions steer the assistant like this:

  • What changed: get_scan_changes first. get_changes_summary and get_changes for exactly who and when. get_activity_log for operation detail and role-assignment activity.
  • Who has access: get_role_assignments. Unused, stale or over-privileged access: get_access_optimizations.
  • Savings: get_sizing_recommendations, get_orphaned_resources, get_cost_anomalies and get_commitment_recommendations together.
  • Reservations and savings plans: get_commitments (inventory, spend, utilization, expiry) and get_commitment_recommendations (what to buy, underutilized or expiring alerts, cleared alerts). Commitment charges over time: get_cost_summary.
  • Upcoming Azure retirements: get_service_retirements.

Permissions

The forbidden message names the permission ID, not the name shown in StratoLens.

MCP tool permissions
PermissionIDTools
none (any signed-in user)whoami
View Scansscan.readlist_scans
View Resourcesdata.readsearch_resources, get_resource_details, get_role_assignments, get_access_optimizations, get_scan_changes, get_security_findings, get_orphaned_resources, get_sizing_recommendations, get_service_retirements
View Resource Changeschange_tracking.readget_changes_summary, get_changes
View Azure Activity Logsactivity_log.readget_activity_log
View Defender Assessmentsdefender.readget_defender_alerts_summary
View Policy Datapolicy.readget_policy_compliance_summary
View Costscost.readget_cost_summary, get_cost_anomalies, get_commitments, get_commitment_recommendations

Identity and Scans

whoami

Permission: none (any signed-in user)

Who the caller is, their permissions, data scope and the MCP client in use. Takes no arguments; any argument is rejected.

Output

whoami output fields
FieldMeaning
userIdYour Entra object ID
displayNameYour display name
permissionsYour effective StratoLens permission IDs, e.g. data.read, cost.read
grantingSourcesHow your access was granted (your user grant and/or group grants)
scope.modeall (every subscription) or include (limited)
scope.subscriptionCountNumber of subscriptions you are limited to; null when mode is all
clientIdClient ID of the MCP client app in use
clientNameThat client's display name in the Trusted clients list, or null

Notes

  • Write and manage permissions listed here apply only in the web app.

Example arguments

{}

list_scans

Permission: View Scans

Finished scans, newest first. Use it to pick a scanId or see when the inventory was last refreshed. Arguments: limit, offset (paging).

Output (items)

list_scans item fields
FieldMeaning
scanIdScan ID
statusCompleted, Failed, CompletedWithNoResults or Cancelled
startedAt / completedAtTimestamps (completedAt may be null)
resourceCountResources found
entityCounts{ managementGroups, subscriptions, resourceGroups, resources }, or null
warningCountScan warnings (0 when none)
statusMessageStatus text, or null

Notes

  • Counts are for the whole tenant, not your data scope.
  • No link: there is no scan-list deep link.

Example arguments

{ "limit": 5 }

Inventory and Access

search_resources

Permission: View Resourcesaccepts scanId=latest (mode current)

Find subscriptions, resource groups, resources and management groups by name. This is how to get the entityId that get_resource_details needs.

Arguments

search_resources arguments
NameRequiredFormat / valuesDefaultNotes
queryyestext, at least 2 charactersContained in the name, case-insensitive
modenocurrent, allcurrentall searches every scan, so it also finds deleted entities
entityTypenoall, subscription, resourceGroup, resourceallall also returns management groups
scanIdnoscan ID or latestlatest completed scanMode current only; ignored (not checked) in mode all
limitnointeger 1-5050Lower maximum than other tools

Output: mode, scanId (null in mode all), items, totalCount, truncated. No offset or nextOffset.

search_resources output fields
FieldMeaning
entityIdFull ARM ID
name, resourceType, entityTypeEntity name, ARM type, hierarchy level
subscriptionId, subscriptionName, resourceGroupLocation in the hierarchy (resourceGroup may be null)
lastSeenScanId, lastSeenAtMode all only: the last scan the entity was seen in
linkExplorer at the row's scan
totalCountMatches the search returned (at most 50)
truncatedTrue when more rows exist than returned, or the search hit its 50-match cap: refine the query

Errors

  • Scan ID errors (see Conventions)(mode current only)

Notes

  • At most 50 matches, highest hierarchy level first. No paging; refine the query instead.

Example arguments

{ "query": "prod-sql", "entityType": "resource" }

get_resource_details

Permission: View Resourcesaccepts scanId=latest

One entity as recorded in a scan, optionally with its scan-by-scan history.

Arguments

get_resource_details arguments
NameRequiredFormat / valuesDefaultNotes
entityIdyesfull ARM IDCase-insensitive; from search_resources
scanIdnoscan ID or latestlatest completed scan
entityTypenomanagementGroup, subscription, resourceGroup, resourceRequired for a management group when your access is limited to part of the tenant
includeHistorynobooleanfalseAdds history

Output

get_resource_details output fields
FieldMeaning
entityId, name, type, entityTypeIdentity
locationAzure region, or null
subscriptionId, subscriptionName, resourceGroupHierarchy (resourceGroup may be null)
tagsTag name/value object
scanIdThe scan read
versionFirstSeenAt, versionLastSeenAtWhen this version of the entity was first and last recorded
rbac{ collectionStatus, directAssignmentCount, eligibleAssignmentCount }, or null
linkExplorer at the scan
historyWith includeHistory only: { items, totalCount, truncated }; items newest first, at most 50: { scanId, scanTimestamp, status, hasChildChanges }, status created, present or deleted

Errors

  • Scan ID errors (see Conventions)
  • not_foundEntity with ID '<id>' not found in scan '<scanId>'.(unknown entity, or outside your data scope)
  • not_foundThis resource has not been discovered by any scans yet. …(with includeHistory, for an entity no scan has found)

Notes

  • Resource properties are not returned; open link for them.

Example arguments

{ "entityId": "/subscriptions/<guid>/resourceGroups/rg-prod/providers/Microsoft.Sql/servers/prod-sql", "includeHistory": true }

get_role_assignments

Permission: View Resourcesaccepts scanId=latest

Who holds which Azure RBAC role where, matching the Role Assignments page. Two modes: principal list (default) or one principal's assignments (principalId set).

Arguments

get_role_assignments arguments
NameRequiredFormat / valuesDefaultNotes
scanIdnoscan ID or latestlatest completed scan
principalIdnoobject IDSwitches to assignment mode
principalTypesnoarray of User, Group, ServicePrincipalallPrincipal list only; ignored with principalId
roleCategoriesnoarray of critical, management, read, otherall
scopeTypesnoarray of managementGroup, subscription, resourceGroup, resourceallLevel the assignment was made at
assignmentSourcesnoarray of direct, inheritedallinherited = through group membership
pimStatusesnoarray of permanent, active, eligibleallactive = PIM time-bound active; eligible = PIM eligibility
roleNamesnoarray of exact role namesallavailableRoleNames lists valid names
searchnotextDisplay name contains, case-insensitive; principal list only
limit, offsetnopaging50, 0Both modes

Output, principal list mode: scanId, principalCount, assignmentCount, byRoleCategory { critical, management, read, other } (the page's filter-responsive badge counts, summed), availableRoleNames, paging fields, link, and items most privileged first:

get_role_assignments principal list item fields
FieldMeaning
principalId, displayName, principalTypeThe user, group or service principal
assignmentCountMatching assignments
critical, management, read, otherMatching assignments per role category
linkRole Assignments page with the same filters and the principal selected

Output, assignment mode: scanId, principalId, paging fields, link, and items most privileged role and broadest scope first:

get_role_assignments assignment item fields
FieldMeaning
roleName, roleCategoryRole and its category
scope, entityType, entityNameWhere the role applies
subscriptionId, subscriptionName, resourceGroupHierarchy, or null
assignmentSourcedirect or inherited
grantedViaGroupId, grantedViaGroupNameThe group an inherited assignment comes from, or null
pimStatus, pimEndDateTimePIM status and end time (or null)
createdOnAssignment date, or null
linkRole Assignments page with the principal selected (same for every row)

Errors

  • Scan ID errors (see Conventions)

Notes

  • Role categories follow the Role Assignments page: any role with "Owner" or "Administrator" in its name is critical, so Storage Blob Data Owner counts; roles containing Contributor, Manager or Operator are management; reader and monitoring roles are read.
  • Group membership is expanded. Filters combine with AND.
  • Links carry every filter except search and open with the page's default sort.
  • The principal list is reused for 2 minutes per scan.

Example arguments

{ "roleCategories": ["critical"], "principalTypes": ["ServicePrincipal"] }

get_access_optimizations

Permission: View Resources

RBAC access that could be reduced, matching the Access Optimization page, principals with most optimizations first. Always reads the latest recommendations.

Arguments

get_access_optimizations arguments
NameRequiredFormat / valuesDefaultNotes
timeWindowDaysno7, 30, 60, 90, 180, 36530Activity window the optimizations are derived for
optimizationTypesnoarray of overPrivileged, overScoped, unused, stale, excessiveSprawl, redundantAssignment, unusedEligibilityall
principalTypesnoarray of User, Group, ServicePrincipalall
roleTypesnoarray of critical, management, read, otherallAccess Optimization categories (see notes)
principalIdnoobject IDOnly this principal
searchnotextDisplay name contains, case-insensitive
includeHiddennobooleanfalse
limit, offsetnopaging50, 0Pages principals

Output: lastUpdatedScanId, lastUpdatedAt, timeWindowDays, byOptimizationType (all seven types, over every match), principalCount, hiddenPrincipalCount, paging fields, link, and items:

get_access_optimizations item fields
FieldMeaning
principalId, displayName, principalTypeThe principal
optimizationCountIts optimizations after the type and role filters
hiddenPrincipal hidden by an admin
optimizationsFirst 25, each: type, roleName, scope, scopeType, entityName, subscriptionId, subscriptionName, resourceGroup, grantedViaGroupId, grantedViaGroupName, lastActivity, action, suggestedRole, suggestedScopeType, redundancyReason and redundancyDetails (set on redundantAssignment only, else null), pimEligible, hidden
optimizationsTruncatedMore than 25 optimizations exist
linkAccess Optimization page with the same window and filters and the principal selected

Notes

  • Type meanings: overPrivileged critical role with no role-assignment changes; overScoped activity in under 30% of its scopes; unused critical or management role with no activity; stale last activity over half the window ago; excessiveSprawl same role in 5+ subscriptions; redundantAssignment duplicated by another grant; unusedEligibility PIM eligible role not used.
  • Groups only get sprawl and redundancy.
  • Role categories differ from get_role_assignments: exactly Owner or User Access Administrator = critical; exactly Contributor = management; name containing Reader, Viewer or Monitor = read.
  • Links carry every filter except search.
  • Each principal's optimizations are in derivation order, not the page's detail-panel order.

Example arguments

{ "optimizationTypes": ["unused", "overPrivileged"], "timeWindowDays": 90 }

Changes and Activity

get_scan_changes

Permission: View Resources. "Changed by" data also needs View Resource Changes and/or View Azure Activity Logs.accepts latest (compareScanId only)

The "what changed" tool. Compares two scans exactly as the Changes page does with Show Ignored off: ignore rules applied, role-assignment changes included, with who made each change.

Arguments

get_scan_changes arguments
NameRequiredFormat / valuesDefaultNotes
compareScanIdnoCompleted scan ID or latestlatest completed scanThe newer scan
baseScanIdnoCompleted scan ID older than comparethe completed scan right before compareNot with since
sincenoISO 8601 UTC timestampPicks as base the newest completed scan at or before this time; not with baseScanId
changeTypesnoarray of added, deleted, modifiedallFilters items only; counts are not affected
entityTypesnoarray of managementGroup, subscription, resourceGroup, resourceall
subscriptionIdnoGUIDCase-insensitive
resourceGroupNamenonameCase-insensitive; requires subscriptionId
resourceTypenoexact ARM typeCase-insensitive, e.g. Microsoft.Compute/virtualMachines
includeAttributionnobooleantruefalse skips the "changed by" lookup
limit, offsetnopaging50, 0

Output

get_scan_changes output fields
FieldMeaning
baseScan, compareScan{ scanId, scanTimestamp } of the pair compared
sinceCoverageOnly with since: exact; startsLater (no scan that old, the oldest was used); endsBefore (no scan since then; use get_changes)
byStatus{ added, deleted, modified }, after the scope filters, before changeTypes
byEntityType{ managementGroup, subscription, resourceGroup, resource }, same basis
hiddenByIgnoreRules{ typeRules, ignoredOnly }: typeRules is the page's Type Ignores tab total; ignoredOnly counts rows whose only changes are ignored (not a number the page shows)
attribution{ available: true, sources: { arg, activity } } or { available: false, reason }
topChangedByOnly when attribution is available: top 10 { displayName, changeCount, rbacCount } over every match
itemsSorted deleted → added → modified, then entity type, name, ID
linkChanges page for the pair (with the subscription / resource group selected when filtered)

Each item

get_scan_changes item fields
FieldMeaning
entityIdARM ID, lowercase
name, type, entityType, changeStatusIdentity and added / deleted / modified
subscriptionId, subscriptionName, resourceGroupHierarchy, or null
changedAreasWhat changed, e.g. properties, tags, rbacAssignments
changedPropertyPaths, changedPropertyCountFirst 5 changed property paths and the total (modified rows only)
hasChildChanges, childChangeCountsChanges below this entity
changedByOnly when attribution is available: top 3 { displayName, sources, changeCount, rbacCount, lastChangeTime }; empty = Unattributed
changedByTruncatedMore than 3 users
linkChanges page for the pair with the entity selected (management groups: the pair only)

Errors

  • invalid_argumentsPass baseScanId or since, not both.
  • invalid_argumentsresourceGroupName requires subscriptionId to be specified
  • invalid_argumentssince must be a valid ISO timestamp
  • Scan ID errors (see Conventions)(for an explicit compareScanId / baseScanId)
  • not_foundNo completed scan exists yet. Run a scan in StratoLens first.
  • invalid_argumentsScan <id> is not a Completed scan; use list_scans to find a Completed scanId.(compare)
  • not_foundNo completed scan is older than <id>; there is nothing to compare.
  • invalid_argumentsScan <id> is not a Completed scan; use list_scans to find a Completed scanId.(base)
  • invalid_argumentsBase scan '<base>' must be older than compare scan '<compare>'.
  • not_found… The scan holds no entities in your data scope.(a scan holds no entities in your data scope)

Notes

  • Attribution reason values: "Requires change_tracking.read or activity_log.read permission"; "time window must not exceed 366 days" (scans more than 366 days apart); "Not requested (includeAttribution is false)."
  • Not visible: changes after compareScan.scanTimestamp, and changes made and reverted between the two scans.
  • rbacAssignments in changedAreas does not say which assignments changed; use get_activity_log.
  • Before/after values and properties are never returned.
  • Results are reused for 2 minutes per scan pair, so the first call on a very large tenant can be slow and later pages are fast.
  • Do not pass latest as baseScanId.

Example arguments

{ "since": "2026-10-01T00:00:00Z", "changeTypes": ["deleted"] }

get_changes_summary

Permission: View Resource Changes

Supporting evidence: totals of raw Azure Resource Graph change events (Create, Update, Delete) in a time window.

Arguments

get_changes_summary arguments
NameRequiredFormat / valuesDefaultNotes
startyesISO 8601 timestampInclusive, whole seconds; no time zone = UTC
endyesISO 8601 timestampInclusive, whole seconds; at most 366 days after start
subscriptionIdnoGUID
resourceGroupNamenonameCase-insensitive; requires subscriptionId
limit, offsetnopaging50, 0Page the subscription list

Output

get_changes_summary output fields
FieldMeaning
window{ start, end } as applied (start …:SS.0000000Z, end …:SSZ)
totalChangesChange events
changedEntityCountEntities with at least one change
changeTypeCountsCounts per Create / Update / Delete
topChangedByTop 10 { changedBy, changeCount }
subscriptions{ items, totalCount, offset, nextOffset, truncated }; items busiest first: { subscriptionId, subscriptionName, totalChanges, changedEntityCount, changeTypeCounts, link } (management group changes group under a null subscription)
linkResource Changes page for the window

Errors

  • invalid_argumentsresourceGroupName requires subscriptionId to be specified
  • start must be a valid ISO timestamp
  • end must be a valid ISO timestamp
  • start must be before end
  • time window must not exceed 366 days

Notes

  • Not filtered by StratoLens ignore rules; no role-assignment changes.

Example arguments

{ "start": "2026-10-12T00:00:00Z", "end": "2026-10-19T00:00:00Z" }

get_changes

Permission: View Resource Changes

Supporting evidence: individual raw Resource Graph change events, newest first.

Arguments

get_changes arguments
NameRequiredFormat / valuesDefaultNotes
start, endyesas get_changes_summary
subscriptionIdnoGUID
resourceGroupNamenonameCase-insensitive; does not require subscriptionId here
resourceNamenonameCase-insensitive
resourceIdnofull ARM IDCase-insensitive
changeTypesnoarray of Create, Update, Deleteall
limit, offsetnopaging50, 0

Output: window plus paging fields and items:

get_changes item fields
FieldMeaning
changeId, changeTime, changeTypeThe event
resourceId, resourceName, resourceType, entityTypeThe entity
subscriptionId, subscriptionName, resourceGroupHierarchy, or null
changedBy, changedByTypeWho made it (display name when known), or null
changedPropertyCount, changedPropertiesNumber of changed properties and the first 5 paths
linkResource Changes page for the entity and window

Errors

  • start must be a valid ISO timestamp
  • end must be a valid ISO timestamp
  • start must be before end
  • time window must not exceed 366 days

Notes

  • Before and after values are not returned; open link.
  • Every page reloads the whole window, so a year-long window on a busy tenant can time out. Use get_changes_summary first and narrow the window.

Example arguments

{ "start": "2026-10-18T00:00:00Z", "end": "2026-10-19T00:00:00Z", "changeTypes": ["Delete"] }

get_activity_log

Permission: View Azure Activity Logs

Azure Activity Log operations that changed something, newest first, including role assignment changes.

Arguments

get_activity_log arguments
NameRequiredFormat / valuesDefaultNotes
start, endyesas get_changes_summary
callersnoarray, at most 50UPN, service principal object or app ID, or a callerDisplayName value; case-insensitive exact match
resourceIdsnoarray of ARM IDs, at most 50Prefix match, so child resources match too; case-insensitive
subscriptionIdsnoarray of GUIDs, at most 50
includeFailedOperationsnobooleantrue
limit, offsetnopaging50, 0

Output: window plus paging fields and items:

get_activity_log item fields
FieldMeaning
timestamp, operationName, operationType, statusThe operation
caller, callerDisplayNameWho ran it
resourceId, resourceName, resourceType, subscriptionId, resourceGroupTarget
changeSummaryShort description, or null
roleAssignmentRole assignment operations: { principalDisplayName, principalType, principalId, roleDefinitionName, roleDefinitionId, scope }; null on other rows
correlationIdAzure correlation ID
linkActivity Explorer for the subscription and window; null for management group operations

Errors

  • start must be a valid ISO timestamp
  • end must be a valid ISO timestamp
  • start must be before end
  • time window must not exceed 366 days

Notes

  • For one person's activity, pass callers rather than paging the whole window.
  • Rows with an identical timestamp have no guaranteed order, so paging can rarely repeat or skip one such row at a page edge.
  • Deep offsets cost more.

Example arguments

{ "start": "2026-10-01T00:00:00Z", "end": "2026-10-19T00:00:00Z", "callers": ["alex@contoso.com"] }

Security and Policy

get_security_findings

Permission: View Resources

StratoLens security findings (insecure configurations, public exposure), most severe first, matching the Security Findings page. Reads the latest scan's findings.

Arguments

get_security_findings arguments
NameRequiredFormat / valuesDefault
severitiesnoarray of Critical, High, Medium, Lowall
categoriesnoarray of PublicExposure, InsecureConfiguration, Hardening, Identity, Governanceall
subscriptionIdnoGUID
includeHiddennobooleanfalse
limit, offsetnopaging50, 0

Output: lastUpdatedScanId, lastUpdatedAt, bySeverity and byCategory (after the subscription and hidden filters, before the severity and category filters), hiddenCount, paging fields, link, and items:

get_security_findings item fields
FieldMeaning
checkId, checkTitle, category, severityThe check
resourceId, resourceName, resourceType, subscriptionId, subscriptionName, resourceGroupAffected resource
instanceLabelWhich instance on the resource, or null
currentValue, expectedValue, recommendationWhat was found and the fix
firstDetectedAt, isNewFirst detection; isNew = within the last 7 days
privateEndpointBypassFinding concerns a private-endpoint bypass
hiddenHidden by an admin
linkSecurity Findings page with the finding's entity selected

Notes

  • Order: severity, then New first, then private-endpoint bypass first. A finding can stop being New during paging and move.

Example arguments

{ "severities": ["Critical", "High"] }

get_defender_alerts_summary

Permission: View Defender Assessmentsaccepts scanId=latest

Microsoft Defender for Cloud alerts present at a scan, with per-subscription rows. Arguments: scanId (scan ID or latest, default latest completed scan), limit, offset (page the subscription list).

Output

get_defender_alerts_summary output fields
FieldMeaning
scanIdScan read
totalAlertsAll alerts
openAlertsActive or InProgress and not hidden (the Defender Alerts page's default view)
severityCountsBy High, Medium, Low, Informational
statusCountsBy Active, InProgress, Resolved, Dismissed
openBySeverityOpen alerts per severity
hiddenCountHidden by an admin
subscriptionsPaged; items most open first: { subscriptionId, subscriptionName, totalAlerts, openAlerts, severityCounts, statusCounts, link }
linkDefender Alerts page at the scan

Errors

  • Scan ID errors (see Conventions)

Example arguments

{}

get_policy_compliance_summary

Permission: View Policy Dataaccepts scanId=latest

Azure Policy compliance at a scan. Counts are policy evaluations (one per resource and policy). Arguments: scanId (scan ID or latest, default latest completed scan), limit, offset (page the subscription list).

Output

get_policy_compliance_summary output fields
FieldMeaning
scanIdScan read
totalEvaluationsEvaluations
complianceStateCountsBy Compliant, NonCompliant, Exempt, Conflict, Unknown
evaluatedEntityCountEntities evaluated
nonCompliantEntityCountEntities with at least one NonCompliant evaluation
topNonCompliantAssignmentsTop 10 { assignmentId, displayName, policyDefinitionDisplayName, scope, nonCompliantCount, link }
subscriptionsPaged; items most NonCompliant first: { subscriptionId, subscriptionName, totalEvaluations, nonCompliantEntityCount, complianceStateCounts, link }
linkPolicy Compliance page at the scan

Errors

  • Scan ID errors (see Conventions)

Example arguments

{ "limit": 10 }

Cost and Savings

get_cost_summary

Permission: View Costs

Spend for a period: totals per currency, per-subscription rows and the top 10 resources.

Arguments

get_cost_summary arguments
NameRequiredFormat / valuesDefaultNotes
startDatenoYYYY-MM-DDcurrent month to dateUsed only together with endDate
endDatenoYYYY-MM-DD, inclusivecurrent month to dateUsed only together with startDate; at most 366 days span
limit, offsetnopaging50, 0Page the subscription list

Output

get_cost_summary output fields
FieldMeaning
period{ type: "range", startDate, endDate } or { type: "currentMonthToDate", month }
totalsOne row per currency: { currency, cost, amortizedCost }; currencies are never added together
resourceCountResources with cost
subscriptionsPaged; items keyed by subscription and currency, most expensive first: { subscriptionId, subscriptionName, currency, cost, amortizedCost, resourceCount, link }
topResourcesTop 10 by cost: { resourceId, resourceName, resourceType, subscriptionId, subscriptionName, resourceGroup, currency, cost, amortizedCost, link } (not paged)
linkCost Explorer for the same period

Errors are checked only when both dates are given.

Errors

  • invalid_argumentsInvalid date format. Use YYYY-MM-DD format.
  • invalid_argumentsstartDate must not be after endDate
  • invalid_argumentsInvalid calendar date.
  • invalid_argumentsDate range exceeds maximum supported span of 366 days

Notes

  • If only one date is given it is ignored and the default period applies; period says which was used.
  • Amortized cost spreads reservation and savings plan purchases over the resources they cover.
  • Costs are rounded to two decimals.

Example arguments

{ "startDate": "2026-09-01", "endDate": "2026-09-30" }

get_cost_anomalies

Permission: View Costs

Cost anomalies (a day whose cost moved sharply from the 30-day baseline), largest absolute change first, matching the Anomaly Detection page defaults.

Arguments

get_cost_anomalies arguments
NameRequiredFormat / valuesDefaultNotes
timeWindowDaysno7, 30, 60, 9030Anomalies on or after this many days ago
minPercentChangenonumber ≥ 010Minimum absolute change in percent
minCostChangenonumber ≥ 01Minimum absolute change in the billing currency
directionnoincrease, decreaseboth
subscriptionIdnoGUID
includeHiddennobooleanfalse
includeOneTimeChargesnobooleanfalseReservation purchases, refunds, Marketplace and similar
limit, offsetnopaging50, 0

Output: lastUpdatedScanId, lastUpdatedAt, resourcesAnalyzed, fromDate, bySeverity { high, medium, low } and byDirection { increase, decrease } (every filter except direction), hiddenResourceCount, paging fields, link, and one item per anomaly:

get_cost_anomalies item fields
FieldMeaning
anomalyDate, anomalyType, severity, directionanomalyType spike or pattern-shift; severity high / medium / low
baselineCost, anomalyCost, costChange, percentChange, currencyAmounts (two decimals; percent one decimal)
descriptionText description
resourceId, resourceName, resourceType, entityType, subscriptionId, subscriptionName, resourceGroupAffected resource
oneTimeCharge, hiddenFlags
linkAnomaly Detection page with the resource selected and the same filters

Example arguments

{ "timeWindowDays": 7, "direction": "increase" }

get_orphaned_resources

Permission: View Resources

Orphaned, idle and empty resources, highest monthly cost first, matching the Orphaned Resources page.

Arguments

get_orphaned_resources arguments
NameRequiredFormat / valuesDefaultNotes
recommendationTypesnoarray of type strings, e.g. orphaned_managed_disk, orphaned_public_ip, idle_vm, stopped_vm_not_deallocatedallbyRecommendationType lists the types present
subscriptionIdnoGUID
metricsTimeframeDaysno1, 7, 14, 30, 6030For activity-based checks, how long without activity counts as idle
includeHiddennobooleanfalse
limit, offsetnopaging50, 0

Output: lastUpdatedScanId, lastUpdatedAt, totals { count, monthlyCost, annualCost, currencies } (every match), byRecommendationType ({ <type>: { count, monthlyCost } }, before the type filter), hiddenCount, paging fields, link, and items:

get_orphaned_resources item fields
FieldMeaning
resourceId, resourceName, resourceType, entityType, subscriptionId, subscriptionName, resourceGroupThe resource
recommendationTypee.g. orphaned_managed_disk
statusUnattached, Idle, Stopped (Not Deallocated), Stale or Empty
orphanedDays, orphanedSinceAge (calculated live) and start
monthlyCost, annualCost, currencyEstimated cost in the resource's billing currency, or null
detectionMethod, reason, lastMetricDateinventory or metrics, the reason, and last activity date
hiddenHidden by an admin
linkOrphaned Resources page with the resource selected

Example arguments

{ "recommendationTypes": ["orphaned_managed_disk"] }

get_sizing_recommendations

Permission: View Resources

VM and managed disk right-sizing, highest monthly savings first, as the Sizing page shows before any toggle is changed.

Arguments

get_sizing_recommendations arguments
NameRequiredFormat / valuesDefaultNotes
typesnoarray of vm (VMs and scale sets), disk (managed disks)both
subscriptionIdnoGUID
minimumMonthlySavingsnonumber ≥ 0, USD100 shows all
includeHiddennobooleanfalse
limit, offsetnopaging50, 0

Output: currency (always USD), minimumMonthlySavings, totals { count, monthlySavings, annualSavings }, byType (per selected type: { count, monthlySavings, annualSavings, hiddenCount, lastUpdatedScanId, lastUpdatedAt }), hiddenCount, paging fields, link, and items:

get_sizing_recommendations item fields
FieldMeaning
typevm or disk
resourceId, resourceName, resourceType, subscriptionId, subscriptionName, resourceGroupThe resource
current, recommendedCurrent and recommended size
monthlySavings, annualSavingsSavings in the page's default view
bestMonthlySavingsSavings with the page's optional toggles on (other families, Standard HDD, Premium SSD v2); can be higher
severityhigh, medium or low
evidenceVM: { analysisWindowDays, cpu { average, p95, maximum }, memoryP95 } (memoryP95 null when not collected). Disk: { analysisWindowDays, iops, throughputMBps, vmDeallocatedDays }, iops and throughputMBps as { avgP95, peakP95, maximum } or null
hiddenHidden by an admin
linkSizing page with the resource selected and the savings threshold at 0

Notes

  • Savings are USD list prices, not billed cost.
  • hiddenCount counts hidden resources that would otherwise match, so it can differ from the page's hidden count.

Example arguments

{ "types": ["vm"], "minimumMonthlySavings": 50 }

get_service_retirements

Permission: View Resources

Azure service retirements affecting your resources, soonest deadline first (undated last), matching the Service Retirements page.

Arguments

get_service_retirements arguments
NameRequiredFormat / valuesDefaultNotes
deadlinenoall, overdue, 90, 180, 365allDay windows include overdue findings; undated findings match only all
impactsnoarray of High, Medium, LowallAny selection leaves out serviceHealth findings (they have no impact)
includeTypeLevelnobooleanfalseInclude resourceType matches
includeUndatednobooleanfalseUndated serviceHealth findings are always included
includeHiddennobooleanfalse
subscriptionIdnoGUID
limit, offsetnopaging50, 0

Output: lastUpdatedScanId, lastUpdatedAt, catalogEntryCount, byUrgency { overdue, next90, next180, later, undated } (every match), hiddenCount, paging fields, link, and items:

get_service_retirements item fields
FieldMeaning
title, retirementDate, urgencyurgency is overdue, next90, next180, later or undated
tieradvisorResource (Advisor confirmed the resource), resourceType (every resource of a retiring type, not confirmed per resource) or serviceHealth (a Service Health event for a subscription)
category, impactCategory; impact High / Medium / Low or null
resourceId, resourceName, resourceType, subscriptionId, subscriptionName, resourceGroupAffected resource (resource fields null for serviceHealth)
impactedResourceCountserviceHealth: resources affected
solutionAdvisor solution text
learnMoreLinkMigration guidance link (http or https only), or null
hiddenHidden by an admin
linkService Retirements page with the resource selected (serviceHealth findings and findings without a resource group: the subscription)

Notes

  • catalogEntryCount 0 or null means the retirement catalog or scan has not run, so no findings is not an all-clear.
  • hiddenCount counts hidden findings that would otherwise match, so it can be lower than the page's.

Example arguments

{ "deadline": "90" }

get_commitments

Permission: View Costs

Reservations and savings plans as the Commitments dashboard shows them.

Arguments

get_commitments arguments
NameRequiredFormat / valuesDefaultNotes
commitmentTypenoreservation, savingsPlanboth
subscriptionIdnoGUIDCommitments applied to it, or consuming it when the commitment has no applied subscriptions
utilizationWindowno1, 7, 30 (strings)30Days; 1 and 7 exist only in partial or enhanced data tier
maxUtilizationPercentnonumber 0-100At or below this; unknown utilization never matches
expiringWithinDaysnointeger 1-1900Expiring in 0 to N days; base-tier rows never match
includeExpirednobooleanfalseInclude expired and cancelled
sortBynoutilization (ascending, unknown last), expiry (soonest first, unknown last), monthlyCost (highest first), wastage (highest first), nameutilizationTies by name, then commitment ID
limit, offsetnopaging50, 0

Output

get_commitments output fields
FieldMeaning
dataTierbase, partial or enhanced
partialTierMissingSidePartial tier: reservations or savingsPlans (the side without detail), else null
utilizationAvailablefalse in base tier
utilizationWindow, currency, lastUpdatedScanId, lastUpdatedAtContext
totals{ reservations, savingsPlans, monthlyCost, monthlyWastage, overallUtilizationPercent (one decimal, or null), unknownUtilizationCount, unknownCostCount } over every match
nearestExpiry{ name, expiryDate, daysUntilExpiry } of the soonest active expiry among the matches (no window cap), or null (always null in base tier)
items, paging fields, linkRows below; link opens the dashboard with the same filters

Each item: commitmentId, name, commitmentType, sku, reservedResourceType, meterCategory, quantity, commitmentAmountPerHour, location, instanceFlexibility, term, billingPlan, scope, appliedScopes, subscriptions [{ id, name }], billingScopeId, benefitStartDate, expiryDate, daysUntilExpiry (negative only with includeExpired), provisioningState, active, utilizationPercent (selected window), utilization { day1, day7, day30 }, utilizationTrend (UP, DOWN, STEADY), monthlyCost, monthlyWastage, currency, link. Any absent optional field is null.

Notes

  • Base tier is inventory and spend only: no SKU, term, scope, expiry, utilization or wastage. An empty underutilized or expiring result in base tier is not an all-clear; the Permissions & Data Tier drawer on the Commitments page explains how to get more.
  • Links open the dashboard filtered, not a selected row.
  • Commitment charges over time belong to get_cost_summary.

Example arguments

{ "maxUtilizationPercent": 80, "sortBy": "wastage" }

get_commitment_recommendations

Permission: View Costs

Commitment coverage recommendations as the Commitment Coverage page shows them, largest monthly impact first.

Arguments

get_commitment_recommendations arguments
NameRequiredFormat / valuesDefaultNotes
subTypesnoarray of purchase, underutilized, expiringall
subscriptionIdnoGUID, tenant-wide or shared-scopeA GUID also matches alerts whose commitment applies to or consumes that subscription
includeHiddennobooleanfalse
includeResolvednobooleanfalseAdds resolved
limit, offsetnopaging50, 0

Output

get_commitment_recommendations output fields
FieldMeaning
dataTier, currency, lastUpdatedScanId, lastUpdatedAtContext
currentSettings{ utilizationThresholdPercent, utilizationEvaluationWindowDays, expiryWarningDays, recommendationLookbackDays }: today's scanner settings (defaults 85, 30, 90, 30), not necessarily what the last scan used
totals{ purchase { count, estimatedSavingsPerMonth }, underutilized { count, estimatedWastagePerMonth }, expiring { count, monthlyCostAtRisk } } over every match
hiddenCountHidden recommendations that would otherwise match
items, paging fields, linkRows below
resolvednull unless includeResolved: { totalCount, totalMonthlySavings, truncated, singleScopeOnly: true, items }, items newest first, at most 200: { recommendationType, resolutionType, commitmentName, subscriptionId, subscriptionName, estimatedMonthlySavings, currency, originalMonthlyCost, resolvedAt, resolvedByScanId }

Each item

get_commitment_recommendations item fields
FieldMeaning
recommendationId, subTypeID and purchase / underutilized / expiring
scopeBucketsubscription, tenant-wide (Shared-scope purchase recommendations), shared-scope (alerts on commitments shared across subscriptions) or unknown
subscriptionId, subscriptionNameThe bucket's subscription (or the bucket ID)
subscriptionIds, scopeSubscriptions and scope of the commitment, or null
hiddenHidden by an admin
impact{ amount, kind }, kind savings (purchase), wastage (underutilized) or at-risk (expiring)
currencyCurrency
purchasePurchase rows: { benefitType, armSkuName, recommendedQuantity, recommendedCommitmentAmountPerHour, term, lookBackPeriodDays, location, reservedResourceType, estimatedSavingsPerMonth, savingsPercentage, coveragePercentage, estimatedOnDemandCost }; else null
alertUnderutilized and expiring rows: { commitmentId, commitmentName, commitmentType, currentMonthlyCost, currentUtilizationPercent, utilizationThresholdPercent, evaluationWindowDays, estimatedWastagePerMonth, expiryDate, daysUntilExpiry }; else null
linkCommitment Coverage page with the row's sub-type and subscription

Notes

  • Purchase recommendations exist in every data tier; underutilized and expiring alerts only in partial or enhanced tier, so none in base tier is not an all-clear.
  • resolved ignores subTypes, subscriptionId and includeHidden, as the page's Show Resolved view does, and only ever holds single-subscription commitments. Its resolutionType is commitment_utilization_improved or commitment_renewed.
  • Expiring ties sort by fewest days left.
  • For a GUID filter the link shows only that subscription's bucket, so it can omit shared-scope alerts the tool matched.

Example arguments

{ "subTypes": ["underutilized", "expiring"], "includeResolved": true }

See also

Scripts that need the same data without an AI assistant can use the External API.

Was this page helpful?