内容
# 服务端 MCP 服务器
连接任何 AI 助手 — Claude, Cursor, 或任何支持 [MCP](https://modelcontextprotocol.io) 的助手 — 到您的 ServiceNow 实例。查询记录,创建和更新数据,探索数据模型,运行服务端脚本,并调试,所有操作都可以通过自然语言进行。
几分钟内部署到 **Cloudflare Workers**。支持多个用户,每个用户都可以拥有自己的 ServiceNow 实例和凭证。
```
"当前有多少个 P1 事件是开启的?"
"生成 15 个关于网络中断的演示事件。"
"查找存储 AI 代理执行日志的表。"
"事件状态的有效值是什么?"
"显示过去 30 分钟内记录的错误。"
```
---
## 目录
- [功能](#功能)
- [工作原理](#工作原理)
- [部署您自己的(5 分钟)](#部署您自己的5分钟)
- [连接 AI 客户端](#连接-ai-客户端)
- [ServiceNow 设置](#servicenow设置)
- [配置参考](#配置参考)
- [本地开发](#本地开发)
- [项目结构](#项目结构)
- [安全性](#安全性)
---
## 功能
| 类别 | 工具 |
|---|---|
| **探索** | `search_tables`, `search_fields`, `get_table_schema`, `get_choices` — 无需猜测即可找到正确的表和字段 |
| **创建和管理** | `create_record`, `batch_create_records`, `update_record`, `delete_record`, `update_incident`, `add_work_note` |
| **查询和分析** | `query_table`, `get_record`, `aggregate_table`, `get_user`, `search_knowledge` |
| **调试** | `query_logs` — 按级别、来源、文本和时间窗口读取最近的系统日志 |
| **更新集** | `set_current_update_set`, `get_current_update_set` |
| **开发** _(可选)_ | `execute_script`, `check_script_runner_status`, `reinstall_script_runner` — 同步运行服务端 JavaScript |
- **完整的表 API 覆盖** — 与每个表(开箱即用或自定义)一起工作,而不是固定的集合。
- **多用户** — 一个部署为多个用户服务,每个用户都有自己的实例和登录。
- **默认安全** — 共享的 bearer token 控制服务器;凭证永远不会被存储。
---
## 工作原理
```
AI 客户端(Claude Desktop / Claude.ai / Cursor)
│ 授权:Bearer <token>
│ X-ServiceNow-Instance / 用户名 / 密码
▼
Cloudflare Worker ──► 检查 token ──► 解析凭证
│ │
▼ ▼
Durable Object (每个会话) ── Basic Auth ──► ServiceNow REST API
```
两个独立的层:
1. **`MCP_AUTH_TOKEN`** — 一个共享的密钥,用于决定 *谁可以使用 Worker*。
2. **`X-ServiceNow-*` 头部** — 每个客户端的 *实例和凭证*。每个用户都将相同的 Worker 指向自己的 ServiceNow。
凭证在每个请求时解析并传递给会话;不会持久化任何实例特定的数据。
---
## 部署您自己的(5 分钟)
您需要一个免费的 [Cloudflare 账户](https://dash.cloudflare.com/sign-up) 和已安装的 Node.js。
### 1. 克隆和安装
```bash
git clone https://github.com/ciphervinci/rk-servicenow-mcp.git
cd rk-servicenow-mcp
npm install
```
### 2. 登录到 Cloudflare
```bash
npx wrangler login
```
### 3. 设置访问令牌
这是客户端必须发送的共享密码。生成一个强密码:
```bash
openssl rand -hex 32
```
将其存储为加密的秘密(永远不要提交):
```bash
npx wrangler secret put MCP_AUTH_TOKEN
# 在提示时粘贴该值
```
### 4. 部署
```bash
npm run deploy
```
您将获得一个类似 `https://rk-servicenow-mcp.<your-subdomain>.workers.dev` 的 URL。
### 5. 验证
```bash
curl https://rk-servicenow-mcp.<your-subdomain>.workers.dev/health
```
返回服务器状态和工具列表。就是这样 — 您的服务器已上线。
> **从 Cloudflare 仪表板(Git 集成)部署而不是从 CLI 部署?**
> 在 **设置 → 构建** 下,将构建命令设置为 `bun add ai@5.0.78`,将部署命令设置为 `npx wrangler deploy`。这解决了与依赖项的捆绑问题。其他一切都相同。
---
## 连接 AI 客户端
每个用户都提供自己的 ServiceNow 实例和凭证作为头部,以及共享的令牌。
### 头部
| 头部 | 必需 | 示例 |
|---|---|---|
| `Authorization` | ✅ | `Bearer <your-MCP_AUTH_TOKEN>` |
| `X-ServiceNow-Instance` | ✅ | `https://devXXXXX.service-now.com` |
| `X-ServiceNow-Username` | ✅ | `admin` |
| `X-ServiceNow-Password` | ✅ | `your-password` |
| `X-ServiceNow-Script-Execution` | 可选 | `true` 以启用 `execute_script` |
### Claude Desktop
打开 **设置 → 开发者 → 编辑配置** 并添加:
```json
{
"mcpServers": {
"servicenow": {
"command": "npx",
"args": [
"mcp-remote",
"https://rk-servicenow-mcp.<your-subdomain>.workers.dev/sse",
"--header", "Authorization:Bearer <your-token>",
"--header", "X-ServiceNow-Instance:https://devXXXXX.service-now.com",
"--header", "X-ServiceNow-Username:admin",
"--header", "X-ServiceNow-Password:your-password",
"--header", "X-ServiceNow-Script-Execution:true"
]
}
}
}
```
重启 Claude Desktop。连接器菜单中会出现这些工具。
### Claude.ai(网页)
**设置 → 连接器 → 添加自定义连接器。** 使用 `/mcp` 端点:
```
https://rk-servicenow-mcp.<your-subdomain>.workers.dev/mcp
```
在连接器的头部字段中添加 `Authorization` 和 `X-ServiceNow-*` 头部。
### Cursor
添加到 `~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"servicenow": {
"command": "npx",
"args": [
"mcp-remote",
"https://rk-servicenow-mcp.<your-subdomain>.workers.dev/sse",
"--header", "Authorization:Bearer <your-token>",
"--header", "X-ServiceNow-Instance:https://devXXXXX.service-now.com",
"--header", "X-ServiceNow-Username:admin",
"--header", "X-ServiceNow-Password:your-password"
]
}
}
}
```
### 任何其他 MCP 客户端
指向 `/mcp` 端点(Streamable HTTP)或 `/sse` 端点(SSE)并发送相同的头部。如果客户端无法发送自定义头部,请使用 `mcp-remote` 作为桥接,并使用 `--header` 标志如上所示。
---
## ServiceNow 设置
创建一个专用的服务账户用户 — 不要重用个人管理员登录。仅授予所需的角色:
| 您要执行的操作 | 角色 |
|---|---|
| 读取表 | `snc_read_only` 或表 ACL |
| ITSM 读取/写入(事件、变更、问题) | `itil` |
| 知识搜索 | `knowledge` |
| 探索元数据和读取日志 | 读取 `sys_dictionary`、`sys_db_object`、`sys_choice`、`syslog` |
| 更新集 | 写入 `sys_user_preference` |
| `execute_script` | `admin` |
> 提示:免费的 [ServiceNow 开发者实例](https://developer.servicenow.com/)(PDI)非常适合尝试此功能。
---
## 配置参考
将凭证设置为 **秘密**(加密,生存重新部署)而不是纯文本变量:
```bash
npx wrangler secret put MCP_AUTH_TOKEN # 必需 — 共享访问令牌
npx wrangler secret put SERVICENOW_USERNAME # 可选 — 默认用户名
npx wrangler secret put SERVICENOW_PASSWORD # 可选 — 默认密码
```
非敏感的默认值位于 `wrangler.jsonc` 的 `vars` 下:
| 变量 | 用途 |
|---|---|
| `SERVICENOW_INSTANCE_URL` | 默认实例,如果客户端未发送 `X-ServiceNow-Instance` 头部 |
| `ENABLE_SCRIPT_EXECUTION` | 脚本执行的默认值(`"true"`/`"false"`),如果未发送头部 |
在 **多用户模式** 下,留空 ServiceNow 默认值 — 每个客户端通过头部提供自己的。在 **单用户模式** 下,设置它们,客户端只需连接 `Authorization` 头部。
---
## 本地开发
创建 `.dev.vars`(gitignored):
```
MCP_AUTH_TOKEN=dev-token
SERVICENOW_INSTANCE_URL=https://devXXXXX.service-now.com
SERVICENOW_USERNAME=admin
SERVICENOW_PASSWORD=your-password
ENABLE_SCRIPT_EXECUTION=true
```
运行:
```bash
npm run dev # http://localhost:8787
```
通过 `mcp-remote` 将客户端指向 `http://localhost:8787/sse` 进行本地测试。
---
## execute_script
启用时,服务器在首次使用时会在您的实例上安装一个小型 Scripted REST API(`sys_ws_definition` + `sys_ws_operation`)。之后,脚本同步运行 — 通常小于一秒。返回值用 `return JSON.stringify(...)` 包装:
```javascript
var gr = new GlideRecord('incident');
gr.addEncodedQuery('sys_created_onONToday@javascript:gs.beginningOfToday()@javascript:gs.endOfToday()');
gr.query();
var n = 0;
while (gr.next()) { gr.urgency = 1; gr.update(); n++; }
return JSON.stringify({ updated: n });
```
通过 `X-ServiceNow-Script-Execution: true` 头部启用每个会话。需要在实例上具有 `admin` 权限。
---
## 项目结构
```
src/
├── index.ts # Worker:身份验证,凭证解析,路由
├── mcp-agent.ts # Durable Object 代理;每个会话接收凭证
├── sn-client.ts # REST 客户端,类型,帮助程序
├── ai-stub.js # 依赖项的构建垫片
└── tools/ # 每个工具组一个文件
```
**添加工具:** 创建 `src/tools/x.ts` 导出 `registerXTools(server, props)`,在 `mcp-agent.ts` 中调用它,并在 `registeredToolNames()` 中添加名称。使用 `snFetch`、`ok()` 和 `fail()` 来自 `sn-client.ts`。
**端点:** `/mcp`(Streamable HTTP),`/sse`(SSE for `mcp-remote`),`/health`(状态,无身份验证)。
---
## 安全性
- **始终设置 `MCP_AUTH_TOKEN`。** 空令牌禁用身份验证,并向具有 URL 的任何人公开所有工具 — 包括脚本执行。
- 将令牌和密码存储为 **秘密**,而非纯文本变量(基于 Git 的部署会覆盖变量)。
- 服务账户的 ServiceNow 角色定义服务器可以执行的操作。使用最小特权。
- 为了提高安全性,请在 Worker 前面添加 [Cloudflare Access](https://developers.cloudflare.com/cloudflare-one/)。
---
## License
MIT
由 [Rishikesh](https://github.com/ciphervinci) · [Medium](https://medium.com/@rkesh0504) 构建