Skip to content

Agent Identities

An agent identity is a non-human principal owned by exactly one team. Register one for an AI agent or an automation that runs without a person signed in, such as a scheduled job or a team assistant. The agent authenticates with its own credentials, carries its own permissions, and is the consumer of its own access agreements.

Agents and people

An agent identity is not a user. It can't sign in to the web UI, takes no seat, and is no member of any team. Its owning team is accountable for it.

An AI client that works for a signed-in person, such as Claude, Copilot, or ChatGPT connected through MCP OAuth or a personal API key, keeps that person's identity and needs no agent identity. Entropy Data records the AI client next to the person. An access agreement requested through MCP OAuth shows, for example, Requested by: juliet@example.com via AI client, and its audit trail names the client: Juliet Peers via Claude.

Register an agent identity when the agent runs on its own, so that its access belongs to the agent and does not depend on any one person.

Register an agent

Open the team page in Studio and choose Add Agent in the Agents section.

FieldDescription
NameThe display name of the agent.
IDUnique in the organization. Used in the API and in the audit log as agent:<id>. It can't be changed later.
DescriptionOptional. What the agent is.
PurposeRequired. What the agent does with data. It pre-fills access requests for the agent and, with AI features enabled, is checked against the terms of use of data contracts.
Linked identitiesOptional. The same agent in other systems, each as a type and an identifier. Provisioning uses them to grant access in the data platform, and tokens from your identity provider are matched against them.
PermissionsWhat the agent may change, see Permissions.

The web UI offers these linked identity types. Through the API you can also use a type of your own.

TypeAPI value
Microsoft Entra Agent IDentra-agent-id
Oktaokta
Snowflake usersnowflake-user
Databricks service principaldatabricks-service-principal
Google Cloud service accountgcp-service-account
AWS IAM roleaws-iam-role
SPIFFE IDspiffe-id
Otherother

Members who hold TEAM_API_KEY_MANAGE on the owning team register and edit its agents, manage their credentials, and set their permissions. Organization owners can do the same for any team. Through the API, any API key that carries TEAM_API_KEY_MANAGE for the owning team can, such as an organization API key or a key of that team. Either way, you can only grant permissions you hold on that team yourself. When editing an agent, you can keep permissions someone else granted it, but not add ones you don't hold.

Through the API

PUT /api/agent-identities/{id} registers or updates an agent and replaces the whole record, so a field you leave out, such as description or linkedIdentities, is cleared. owner is the id of the owning team. If you omit permissions, the agent gets ACCESS_REQUEST alone, on update as well as on create. Pass an empty list for a read-only agent. status is active or disabled.

PUT
/api/agent-identities/:id
curl --request PUT https://api.entropy-data.com/api/agent-identities/churn-risk-scorer \
--header "x-api-key: $ENTROPY_DATA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
  "id": "churn-risk-scorer",
  "name": "Churn Risk Scorer",
  "owner": "sales-team",
  "description": "Scores active customers for churn risk every night.",
  "purpose": "Predict churn risk for active B2B customers so account managers can prioritize retention calls.",
  "permissions": ["ACCESS_REQUEST"],
  "linkedIdentities": [
    { "type": "snowflake-user", "id": "SVC_CHURN_SCORER" }
  ]
}'

Changing owner moves the agent to another team, which takes TEAM_API_KEY_MANAGE on both teams. GET /api/agent-identities lists the agents of the teams your key can read, and ?owner=<team id> narrows the list to one team.

Permissions

An agent's permissions come from the same team permission catalog as an API key's. They apply to the owning team and its subteams.

  • ACCESS_REQUEST is preselected, so a new agent can request access for itself and change nothing else.
  • Read only is an empty list. The agent reads what it can see and changes nothing. It can still query data it has access to.
  • All gives the agent every permission you can grant in this team, as they are when you save. Later changes to your own role don't carry over. Restricted picks permissions one by one, from those you hold on the team.
  • These permissions are never available to agents: TEAM_ADD, TEAM_EDIT, TEAM_DELETE, TEAM_API_KEY_MANAGE, TEAM_MEMBER_ADD, TEAM_MEMBER_EDIT, TEAM_MEMBER_DELETE, and ORGANIZATION_ADMIN. An agent can't create credentials, change its team, or change who is accountable for it.
  • ACCESS_APPROVE and ACCESS_ADD never apply to the agent's own agreements.

These rules hold whatever permissions the agent carries:

  • An agent requests access only for itself.
  • An agent never approves, adds, or extends an agreement in which it is the consumer.
  • An agent never changes its own identity, keys, or permissions.

Permissions decide what the agent may change. Which data it may query is decided by its access agreements.

The agent page

Select an agent in the team's Agents section to open its page:

  • Info: the purpose, description, linked identities, and who registered the agent and when. The ID is shown under the agent's name, next to the owning team, which answers for the agent, and the agent's status.
  • Access: the agreements in which the agent is the consumer.
  • API Keys and OAuth Clients: the agent's credentials.
  • Data Platform Connections: the datasource connections the agent queries data with.
  • Permissions: what the agent may change on its owning team and subteams.
  • How to connect: the MCP and token endpoints, with guides for common agent frameworks.
  • Activity: what the agent did through MCP and the API. See Activity.
  • Audit Trail: what people changed on the agent: its registration, changes, permission changes, disabling and enabling, API keys, OAuth clients, and connections created and deleted, and access requested on the agent's behalf.

Activity

The activity records, newest first:

  • every MCP tool call the agent makes, with its arguments
  • every API request the agent makes, including requests to endpoints that aren't open to agents
  • the access requests the agent makes itself
  • every access decision on the agent's queries, allowed or denied, including dry runs

Failed calls are marked Failed, with the error or the HTTP status. An access decision or access request made during a tool call or an API request appears as that call's entry, with the tool and its arguments or the request and its query parameters. If the call fails, it also gets an entry of its own, marked Failed. A decision that another caller asks for about the agent, for example through the access evaluation API, names that caller.

Each agent keeps its newest 10,000 entries from the last 30 days. Older entries are deleted when the agent's next entry is recorded. Show older loads earlier entries.

Select an entry to open its page: the tool and its arguments (long values shortened), or the API request and its query parameters, the outcome and duration, the API key or OAuth client and the client that made the call, and the other calls of the same session.

Sessions

An entry's Session groups the calls of one run of the agent. Select it to show only that session's calls. Clients send different identifiers, so Entropy Data takes the first one a call carries. API requests use only the X-Agent-Session-Id and traceparent headers.

SourceSent by
X-Agent-Session-Id headerYour agent, with an ID of your choice, such as its own run or conversation ID.
OpenAI conversationChatGPT, as _meta["openai/session"].
Session of the clientClients such as Codex, as _meta.sessionId.
Trace ID of the clientClients that send W3C trace context, in _meta.traceparent or the traceparent header.
MCP sessionAny MCP client. Some clients open one per tool call, others keep one for as long as they run.

To group an agent's calls reliably, send X-Agent-Session-Id with every MCP and API request of a run:

OpenAI Agents SDK

import os
import uuid

from agents.mcp import MCPServerStreamableHttp


async def main() -> None:
    async with MCPServerStreamableHttp(
        name="Entropy Data",
        params={
            "url": "https://app.entropy-data.com/mcp",
            "headers": {
                "Authorization": f"Bearer {os.environ['ENTROPY_DATA_AGENT_KEY']}",
                "X-Agent-Session-Id": str(uuid.uuid4()),
            },
        },
    ) as server:
        ...  # pass the server to your agent, e.g. Agent(mcp_servers=[server])

Disable or delete an agent

  • Disable stops the agent at once: its API keys and access tokens no longer work. Its agreements stay as they are. Enable turns it back on.
  • Delete revokes the agent's API keys and OAuth clients, removes its connections, activity, and audit trail, withdraws the access it has requested, and ends the access it has been granted, after the data contract's notice period if it has one. Providers are notified as for any ended agreement.

A team that owns agents can't be deleted. Delete its agents first, or move them to another team by changing owner through the API.

Credentials

An agent authenticates with an API key, with OAuth client credentials, or with a token from your identity provider. Each of them acts as the agent, with the agent's permissions.

API keys

Create a key on the agent page under API Keys, or with POST /api/agent-identities/{id}/api-keys. An expiration date is required.

POST
/api/agent-identities/:id/api-keys
curl https://api.entropy-data.com/api/agent-identities/churn-risk-scorer/api-keys \
--header "x-api-key: $ENTROPY_DATA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
  "displayName": "nightly-run",
  "expiresAt": "2027-10-01T00:00:00Z"
}'

The key starts with ed_<environment>_agent_, for example ed_live_agent_. It is shown once, in the response that creates it, and Entropy Data stores only a hash. Send it in the x-api-key header, or as Authorization: Bearer, to /api and to /mcp. MCP clients configure it like any other API key.

A key carries the agent's permissions and has none of its own, so a change to the agent's permissions applies to all of its keys. DELETE /api/agent-identities/{id}/api-keys/{keyId} deletes a key, and it stops working at once.

Select a key on the agent page to open its page: who created it, when it expires and was last used, and the agent's activity with that key.

OAuth client credentials

For an agent that uses the OAuth 2.0 client credentials grant, create an OAuth client on the agent page under OAuth Clients, or with POST /api/agent-identities/{id}/oauth-clients. The response returns clientId and clientSecret. The secret is shown only once.

POST
/api/agent-identities/:id/oauth-clients
curl https://api.entropy-data.com/api/agent-identities/churn-risk-scorer/oauth-clients \
--header "x-api-key: $ENTROPY_DATA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
  "displayName": "scheduler"
}'

The agent exchanges them for an access token at the token endpoint, with HTTP Basic client authentication. The token is valid for one hour. On self-hosted installations, use your own host.

POST
/oauth2/token
curl https://app.entropy-data.com/oauth2/token \
--user "$CLIENT_ID:$CLIENT_SECRET" \
--data "grant_type=client_credentials"

Send the access token as Authorization: Bearer to /mcp or /api. DELETE /api/agent-identities/{id}/oauth-clients/{clientId} deletes a client, and the tokens it already holds stop working at once.

Select a client on the agent page to open its page with the agent's activity with that client's tokens.

Tokens from your identity provider

An agent that has an identity in your identity provider, such as a Microsoft Entra Agent ID, can authenticate with the access tokens that provider issues to it. An organization owner registers the provider as a trusted issuer, with an API key that carries ORGANIZATION_ADMIN:

PUT
/api/agent-token-issuers/:id
curl --request PUT https://api.entropy-data.com/api/agent-token-issuers/entra \
--header "x-api-key: $ENTROPY_DATA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
  "id": "entra",
  "issuer": "https://login.microsoftonline.com/<tenant-id>/v2.0",
  "audience": "api://entropy-data",
  "claim": "oid",
  "linkedIdentityType": "entra-agent-id"
}'
FieldDescription
issuerThe token's iss claim.
jwksUriOptional. The location of the issuer's signing keys. If omitted, they are discovered from the issuer's OpenID configuration.
audienceOptional, but recommended. The required aud claim. Tokens for other audiences are rejected. If omitted, the audience is not checked.
claimThe claim that identifies the agent, such as oid, azp, or sub. Defaults to sub.
linkedIdentityTypeThe linked identity type the claim value must match, such as entra-agent-id.

A Bearer token on /mcp or /api whose issuer and audience match is validated against the issuer's signing keys. The value of the configured claim is then matched against the organization's agents' linked identities of that type, and a match acts as that agent. A value that matches more than one agent is refused. For the example above, add a linked identity of type Microsoft Entra Agent ID with the agent's object ID to the agent.

GET /api/agent-token-issuers lists the trusted issuers. DELETE /api/agent-token-issuers/{id} removes one, and its tokens are no longer accepted.

Access

An agent holds only its own access agreements. It never inherits the access of its owning team or of the person who registered it.

Request access for an agent

On a data product's output port, choose Request Access and pick Agent as the consumer. Only the active agents of teams where you hold ACCESS_REQUEST are offered, and picking one fills an empty purpose with the agent's purpose. If the request is approved, only the agent gets access. The members of its team don't.

Organization owners can switch the Agent consumer type on or off, like the other consumer types, under Governance & Workflows → Access Management in the organization settings.

The provider approves as usual, see the Access Approval Workflow. The approval box names the agent and its team, for example Agent Churn Risk Scorer of team Sales requests access to data product Customer 360.

The agent requests access itself

An agent that carries ACCESS_REQUEST can request access for itself:

  • MCP: the request_access tool.
  • API: PUT /api/access/{id} with consumer set to {"agentId": "<agent id>"} or to {}.
PUT
/api/access/:id
curl --request PUT https://api.entropy-data.com/api/access/churn-scorer-customer-360 \
--header "x-api-key: $AGENT_API_KEY" \
--header "Content-Type: application/json" \
--data '{
  "id": "churn-scorer-customer-360",
  "info": {
    "purpose": "Predict churn risk for active B2B customers so account managers can prioritize retention calls."
  },
  "provider": {
    "dataProductId": "customer-360",
    "outputPortId": "snowflake"
  },
  "consumer": {
    "agentId": "churn-risk-scorer"
  }
}'

If the agent already has an open request or an approved agreement on that output port, no second request is filed. The MCP tool returns the existing agreement. The API answers 200 without creating the new id, so find the agreement with GET /api/access. A PUT to an id that already exists answers 403. A new request follows the usual approval: the data product owner is notified of the request, and the agent's owning team of the decision.

A self-request also needs the Agent consumer type and access requests to be enabled for the organization. Organizations that saved their consumer types before agents existed have Agent switched off until an owner turns it on.

In the API

An agent's agreements carry consumer.agentId. consumer.teamId and consumer.dataProductId are left out on purpose: a provisioning integration that doesn't know agents finds no principal and grants nothing, instead of granting the agent's whole team.

GET /api/access/{id}

{
  "id": "churn-scorer-customer-360",
  "info": {
    "purpose": "Predict churn risk for active B2B customers so account managers can prioritize retention calls.",
    "status": "approved",
    "active": true
  },
  "provider": {
    "teamId": "customer-team",
    "dataProductId": "customer-360",
    "outputPortId": "snowflake"
  },
  "consumer": {
    "agentId": "churn-risk-scorer"
  }
}

GET /api/access?consumerType=agent lists the agreements with agent consumers. To provision one, read the agent with GET /api/agent-identities/{agentId}, using a key that can read the agent's owning team, and grant to the platform principal named by its linked identity of your platform's type, for example gcp-service-account for BigQuery or snowflake-user for Snowflake.

Use data

An agent sees what a team API key of its owning team sees: public data products, and those its owning team and subteams own or are given visibility to. Through MCP it also sees data products it holds an active agreement on.

MCP tools

Connect the agent to the MCP server with one of its credentials. These tools are open to agents:

ToolFor an agent
searchFinds the data products the agent can see.
fetchShows a data product, with the agent's own access status on each output port.
request_accessRequests access for the agent itself.
execute_queryRuns a query on an output port the agent has access to, see Query data.
check_accessChecks whether a query would be allowed, without running it, see Check access.
semantics_*Read the organization's semantics. Saving and deleting need SEMANTIC_NAMESPACE_ADD, SEMANTIC_NAMESPACE_EDIT, or SEMANTIC_NAMESPACE_DELETE on the namespace's team.

The data product and data contract tools (dataproduct_save, dataproduct_schema, datacontract_get, datacontract_save, datacontract_schema, datacontract_test, datacontract_test_results) refuse agent sessions with This tool is not available to agents.

REST endpoints

These endpoints are open to agents:

  • GET /api/agent-identities and GET /api/agent-identities/{id}: the agent's own record.
  • GET /api/access and GET /api/access/{id}: the agent's own agreements.
  • PUT /api/access/{id}: an access request for the agent itself.
  • POST /api/access/evaluation: an evaluation of the agent's own access, see Access evaluation API.
  • GET /api/dataproducts and GET /api/dataproducts/{id}.
  • GET /api/datacontracts, GET /api/datacontracts/{id}, and GET /api/datacontracts/{id}/datacontract.yaml.
  • GET /api/teams and GET /api/teams/{id}.
  • POST /api/test-results: with DATACONTRACT_TEST_RESULTS_EDIT or DATAPRODUCT_TEST_RESULTS_EDIT, for the owning team and its subteams.

Every other endpoint answers 403 with This endpoint is not available to agents.

Query data

execute_query runs read-only queries, when the organization allows data access. It runs a query only on an output port where the agent has an active agreement, provisioned where your organization requires it. With AI features enabled, the agent's purpose and the purpose given for the query are also checked against the data contract's terms of use. The query uses the roles of the agent's own agreements.

The query runs with the agent's own datasource connection, so the data platform sees the agent's account. Register one on the agent page under Data Platform Connections, or with POST /api/agent-identities/{id}/connections. The credentials are stored encrypted and are never returned. Without a connection for the output port's platform, execute_query explains how to add one.

POST
/api/agent-identities/:id/connections
curl https://api.entropy-data.com/api/agent-identities/churn-risk-scorer/connections \
--header "x-api-key: $ENTROPY_DATA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
  "type": "snowflake",
  "name": "Churn scorer service user",
  "account": "acme-xy12345",
  "pat": "<programmatic access token>",
  "role": "CHURN_SCORER",
  "warehouse": "ANALYTICS_WH"
}'

Every connection has a type and a name, plus the fields of its type:

TypeFields
postgreshost, port, database, user, password
mysql, mariadb, mssqlhost, port, user, password
exasolhost, port, user, password, certificateFingerprint
trinoserverUrl, catalog, schema, username, password
databricksjdbcUrl, catalogPattern, personalAccessToken
snowflakeaccount, pat (a programmatic access token), role, warehouse

GET /api/agent-identities/{id}/connections lists the agent's connections, and DELETE /api/agent-identities/{id}/connections/{connectionId} removes one. Adding and removing connections takes TEAM_API_KEY_MANAGE on the agent's team.

Check access

The MCP tool check_access is a dry run of the same decision for a query on an output port. It takes dataProductId, outputPortId, and query, and runs nothing. The purpose that counts is the agreement's purpose plus the agent's purpose, never free text from the call.

Each dry run is logged in the agent's activity like a real decision. When an agent is denied five times within an hour, by dry runs or real queries, the owning team gets one email.

Access evaluation API

POST /api/access/evaluation answers the same question in the shape of OpenID AuthZEN. With subject.type set to agent, the request is evaluated against the agent's own agreements:

POST /api/access/evaluation

{
  "subject": { "type": "agent", "id": "churn-risk-scorer" },
  "resource": {
    "type": "dataproduct",
    "id": "customer-360",
    "properties": { "outputPortId": "snowflake" }
  },
  "action": {
    "name": "can_query",
    "properties": {
      "sql": "SELECT customer_id, churn_signals FROM customer_360.customers",
      "purpose": "Score churn risk for active B2B customers."
    }
  }
}

The response carries decision, and on a denial the reasons in context.reasons. An agent can only evaluate itself. An API key can evaluate the agents of the teams it can read.

See the Agent Identities endpoints in Swagger for the formal definitions.