mcp-bw-adt-api
Exposes SAP BW/4HANA ADT operations as MCP tools for LLM clients, with a local-file buffering layer to handle large XML payloads and table data efficiently.
README
mcp-bw-adt-api
An MCP (Model Context Protocol) server that exposes the
bw-adt-api library — SAP BW/4HANA ADT
(ABAP Developer Tools) operations — to LLM clients such as ZCode, Claude Desktop, or any
MCP-compatible client.
It wraps the ~100 public methods of BWAdtClient (ADSO, Transformation, DTP, DataSource,
Process Chain, InfoObject, DDIC tables, search, dataflow lineage, transports, …) as MCP tools,
with a local-file buffering layer that keeps large XML payloads and table data out of the
LLM context window.
Why a buffering layer?
bw-adt-api payloads are large — measured on real systems:
| Payload | Typical size |
|---|---|
| Object XML (PUT request body) | 15–80 KB |
| DDIC table data, 100 rows × 20 cols | ~68 KB |
| DDIC table data, 10 000 rows | ~6.7 MB |
| Process chain logs, 200 entries | ~39 KB |
Pushing these through the LLM context window is wasteful or fatal. This server solves it two ways:
Mechanism A — large request bodies via local files (POST/PUT)
Every tool that takes a large string body (object XML, SQL statement, ABAP source) accepts two fields:
<label>Content— inline string<label>Path— path to a file under the workdir (takes precedence)
So instead of the LLM having to generate or hold a 50 KB XML, it reads the current XML to a file, edits it (or uses an atomic-edit tool), then references the file by path.
Mechanism B — large responses via outputPath
Most read tools accept an optional outputPath. When set, the full result is written to that
file and the tool returns only a small summary envelope:
{ "ok": true, "outputPath": "/abs/path/big.json", "bytes": 723908, "summary": "object with key(s): tableName, rows, …" }
- Objects / arrays are written as JSON.
- Raw XML strings (from
bw_*_get_xmlwithoutputPath) are written as plain text, so the same path can be reused asxmlPathin a later save call.
Without outputPath, the result is returned inline (with table data paginated to a soft cap and
truncated/hint flags set when needed).
Workdir sandbox
All file paths resolve under the workdir and are confined to its subtree (.. escapes and
out-of-tree absolute paths are rejected). By default the workdir is <cwd>/.mcp-bw-out (a scratch
folder under the server process working directory) so buffered files do not land on project source.
Override with BW_MCP_WORKDIR if you need a different root (e.g. the workspace root).
Quick start
# 1. Install + build
npm install
npm run build
# 2. Configure connection (copy & edit)
cp .env.example .env
# multi-env: BW_PROFILES + BW_<NAME>_* (or legacy BW_BASE_URL / …)
# 3. Inspect the tool catalog (no BW connection needed)
npm run list-tools
Environment variables — multi-profile (recommended)
| Variable | Required | Description |
|---|---|---|
BW_PROFILES |
yes* | Comma-separated profile names, e.g. test,prod |
BW_DEFAULT |
no | Startup profile (default = first in BW_PROFILES) |
BW_<NAME>_BASE_URL |
yes* | BW server URL for that profile |
BW_<NAME>_USERNAME |
yes* | SAP logon user |
BW_<NAME>_PASSWORD |
yes* | Password (never exposed to the LLM) |
BW_<NAME>_CLIENT |
no | SAP logon client, e.g. 100 |
BW_<NAME>_LANGUAGE |
no | Language key, e.g. ZH |
BW_<NAME>_READONLY |
no | true → reject mutating tools on this profile |
BW_<NAME>_ALLOW_UNAUTHORIZED |
no | true to accept self-signed certs |
BW_MCP_WORKDIR |
no | Root for file buffering (default = <cwd>/.mcp-bw-out) |
* Or use the legacy single-env vars (BW_BASE_URL, BW_USERNAME, BW_PASSWORD,
optional BW_CLIENT / BW_LANGUAGE / BW_READONLY / BW_ALLOW_UNAUTHORIZED) when
BW_PROFILES is unset — they become a profile named default.
Switch at runtime with bw_env_list / bw_env_switch. The active profile’s client
auto-logs-in on its first request; bw_disconnect drops only the current profile’s session.
Read-only profiles: mutating tools are omitted from tools/list, and the server emits
notifications/tools/list_changed when readOnly visibility changes. Host support for
mid-session refresh is incomplete (Cursor / Claude Code may keep a stale list until MCP
reconnect or a new chat) — the server still rejects mutating tools/call as a hard
guard.
Registering in an MCP client
Add the server to your client's MCP config. Examples:
ZCode (.zcode/mcp.json in the workspace, or user-level)
{
"mcpServers": {
"bw-adt": {
"command": "node",
"args": ["E:/04-code/02-personnal/mcp-bw-adt-api/build/index.js"],
"env": {
"BW_PROFILES": "test,prod",
"BW_DEFAULT": "test",
"BW_TEST_BASE_URL": "http://your-bw-test:8000",
"BW_TEST_USERNAME": "developer",
"BW_TEST_PASSWORD": "secret",
"BW_TEST_CLIENT": "100",
"BW_TEST_LANGUAGE": "ZH",
"BW_TEST_READONLY": "false",
"BW_PROD_BASE_URL": "http://your-bw-prod:8000",
"BW_PROD_USERNAME": "developer",
"BW_PROD_PASSWORD": "secret",
"BW_PROD_CLIENT": "100",
"BW_PROD_LANGUAGE": "ZH",
"BW_PROD_READONLY": "true"
// "BW_MCP_WORKDIR": "C:/path/to/workspace"
}
}
}
}
The server inherits the client process's
cwd, soBW_MCP_WORKDIRusually does not need to be set — files are buffered into the workspace that owns the MCP server.
Claude Desktop (claude_desktop_config.json)
Same shape under "mcpServers".
Tool catalog
Tools are named bw_<domain>_<action>. Run npm run list-tools for the full list with input
schemas. Domains:
| Domain | Prefix | Example tools |
|---|---|---|
| System / env | bw_system_*, bw_env_*, bw_disconnect |
bw_env_list, bw_env_switch, bw_system_status |
| Search | bw_search_*, bw_quick_search |
bw_search_objects, bw_quick_search |
| Dataflow / lineage | bw_dataflow_* |
bw_dataflow_get, bw_dataflow_lineage |
| Generic CRUD | bw_object_* |
bw_object_create/update/delete/activate |
| ADSO | bw_adso_* |
bw_adso_get_xml, bw_adso_save_and_activate, bw_adso_add_field |
| Transformation | bw_trfn_* |
bw_trfn_save_and_activate, bw_trfn_add_rules_and_save, bw_trfn_auto_map_and_save |
| DTP | bw_dtp_* |
bw_dtp_execute, bw_dtp_save_and_activate |
| DataSource | bw_datasource_* |
bw_datasource_save_and_activate, bw_datasource_merge_proposal |
| Replication | bw_replication_* |
bw_replication_replicate_full |
| Process Chain | bw_processchain_* |
bw_processchain_execute, bw_processchain_logs |
| InfoObject | bw_infoobject_* |
bw_infoobject_get |
| DDIC tables / data | bw_table_* |
bw_table_get_data, bw_table_query_sql |
| BICS reporting / preview | bw_reporting_* |
bw_reporting_preview, bw_reporting_initial_view |
| Transport / CTS | bw_transport_* |
bw_transport_check, bw_transport_create |
Note: Transformation creation is unsupported server-side (SAP JCo limitation) and
bw_object_createwithobjectType: "trfn"returns an error. All other TRFN operations work.
Typical workflows
Read-modify-write an ADSO (no large XML held by the LLM)
1. bw_adso_get_xml { id: "ZL_FID40", format: "summary", outputPath: "adso.xml" }
→ LLM sees a small envelope; the full XML is on disk under the workdir.
2. bw_adso_add_field { id: "ZL_FID40", name: "ZZFLAG", dataType: "CHAR", length: 1 }
→ atomic edit: reads current XML, adds the field, saves+activates.
(Or the LLM edits adso.xml directly, then:)
3. bw_adso_save_and_activate { id: "ZL_FID40", xmlPath: "adso.xml" }
→ writes the file's XML back, one-stop lock→PUT→activate→unlock.
Query a large table without flooding context
bw_table_get_data { table: "/BIC/AZL_FID402", maxRows: 1000, outputPath: "data.json" }
→ { ok: true, outputPath: "…/data.json", bytes: 680000, summary: "…: 1000 row(s)…" }
The LLM can then run a follow-up script/tool to inspect data.json instead of ingesting it.
Inspect process chain logs safely
bw_processchain_logs { id: "ZPC_FID", limit: 50, offset: 0 }
→ inline, capped. Use outputPath for the full log set.
Architecture
src/
├── index.ts stdio entry; --list-tools catalog dump
├── server.ts MCP Server + tools/list + tools/call (outputPath interception)
├── session.ts singleton BWAdtClient from env (auto-login)
├── errors.ts AdtException → MCP error result mapping
├── fileio.ts workdir sandbox, readInput (mechanism A), writeOutput (mechanism B)
├── response.ts pagination, projection, summaries
├── tool.ts ToolDef + zod→JSON Schema + largeInput/outputPathField helpers
└── tools/ one file per domain, each exporting ToolDef[]
- Credentials are read once from env at startup and never surfaced to the LLM.
- Write operations (delete, activate, execute) are exposed directly, no extra confirmation layer — rely on your MCP client's tool-approval prompt.
- Pagination: table tools default
maxRowsto 50 and cap inline returns; logs default to 100 withlimit/offset.
Development
npm run build # tsc → build/
npm run watch # tsc -w
npm start # run the server (stdio)
npm run list-tools # dump the tool catalog as JSON
The server depends on bw-adt-api via a local file: link during development. Once published,
switch the dependency to "bw-adt-api": "^0.1.0".
License
MIT
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。
mcp-server-qdrant
这个仓库展示了如何为向量搜索引擎 Qdrant 创建一个 MCP (Managed Control Plane) 服务器的示例。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。