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.
- 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.
- 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_configandincident_categoriesfor ServiceNow configuration and data. - Prompts: Includes
create_incident_promptandquery_table_promptfor 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.
Usage:
| 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) |
| 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) |
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:
servicenow-mcp --transport "stdio"servicenow-mcp --transport "http" --host "0.0.0.0" --port "8000"Embedded Eunomia:
mcp_policies.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:
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"# 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# 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# 3. Static RSA Key (Dev)
servicenow-mcp --auth-type jwt \
--token-public-key ./public_key.pem \
--token-issuer test-issuer \
--token-audience test-mcp# 4. With Delegation
--enable-delegation --auth-type jwt ... (uses JWT as subject_token)#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"#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"#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
# 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"The servicenow-a2a tool hosts an Agent-to-Agent (A2A) server that orchestrates specialized child agents for different ServiceNow domains.
servicenow-a2a --port 9000 --provider openai --model-id gpt-4oYou can run the A2A server using the same Docker image by overriding the command.
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/mcpNote: The A2A agent requires a running MCP server to function. In the example above,
host.docker.internalallows 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.
OAuth Authentication
#!/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
#!/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
#!/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()}")The ServiceNow MCP server can be deployed using Docker, with configurable authentication, middleware, and Eunomia authorization.
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:latestFor advanced authentication (e.g., OIDC Proxy with token delegation) or Eunomia, add the relevant environment variables:
For Additional OpenAPI Tool Import, include OPENAPI_FILE.
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:latestCreate a docker-compose.yml file:
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:8004For advanced setups with authentication, token delegation, and Eunomia:
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.jsonRun the service:
docker-compose up -dRecommended: Store secrets in environment variables with lookup in the JSON file.
For Testing Only: Plain text storage will also work, although not recommended.
{
"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
}
}
}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).
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.jsonby default). - Remote (
remote): Connects to an external Eunomia server for centralized policy decisions.
To configure Eunomia policies:
Embedded Eunomia:
mcp_policies.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
}
]
}# Initialize a default policy file
eunomia-mcp init
# Validate the policy file
eunomia-mcp validate mcp_policies.jsonInstallation Instructions:
Install Python Package
python -m pip install servicenow-api eunomia-mcpTests:
python ./test/test_servicenow_models.py