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.
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.
Let AI agents query data and act across all your business apps via MCP.
An AI concierge that turns static forms into adaptive AI conversations. From any MCP client.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables natural language interaction with ServiceNow instances for managing incidents, changes, CMDB, service catalog, users, groups, and knowledge base via MCP.4126 npm1MIT
- 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.151,918 PyPI4MIT
- AlicenseCqualityAmaintenanceEnables AI to interact with ServiceNow instances via MCP, providing 400+ tools across all modules for automation, development, and management.5002,492 npm17Elastic 2.0
- AlicenseNot gradedqualityDmaintenanceMCP server to interact with ServiceNow instances, enabling ITSM, CMDB, workflow, and knowledge search operations.MIT