Skip to content

Connect Unkey to ChatGPT: Control API Keys, RBAC, and Rate Limits

Learn how to connect Unkey to ChatGPT using a managed MCP server. Automate API key provisioning, rate limiting, and RBAC workflows with natural language.

Yuvraj Muley Yuvraj Muley · · 10 min read
Connect Unkey to ChatGPT: Control API Keys, RBAC, and Rate Limits

You want to connect Unkey to ChatGPT so your AI agents can provision API keys, audit role-based access control (RBAC), and manage rate limits on the fly. If your team uses Claude, check out our guide on connecting Unkey to Claude, or explore our broader architectural overview on connecting Unkey to AI Agents. Here is exactly how to do it using a managed Model Context Protocol (MCP) server.

Giving a Large Language Model (LLM) read and write access to your core authentication infrastructure is an engineering challenge. You are exposing the system that controls who can access your product and how much they can consume. You either spend weeks building, hosting, and maintaining a secure custom MCP server to safely expose Unkey's capabilities, or you use a managed infrastructure layer that handles the boilerplate for you.

This guide breaks down exactly how to use Truto to generate a secure, managed MCP server for Unkey, connect it natively to ChatGPT, and execute complex authentication and identity workflows using natural language.

The Engineering Reality of the Unkey API

A custom MCP server is a self-hosted integration layer that translates an LLM's JSON-RPC tool calls into REST API requests. While the MCP standard provides a predictable way for models to discover tools, implementing it against strict authentication infrastructure like Unkey introduces specific technical hurdles.

If you decide to build a custom MCP server for Unkey, you are responsible for the entire API lifecycle. Here are the specific integration challenges that break standard CRUD assumptions when working with the Unkey API:

Plaintext Key Isolation and Hashing

Unkey is designed with strict security guarantees. When you create a new API key, the plaintext string is returned exactly once. Subsequent lookups, verifications, or audits require the key ID or the hashed version of the key. If your MCP server drops the connection, fails to parse the initial response, or the LLM hallucinates during the creation step, that plaintext key is lost forever. Your server logic must guarantee that the LLM captures and explicitly outputs the plaintext key to the user immediately upon creation.

Atomic RBAC Operations vs. Additive Updates

Unkey offers discrete methods for managing permissions. Operations like set_permissions and set_roles are atomic - they completely overwrite the existing arrays on a key. If an LLM is asked to "add the billing permission to this key" and it mistakenly calls the atomic set endpoint without passing the existing permissions, it will silently revoke all prior access. Your MCP server must expose strictly scoped schemas to prevent destructive overrides, ensuring the LLM understands the difference between appending a permission and replacing a permission set.

Edge Propagation Latency

Unkey operates on a globally distributed edge network. When you assign a new role to an identity or create a new rate limit override, changes can take up to 30 seconds to propagate across all edge regions. If an LLM creates a key, assigns a permission, and immediately attempts to verify that key in the next tool call, the verification might fail due to replication lag. A custom MCP server must implement intentional delays or instruct the LLM to expect asynchronous propagation.

Rate Limit Enforcement and 429 Errors

When you use Unkey to enforce rate limits on your own users, you must also respect Unkey's rate limits on your management API calls. If your AI agent attempts to bulk-audit thousands of keys without pagination constraints, Unkey will reject the requests with an HTTP 429 error.

Factual Note on Truto and Rate Limits: Truto does not retry, throttle, or apply exponential backoff on rate limit errors. When the upstream Unkey API returns a 429 Too Many Requests, Truto passes that error directly back to the caller (your LLM agent). Truto normalizes the upstream rate limit information into standardized IETF headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). The caller is strictly responsible for interpreting these headers and executing their own retry or backoff logic.

The Managed MCP Approach

Instead of building custom exponential backoff logic, writing complex JSON schemas for every Unkey endpoint, and deploying intermediate infrastructure, you can use Truto. Truto acts as a managed integration layer that dynamically generates MCP tools based on the active API documentation and capabilities of your connected Unkey account.

When you connect Unkey to Truto, the platform creates a self-contained, token-secured MCP server URL. This URL exposes the Unkey API as a set of LLM-ready tools. The tool descriptions instruct the LLM on exactly how to handle cursors, edge propagation, and payload requirements without requiring you to maintain custom TypeScript or Python servers.

How to Create the Unkey MCP Server

To expose Unkey tools to ChatGPT, you must first generate an MCP server via Truto. This server is scoped exclusively to your connected Unkey workspace and secured by a cryptographic token. You can create this server using the Truto UI or programmatically via the API.

Method 1: Via the Truto UI

  1. Log in to your Truto dashboard and navigate to your connected Unkey Integrated Account.
  2. Click the MCP Servers tab.
  3. Click Create MCP Server.
  4. Configure your server settings. You can restrict the server to read-only operations or apply tag-based filtering if you only want the LLM to access rate limit endpoints.
  5. Click Save and copy the generated MCP server URL. It will look like https://api.truto.one/mcp/abc123def456....

Method 2: Via the Truto API

For platform teams embedding AI into their own infrastructure, you can generate MCP servers programmatically. Submit a POST request to the Truto API using your integrated account ID.

curl -X POST https://api.truto.one/integrated-account/{integrated_account_id}/mcp \
  -H "Authorization: Bearer YOUR_TRUTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Unkey ChatGPT Agent",
    "config": {
      "methods": ["read", "write"],
      "require_api_token_auth": false
    }
  }'

The API returns a payload containing the secure url. This URL is all the client needs to connect.

How to Connect the MCP Server to ChatGPT

Once you have your Truto MCP server URL, you must register it with your LLM client. ChatGPT supports connecting to remote MCP servers directly via Server-Sent Events (SSE).

Method 1: Via the ChatGPT UI

  1. Open ChatGPT and navigate to Settings -> Apps -> Advanced settings.
  2. Enable Developer mode (MCP support requires this feature flag).
  3. Under the MCP servers / Custom connectors section, click Add new server.
  4. Name: Enter a descriptive label like "Unkey Auth Management".
  5. Server URL: Paste the Truto MCP URL you generated in the previous step.
  6. Click Save. ChatGPT will immediately ping the endpoint, execute the handshake, and load the Unkey tools into your agent's context.

Method 2: Via Manual Configuration File

If you are using an alternative MCP client (like Claude Desktop) or testing locally via the MCP CLI, you configure the remote server using a JSON configuration file. Standard local MCP servers use stdio (standard input/output), but remote managed servers like Truto use SSE. You handle this by specifying the standard remote SSE transport command.

{
  "mcpServers": {
    "unkey-auth": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-sse",
        "https://api.truto.one/mcp/abc123def456..."
      ]
    }
  }
}

Hero Tools for Unkey

Once connected, Truto exposes your Unkey workspace as discrete, callable tools. By relying on dynamically generated tools driven by live integration schemas, the LLM always has the correct payload structures. Here are the highest-leverage operations your AI agent can perform.

create_a_unkey_key

Creates a new API key within an existing Unkey API namespace. The agent can configure rate limits, assign credits, specify an expiration date, and link the key to an existing identity. The plaintext key is returned in the response.

"Create a new API key for the 'production-api' namespace. Assign it to the identity external ID 'usr_98765', give it a monthly rate limit of 10000 requests, and show me the plaintext key so I can send it to the developer."

unkey_keys_verify

Verifies an API key's validity, evaluating its permissions, rate limits, and usage quota. This is critical for auditing workflows where the LLM needs to confirm exactly what a specific key string is authorized to do.

"Check this API key: 'unk_2a3b4c...'. Tell me if it is currently valid, what permissions are attached to it, and how many credits it has remaining for this billing period."

unkey_keys_set_permissions

Replaces all direct permissions on an Unkey key in one atomic operation. This is useful for hard-resets of access profiles. The LLM handles the schema requirements to ensure the payload overwrites existing state cleanly.

"Update the permissions for key ID 'key_5x8y9z'. Strip any existing permissions and explicitly set only the 'read_billing' and 'write_invoices' permissions."

create_a_unkey_identity

Creates a centralized identity record to group multiple API keys under a single user or organization entity. This enables shared metadata and unified rate limit tracking across multiple distinct keys.

"Provision a new identity for external ID 'org_acme_corp'. Set a global rate limit for this identity at 50 requests per second, and return the newly generated identity ID."

unkey_ratelimit_limit

Executes a manual rate limit check against a specific identifier within a namespace. The LLM can use this to simulate or enforce quota limits during diagnostic workflows.

"Run a rate limit check for the identifier 'user_123' in the 'global_api' namespace. The limit should be 5 requests per 60 seconds. Tell me if the check passed and how many requests they have remaining."

unkey_keys_update_credits

Modifies the credit balance for an existing key. The agent can increment or decrement the balance, or set the value to null to grant unlimited usage.

"Add 5000 credits to key ID 'key_777888'. Ensure that the response confirms the total remaining balance after the increment operation."

For the complete tool inventory and schema details, review the Unkey integration page.

Workflows in Action

Giving ChatGPT access to Unkey transforms manual security and provisioning runbooks into automated conversations. Here are real-world examples of how an AI agent coordinates these tools.

Workflow 1: Provisioning a New Developer Sandbox Tenant

When a new enterprise customer signs up, your onboarding team needs to provision their identity, issue sandbox credentials, and set strict initial rate limits.

"We just signed Acme Corp. Their external tenant ID is 'acme_001'. Create an identity for them in Unkey, set a baseline rate limit of 10 requests per second, and generate a new sandbox API key linked to this identity. Make sure the key has the 'sandbox_access' role."

  1. create_a_unkey_identity: The agent creates the identity using externalId: 'acme_001' and applies the ratelimits object specifying 10 requests per second.
  2. create_a_unkey_key: The agent creates the key, passing the newly generated identity ID and the sandbox_access role parameter.
  3. Synthesis: ChatGPT returns the plaintext key and confirms that the rate limits and identity linking are successfully active.

Workflow 2: Auditing and Rotating a Compromised Key

If a developer accidentally pushes a key to a public repository, the security team needs to verify the scope of the key, disable it, and issue a secure replacement immediately.

sequenceDiagram
    participant User as SecOps Engineer
    participant ChatGPT as ChatGPT
    participant Truto as Truto MCP Server
    participant Unkey as Unkey API
    User->>ChatGPT: "A key leaked: unk_123... Rotate it."
    ChatGPT->>Truto: Call unkey_keys_whoami
    Truto->>Unkey: GET /keys.whoami
    Unkey-->>Truto: Return key metadata (keyId)
    Truto-->>ChatGPT: Return keyId and identity
    ChatGPT->>Truto: Call update_a_unkey_key_by_id (enabled: false)
    Truto->>Unkey: PUT /keys/{keyId}
    Unkey-->>Truto: Success
    Truto-->>ChatGPT: Key disabled
    ChatGPT->>Truto: Call create_a_unkey_key
    Truto->>Unkey: POST /keys
    Unkey-->>Truto: Return new plaintext key
    Truto-->>ChatGPT: Return new key

"We had a security incident. The key 'unk_9a8b7c6d...' was leaked. Look up its current permissions, immediately disable the key, and then generate a new replacement key with the exact same permissions and identity linking."

  1. unkey_keys_whoami: The agent takes the leaked key string and looks up the key record to retrieve the internal keyId, roles, permissions, and identity references.
  2. update_a_unkey_key_by_id: The agent uses the keyId to update the record, passing enabled: false to instantly revoke access.
  3. create_a_unkey_key: The agent provisions a fresh key, copying the exact roles, permissions, and identity ID from the step 1 audit.
  4. Synthesis: ChatGPT outputs the audit report of the compromised key, confirms its disabled status, and provides the new plaintext key for secure distribution.

Security and Access Control

Exposing your authentication backend to an LLM requires strict boundary setting. Truto provides multiple layers of security to lock down exactly what an MCP server can do.

  • Method Filtering: You can configure the server to only allow specific operations. By passing methods: ["read"] during creation, you ensure the LLM can audit identities and verify keys, but physically cannot create, update, or delete them.
  • Tag Filtering: Integration resources are mapped to logical tags. You can filter the MCP server to only expose tools tagged with rate_limits, preventing the LLM from accessing identity or RBAC endpoints entirely.
  • Require API Token Auth: By setting require_api_token_auth: true, possession of the MCP URL is no longer sufficient. The connecting client must also pass a valid Truto API bearer token in the Authorization header, adding a critical second factor for enterprise deployments.
  • Time-to-Live (TTL) Expirations: You can supply an expires_at ISO datetime when generating the server. Once the timestamp is reached, durable object alarms automatically destroy the database records and edge storage, instantly revoking the LLM's access.

Closing the Loop on Access Management

Integrating Unkey with ChatGPT fundamentally changes how engineering teams handle access management. You are replacing custom CLI scripts, dashboard clicks, and complex API coordination with declarative, natural language commands. Truto handles the protocol translation, API execution, and payload structuring so you don't have to write and maintain custom MCP server middleware.

FAQ

How does Truto handle Unkey rate limit errors?
Truto does not retry or apply exponential backoff on HTTP 429 rate limit errors. It passes the error directly to the calling LLM agent, normalizing the upstream rate limit data into standardized headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). The caller is responsible for retry logic.
Can I restrict the Unkey tools my ChatGPT agent can use?
Yes. When creating the MCP server in Truto, you can use method filtering to allow only read operations, or tag filtering to restrict access to specific resource categories like rate limits or identities.
What happens if the LLM fails to capture the plaintext API key upon creation?
Unkey returns the plaintext key exactly once upon creation. If the LLM drops the connection or fails to output it, the key cannot be retrieved again. You will need to rotate the key or issue a new one.
How do I secure the MCP server URL?
You can enforce a second layer of security by enabling `require_api_token_auth: true` on the MCP server, which requires the client to pass a valid Truto API bearer token. You can also set a strict expiration date using the `expires_at` field.

More from our Blog