Skip to main content
Glama

SAP-MCP

通过 ADT 为 SAP 本地部署 提供 MCP 服务器:一个进程同时运行 MCP 端点和 Web 管理界面,可同时连接多个 SAP 系统,内置调试器和运行时诊断工具。工具名称遵循 vibing-steampunk 的 PascalCase 约定,并增加了多系统模型和管理页面。

无需在 SAP 上安装任何 ABAP 对象即可使用——唯一的例外是 RunReport,服务器会自动安装(参见 D 组)。

安装

Windows — 双击 install.bat,或在终端中运行:

install.bat

它会检查 Python 3.10+,创建 .venv,安装依赖,并根据模板文件生成 systems.json。然后打开 systems.json,填写真实 SAP 系统的 URL/用户名/密码,再运行 run.bat

其他平台:

python -m venv .venv && . .venv/bin/activate
pip install -e .
cp systems.example.json systems.json   # sửa URL, user, password
python -m sap_mcp

systems.json 包含密码,且已在 .gitignore 中——不要提交它。

运行服务器

Windows — 双击 run.bat,或:

run.bat              :: cổng 8765, chế độ focused (50 tool)
run.bat 8766         :: đổi cổng
run.bat 8766 expert  :: đổi cổng + bật đủ 66 tool

run.bat 会自动将控制台设置为 UTF-8(日志包含越南语,cp1252 控制台会导致 Python 崩溃),如果 systems.json 不存在则自动从模板创建,并明确提示哪个 PID 占用了端口,而不是让 uvicorn 抛出原始套接字错误。

打开 http://127.0.0.1:8765 添加/编辑/测试系统。MCP 端点在 /mcp

连接到 MCP 客户端

mcp.example.json 复制为项目目录中的 .mcp.json,或将 mcpServers 部分合并到客户端现有的配置文件中:

{
  "mcpServers": {
    "sap-mcp": {
      "type": "http",
      "url": "http://127.0.0.1:8765/mcp"
    }
  }
}

如果使用不同端口运行 run.bat,请相应修改端口。客户端连接前服务器必须已在运行——这是 streamable-http 传输,客户端不会像 stdio 那样自动启动进程。

系统配置(systems.json

字段

默认值

说明

url

SAP 系统的 https://host:port

client

100

sap-client

language

EN

sap-language

username / password

基本身份验证

verify_ssl

true

自签名证书设为 false

ca_bundle

自定义 CA 路径(替代 verify_ssl

timeout

30

常规 HTTP 超时,秒

allow_write

false

启用后才可写入

write_packages

["Z*","Y*","$TMP"]

允许写入的包

write_objects

按对象名称进一步限制

require_transport

true

可传输包必须包含 TR

allow_debug

false

启用后才可使用 D 组(调试器 + 运行代码)

debug_timeout

1800

断点处可停留时间,秒

debug_listen_seconds

300

DebuggerListen 默认等待时间,秒

SAP 标准命名空间中的对象始终被拒绝,无法通过配置关闭。

debug_timeout 不仅仅是一个摆设数字。 代码在断点处停止时会一直持有触发它的 HTTP 请求,因此常规 timeout(30 秒)会在您查看变量时中断:后台线程死亡,报告结果丢失,DebuggerDetach 返回 The read operation timed out 而不是数据。此上限仅在调试期间(有监听器,或正在调试目标处停止时)才会放宽——如果对所有运行都放宽,那么一个挂起的报告会占用 SAP 工作进程半小时而无人查看。

环境变量

变量

默认值

说明

SAP_MCP_SYSTEMS

./systems.json

配置文件路径

SAP_MCP_PORT

8765

HTTP 端口

SAP_MCP_MODE

focused

focused(50 个工具)或 expert(66 个工具)

SAP_MCP_DISABLED_GROUPS

禁用功能组,例如 CC,D

组代码:C 传输请求,D 调试器,P 运行时诊断(转储、跟踪)——请参阅下面的工具部分。核心工具不属于任何组,始终启用。同时禁用两者(SAP_MCP_DISABLED_GROUPS=D,P)会将 focused/expert 恢复为 30/45 个工具。

工具

管理 ListSystems GetConnectionInfo GetSystemInfo

读取 GetSource GetObjectStructure GetClassInfo GetPackage GetFunctionGroup SyntaxCheck · expert: GetProgram GetClass GetInterface GetInclude GetFunction GetClassInclude

GetSource 可以读取片段而不是整个对象:around="SELECT" 获取注释外第一次出现位置周围的窗口,或使用 from_line/to_line 获取精确的行范围。每个片段都以一行注释开头,标明它是片段——只有完整版本才能用于 UpdateSource,用窗口覆盖会删除其余部分。GetPackagemax_objects 上限,并在截断时明确说明。

搜索 SearchObject GrepObjects GrepPackages · expert: GrepObject GrepPackage

数据 RunQuery GetTableContents

RunQuery 执行 Open SQL SELECT 并返回结果表;GetTableContents 为您构建 SELECT 语句。不需要 allow_write,因为SAP 本身会在此端点拒绝写命令:

DELETE FROM t001 …  → 400 Invalid query string. Only SELECT statement is allowed.

读取的屏障是 systems.json 中 SAP 用户的权限——该用户能读取的所有表,代理也能读取,包括人事表。不要配置一个万能用户。

源代码导航 FindDefinition FindReferences

FindDefinition(system, 'CLAS', 'ZCL_X', symbol='cl_salv_bs_runtime_info') — 服务器在源代码中自动查找符号(忽略注释),然后在该位置解析,返回类型、名称和组件列表。不使用 navigation/target,尽管名称听起来更合理:当无法解析时,它返回输入 URI 本身,即假成功。可用的路径是 abapsource/codecompletion/elementinfo,并且它要求 body 中包含完整源代码。

FindReferences 返回使用位置。SAP 返回一个混合了三种节点类型的树;只有 gradeDirect 索引才是真正的使用位置。gradeComponent 是所查询对象自身的组件——如果计算在内,一个无人调用的类会有 6 个使用位置。

写入 WriteSource EditSource Activate ActivatePackage CreatePackage GetInactiveObjects LockObject UnlockObject · expert: CreateObject UpdateSource DeleteObject

综合 CompareSource CloneObject PrettyPrint ImportFromFile ExportToFile

C 组 ListTransports · expert: GetTransport CreateTransport ReleaseTransport DeleteTransport

D 组 — 调试器 SetBreakpoint DeleteBreakpoint DebuggerListen DebuggerPoll DebuggerStopListener DebuggerAttach DebuggerDetach DebuggerGetStack DebuggerGetVariables DebuggerStep RunClass RunReport RunUnitTests

需要 allow_debug: true。使用顺序:

  1. SetBreakpoint — 行必须是可执行语句,而不是声明。无需数行:statement="SELECT" 让服务器自动查找(它会忽略注释,因此不会落入不可执行的行)并报告行号。

  2. DebuggerListen — 立即返回,监听器在后台运行

  3. RunClass / RunReport / RunUnitTests — 运行代码

  4. 如果断点触发,步骤 3 立即返回 已停止在断点…(不是数据)。DebuggerPoll 随时报告状态。

  5. DebuggerAttachDebuggerGetStack / DebuggerGetVariables / DebuggerStep

  6. DebuggerDetach — 释放调试目标;代码继续运行,步骤 3 的结果在此返回(如果运行时间长,则在 DebuggerPoll 中返回)

如果没有断点触发,步骤 3 像普通工具一样直接返回结果。

为什么三个运行代码的工具在后台运行。 当代码在断点处停止时,SAP 会持有正在运行的 HTTP 请求——调用只有在调试目标被释放后才会返回。如果同步调用,工具本身会挂起,代理永远无法调用 DebuggerAttach 来释放它:自我死锁。因此,这三个工具在后台线程的单独会话中运行,并在监听器捕获到调试目标后立即响应。

调试时,每个系统使用三个独立的 HTTP 会话:一个用于监听器 + 调试会话(有状态的,会保持数十秒),一个用于运行代码(可能被阻塞直到调试目标被释放),一个用于设置/删除断点。如果不分离,它们会相互阻塞:在监听器的会话上运行代码只能插入两个长轮询循环之间的间隙——恰好 SAP 没有注册监听器,因此断点永远不会触发。

调试带选择屏幕的报告。 外部断点无法捕获对话框会话——在 SE38 中按 F8 时调试器看不到任何内容(已在真实系统上测试)。在步骤 3 中使用 RunReport 而不是 RunClass:它在外部会话中运行报告,因此断点才会触发。

RunReport 阻止 ALV 显示但仍能获取数据(cl_salv_bs_runtime_info),因此以 ALV 结尾的报告不会中途转储。接受 PARAMETERSSELECT-OPTIONS(参数名以 S_ 开头)以及变体。

RunReport 写入 SAP,因此它需要 allow_writeallow_debug,而不像其他调试器工具那样只需要 allow_debug。服务器自动将两个对象安装到 $TMP 中,您无需执行任何操作:

  • ZCL_MCP_RUNNER — 中间类,通用且永远不会被修改。它执行 SUBMIT (mv_report) WITH SELECTION-TABLE mt_sel,即报告名称和整个选择屏幕都是运行时数据。

  • ZMCP_RUNNER_ARGS — 仅包含注释行的程序,每次运行前都会被覆盖。类在运行时使用 READ REPORT 读取它。

*@MCP TOKEN 24b8bff8dfb8477b
*@MCP REPORT ZPG_DEMO
*@MCP MAX 100
*@MCP SEL S_BUKRS S I BT
*@MCP LOW 1000
*@MCP HIGH 2000

为什么仍然需要写入:IF_OO_ADT_CLASSRUN~MAIN( out ) 不接受任何参数——没有查询参数,没有请求体。对象的源代码是 ADT REST 开放的唯一定参数通道。

最重要的后果是安全:代理提供的任何内容都不再成为 ABAP 代码。以前的版本将过滤值嵌入 ABAP 字面量中,因此一个引号泄漏就可以向 SAP 系统注入任意命令——该位置必须转义才能安全。现在该值位于注释行中,并通过 RSPARAMS 表到达 SAP,因此没有语法可以破坏。只有换行符被禁止(它会生成一个假的参数字段),超过 45 个字符的值会被拒绝,因为 RSPARAMS-LOWCHAR45——SAP 会静默截断,这意味着过滤错误而无人知晓。

每次运行都携带一个令牌;类返回该令牌,服务器进行核对。如果参数写入损坏但仍继续运行,则报告使用旧参数运行,结果被标记为新请求——令牌是防止这种静默错误的屏障。

与 vibing-steampunk(需要 ZADT_VSP 插件:1 个接口、3 个类、WebSocket 处理器)相比,RunReport 需要更少,且无需手动配置 SAPC 和 SICF:

vsp (ZADT_VSP)

SAP-MCP (RunReport)

必须安装的 ABAP 对象

4

2

SAPC + SICF 配置

需要基础管理员

不需要

服务器自动安装

每次运行都修改的类

SELECT-OPTIONS

否(硬编码 kind='P'

每次运行都写入 SAP

是(一个注释文件)

最后一行是不需要管理员安装任何东西的代价:vsp 通过 WebSocket 传递参数,因此不接触系统,而 RunReport 通过源代码传递,因为 ADT REST 没有打开其他通道。作为交换,被写入的对象是一个仅包含注释的文件——它没有语法可以损坏,而包含逻辑的类保持不变。

P 组 — 运行时诊断 ListDumps GetDump StartTrace ListTraces GetTrace DeleteTrace GetSQLTraceState · expert: DeleteTraceRequest

短转储(ST22)。 ListDumpsuser/error/program/since 过滤, GetDump 返回 summary(发生了什么、错误分析、停止位置、调用 栈)、source(死点处的源代码)、fullmeta

性能测量(SAT/ATRA)。 StartTrace('ZPG_X', 'report') → 运行代码 → ListTracesGetTraceGetTrace 默认返回按调用排序的耗时分析, 按降序排列;view='db' 返回按表统计的数据库访问——次数、从缓冲区读取 次数、耗时。RunReport(..., trace=True) 将整个流程简化:它会自动 为正确的报表设置限定的测量请求。

   NET µs      %  GROSS µs   LẦN  GỌI TỪ                     VIỆC
     3800   51.2      3800     1  CL_HTTP_SERVER_NET=======C DB: Exec Static
      368    5.0      4185     1  SAPLHTTP_RUNTIME           Call M. …SEND_RESPONSE

NW 758 上实测的三件事,与 vibing-steampunk 的假设相反—— 如果照做,每一件都会静默地破坏工具:

vsp 的做法

在 NW 758 上实测的结果

feed dump 的 Accept

application/atom+xml

406 — 必须是 …;type=feed

过滤 dump

发送 $filter FQL

SAP 忽略,返回完整列表

ST05 trace/directory

当作 feed trace 读取

返回一个 Fiori URL,没有记录

所以 ListDumps 在 MCP 服务器端过滤,SQL 语句取自 ABAP trace 的 dbAccesses 而不是 ST05。GetSQLTraceState 仍然有用,用于检测被遗忘的 trace 仍处于开启状态——它会拖慢整个系统,但从外部看不出任何迹象。

StartTrace 必须指定对象名称。 一个不限范围的 trace 请求会立刻 捕获到刚刚发出它的那个 HTTP 调用本身:得到的测量结果全是 ICFSERVICE/HTTP_HEADER_REG——测的是 ADT 引擎而不是你的代码—— 但看起来仍然是一份非常真实的数字表格。有了限定,测量结果就会准确落在 后续的那次运行上(T001DDFTXVARID…)。

StartTraceDeleteTraceDeleteTraceRequest 需要 allow_debug: 它们会改变系统的行为,而被遗忘的请求会偷偷测量后续的某次运行。三个 只读工具(ListDumpsGetDumpGetSQLTraceState)则不需要任何权限。

状态

核心工具组、D 组(调试器,包括 RunReport)和 P 组(dump + trace) 已完成——50 个工具处于 focused 模式 / 66 个处于 expert 模式,已在 NetWeaver 758 上运行。DDIC/i18n、abapGit 和 ABAP helper 部分尚未完成。

已知限制

1. ImportFromFile / ExportToFile 不限制路径。 这两个工具接受 模型传入的任何路径。import_from_file 只检查 os.path.isfileexport_to_file 只检查 os.path.isdir——没有白名单,不限制在某个 工作区目录内,不阻止 .. 或绝对路径。因此,一个 agent——包括受其从 SAP 读取内容影响的 agent——可以读取服务器进程能读取的任何文件并送入 SAP,或将 SAP 源代码写入任何可写路径。当前的风险缓解措施:只在你能 控制的机器上运行服务器,使用一个除了你希望 agent 拥有的权限之外没有 任何文件访问权限的账户。

2. REST 管理路由没有认证。 //api/systems* 仅通过绑定到 127.0.0.1 来保护。任何能访问该端口 loopback 的东西都可以列出、添加、 修改、删除系统配置并触发连接测试。不要将此端口暴露到本地机器之外, 也不要在共享主机上运行它。

3. 调试器可以读取内存中的所有变量。 DebuggerGetVariables 返回 断点处的真实值,包括变量中存在的敏感数据——密码、密钥、个人数据。 这是调试的本质,不是缺陷。此外,RunClass 可以执行任意 ABAP 代码。 因此 allow_debug 默认关闭,只应在开发系统上开启。

4. RunReport 共享一个参数文件。 $TMP 中的 ZMCP_RUNNER_ARGS 在每次运行前被覆写。在单个服务器内,运行已经排队(每个系统一个执行 通道),但两个服务器或两个人使用同一个系统时仍会互相覆盖参数。输出中 的 token 能检测到这种情况并将其转为错误,而不是返回错误数据。 vibing-steampunk 通过为每个会话使用独立的 APC WebSocket 来完全规避, 代价是需要手动配置 SICF。

架构

transport/(HTTP、认证、CSRF)→ adt/(对象类型、返回数据)→ tools/(格式化 + MCP 注册)。adt/uri.py 表是构建 URI 的唯一来源。 D 组额外为每个系统使用三个 AdtSessiontransport/debug_pool.py, 按通道划分),因为 listener 在后台运行,调试会话必须在多次调用之间 保持连续状态,且正在运行的代码可能被阻塞在断点处——这些会话没有一个 能从共享的 SessionPool 借用。

工具在 worker 线程中运行,不在事件循环上。 FastMCP 直接在事件循环 上调用同步函数,所以如果保持原样,一次 SAP 调用就会阻塞整个服务器: 在 RunReport 等待期间 agent 无法调用 DebuggerPoll,不同的系统会 互相阻塞,web 管理界面也会卡死。tools/_registry.py 在注册前用 anyio.to_thread.run_sync 包装每个工具。按系统串行化的机制仍然保留, 而且是有意为之——它位于 SessionPool 中,因为 SAP 的锁句柄仅对每个 系统的一个连接有效。

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Hosted Amazon Seller and Vendor MCP server for Claude, ChatGPT, Cursor, Codex, Gemini, Copilot.

  • Official Microsoft MCP Server to query Microsoft Entra data using natural language

  • GibsonAI MCP server: manage your databases with natural language

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/NhatPD-VNEXT/SAP-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server