sap-support-mcp
An MCP server over Streamable HTTP that exposes two SAP help-desk operations to an AI agent: sap_reset_password and sap_unlock_users.
README
sap-support-mcp
An MCP server over Streamable HTTP that exposes two SAP help-desk operations to an AI agent:
| Tool | What it does |
|---|---|
sap_reset_password |
Sets a user's password to a generated temporary value via BAPI_USER_CHANGE. The password is stored as initial, so SAP forces the user to choose a new one at next logon. |
sap_unlock_users |
Clears the administrator lock and resets the failed-logon counter for 1–25 users via BAPI_USER_UNLOCK. |
The two are deliberately separate, because SAP treats them separately: unlocking does not
change a password, and resetting a password does not clear a lock. A user who is locked
and has forgotten their password needs both. sap_reset_password detects this case and
says so in its response.
How it talks to SAP
Calls go over plain HTTP to the ABAP system's SOAP RFC service
(/sap/bc/soap/rfc) with basic authentication — no SAP NetWeaver RFC SDK, no native
binaries, so the server runs anywhere Node does.
MCP client ──Streamable HTTP──▶ sap-support-mcp ──SOAP/HTTPS──▶ /sap/bc/soap/rfc ──▶ BAPI_USER_*
Three function modules are used: BAPI_USER_GET_DETAIL (existence + lock state),
BAPI_USER_CHANGE (password), BAPI_USER_UNLOCK (locks).
Each SOAP RFC call is its own stateless session, so a follow-up
BAPI_TRANSACTION_COMMIT would land in a different LUW and do nothing. That is fine
here: the BAPI_USER_* modules commit internally. Do not extend this server with BAPIs
that require an explicit commit without first moving to a stateful transport.
Setup
npm install
cp .env.example .env
Generate the bearer token clients will use:
node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"
Fill in .env, then:
npm run dev
For production:
npm run build && npm start
SAP-side prerequisites
- The SOAP RFC service must be active in
SICFat/sap/bc/soap/rfc. - Create a dedicated technical user (type Communications) for
SAP_USER. It needs:S_RFC— activity 16, function groupsSUSRandSU_USER(or the specific modulesBAPI_USER_GET_DETAIL,BAPI_USER_CHANGE,BAPI_USER_UNLOCK).S_USER_GRP—ACTVT02 (change) and 05 (lock/unlock), withCLASSrestricted to the user groups the help desk is allowed to serve. This is the strongest control available — the allow/deny lists in this server are defence in depth on top of it, not a replacement for it.
- Do not give the technical user
S_USER_GRPover theSUPERgroup.
Configuration
Every setting is an environment variable; see .env.example for the full list with comments. The ones that matter most:
| Variable | Purpose |
|---|---|
MCP_AUTH_TOKEN |
Bearer token required on every MCP request. No unauthenticated mode exists. Minimum 16 characters. |
SAP_BASE_URL, SAP_CLIENT, SAP_USER, SAP_PASSWORD |
The target system and the technical user. |
USER_ALLOW_LIST |
If set, only matching users can be targeted. Supports *, e.g. SUPPORT_*,BUSINESS_*. |
USER_DENY_LIST |
Merged on top of the built-in deny list. Deny always beats allow. |
AUDIT_LOG_FILE |
JSONL audit trail. Defaults to audit/sap-support-mcp.audit.jsonl. |
SAP_REJECT_UNAUTHORIZED |
Leave true. Set false only for a sandbox with a self-signed certificate. |
Guardrails
Bearer auth. Every request to MCP_PATH needs Authorization: Bearer <token>,
compared with a timing-safe equality check. /healthz is the only unauthenticated route
and reveals nothing about SAP.
Allow / deny lists. SAP*, DDIC, SAPCPIC, EARLYWATCH, TMSADM, SAPSUPPORT,
ADS_AGENT and ADSUSER are denied unconditionally — adding * to the allow list
cannot expose them. Patterns are anchored, so SUPPORT_* does not match XSUPPORT_1.
A denied user is rejected before any call reaches SAP.
Dry run. Both tools take dryRun: true, which checks the policy and confirms the
user exists and reports its current lock state, without changing anything.
Audit trail. Append-only JSONL. Each operation writes an attempt record before
touching SAP and a terminal record (success / failed / denied / dry_run)
afterwards, sharing one correlationId, so a crash mid-call still leaves evidence:
{"ts":"2026-07-31T08:18:49.261Z","correlationId":"ed66d93a…","operation":"unlock_user","outcome":"attempt","targetUser":"JDOE","sapClient":"100","reason":"INC-SMOKE-1","sessionId":"9b85a10a…","clientIp":"127.0.0.1"}
Every tool call requires a reason (ticket number or justification) which is recorded.
Generated passwords are never written to the audit trail — AuditLog has no field that
could carry one, and a test asserts the password does not appear in the file.
Connecting a client
{
"mcpServers": {
"sap-support": {
"type": "http",
"url": "http://127.0.0.1:3000/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN_HERE" }
}
}
}
Sessions are stateful: the server issues an Mcp-Session-Id on initialize, and each
session gets its own McpServer instance so caller identity stays isolated in the audit
trail.
Security notes worth reading before you deploy this
- The temporary password passes through the model's context.
sap_reset_passwordreturns it in the tool result, so it is visible to the LLM and to whatever transcript store sits behind it. That is inherent to handing a password back through MCP. If your threat model cannot accept it, changeresetPassword.tsto deliver the password out of band (email the user, push to a vault) and return only a confirmation. HOSTdefaults to127.0.0.1. Binding to0.0.0.0puts SAP password resets on your network; put it behind TLS and a reverse proxy if you do.- Everything the caller supplies is XML-escaped before it enters the SOAP envelope, and usernames are additionally validated against SAP's character rules, so a crafted username cannot inject extra RFC parameters.
- The deny list protects against a confused agent, not a hostile one holding the
bearer token.
S_USER_GRPon the SAP side is the real boundary.
Tests
npm test
43 tests, no SAP system required. test/mockSap.ts is a stand-in for /sap/bc/soap/rfc
that reproduces SAP's real response shapes — including message class 01/124 for an
unknown user, HTTP 401 for bad credentials, SOAP faults, and the fact that
BAPI_USER_UNLOCK clears an administrator lock but not a CUA global lock. The
end-to-end tests drive the real Express app through a real MCP client over Streamable
HTTP.
Layout
src/
index.ts entry point: config, wiring, graceful shutdown
config.ts env schema + built-in deny list
http/
server.ts Express app, Streamable HTTP transport, session registry
auth.ts bearer token middleware
mcp/
server.ts McpServer construction + instructions
tools/
resetPassword.ts sap_reset_password
unlockUsers.ts sap_unlock_users
sap/
soap.ts SOAP envelope building, XML escaping, fault handling
userService.ts the three BAPIs + RETURN-table interpretation
security/
policy.ts allow/deny evaluation
audit.ts append-only JSONL audit trail
util/
password.ts temporary password generation
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
E2B
Using MCP to run code via e2b.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.