servicenow-mcp
# servicenow-mcp
An MCP server for managing ServiceNow incidents via the Table API. Exposes tools to create,
read, update, search, comment on, and resolve incidents.
## Setup
1. Install dependencies:
```bash
uv sync
```
2. Copy `.env.example` to `.env` and fill in your credentials:
```bash
cp .env.example .env
```
- `SERVICENOW_INSTANCE`: the instance name only (e.g. `dev12345` for `dev12345.service-now.com`)
- `SERVICENOW_USERNAME` / `SERVICENOW_PASSWORD`: basic auth credentials for a user with
access to the `incident` table (read/write via the Table API)
3. Run the server directly to sanity-check it starts:
```bash
uv run servicenow-mcp
```
## Using with Claude Desktop / Claude Code
There are two ways to connect, depending on whether you want everyone using the server to
share one ServiceNow service account, or each person to authenticate as themselves. See
[Authentication](#authentication) below for the full picture.
### Option A — stdio, shared service account
The client launches the server itself as a subprocess; every tool call uses the
`SERVICENOW_USERNAME` / `SERVICENOW_PASSWORD` passed in via `env`.
```json
{
"mcpServers": {
"servicenow": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/servicenow-mcp", "run", "servicenow-mcp"],
"env": {
"SERVICENOW_INSTANCE": "your-instance",
"SERVICENOW_USERNAME": "your-username",
"SERVICENOW_PASSWORD": "your-password"
}
}
}
}
```
### Option B — HTTP, per-client credentials
Start the server once as a long-running HTTP process (it only needs `SERVICENOW_INSTANCE`,
plus `SERVICENOW_USERNAME`/`PASSWORD` as a fallback for requests with no auth header):
```bash
uv run servicenow-mcp --transport streamable-http --host 127.0.0.1 --port 8003
```
Then point `.mcp.json` at it and send your own ServiceNow login as an HTTP Basic Auth
header — this is what makes the connection "client level": the credentials live in your
client config, not the server's:
```json
{
"mcpServers": {
"servicenow": {
"type": "http",
"url": "http://127.0.0.1:8003/mcp",
"headers": {
"Authorization": "Basic <base64 of your-username:your-password>"
}
}
}
}
```
Generate the base64 value from a terminal (note the leading space, which `-n` on `echo`
avoids):
```bash
echo -n "your-username:your-password" | base64
```
`.mcp.json` isn't covered by `.gitignore` the way `.env` is — don't commit real credentials
into it if this directory ever becomes a shared/git repo.
## Tools
- `create_incident` — create a new incident
- `get_incident` — fetch by number (e.g. `INC0010023`) or sys_id
- `update_incident` — update arbitrary fields
- `search_incidents` — search with a ServiceNow encoded query (`sysparm_query`)
- `add_comment` — add a customer-visible comment or internal work note
- `resolve_incident` — set state to Resolved with close notes/code
## Authentication
Auth is basic auth (username/password). Where those credentials come from depends on transport:
- **stdio**: always uses the shared `SERVICENOW_USERNAME` / `SERVICENOW_PASSWORD` from `.env`.
- **HTTP (`sse` / `streamable-http`)**: each request can authenticate as its own ServiceNow
user by sending a standard HTTP Basic Auth header:
```
Authorization: Basic base64(username:password)
```
`SERVICENOW_INSTANCE` stays server-side (it's one instance for all clients), but the
username/password are per-client — so `search_incidents` results, `caller_id` resolution,
etc. reflect that individual user's ServiceNow permissions instead of one shared service
account. If a request has no `Authorization` header, it falls back to the shared
`SERVICENOW_USERNAME` / `SERVICENOW_PASSWORD` from `.env`.
If you need OAuth 2.0 later, swap the `requests.Session.auth` setup in
`src/servicenow_mcp/client.py` for a token-based flow — the rest of the client is
auth-agnostic.
## Notes
- The incident table's `state` field is numeric (e.g. `6` = Resolved, `7` = Closed); values
can differ if your instance customizes incident states.
TDQS
Scored across 6 tools
Each tool has a clear, distinct purpose covering the full incident lifecycle: get, create, update, search, add comment, and resolve. There is no overlap or ambiguity between them.
Tools follow a verb_noun pattern (e.g., get_incident, create_incident). The only minor deviation is 'add_comment' which is still verb_noun but lacks the 'incident' suffix, though it is clearly contextual.
Six tools is an ideal size for an incident management MCP server. Each tool serves a necessary operation without being too many or too few, keeping the surface focused and manageable.
Core incident operations are covered: create, read, update, search, comment, and resolve. Missing an explicit delete tool, but ServiceNow incidents are typically not deleted; update can handle assignment. Minor gap but still robust.