Test-Governance MCP Server

Test-Governance MCP Server

Enables AI assistants to securely access Okta Identity Governance APIs for managing users, groups, apps, access requests, and certifications with configurable deployment modes and safety controls.

Category
Visit Server

README

Test - Governance MCP Server for OIG

Disclaimer: This project is a test/proof of concept developed using publicly available Okta APIs. This MCP server implementation is not affiliated with Okta, its official MCP servers, or its developer tools. This was developed on a personal device without any use of Okta (Okta, Inc.) resources or information outside of what is available to the public.

A Model Context Protocol (MCP) server that provides AI assistants with secure, structured access to Okta Identity Governance (OIG) APIs.

Built with TypeScript on Node.js, this server exposes 28 tools (19 admin + 9 end-user) that let LLMs query users, groups, apps, entitlements, access requests, certification campaigns, and more — with built-in safety controls for write operations.

Features

  • 28 tools — 19 admin tools for Okta core + OIG governance APIs, plus 9 end-user tools for delegated mode
  • Four deployment modesread-only, governance-admin, full-admin for admin use; delegated for end-user access via their own Okta login
  • End-user authentication — OAuth2 Authorization Code + PKCE flow lets users sign in with their own Okta credentials; the AI agent acts within their permissions
  • Confirmation protocol — write/destructive actions in admin modes require a two-step confirmation with HMAC-signed tokens
  • Intelligent rate limiting — tracks Okta's per-endpoint rate limits and backs off proactively
  • Response caching — LRU cache reduces redundant API calls (disabled in delegated mode to prevent cross-user data leaks)
  • Full audit trail — every tool invocation logged to stderr; mutations logged to SQLite
  • Two transports — stdio (for Claude Desktop, CLI tools) or HTTP (for web integrations and delegated mode)
  • Auto-detection — probes your Okta org at startup to determine if OIG is enabled (admin modes)

Prerequisites

  • Node.js >= 20
  • An Okta org with API access
  • Okta Identity Governance license (for governance tools; core user/group/app tools work without it)

Installation

git clone https://github.com/kaivalyapowale/test-governance-mcp.git
cd test-governance-mcp
npm install
npm run build

Configuration

All configuration is via environment variables. Copy .env.example to .env and fill in your values:

cp .env.example .env

Required

Variable Description
OKTA_ORG_URL Your Okta org URL (e.g., https://your-org.okta.com)

Authentication (choose one)

Option 1: SSWS API Token (simpler, good for development)

Variable Description
OKTA_API_TOKEN Okta API token (created in Admin > Security > API > Tokens)

Option 2: OAuth2 Client Credentials (recommended for production)

Variable Description
OKTA_CLIENT_ID OAuth2 service app client ID
OKTA_PRIVATE_KEY_PATH Path to RS256 private key PEM file
OKTA_SCOPES Comma-separated OAuth2 scopes (see Scopes below)

OAuth2 Scopes

The default scopes (okta.users.read, okta.groups.read, okta.apps.read, okta.logs.read) only cover core Okta APIs. If your org has OIG enabled, you will need additional governance scopes for the OIG tools to work. The exact scope names depend on your Okta org configuration — check your Okta Admin console under Security > API > Authorization Servers for available governance scopes (e.g., okta.governance.accessRequests.read, okta.governance.campaigns.read, etc.).

Alternatively, using an SSWS API token with sufficient admin permissions avoids scope configuration entirely, as SSWS tokens inherit the permissions of the admin user who created them.

Optional

Variable Default Description
MCP_DEPLOYMENT_MODE read-only read-only, governance-admin, full-admin, or delegated
MCP_CLIENT_SECRET Required for governance-admin and full-admin modes. Used to sign confirmation tokens.
MCP_STATE_DB_PATH ./data/state.db SQLite database path for audit log and token tracking
MCP_TRANSPORT stdio stdio or http
MCP_HTTP_PORT 3000 HTTP server port (when transport is http)
MCP_HTTP_HOST 127.0.0.1 HTTP server bind address
MCP_LOG_LEVEL info debug, info, warn, or error

Delegated Mode Configuration

Delegated mode requires additional configuration for the OAuth2 Authorization Code flow with PKCE. This mode requires HTTP transport.

Variable Description
OKTA_DELEGATED_CLIENT_ID Client ID of an Okta app configured for Authorization Code + PKCE (SPA or Native type)
OKTA_DELEGATED_REDIRECT_URI Redirect URI registered in the Okta app (e.g., http://localhost:3000/auth/callback)
OKTA_DELEGATED_SCOPES Comma-separated scopes (defaults to openid,profile,email,okta.users.read,okta.groups.read,okta.apps.read)
MCP_SESSION_SECRET Secret key for signing session cookies (use a random 32+ character string)

Usage

Stdio transport (Claude Desktop, CLI)

npm start

Add to your Claude Desktop config (claude_desktop_config.json):

{
  "mcpServers": {
    "okta-governance": {
      "command": "node",
      "args": ["/absolute/path/to/oig-mcp-server/dist/index.js"],
      "env": {
        "OKTA_ORG_URL": "https://your-org.okta.com",
        "OKTA_API_TOKEN": "your-token",
        "MCP_DEPLOYMENT_MODE": "read-only"
      }
    }
  }
}

HTTP transport (admin modes)

MCP_TRANSPORT=http MCP_HTTP_PORT=3000 npm start

Endpoints:

  • POST /mcp — MCP JSON-RPC endpoint
  • GET /health — Health check (returns tool count and deployment mode)

Delegated mode (end-user access)

Delegated mode lets end users authenticate with their own Okta credentials. The server uses their access token for all API calls, so responses are naturally scoped to their permissions — no admin privileges required.

MCP_DEPLOYMENT_MODE=delegated \
MCP_TRANSPORT=http \
OKTA_ORG_URL=https://your-org.okta.com \
OKTA_DELEGATED_CLIENT_ID=your_spa_client_id \
OKTA_DELEGATED_REDIRECT_URI=http://localhost:3000/auth/callback \
MCP_SESSION_SECRET=$(openssl rand -hex 32) \
npm start

Auth flow (browser — cookie-based):

  1. User visits GET /auth/login → redirected to Okta sign-in page
  2. After login, Okta redirects to GET /auth/callback → session cookie is set
  3. All subsequent POST /mcp requests use the user's own access token
  4. GET /auth/status — check if authenticated
  5. POST /auth/logout — end session

Auth flow (CLI / non-browser — Bearer token):

For non-browser MCP clients (Claude Code CLI, MCP Inspector, custom scripts), you can pass a user's Okta access token directly via the Authorization header instead of using cookies:

curl -X POST http://localhost:3000/mcp \
  -H "Authorization: Bearer <user's Okta access token>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"okta_my_profile","arguments":{}},"id":1}'

The server validates the token against Okta (GET /api/v1/users/me), extracts the user identity, and runs the tool as that user. This is stateless — no session is stored. Bearer tokens take priority over cookies if both are present.

Okta app setup: Create a SPA or Native application in Okta Admin (Applications > Create App Integration). Set the Sign-in redirect URI to match OKTA_DELEGATED_REDIRECT_URI. Enable Authorization Code grant type with PKCE. No client secret is needed.

Deployment Modes

The server supports four deployment modes. The first three are admin modes that use a service-level API token or OAuth2 client credentials. The fourth is delegated mode where each end user authenticates individually.

Admin Modes

Mode Access Use Case
read-only Query users, groups, apps, entitlements, grants, campaigns, etc. Safe exploration and reporting
governance-admin Read + create access requests, launch campaigns, submit decisions, assign group/app membership Day-to-day governance operations
full-admin All actions including revoke grants, remove memberships, user lifecycle (suspend/deactivate) Full administrative control

Write and destructive actions use a two-step confirmation protocol: the first call returns a preview and a signed token; the second call with that token executes the action. Tokens are single-use and expire after 5 minutes.

Delegated Mode

Mode Access Use Case
delegated End-user tools only: view own profile/groups/apps, browse catalog, request access, review certifications AI-assisted end-user experience (e.g., chatbot, help desk)

In delegated mode:

  • The user logs in with their own Okta credentials via OAuth2 Authorization Code + PKCE
  • All API calls use the user's own access token — no admin privileges
  • The user's userId is automatically injected into all tool calls (they can't query other users)
  • No confirmation tokens are needed — the user IS the actor
  • Admin tools are completely hidden; only end-user tools are available

Integrating with AI Agents (Delegated Mode)

Delegated mode is designed for building AI-powered end-user experiences — chatbots, help desk agents, or self-service portals where users interact with an AI assistant to manage their own access.

Architecture

┌─────────────────────────────────────────────────────────┐
│  End User's Browser / App                               │
│                                                         │
│  ┌──────────────┐     ┌──────────────────────────────┐  │
│  │  Chat UI /   │────▶│  AI Agent Backend             │  │
│  │  Frontend    │◀────│  (Claude, GPT, custom LLM)    │  │
│  └──────────────┘     └──────────┬───────────────────┘  │
│                                  │ MCP JSON-RPC          │
│                                  ▼                       │
│                       ┌──────────────────────────────┐  │
│                       │  This MCP Server             │  │
│                       │  (delegated mode, HTTP)      │  │
│                       │                              │  │
│                       │  /auth/login  → Okta SSO     │  │
│                       │  /auth/callback ← token      │  │
│                       │  /mcp ← tools (user context) │  │
│                       └──────────┬───────────────────┘  │
│                                  │ Bearer {user token}   │
│                                  ▼                       │
│                       ┌──────────────────────────────┐  │
│                       │  Okta APIs                   │  │
│                       │  (scoped to user's perms)    │  │
│                       └──────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

How it works

  1. User opens your app — the frontend checks GET /auth/status. If not authenticated, it redirects the user to GET /auth/login.
  2. User signs in via Okta — standard Okta login page (SSO, MFA, etc.). After authentication, Okta redirects back to /auth/callback, which sets a session cookie.
  3. AI agent calls tools — the agent backend sends MCP JSON-RPC requests to POST /mcp. The session cookie is included automatically. Every tool call runs under the user's own identity.
  4. User asks questions naturally — e.g., "What apps do I have access to?", "Request access to Salesforce", "Do I have any pending reviews?". The AI agent translates these into the appropriate tool calls.

What the AI agent can do for the user

User intent Tool used What happens
"What's my access?" iga_my_access Returns user's groups, apps, and active grants in one call
"Show me my groups" okta_my_groups Lists groups the user belongs to
"What can I request access to?" iga_catalog_browse Browses the access catalog scoped to the user
"Request access to Salesforce Admin role" iga_request_access Submits an access request with the user as requester
"What's the status of my requests?" iga_my_requests Lists the user's access requests with status
"Do I have any reviews to complete?" iga_my_pending_reviews Lists pending certification items assigned to the user
"Approve the review for Jane's access" iga_submit_review_decision Submits APPROVE/REVOKE on a review item

Key behaviors in delegated mode

  • No userId parameter — the user's identity is injected automatically from their session. They cannot query other users' data.
  • No confirmation tokens — unlike admin modes, delegated tools execute directly because the authenticated user IS the actor making the request.
  • Okta enforces permissions — if the user doesn't have permission for an action, Okta returns 403. The server doesn't need its own permission layer.
  • Session expiry — tokens refresh automatically. If the refresh token expires, the user is prompted to log in again.
  • Admin tools are hidden — the AI agent only sees the 9 delegated tools. It cannot access admin-level tools like okta_users, iga_campaigns, or iga_risk_assessment.

Example: connecting Claude as the AI agent

If you're using Claude (or another LLM) as the agent backend with an MCP client library:

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';

// The MCP client connects to your delegated-mode server
// The session cookie from the user's browser must be forwarded
const transport = new StreamableHTTPClientTransport(
  new URL('http://localhost:3000/mcp'),
  {
    // Forward the user's session cookie from the browser request
    headers: { Cookie: `mcp_session=${userSessionCookie}` },
  },
);

const client = new Client({ name: 'my-agent', version: '1.0.0' });
await client.connect(transport);

// Now call tools — they execute as the authenticated user
const myAccess = await client.callTool('iga_my_access', {});

Okta app setup for delegated mode

  1. Go to Okta Admin ConsoleApplicationsCreate App Integration
  2. Select OIDC - OpenID ConnectSingle-Page Application (or Native)
  3. Set Sign-in redirect URI to your OKTA_DELEGATED_REDIRECT_URI (e.g., http://localhost:3000/auth/callback)
  4. Set Sign-out redirect URI if needed
  5. Under General Settings, ensure Authorization Code grant type is enabled (with PKCE — this is default for SPA apps)
  6. No client secret is needed (PKCE replaces it)
  7. Under Assignments, assign the users or groups who should have access
  8. Copy the Client ID and use it as OKTA_DELEGATED_CLIENT_ID

Tools

Delegated End-User Tools (delegated mode only)

These tools are available when the server runs in delegated mode. They operate under the authenticated user's identity — no userId parameter needed.

Tool Description
okta_my_profile View your own Okta profile
okta_my_groups List groups you belong to
okta_my_apps List applications assigned to you
iga_my_access Full summary of your access: profile, groups, apps, and active grants
iga_catalog_browse Browse the access catalog to discover requestable entitlements
iga_request_access Submit an access request (requesterId auto-set to you)
iga_my_requests List your own access requests and their status
iga_my_pending_reviews List certification review items pending your decision
iga_submit_review_decision Submit APPROVE/REVOKE decision on a review item assigned to you

Admin Tools (read-only / governance-admin / full-admin modes)

Core Okta Tools (always available)

Tool Actions Description
okta_users list, get, groups, apps, lifecycle, assign_to_group, remove_from_group, assign_to_app, remove_from_app Manage users and their memberships
okta_groups list, get, members Query groups and membership
okta_apps list, get Query application integrations

OIG Governance Tools (require OIG license)

Tool Actions Description
iga_entitlements list, get, search, set_owner Manage application entitlements
iga_bundles list, get, create, update Entitlement bundles (access packages)
iga_resource_collections list, get Resource collection groupings
iga_policies list, get, create, update Governance policies
iga_sod list, get, detect, create Separation of duties rules and violation detection
iga_grants list, get, revoke Active entitlement grants
iga_campaigns list, get, create, launch, list_items, submit_decision, close, archive Certification campaigns
iga_access_requests list, get, create, decide Access request workflows
iga_security_reviews list, get, submit_finding Security review management
iga_list_catalog_entries Browse the access catalog
iga_get_audit_log Query local mutation audit log

Intelligence Tools (require OIG license)

These tools fan out to multiple APIs in a single call to provide aggregated insights.

Tool Description
iga_investigate_user_access Full picture of a user's access: profile, groups, apps, grants, pending requests, SoD violations. Supports summary, detailed, and full depth.
iga_explain_access_changes Timeline of governance-relevant changes for a user over a time range
iga_governance_dashboard Org-wide governance snapshot: active campaigns, pending requests, open reviews, SoD violations
iga_risk_assessment Risk scoring for a user based on grant count, auth failures, login recency, and account status
iga_access_coverage_report Per-app governance coverage: entitlement discovery, active policies, recent certifications

Architecture

src/
├── index.ts                  # Server entry point, transport setup
├── config.ts                 # Zod-validated configuration from env vars
├── auth/
│   ├── token-manager.ts      # SSWS and OAuth2 (JWT client credentials) auth
│   ├── session-manager.ts    # OAuth2 Auth Code + PKCE flow, session storage (delegated mode)
│   └── session-context.ts    # AsyncLocalStorage for per-request session threading
├── api/
│   └── client.ts             # HTTP client with caching, rate limiting, retries
├── state/
│   ├── repository.ts         # State interface (audit log, token tracking)
│   └── sqlite.ts             # SQLite implementation (better-sqlite3, WAL mode)
├── tools/
│   ├── registry.ts           # Tool registry with deployment mode filtering
│   ├── delegated.ts          # End-user tools for delegated mode (9 tools)
│   ├── users.ts              # okta_users
│   ├── groups.ts             # okta_groups
│   ├── apps.ts               # okta_apps
│   ├── entitlements.ts       # iga_entitlements
│   ├── bundles.ts            # iga_bundles
│   ├── collections.ts        # iga_resource_collections
│   ├── policies.ts           # iga_policies
│   ├── sod.ts                # iga_sod
│   ├── grants.ts             # iga_grants
│   ├── campaigns.ts          # iga_campaigns
│   ├── access-requests.ts    # iga_access_requests
│   ├── security-reviews.ts   # iga_security_reviews
│   ├── catalog.ts            # iga_list_catalog_entries
│   ├── audit-log.ts          # iga_get_audit_log
│   ├── investigate.ts        # iga_investigate_user_access
│   ├── explain-changes.ts    # iga_explain_access_changes
│   ├── dashboard.ts          # iga_governance_dashboard
│   ├── risk.ts               # iga_risk_assessment
│   └── coverage.ts           # iga_access_coverage_report
└── util/
    ├── types.ts              # Shared types (ToolResponse, ToolError, etc.)
    ├── errors.ts             # Error classes and Okta error mapping
    ├── response.ts           # Response builder helpers
    ├── confirmation.ts       # HMAC-SHA256 confirmation token protocol
    ├── action-filter.ts      # Per-action deployment mode filtering
    └── audit.ts              # Audit logger (stderr + SQLite) with field redaction

Security

All modes

  • No credentials in code — all auth is via environment variables
  • Rate limit awareness — proactively backs off when Okta rate limit headers show remaining capacity below threshold
  • Concurrency control — configurable semaphore limits parallel API calls (default: 3)
  • Deployment mode gating — tools and actions are filtered at registration time so the LLM never sees unavailable operations

Admin modes (read-only / governance-admin / full-admin)

  • Confirmation tokens — write/destructive operations require HMAC-SHA256 signed, single-use tokens with 5-minute expiry
  • Audit logging — all tool invocations logged to stderr; all mutations logged to SQLite with Okta request IDs
  • Sensitive field redaction — fields named password, secret, token, apikey, credentials, privatekey, or clientSecret are replaced with [REDACTED] in logs
  • Response caching — LRU cache reduces redundant API calls

Delegated mode

  • OAuth2 PKCE — Authorization Code flow with Proof Key for Code Exchange; no client secret stored on the server
  • Signed session cookies — session IDs are HMAC-signed to prevent tampering; cookies are HttpOnly and SameSite=Lax
  • No cross-user data — cache is skipped for all delegated API calls; each request uses only the authenticated user's token
  • User identity auto-injected — tools cannot be tricked into querying other users; userId comes from the session, not from parameters
  • Okta-enforced permissions — the server does not maintain its own permission model; Okta returns 403 if the user lacks access
  • Session lifecycle — tokens refresh automatically; idle sessions expire after 24 hours; expired pending auth flows are cleaned up every 5 minutes

Development

# Watch mode (recompiles on change)
npm run dev

# Run tests
npm test

# Type check without emitting
npx tsc --noEmit

Dependencies

Package Purpose License
@modelcontextprotocol/sdk MCP server SDK MIT
better-sqlite3 SQLite for audit log and token tracking MIT
jose JWT signing for OAuth2 client credentials MIT
lru-cache API response caching ISC
zod Schema validation for config and tool inputs MIT

Disclaimer

This project is a test/proof of concept developed using publicly available Okta APIs. This MCP server implementation is not affiliated with Okta, its official MCP servers, or its developer tools. This was developed on a personal device without any use of Okta (Okta, Inc.) resources or information outside of what is available to the public.

License

MIT

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured