Metadata-Version: 2.4
Name: okta-agent
Version: 2.3.1
Summary: Okta CIAM/SSO MCP Server and Agent for Agentic AI!
Author-email: Project Maintainers <maintainers@users.noreply.github.com>
License: MIT
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: MIT License
Classifier: Environment :: Console
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.6
Requires-Dist: httpx>=0.28.1
Requires-Dist: PyJWT[crypto]>=2.15.1
Provides-Extra: mcp
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.6; extra == "mcp"
Provides-Extra: all
Requires-Dist: okta-agent[mcp]>=1.0.0; extra == "all"
Provides-Extra: test
Requires-Dist: pytest-xdist>=3.8.0; extra == "test"
Requires-Dist: pytest>=9.1.1; extra == "test"
Requires-Dist: pytest-asyncio>=1.4.0; extra == "test"
Requires-Dist: pytest-cov>=7.1.0; extra == "test"
Dynamic: license-file

# Okta Agent
## CLI or API | MCP

![PyPI - Version](https://img.shields.io/pypi/v/okta-agent)
![MCP Server](https://badge.mcpx.dev?type=server 'MCP Server')
![PyPI - Downloads](https://img.shields.io/pypi/dd/okta-agent)
![GitHub Repo stars](https://img.shields.io/github/stars/Knuckles-Team/okta-agent)
![PyPI - License](https://img.shields.io/pypi/l/okta-agent)
![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/okta-agent)
![PyPI - Wheel](https://img.shields.io/pypi/wheel/okta-agent)

*Version: 2.3.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](#overview)
- [Architecture](#architecture)
- [Installation](#installation)
- [Configure](#configure)
- [Environment Variables](#environment-variables)
- [Quick Start](#quick-start)
- [Run](#run)
- [MCP Tools](#mcp-tools)
- [Deployment](#deployment)
- [Keycloak Parity](#keycloak-parity)
- [Development](#development)

## Overview

Enterprise CIAM/SSO connector for the agent fleet: a production-grade MCP
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 `httpx` client — 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's `after` cursor),
  with hard item caps and resumable `next_cursor`s.
- Safety: destructive operations (disable / remove / clear sessions /
  password ops) are blocked unless explicitly allowed; credential material is
  redacted from logs and error envelopes.

## Architecture

## Installation

> **Install the connector-focused `[mcp]` extra.** Examples use `okta-agent[mcp]` to add
> FastMCP / FastAPI through `agent-connector-sdk`; the required Agent Connector SDK core
> enables model orchestration.

Pick the extra that matches what the operator want to run:

| Extra | Installs | Use when |
|-------|----------|----------|
| `okta-agent[mcp]` | Connector-focused MCP server (`agent-connector-sdk` — FastMCP/FastAPI + `epistemic-graph[full]`) | The operator only run the **MCP server** (smallest install / image) |
| `okta-agent[all]` | Everything (`mcp` + `agent` + `logfire`) | Development / both surfaces |

### Container images (`:mcp`)

One multi-stage `docker/Dockerfile` builds the MCP-only image (`--target mcp`):

| Image tag | Build target | Contents | Entrypoint |
|-----------|--------------|----------|------------|

```bash
```

agent (`immutable agent digest`) with a co-located `:mcp` sidecar.

### Knowledge-graph database (`epistemic-graph`)

Agent Connector SDK core dependency (`epistemic-graph[full]`). The `[mcp]` extra keeps
deployments can use the bundled engine. For production or shared state, run
**epistemic-graph as a dedicated database service** and configure the runtime to use it.
Deployment recipes (single-node + Raft HA), connection configuration, and architecture
diagrams are documented in the
[epistemic-graph deployment guide](https://knuckles-team.github.io/epistemic-graph/deployment/).

## Configure

```bash
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_TLS_PROFILE`, `OKTA_MAX_RETRIES`,
`OKTA_BACKOFF_CAP_SECONDS`, `OKTA_ALLOW_DESTRUCTIVE`, per-tool switches).

## Environment Variables

<!-- ENV-VARS-TABLE:START -->

#### 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_REF` | `secret://telemetry/otlp-public-key` |  |
| `OTEL_EXPORTER_OTLP_SECRET_KEY_REF` | `secret://telemetry/otlp-secret-key` |  |
| `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` | secret-injected |  |
| `OKTA_CLIENT_ID` | — | Service-app client id (org authorization server, client_credentials grant) |
| `OKTA_PRIVATE_KEY` | secret-injected | PEM private key inline, or a path to a PEM file |
| `OKTA_PRIVATE_KEY_FILE` | secret-injected |  |
| `OKTA_KEY_ID` | secret-injected | 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_TLS_PROFILE` | `system` | Named outbound TLS policy. Configure profiles in AgentConfig; a reference may resolve runtime trust material without persisting certificate paths here. |
| `OKTA_TLS_PROFILE_REF` | — |  |
| `OKTA_MAX_RETRIES` | `2` | 429 handling: retry attempts and backoff cap (seconds) |
| `OKTA_BACKOFF_CAP_SECONDS` | `60` |  |
| `OKTA_ALLOW_DESTRUCTIVE` | `False` | Safety: org-wide default for destructive tool actions (deactivate/delete/clear-sessions/password ops). Per-call allow_destructive=true also works; default is blocked. |
| `USERSTOOL` | `True` | Tool registration switches |
| `GROUPSTOOL` | `True` |  |
| `APPSTOOL` | `True` |  |
| `POLICIESTOOL` | `True` |  |
| `SYSTEMTOOL` | `True` |  |
| `INGESTTOOL` | `True` |  |

#### Inherited agent-connector-sdk variables (apply to every connector)

| Variable | Example | Description |
|----------|---------|-------------|
| `MCP_TOOL_MODE` | `intent` | Tool surface: `intent` \| `condensed` \| `verbose` \| `both` |
| `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 child auth: `oidc-client-credentials` \| `basic` \| `none` |
| `OIDC_CLIENT_ID` | — | OIDC client id (service-account auth) |
| `OIDC_CLIENT_SECRET_REF` | `secret://identity/oidc-client-secret` | Runtime secret reference for the OIDC service account |
| `MCP_BASIC_AUTH_USERNAME` | — | HTTP Basic username (`MCP_CLIENT_AUTH=basic`) |
| `MCP_BASIC_AUTH_PASSWORD_REF` | `secret://identity/mcp-basic-password` | Runtime secret reference for HTTP Basic auth (`MCP_CLIENT_AUTH=basic`) |
| `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 |

_30 package + 16 inherited variable(s). Auto-generated from `.env.example` + the shared agent-connector-sdk set — do not edit._
<!-- ENV-VARS-TABLE:END -->

| 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_TLS_PROFILE` | `system` | Named outbound TLS policy from AgentConfig |
| `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) |

## Quick Start

```python
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

```bash
okta-mcp                                  # stdio MCP server
okta-mcp --transport streamable-http --host 0.0.0.0 --port 8000
```

## MCP Tools

Five consolidated, action-routed tools. Each takes `action`, `params_json`,
and (where applicable) `allow_destructive`.

<!-- This table is auto-generated by `python -m agent_connector_sdk.mcp.readme_tools` — do not edit by hand. -->

<!-- MCP-TOOLS-TABLE:START -->

#### Condensed action-routed tools (`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_ingest` | `INGESTTOOL` | Natively ingest Okta users/groups/apps into epistemic-graph as typed nodes. |
| `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`)

<details>
<summary>54 per-operation tools — one per public API method (click to expand)</summary>

| 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. |

</details>

_6 action-routed tool(s) · 54 verbose 1:1 tool(s). Each is enabled unless its `<DOMAIN>TOOL` toggle is set false; `MCP_TOOL_MODE` selects the surface (**`intent` default** — the six verb-tools, granular set loaded on demand · `condensed` action-routed · `verbose` 1:1 · `both`). Auto-generated — do not edit._
<!-- MCP-TOOLS-TABLE:END -->

### Examples

```json
{"action": "search", "params_json": "{\"conditions\": [{\"field\": \"status\", \"op\": \"eq\", \"value\": \"ACTIVE\"}, {\"field\": \"profile.department\", \"op\": \"eq\", \"value\": \"Engineering\"}]}"}
```

```json
{"action": "create", "params_json": "{\"template\": \"oidc\", \"label\": \"My App\", \"settings\": {\"redirect_uris\": [\"https://app.example.com/cb\"]}}"}
```

```json
{"action": "deactivate", "params_json": "{\"user_id\": \"00u1\"}", "allow_destructive": true}
```

Every successful response is an envelope:

```json
{"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_URL`, `PROVIDER`, and `MODEL_ID` from the environment. Prebuilt images:
(full agent) — see [Container images](#container-images-mcp-vs-agent). See
[docs/deployment.md](docs/deployment.md) for transports, reverse proxy, and DNS
guidance.

<!-- BEGIN GENERATED: additional-deployment-options -->
### Additional Deployment Options

`okta-agent` can run as a local stdio process or container, or behind a remote
network boundary. The
[Deployment guide](https://knuckles-team.github.io/okta-agent/deployment/) carries
the detailed transport contract.

- **Local container** — launch a reviewed immutable image as a least-privilege
  stdio child with no listener or published port.
- **Remote URL** — connect through an operator-supplied authenticated HTTPS
  ingress. Keep its URL, outbound identity references, trust profile, and exact
  `MCP_ALLOWED_HOSTS` in `AgentConfig`.
<!-- END GENERATED: additional-deployment-options -->

## 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

```bash
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/).

<!-- BEGIN agent-connector-sdk-deployment (generated; do not edit between markers) -->

## Deploy with `agent-connector-sdk-deployment`

Provision this package with the consolidated **`agent-connector-sdk-deployment`**
workflow. It selects an installed-package, editable-source, or immutable-container
path; records only runtime secret and TLS-profile references in `AgentConfig`; and
runs doctor, registration, policy, observability, and rollback gates. Ask your agent
to **"deploy `okta-agent` with agent-connector-sdk-deployment"**.

| Install mode | Command |
|------|---------|
| Installed package | `uv tool install "okta-agent[mcp]"`, then run `okta-mcp` |
| Immutable container | deploy `registry.example.invalid/okta-agent@sha256:<digest>` through the operator-selected orchestrator |

The repository embeds no deployment profile, credential value, certificate path, or
environment-specific endpoint. Supply those at runtime through `AgentConfig` and the
configured secret provider.

<!-- END agent-connector-sdk-deployment -->

<!-- GOVERNED-CAPABILITY:START -->
## Governed capability contract

This package ships a compact canonical skill surface with specialist procedures
kept as referenced workflows. The current MCP tools, skill metadata,
`connector_manifest.yml`, ontology, mappings, shapes, fixtures, migrations,
tool-schema fingerprints, and certification metadata form one versioned
capability contract. Validate them together; do not rely on stale tool names or
historical per-task skill wrappers.

Runtime endpoints, credentials, certificate trust, tenant identity, retention,
and observability policy are deployment inputs and are never packaged values.
See [Configuration, trust, and privacy](docs/configuration.md) before enabling a
network transport, connector ingestion, Arbora delegation, or trace export.
<!-- GOVERNED-CAPABILITY:END -->
