sap-support-mcp

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.

Category
Visit Server

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

  1. The SOAP RFC service must be active in SICF at /sap/bc/soap/rfc.
  2. Create a dedicated technical user (type Communications) for SAP_USER. It needs:
    • S_RFC — activity 16, function groups SUSR and SU_USER (or the specific modules BAPI_USER_GET_DETAIL, BAPI_USER_CHANGE, BAPI_USER_UNLOCK).
    • S_USER_GRP — ACTVT 02 (change) and 05 (lock/unlock), with CLASS restricted 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.
  3. Do not give the technical user S_USER_GRP over the SUPER group.

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_password returns 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, change resetPassword.ts to deliver the password out of band (email the user, push to a vault) and return only a confirmation.
  • HOST defaults to 127.0.0.1. Binding to 0.0.0.0 puts 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_GRP on 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

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.

Official
Featured
TypeScript
Magic Component Platform (MCP)

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.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

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.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

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.

Official
Featured
TypeScript
Kagi MCP Server

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.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Exa Search

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.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured