mcp-bw-modelling-api
# MCP Server - SAP BW Modeling API
An MCP (Model Context Protocol) server that exposes SAP BW4/HANA modeling objects as tools via [FastMCP](https://gofastmcp.com). Allows AI assistants to explore and query your BW system's metadata: InfoAreas, InfoObjects, ADSOs, CompositeProviders, Queries, and more.
## Compatibility
This server has only been tested against **SAP BW/4HANA**, and it relies on the
BW Modeling API (the `/sap/bw/modeling/` ADT-based endpoints).
It does **not** work on classic **BW 7.5 on AnyDB** (non-HANA). Testing on a
BW 7.5 AnyDB system showed the `/sap/bw/modeling/` endpoints are not available
there, so the tools fail to retrieve anything. The BW Modeling API is a
BW/4HANA (and BW-on-HANA modeling) capability and is not exposed on classic
AnyDB installations. Use this server only against BW/4HANA.
## Prerequisites
- Python 3.10+
- A SAP **BW/4HANA** system with the BW Modeling API enabled (`/sap/bw/modeling/`).
Classic BW 7.5 on AnyDB is not supported (see [Compatibility](#compatibility)).
- A SAP user with appropriate authorizations for the Modeling API
## Installation
Using a **virtual environment** is strongly recommended. It isolates this
server's dependencies (notably `fastmcp` and its pinned `pydantic`) from your
system-wide Python, so a later global package upgrade can't silently break the
server. Mismatched `fastmcp`/`pydantic` versions are a common cause of the
server failing to start.
Create and activate a venv, then install the dependencies into it:
```bash
# Create the virtual environment (once)
python -m venv .venv
# Activate it
# Windows (PowerShell):
.\.venv\Scripts\Activate.ps1
# macOS/Linux:
source .venv/bin/activate
# Install dependencies into the venv
pip install -r requirements.txt
```
When configuring the MCP client, point `command` at the venv's Python
interpreter so the server always runs with the isolated dependencies — for
example `.venv/Scripts/python.exe` on Windows or `.venv/bin/python` on
macOS/Linux (see [MCP Client Configuration](#mcp-client-configuration)).
Without a venv, install globally instead:
```bash
pip install -r requirements.txt
```
## Configuration
The server is configured via environment variables:
| Variable | Required | Description | Default |
|----------|----------|-------------|---------|
| `BW_BASE_URL` | Yes | Base URL of the BW system (e.g. `https://bw4hana.example.com`) | — |
| `BW_USERNAME` | Yes | SAP username | — |
| `BW_PASSWORD` | Yes | SAP password | — |
| `BW_CLIENT` | No | SAP client number | `100` |
| `BW_VERIFY_SSL` | No | Verify SSL certificates (`true`/`false`) | `false` |
## Running the Server
### Standalone (stdio transport)
```bash
python server.py
```
### With FastMCP CLI
```bash
fastmcp run server.py:mcp
```
### HTTP transport
```bash
fastmcp run server.py:mcp --transport http --port 8000
```
## MCP Client Configuration
Add this to your MCP client config (e.g. `.kiro/settings/mcp.json`). If you set
up a virtual environment (recommended), set `command` to the venv's Python
interpreter rather than a bare `python`, so the server runs with the isolated
dependencies:
```json
{
"mcpServers": {
"bw-modeling": {
"command": "path/to/.venv/Scripts/python.exe",
"args": ["path/to/server.py"],
"env": {
"BW_BASE_URL": "https://your-bw-system.example.com",
"BW_USERNAME": "your_user",
"BW_PASSWORD": "your_password",
"BW_CLIENT": "100"
}
}
}
}
```
## Available Tools
| Tool | Description |
|------|-------------|
| `check_connection` | Test connectivity to the BW system |
| `search_bw_objects` | Search for any BW object by name/type |
| `list_infoareas` | List all InfoAreas (organizational folders) |
| `list_infoobjects` | List InfoObjects (characteristics, key figures) |
| `list_adsos` | List Advanced DataStore Objects |
| `list_composite_providers` | List CompositeProviders (HCPR) |
| `list_queries` | List BEx/BW Queries |
| `get_object_details` | Get full metadata for any BW object |
| `get_infoobject_details` | Get InfoObject properties, incl. navigational vs display attributes and compounding |
| `get_characteristic_values` | Read the actual master-data values of a characteristic (e.g. list 0CUSTOMER/0MATERIAL values), optionally restricted to an InfoProvider |
| `get_adso_fields` | Get field list of an ADSO |
| `get_composite_provider_parts` | Get the source (part) providers and join conditions of a CompositeProvider; optionally the node tree (joins, projection filters, calculated fields), per-provider field assignments (source field -> CompositeProvider field) and output-field lineage |
| `get_infoarea_contents` | List objects in an InfoArea (flat search) |
| `get_infoarea_tree` | List objects under an InfoArea via the InfoProvider structure (recursive, reliable) |
| `get_transformation_details` | Get transformation metadata (source, target, rules) |
| `get_dtp_details` | Get a Data Transfer Process's source/target, settings, and (uniquely) its filter restrictions |
| `get_query_structure` | List a query's characteristics, key figures, and measures (restricted + calculated) |
| `get_query_filters` | Read a query's filters (fixed/default) and restricted key figures |
| `read_query_data` | Execute a query and return its result data (default view only) - see [Reading Query Result Data](#reading-query-result-data) |
| `read_query_data_drilldown` | Execute a query with an ad-hoc drilldown, an ad-hoc filter, and/or a mandatory-variable screen submitted automatically - see [Reading Query Result Data](#reading-query-result-data) |
| `get_data_flow` | Show lineage: inbound/outbound transformations and DTPs (with source/target, status, and process chains) |
| `search_abap_objects` | Search the ABAP repository (via ADT) for programs, classes, interfaces, function modules, CDS views, tables, packages by name (read-only) |
| `get_abap_source` | Read the ABAP source of a program, include, class (optionally one method, or its local includes), interface, function module, CDS view or table (read-only; e.g. a transformation's generated AMDP class) |
## Reading Query Result Data
Two tools execute a query and return its actual figures, not just its
design. They trade off reliability against capability, so try
`read_query_data` first and only reach for `read_query_data_drilldown` when
you hit one of its limitations:
- **`read_query_data`** runs the query via the BW reporting (BICS) runtime -
a single, stable API call. It returns exactly the query's saved default
view: default variable values, default drilldown. If the query has a
*mandatory* variable, this call returns no data (just the variable list) -
it cannot submit one.
- **`read_query_data_drilldown`** exists to cover that gap and to add an
ad-hoc characteristic to the drilldown that the query's default view
doesn't show, restrict the result to specific characteristic values
before execution (e.g. one customer, or a short list of fiscal periods)
via its `filters` parameter, and/or override one of the query's own
variables via `variable_values` (e.g. submit a specific date instead of
a "current date" SAP-exit default). It does so via **InA (Information
Access)**, the internal HTTP API behind BW/4HANA's own "Data Preview"
Fiori app (`/sap/bw/ina/GetResponse`) - reverse-engineered from that
app's client-side source, since SAP does not publicly document it. It
performs a 3-call handshake (fetch metadata, submit variables at their
default value or the given `variable_values` override, request the
result grid) and echoes back the query's design-time filters, plus any
ad-hoc `filters`, so the server doesn't aggregate more than the caller
actually needs. Both `filters` and `variable_values` are equality/
IN-list only (no ranges or exclusions); `filters` can only target a
characteristic already part of the query's design, same as the
drilldown. Note that a characteristic can be restricted by both a query
variable and an ad-hoc filter at once (they combine with AND) - if a
variable's default is narrower than the filter you want, use
`variable_values` to change the variable itself instead of `filters`
(see `get_query_filters` for which characteristics are variable-driven).
Because it rides on an undocumented, unversioned protocol rather than the
BW Modeling API, `read_query_data_drilldown` is inherently less
future-proof: SAP could change `/sap/bw/ina/*` without notice. Use it when
you need what it uniquely offers, but don't treat it as a drop-in
replacement for `read_query_data`.
## Supported Object Types
| Code | Object Type |
|------|-------------|
| `AREA` | InfoArea |
| `IOBJ` | InfoObject |
| `ADSO` | DataStore Object (advanced) |
| `HCPR` | CompositeProvider |
| `QUERY` | Query |
| `TRFN` | Transformation |
| `DTP` | Data Transfer Process |
| `MPRO` | MultiProvider |
| `ODSO` | DataStore Object (classic) |
TDQS
Scored across 15 tools
Tools are mostly distinct by object type (list_* for different resources), but some overlap exists: get_object_details is generic and could conflict with get_infoobject_details, and get_infoarea_contents overlaps with list_* for hierarchical access. Descriptions clarify usage, but a few boundaries are fuzzy.
All tools follow a consistent verb_noun pattern using snake_case (search_, list_, get_, check_). The pattern is uniform across the entire set, with predictable verb choices and plural nouns for list operations.
15 tools is well-scoped for a BW modeling API. Each tool serves a distinct functional need (listing, details, specific operations), and the count feels neither sparse nor overwhelming for the domain.
The API covers read-only exploration of major BW objects (InfoAreas, InfoObjects, ADSOs, CompositeProviders, Queries), but lacks listing for transformations (only get_transformation_details) and no list for Open ODS Views. There are no write operations, which may be intentional, but the missing listing for some object types creates notable gaps.