Skip to main content
Glama
MDK-s-Organisation

servicenow-mcp

README.md
# servicenow-mcp

An MCP server that connects Claude (or any MCP client) to your own ServiceNow instance through its standard REST API (Table API and Attachment API).

- Works with any instance: a personal developer instance or a company one.
- You sign in as yourself in the browser (OAuth with PKCE). No password is ever typed into or stored by this tool, and it can only see what your ServiceNow user can see.
- Read-only unless you turn writes on.
- One file, Node 18 or newer, no npm packages.

## Quick start

There are three steps: register an OAuth client on your instance (once), sign in, and add the server to your MCP client.

### 1. Register an OAuth client on your instance

This needs the admin role. On a company instance, ask your ServiceNow admin to do it and send you the client id.

1. In ServiceNow open **System OAuth > Application Registry** and choose **New**, then the option to create an OAuth API endpoint for external clients (on newer releases this is called a new inbound integration).
2. Grant type: **Authorization code**.
3. Client type: **Public** (no client secret, PKCE is used instead).
4. Redirect URL: `http://localhost:8787/callback`
5. Save it and copy the **Client ID**.

One client id can be shared by everyone on the same instance. Each person still signs in as themselves.

### 2. Sign in

```
npx -y github:MDK-s-Organisation/servicenow-mcp login
```

It asks for your instance and the client id, then opens the ServiceNow sign in page in your browser. When you approve, the tab says you can close it and the terminal prints who you are signed in as.

For the instance you can type the short name (`dev12345`), the host (`acme.service-now.com`) or the full URL (`https://acme.service-now.com`).

You can also pass everything up front:

```
npx -y github:MDK-s-Organisation/servicenow-mcp login --instance dev12345 --client-id <id>
```

Options: `--instance <url or name>`, `--client-id <id>`, `--port <n>` (default 8787, must match the redirect URL), `--no-open` (only print the link, do not open the browser).

### 3. Add it to your MCP client

`login` saves the instance, client id and port, so the server needs no extra settings.

Claude Code:

```
claude mcp add servicenow -- npx -y github:MDK-s-Organisation/servicenow-mcp
```

Claude Desktop, Cursor, VS Code and other clients that use a JSON config:

```json
{
  "mcpServers": {
    "servicenow": {
      "command": "npx",
      "args": ["-y", "github:MDK-s-Organisation/servicenow-mcp"]
    }
  }
}
```

Then ask your assistant something like "show my instance info" to check the connection.

## Running from a clone

If you prefer not to use `npx`:

```
git clone https://github.com/MDK-s-Organisation/servicenow-mcp.git
cd servicenow-mcp
node server.mjs login
```

There is nothing to build and nothing to `npm install`. Register it with the absolute path to the file:

```
claude mcp add servicenow -- node /absolute/path/to/servicenow-mcp/server.mjs
```

## Commands

```
node server.mjs            # run as an MCP server over stdio (what the MCP client starts)
node server.mjs login      # sign in
node server.mjs status     # instance, signed in or not, token expiry, writes on or off
node server.mjs logout     # delete the saved tokens
```

With `npx`, put the command after the package name, for example `npx -y github:MDK-s-Organisation/servicenow-mcp status`.

## Tools

Read tools, always available:

| Tool | What it does |
| --- | --- |
| `sn_instance_info` | Instance URL, signed in user, build tag, whether writes are allowed |
| `sn_table_query` | Query a table (encoded query, fields, limit up to 200, offset, order, display values) |
| `sn_table_get` | Read one record by sys_id |
| `sn_table_schema` | Columns of a table, from sys_dictionary |
| `sn_attachment_list` | List attachments of a table or a record |
| `sn_attachment_download` | Save an attachment to a local file (never returns the contents) |

Write tools, listed but refused unless writes are on:

| Tool | What it does |
| --- | --- |
| `sn_table_create` | Create a record |
| `sn_table_update` | Change fields on a record |
| `sn_table_delete` | Delete a record |
| `sn_attachment_upload` | Attach a local file to a record |
| `sn_attachment_delete` | Delete an attachment |

## Read-only by default

Write tools only run when `SN_ALLOW_WRITE=1` is set where the server is registered:

```
claude mcp add servicenow -e SN_ALLOW_WRITE=1 -- npx -y github:MDK-s-Organisation/servicenow-mcp
```

In a JSON config, add `"env": { "SN_ALLOW_WRITE": "1" }` next to `command` and `args`.

Without it the write tools return a clear refusal and send nothing to ServiceNow. Even with writes on, the server can only do what your ServiceNow user is allowed to do.

## Settings

Environment variables, all optional once you have signed in:

| Variable | Default |
| --- | --- |
| `SN_INSTANCE` | none, `login` asks for it or takes `--instance` |
| `SN_CLIENT_ID` | none, `login` asks for it or takes `--client-id` |
| `SN_CLIENT_SECRET` | none, only for an OAuth client that was registered with a secret |
| `SN_REDIRECT_PORT` | `8787` |
| `SN_TOKEN_FILE` | `~/.config/servicenow-mcp/tokens.json` |
| `SN_CONFIG_FILE` | `~/.config/servicenow-mcp/config.json` |
| `SN_ALLOW_WRITE` | unset, writes are off unless this is exactly `1` |

The config file may hold `instance`, `clientId`, `redirectPort` and `allowWrite`. Environment variables win over the file.

If your admin registered a confidential client (one with a secret), set `SN_CLIENT_SECRET` both when you run `login` and where the server is registered. The secret is read from the environment only and is never written to disk by this tool.

To use two instances, give each its own files with `SN_TOKEN_FILE` and `SN_CONFIG_FILE`, and register the server twice under different names.

## Where tokens are kept

Tokens are stored in `~/.config/servicenow-mcp/tokens.json`. The folder is created with mode 0700 and the file with mode 0600, so only your user can read it. The access token is renewed automatically with the refresh token. Tokens are never printed, logged or returned by any tool. The instance must use https (plain http is accepted for localhost only), and a saved sign in is never sent to a different instance.

To sign out run the `logout` command. This deletes the token file. To also end the session on the ServiceNow side, revoke the token there under **System OAuth > Manage Tokens**.

## Troubleshooting

- **"No ServiceNow instance is set"**: run `login` first, or set `SN_INSTANCE`.
- **The browser shows an invalid redirect error**: the redirect URL on the OAuth client must be exactly `http://localhost:8787/callback`. If you use `--port`, change it on the instance too.
- **"ServiceNow answered with a redirect instead of data"**: a developer instance goes to sleep when unused. Wake it at developer.servicenow.com and try again.
- **A table returns nothing or a 403**: your ServiceNow user lacks access to it. The server never goes around ServiceNow access controls.

## Tests

```
node test/run-tests.mjs
```

The tests start a local mock of ServiceNow (`test/mock-servicenow.mjs`), run the whole sign in flow and every tool against it, and print PASS or FAIL lines. They never contact a real instance, never open a browser, and keep their token and config files in a temporary folder.

## License

MIT, see [LICENSE](LICENSE).