Skip to main content
Glama
pavithrakumaran10

ServiceNow MCP Server

ServiceNow Developer Actions — MCP Server

An MCP server that connects Claude Desktop (or any MCP client) to a ServiceNow instance, exposing guarded developer actions as natural-language tools. Claude can read incidents, inspect CMDB and table schemas, and create records — with every write isolated to a scoped Update Set, restricted to an allowlist of tables, and protected by a dry-run preview.

Built with FastMCP, a typed REST client, and an explicit guardrail layer — the difference between an LLM API wrapper and an agent tool you'd let near a production instance.


Why this project

This demonstrates two skill sets at once:

  • AI engineering / agent architecture — agentic tool design with safety rails: input schemas (Pydantic), an allowlist + blocklist for writable tables, automatic Update Set scoping, and a dry_run mode on risky tools so the model previews intent before mutating anything.

  • ServiceNow integration architecture — a resilient Table API client with OAuth2 (with Basic-auth fallback), token refresh on 401, and exponential backoff on 429/5xx, plus CMDB and sys_dictionary introspection tools.


Related MCP server: ServiceNow MCP Server

Architecture

Claude Desktop / Claude Code
   │  (MCP protocol over stdio)
   ▼
FastMCP Server  ── server.py
   │
   ├── tools (read)   get_incidents · query_table · query_records · get_record
   │                  describe_table · get_cmdb_cis · get_update_set
   ├── tools (write)  create_incident · create_script_include · create_record
   │                  update_record · execute_background_script   ← guarded
   │
   ├── guardrails.py  allowlist · blocklist · update-set enforcement · dry-run
   ▼
ServiceNowClient  ── client.py   (OAuth2 / Basic · retry · backoff · typed errors)
   │  REST (Table API + a companion Scripted REST resource for script execution)
   ▼
ServiceNow instance (PDI)

Tools

Tool

Type

Notes

get_incidents

read

Newest-first, active filter

query_table

read

GlideRecord-style query on any table

query_records

read

Like query_table, with explicit field selection

get_record

read

Fetch a single record by sys_id

describe_table

read

Field inspection via sys_dictionary

get_cmdb_cis

read

List CIs from a CMDB class

get_update_set

read

List changes currently inside an Update Set, for review

create_incident

write

Allowlisted, Update-Set enforced, dry_run

create_script_include

write

dry_run=True by default

create_record

write

Any allowlisted table (Business Rules, UI Actions, Flows…)

update_record

write

Patch a field (e.g. script) on any allowlisted table

execute_background_script

write

Preview-only by default; confirm=True required to run

Guardrails

Guardrail

What it does

Enforced by

Writable allowlist

Only dev-artifact tables (sys_script, sys_script_include, sys_script_client, sys_ui_action, sys_ui_page, catalog_script_client, sys_hub_flow, incident, sc_req_item, task) may be written.

assert_writable()

Blocklist wins

Security/identity tables (sys_user, sys_user_group, sys_security_acl, sys_user_role, sys_properties) are refused even if a table were also allowlisted.

assert_writable() (blocklist checked first)

Update Set enforcement

Before any write, the server resolves MCP_DEV_UPDATE_SET_ID, confirms it's a real in progress Update Set, makes it the current set for the authenticated user (via sys_user_preference), and reads that preference back to confirm before proceeding. Unset, not found, not in-progress, or unconfirmed → the write is refused. No write can silently land in Default or in whatever set was last active.

ensure_update_set()

Dry-run by default

create_script_include, create_record, update_record, and execute_background_script default to previewing rather than writing; you opt in per call.

dry_run / confirm params

Background script two-step

execute_background_script always returns the script text plus a best-effort static scan of GlideRecord table references first. It only executes when called again with confirm=True — never automatically.

execute_background_script()

Confirmation summary

Every successful write returns table, sys_id, changed fields, and the Update Set it landed in.

write_result()

Setting up execute_background_script

The Table API has no native endpoint for ad hoc script execution, so this tool POSTs to a small Scripted REST resource you create once on the PDI (Studio → Scripted REST APIs):

// Resource: POST /api/x_snc/mcp_dev/execute  (path must match SN_SCRIPT_EXEC_PATH)
(function process(request, response) {
    var body = request.body.data;
    var result;
    try {
        result = String(eval(body.script));
    } catch (e) {
        result = "ERROR: " + e.message;
    }
    return { result: result };
})(request, response);

Scope this resource's ACL to an admin-only role — it is equivalent to background script access and should never be broadly exposed.

Build a Business Rule by chat

  1. "Show me the field name for the incident summary." → Claude calls describe_table("incident") to confirm before writing code against it.

  2. "Create a Business Rule called 'Auto-assign VPN incidents' on incident, before insert, that sets assignment_group when short_description contains 'VPN'. Dry run first." → Claude calls create_record("sys_script", {...}, dry_run=True) and shows you the payload it would insert.

  3. "Looks right, go ahead." → Claude re-calls with dry_run=False. ensure_update_set() confirms MCP_DEV_UPDATE_SET_ID is current, the record is inserted, and you get back table / sys_id / fields / Update Set in the response.

  4. "What's in the Update Set so far?" → Claude calls get_update_set() and lists every change recorded, so you can review before promoting or exporting it.


Setup

git clone <your-repo-url> && cd servicenow-mcp
python -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
cp .env.example .env        # fill in your PDI URL, credentials, and MCP_DEV_UPDATE_SET_ID
pytest                      # all green

Connect to Claude Desktop

Add to claude_desktop_config.json (Developer → Open App Configuration File), then restart:

{
  "mcpServers": {
    "servicenow": {
      "command": "python",
      "args": ["-m", "servicenow_mcp.server"],
      "cwd": "/absolute/path/to/servicenow-mcp/src",
      "env": {
        "SN_URL": "https://dev.service-now.com/",
        "SN_USER": "user",
        "SN_PASS": "pass",
        "SN_UPDATE_SET": "MCP Automated Changes",
        "MCP_DEV_UPDATE_SET_ID": "sys_id_of_your_dev_update_set"
      }
    }
  }
}

A 🔧 indicator confirms the tools loaded. Then try:

"Show me the 5 newest active incidents" "Describe the cmdb_ci_server table" "Create an incident: VPN gateway down, urgency high — dry run first"


Tech

Python 3.10+ · FastMCP · Pydantic v2 · requests · pytest + responses

Roadmap

  • OAuth client-credentials grant (service account)

  • commit_to_source_control tool wrapping Studio's Git integration

  • Read-through cache for schema/CMDB lookups

  • Structured audit log of every write the server performs


Author: Pavithra Kumaran S — ServiceNow Senior Consultant exploring AI agent architecture.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    D
    maintenance
    Enables Claude to interact with ServiceNow instances through comprehensive API integration. Supports incident management, service catalog operations, change requests, knowledge base management, user administration, and agile project management with multiple authentication methods.
    82
    MIT
  • A
    license
    Not graded
    quality
    Not graded
    maintenance
    Enables Claude to interact with ServiceNow instances for incident management, service catalog operations, change requests, knowledge base management, user administration, and agile project workflows through various authentication methods.
    -