
PLAYBOOK
Building an Enterprise Agent Inventory
The five build steps are NIST's CM-8 read for a new asset class, plus the three API calls that actually find agents and the one inventory criterion agents break.
TL;DR
Building an agent inventory is reconciliation work, and the control that describes it predates agents entirely. NIST SP 800-53 CM-8 already asks for an inventory that "accurately reflects the system", includes every component, avoids "duplicate accounting", and sits at whatever granularity you need. CM-8(4) asks for the owner by name. CM-8(3) asks for automated detection of things nobody authorized.
Read that way, the five steps below are not a methodology. They are CM-8 applied to an asset class that ships its own credentials.
The common view is that this is a tooling problem. It is mostly a query problem, and three calls do most of
the work: GET /oauth2PermissionGrants in Microsoft Graph, GET /admin/directory/v1/users/{userKey}/tokens
in Google Workspace, and the Recommender API's service-account insights, which flag accounts that "haven't
authenticated in the past 90 days".
One criterion agents genuinely break, and it is the first one. A record cannot accurately reflect what an agent can do, because under MCP a server's tool set "MAY vary by the authorization presented on the request". Capability is evaluated per call, so the inventory stores a claim about capability rather than capability itself.
Start with the grants. Normalize thin, name an owner, record verbs rather than connections, and tag lifecycle state at discovery time so nothing arrives untagged.
Overview
An inventory only earns its keep once it is built, and building one is less about tooling than about discipline: pulling signal out of places never designed to report to a central system, in a way that survives contact with a live enterprise.
Agents do not live in one tidy directory. A data team stands one up inside a notebook platform. A marketing team authorizes a third-party agent through an OAuth grant nobody else sees. A platform team deploys one into a Kubernetes cluster as a service account. They span AI platforms, SaaS tools, automation systems, cloud environments, code repositories and developer laptops, and most were never announced to anyone responsible for tracking such things.
What an inventory is, and how it differs from a registry or a CMDB, is covered in what is an agent inventory and agent inventory vs. CMDB. This post is the build: five steps, the queries behind each, and the harder problem of keeping the record current once the first pass is done.
The goal: a record you would trust under pressure. Automated discovery and human review, run together on a schedule, are what get you there. Neither alone is enough.
What the Controls Require
Before designing a schema, it is worth knowing that the requirements already exist and are unusually specific.
NIST SP 800-53 Revision 5, control CM-8, System Component Inventory, asks for an inventory that "accurately reflects the system", "includes all components within the system", "does not include duplicate accounting of components or components assigned to any other system", and "is at the level of granularity deemed necessary for tracking and reporting". It then asks you to "review and update the system component inventory" at a frequency you define.
Three of its enhancements map directly onto the steps below. CM-8(3), Automated Unauthorized Component Detection, asks you to "detect the presence of unauthorized hardware, software, and firmware components within the system using organization-defined automated mechanisms" and then to disable network access, isolate the component, or notify named people. That is discovery, with teeth. CM-8(4), Accountability Information, asks you to include "a means for identifying by name, position, role, individuals responsible and accountable for administering those components". That is ownership, and it is a control requirement, not a nice-to-have. CM-8(2), Automated Maintenance, is the keeping-it-current problem.
On the AI-specific side, the NIST AI Risk Management Framework puts it in one sentence at GOVERN 1.6: "Mechanisms are in place to inventory AI systems and are resourced according to organizational risk priorities." The second half of that sentence is the part most programs skip.
One CM-8 criterion is genuinely hard to satisfy for agents, and it is the first one. Under the Model Context Protocol, a server's advertised tool set "MUST NOT vary per-connection or as a side effect of other requests on the connection", but it "MAY vary by the authorization presented on the request ... since credentials are per-request input, not connection state". An agent's real capability surface is therefore a function evaluated at call time. Whatever your inventory stores is a claim about capability, dated, and worth re-deriving rather than trusting.
Step 1: Discovery
You cannot inventory what you cannot see, and no single signal is complete. Pull from several sources at once and treat each as a partial view.
- OAuth grants: authorizations issued to third-party agents through your identity provider, usually the fastest way to surface SaaS-embedded and external agents.
- API usage: traffic and key-usage patterns that indicate an automated, non-human caller.
- Service accounts: non-human identities in cloud and directory systems that an agent uses to act,
often shared by several agents (
aact:identity-model/shared-service-account). - SaaS integrations: connected apps inside your CRM, HRIS or ticketing system.
- Network activity: egress to model providers or tool endpoints that hints at an agent somewhere unexpected.
- Code repositories: agent frameworks, prompts and tool definitions checked into source control.
- Cloud deployments: functions, containers and jobs running agent workloads.
- Self-registration: a submission workflow where teams declare agents they are building or adopting.
Take a procurement team that authorizes a vendor-supplied agent to read purchase orders and draft supplier emails. To finance it looks like a helpful add-on. From a discovery standpoint it appears as an OAuth grant against the procurement SaaS, an outbound integration to a mail API, and, if nobody asked, nothing in any official record. Three signals, one agent, no entry. Discovery is connecting those before an incident does it for you.
The Queries That Actually Find Agents
Discovery reads better as a list of endpoints than as a list of categories. Three calls do most of the work on day one, and all three are read-only.
GET https://graph.microsoft.com/v1.0/oauth2PermissionGrantsMicrosoft Graph returns delegated permission grants: every client application allowed to "access APIs on
behalf of signed-in users". Least-privileged permission is Directory.Read.All. Two fields decide how
worried to be. consentType is either Principal, meaning one user consented for themselves, or
AllPrincipals, meaning somebody consented on behalf of the entire tenant. And scope is a single
space-delimited string, which is where the risk hides: the example in Microsoft's own reference shows one
AllPrincipals grant carrying Mail.ReadWrite, Files.ReadWrite.All, Directory.ReadWrite.All,
Group.ReadWrite.All, Sites.ReadWrite.All and DeviceManagementManagedDevices.PrivilegedOperations.All,
among about thirty others, in one value. One row in your inventory, thirty-four scopes.
One trap worth knowing before you build a sync on it: Microsoft notes the call "might have replication delays
for delegated permission grants that were recently created, updated, or deleted", and that the delay "will be
minimized if a filter on clientId is specified". A newly authorized agent can be missing from an unfiltered
list.
GET https://admin.googleapis.com/admin/directory/v1/users/{userKey}/tokensThe Google Workspace equivalent "returns tokens that a specified user has issued to third-party
applications", and needs the admin.directory.user.security scope. Each Token resource carries clientId,
displayText ("the displayable name of the application the token is issued to"), scopes[], userKey, plus
two booleans that are better triage signals than they look: anonymous, true when "the application has an
anonymous Client ID", and nativeApp, true when the application "is installed to a desktop or mobile
device". An anonymous client ID with write scopes is the first row to look at.
It is a per-user call, so a first pass means iterating your directory. The audit-log route is the other half of the same picture: Workspace keeps its OAuth Token audit log for six months, and that log lags by "a couple of hours" while Admin, Login and Drive events are near real time. The log that finds new third-party agents is the slowest one you have.
gcloud recommender insights list \
--insight-type=google.iam.serviceAccount.Insight \
--project=PROJECT_ID --location=globalGoogle Cloud's service-account insights report "which service accounts in your project haven't authenticated in the past 90 days". That is your staleness signal, delivered rather than computed. Read the caveat before acting on it: API keys bound to service accounts, and authentication against a Google API outside Google Cloud, may not be tracked, so an account flagged unused can be in use. Cross-reference before deleting anything.
Normalize into one schema Recommender service-account insights ------+ Repos, cloud jobs, self-registration ------/ -> One record per agent: owner, verbs, lifecycle state -> and back to the sources, because grants change and MCP tool sets vary by the authorization presented on each call -->
Figure 1 — Four feeds, one record, and a loop back to the sources because the answer expires.
Step 2: Normalization
Discovery produces a messy pile of signals from systems that all describe agents differently. Normalization collapses that into one schema, so an agent found in a code repo and one found through an OAuth grant end up described the same way. Skip this and the inventory is a list of links you cannot query. It is also the CM-8 clause about avoiding "duplicate accounting": the same agent arriving from three feeds has to resolve to one row.
At minimum, every record carries the same core fields:
{
"name": "supplier-comms-assistant",
"owner": "procurement-ops",
"technical_owner": "platform-team",
"purpose": "Draft supplier emails from open purchase orders",
"connected_systems": ["coupa", "outlook-graph"],
"permissions": ["po:read", "mail:send"],
"consent_type": "Principal",
"credentials": ["svc-procure-agent"],
"discovered_via": ["graph:oauth2PermissionGrants", "repo:scan"],
"lifecycle_state": "production",
"last_authenticated": "2026-06-11T09:14:00Z",
"risk_classification": "medium"
}The exact shape matters less than the consistency. Once a recruiting-screener in the HRIS and a
revenue-forecast job in the warehouse map to the same fields, you can ask portfolio questions: which agents
can send external email, which touch regulated data, which have no owner.
Before inventing the shape, look at what already exists, because a maintained schema buys you tooling you did not write.
| Option | What it is good for | What it costs |
|---|---|---|
| Your own schema | fits your risk questions exactly, ships this quarter | nothing else reads it; you maintain it forever |
| CycloneDX | version 1.7, released 21 October 2025, standardised as ECMA-424 on 10 December 2025; can represent "software, hardware devices, machine learning models, source code, and configurations" | designed around supply chain and provenance, so runtime permissions need extension |
| A2A Agent Card | the protocol's own self-description at spec version 1.0.0: name, description, url, version, capabilities, skills, securitySchemes, provider | only covers agents that publish one, and it is the agent's own claim about itself |
Table 1 — Three places to get a schema. The realistic answer for most teams is a thin internal record that can export to the other two.
Step 3: Ownership
Ownership is the field people skip and regret skipping, and it is the one CM-8(4) spells out: include "a means for identifying by name, position, role, individuals responsible and accountable for administering those components".
Every agent needs a business owner, accountable for why it exists and whether it should keep existing. Many also need a technical owner who understands how it runs and can change or stop it.
Without ownership, basic questions have no answer. When a legal-intake agent starts mis-routing privileged documents, who reviews its access? When a marketing agent keeps emailing a suppressed segment, who pauses it? When the engineer who built a data-pipeline agent leaves, who inherits it? An ownerless agent does not get safer with time. It becomes an orphaned access path nobody watches.
A useful rule: an agent with no business owner should not be in production. Discovery can find that agent. Only a named owner can decide what happens to it next.
Step 4: Permissions at a Useful Level of Detail
Record permissions at a resolution that supports risk decisions. Noting that an agent is connected to the
CRM or connected to the data lake is not enough. Connection is binary. Risk lives in the verbs. Those
scopes are fixed at issue and not re-checked per call, the taxonomy's aact:authorization-model/scope-at-grant.
- read and export: can it pull data out, or remove it entirely?
- create, update, delete: can it change records?
- send and share: can it reach the outside world or other people?
- approve: can it complete something that normally requires a human's sign-off?
The Graph example above is the argument for this, in one field. A single grant whose scope string contains
Mail.ReadWrite alongside Directory.ReadWrite.All is not one fact, it is two very different ones, and an
inventory that records "connected to Microsoft 365" has thrown both away. A sales-ops agent with read on the
CRM is a reporting convenience; the same agent with export and send can walk a customer list out of the
door.
Record consentType next to the scopes. A Principal grant is one person's data. An AllPrincipals grant is
the tenant, and the difference does not show up anywhere in the scope list itself.
Step 5: Lifecycle State
Lifecycle state is the field that stops a prototype from silently becoming a production system. Tag every agent with where it sits:
- experimental: early exploration, not connected to anything sensitive.
- pilot: running with a limited scope and audience.
- approved: reviewed and cleared, not yet broadly live.
- production: operating with real access and real consequences.
- deprecated: on its way out, scheduled for removal.
- decommissioned: retired, credentials revoked, access removed.
The common failure is a quiet promotion that never happened on paper. A finance team builds an
experimental agent to reconcile a handful of invoices. It works. Six months later it reconciles thousands a
day with write access to the ledger, still tagged experimental, never reviewed. Lifecycle state, kept
honest, forces that promotion to be a decision instead of an accident.
Pair the state with a dated fact rather than a feeling. last_authenticated from a service-account insight,
or the timestamp of the newest grant, is what makes deprecated checkable. And for decommissioned, record
which of two things happened: the credential was deleted from your side, or the grant was revoked at the
provider. Those are different acts with different blast radii, and conflating them is how a retired agent
keeps working.
Figure 2 — The five build steps, feeding back into discovery as agents drift, change owners and gain access.
Keeping It Live at Scale
A handful of agents, one person can hold in their head. That stops being true somewhere past a few dozen, and the failure mode changes with it. Below that line, a slightly stale inventory is an inconvenience. Above it, a stale inventory is dangerous, because people start trusting it and it is wrong.
Volume also breaks the naive version of every step above. Discovery signals collide: the same agent shows up under three names because three teams registered it separately, which is exactly the duplicate accounting CM-8 prohibits, and somebody has to reconcile them. Schemas that were fine for fifty agents drift at five hundred once enough people fill them in by hand. Review cadences that worked for a curated pilot group become a backlog nobody clears.
The fix is the two forces CM-8 already names, applied continuously rather than once.
- Automated signals rediscover agents and flag drift: a new OAuth scope, a service account that gained a permission, an account that has not authenticated in 90 days. This is CM-8(3), and note that the control does not stop at detection. It asks you to disable access, isolate, or notify named people.
- Human review supplies the context automation cannot infer: why an agent exists, whether a new permission was intended, and whether it should still operate at all.
Automation without review produces a haystack of unexplained findings nobody triages. Review without automation produces a confident-looking document that quietly rots. We think the combination is the only version that survives past a hundred agents.
In Practice
Most teams do not need to perfect all five steps before getting value. A pragmatic sequence beats a big-bang rollout.
Start with the highest-signal source, which for most enterprises is OAuth grants in the identity provider.
One authenticated GET surfaces third-party and SaaS-embedded agents with no instrumentation at all.
Normalize early even if the schema is thin, because a small consistent record beats a rich inconsistent one.
You can add fields later. You cannot retrofit consistency cheaply once five teams have filled in a form five
different ways.
Backfill ownership before permissions. An owner can describe an agent's permissions later; a permission map cannot tell you who to call. Set lifecycle state at discovery time, tagging every newly found agent immediately even if the tag is "unreviewed", because untagged agents are the ones that drift.
The first pass will be uncomfortable. Expect agents nobody remembers authorizing, agents with permissions far
broader than their stated purpose, and at least one AllPrincipals grant somebody clicked through in 2024.
We would treat that discomfort as the inventory doing its job.
Frequently Asked Questions
How do I find all the AI agents in my organization? Start with delegated OAuth grants:
GET /oauth2PermissionGrants in Microsoft Graph and GET /admin/directory/v1/users/{userKey}/tokens in
Google Workspace. Add service-account inventories, repository scans for agent frameworks and tool
definitions, and a self-registration route. No single source is complete, which is why CM-8 asks for
automated detection rather than a form.
What fields does an agent inventory need? Name, business owner, technical owner, purpose, connected systems, permissions at verb level, consent type, credentials, lifecycle state, risk classification, and the date of the last observed activity. CM-8 requires owner information explicitly; the rest is what makes the record answer questions.
Should we use a BOM format instead of our own schema? Consider it. CycloneDX reached version 1.7 on 21 October 2025 and was standardised as ECMA-424 on 10 December 2025, and it can represent machine learning models and configurations alongside software. It is built around supply chain and provenance rather than runtime permissions, so expect to extend it. A thin internal record that can export to CycloneDX is a reasonable middle.
How often should the inventory be reviewed? CM-8 leaves the frequency to you, which is a hint that it should be tied to a signal rather than a calendar. Two usable triggers: any new or changed OAuth grant, and the 90-day no-authentication threshold Google Cloud already reports for service accounts.
Can the inventory record what an agent is allowed to do? It can record what it was granted, as of a date. It cannot record capability as a fact, because under MCP a tool set "MAY vary by the authorization presented on the request". Treat the permissions field as a dated claim and re-derive it, rather than treating it as authoritative.
Why does an agent appear three times? Because three feeds found it and nothing reconciled them. CM-8 is explicit that an inventory must not include "duplicate accounting of components", so pick a join key early, a client ID or a service-account identity, and record which feed each row came from so a human can merge them.
Is an inventory the same thing as a registry? No. An inventory records everything that exists, including what nobody approved. A registry records what was declared and approved. You need both, and they disagree in the interesting cases.
What does the EU AI Act require here? Not an agent inventory by that name. The obligations that press on this are record-keeping and deployer duties for high-risk systems, which start 2 December 2027 for Annex III systems and 2 August 2028 for Annex I. A current inventory is how you find out which of your agents those apply to.
Conclusion
None of the five steps is hard on its own. Discovery is three API calls and a repo scan, normalization is a schema, ownership is a name in a field. What is hard is doing all five at once, and keeping the record honest after nobody is looking.
It helps to notice that the requirement is old. CM-8 wanted an inventory that accurately reflects the system, carries the accountable person's name, and gets reviewed on a schedule, long before anything called an agent existed. What agents add is a capability surface that is computed per call rather than stored, which means the inventory's job is not to be right forever. It is to be dated, reconciled, and refreshed from the sources that actually know.
You don't build an agent inventory to file it away. You build it because it is the one record every other part of agent operations quietly depends on, and the moment you stop maintaining it, so does everything built on top.
Sources
All URLs read 2026-09-29.
- Agent Access Control Taxonomy — the nine dimensions an inventory record has to capture;
aact:identity-modelfor what the agent is to the target system, andaact:authorization-modelfor whether a grant is re-checked per call. - NIST SP 800-53 Rev 5, CM-8 System Component Inventory — the four accuracy criteria, the prohibition on duplicate accounting, granularity left to the organization, and the review-and-update requirement.
- NIST SP 800-53 Rev 5, CM-8(3) Automated Unauthorized Component Detection — automated detection of unauthorized components, and the disable, isolate or notify response options.
- NIST SP 800-53 Rev 5, CM-8(4) Accountability Information — identifying by name, position or role the individuals responsible and accountable for administering components.
- NIST AI Risk Management Framework 1.0, Core — GOVERN 1.6 on inventory mechanisms resourced according to risk priorities, and MANAGE 4.1 on post-deployment monitoring and decommissioning.
- List oAuth2PermissionGrants, Microsoft Graph v1.0 — the endpoint,
Directory.Read.Allas least-privileged permission, theconsentTypeandscopefields, the exampleAllPrincipalsgrant carrying thirty-plus scopes, and the replication delay unless filtered onclientId. - Tokens: list, Google Workspace Admin SDK Directory API — tokens a user has issued to third-party applications, and the
admin.directory.user.securityscope. - Token resource, Google Workspace Admin SDK Directory API —
clientId,displayText,scopes[],userKey, and theanonymousandnativeAppbooleans. - Data retention and lag times, Google Workspace Admin — six-month retention on the OAuth Token audit log and its couple-of-hours lag against near-real-time Admin, Login and Drive events.
- Service account insights, Google Cloud — service accounts that have not authenticated in the past 90 days, delivery through the Recommender API, and the caveat that bound API keys and non-Google-Cloud activity may not be tracked.
- Model Context Protocol specification, 2026-07-28, Tools — the tool set must not vary per connection but may vary by the authorization presented, "credentials are per-request input, not connection state", and the tool definition fields.
- CycloneDX specification overview — version 1.7 released 21 October 2025, standardised as ECMA-424 on 10 December 2025, covering software, hardware, machine learning models, source code and configurations.
- A2A Protocol specification — spec version 1.0.0, and the Agent Card as "a JSON metadata document published by an A2A Server, describing its identity, capabilities, skills, service endpoint, and authentication requirements".
- EU AI Act Article 26: Obligations of deployers — deployer duties for high-risk AI systems, including the requirement to keep automatically generated logs for at least six months.
- EU AI Act Article 12: Record-keeping — automatic event recording over the system's lifetime, with high-risk obligations applying from 2 December 2027 for Annex III and 2 August 2028 for Annex I.