servicenow-mcp
MCP server for ServiceNow that exposes Table, Aggregate, and schema APIs as tools with a write gate protecting against unintended modifications.
README
servicenow-mcp
Standalone MCP server for ServiceNow. Exposes the Table, Aggregate, and schema APIs as tools, with an in-process update-set write gate: write tools are only registered when explicitly enabled, and every write is refused while your current update set is "Default".
Works with Claude Code, Claude Desktop, Antigravity CLI, opencode, GitHub Copilot CLI, GitHub Copilot in VS Code, and any other MCP client (stdio transport).
Requirements
- Node.js >= 20.6
- A ServiceNow instance reachable with Basic Auth (username/password)
Install
git clone https://github.com/JoseanMeonez/servicenow-mcp.git
cd servicenow-mcp
npm install
npm run build
Configuration
All configuration is via environment variables (a .env file in the repo root is also loaded
when present — see .env.example):
| Variable | Default | Description |
|---|---|---|
SN_BASE_URL |
— (required) | Instance URL, e.g. https://dev12345.service-now.com |
SN_USERNAME |
— (required) | Basic Auth username |
SN_PASSWORD |
— (required) | Basic Auth password |
SN_MCP_ALLOW_WRITES |
false |
Register write tools (create/update/delete/set update set) |
SN_MCP_REQUIRE_UPDATE_SET |
true |
Refuse writes while the current update set is "Default" |
SN_MCP_DEFAULT_LIMIT |
50 |
Default query page size |
SN_MCP_MAX_LIMIT |
500 |
Hard ceiling on any requested limit |
SN_MCP_REQUEST_TIMEOUT_MS |
30000 |
Per-request timeout |
SN_MCP_RETRY_MAX_ATTEMPTS |
3 |
Attempts for 429/5xx responses (honors Retry-After) |
Changing SN_MCP_ALLOW_WRITES requires restarting the MCP server process — tools are
registered at startup, not per call.
Instance user setup (required per instance)
Recent ServiceNow releases do not accept Basic Auth on the REST API by default. For every
instance you connect, the user in SN_USERNAME must be set up as follows:
- Roles: grant
snc_basic_auth_api_access(mandatory for Basic Auth REST access) plus the roles needed for the tables you will touch. On a personal dev instanceadminis fine; at work prefer least-privilege roles overadmin. - Integration user flag: on the
sys_userrecord, setinternal_integration_user = true. - Recommended: use a dedicated integration user (e.g.
api.tester), never a personal or theadminaccount, so API access can be rotated or revoked independently.
Symptom when this is missing: every request fails with
401 "User is not authenticated" even though the credentials are correct. The server's error
output includes this hint automatically on 401 responses.
Register with Claude Code
claude mcp add servicenow-mcp -- node C:/Users/you/path/to/servicenow-mcp/dist/index.js
or copy .mcp.json.example into your project's .mcp.json and adjust path + env.
Register with Claude Desktop
Claude Desktop uses a different config file than Claude Code:
%APPDATA%\Claude\claude_desktop_config.json (Windows). Add under mcpServers, using the
full path to node.exe (Desktop may not inherit your shell PATH):
{
"mcpServers": {
"servicenow-dev": {
"command": "C:\\Program Files\\nodejs\\node.exe",
"args": [
"--env-file=C:/path/to/servicenow-mcp/instances/dev.env",
"C:/path/to/servicenow-mcp/dist/index.js"
]
}
}
}
Then fully quit Claude Desktop (system tray → Quit, not just closing the window) and reopen it — the config is only read at startup.
Register with Antigravity CLI
Antigravity CLI's MCP config lives at ~/.gemini/antigravity-cli/mcp_config.json (it shares
the Gemini CLI config layout, not ~/.antigravitycli). Add under mcpServers:
{
"mcpServers": {
"servicenow-dev": {
"command": "node",
"args": [
"--env-file=C:/path/to/servicenow-mcp/instances/dev.env",
"C:/path/to/servicenow-mcp/dist/index.js"
]
}
}
}
Start a new Antigravity CLI session afterward — config is only read at startup, an existing session won't pick it up.
Prompt to hand to Antigravity CLI (or any agent with file-edit access) to do this for you:
Add a new entry under
mcpServersin~/.gemini/antigravity-cli/mcp_config.jsonnamedservicenow-<instance>, pointing tonodewith args--env-file=<absolute path to instances/<instance>.env>and<absolute path to dist/index.js>. Keep existing entries intact. Then tell me to start a new session for it to take effect.
Register with opencode
Add under mcp in ~/.config/opencode/opencode.json (or your project's opencode.json):
{
"mcp": {
"servicenow-dev": {
"enabled": true,
"type": "local",
"command": [
"node",
"--env-file=C:/path/to/servicenow-mcp/instances/dev.env",
"C:/path/to/servicenow-mcp/dist/index.js"
]
}
}
}
Note the command and its args live together in a single array (unlike Claude's
command/args split).
Prompt to hand to opencode:
Add a new entry under
mcpin~/.config/opencode/opencode.jsonnamedservicenow-<instance>, with"type": "local","enabled": true, andcommandas an array:["node", "--env-file=<absolute path to instances/<instance>.env>", "<absolute path to dist/index.js>"]. Keep existing entries intact.
Register with GitHub Copilot CLI
Copilot CLI's config lives at ~/.copilot/mcp-config.json (override via COPILOT_HOME).
Add under mcpServers, with an explicit "type": "stdio":
{
"mcpServers": {
"servicenow-dev": {
"type": "stdio",
"command": "node",
"args": [
"--env-file=C:/path/to/servicenow-mcp/instances/dev.env",
"C:/path/to/servicenow-mcp/dist/index.js"
],
"env": {}
}
}
}
Or from the terminal: copilot mcp add (interactive), then verify with /mcp show inside a
Copilot CLI session.
Prompt to hand to Copilot CLI:
Add a new entry under
mcpServersin~/.copilot/mcp-config.jsonnamedservicenow-<instance>, with"type": "stdio",command: "node", and args["--env-file=<absolute path to instances/<instance>.env>", "<absolute path to dist/index.js>"]. Keep existing entries intact. Then run/mcp showto confirm it loaded.
Register with GitHub Copilot in VS Code
VS Code Copilot uses .vscode/mcp.json in the workspace (commit it to share with your team),
with the root key servers — not mcpServers like the other clients:
{
"servers": {
"servicenow-dev": {
"type": "stdio",
"command": "node",
"args": [
"--env-file=C:/path/to/servicenow-mcp/instances/dev.env",
"C:/path/to/servicenow-mcp/dist/index.js"
]
}
}
}
Saving the file with valid JSON restarts the Copilot agent and reloads servers automatically — no full VS Code restart needed.
Prompt to hand to Copilot Chat in VS Code:
Create or update
.vscode/mcp.jsonin this workspace: add an entry underservers(notmcpServers) namedservicenow-<instance>, with"type": "stdio",command: "node", and args["--env-file=<absolute path to instances/<instance>.env>", "<absolute path to dist/index.js>"]. Keep existing entries intact.
Multiple instances
The recommended pattern is one server process per instance, each declared as its own
entry in .mcp.json and pointed at a per-instance profile file via Node's native
--env-file flag (before the script path):
{
"mcpServers": {
"servicenow-dev": {
"command": "node",
"args": ["--env-file=/path/to/instances/dev.env", "/path/to/dist/index.js"]
},
"servicenow-prod": {
"command": "node",
"args": ["--env-file=/path/to/instances/prod.env", "/path/to/dist/index.js"]
}
}
}
Node fails fast if the profile file is missing, and real environment variables take precedence over file values.
Why per-process instead of one multi-tenant server:
- Zero shared state. The server holds no caches and no sessions (see below); separate processes make cross-instance leakage structurally impossible, not just avoided.
- Per-instance write policy. A prod profile with
SN_MCP_ALLOW_WRITES=false(or simply omitting it) never even registers write tools — the client cannot call what does not exist. - Clear tool naming. Tools surface as
mcp__servicenow-dev__*vsmcp__servicenow-prod__*, so it is always explicit which instance a call targets. - Independent rate limits. ServiceNow enforces inbound REST rate limits per user per instance, so parallel processes against different instances never interact.
To add a new instance in one step, use the helper — it writes the profile file with correct password quoting and prints the registration command:
npm run add-instance -- work https://mycompany.service-now.com api.integration 'the-password'
Keep profile files (e.g. instances/*.env) out of git — the .gitignore already excludes
.env and instances/.
Statelessness guarantees
- No record, schema, or token caching — every tool call hits the instance fresh.
- Basic Auth header is computed per request; response cookies are ignored (no cookie jar), so no ServiceNow session is retained between calls.
- The write gate re-reads your current update set from the instance on every write.
If a metadata cache (e.g. table schemas) ever becomes worth it, it should be explicit, on-disk, and per-instance — never implicit in-process memory.
Tools
Read tools (always registered):
| Tool | Description |
|---|---|
servicenow_query_records |
Query a table with an encoded query; paginated (hasMore/nextOffset) |
servicenow_get_record |
Fetch one record by sys_id |
servicenow_get_aggregate |
Stats API: count/avg/sum/min/max, optionally grouped |
servicenow_get_table_schema |
Field list from sys_dictionary, including inherited fields |
servicenow_get_current_update_set |
Show your current update set |
Write tools (only when SN_MCP_ALLOW_WRITES=true):
| Tool | Description |
|---|---|
servicenow_create_record |
Create a record (gated) |
servicenow_update_record |
Update a record (gated) |
servicenow_delete_record |
Delete a record (gated, requires confirm: true) |
servicenow_set_current_update_set |
Switch your current update set (how you move off "Default") |
The write gate
Every write first resolves your current update set on the instance
(sys_user_preference → sys_update_set). If it is "Default", the write is refused with a
clear error telling you to switch sets first. This keeps AI-driven changes tracked in a real
update set, the same discipline you'd apply by hand. Disable with
SN_MCP_REQUIRE_UPDATE_SET=false (e.g. for non-development instances).
Development
npm run dev # run from source (tsx)
npm test # unit + in-memory integration tests
npm run test:live # live smoke tests (needs SN_* env or .env; read-only)
npm run inspect # MCP Inspector against dist/index.js
npm run ci # lint + build + test
Known limitations
- Basic Auth only (v1). If your instance enforces SSO/MFA for API access, requests fail
with a "possible SSO/MFA redirect" error. An OAuth or session-based
AuthStrategyis the planned phase 2 (src/client/auth.tsis the single seam to extend). - Schema from
sys_dictionary. Portable to every instance (including PDIs), but virtual/ computed fields may be missing compared to/api/now/doc/table/schema. - PDI hibernation. Personal developer instances sleep after inactivity; wake yours in a browser before running live tests.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。