Open Now
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Open NowShow me all open high-priority incidents assigned to me and summarize them."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Open Now — Headless MCP for ServiceNow
Open Now is a headless MCP interface for ServiceNow: a small, stable MCP kernel, a curated skill catalog that encodes how real work is done (ITSM/CMDB/ITOM/SPM/CSM/HRSD/SecOps/platform), a generated toolkit for metadata-driven table/record/script access, and an in-instance runtime (sn_headless scoped app) that keeps every read and write inside ServiceNow's ACL, Business Rule, and Data Policy fabric.
The invariant: the AI client orchestrates; ServiceNow remains the governed system of action. The kernel is protocol only — all capability, permission, and audit logic runs in the instance as the invoking user. No Table API in the kernel, no service account on the interactive path.
Design spec:
docs/spec.md· Wire contract:docs/wire-contract.md· Implementation plan:docs/implementation-plan.md
How it fits together
flowchart LR
subgraph Client["Any MCP client (Claude, Copilot, Grok, CLI...)"]
C1[discover / describe / dispatch_readonly / dispatch]
end
subgraph Kernel["open-now mcp-server (Bun/TS)"]
T[4 stable kernel tools + toolkit + confirm policy + OAuth PKCE session]
end
subgraph Instance["ServiceNow instance"]
REST[Scripted REST sn_headless]
RT[SkillRuntime + QueryGuard + RecordResolver + ConfirmGate]
EXEC[Skill executables - Script Includes]
GLIDE[GlideRecordSecure = real ACLs, Business Rules, Data Policies, Flows]
end
C1 -- MCP --> T -- token-bound REST, as user --> REST --> RT --> EXEC --> GLIDEThree components, one contract (packages/contracts):
Component | Path | What it owns |
MCP kernel |
| The four tools, confirmation protocol, OAuth/PKCE, sessions, domain modes |
Instance runtime |
| Skill registry, audit, discover index, query guard, planners/appliers (scoped app update set) |
Skill catalog |
| 32 validated skill documents (the contract source of truth; seeded into the registry) |
Related MCP server: servicenow-platform-mcp
Quickstart (PDI or subprod)
Build the app —
bun run build:appproducesdist/sn_headless/update-set.xml.Install it — System Update Sets → Load XML, then activate the
sn_headlessscope. Full PDI walkthrough:instance/bootstrap/README.md.Create an OAuth app in the instance (System OAuth → Application Registry): grant type Authorization Code, PKCE enabled, redirect URI = your server URL +
/oauth/callback. Copy the client id.Configure the server (env or
--config file.json; see Configuration).Seed the catalog —
bun run seed(imports all 32 skill documents into the registry;--dry-runto preview).Run — stdio for local/builder use, HTTP for interactive clients:
# stdio (static per-user token) OPEN_NOW_INSTANCE_URL=https://dev123456.service-now.com \ OPEN_NOW_ACCESS_TOKEN=<your-token> \ bun run packages/mcp-server/src/bin/open-now.ts --transport stdio # http (per-user OAuth sign-in) OPEN_NOW_INSTANCE_URL=https://dev123456.service-now.com \ OPEN_NOW_OAUTH_CLIENT_ID=<client-id> \ bun run packages/mcp-server/src/bin/open-now.ts --transport httpConnect a client — e.g. Claude Desktop (
claude_desktop_config.json):{ "mcpServers": { "open-now": { "command": "bun", "args": ["run", "packages/mcp-server/src/bin/open-now.ts", "--transport", "stdio"], "env": { "OPEN_NOW_INSTANCE_URL": "https://dev123456.service-now.com", "OPEN_NOW_ACCESS_TOKEN": "<your-token>" } } } }In HTTP mode the client signs in at
/oauth/authorize; each MCP session is bound to the resulting user token. Pass the session via theMcp-Session-Idheader orAuthorization: Bearer <sessionId>(the/oauth/tokenendpoint mints the session id as an opaque token).
One quick check
bun run eval -- --gateway mock # 9 golden steps, no instance requiredUsing the tools
The kernel tool surface is intentionally four stable tools (spec §3.3); the action surface grows behind them — via the 32-skill catalog and the generated toolkit (see below) — so the model context never has to absorb hundreds of tool descriptions.
Default surface: 4 kernel tools + 32 curated skills + 10 generated toolkit tools. In table mode (OPEN_NOW_TOOLKIT=table) the toolkit expands to ~125 per-table tools; everything still routes through one instance-side trust boundary.
Tool | Purpose |
| Semantic/intent search over the skill index. Returns ranked skill ids + raw-operation fallbacks with a one-line why. |
| The technical contract: inputs, tables, roles, confirmation policy, related skills. Required before dispatch for write-class skills. |
| GET-equivalent only. Reads, aggregates, relationship walks, KB search. Never mutates. |
| Invoke a skill. Confirmation policy enforced: write-class returns a pending diff unless |
Example flow
discover("server down for the app team")
→ sn.cmdb.ci.find [0.9], sn.itsm.incident.triage [0.8], raw:incident [0.05]
describe("sn.itsm.incident.update")
→ { inputs: { incident_number, mode: comment|work_note|resolve, ... }, confirmation: update_owned, ... }
dispatch("sn.itsm.incident.update", { inputs: { incident_number: "INC0010001",
mode: "resolve", resolution_code: "fixed", resolution_notes: "rebooted" } })
→ { outcome: "pending", diff: [ { field: "state", before: "1", after: "6" }, ... ],
auditId: "...", requestId needed for confirm }
dispatch("sn.itsm.incident.update", { inputs: {...}, confirm: true, requestId: "<same id>" })
→ { outcome: "applied", focusedPayload: { record_numbers: ["INC0010001"] } }Write semantics:
read— answered directly, never confirmed.update_owned+autoApplypolicy + record owned by caller — applied silently (policy is declared in the skill document; the kernel/registry enforce it).everything else —
pendingwith a field diff (or draft for create-class) until confirmed.resolvemode requiresresolution_code+resolution_notes; missing inputs come back asoutcome: "error"withmissingFields.same
requestIdtwice → Server replays the settled outcome; the applier never runs twice.GraphQL-shaped risk: HR/SecOps skills take structured inputs only — an itil user withoutsn_hr_core.case_writergetsdeniedbefore any HR-table query runs.
Raw fallback
dispatch on raw:incident ({ table, query, fields, limit }) is the builder escape hatch behind QueryGuard (allowlisted operators, capped windows, field allowlists, no JS:/GOTO). It always shows as a discover candidate but is never the default path for operators.
Toolkit — the generated wide surface
Beyond the 32 skills, a generated toolkit covers any table without hand-written glue — all still executed in the instance through QueryGuard/RecordResolver/ConfirmGate/audit. No Table API in the kernel, no service account, ever.
Generic mode (default, OPEN_NOW_TOOLKIT=generic) — 10 tools, context-safe, metadata-driven:
Tool | Behavior |
| metadata from |
| one record by number or sys_id (role-gated on HR/SecOps tables) |
| draft/diff first → |
| server-side COUNT/AVG/MIN/MAX/SUM, optional groupBy — no row dumps |
| short server-side Glide script, eval'd in the scoped runtime |
| attachments per record (base64, draft-then-confirm) |
Table mode (OPEN_NOW_TOOLKIT=table) — NowAIKit-style breadth: tbl_<table>_{query,get,create,update,delete} generated per table from OPEN_NOW_TABLE_TOOLS (comma list; default is a core ~25-table allowlist → ~125 tools). Everything routes to the same runtime — one audit model, same confirm semantics. Set OPEN_NOW_TABLE_TOOLS= to disable, or list exactly the tables you want.
table_schema({ table: "incident" }) → fields from sys_dictionary
record_update({ table: "incident", number: "INC0010001", values: { state: "2" } })
→ pending (field diff) → confirm:true + same requestId → applied (exactly once)
record_delete({ table: "incident", number: "INC0010001" })
→ pending ("Deletes require confirmation") → confirm:true → deleted
run_script({ script: "new GlideRecord('incident').getRowCount()" }) → resultSkill catalog
32 skills ship today (all validated against the contracts schema; every doc has a matching Exec* planner + applier — enforced by tests):
P1 (22): shift briefing, incident triage/similar/update/major, problem open, change draft/assess-risk/CAB-prep/implement, request submit/fulfill, SLA at-risk, ITOM alert triage/correlate, CMDB CI find/blast-radius/service health, SPM portfolio, KB answer, my work, safe aggregate.
P2 (10): SPM project prep, CSM case briefing/update, HRSD case handle, SecOps SIR/vuln, platform schema describe, update set review, script impact, flow run.
Adding a skill: create packages/skill-docs/src/sn.<domain>.<obj>.<verb>.json (strict schema — SkillDoc in packages/contracts; one executable ref naming the domain Exec* class and plan_/apply_ methods), implement the method in the matching instance/sn_headless/script-includes/Exec*.js, re-run bun run build:app && bun run seed. bun test tests/unit/skill-docs.test.ts + tests/unit/instance/exec-methods.test.ts verify the binding.
Configuration
All settings via environment (defaults in parentheses) or --config file.json (same keys, camelCase):
Env var | Purpose |
| Instance URL, no trailing slash (required; |
|
|
| HTTP port (default |
| Static per-user token for stdio mode ( |
| OAuth application registry client id (http mode) |
| Defaults to |
| Comma-separated, default |
| SQLite path for session store (default in-memory) |
| Domain mode: expose only |
| Hard-require describe before any dispatch |
| Comma-separated allowlist |
| Generated wide surface: |
| Comma-separated table allowlist for table mode (empty = none; unset = core allowlist) |
Pause switch: each registry row has an active flag — a single flip pauses a skill sans deploy.
Development
bun install
bunx tsc --noEmit # typecheck
bun test tests/unit # 74 unit tests (kernel, runtime shim, catalog, builder)
bun run eval -- --gateway mock # golden protocol suite (9 steps, §8.4 cases)
bun run eval -- --gateway instance # same suite against a real instance (env-gated)
bun run bench # latency + token estimate per skill
bun run seed -- --dry-run # catalog import preview
bun run build:app # rebuild dist/sn_headless/update-set.xmlCI (.github/workflows/ci.yml) runs typecheck + unit tests + app build on every push; the integration job activates when SNOW_INSTANCE/SNOW_ACCESS_TOKEN secrets are present.
Instance-side tests use a Glide shim (tests/unit/helpers/glide-shim.ts) — no instance needed. Real ACL/BR verification runs via bun test tests/integration + --gateway instance against a PDI (see instance/bootstrap/README.md).
Security model (short version)
Default run-as is the invoking user; no impersonation, per-user OAuth + PKCE.
Writes fire real Business Rules/Data Policies/Approvals in the instance — the MCP layer never reimplements them.
Every dispatch writes an audit row (
sn_headless_run): actor, skill, tables, record numbers, query hash, outcome, latency. A dispatch without an audit line is a failed dispatch.Model queries are hostile:
QueryGuardallowlists operators/caps/fields, rejectsJS:/GOTO.Restricted tables (HR/SecOps/Legal) deny by role before any query; deletes are opt-in and off by default.
403is fail-closed: the skill returnsdeniedwith a reason; the client never retries with a broader query.
Repository layout
open-now/
├── README.md # this file (usage)
├── docs/ # spec.md (design), wire-contract.md, evaluation.md, implementation-plan.md
├── packages/
│ ├── contracts/ # zod schemas + types (single source for both sides)
│ ├── skill-docs/ # 32 skill documents (catalog source of truth)
│ ├── mcp-server/ # kernel, gateways, auth, domain modes, CLI
│ └── client-lib/ # typed client helpers for MCP hosts
├── instance/
│ ├── sn_headless/ # scoped app: app.json, script-includes/, rest/
│ └── bootstrap/ # PDI setup guide
├── scripts/ # build-app, seed, eval-runner, bench, export-update-set
├── tests/ # unit/, integration/, fixtures/ (goldens, mock gateway)
└── dist/ # built update set (git-ignored)This server cannot be deployed
Maintenance
Related MCP Connectors
Governed data discovery, exact queries, decisions, simulations, and runtime utilities over MCP.
Orchestration & technical-consulting MCP for end-to-end Salesforce, ServiceNow & HubSpot back-end.
Unified MCP Server is a remote MCP connector for AI agents and vertical AI products that provides access to 22,000+ authorized SaaS tools across 400+ integrations and 24 categories directly inside LLMs (Claude, GPT, Gemini, Cohere). Tools operate only on explicitly authorized customer connections, enabling agents to safely read and write against live third-party systems.
The governed runtime for agent skills. Search the catalog and inspect a skill before running it.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables natural language interaction with ServiceNow instances for managing incidents, changes, CMDB, service catalog, users, groups, and knowledge base via MCP.4116 npmMIT
- AlicenseAqualityAmaintenanceEnables AI agents to interact with ServiceNow through MCP, providing schema inspection, record CRUD, attachments, audit, Flow Designer, and platform investigations with policy-guarded access.15305 PyPI4MIT
- AlicenseNot gradedqualityCmaintenanceMCP server enabling interaction with ServiceNow API for managing incidents, CMDB, change management, and other ServiceNow operations via natural language.19MIT
- AlicenseCqualityAmaintenanceEnables AI to interact with ServiceNow instances via MCP, providing 400+ tools across all modules for automation, development, and management.500522 npm17Elastic 2.0