Metadata-Version: 2.4
Name: servicenow-api
Version: 1.3.31
Summary: Python ServiceNow API Wrapper
Author-email: Audel Rouhi <knucklessg1@gmail.com>
License: MIT
Classifier: Development Status :: 5 - Production/Stable
Classifier: License :: Public Domain
Classifier: Environment :: Console
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.8.1
Requires-Dist: urllib3>=2.2.2
Requires-Dist: pydantic[email]>=2.8.2
Provides-Extra: mcp
Requires-Dist: fastmcp>=2.13.0.2; extra == "mcp"
Requires-Dist: eunomia-mcp>=0.3.10; extra == "mcp"
Provides-Extra: a2a
Requires-Dist: pydantic-ai-slim[a2a,anthropic,fastmcp,google,huggingface,openai]>=1.32.0; extra == "a2a"
Provides-Extra: all
Requires-Dist: fastmcp>=2.13.0.2; extra == "all"
Requires-Dist: eunomia-mcp>=0.3.10; extra == "all"
Requires-Dist: pydantic-ai-slim[a2a,anthropic,fastmcp,google,huggingface,openai]>=1.32.0; extra == "all"
Dynamic: license-file

# ServiceNow API - A2A & MCP Server

![PyPI - Version](https://img.shields.io/pypi/v/servicenow-api)
![PyPI - Downloads](https://img.shields.io/pypi/dd/servicenow-api)
![GitHub Repo stars](https://img.shields.io/github/stars/Knuckles-Team/servicenow-api)
![GitHub forks](https://img.shields.io/github/forks/Knuckles-Team/servicenow-api)
![GitHub contributors](https://img.shields.io/github/contributors/Knuckles-Team/servicenow-api)
![PyPI - License](https://img.shields.io/pypi/l/servicenow-api)
![GitHub](https://img.shields.io/github/license/Knuckles-Team/servicenow-api)

![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/servicenow-api)
![GitHub pull requests](https://img.shields.io/github/issues-pr/Knuckles-Team/servicenow-api)
![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/Knuckles-Team/servicenow-api)
![GitHub issues](https://img.shields.io/github/issues/Knuckles-Team/servicenow-api)

![GitHub top language](https://img.shields.io/github/languages/top/Knuckles-Team/servicenow-api)
![GitHub language count](https://img.shields.io/github/languages/count/Knuckles-Team/servicenow-api)
![GitHub repo size](https://img.shields.io/github/repo-size/Knuckles-Team/servicenow-api)
![GitHub repo file count (file type)](https://img.shields.io/github/directory-file-count/Knuckles-Team/servicenow-api)
![PyPI - Wheel](https://img.shields.io/pypi/wheel/servicenow-api)
![PyPI - Implementation](https://img.shields.io/pypi/implementation/servicenow-api)

*Version: 1.3.31*

ServiceNow API + MCP Server + A2A

This repository is actively maintained and will continue adding more API calls. It includes a Model Context Protocol (MCP) server and an out of the box Agent2Agent (A2A) agent

The MCP Server is enhanced with various authentication mechanisms, middleware for observability and control, and optional Eunomia authorization for policy-based access control.

Contributions are welcome!

All API Response objects are customized for the response call. You can access return values in a `parent.value.nested_value` format, or use `parent.model_dump()` to get the response as a dictionary.

#### API Calls:
- Application Service
- Change Management
- CI/CD
- CMDB
- Import Sets
- Incident
- Knowledge Base
- Table
- Custom Endpoint

If your API call isn't supported, you can use the `api_request` tool to perform GET/POST/PUT/DELETE requests to any ServiceNow endpoint.

#### Features:
- **Authentication**: Supports multiple authentication types including none (disabled), static (internal tokens), JWT, OAuth Proxy, OIDC Proxy, and Remote OAuth for external identity providers.
- **Middleware**: Includes logging, timing, rate limiting, and error handling for robust server operation.
- **Eunomia Authorization**: Optional policy-based authorization with embedded or remote Eunomia server integration.
- **Resources**: Provides `instance_config` and `incident_categories` for ServiceNow configuration and data.
- **Prompts**: Includes `create_incident_prompt` and `query_table_prompt` for AI-driven interactions.
- **OIDC Token Delegation**: Supports token exchange for ServiceNow API calls, enabling user-specific authentication via OIDC.
- **OpenAPI JSON Tool Import**: Import custom ServiceNow API Endpoints through the OpenAPI JSON generated.

<details>
  <summary><b>Usage:</b></summary>

### MCP CLI

| Short Flag | Long Flag                       | Description                                                                                               |
|------------|---------------------------------|-----------------------------------------------------------------------------------------------------------|
| -h         | --help                          | Display help information                                                                                  |
| -t         | --transport                     | Transport method: 'stdio', 'http', or 'sse' [legacy] (default: stdio)                                     |
| -s         | --host                          | Host address for HTTP transport (default: 0.0.0.0)                                                        |
| -p         | --port                          | Port number for HTTP transport (default: 8000)                                                            |
|            | --auth-type                     | Authentication type: 'none', 'static', 'jwt', 'oauth-proxy', 'oidc-proxy', 'remote-oauth' (default: none) |
|            | --token-jwks-uri                | JWKS URI for JWT verification                                                                             |
|            | --token-issuer                  | Issuer for JWT verification                                                                               |
|            | --token-audience                | Audience for JWT verification                                                                             |
|            | --token-algorithm               | JWT signing algorithm (e.g., HS256, RS256). Required for HMAC or static keys. Auto-detected for JWKS.     |
|            | --token-secret                  | Shared secret for HMAC (HS*) verification. Used with --token-algorithm.                                   |
|            | --token-public-key              | Path to PEM public key file or inline PEM string for static asymmetric verification.                      |
|            | --required-scopes               | Comma-separated required scopes (e.g., servicenow.read,servicenow.write). Enforced by JWTVerifier.        |
|            | --oauth-upstream-auth-endpoint  | Upstream authorization endpoint for OAuth Proxy                                                           |
|            | --oauth-upstream-token-endpoint | Upstream token endpoint for OAuth Proxy                                                                   |
|            | --oauth-upstream-client-id      | Upstream client ID for OAuth Proxy                                                                        |
|            | --oauth-upstream-client-secret  | Upstream client secret for OAuth Proxy                                                                    |
|            | --oauth-base-url                | Base URL for OAuth Proxy                                                                                  |
|            | --oidc-config-url               | OIDC configuration URL                                                                                    |
|            | --oidc-client-id                | OIDC client ID                                                                                            |
|            | --oidc-client-secret            | OIDC client secret                                                                                        |
|            | --oidc-base-url                 | Base URL for OIDC Proxy                                                                                   |
|            | --remote-auth-servers           | Comma-separated list of authorization servers for Remote OAuth                                            |
|            | --remote-base-url               | Base URL for Remote OAuth                                                                                 |
|            | --allowed-client-redirect-uris  | Comma-separated list of allowed client redirect URIs                                                      |
|            | --eunomia-type                  | Eunomia authorization type: 'none', 'embedded', 'remote' (default: none)                                  |
|            | --eunomia-policy-file           | Policy file for embedded Eunomia (default: mcp_policies.json)                                             |
|            | --eunomia-remote-url            | URL for remote Eunomia server                                                                             |
|            | --enable-delegation             | Enable OIDC token delegation to ServiceNow (default: False)                                               |
|            | --servicenow-audience           | Audience for the delegated ServiceNow token                                                               |
|            | --delegated-scopes              | Scopes for the delegated ServiceNow token (space-separated)                                               |
|            | --openapi-file                  | Path to OpenAPI JSON spec to import tools/resources from                                                  |
|            | --openapi-base-url              | Base URL for the OpenAPI client (defaults to ServiceNow instance URL)                                     |

### A2A CLI

| Short Flag | Long Flag         | Description                                                            |
|------------|-------------------|------------------------------------------------------------------------|
| -h         | --help            | Display help information                                               |
|            | --host            | Host to bind the server to (default: 0.0.0.0)                          |
|            | --port            | Port to bind the server to (default: 9000)                             |
|            | --reload          | Enable auto-reload                                                     |
|            | --provider        | LLM Provider: 'openai', 'anthropic', 'google', 'huggingface'           |
|            | --model-id        | LLM Model ID (default: qwen3:4b)                                       |
|            | --base-url        | LLM Base URL (for OpenAI compatible providers)                         |
|            | --api-key         | LLM API Key                                                            |
|            | --mcp-url         | MCP Server URL (default: http://localhost:8000/mcp)                    |

### Using as an MCP Server

The MCP Server can be run in two modes: `stdio` (for local testing) or `http` (for networked access). To start the server, use the following commands:

#### Run in stdio mode (default):
```bash
servicenow-mcp --transport "stdio"
```

#### Run in HTTP mode:
```bash
servicenow-mcp --transport "http"  --host "0.0.0.0"  --port "8000"
```

#### Run in Production:



**Embedded Eunomia:**

`mcp_policies.json`

```json
{
  "policies": [
    {
      "id": "servicenow_read_policy",
      "description": "Allow read-only tools if user has read scope",
      "allow": true,
      "conditions": [
        {
          "tool": ["get_application", "get_cmdb", "batch_install_result"],  // Per-tool targeting
          "scopes": ["servicenow.read", "servicenow.full"]  // Like your PRODUCT_READ_SCOPE
        }
      ]
    },
    {
      "id": "servicenow_write_policy",
      "description": "Allow write tools if user has write scope and is admin",
      "allow": true,
      "conditions": [
        {
          "tool": ["batch_install", "batch_rollback", "app_repo_install"],  // Write tools
          "scopes": ["servicenow.write", "servicenow.full"],  // Like your PRODUCT_WRITE_SCOPE
          "claims": {"role": "admin"}  // Extra claim check (from JWT)
        }
      ]
    },
    {
      "id": "default_deny",
      "description": "Deny all other access",
      "allow": false
    }
  ]
}
```

Run command examples:
```bash
export IDENTITY_JWKS_URI="https://your-identity-provider.com/.well-known/jwks.json"
export API_IDENTIFIER="servicenow-mcp"
export PRODUCT_READ_SCOPE="mcpserverapi.product.read"
export INVENTORY_READ_SCOPE="mcpserverapi.inventory.read"
servicenow-mcp \
--transport "http"  \
--host "0.0.0.0" \
--port "8000" \
--auth-type "jwt" \
--token-jwks-uri "${IDENTITY_JWKS_URI}" \
--token-issuer "https://your-identity-provider.com" \
--token-audience "${API_IDENTIFIER}" \
--required-scopes "$PRODUCT_READ_SCOPE,$INVENTORY_READ_SCOPE" \
--eunomia-type "embedded" \
--eunomia-policy-file "mcp_policies.json"
```

```bash
# 1. JWKS (Production, RS256)
servicenow-mcp --auth-type jwt \
  --token-jwks-uri https://auth.example.com/.well-known/jwks.json \
  --token-issuer https://auth.example.com \
  --token-audience servicenow-mcp \
  --required-scopes servicenow.read,servicenow.write
```

```bash
# 2. HMAC (Internal, HS256)
servicenow-mcp --auth-type jwt \
  --token-secret "your-256-bit-secret-here-min-32-chars" \
  --token-algorithm HS256 \
  --token-issuer internal-auth \
  --token-audience mcp-api
```

```bash
# 3. Static RSA Key (Dev)
servicenow-mcp --auth-type jwt \
  --token-public-key ./public_key.pem \
  --token-issuer test-issuer \
  --token-audience test-mcp
```

```bash
# 4. With Delegation
--enable-delegation --auth-type jwt ... (uses JWT as subject_token)
```

```bash
#5 JWKS (Production, Asymmetric RS256)
servicenow-mcp --transport "http" --auth-type "jwt" \
  --token-jwks-uri "https://auth.example.com/.well-known/jwks.json" \
  --token-issuer "https://auth.example.com" \
  --token-audience "servicenow-mcp" \
  --required-scopes "servicenow.read,servicenow.write"
```

```bash
#6 HMAC (Internal/Microservices, HS256)
servicenow-mcp --transport "http" --auth-type "jwt" \
  --token-secret "your-256-bit-secret-min-32-chars" \
  --token-algorithm "HS256" \
  --token-issuer "internal-auth" \
  --token-audience "mcp-api"
```

```bash
#7 Static Public Key (Dev/Testing, RS256)
servicenow-mcp --transport "http" --auth-type "jwt" \
  --token-public-key "/path/to/public_key.pem" \
  --token-issuer "test-issuer" \
  --token-audience "test-mcp"
```

Native Fast MCP Arguments
```bash
# Enable JWT verification
export FASTMCP_SERVER_AUTH=fastmcp.server.auth.providers.jwt.JWTVerifier

# For asymmetric verification with JWKS endpoint:
export FASTMCP_SERVER_AUTH_JWT_JWKS_URI="https://auth.company.com/.well-known/jwks.json"
export FASTMCP_SERVER_AUTH_JWT_ISSUER="https://auth.company.com"
export FASTMCP_SERVER_AUTH_JWT_AUDIENCE="mcp-production-api"
export FASTMCP_SERVER_AUTH_JWT_REQUIRED_SCOPES="read:data,write:data"

# OR for symmetric key verification (HMAC):
export FASTMCP_SERVER_AUTH_JWT_PUBLIC_KEY="your-shared-secret-key-minimum-32-chars"
export FASTMCP_SERVER_AUTH_JWT_ALGORITHM="HS256"  # or HS384, HS512
export FASTMCP_SERVER_AUTH_JWT_ISSUER="internal-auth-service"
export FASTMCP_SERVER_AUTH_JWT_AUDIENCE="mcp-internal-api"
```

### Using as an A2A Agent

The `servicenow-a2a` tool hosts an Agent-to-Agent (A2A) server that orchestrates specialized child agents for different ServiceNow domains.

#### Run in CLI mode:

```bash
servicenow-a2a --port 9000 --provider openai --model-id gpt-4o
```

#### Run in Docker:

You can run the A2A server using the same Docker image by overriding the command.

```bash
docker run -d \
  -p 9000:9000 \
  -e SERVICENOW_INSTANCE=https://yourinstance.servicenow.com \
  -e SERVICENOW_USERNAME=user \
  -e SERVICENOW_PASSWORD=pass \
  knucklessg1/servicenow:latest \
  servicenow-a2a \
  --port 9000 \
  --mcp-url http://host.docker.internal:8000/mcp
```

> **Note:** The A2A agent requires a running MCP server to function. In the example above, `host.docker.internal` allows the container to talk to an MCP server running on your host machine. If you are running both in the same network or compose stack, use the service name.

### Basic API Usage

**OAuth Authentication**

```python
#!/usr/bin/python
# coding: utf-8
from servicenow_api.servicenow_api import Api

username = "<SERVICENOW USERNAME>"
password = "<SERVICENOW PASSWORD>"
client_id = "<SERVICENOW CLIENT_ID>"
client_secret = "<SERVICENOW_CLIENT_SECRET>"
servicenow_url = "<SERVICENOW_URL>"

client = Api(
    url=servicenow_url,
    username=username,
    password=password,
    client_id=client_id,
    client_secret=client_secret
)

table = client.get_table(table="<TABLE NAME>")
print(f"Table: {table.model_dump()}")
```

**Basic Authentication**

```python
#!/usr/bin/python
# coding: utf-8
from servicenow_api.servicenow_api import Api

username = "<SERVICENOW USERNAME>"
password = "<SERVICENOW PASSWORD>"
servicenow_url = "<SERVICENOW_URL>"

client = Api(
    url=servicenow_url,
    username=username,
    password=password
)

table = client.get_table(table="<TABLE NAME>")
print(f"Table: {table.model_dump()}")
```

**Proxy and SSL Verify**

```python
#!/usr/bin/python
# coding: utf-8
from servicenow_api.servicenow_api import Api

username = "<SERVICENOW USERNAME>"
password = "<SERVICENOW PASSWORD>"
servicenow_url = "<SERVICENOW_URL>"

proxy = "https://proxy.net"

client = Api(
    url=servicenow_url,
    username=username,
    password=password,
    proxy=proxy,
    verify=False
)

table = client.get_table(table="<TABLE NAME>")
print(f"Table: {table.model_dump()}")
```

### Deploy MCP Server as a Service

The ServiceNow MCP server can be deployed using Docker, with configurable authentication, middleware, and Eunomia authorization.

#### Using Docker Run

```bash
docker pull knucklessg1/servicenow:latest

docker run -d \
  --name servicenow-mcp \
  -p 8004:8004 \
  -e HOST=0.0.0.0 \
  -e PORT=8004 \
  -e TRANSPORT=http \
  -e AUTH_TYPE=none \
  -e EUNOMIA_TYPE=none \
  -e SERVICENOW_INSTANCE=https://yourinstance.servicenow.com \
  -e SERVICENOW_USERNAME=user \
  -e SERVICENOW_PASSWORD=pass \
  -e SERVICENOW_CLIENT_ID=client_id \
  -e SERVICENOW_CLIENT_SECRET=client_secret \
  -e SERVICENOW_VERIFY=False \
  knucklessg1/servicenow:latest
```

For advanced authentication (e.g., OIDC Proxy with token delegation) or Eunomia, add the relevant environment variables:


For Additional OpenAPI Tool Import, include OPENAPI_FILE.
```bash
docker run -d \
  --name servicenow-mcp \
  -p 8004:8004 \
  -e HOST=0.0.0.0 \
  -e PORT=8004 \
  -e TRANSPORT=http \
  -e AUTH_TYPE=oidc-proxy \
  -e FASTMCP_SERVER_AUTH_JWT_ALGORITHM=HS256 \
  -e FASTMCP_SERVER_AUTH_JWT_PUBLIC_KEY="your-shared-secret" \
  -e FASTMCP_SERVER_AUTH_JWT_REQUIRED_SCOPES="servicenow.read,servicenow.write" \
  -e OIDC_CONFIG_URL=https://provider.com/.well-known/openid-configuration \
  -e OIDC_CLIENT_ID=your-client-id \
  -e OIDC_CLIENT_SECRET=your-client-secret \
  -e OIDC_BASE_URL=https://your-server.com \
  -e ALLOWED_CLIENT_REDIRECT_URIS=http://localhost:*,https://*.example.com/* \
  -e ENABLE_DELEGATION=True \
  -e SERVICENOW_AUDIENCE=https://yourinstance.servicenow.com \
  -e DELEGATED_SCOPES="api user_impersonation" \
  -e EUNOMIA_TYPE=embedded \
  -e EUNOMIA_POLICY_FILE=/app/mcp_policies.json \
  -e SERVICENOW_INSTANCE=https://yourinstance.servicenow.com \
  -e SERVICENOW_USERNAME=user \
  -e SERVICENOW_PASSWORD=pass \
  -e SERVICENOW_CLIENT_ID=client_id \
  -e SERVICENOW_CLIENT_SECRET=client_secret \
  -e SERVICENOW_VERIFY=False \
  -e OPENAPI_FILE=/app/servicenow_openapi.json \
  knucklessg1/servicenow:latest
```

#### Using Docker Compose

Create a `docker-compose.yml` file:

```yaml
services:
  servicenow-mcp:
    image: knucklessg1/servicenow:latest
    environment:
      - HOST=0.0.0.0
      - PORT=8004
      - TRANSPORT=http
      - AUTH_TYPE=none
      - EUNOMIA_TYPE=none
      - SERVICENOW_INSTANCE=https://yourinstance.servicenow.com
      - SERVICENOW_USERNAME=user
      - SERVICENOW_PASSWORD=pass
      - SERVICENOW_CLIENT_ID=client_id
      - SERVICENOW_CLIENT_SECRET=client_secret
      - SERVICENOW_VERIFY=False
    ports:
      - 8004:8004
```

For advanced setups with authentication, token delegation, and Eunomia:

```yaml
services:
  servicenow-mcp:
    image: knucklessg1/servicenow:latest
    environment:
      - HOST=0.0.0.0
      - PORT=8004
      - TRANSPORT=http
      - AUTH_TYPE=oidc-proxy
      - OIDC_CONFIG_URL=https://provider.com/.well-known/openid-configuration
      - OIDC_CLIENT_ID=your-client-id
      - OIDC_CLIENT_SECRET=your-client-secret
      - OIDC_BASE_URL=https://your-server.com
      - ALLOWED_CLIENT_REDIRECT_URIS=http://localhost:*,https://*.example.com/*
      - ENABLE_DELEGATION=True
      - SERVICENOW_AUDIENCE=https://yourinstance.servicenow.com
      - DELEGATED_SCOPES='api user_impersonation'
      - EUNOMIA_TYPE=embedded
      - EUNOMIA_POLICY_FILE=/app/mcp_policies.json
      - SERVICENOW_INSTANCE=https://yourinstance.servicenow.com
      - SERVICENOW_USERNAME=user
      - SERVICENOW_PASSWORD=pass
      - SERVICENOW_CLIENT_ID=client_id
      - SERVICENOW_CLIENT_SECRET=client_secret
      - SERVICENOW_VERIFY=False
      - FASTMCP_SERVER_AUTH_JWT_ALGORITHM=HS256
      - FASTMCP_SERVER_AUTH_JWT_PUBLIC_KEY=your-shared-secret
      - FASTMCP_SERVER_AUTH_JWT_REQUIRED_SCOPES=servicenow.read,servicenow.write
    ports:
      - 8004:8004
    volumes:
      - ./mcp_policies.json:/app/mcp_policies.json
```

Run the service:

```bash
docker-compose up -d
```

#### Configure `mcp.json` for AI Integration

Recommended: Store secrets in environment variables with lookup in the JSON file.

For Testing Only: Plain text storage will also work, although **not** recommended.

```json
{
  "mcpServers": {
    "servicenow": {
      "command": "uv",
      "args": [
        "run",
        "--with",
        "servicenow-api",
        "servicenow-mcp",
        "--transport",
        "${TRANSPORT}",
        "--host",
        "${HOST}",
        "--port",
        "${PORT}",
        "--auth-type",
        "${AUTH_TYPE}",
        "--eunomia-type",
        "${EUNOMIA_TYPE}",
        "--enable-delegation",
        "${ENABLE_DELEGATION}",
        "--servicenow-audience",
        "${SERVICENOW_AUDIENCE}",
        "--delegated-scopes",
        "${DELEGATED_SCOPES}"
      ],
      "env": {
        "SERVICENOW_INSTANCE": "https://yourinstance.servicenow.com",
        "SERVICENOW_USERNAME": "user",
        "SERVICENOW_PASSWORD": "pass",
        "SERVICENOW_CLIENT_ID": "client_id",
        "SERVICENOW_CLIENT_SECRET": "client_secret",
        "SERVICENOW_VERIFY": "False",
        "TOKEN_JWKS_URI": "${TOKEN_JWKS_URI}",
        "TOKEN_ISSUER": "${TOKEN_ISSUER}",
        "TOKEN_AUDIENCE": "${TOKEN_AUDIENCE}",
        "OAUTH_UPSTREAM_AUTH_ENDPOINT": "${OAUTH_UPSTREAM_AUTH_ENDPOINT}",
        "OAUTH_UPSTREAM_TOKEN_ENDPOINT": "${OAUTH_UPSTREAM_TOKEN_ENDPOINT}",
        "OAUTH_UPSTREAM_CLIENT_ID": "${OAUTH_UPSTREAM_CLIENT_ID}",
        "OAUTH_UPSTREAM_CLIENT_SECRET": "${OAUTH_UPSTREAM_CLIENT_SECRET}",
        "OAUTH_BASE_URL": "${OAUTH_BASE_URL}",
        "OIDC_CONFIG_URL": "${OIDC_CONFIG_URL}",
        "OIDC_CLIENT_ID": "${OIDC_CLIENT_ID}",
        "OIDC_CLIENT_SECRET": "${OIDC_CLIENT_SECRET}",
        "OIDC_BASE_URL": "${OIDC_BASE_URL}",
        "REMOTE_AUTH_SERVERS": "${REMOTE_AUTH_SERVERS}",
        "REMOTE_BASE_URL": "${REMOTE_BASE_URL}",
        "ALLOWED_CLIENT_REDIRECT_URIS": "${ALLOWED_CLIENT_REDIRECT_URIS}",
        "EUNOMIA_TYPE": "${EUNOMIA_TYPE}",
        "EUNOMIA_POLICY_FILE": "${EUNOMIA_POLICY_FILE}",
        "EUNOMIA_REMOTE_URL": "${EUNOMIA_REMOTE_URL}",
        "ENABLE_DELEGATION": "${ENABLE_DELEGATION}",
        "SERVICENOW_AUDIENCE": "${SERVICENOW_AUDIENCE}",
        "DELEGATED_SCOPES": "${DELEGATED_SCOPES}"
      },
      "timeout": 200000
    }
  }
}
```

#### Middleware

The MCP server includes the following built-in middleware for enhanced functionality:

- **ErrorHandlingMiddleware**: Provides comprehensive error logging and transformation.
- **RateLimitingMiddleware**: Limits request frequency with a token bucket algorithm (10 requests/second, burst capacity of 20).
- **TimingMiddleware**: Tracks execution time of requests.
- **LoggingMiddleware**: Logs all requests and responses for observability.
- **UserTokenMiddleware**: Extracts Bearer tokens for OIDC token delegation to ServiceNow (enabled with `--enable-delegation`).

#### Eunomia Authorization

The server supports optional Eunomia authorization for policy-based access control:

- **Disabled (`none`)**: No authorization checks.
- **Embedded (`embedded`)**: Runs an embedded Eunomia server with a local policy file (`mcp_policies.json` by default).
- **Remote (`remote`)**: Connects to an external Eunomia server for centralized policy decisions.

To configure Eunomia policies:

**Embedded Eunomia:**

`mcp_policies.json`

```json
{
  "policies": [
    {
      "id": "servicenow_read_policy",
      "description": "Allow read-only tools if user has read scope",
      "allow": true,
      "conditions": [
        {
          "tool": ["get_application", "get_cmdb", "batch_install_result"],  // Per-tool targeting
          "scopes": ["servicenow.read", "servicenow.full"]  // Like your PRODUCT_READ_SCOPE
        }
      ]
    },
    {
      "id": "servicenow_write_policy",
      "description": "Allow write tools if user has write scope and is admin",
      "allow": true,
      "conditions": [
        {
          "tool": ["batch_install", "batch_rollback", "app_repo_install"],  // Write tools
          "scopes": ["servicenow.write", "servicenow.full"],  // Like your PRODUCT_WRITE_SCOPE
          "claims": {"role": "admin"}  // Extra claim check (from JWT)
        }
      ]
    },
    {
      "id": "default_deny",
      "description": "Deny all other access",
      "allow": false
    }
  ]
}
```

```bash
# Initialize a default policy file
eunomia-mcp init

# Validate the policy file
eunomia-mcp validate mcp_policies.json
```

</details>

<details>
  <summary><b>Installation Instructions:</b></summary>

Install Python Package

```bash
python -m pip install servicenow-api eunomia-mcp
```

</details>

<details>
  <summary><b>Tests:</b></summary>

```bash
python ./test/test_servicenow_models.py
```

</details>

<img width="100%" height="180em" src="https://github-readme-stats.vercel.app/api?username=Knucklessg1&show_icons=true&hide_border=true&&count_private=true&include_all_commits=true" />

![GitHub followers](https://img.shields.io/github/followers/Knucklessg1)

![GitHub User's stars](https://img.shields.io/github/stars/Knucklessg1)

[![MseeP.ai Security Assessment Badge](https://mseep.net/pr/knuckles-team-servicenow-api-badge.png)](https://mseep.ai/app/knuckles-team-servicenow-api)
