Metadata-Version: 2.5
Name: sap-universal-mcp
Version: 0.12.1
Summary: 统一 SAP MCP 服务器:一个工具连接 R/3 (ECC)、S/4HANA、PCE (RISE 私有云) 与 S/4HANA Public Cloud,Mac / Windows / Linux 通用
Project-URL: Homepage, https://github.com/your-org/sap-universal-mcp
Author: Dylan
License: MIT
License-File: LICENSE
Keywords: mcp,model-context-protocol,odata,rfc,s4hana,sap
Requires-Python: >=3.10
Requires-Dist: cryptography>=42
Requires-Dist: fastmcp>=2.3
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.7
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Provides-Extra: rfc
Requires-Dist: pyrfc>=3.3; extra == 'rfc'
Description-Content-Type: text/markdown

# sap-universal-mcp

统一 SAP MCP 服务器:**一个工具连接四种 SAP 形态**,Mac / Windows / Linux 通用。

| 形态 | 认证 | 数据通道 | 表读取 | 自由 SQL |
|---|---|---|---|---|
| R/3 / ECC | 用户密码 | **RFC/BAPI** | ✅ RFC_READ_TABLE(自动分块) | ✅(需 ABAP 附加组件) |
| S/4HANA On-Premise | 用户密码 | OData + RFC | ✅ | ✅(需 ABAP 附加组件) |
| PCE(RISE 私有云) | 用户密码 | OData + RFC(saprouter/白名单) | ✅ | 视客户配置 |
| S/4HANA Public Cloud | **OAuth2 通信安排** | 白名单 OData API | ❌ → 引导 Custom CDS Views | ❌(物理不存在) |

设计原则:
- **能力自适应**——启动时按系统配置自动选择通道;不支持的操作返回"替代建议"而不是报错
- **安全护栏**——密码走环境变量不入配置文件;`read_only` / `allow_free_sql` / `max_rows` 三道闸;全部调用落审计日志
- **轻量**——核心仅依赖 fastmcp/httpx/pydantic,RFC 与 GUI 自动化都是可选安装

## 安装

**要求 Python 3.10–3.12**(启用 RFC 通道时 pyrfc 只支持到 3.12)。

```bash
# 基础安装(OData / 公有云通道,无需任何 SAP SDK)
pip install sap-universal-mcp        # 或: uvx sap-universal-mcp
# 或源码
git clone <repo> && cd sap-universal-mcp
uv venv -p 3.11 && uv pip install -e .

# 可选:RFC 通道(R/3 老系统 / 任意读表)
uv pip install -e ".[rfc]"
```

### RFC 通道前置(仅 R/3 直连需要)

pyrfc 不捆绑 NWRFC SDK(SAP 许可限制),需手工准备:

1. 从 SAP Support Portal 下载 **NWRFC SDK**(Windows: NWRFCSDK_*.zip;macOS: MACOSX_*.sar)
2. 解压到固定目录,设置环境变量:
   - macOS/Linux:`export SAPNWRFC_HOME=/usr/local/nwrfcsdk`(`DYLD_LIBRARY_PATH`/`LD_LIBRARY_PATH` 加 `$SAPNWRFC_HOME/lib`)
   - Windows:把 `nwrfcsdk\lib` 加入 `PATH`
3. `uv pip install -e ".[rfc]"` 会装 pyrfc 3.3.1(SAP 已归档的最终版,功能稳定)

不装 RFC 也能用:OData / 公有云通道完全独立。

## 配置

复制 `examples/systems.example.json` 到 `~/.sap-universal-mcp/systems.json`(或设 `SAPMCP_CONFIG` 指向任意路径),按系统修改。

**密码永远放环境变量**,命名规则 `SAPMCP_<系统名>_PASSWORD`:

```bash
export SAPMCP_S4_DEV_PASSWORD='xxx'
export SAPMCP_PUBLIC_CLOUD_SECRET='sb-xxx 的 client secret'
```

配置校验(不启动服务):

```bash
sap-universal-mcp --check
```

## 接入 MCP 客户端

**Claude Desktop / Cursor / ZCode / 任意 MCP 客户端**(stdio):

```json
{
  "mcpServers": {
    "sap": {
      "command": "/path/to/.venv/bin/sap-universal-mcp",
      "env": {
        "SAPMCP_S4_DEV_PASSWORD": "xxx",
        "SAPMCP_PUBLIC_CLOUD_SECRET": "yyy"
      }
    }
  }
}
```

Windows 把 command 换成 `.venv\Scripts\sap-universal-mcp.exe`。

**HTTP 模式**(多客户端共享):

```bash
sap-universal-mcp --http 127.0.0.1:8321
```

## 工具一览

| 工具 | 说明 | 通道 |
|---|---|---|
| `sap_status` | 活动系统 / 能力矩阵 / 护栏配置 | - |
| `sap_use_system` | 切换目标系统 | - |
| `sap_probe` | 探测连通性(OData/WebGUI/RFC 库) | - |
| `sap_list_services` | 枚举 OData 服务(公有云=白名单) | OData |
| `sap_service_metadata` | 实体集/主键/字段 | OData |
| `sap_query` | 通用查询($filter/$select/$top…) | OData |
| `sap_read_table` | 任意表读取(512 字节自动分块) | RFC |
| `sap_call_rfc` | RFC/BAPI 通用调用 | RFC |
| `sap_exec_sql` | 自由 SELECT(三道护栏) | RFC+ABAP |
| `sap_dev_check` | ADT 开发通道自检 | ADT |
| `sap_dev_create` | 通用创建:类/接口/程序/CDS 视图/服务定义/**服务绑定** | ADT |
| `sap_dev_write` | 写源码(状态会话锁定协议) | ADT |
| `sap_dev_activate` | 两段式激活握手 | ADT |
| `sap_dev_syntax_check` | 语法检查(含 CDS) | ADT |
| `sap_dev_publish` | 发布服务绑定(Fiori 应用上线) | ADT |
| `sap_dev_table_preview` | 任意表读取(SE16 平替,零授权零安装) | ADT |
| `sap_dev_sql_preview` | 自由 SELECT(免 ABAP 附加组件) | ADT |

审计日志:`~/.sap-universal-mcp/audit/audit-YYYYMMDD.jsonl`(工具/系统/参数摘要/行数/耗时,凭证自动脱敏)。

## 自由 SQL 的 ABAP 附加组件

`exec_sql` 不是 SAP 标准能力,需在目标系统部署一个 Z 函数(约 80 行,`abap/Z_SAPMCP_EXEC_SQL.abap`):

1. SE37 → 创建函数组 `Z_SAPMCP` → 新建 RFC 函数 `Z_SAPMCP_EXEC_SQL`(启用远程调用)
2. 粘贴 `abap/` 目录代码,激活
3. systems.json 中该系统 `"allow_free_sql": true`

函数内部强制仅 SELECT + 关键字黑名单,配合接口用户的表级授权双重防护。

## 公有云快速接入

1. 系统 → 通信管理 → 创建 **Communication System** + **Communication Arrangement**(选一个 API 场景,如 `SAP_COM_0009`)
2. 生成 service key,拿到 `clientid` / `clientsecret` / `tokenurl`(即 `oauth.token_url`)
3. 把要用的 API 路径填进 `api_whitelist`(与 [SAP API Hub](https://api.sap.com) 上的服务一致)
4. 导出 `SAPMCP_PUBLIC_CLOUD_SECRET=<clientsecret>`

## 与参考项目的关系

设计吸收了社区项目的经验:[thupalo/sap-rfc-mcp-server](https://github.com/thupalo/sap-rfc-mcp-server)(RFC 元数据缓存、安全配置分层)、[GutjahrAI/sap-odata-mcp-server](https://github.com/GutjahrAI/sap-odata-mcp-server)(服务发现策略、错误码翻译)、[sap-ai-mcp-servers 清单](https://github.com/marianfoo/sap-ai-mcp-servers)。差异点:四形态统一适配、能力探测降级、中英双语错误提示、开箱即用的双平台分发。

## 路线图

- [ ] RFC 元数据磁盘缓存(降低重复 STFC 调用)
- [ ] 写操作通道(CRUD + BAPI COMMIT,白名单函数级授权)
- [ ] Playwright 兜底通道(R/3 ITS WebGUI / PCE 登录,懒加载)
- [ ] Web GUI 脚本通道(Windows COM)
- [ ] PyPI 发布 + uvx 一键运行

## License

MIT


## AI 辅助 ABAP 开发(ADT 通道,v0.2.0)

公有云开发者扩展(Developer Extensibility)走 ADT REST API(与 Eclipse 同款),已用真实租户全链路验证:
SSO 浏览器登录(支持 MFA)→ 建请求号 → 建包(自动继承软件组件)→ 建类/CDS/服务定义/服务绑定 →
写码 → 激活 → 语法检查 → 发布成 Fiori 应用。

```bash
# 首次/会话过期时:弹出浏览器完成 SSO 登录(8 小时有效)
sap-universal-mcp login <系统名>
```

协议要点(踩坑记录,详见 adapters/adt.py 注释):
- 锁定→写码→解锁必须在同一 ICM 状态上下文(`X-sap-adt-sessiontype: stateful` + `sap-contextid` cookie)
- 激活是两段式握手(preaudit 返回补齐清单后需二次提交)
- 服务绑定的 `srvb:type` 合法值是 `ODATA`,UI/API 区分在 `category`(0=UI,1=API)
- 改过的对象要用 `?version=inactive` 的 ETag 写入


## 乙方多客户场景(v0.3.0+)

给咨询/乙方团队的设计:一个顾问,多个客户,每个客户 DEV/QAS/PRD。

**按客户拆配置文件**(systems.d 目录,合并加载):
```
~/.sap-universal-mcp/systems.d/
  10_tontec.json    # {"active": "tontec_dev", "systems": {...}}
  20_acme.json
```
启动参数指向目录即可:`sap-universal-mcp -c ~/.sap-universal-mcp/systems.d`

**系统角色红线**(`"role": "DEV|QAS|PRD"`):
- PRD:一律禁写,`read_only: false` 也无法覆盖
- QAS:默认禁写(开发在 DEV 完成后走传输)
- 拒绝动作进审计日志

**操作者角色矩阵**(环境变量 `SAPMCP_ROLE=developer|tester|consultant`):
- developer:仅 DEV 系统可写
- tester / consultant:工具内一律只读

**凭证仓库**:`~/.sap-universal-mcp/credentials.json`(建议 chmod 600)。
优先级:配置内 password > 环境变量 > 凭证仓库。

**状态分组**:`sap_status` 按 customer 分组展示系统、角色与可写状态。

## Windows

- 安装同 Mac(Python 3.10-3.12);启动器用 `start-mcp.bat`
- RFC 通道把 `nwrfcsdk\lib` 加入 PATH;其余通道无平台差异
- SSO 浏览器登录用 Edge/Chrome 自动回退

## 发布

```bash
uv build && uv publish   # 需要 PyPI token
```


## 代码管理:Git 作为唯一真相源(v0.6.0)

继承 sap-ai-kit 的核心信条:**程序版本以 Git 为准(AI 和人共用),凭证永不入库**。

- 仓库布局:`~/.sap-universal-mcp/coderepo/<客户>/<系统>/<包>/<类型>/<对象>.abap`(配置 `code_repo` 可改路径)
- **写 SAP 成功 → 自动落盘 + git 提交**(带系统/请求号元数据;归档失败不阻断写)
- `sap_dev_pull`:把 SAP 对象拉回仓库(接手客户代码、盘点归档)
- `sap_dev_push`:把仓库对象部署回 SAP(走 confirm 写确认流程,换系统/交付部署)
- `sap_repo_status`:仓库总览(对象清单/客户分组/最近提交/脏文件)
- git 缺失时自动降级为"只落盘不提交"


## 传输与仓库治理(v0.7.0)

- `sap_dev_delete`:删除对象(stateful 协议)+ 代码仓库自动打墓碑,confirm 确认
- `sap_dev_transport_info`:请求详情(状态/任务/对象清单),释放前检查
- `sap_dev_diff`:SAP 与代码仓库源码对比,防覆盖(push/pull 前建议先 diff)
- `sap_dev_release_transport`:释放请求(自动先释放任务,处理"互锁"报错的根因)
- ADT 全请求状态化修复:CSRF 探测退休 SSO 会话的病根(公有云/PCE 通用)


## 写操作通道(v0.8.0)

`sap_create_entity` / `sap_update_entity`:OData 创建/更新业务数据。**已在 Tontec PCE 真机验证**:
AI 全程自主创建采购订单:PCE 4210000212(NB,公司 3101,创建人 ITSHZY);公有云一次通过 4500000077(公司 8010)——双租户写验证。

安全模型:
- 写前确认(confirm 预览 → 确认执行),全程审计日志
- PRD/QAS 系统硬拦截(不可覆盖),操作者角色矩阵叠加
- CSRF 会话绑定教训已固化:token 与会话 cookie 必须同会话

多轮业务校验实战(每轮 SAP 报错 → AI 修正 payload → 下一关):
订单类型须 NB → 计划行交货日期必填 → 物料须在工厂有主数据且外购 → 净价 > 0 → 成功。

现场发布 OData 服务的完整手册(踩坑实录):
PFCG S_SERVICE(值帮助选 IWSV)→ /IWFND/MAINT_SERVICE 添加服务(**系统别名用 LOCAL1**
——带路由标志的 LOCAL 别名会导致运行时 MED/170 不可解析)→ /IWFND/CACHE_CLEANUP 全局清缓存。


## RAP 可编辑应用一键生成(v0.9.0)

`sap_dev_create_rap_app`:**一次调用生成完整可增删改的 Fiori Elements 应用**(8 对象):
数据表(TABL)→ CDS 根视图 → BP 类 → 行为定义(BDEF,strict(2) 托管)→ 投影视图 →
元数据扩展(DDLX)→ 服务定义(SRVD)→ 服务绑定(SRVB)+ 发布。

- 模板遵循 ABAP Cloud 官方规范(uuid 主键 / abp_ 管理字段 / @Semantics 注解 `: true` /
  字段 CamelCase 别名 / 视图不选 client / @Metadata.layer 必填)
- 编排:骨架创建(已存在自动跳过,支持断点续跑)→ 源码 → 分组激活 → 发布
- 真机验证(公有云):NOTE 应用 8 对象全部生成并激活(请求号 H59K901498)
- 已知边界:个别租户的 `publishjobs`(本地服务端点激活)可能持续失败——绑定本身已 active,
  Eclipse 里打开绑定点一次"发布"按钮即可;或稍后重试 `sap_dev_publish`
- 类型租户差异:`abp_last_change_tstmpl` 在部分租户未释放(DDIC 激活日志可诊断),模板已移除该字段
- BDEF 与 BP 类互相引用,必须同批激活(生成器已内置)


## UI5 应用生成器(v0.10.0)

`sap_dev_generate_ui5`:**需求 → 完整 UI5 freestyle 应用**(列表+新增对话框+删除+内联编辑)。

- AI 把用户需求解读为 spec(应用名/标题/服务/实体集/字段清单),工具负责生成合规代码
- 产物:manifest/视图/控制器/i18n/index.html/README 共 7 文件,落代码仓库 `_ui5/<应用名>/` 并 git 提交
- 不触 SAP(本地生成),部署走 BAS/npm deploy(部署定为人工流程)
- 真机演示:为 RAP 应用 ZSB_AIFI_NOTE 生成 notemgr 前端
- 65 测试全绿


## 影响分析与代码检查(v0.11.0)

- `sap_dev_where_used`:对象使用位置(ADT usageReferences POST 变体,含包/类型/描述)。
  注意:RIS 不索引 SRVD/SRVB 等非代码引用,业务代码引用(类/程序/CDS)可靠。
- `sap_dev_atc`:ATC 代码检查(运行→工作清单→发现项)。on-prem/PCE 可用(需检查变体,
  如 `ABAP_CLOUD_DEVELOPMENT_DEFAULT`);**公有云租户不支持即席运行**(422/SATC,SAP 中心管道执行),
  工具返回明确说明并建议改用 `sap_dev_syntax_check`。


## 文档地图

| 文档 | 内容 |
|---|---|
| [PITFALLS-AND-GUIDE.md](docs/PITFALLS-AND-GUIDE.md) | 30 坑实录 + 功能全景 + **前置条件矩阵** + 甲方管理员清单 |
| [EDITIONS.md](docs/EDITIONS.md) | 版本分层 + 许可证机制 + 团队分发三层防护 |
| [TEAM-ONBOARDING.md](docs/TEAM-ONBOARDING.md) | 团队装用手册(顾问/开发) |
| [RFC-SETUP.md](docs/RFC-SETUP.md) | RFC 通道安装(Mac/NWRFC SDK/Rosetta) |
| docs/legacy-sap-ai-kit/ | 前代参考实现档案(设计/教训) |

## 版本分层与许可证(v0.12.0)

**顾问版**(默认,只读工具全开放)/ **开发版**(全功能)由 Ed25519 签名许可证控制——
只有持有根私钥的发行者能签发开发版许可。详见 [docs/EDITIONS.md](docs/EDITIONS.md)。

```bash
sap-universal-mcp license show    # 查看当前版本
```

原 sap-ai-kit(参考实现)的设计资产已合并至 docs/legacy-sap-ai-kit/。
