Skip to main content
Glama
coding-with-abbi

sap-sales-order-mcp

README.md
# sap-sales-order-mcp

> **Production-ready MCP server for SAP S/4HANA Sales Order Management.**
> Sandbox-first, offline-testable, built on FastMCP.

[![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://python.org)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Tests](https://img.shields.io/badge/tests-53%20passed-brightgreen.svg)](tests/)
[![MCP Compatible](https://img.shields.io/badge/MCP-compatible-purple.svg)](https://modelcontextprotocol.io)
[![SAP API Business Hub](https://img.shields.io/badge/SAP-API%20Business%20Hub-0FAAFF.svg)](https://api.sap.com/)

A reference implementation showing how to build a **maintainable, testable
MCP server** that connects Claude (or any MCP client) to an enterprise system.
Uses the public SAP API Business Hub sandbox — no on-prem SAP install needed.

**Why this repo exists:** most MCP + SAP examples show a toy server with one
tool and no error handling. This one applies the patterns from Anthropic's
*Claude Certified Architect (Foundations)* curriculum — boundary
descriptions, structured errors, offline mocks, and a tool-selection
reliability harness — to a real (public) SAP API.

---

## 5-Minute Quickstart

```bash
# 1. Clone + install
git clone https://github.com/coding-with-abbi/sap-sales-order-mcp.git
cd sap-sales-order-mcp
pip install -e .

# 2. Smoke-test all 4 tools offline (no API key needed)
python mcp_server.py --selftest

# 3. Add your SAP API key (get it free at api.sap.com)
cp .env.example .env
# Edit .env: SAP_API_KEY=<your key>

# 4. Verify live connection
LIVE_TESTS=1 python -m pytest tests/test_integration_live.py
```

**Add to Claude Desktop** (macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "sap-sales-orders": {
      "command": "python",
      "args": ["/absolute/path/to/sap-sales-order-mcp/mcp_server.py"],
      "env": {
        "SAP_API_KEY": "your_key_here"
      }
    }
  }
}
```

Restart Claude Desktop, then ask: *"Show me all open sales orders for customer 17100001."*

---

## Tools

Four tools, each with **boundary descriptions** (USE WHEN / DO NOT use) that
guide Claude to pick the right one on ambiguous requests. See
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the design rationale.

| Tool | What it does | Typical prompt |
|---|---|---|
| **`list_sales_orders`** | Paginated list with optional filters (customer, type, status, created-since) | "Show me all open orders" |
| **`get_sales_order`** | Single order header by ID (customer, amounts, status, dates) | "Details for order 1000001" |
| **`get_sales_order_items`** | Line items of an order (material, quantity, price) | "What products are on order 1000001?" |
| **`search_orders_by_customer`** | Convenience wrapper: all orders for a specific customer | "Show orders for customer 17100001" |

Full contracts (docstrings): [src/sap_sales_mcp/tools.py](src/sap_sales_mcp/tools.py).
More prompts + responses: [docs/EXAMPLES.md](docs/EXAMPLES.md).

---

## Architecture Highlights

- **Offline-first.** Unit tests + `--selftest` run against a `MockSAPClient`
  with realistic OData v2 fixtures. No API key, no network. Live tests are
  opt-in via `LIVE_TESTS=1`.
- **Structured errors.** Every failure returns a `ToolError` with
  `errorCategory` (`transient`|`validation`|`business`|`permission`) +
  `isRetryable` — never a bare `"failed"` string. Claude can act on them.
- **Boundary descriptions.** Each tool's docstring explicitly states
  `USE WHEN` and `DO NOT use for`, with cross-references. A
  [tool-selection-reliability harness](tool_selection_harness.py) empirically
  verifies that these descriptions guide the model correctly on ambiguous
  requests.
- **Retry policy.** Bounded exponential backoff (1s/2s/4s) on transient HTTP
  errors only. Never on validation, business, or permission errors.
- **Lazy imports.** The offline codepath is stdlib-only — `httpx`, `mcp`,
  `python-dotenv` are imported lazily in live functions. Unit tests run
  without them.
- **Path-scoped rules.** `.claude/rules/python.md` and
  `.claude/rules/mcp-tool-design.md` load only when editing matching files
  — root `CLAUDE.md` stays lean.

---

## Testing

```bash
# Unit tests (offline, always safe)
python -m pytest

# Tool-selection harness (deterministic proxy for LLM tool-picking)
python tool_selection_harness.py

# Integration tests against real SAP sandbox
LIVE_TESTS=1 python -m pytest tests/test_integration_live.py
```

Current status: **53 passed + 5 skipped** (5 skipped = live tests, opt-in).

---

## Documentation

- [`docs/SETUP.md`](docs/SETUP.md) — Full setup guide (SAP API Hub, Claude Desktop, troubleshooting)
- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — Design decisions + CCA-F pattern rationale
- [`docs/EXAMPLES.md`](docs/EXAMPLES.md) — 10 prompt/response examples
- [`docs/NEXT-STEPS.md`](docs/NEXT-STEPS.md) — v2 ideas (create-order with approval gate, OAuth, more domains)
- [`CONTRIBUTING.md`](CONTRIBUTING.md) — How to contribute

---

## Positioning

Built by [Jacob Abb](https://linkedin.com/in/jacob-abb) — AI Consultant &
Engineer specialising in Enterprise-AI (RAG, Voicebots, SAP+GenAI). This
project is part of a public reference portfolio; adapt it for your own SAP
system or use it as a template for other SAP domains (Business Partner,
Purchase Order, Materials).

Related: the patterns here (boundary descriptions, structured errors,
tool-selection harness) come directly from Anthropic's
[Claude Certified Architect – Foundations](https://www.anthropic.com/certification)
curriculum.

---

## Credits

- **SAP** — [API Business Hub](https://api.sap.com/) for the sandbox
- **Anthropic** — [MCP protocol](https://modelcontextprotocol.io) + Claude
  Certified Architect curriculum
- **FastMCP** — the Python MCP framework this server is built on

---

## License

[MIT](LICENSE) — use freely, adapt for your production SAP systems, fork it
for other domains. PRs welcome (see [CONTRIBUTING.md](CONTRIBUTING.md)).