SAP-MCP
SAP-MCP
MCP-сервер для SAP on-premise через ADT: один процесс запускает и MCP-эндпоинт, и веб-админку, подключается к нескольким системам SAP одновременно, имеет отладчик и инструменты диагностики рантайма. Имена инструментов следуют соглашению PascalCase из vibing-steampunk, плюс мультисистемная модель и страница администрирования.
Устанавливать объекты ABAP на SAP не нужно — единственное исключение — RunReport, и сервер устанавливает его сам (см. раздел Группа D).
Установка
Windows — двойной клик по install.bat, или выполните в терминале:
install.batСкрипт проверяет Python 3.10+, создаёт .venv, устанавливает зависимости и создаёт systems.json из файла-шаблона. Затем откройте systems.json, укажите URL / пользователя / пароль реальной системы SAP и запустите 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_mcpsystems.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 toolrun.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)
Поле | По умолчанию | Назначение |
| — |
|
|
|
|
|
|
|
| — | Базовая аутентификация |
|
| Установите |
| — | Путь к собственному CA (вместо |
|
| Обычный лимит HTTP, секунды |
|
| Включает запись |
|
| Пакеты, в которые разрешена запись |
| — | Дополнительное ограничение по именам объектов |
|
| Для транспортабельных пакетов обязателен TR |
|
| Включает группу D (отладчик + запуск кода) |
|
| Сколько можно стоять на брейкпоинте, секунды |
|
| Время ожидания по умолчанию для |
Объекты в стандартном пространстве имён SAP всегда отклоняются, отключить это настройкой нельзя.
debug_timeout — не просто число для галочки. Код, остановленный на брейкпоинте, удерживает HTTP-запрос, который его запустил, поэтому обычный timeout (30 с) обрывает всё, пока вы смотрите переменные: фоновый поток умирает, результат отчёта теряется, DebuggerDetach возвращает The read operation timed out вместо данных. Этот лимит увеличивается только во время отладки (есть listener или остановка на debuggee) — если увеличивать для всех запусков, зависший отчёт будет полчаса держать рабочий процесс SAP, и никто на это не посмотрит.
Переменные окружения
Переменная | По умолчанию | Назначение |
|
| Путь к файлу конфигурации |
|
| HTTP-порт |
|
|
|
| — | Отключение групп функций, например |
Коды групп: 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; перезапись окном удалит остальную часть. GetPackage имеет лимит max_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.Барьер для ЧТЕНИЯ — это права пользователя SAP в systems.json — всё, что этот пользователь может читать, прочитает и агент, включая кадровые таблицы. Не настраивайте универсального пользователя.
Навигация по исходному коду FindDefinition FindReferences
FindDefinition(system, 'CLAS', 'ZCL_X', symbol='cl_salv_bs_runtime_info') — сервер сам находит символ в исходнике (пропуская комментарии) и разрешает его в этом месте, возвращая тип, имя и список компонентов. Не используйте navigation/target, хотя название звучит логичнее: при неудаче он возвращает тот же входной uri, то есть ложный успех. Рабочий путь — abapsource/codecompletion/elementinfo, и он требует весь исходник в теле запроса.
FindReferences возвращает where-used. 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. Порядок действий:
SetBreakpoint— строка должна быть исполняемым оператором, а не объявлением. Считать строки не нужно:statement="SELECT"— сервер найдёт сам (он пропускает комментарии, так что не попадёт на неисполняемую строку) и сообщит номер строки.DebuggerListen— возвращается сразу, listener работает в фонеRunClass/RunReport/RunUnitTests— запуск кодаЕсли брейкпоинт сработал, шаг 3 сразу возвращает
Остановлено на брейкпоинте …(не данные).DebuggerPollсообщает состояние в любой момент.DebuggerAttach→DebuggerGetStack/DebuggerGetVariables/DebuggerStepDebuggerDetach— освобождает debuggee; код дорабатывает, и результат шага 3 возвращается здесь (или вDebuggerPoll, если выполнение долгое)
Если ни один брейкпоинт не сработал, шаг 3 возвращает результат напрямую, как обычный инструмент.
Почему три инструмента запуска кода работают в фоне. Когда код останавливается на брейкпоинте, SAP удерживает HTTP-запрос, который его запустил — вызов вернётся только после освобождения debuggee. При синхронном вызове сам инструмент зависнет, и агент никогда не сможет вызвать DebuggerAttach, чтобы его освободить: сам себя заблокирует. Поэтому эти три инструмента работают в отдельной сессии в фоновом потоке и отвечают сразу, как только listener поймает debuggee.
Каждая система использует три отдельные HTTP-сессии при отладке: одна для listener + сессии отладки (stateful, удерживается десятки секунд), одна для запуска кода (может быть заблокирована до освобождения debuggee), одна для установки/снятия брейкпоинтов. Без разделения они блокируют друг друга: запуск кода в сессии listener может вклиниться только в промежуток между двумя циклами long-poll — как раз когда у SAP нет зарегистрированного listener, поэтому брейкпоинт никогда не сработает.
Отладка отчётов с selection-screen. Внешний брейкпоинт не ловит диалоговую сессию — при F8 в SE38 отладчик ничего не видит (проверено на реальной системе). Используйте RunReport вместо RunClass на шаге 3: он запускает отчёт во внешней сессии, поэтому брейкпоинт срабатывает.
RunReport перехватывает отображение ALV, но при этом получает данные (cl_salv_bs_runtime_info), так что отчёт, заканчивающийся ALV, не падает с дампом на середине. Принимает и PARAMETERS, и SELECT-OPTIONS (имена параметров, начинающиеся с S_), и вариант.
RunReport пишет в SAP, поэтому ему нужны и allow_write, и allow_debug, а не только allow_debug, как остальным инструментам отладчика. Сервер сам устанавливает два объекта в $TMP, вам ничего делать не нужно:
ZCL_MCP_RUNNER— промежуточный класс, универсальный и никогда не изменяется. Он выполняетSUBMIT (mv_report) WITH SELECTION-TABLE mt_sel, то есть имя отчёта и весь selection-screen — это данные времени выполнения.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 ) не принимает никаких параметров — ни query-параметров, ни тела. Исходник объекта — единственный канал передачи параметров, который открывает ADT REST.
Самое важное следствие — безопасность: ничто, предоставленное агентом, больше не становится кодом ABAP. Предыдущая версия встраивала значения фильтров в литералы ABAP, поэтому одна проскочившая кавычка позволяла вставить произвольную команду в систему SAP — это место нужно было экранировать, чтобы было безопасно. Теперь значение находится в строке комментария и попадает в SAP через таблицу RSPARAMS, так что ломать синтаксис нечем. Запрещён только символ перевода строки (он порождает фиктивную строку параметра), а значения длиннее 45 символов отклоняются, потому что RSPARAMS-LOW — это CHAR45 — SAP молча обрежет, то есть фильтр будет неверным, и никто не узнает.
Каждый запуск несёт токен; класс возвращает этот токен, и сервер сверяет. Если запись параметра повреждена, а выполнение продолжается, отчёт запустится со старыми параметрами, а результат будет помечен меткой нового запроса — токен блокирует именно такую тихую ошибку.
По сравнению с vibing-steampunk (требует плагин ZADT_VSP: 1 интерфейс, 3 класса, WebSocket-обработчик), RunReport требует меньше и не нуждается в ручной настройке SAPC + SICF:
vsp ( | SAP-MCP ( | |
Объектов ABAP для установки | 4 | 2 |
Настройка SAPC + SICF | нужен админ basis | нет |
Сервер устанавливает сам | нет | да |
Класс изменяется при каждом запуске | нет | нет |
SELECT-OPTIONS | нет (захардкожено | да |
Запись в SAP при каждом запуске | нет | да (один файл-комментарий) |
Последняя строка — цена отсутствия необходимости в админе для установки: vsp передаёт параметры через WebSocket и не трогает систему, RunReport передаёт через исходник, потому что ADT REST не открывает другого канала. Взамен записываемый объект — это файл, состоящий только из комментария — в нём нечему ломаться, а класс с логикой остаётся неизменным.
Группа P — диагностика рантайма ListDumps GetDump StartTrace ListTraces
GetTrace DeleteTrace GetSQLTraceState · expert: DeleteTraceRequest
ST22(短转储)。 ListDumps 按 user/error/program/since 过滤,
GetDump 返回 summary(发生了什么、错误分析、停止位置、调用
栈)、source(停止位置的源代码)、full 或 meta。
性能测量(SAT/ATRA)。 StartTrace('ZPG_X', 'report') → 运行代码 →
ListTraces → GetTrace。GetTrace 默认返回 db 格式的跟踪记录,
按 view='db' 过滤;view='all' 则返回所有记录。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 上**,与那些蒸汽朋克风格的东西相反:
| 功能 | 之前 | 之后 |
| --------------- | ---------------------- | -------------------------- |
| dump 的 Accept 头 | `application/atom+xml` | **406** — 应为 `…;type=feed` |
| dump 过滤 | 发送 `$filter` FQL | SAP **忽略**,返回完整列表 |
| ST05 跟踪目录 | 读取为 feed | 返回 **一个 Fiori URL**,无记录 |
所以 `ListDumps` 在 MCP 服务器端过滤,SQL 从 ABAP 的 `dbAccesses`
中获取,而不是从 ST05 获取。`GetSQLTraceState` 仍然有助于检测被遗忘的
跟踪是否处于开启状态——它会让整个系统变慢,但从外部看不到任何迹象。
**`StartTrace` 需要对象名称。** 无限制的跟踪请求会
立即捕获刚刚发出的 HTTP 调用本身:
`ICFSERVICE`/`HTTP_HEADER_REG` — 它测量的是 ADT 框架,而不是你的代码。
有限制的跟踪则准确落在后续的运行上(`T001`、`DDFTX`、`VARID`…)。
**`StartTrace`、`DeleteTrace`、`DeleteTraceRequest` 需要 `allow_debug`:** 它们会改变
系统行为,而被遗忘的跟踪会悄悄地拖慢后续的每次运行。这三个工具
(`ListDumps`、`GetDump`、`GetSQLTraceState`)则不需要。
**状态**
核心工具组,调试器组(包括 `RunReport`)以及 dump + 跟踪
组 — 在 NW 758 上以 focused / expert 模式全部完成。
DDIC/i18n、abapGit 和 ABAP helper 尚未完成。
**已知限制**
**1. `ImportFromFile` / `ExportToFile` 不限制路径。** 这两个
工具接受模型提供的任何路径。`import_from_file` 只检查
`os.path.isfile`,`export_to_file` 只检查 `os.path.isdir` — 没有
白名单,不限制工作区目录,不阻止 `..` 或
绝对路径。因此,任何 agent — 包括受从 SAP 读取内容影响的 agent —
都可以读取服务器进程能读取的任何文件,或将 SAP 源代码写入任何可写路径。
目前的缓解措施:只在您控制的机器上以受限账户运行服务器,该账户只能访问您希望 agent 拥有的文件。
**2. 管理路由无认证。** `/` 和 `/api/systems*` 仅通过
绑定到 `127.0.0.1` 来保护。任何能访问回环接口的东西
都可以列出、添加、修改、删除系统配置并触发
连接测试。不要将此端口暴露给外部,也不要在
共享主机上运行。
**3. 调试器可以读取所有内存变量。** `DebuggerGetVariables` 返回
断点处的实际值,包括敏感数据 —
密码、密钥、个人信息。这是调试的本质,而非缺陷。
此外,`RunClass` 可以执行任意 ABAP 代码。因此 `allow_debug` 默认关闭,
只应在开发系统上启用。
**4. `RunReport` 使用共享参数文件。** `ZMCP_RUNNER_ARGS` 中的参数
在每次运行前写入 `$TMP`。在单服务器上,运行是顺序
排队的(每个系统一个会话池),但两个服务器或两个用户共享
同一个系统时,仍可能互相覆盖参数。检测到令牌不匹配时会报错,
而不是返回错误的数据。
**架构**
`transport/`(HTTP、认证、CSRF)→ `adt/`(对象类型、数据返回)→
`tools/`(格式化和 MCP 注册)。`adt/uri.py` 是 URI 构建的唯一来源。
`SessionPool` 为每个系统维护一个 `AdtSession`(按
`system` + `client` + `user` 键控),因为 SAP 的锁句柄
仅在单个连接上有效。调试器轮询使用相同的会话,
因此调试会话期间,同一系统的其他工具调用会排队等待。
**工具在工作线程中运行,而非事件循环。** FastMCP 直接在
事件循环上调用同步函数,因此如果保持原样,一次 SAP 调用就会阻塞整个服务器:
在 `RunReport` 等待期间,agent 无法调用 `DebuggerPoll`,不同
系统会互相阻塞,Web 管理界面也会卡死。`tools/_registry.py` 在注册前用
`anyio.to_thread.run_sync` 包装所有工具。按系统串行化的逻辑
仍然存在且是有意为之 — 它位于 `SessionPool` 中,因为 SAP 的锁句柄
仅对每个系统的一个连接有效。This server cannot be installed
Maintenance
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
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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