关于 GuniWeb SAP MCP
GuniWeb SAP MCP 是供 n8n 工作流及其他 MCP 客户端使用的 SAP S/4HANA 和 ECC 服务,可通过 OData、IDoc 与 RFC/BAPI 操作 SAP。它采用人工治理的工作流设计,写操作默认关闭,并支持按服务器和令牌限制权限。
主要功能
- 01支持 OData V2/V4 操作
- 02发送和接收 IDoc
- 03通过 RFC/BAPI 调用 SAP
- 04发现服务并渐进读取元数据
- 05写操作默认关闭并支持权限限制
适用场景
- 01在 n8n 工作流中查询 SAP 数据
- 02通过 OData 创建或更新业务记录
- 03在配置的 SAP 系统间选择目标并限制访问
MCP 相关
该 MCP 服务将 SAP S/4HANA 和 ECC 的 OData、IDoc 及 RFC/BAPI 能力开放为工具,供 n8n 和其他 MCP 客户端调用。支持 stdio 与 Streamable HTTP 传输。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y guniweb-sap-mcpSAP_BASE_URLBase URL of the SAP system, including any path segment in front of /sap/opu/odata (e.g. https://s4.example.com or https://gateway.example.com/prefix)SAP_AUTH_TYPE密钥Authentication type: basic, oauth2, apikey, ias, xsuaa, btp-principal, saml-bearerSAP_CLIENTSAP client (Mandant). Appended to every request — a client-dependent Gateway answers 401 without itSAP_USERNAMESAP user for basic authenticationSAP_PASSWORD密钥Password for basic authenticationSAP_MCP_DEMOSet to true to start a built-in mock S/4HANA instead of connecting to a real system. No SAP_* configuration needed — for trying the server out本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
GuniWeb SAP S/4HANA 与 ECC MCP 服务
专为 n8n 设计,可在任何 MCP 宿主中使用。免费使用,由 GuniWeb 构建并维护。
通过模型上下文协议(MCP),使用 OData V2、V4、IDoc 和 RFC/BAPI 将 n8n 工作流连接到 SAP S/4HANA 和 ECC。专为AI 辅助、人工治理的工作流打造:工作流作者决定调用哪些 SAP API 以及调用顺序;大模型负责提取、映射和填充参数。默认禁用写入功能,只有针对每个服务和令牌明确启用后才会开启。
graph LR
n8n["n8n workflow<br/>AI-assisted, human-governed"] -->|MCP Protocol| MCP["guniweb-sap-mcp<br/>22 Tools • 8 Auth Types"]
MCP -->|"OData V2/V4<br/>IDoc XML<br/>RFC/BAPI"| SAP["SAP S/4HANA & ECC"]
MCP -->|"OAuth2 / JWT"| BTP["SAP BTP"]
BTP --> SAP
style n8n fill:#4a90d9,color:#fff,stroke:#3a7bc8
style MCP fill:#2d2d2d,color:#fff,stroke:#555
style SAP fill:#1a6fb5,color:#fff,stroke:#0f5a9d
style BTP fill:#e8a317,color:#fff,stroke:#c88d14
功能
OData 与 IDoc
- OData V2 + V4 CRUD —— 使用自动版本检测进行读取、查询、创建、更新和删除
- 深度插入 —— 在一个请求中创建父实体及子实体
- Function Imports(V2)与 Actions/Functions(V4) —— 触发 SAP 业务逻辑
- 批量操作 —— 在单个
$batch请求中执行多个操作 - 自然语言转 OData 查询 —— 将自然语言查询转换为结构化 OData 筛选条件
- IDoc 发送与接收 —— 基于 HTTP/XML,无需依赖 RFC
发现与智能
- 服务发现 —— 自动发现 OData 服务,包含 16 个业务领域类别
- 渐进式元数据 —— 服务目录 -> 实体集 -> 属性 -> 查询
- 智能查询路由 —— 基于领域的路由资源,用于大模型选择工具
- 决策树式工具描述 —— 通过“适用场景 / 不适用场景”说明引导大模型
受治理的工具可见性
- 四级工具注册表 —— Core / OData / IDoc / RFC 层级,按需启用
sap_enable_tools—— 大模型可在运行时启用其他工具层级,但受你设置的限制- 默认只读(自 0.2.2 起) —— 写入工具需要
--allow-write - 按令牌策略(0.3.0) —— 每个 Bearer 令牌均可设置
readOnly和工具层级上限,且只会进一步收紧限制 - IDoc / RFC 自动禁用 —— 缺少相应配置时隐藏对应工具
- MCP 注释 —— 全部 22 个工具均带有 readOnlyHint、destructiveHint 和 idempotentHint
身份验证(8 种类型)
graph TB
subgraph Technical["Technical User Auth"]
basic["basic<br/><i>Direct S/4HANA</i>"]
userbasic["user-basic<br/><i>Personal SAP login per request</i>"]
oauth2["oauth2<br/><i>BTP Client Credentials</i>"]
apikey["apikey<br/><i>Sandbox / Testing</i>"]
end
subgraph Enterprise["Enterprise Auth (OIDC)"]
ias["ias<br/><i>SAP IAS Token</i>"]
xsuaa["xsuaa<br/><i>SAP XSUAA Token</i>"]
end
subgraph Principal["Principal Propagation<br/><i>End-user identity forwarded to SAP</i>"]
btp["btp-principal<br/><i>JWT Bearer Exchange<br/>via Destination Service</i>"]
saml["saml-bearer<br/><i>SAML 2.0 Assertion<br/>+ RSA-SHA256 Signing</i>"]
end
style Technical fill:#2a5f8f,color:#fff,stroke:#1a4f7f
style Enterprise fill:#5b8c5a,color:#fff,stroke:#4b7c4a
style Principal fill:#8b5e3c,color:#fff,stroke:#7b4e2c
基础设施
- 两种传输模式 —— stdio 和 Streamable HTTP(旧版 SSE 传输已于 0.8.0 中移除)
- 命名目标(0.3.0) —— 一个服务可连接多个 SAP 系统;每个 n8n 凭据使用一个 Bearer 令牌来选择系统及其权限。仍支持静态 API 密钥
- 支持 Docker —— 使用 Docker Compose 部署 n8n + SAP MCP sidecar
- 零遥测 —— 服务只会与您配置的 SAP/BTP 端点通信,不会连接其他任何地方。不收集使用统计信息,不进行更新检查,也不发送崩溃报告
- 1267 项测试 —— 通过 GitHub Actions CI/CD 执行单元测试、集成测试和端到端测试
快速开始
无需 SAP 系统即可试用:--demo
手头没有 SAP 系统?使用内置的模拟 S/4HANA 启动服务,然后从 n8n 或任意 MCP 客户端试用所有工具:
npx guniweb-sap-mcp --demo # stdio — n8n MCP Client in command mode
npx guniweb-sap-mcp --demo --transport http --port 8808 # HTTP — n8n MCP Client with URL http://localhost:8808/mcp
npx guniweb-sap-mcp --demo --allow-write # also try sap_create / sap_update / sap_delete / sap_batch
演示模式会在 localhost 上启动一个内存中的 OData V2 网关(包含三个使用真实 SAP 字段名称的服务——API_BUSINESS_PARTNER、API_SALES_ORDER_SRV、API_PRODUCT_SRV;约 20 个业务伙伴、15 个含行项目的销售订单、10 个产品),并将服务指向该网关。在关键功能上,它的行为与 Gateway 一致:目录发现、$metadata、$filter/$expand/分页、CSRF 令牌、ETag、深度插入、函数导入、带有更改集的 $batch、SAP 风格的错误负载。只有示例数据——数据并非真实数据,不会离开你的机器;进程结束后,所有更改都会消失。也可使用 SAP_MCP_DEMO=true(例如在 Docker 中)。使用演示环境构建的工作流,在将 --demo 替换为你的 SAP_* 配置后即可用于真实系统。
1. 安装
npm install -g guniweb-sap-mcp
或者将其作为容器运行:docker run --rm -p 8808:8808 -e SAP_MCP_DEMO=true ghcr.io/guniweb/guniweb-sap-mcp:latest
2. 配置
export SAP_BASE_URL=https://your-sap-system.example.com
export SAP_AUTH_TYPE=basic
export SAP_USERNAME=your-user
export SAP_PASSWORD=your-password
export SAP_CLIENT=100 # do not omit: without it a client-dependent Gateway
# answers 401 "Anmeldung fehlgeschlagen", which looks
# like a wrong password but is not one
3. 运行
# stdio (default) -- for n8n MCP Client in command mode
guniweb-sap-mcp
# HTTP -- for n8n MCP Client in URL mode or Docker
guniweb-sap-mcp --transport http --port 8808
# With tool tier control
guniweb-sap-mcp --transport http --port 8808 --tiers core,odata
guniweb-sap-mcp --transport http --port 8808 --allow-write # writes are OFF by default
# Production: authenticate the MCP endpoint AND the inbound IDoc webhook
guniweb-sap-mcp --transport http --port 8808 --api-key <mcp-key> --webhook-secret <idoc-secret>
作为容器运行
# Look around first — mock S/4HANA inside the container, no SAP system needed
docker run --rm -p 8808:8808 -e SAP_MCP_DEMO=true ghcr.io/guniweb/guniweb-sap-mcp:latest
# Against a real system (pin the version in production)
docker run -d --name sap-mcp -p 8808:8808 --env-file .env \
ghcr.io/guniweb/guniweb-sap-mcp:<version>
# Flags go straight to the server — writes stay off unless you say so
docker run -d -p 8808:8808 --env-file .env \
ghcr.io/guniweb/guniweb-sap-mcp:<version> --allow-write
此镜像基于已发布的 npm 包构建,而非通过另一条构建路径构建——容器中运行的内容,就是通过 npm install 安装的产物,因此两者不会出现偏差。镜像内默认使用 8808 端口进行 HTTP 传输(SAP_MCP_TRANSPORT / SAP_MCP_PORT);它以非 root 用户身份运行,在 /healthz 提供健康检查,并通过构建来源证明发布,支持 linux/amd64 和 linux/arm64。
不包含:RFC/BAPI。该路径需要 SAP NW RFC SDK,而 SAP 仅向客户授予该 SDK 的许可,因此无法将其打包到公开镜像中。其他功能——OData V2/V4、通过 HTTP/XML 传输的 IDoc——均可正常使用。如需使用 RFC,请在主机上安装 SDK,然后通过 npm 运行服务(SAP ECC 设置)。
仓库中提供了一个 docker-compose.yml,可将 n8n 与服务一同运行。
生产环境加固
| 变量 / 标志 | 默认值 | 描述 |
|---|---|---|
--tool-timeout / SAP_MCP_TOOL_TIMEOUT | 30(秒) | 单次完整工具调用的时间预算,无论它会发出多少个 SAP 请求。超时后,客户端会收到有效的 MCP 响应,其中包含 truncated: true 和通俗易懂的原因说明——连接绝不会一直挂起。分页读取会返回目前已获取的页面。0 会禁用此预算(启动时会记录警告) |
SAP_HTTP_TIMEOUT_MS | 30000 | 单个出站 SAP 请求的超时时间(毫秒)。网关挂起时会快速失败并返回结构化的 TIMEOUT 错误,而不会让 n8n Agent 陷入等待。超时时间受上述工具预算的剩余时长限制 |
--cache-dir / SAP_CACHE_DIR | (未设置 = 仅保存在内存中) | 将目录和元数据缓存持久化到磁盘,避免重启后重新获取。未设置时,每次重启都会重新读取完整目录——对于拥有一千多个服务的系统,这种冷启动会导致客户端超时。n8n 会在传输错误时清除自己的客户端条目,因此重启并不少见 |
SAP_CA_CERT | (未设置) | 为你的 SAP 证书签名的根 CA 的路径——这是文档中提供的绕过企业 PKI 问题的方法。此证书会同步到 NODE_EXTRA_CA_CERTS。建议使用此设置,而不是 SAP_TLS_VERIFY=false;后者会禁用检查,而非解决问题 |
--concurrency / SAP_CONCURRENCY | 5 | 在无法避免多个 SAP 请求时,限制同时发出的请求数 |
--allow-write / SAP_MCP_ALLOW_WRITE | (未设置 = 只读) | 从 0.2.2 起,服务默认只读。 在设置此选项之前,不会注册 sap_create、sap_update、sap_delete、sap_function 和 sap_idoc_send;Agent 看不到的工具,就不会意外调用。仍接受 --read-only,现在它只是描述默认行为 |
SAP_JWT_ISSUER | (未设置 = 不验证) | 用于验证传入用户令牌的 JWKS 签发者。未设置时,令牌只会被解码,生成的身份会标记为 verified: false——将其转发给 SAP 是安全的(SAP 会自行验证),但不能据此做本地决策。设置后,验证失败的令牌会被拒绝并返回 401,而不会静默降级为技术用户 |
SAP_WEBHOOK_SECRET / --webhook-secret | (未设置 = 公开访问 + 启动时警告) | 入站 IDoc Webhook 的共享密钥。接受 Authorization: Bearer <secret> 或 HTTP Basic 身份验证(其密码必须与密钥相同;这与 SAP SM59 HTTP 目标匹配) |
SAP_WEBHOOK_HOST / --webhook-host | 所有接口 | 独立 IDoc Webhook(stdio 模式)的绑定地址。使用反向代理时请设置为 127.0.0.1 |
SAP_WEBHOOK_MAX_BODY_BYTES | 10485760(10 MB) | IDoc 负载超出此大小时,在将其缓冲到内存之前返回 413 |
在 HTTP 传输模式下,/idoc 路由挂载在 MCP 端口上:设置了 --webhook-secret 时,该路由会独立于 --api-key 进行身份验证(因此 SAP 可以使用 Basic 身份验证,而 n8n 使用 Bearer 密钥);未设置时,若配置了 --api-key,该路由会受其保护——若两者都未配置,则该路由公开访问(服务会在启动时记录警告)。
两项超时都必须低于你所用设置中最短的客户端限制。常见限制:Cloudflare 等反向代理会在 100 秒时中止(524),n8n 的 MCP 客户端传输限制为 300 秒。若预算高于最短限制,它永远不会生效,因为客户端会先放弃。
跟踪缓慢的工具调用
每次工具调用完成时都会记录一行日志,其中包含一个关联 ID;该 ID 也会出现在它触发的每个 SAP 请求中:
{"correlationId":"a3f19c8b2d04","tool":"sap_discover_services","outcome":"ok","durationMs":842,"sapCalls":1,"resultBytes":18422}
然后运行 grep a3f19c8b2d04,即可查看这次调用的完整情况,包括它产生了多少个 SAP 请求。outcome 的值可以是 ok、error、timeout(超出预算)或 aborted(客户端断开连接)。
随请求发送 W3C traceparent 标头,其跟踪 ID 会以 traceId 的形式出现在同一行日志中,这样便可从调用应用程序,经由 n8n,一直跟踪到 SAP 请求。该标头只会记录到日志中。无效的标头会被忽略,也永远不会转发给 SAP(详情)。
level: 50 表示确实出了问题。 预期的非 2xx 响应——来自目录路径探测的 404,以及系统不支持 V4 目录时的 V4 目录尝试所返回的 404——会以 info 级别记录,并带有 "expected": true,而不是以 error 级别记录。在生产系统上的测量结果显示:运行 96 小时以上后,日志中唯一一条 error 级别记录就是这条误报。因此,对 level: 50 设置告警是有意义的;以前,这种告警只会带来噪声。
出现故障时
test-connection 会遍历整个链路,并报告第一个失败的阶段——DNS、TLS(包括证书链)、身份验证、客户端(Mandant)和目录。失败之后的阶段会标记为 skipped,绝不会报告为通过。相同的五个阶段也会在启动时记录一次,因此容器日志无需调用任何内容,就能显示连接状态。
每个错误响应都包含错误分类(如有,则包括 SAP 错误代码)、通俗易懂的说明和后续操作——没有任何工具会返回 "Unknown error"。以下三种情况过去都需要单独诊断:
| SAP 返回的内容 | 服务端告知你的内容 |
|---|---|
403,带有 /IWFND/MED/170 | 服务尚未注册——请在 /IWFND/MAINT_SERVICE 中激活。这不是授权问题,尽管返回了 403 |
401,附带 HTML 登录页面 | 是否设置了 sap-client?如果没有,依赖客户端的 Gateway 会以看似密码错误的方式拒绝登录 |
UNABLE_TO_GET_ISSUER_CERT_LOCALLY | 证书链不完整;请通过 SAP_CA_CERT 提供根 CA。错误说明中会指出颁发 CA |
如果启用了 SAP_TLS_VERIFY=false,每个工具结果都会附带相关警告,而不只是启动日志。在第一天之后就没人注意到的禁用检查,往往会一直保留数年;促使我们开展这项工作的生产系统就设置了这一选项,却一直没人发现。
Streamable HTTP 是无状态的
--transport http 以无状态模式提供 MCP 服务:每个请求都是独立的,服务端既不会发出,也不会要求提供 mcp-session-id 标头。服务端没有可恢复的会话,因此客户端随时都可以重新连接,而不会丢失状态。
必须使用会话 ID 的客户端——它们会从初始化响应中读取 mcp-session-id,并在后续请求中发送该 ID——无法与此服务配合使用。n8n MCP Client、Claude Desktop 和 MCP Inspector 均可在不使用会话 ID 的情况下正常工作。
旧版 --transport sse 模式已在 0.8.0 中移除;请使用 http。
多个 SAP 系统:destinations.json
SAP_* 变量描述的是一个 SAP 系统。若要让一个服务连接多个系统——例如在生产系统旁运行一个测试客户端,或让一个 n8n 连接多个客户的系统——请将连接信息放入 destinations.json,并让服务指向该文件:
guniweb-sap-mcp --transport http --port 8808 --destinations /config/destinations.json
# or: SAP_MCP_DESTINATIONS=/config/destinations.json
{
"version": 1,
"destinations": {
"default": {
"baseUrl": "https://s4prod.example.com",
"authType": "basic",
"username": "MCP_USER",
"password": "${S4PROD_PASSWORD}",
"sapClient": "100"
},
"s4test": {
"baseUrl": "https://s4test.example.com",
"authType": "basic",
"username": "MCP_USER",
"password": "${S4TEST_PASSWORD}",
"sapClient": "200"
}
}
}
- 一条目 = 一个连接。 每个条目接受的字段与
SAP_*变量完全相同(authType及其凭据、sapClient、baseUrl)——每个目标都支持所有身份验证类型。 - 每个请求使用个人 SAP 登录信息——
"authType": "user-basic":目标仅记录系统和客户端信息;每个请求都会附带 SAP 用户名和密码(X-SAP-Username/X-SAP-Password;在 n8n 中使用 GuniWeb SAP 节点的凭据)。每个人在 SAP 中都以自己的身份操作——授权、变更文档和审计跟踪记录的都是真实用户,不会共用技术账号。没有技术用户回退机制(未提供登录信息时返回401),缓存按用户隔离,密码绝不会写入日志。仅支持 HTTP 传输。详情请参阅设置指南。 - 机密信息不会写入文件。 任何字符串都可以包含
${VARIABLE};加载时会从环境中解析该变量(Docker secrets、.env)。无法解析占位符会导致文件无效——否则,空密码会引发来自 SAP 的误导性401错误。 - 热重载。 文件会受到监视;文件变更会在下一个请求时生效,无需重启。执行
kill -HUP <pid>可强制重新加载。无效文件绝不会替换正在运行的配置——错误会写入日志,最后一份有效配置继续生效。 - 向后兼容。 不使用
--destinations时,行为不变:SAP_*变量构成唯一目标default。使用该文件时,如果文件未定义default,则会将已设置的SAP_*变量添加为default——因此安装迁移过程不会出现中断。 - 由哪个目标响应? 不带令牌时,使用名为
default的目标(或唯一目标)。带令牌时,使用令牌指定的目标——见下文。
令牌:每个 n8n 凭据使用一个 Bearer 值来选择系统。 n8n MCP Client 只发送一个 Authorization 标头,因此令牌可同时完成两项工作——验证请求并选择目标。SAP 密码不会离开服务端;n8n 只保存令牌。
{
"version": 1,
"destinations": { "s4prod": { "...": "..." }, "s4test": { "...": "..." } },
"tokens": [
{ "hash": "sha256:9f2c…", "destination": "s4prod", "label": "n8n prod workflows" },
{ "hash": "sha256:1a7e…", "destination": "s4test", "label": "n8n dev", "revoked": false }
]
}
- 文件中只保存 SHA-256 哈希值;明文令牌(
gsm_<destination>_<random>)由tokens issue仅打印一次,之后无法找回。将它填入 MCP Client 节点的 n8n Bearer Auth 凭据中。一旦至少存在一个令牌,不带有效令牌的请求就会收到401——--api-key仍可同时使用,并服务于default目标。 - 对所有条目进行恒定时间查找;
"revoked": true会在下一个请求时停用令牌(热重载,无需重启)。一分钟内失败 10 次后,客户端地址会收到带有Retry-After的429——有效令牌也不例外,以此抑制猜测(反向代理才是实施实际速率限制的合适位置)。令牌绝不会写入日志;拒绝请求时会记录地址和原因。 管理文件——无需手动编辑。 同一个二进制文件包含管理命令;每条命令在写入前都会像服务端一样验证结果(绝不会留下无法加载的文件),以原子方式写入,正在运行的服务会在下一个请求时应用变更:
export SAP_MCP_DESTINATIONS=/config/destinations.json # or --destinations <path> on each call
guniweb-sap-mcp destinations add s4prod --base-url https://s4prod.example.com --auth-type basic \
--username MCP_USER --password '${S4PROD_PASSWORD}' --sap-client 100
guniweb-sap-mcp destinations add legacy --from-env # copy the current SAP_* environment (migration)
guniweb-sap-mcp destinations list # names, URLs, auth type, client, token count — never secrets
guniweb-sap-mcp tokens issue s4prod --label "n8n prod" --read-only --tiers core,odata
# → prints the plain token ONCE on stdout (everything else goes to stderr, so TOKEN=$(…) works)
guniweb-sap-mcp tokens list # label, destination, hash prefix, policy, status
guniweb-sap-mcp tokens revoke "n8n prod" # by label or ≥ 8 hex chars of the hash
guniweb-sap-mcp destinations remove s4test [--force] # refuses while tokens point at it, unless --force
--set field=value 支持任何身份验证类型(--auth-type oauth2 --set clientId=… --set clientSecret='${BTP_SECRET}' --set tokenServiceUrl=…);${ENV_VAR} 值会根据当前环境进行检查(可使用 --allow-missing-env 跳过,例如变量只存在于容器内部时)。在 Docker 中,请在容器内运行这些命令,以确保它们访问相同的文件和环境:docker compose exec sap-mcp guniweb-sap-mcp tokens issue s4prod。
-
每个令牌的权限 —
"policy": { "readOnly": true, "tiers": ["core", "odata"] }。策略只会限制权限:即使服务以--allow-write运行,readOnly: true也会隐藏该令牌的写入工具(readOnly: false无法解除只读服务的限制);tiers则是上限——该令牌看不到范围以外的层级,sap_enable_tools也无法启用这些层级。tools/list会针对每个请求进行筛选,因此只读令牌的 Agent 根本不会看到sap_create。 -
按令牌和目标分别设置速率限制 — 适用于循环调用的 AI Agent,也能避免超出 SAP API 配额。在令牌的
policy中设置"rateLimit": { "requestsPerMinute": 60, "maxConcurrent": 4 }可限制该令牌;在目标中设置同一对象,则会限制所有调用者对该 SAP 系统的总调用量。只有工具调用会计入限制(tools/list不收费);超出限制时,服务会返回429和Retry-After,并提示触发的限制。达到maxConcurrent时,调用会先在 FIFO 队列中等待空闲时段,最长等待--rate-limit-max-wait秒(默认值为 60,0= 立即返回429);等待期间断开连接的调用者会离开队列。requestsPerMinute不会触发等待。默认不设置任何限制。仅支持 HTTP 传输。无需手动编辑即可设置:guniweb-sap-mcp tokens limit "n8n agent" --rate-per-minute 60、guniweb-sap-mcp destinations limit s4prod --max-concurrent 4(--clear可移除限制),或在tokens issue中使用--rate-per-minute/--max-concurrent。
管理 API——通过 HTTP 执行相同操作(自助服务)。 使用 --admin-token <secret>(或 SAP_MCP_ADMIN_TOKEN,至少 16 个字符,例如 openssl rand -base64 32)后,服务会在 /admin 下提供 CLI 的各项操作,方便通过 n8n 工作流为新客户开通访问权限、运行脚本或供人员使用 curl 操作,无需登录主机 Shell:
guniweb-sap-mcp --transport http --port 8808 --destinations /config/destinations.json --admin-token "$ADMIN"
A="Authorization: Bearer $ADMIN"; J="Content-Type: application/json"; U=http://localhost:8808/admin
curl -H "$A" $U/destinations # list — never secrets
curl -H "$A" -H "$J" -X PUT $U/destinations/s4prod \ # create (201) or replace (200)
-d '{"baseUrl":"https://s4prod.example.com","authType":"basic","username":"MCP_USER","password":"${S4PROD_PASSWORD}","sapClient":"100"}'
curl -H "$A" -H "$J" -X POST $U/tokens \ # → { "token": "gsm_s4prod_…", … } — shown ONCE
-d '{"destination":"s4prod","label":"n8n prod","readOnly":true,"tiers":["core","odata"]}'
curl -H "$A" $U/tokens # label, destination, hash prefix, policy, status
curl -H "$A" -X DELETE "$U/tokens/n8n%20prod" # revoke by label or hash prefix
curl -H "$A" -X DELETE "$U/destinations/s4test?force=true" # remove; without force it refuses while tokens exist
- 密钥分开,入口也分开。 管理密钥只能访问
/admin;n8n 令牌和--api-key只能访问/mcp。泄露的 n8n 令牌无法创建更多访问权限,管理密钥也无法读取 SAP 数据。错误密钥会按客户端地址计数(每分钟失败 10 次后返回429);每次变更都会记录操作、目标和客户端地址——绝不记录令牌或密钥。未设置--admin-token时,/admin/*会返回404。 - 立即生效。 每次写入都会像 CLI 一样进行验证,以原子方式写入,并在响应前重新加载运行中的配置(
"reloaded": true)。如果服务无法加载已写入的内容——通常是因为写入了只有你的 Shell 才知道的${VAR},且使用了?allowMissingEnv=true——响应会显示"reloaded": false及错误信息,并继续使用上一次有效配置。 - 无需 SAP 配置即可启动。 设置
--admin-token后,即使destinations.json尚不存在且未设置任何SAP_*,服务也会启动:创建第一个目标(以及令牌,或名为default的目标)之前,/mcp会返回503。docker run … -e SAP_MCP_ADMIN_TOKEN=… -e SAP_MCP_DESTINATIONS=/config/destinations.json即可完成首次启动。 - 将 API 放在与
/mcp相同的反向代理/TLS 后面;管理密钥与其他凭据一样,通过 Bearer 请求头传递。
轮换令牌和 SAP 密码——逐步说明哪些操作需要重启、哪些不需要:设置指南 → 轮换凭据。
4. 与 n8n 搭配使用
- 添加一个 AI Agent 节点,并为其添加一个 MCP Client Tool 子节点
- 将 MCP Client URL 设置为
http://sap-mcp:8808/mcp(Docker)或http://localhost:8808/mcp,并配置一个包含 API 密钥或目标令牌的 Bearer Auth 凭据 - AI Agent 节点会自动发现 SAP 工具。它能看到哪些工具由你决定,而不是由模型决定:默认仅提供只读工具,只有使用
--allow-write才会提供写入工具,单令牌策略还可以进一步限制工具。请将工作流设计为由人工编写的确定性流程——LLM 负责填入参数
SAP ECC 设置
ECC NetWeaver 后端需要在快速入门之外进行额外设置。MCP 服务支持 ECC 6.0+(EHP 7+)的 OData V2、OData V4、IDoc HTTP/XML 和 RFC/BAPI。仅使用云端 S/4HANA 租户时,无需参阅本节。
1. 激活 NetWeaver Gateway
在事务代码 SICF 中,激活 /sap/opu/odata/ 下的标准 ICF 服务。然后使用事务代码 /IWFND/MAINT_SERVICE 注册你想公开的 OData 服务。
MCP 服务的目录自动发现会依次探测三个路径,并缓存首个返回 200 的路径:
/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/ServiceCollection(S/4HANA 默认路径)/sap/opu/odata/iwfnd/CATALOGSERVICE;v=2/ServiceCollection(ECC 小写路径)/sap/opu/odata/IWFND/CATALOGSERVICE/ServiceCollection(ECC EHP 7 v=1)
如果网关使用非标准挂载路径,可通过 ODATA_V2_CATALOG_PATH 覆盖。
2. 安装 SAP NW RFC SDK(仅适用于 RFC/BAPI 工具)
rfc 工具层需要此 SDK。如果你只使用 OData 或 IDoc,可跳过此步骤。
Linux:
tar xzf nwrfcsdk_linux.tgz -C /usr/sap/
export LD_LIBRARY_PATH=/usr/sap/nwrfcsdk/lib:$LD_LIBRARY_PATH
npm install node-rfc
macOS:
tar xzf nwrfcsdk_darwin.tgz -C /usr/sap/
export DYLD_LIBRARY_PATH=/usr/sap/nwrfcsdk/lib:$DYLD_LIBRARY_PATH
npm install node-rfc
node-rfc 声明为 optionalDependencies——如果缺少 SDK,服务会在启动时记录一条 Pino 警告,并跳过 RFC 工具层。OData 和 IDoc 工具仍可正常使用。
3. ECC 专用环境变量
除快速入门中记录的变量外:
| 变量 | 必需 | 描述 |
|---|---|---|
ODATA_V2_CATALOG_PATH | 否(自动发现) | 覆盖目录路径,例如 /sap/opu/odata/iwfnd/CATALOGSERVICE;v=2/ServiceCollection |
SAP_TLS_VERIFY | 否(默认为 true) | 在使用自签名证书的 ECC 场景中,设为 false 可禁用 TLS 证书验证 |
SAP_CLIENT_CERT_PATH | 用于 X.509 客户端证书 | PEM 编码的客户端证书路径,例如 /etc/sap/client.crt |
SAP_CLIENT_KEY_PATH | 用于 X.509 客户端证书 | PEM 编码的私钥路径(可通过提示词提供密码) |
SAP_SNC_QOP | 用于 SNC(RFC) | SNC 保护质量级别:1(仅身份验证)、2(完整性)、3/8/9(加密) |
SAP_SNC_MYNAME | 用于 SNC(RFC) | 本地 SNC 名称,例如 p:CN=mcp-server, O=GuniWeb |
SAP_SNC_PARTNERNAME | 用于 SNC(RFC) | 后端 SNC 名称,例如 p:CN=SAPSERVER, O=ACME |
SAP_SNC_LIB | 用于 SNC(RFC) | SNC 库路径(.so / .dylib / .dll),例如 /usr/sap/sapcrypto/libsapcrypto.so |
可用工具(22)
核心层(始终启用)
| 工具 | 描述 |
|---|---|
test-connection | 分阶段诊断连接(DNS → TLS → 身份验证 → 客户端 → 目录);指出首个失败阶段 |
sap_list_services | 列出 OData 服务中的实体集(分页,默认 50) |
sap_discover_services | 按类别筛选和搜索,发现所有服务 |
sap_get_metadata | 检查实体类型、属性、键,以及 SAP 对每个实体集允许的操作(创建/更新/删除) |
OData 层(默认启用)
| 工具 | 描述 |
|---|---|
sap_read | 读取单个实体或实体集合 |
sap_query | 使用 OData $filter、$select、$expand 和分页进行查询(默认 top 为 50) |
sap_nl_query | 使用结构化筛选条件进行自然语言查询 |
sap_create | 创建实体(支持深层插入和草稿服务) |
sap_update | 更新实体(自动处理 ETag) |
sap_delete | 删除实体(自动处理 ETag) |
sap_function | 调用 V2 函数导入或 V4 操作/函数 |
sap_batch | 在单个批处理中执行多个操作 |
IDoc 层(通过 sap_enable_tools 按需启用)
| 工具 | 描述 |
|---|---|
sap_idoc_send | 通过 HTTP/XML 向 SAP 发送 IDoc |
sap_idoc_list_received | 列出通过 webhook 接收的 IDoc |
sap_idoc_status | 检查 IDoc 处理状态 |
sap_idoc_discover | 发现可用的 IDoc 类型 |
RFC 层(通过 sap_enable_tools 按需启用,需要 SAP NW RFC SDK)
| 工具 | 描述 |
|---|---|
sap_rfc_call | 使用经过 zod 验证的参数调用任意启用 RFC 的函数模块 |
sap_rfc_metadata | 获取函数模块签名(导入/导出/表/异常) |
sap_bapi_call | 调用 BAPI,解析 BAPIRET2 返回表,并固定连接以供后续提交使用 |
sap_bapi_commit | 在固定的会话中调用 BAPI_TRANSACTION_COMMIT |
sap_rfc_search_functions | 通过 RFC_FUNCTION_SEARCH 按名称模式查找函数模块 |
元工具
| 工具 | 描述 |
|---|---|
sap_enable_tools | 在运行时启用/停用工具层 |
架构
graph TB
subgraph n8n["n8n"]
Agent["AI Agent + LLM"]
MCPClient["MCP Client Tool"]
Agent --> MCPClient
end
subgraph Server["guniweb-sap-mcp"]
Transport["Transport<br/>stdio | HTTP"]
UserCtx["UserContext<br/>Extraction"]
Registry["ToolRegistryManager<br/>Core | OData | IDoc"]
Tools["17 MCP Tools<br/>3 Resources • 3 Prompts"]
OData["ODataClient<br/>V2/V4 Auto-Detect"]
Discovery["Service Discovery<br/>16 Domain Categories"]
NLQuery["NL-to-OData<br/>Filter Builder"]
HTTP["SapHttpClient<br/>CSRF • Redirect • Auth"]
Auth["Auth Layer<br/>8 Auth Types"]
Cache["Per-User Token Cache<br/>LRU • SHA-256"]
Transport --> UserCtx
Transport --> Registry
Registry --> Tools
Tools --> OData
Tools --> Discovery
Tools --> NLQuery
OData --> HTTP
Discovery --> HTTP
NLQuery --> OData
HTTP --> Auth
Auth --> Cache
end
subgraph SAP["SAP Backend"]
S4["S/4HANA<br/>OData V2/V4"]
IDoc["IDoc<br/>HTTP/XML"]
BTPSuite["BTP Integration<br/>Suite"]
DestSvc["Destination<br/>Service"]
TokenSvc["XSUAA / IAS<br/>Token Service"]
end
MCPClient -->|MCP Protocol| Transport
HTTP -->|Direct| S4
HTTP -->|Via BTP| BTPSuite
BTPSuite --> S4
HTTP --> IDoc
Auth -->|Token Exchange| DestSvc
Auth -->|OIDC / OAuth2| TokenSvc
DestSvc --> S4
style n8n fill:#e8f4fd,stroke:#4a90d9
style Server fill:#f5f5f5,stroke:#555
style SAP fill:#e8f0fe,stroke:#1a6fb5
集成路径
graph LR
subgraph Path1["Path 1: Direct"]
n1["n8n"] -->|MCP| s1["MCP Server"] -->|Basic Auth| sap1["SAP S/4HANA"]
end
subgraph Path2["Path 2: BTP Client Credentials"]
n2["n8n"] -->|MCP| s2["MCP Server"] -->|OAuth2| btp2["BTP Suite"] --> sap2["SAP S/4HANA"]
s2 -->|CC Flow| tok2["XSUAA"]
end
subgraph Path3["Path 3: BTP Principal Propagation"]
n3["n8n + JWT"] -->|MCP| s3["MCP Server"] -->|JWT Exchange| dest3["Destination Svc"] --> sap3["SAP S/4HANA"]
end
subgraph Path4["Path 4: SAML Bearer (no BTP)"]
n4["n8n + JWT"] -->|MCP| s4["MCP Server"] -->|"SAML Assertion<br/>RSA-SHA256"| sap4["SAP OAuth2<br/>Endpoint"]
end
style Path1 fill:#e8f4fd,stroke:#4a90d9
style Path2 fill:#fef9e7,stroke:#e8a317
style Path3 fill:#eafaf1,stroke:#5b8c5a
style Path4 fill:#fdf2e9,stroke:#8b5e3c
请求流程(OData 写入)
sequenceDiagram
participant LLM as LLM (via n8n)
participant Tool as MCP Tool
participant Registry as ToolRegistry
participant OData as ODataClient
participant HTTP as SapHttpClient
participant SAP as SAP Gateway
LLM->>Tool: sap_create(serviceUrl, entitySet, data)
Tool->>Registry: isToolVisible?
Registry-->>Tool: yes
Tool->>OData: create(entitySet, data)
OData->>HTTP: request(POST, url, data)
Note over HTTP,SAP: CSRF Token Fetch
HTTP->>SAP: GET /sap/opu/odata/sap/SRV/<br/>x-csrf-token: fetch<br/>sap-client: 324
SAP-->>HTTP: x-csrf-token: TOKEN<br/>set-cookie: SESSION
Note over HTTP,SAP: Mutating Request
HTTP->>SAP: POST /sap/opu/odata/sap/SRV/EntitySet<br/>x-csrf-token: TOKEN<br/>Cookie: SESSION
SAP-->>HTTP: 201 Created + entity data
HTTP-->>OData: response
OData-->>Tool: created entity
Tool-->>LLM: JSON result via MCP
支持的 SAP 系统
该 MCP 服务支持以下 SAP 后端。连接器是否可用取决于目标系统;先决条件请参阅脚注。
| 连接器 | ECC 6.0+ (EHP 7+) | S/4HANA 本地部署 | S/4HANA Cloud(Public) |
|---|---|---|---|
| OData V2 | ✅ 支持 1 | ✅ 支持 | ✅ 支持 |
| OData V4 | ⚠️ 部分支持 2 | ✅ 支持 | ✅ 支持 |
| IDoc(HTTP/XML) | ✅ 支持 1 | ✅ 支持 | ❌ 不适用 3 |
| RFC/BAPI | ✅ 支持 145 | ✅ 支持 45 | ❌ 不适用 3 |
此外,还经过了以下系统的验证:
- SAP BTP Integration Suite(作为 S/4HANA Cloud RFC/IDoc 路径的中间层)
- SAP API Business Hub Sandbox
文档
- 设置指南 -- 安装、全部 8 种身份验证类型、CLI 参数、命名目标和令牌、Docker 部署
- 架构 -- 技术架构、请求流程、设计决策
- API 参考 -- 全部 22 个工具、资源和提示词及其参数
- 示例 -- SAP 工作流示例及分步说明
- SAP 接口,逐个工具介绍 -- 22 个工具分别调用哪个 SAP 端点、哪些内容受到限制、哪些数据会离开你的网络 — 适用于 Basis 团队、许可证管理员和审计人员
- 变更日志 · 版本发布 · 问题 · 讨论
治理:如何遵循 SAP 的规则
- 仅使用标准集成接口。 服务通过 NetWeaver Gateway 使用 OData V2/V4、通过 HTTP/XML 使用 IDoc,以及使用 RFC/BAPI —— 这些都是有文档记录且受支持的 SAP 系统接入方式(逐个工具查看清单)。不使用 UI 自动化或未记录的接口,也不批量复制 SAP 数据。内置分页限制和时间预算,避免单次工具调用演变成对 Gateway 的负载测试。
- 写入路径受治理且可审计。 默认只读;只有显式指定
--allow-write才会启用写入工具;各令牌策略只能施加限制,不能放宽限制;每次工具调用都会写入一条日志,并生成一个关联 ID,该 ID 也会出现在它触发的每个 SAP 请求中。这正是“由人治理”可验证的原因:决定哪些地方可以写入的是工作流作者,而不是模型。 - 自动创建文档前,有两件事需要先确认。 SAP 的 API 使用政策包含有关自主生成式 API 使用的条款 —— 应将工作流构建为由 LLM 辅助的确定性、人工编写的步骤序列,而不是开放式自主 Agent(本服务正是为此而设计的)。此外,自动创建的业务文档(例如销售订单)可能适用你所在租户的 SAP Digital Access 许可要求 —— 上线前请与 SAP 客户团队确认。以上内容均不构成法律建议;但这两点都是审计人员会询问的问题。
背后团队以及如何获取帮助
guniweb-sap-mcp 由 GuniWeb 构建并维护。GuniWeb 是一家咨询公司,拥有自己的解决方案:让流程顺畅运作,让系统伴随您共同成长。GuniWeb 为中型企业优化业务流程,凭借 20 多年的实践经验,提供战略咨询和切实落地的实施服务,让企业不只是变得更数字化,而是运营得更好。此服务就是其中一项解决方案:它已在客户的生产环境中运行,并用于教学和研究。npm 上的编译包依据 ISC 许可证免费使用;源代码不公开。
- 社区——可通过 Issues 和 Discussions 提出问题、报告错误和分享想法,我们会尽力回应。请参阅 SUPPORT.md。
- 生产环境支持——维护订阅服务,提供优先修复、适配 SAP 版本变更以及直接沟通渠道;写入路径还可选择附带响应时间 SLA:guniweb.de/sap-mcp
- SAP MCP 检查——我们会在正式上线前检查您的 n8n/SAP 配置(身份验证、治理、工具可见性、性能):guniweb.de/sap-mcp
联系方式:[email protected]。安全问题:请参阅 SECURITY.md,并留意其中关于零遥测的承诺。
技术
构建所用技术:
- MCP TypeScript SDK v1.x
- axios -- 处理 CSRF 和重定向的 HTTP 客户端
- jose -- 用于 IAS/XSUAA 身份验证的 JWT/JWKS 验证
- fast-xml-parser -- IDoc XML 和 SAML 断言构建
- Zod v4 -- 模式验证
- pino -- 结构化 JSON 日志记录
- tsup -- ESM 打包
- TypeScript 5.9、Node.js >= 22.18.0
SAP、S/4HANA、ECC、NetWeaver、ABAP 是 SAP SE 在德国及其他国家/地区的商标或注册商标。本项目与 SAP SE 无关联。
许可证
ISC
Footnotes
-
必须激活 NetWeaver Gateway ICF 服务(事务代码
SICF)。请参阅SAP ECC 设置。 ↩ ↩2 ↩3 -
ECC 中的 OData V4 很少见;大多数 ECC NetWeaver Gateway 服务都使用 V2。S/4HANA 默认使用 V4。 ↩
-
S/4HANA Cloud Public Edition 不向外部使用方开放 RFC 或传统 IDoc-HTTP。请使用 SAP BTP Integration Suite 作为中间层。 ↩ ↩2
-
主机上需要安装 SAP NW RFC SDK 7.50+。
node-rfc声明为optionalDependencies;如果缺少 SDK,服务会发出启动警告并以降级模式运行。 ↩ ↩2
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。