Skip to content

Building an AI Agent That Retrieves Credentials Securely from the 12Port Vault

If you are building AI agents that need access to sensitive credentials, passwords, or API keys, you have two choices. You can store those credentials somewhere in the agent's configuration and accept the associated risk. Or you can retrieve them at runtime from a vault that enforces access control, maintains an audit trail, and supports approval workflows.

This guide focuses on the second option and walks through how to use 12Port's MCP integration to retrieve a credential securely from a PAM vault and hand it to an AI agent for downstream use.

The MCP integration covers four things: authenticating to 12Port, discovering available vault operations, finding the right asset, and retrieving its credential. What the agent does with that credential afterward is entirely up to you.


What Is MCP and Why Does It Matter?

MCP stands for Model Context Protocol. It is an open standard that defines a structured, consistent interface to interact with external services. A service that supports MCP publishes a JSON document describing everything an agent needs to interact with it: what operations are available, what parameters they accept, what they return, and how to authenticate.

12Port exposes this document at a well-known URL on your vault server:

https://<your-server>/ztna/<tenant>/.well-known/mcp-agent.json

That file is an OpenAPI 3.0 specification describing six operations covering asset search, credential retrieval, and a complete workflow approval cycle. An agent can read this document once and determine how to use the entire vault integration. No separate API documentation. No custom connector code. No vendor SDK required.


What the MCP Integration Does

To clarify scope, 12Port's MCP integration is a credential retrieval layer. It performs four functions:

Note

While our examples use Python, the same flow applies to any language capable of making HTTP requests.

1. Authenticates to 12Port using an API token

Every request to the vault is authenticated using a standard JWT bearer token. The agent configures this once on its HTTP session, and all subsequent requests are authorized automatically.

session = requests.Session()
session.headers.update({
    "Authorization": f"Bearer {jwt_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
})

2. Fetches and parses the MCP spec to discover available endpoints

The agent fetches the MCP spec (../.well-known/mcp-agent.json) and indexes every available operation by its operationId. This is the discovery step. After this, the agent knows exactly what the vault can do and how to call each operation.

spec = session.get(MCP_SERVICE_URL).json()

for path, methods in spec["paths"].items():
    for method, operation in methods.items():
        endpoints[operation["operationId"]] = {
            "method": method.upper(),
            "path": path,
            "parameters": operation.get("parameters", []),
        }

At startup, the agent prints a summary of every discovered endpoint. For example:

MCP Endpoint Discovery Example

3. Asks the user which vault asset holds the credential

Assets in 12Port are vault entries that store credentials and other sensitive data. The user provides either an asset name or an asset ID. The agent searches for it using the polySearch_1 endpoint with the structured query format documented in the spec:

Note

The examples below use a helper function mcp.call(...) to wrap HTTP requests to MCP endpoints.

results = mcp.call("polySearch_1", query_params={
    "q.1.f": asset_name,
    "ctp": 1,       # assets only, not containers
    "pgp": 0,
    "pgs": 25,
})

The agent performs client-side name matching, preferring exact matches and falling back to a single partial match when applicable.

4. Retrieves the credential, handling both direct access and workflow-protected access

Once the asset is found, the agent calls get-asset-credentials:

result = mcp.call("credentials_1", path_params={"id": asset_id})
credential = result.get("password")

The CredentialsInfo response contains three fields: user, password, and configuration. Secrets, API keys, and passwords are stored in the password field.

If the credential is directly accessible, this is all that happens. If it is protected by a workflow approval requirement, the agent handles the full approval cycle automatically, submitting an access request, polling for approval, and retrieving the credential once access is granted. This is covered in detail in the workflow section below.

At this point, the MCP integration has done its job. The agent has the credential. What it does next is entirely outside the scope of 12Port.


What the Agent Does With the Credential Is Up to You

This behavior is important to understand. Once the credential is retrieved from the vault, the agent can use it for anything. The MCP integration does not dictate or constrain what comes next.

In our example, we retrieved an OpenAI API key and used it to start an interactive chat session. But the same retrieval pattern applies to any credential stored in the vault:

  • A database password retrieved so the agent can connect to a production database and run queries
  • A service account password used to start or authenticate a support bot
  • An API key for a third-party service the agent needs to call
  • An SSH key or certificate used to access a remote system
  • Any other secret your organization stores in 12Port

The vault is credential-agnostic. The MCP integration retrieves whatever is stored in the asset's password field and hands it to the agent. The agent then uses it according to its intended purpose.

This separation is intentional and important. 12Port's responsibility ends at secure credential retrieval. Your agent's responsibility begins there.

Warning

12Port does not persist or track how credentials are used after retrieval; secure handling beyond retrieval is the responsibility of the agent.


The Workflow Approval Path

Some credentials in your vault are protected by workflow approval requirements. When an agent requests one of these, get-asset-credentials returns HTTP 500 with a specific message:

{"value": "TENANT:<tenantName>; MSG-00863: Action is restricted by workflow form"}

This is not a fatal error. It indicates that an access request must be submitted first. The agent handles this automatically.

Submit the request:

result = mcp.call("createAssetRequest",
    path_params={"asset-id": asset_id},
    body={
        "message": "Automated request by PAM MCP AI Agent",
        "requestedFrom": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
        "requestedTo": (datetime.now(timezone.utc) + timedelta(hours=1)).strftime("%Y-%m-%dT%H:%M:%SZ"),
    }
)
request_id = result["value"]

Discover the action type:

createAssetRequest does not return the workflow action type. The action type is asset-specific and determined by the vault's workflow form configuration. It may be AssetUnlock, AssetAccess, or any other value in the RequestAction enum. After submission, the agent probes all eight enum values by calling get-request-status/{action}?aid={asset_id} for each. The one that returns status=Active is the correct action type for this asset. The agent stores this value alongside the request ID and uses it for all subsequent status checks.

This step is required. Polling the wrong action type returns status=Open for all states, including after rejection, making it impossible to detect terminal conditions.

Poll for approval:

The agent polls get-request-status on the discovered action type. Each cycle produces one of four outcomes:

MCP Workflow Polling for Approval Example

The get-request-status response uses the following status values:

  • Open — access is available; call get-asset-credentials immediately to retrieve the credential
  • Active — request is in the approval queue; keep polling
  • Closed — no approved access exists; submit a new request via create-asset-request
  • Restricted — access is never permitted for this user or location; terminal
  • MFA — multi-factor authentication is required; terminal

get-asset-credentials is called exactly twice in the workflow path: once at the start to detect MSG-00863 and enter the workflow, and once when get-request-status returns Open to retrieve the credential. It is never called during the polling loop itself.

Tip

In practice, polling intervals of 15–60 seconds are typical. Timeout behavior should be aligned with your organization's approval SLAs.

Session state and restarts:

When a request is submitted and the action type is discovered, the agent immediately writes both values to a local file (.pending_request.json) along with the asset ID. If the agent is restarted while a request is pending, it reads this file on startup and resumes polling from the saved state rather than submitting a duplicate request.

Retrieve the credential:

Once get-asset-credentials returns HTTP 200, the credential is in the response. The MCP integration is complete.

The approval cycle can handle automatic workflows that resolve in seconds and multi-layer human approval processes that take days. The poll interval and timeout are configurable. If a request is rejected, the agent can resubmit automatically or prompt the user.


Closing the Request on Exit

When the agent session ends, if a workflow request was used, it is good practice to formally close it. This keeps the approval in an open state only for as long as it is needed and maintains a clean audit trail.

  [workflow] A workflow request was used during this session.
  Would you like to complete (close) the approved workflow request? (yes/no):

MCP Close Workflow Prompt Example

Completing the request calls complete-request, passing the request UUID — the id field returned by get-request-status when status=Active. Note that this is the workflow request UUID, not the asset ID; both are UUIDs and must not be confused. This call signals to 12Port that the agent is done with the approved access and clears the .pending_request.json file. This behaviour can also be configured to happen automatically on exit.


Build Considerations

Read the full spec before writing code. The MCP spec for 12Port is well-documented, but some of that documentation lives in the endpoint description field rather than in the parameter names. The search endpoint is a good example. The parameter is listed as f in the schema, but the description explains it only works in the structured q.1.f= format. Reading the full description before building the search function avoids a debugging cycle.

Use configuration to eliminate interactive prompts. Autonomous agents should not depend on user input during execution. Any value that can be known ahead of time, such as asset_name, asset_id, poll intervals, or whether to automatically complete workflow requests, should be defined in the .env file or equivalent configuration layer. The agent should only prompt for input if a required parameter is missing. This allows the same implementation to support both interactive testing and fully autonomous operation without code changes, and ensures predictable behavior in production environments.

The workflow status values require careful reading. Active means the request is in the approval queue, waiting for approval. Open during polling is the approval signal; when the agent sees Open after submitting a request, access has been granted and get-asset-credentials should be called immediately to retrieve the credential. Note that Open is also the default state before any request has ever been submitted, which is exactly why probing the wrong action type is dangerous: an incorrect action type always returns Open regardless of the actual request state, making it impossible to distinguish approval from rejection or a pre-request baseline.

Probe for the correct action type before polling. The vault's workflow form configuration determines which RequestAction enum value carries the request for a given asset. Do not assume or hardcode a value. After submitting a request, probe all enum values to find the one returning status=Active. Polling the wrong action type always returns Open, making rejection detection impossible.

Poll get-request-status exclusively during the approval wait. Call get-asset-credentials only twice in the entire workflow path: once at the start to detect MSG-00863 and enter the workflow, and once when get-request-status returns Open to retrieve the credential. Do not call get-asset-credentials while status is Active; it cannot succeed until access is granted and adds nothing the status endpoint is not already providing.

Session state survives process restarts. If the agent is stopped while waiting for approval, the pending workflow request is still active in 12Port. Persist the request ID, action type, and asset ID to a local file immediately after action type discovery. On next startup, check for this file and resume polling rather than submitting a new request.


The MCP Integration in Summary

12Port's MCP integration is a four-step credential retrieval layer:

  1. Authenticate to 12Port with an API token
  2. Read the MCP spec to discover available vault operations
  3. Find the asset that holds the credential
  4. Retrieve the credential, with full workflow approval support if required

That is the boundary of the integration. What your agent does with the retrieved credential, whether it starts a chat session, connects to a database, authenticates a service, or something else entirely, is your agent's business. 12Port's job is to make sure the credential gets from the vault to the agent securely, with full audit logging, access control enforcement, and policy compliance along the way.