Okta CIAM/SSO MCP Server and Agent for Agentic AI!
Project description
Okta Agent
CLI or API | MCP | Agent
Version: 1.0.1
Documentation — Installation, deployment, usage across the API, CLI, and MCP server live on the docs site: https://knuckles-team.github.io/okta-agent/
Table of Contents
- Overview
- Architecture
- Installation
- Configure
- Environment Variables
- Quick Start
- Run
- MCP Tools
- Deployment
- Keycloak Parity
- Development
Overview
Enterprise CIAM/SSO connector for the agent fleet: a production-grade MCP
server and Pydantic AI agent over the Okta Management API — users, groups,
applications, policies, and the system log. Complements keycloak-agent
(open-source IdP) with the commercial-IdP side of the house, mirroring its
verb taxonomy so agents can switch IdPs with familiar verbs.
- Raw
httpxclient — no Okta SDK; every method documents the endpoint it calls. - Two auth modes: SSWS API token and OAuth2 private-key-JWT (org authorization server, Okta API scopes).
- Rate-limit aware: every response envelope carries the latest
X-Rate-Limit-*snapshot; HTTP 429 triggers capped automatic backoff. - Cursor pagination via
Link: rel="next"headers (Okta'saftercursor), with hard item caps and resumablenext_cursors. - Safety: destructive operations (deactivate / delete / clear sessions / password ops) are blocked unless explicitly allowed; credential material is redacted from logs and error envelopes.
Architecture
graph TD
User([User/A2A]) --> Server[A2A Server / okta-agent]
Server --> Agent[Pydantic AI Agent]
Agent --> MCP[MCP Server / okta-mcp]
MCP --> Client[Api facade / httpx]
Client --> ExternalAPI([Okta Management API])
Installation
Install the slim
[mcp]extra. For MCP-server hosting (includinguvx/ container deploys), installokta-agent[mcp]— the MCP-server extra that pulls only the FastMCP / FastAPI tooling (agent-utilities[mcp]). It deliberately excludes the heavy agent runtime (the epistemic-graph engine,pydantic-ai,dspy,llama-index,tree-sitter), so installs are dramatically smaller and faster. Use the full[agent]extra only when you need the integrated Pydantic AI agent.
Pick the extra that matches what you want to run:
| Extra | Installs | Use when |
|---|---|---|
okta-agent[mcp] |
Slim MCP server only (agent-utilities[mcp] — FastMCP/FastAPI) |
You only run the MCP server (smallest install / image) |
okta-agent[agent] |
Full agent runtime (agent-utilities[agent,logfire] — Pydantic AI + the epistemic-graph engine) |
You run the integrated A2A agent |
okta-agent[all] |
Everything (mcp + agent + logfire) |
Development / both surfaces |
pip install okta-agent # core API client
pip install okta-agent[mcp] # slim MCP server (FastMCP/FastAPI)
pip install okta-agent[agent] # full A2A agent runtime + epistemic-graph engine
pip install okta-agent[all] # everything (development)
Container images (:mcp vs :agent)
One multi-stage docker/Dockerfile builds two right-sized images, selected by --target:
| Image tag | Build target | Contents | Entrypoint |
|---|---|---|---|
knucklessg1/okta-agent:mcp |
--target mcp |
okta-agent[mcp] — slim, no engine/pydantic-ai/dspy/llama-index/tree-sitter |
okta-mcp |
knucklessg1/okta-agent:latest |
--target agent (default) |
okta-agent[agent] — full agent runtime + epistemic-graph engine |
okta-agent |
docker build --target mcp -t knucklessg1/okta-agent:mcp docker/ # slim MCP server
docker build --target agent -t knucklessg1/okta-agent:latest docker/ # full agent
docker/mcp.compose.yml runs the slim :mcp server; docker/agent.compose.yml runs the
agent (:latest) with a co-located :mcp sidecar.
Knowledge-graph database (epistemic-graph)
The full agent ([agent] / :latest) embeds the epistemic-graph engine (pulled in
transitively via agent-utilities[agent]). For production — or to share one knowledge graph
across multiple agents — run epistemic-graph as its own database container and point the
agent at it instead of embedding it. Deployment recipes (single-node + Raft HA), connection
config, and the full database architecture (with diagrams) are documented in the
epistemic-graph deployment guide.
The slim [mcp] server does not require the database.
Configure
export OKTA_ORG_URL="https://acme.okta.com"
# Mode 1 — SSWS API token (takes precedence)
export OKTA_API_TOKEN="<api token>"
# Mode 2 — OAuth2 private-key-JWT (service app, Okta API scopes)
export OKTA_CLIENT_ID="0oa..."
export OKTA_PRIVATE_KEY_FILE="/path/to/key.pem" # or OKTA_PRIVATE_KEY inline
export OKTA_SCOPES="okta.users.read okta.groups.manage"
See .env.example for every knob (OKTA_SSL_VERIFY, OKTA_MAX_RETRIES,
OKTA_BACKOFF_CAP_SECONDS, OKTA_ALLOW_DESTRUCTIVE, per-tool switches).
Environment Variables
Package environment variables
| Variable | Example | Description |
|---|---|---|
HOST |
0.0.0.0 |
|
PORT |
8000 |
|
TRANSPORT |
stdio |
options: stdio, streamable-http, sse |
ENABLE_OTEL |
True |
|
OTEL_EXPORTER_OTLP_ENDPOINT |
http://localhost:8080/api/public/otel |
|
OTEL_EXPORTER_OTLP_PUBLIC_KEY |
pk-... |
|
OTEL_EXPORTER_OTLP_SECRET_KEY |
sk-... |
|
OTEL_EXPORTER_OTLP_PROTOCOL |
http/protobuf |
|
EUNOMIA_TYPE |
none |
options: none, embedded, remote |
EUNOMIA_POLICY_FILE |
mcp_policies.json |
|
EUNOMIA_REMOTE_URL |
http://eunomia-server:8000 |
|
OKTA_ORG_URL |
https://acme.okta.com |
Okta org URL (no trailing slash), e.g. https://acme.okta.com |
OKTA_AGENT_BASE_URL |
— | Accepted as a fallback for OKTA_ORG_URL when that is unset |
OKTA_API_TOKEN |
— | |
OKTA_CLIENT_ID |
— | Service-app client id (org authorization server, client_credentials grant) |
OKTA_PRIVATE_KEY |
— | PEM private key inline, or a path to a PEM file |
OKTA_PRIVATE_KEY_FILE |
— | |
OKTA_KEY_ID |
— | Optional JWKS key id for the client assertion header |
OKTA_SCOPES |
okta.users.read okta.groups.read okta.apps.read |
Space-separated Okta API scopes |
OKTA_SSL_VERIFY |
True |
TLS verification toward the org |
OKTA_MAX_RETRIES |
2 |
429 handling: retry attempts and backoff cap (seconds) |
OKTA_BACKOFF_CAP_SECONDS |
60 |
|
OKTA_ALLOW_DESTRUCTIVE |
False |
allow_destructive=true also works; default is blocked. |
USERSTOOL |
True |
Tool registration switches |
GROUPSTOOL |
True |
|
APPSTOOL |
True |
|
POLICIESTOOL |
True |
|
SYSTEMTOOL |
True |
Inherited agent-utilities variables (apply to every connector)
| Variable | Example | Description |
|---|---|---|
MCP_TOOL_MODE |
condensed |
Tool surface: condensed |
MCP_ENABLED_TOOLS |
— | Comma-separated tool allow-list |
MCP_DISABLED_TOOLS |
— | Comma-separated tool deny-list |
MCP_ENABLED_TAGS |
— | Comma-separated tag allow-list |
MCP_DISABLED_TAGS |
— | Comma-separated tag deny-list |
MCP_CLIENT_AUTH |
— | Outbound MCP auth (oidc-client-credentials for fleet calls) |
OIDC_CLIENT_ID |
— | OIDC client id (service-account auth) |
OIDC_CLIENT_SECRET |
— | OIDC client secret (service-account auth) |
DEBUG |
False |
Verbose logging |
PYTHONUNBUFFERED |
1 |
Unbuffered stdout (recommended in containers) |
MCP_URL |
http://localhost:8000/mcp |
URL of the MCP server the agent connects to |
PROVIDER |
openai |
LLM provider for the agent |
MODEL_ID |
gpt-4o |
Model id for the agent |
ENABLE_WEB_UI |
True |
Serve the AG-UI web interface |
28 package + 14 inherited variable(s). Auto-generated from .env.example + the shared agent-utilities set — do not edit.
| Variable | Default | Purpose |
|---|---|---|
OKTA_ORG_URL |
— | Okta org URL, no trailing slash (OKTA_AGENT_BASE_URL accepted as fallback) |
OKTA_API_TOKEN |
— | SSWS API token (auth mode 1, takes precedence) |
OKTA_CLIENT_ID |
— | Service-app client id (private-key-JWT) |
OKTA_PRIVATE_KEY / OKTA_PRIVATE_KEY_FILE |
— | PEM private key inline or path |
OKTA_KEY_ID |
— | Optional JWKS key id for the client assertion |
OKTA_SCOPES |
read scopes | Space-separated Okta API scopes |
OKTA_SSL_VERIFY |
True |
TLS verification toward the org |
OKTA_MAX_RETRIES |
2 |
429 retry attempts |
OKTA_BACKOFF_CAP_SECONDS |
60 |
429 backoff cap |
OKTA_ALLOW_DESTRUCTIVE |
False |
Org-wide default for destructive tool actions |
HOST / PORT / TRANSPORT |
0.0.0.0 / 8000 / stdio |
MCP server bind + transport |
USERSTOOL / GROUPSTOOL / APPSTOOL / POLICIESTOOL / SYSTEMTOOL |
True |
Per-domain tool toggles |
ENABLE_OTEL / OTEL_EXPORTER_OTLP_* |
— | Telemetry (OTEL / Langfuse) |
EUNOMIA_TYPE / EUNOMIA_POLICY_FILE / EUNOMIA_REMOTE_URL |
none |
MCP authorization middleware |
AUTH_TYPE |
none |
MCP server auth mode (Docker) |
DEFAULT_AGENT_NAME / AGENT_DESCRIPTION / AGENT_SYSTEM_PROMPT |
identity files | A2A agent identity overrides |
Quick Start
from okta_agent import Api
from okta_agent.api.credentials import SswsToken
from okta_agent.okta_input_models import SearchInput, FilterCondition
api = Api(org_url="https://acme.okta.com", credential=SswsToken("<token>"))
active = api.search_users(
conditions=[{"field": "status", "op": "eq", "value": "ACTIVE"}],
)
print(active["data"], active["rate_limit"])
# Or build typed tool params for the MCP surface:
params = SearchInput(
conditions=[FilterCondition(field="status", op="eq", value="ACTIVE")]
).model_dump_json(exclude_none=True)
Run
okta-mcp # stdio MCP server
okta-mcp --transport streamable-http --host 0.0.0.0 --port 8000
okta-agent # A2A agent server
MCP Tools
Five consolidated, action-routed tools. Each takes action, params_json,
and (where applicable) allow_destructive.
Condensed action-routed tools (default — MCP_TOOL_MODE=condensed)
| MCP Tool | Toggle Env Var | Description |
|---|---|---|
okta_apps |
APPSTOOL |
Manage Okta applications — CRUD, lifecycle, and user/group assignments. |
okta_groups |
GROUPSTOOL |
Manage Okta groups — CRUD, membership, and dynamic group rules. |
okta_policies |
POLICIESTOOL |
Inspect Okta policies and toggle policy/rule lifecycle. |
okta_system |
SYSTEMTOOL |
Inspect the Okta org — settings, auth servers, system log, authenticators, zones. |
okta_users |
USERSTOOL |
Manage Okta users — lifecycle, credentials, groups/apps/factors, sessions. |
Verbose 1:1 API-mapped tools (MCP_TOOL_MODE=verbose or both)
54 per-operation tools — one per public API method (click to expand)
| MCP Tool | Toggle Env Var | Description |
|---|---|---|
okta_activate_app |
APITOOL |
Activate an application. |
okta_activate_group_rule |
APITOOL |
Activate a group rule. |
okta_activate_policy |
APITOOL |
Activate a policy. |
okta_activate_policy_rule |
APITOOL |
Activate a policy rule. |
okta_activate_user |
APITOOL |
Activate a STAGED/DEPROVISIONED user. |
okta_add_group_member |
APITOOL |
Add a user to a group. |
okta_assign_group_to_app |
APITOOL |
Assign a group to an app. |
okta_assign_user_to_app |
APITOOL |
Assign a user to an app with an optional app-specific profile. |
okta_clear_user_sessions |
APITOOL |
Revoke all of a user's sessions — destructive. |
okta_create_app |
APITOOL |
Create an app from a basic template (oidc/saml/bookmark). |
okta_create_group |
APITOOL |
Create an OKTA_GROUP. |
okta_create_group_rule |
APITOOL |
Create an INACTIVE group rule from an Okta Expression Language condition. |
okta_create_user |
APITOOL |
Create a user, optionally activated immediately. |
okta_deactivate_app |
APITOOL |
Deactivate an application — destructive. |
okta_deactivate_group_rule |
APITOOL |
Deactivate a group rule — destructive. |
okta_deactivate_policy |
APITOOL |
Deactivate a policy — destructive. |
okta_deactivate_policy_rule |
APITOOL |
Deactivate a policy rule — destructive. |
okta_deactivate_user |
APITOOL |
Deactivate (deprovision) a user — destructive. |
okta_delete_group |
APITOOL |
Delete a group — destructive. |
okta_expire_password |
APITOOL |
Expire a user's password — destructive. |
okta_get_app |
APITOOL |
Get one application by id. |
okta_get_group |
APITOOL |
Get one group by id. |
okta_get_org |
APITOOL |
Get the org settings (company info, subdomain, status). |
okta_get_policy |
APITOOL |
Get one policy, optionally expanded with its rules. |
okta_get_system_log |
APITOOL |
Query the system log (audit events), capped and cursor-paginated. |
okta_get_user |
APITOOL |
Get one user by id, login, or login shortname. |
okta_list_app_groups |
APITOOL |
List the groups assigned to an app. |
okta_list_app_users |
APITOOL |
List the users assigned to an app. |
okta_list_apps |
APITOOL |
List applications with optional q label match or SCIM filter. |
okta_list_authenticators |
APITOOL |
List the org's authenticators (Okta Verify, WebAuthn, password, ...). |
okta_list_authorization_servers |
APITOOL |
List custom authorization servers. |
okta_list_group_members |
APITOOL |
List the users in a group. |
okta_list_group_rules |
APITOOL |
List group rules. |
okta_list_groups |
APITOOL |
List groups with optional q name prefix, SCIM filter or search. |
okta_list_network_zones |
APITOOL |
List network zones. |
okta_list_org_factors |
APITOOL |
List org-level MFA factor enablement (legacy Factors API view). |
okta_list_policies |
APITOOL |
List policies of one type (okta_sign_on/password/mfa_enroll/access_policy). |
okta_list_policy_rules |
APITOOL |
List the rules of a policy. |
okta_list_user_apps |
APITOOL |
List the app links assigned to a user. |
okta_list_user_factors |
APITOOL |
List the enrolled MFA factors for a user. |
okta_list_user_groups |
APITOOL |
List the groups a user belongs to. |
okta_list_users |
APITOOL |
List users with optional q prefix match, SCIM filter or search. |
okta_remove_group_member |
APITOOL |
Remove a user from a group — destructive. |
okta_reset_password |
APITOOL |
Start the password-reset flow — destructive. |
okta_search_groups |
APITOOL |
Search groups from structured SCIM conditions (built safely). |
okta_search_users |
APITOOL |
Search users from structured SCIM conditions (built safely). |
okta_suspend_user |
APITOOL |
Suspend an ACTIVE user — destructive. |
okta_unassign_group_from_app |
APITOOL |
Remove a group's app assignment — destructive. |
okta_unassign_user_from_app |
APITOOL |
Remove a user's app assignment — destructive. |
okta_unlock_user |
APITOOL |
Unlock a LOCKED_OUT user. |
okta_unsuspend_user |
APITOOL |
Return a SUSPENDED user to ACTIVE. |
okta_update_app |
APITOOL |
Replace an application (PUT semantics — pass the full app object). |
okta_update_group |
APITOOL |
Replace a group's profile (PUT semantics — name is required). |
okta_update_user |
APITOOL |
Partially update a user's profile and/or credentials. |
5 action-routed tool(s) (default) · 54 verbose 1:1 tool(s). Each is enabled unless its <DOMAIN>TOOL toggle is set false; MCP_TOOL_MODE selects the surface (condensed default · verbose 1:1 · both). Auto-generated — do not edit.
Examples
{"action": "search", "params_json": "{\"conditions\": [{\"field\": \"status\", \"op\": \"eq\", \"value\": \"ACTIVE\"}, {\"field\": \"profile.department\", \"op\": \"eq\", \"value\": \"Engineering\"}]}"}
{"action": "create", "params_json": "{\"template\": \"oidc\", \"label\": \"My App\", \"settings\": {\"redirect_uris\": [\"https://app.example.com/cb\"]}}"}
{"action": "deactivate", "params_json": "{\"user_id\": \"00u1\"}", "allow_destructive": true}
Every successful response is an envelope:
{"data": [...], "rate_limit": {"limit": 600, "remaining": 599, "reset": 1700000000}, "count": 5, "truncated": false, "next_cursor": null}
Errors map Okta's envelope: {"error": {"status", "error_code", "error_summary", "error_id", "error_causes", "rate_limit"}}.
Deployment
# MCP server only (port 8000, streamable-http, /health)
docker compose -f docker/mcp.compose.yml up -d
# MCP server + A2A agent server (agent on port 9021, AG-UI web interface)
docker compose -f docker/agent.compose.yml up -d
The A2A agent server (okta-agent console script, agent_server.py) reads
MCP_URL, PROVIDER, and MODEL_ID from the environment. Prebuilt images:
knucklessg1/okta-agent:mcp (slim MCP server) and knucklessg1/okta-agent:latest
(full agent) — see Container images. See
docs/deployment.md for transports, reverse proxy, and DNS
guidance.
Additional Deployment Options
okta-agent can also run as a local container (Docker / Podman / uv) or be
consumed from a remote deployment. The
Deployment guide has full, copy-paste
mcp_config.json for all four transports — stdio, streamable-http,
local container / uv, and remote URL:
- Local container / uv — launch the server from
mcp_config.jsonviauvx,docker run, orpodman run, or point at a local streamable-http container byurl. - Remote URL — connect to a server deployed behind Caddy at
http://okta-mcp.arpa/mcpusing the"url"key.
Keycloak parity
Verbs intentionally mirror keycloak-agent where the concepts overlap, so an
agent fluent in one IdP connector can drive the other:
| Concept | keycloak-agent | okta-agent |
|---|---|---|
| Users CRUD | keycloak_agent_users list/get/create/update |
okta_users list/get/create/update |
| Password reset | reset_password |
reset_password (plus expire_password) |
| User's groups | list_users_by_user_id_groups |
list_groups |
| Groups CRUD + members | keycloak_agent_groups |
okta_groups (+ Okta group rules) |
| OAuth/SAML clients | keycloak_agent_clients |
okta_apps (Keycloak "clients" = Okta "apps") |
| Auth policies/flows | keycloak_agent_authentication |
okta_policies (read + lifecycle) |
| Server/org info & events | keycloak_agent_info / attack detection |
okta_system (org + system log) |
Okta-only surface: lifecycle states (suspend/unlock), group rules, app assignment profiles, network zones, Okta API scopes via private-key-JWT.
Development
pip install -e .[mcp,test]
pytest -v
pre-commit run --all-files
API references are cited in every client docstring (https://developer.okta.com/docs/api/).
Deploy with agent-os-genesis
This package can be provisioned for you — skill-guided — by the agent-os-genesis
universal skill (its single-package deploy mode): it picks your install method, seeds
secrets to OpenBao/Vault (or .env), trusts your enterprise CA, registers the MCP
server, and verifies it — the same machinery that stands up the whole Agent OS, narrowed
to just this package. Ask your agent to "deploy okta-agent with agent-os-genesis".
| Install mode | Command |
|---|---|
| Bare-metal, prod (PyPI) | uvx okta-mcp · or uv tool install okta-agent |
| Bare-metal, dev (editable) | uv pip install -e ".[all]" · or pip install -e ".[all]" |
| Container, prod | deploy knucklessg1/okta-agent:latest via docker-compose / swarm / podman / podman-compose / kubernetes |
| Container, dev (editable) | deploy docker/compose.dev.yml (source-mounted at /src; edits live on restart) |
Secrets are read-existing + seeded via vault_sync — you are only prompted for what's missing.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file okta_agent-1.0.1.tar.gz.
File metadata
- Download URL: okta_agent-1.0.1.tar.gz
- Upload date:
- Size: 62.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49ea131c375d4ebe54ceab7d7afea078d3d01c316bffd6ee48410ec467164ff4
|
|
| MD5 |
dc7fb8fe84bd884d46aaecae1b421687
|
|
| BLAKE2b-256 |
ab189440faa08d81ae42dc1c372b27a312ab4d5ce683226c13d25457ddf21320
|
File details
Details for the file okta_agent-1.0.1-py3-none-any.whl.
File metadata
- Download URL: okta_agent-1.0.1-py3-none-any.whl
- Upload date:
- Size: 73.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0776a992fd54255e45bd02e9265f6476da9c6bf471106d76bf5cda9ae3aee427
|
|
| MD5 |
64fb346005e963359a6e9e7a25fbaa20
|
|
| BLAKE2b-256 |
f455745e10120f134fec5b511de02e257daedb40062ccde0926c0f88a90ce3a0
|