{
  "markdown": "# sap-abap-mcp\n\n[![npm version](https://img.shields.io/npm/v/%40coaspe%2Fsap-abap-mcp)](https://www.npmjs.com/package/@coaspe/sap-abap-mcp)\n[![npm downloads](https://img.shields.io/npm/dw/%40coaspe%2Fsap-abap-mcp)](https://www.npmjs.com/package/@coaspe/sap-abap-mcp)\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-io.github.Coaspe-5A45FF)](https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.Coaspe/sap-abap-mcp)\n[![license](https://img.shields.io/badge/license-MIT-0A6ED1)](LICENSE)\n\n**The headless, client-neutral, governance-first MCP server for SAP ABAP\ndevelopment across multiple systems.**\n\nSAP ABAP MCP lets Codex, Claude, and other local MCP hosts work with SAP ABAP\nthrough ABAP Development Tools (ADT) HTTP services. It can inspect and edit\nsource, run quality checks, manage transports, use abapGit and the RAP\ngenerator, inspect runtime data, compare systems, and perform guarded\nrefactorings without an IDE runtime, SAP GUI, or an ABAP FS virtual workspace.\n\n## Why this server\n\nSAP now provides an [official ADT MCP\nServer](https://help.sap.com/docs/abap-cloud/abap-development-tools-user-guide/configuring-adt-mcp-server-ed94320814734d97801f51a5b6deb802)\ninside its ADT clients. This project serves a different operating model:\nheadless automation from any supported local MCP host.\n\n| | SAP ABAP MCP | SAP ADT MCP Server |\n|---|---|---|\n| Runtime | Independent Node.js process: local `stdio`, or self-hosted Streamable HTTP for a shared instance | Local HTTP server hosted by an ADT client |\n| Agent hosts | Codex, Claude, and other MCP clients, locally or over HTTP | MCP hosts configured against the running ADT server |\n| SAP sessions | Multiple named profiles in one process | SAP projects and sessions managed by ADT |\n| Guardrails | Production profiles are read-only; writes support package restrictions and explicit confirmations; HTTP mode adds API key roles, rate limits, and a structured audit log | Governed by the installed ADT version, SAP authorizations, and client configuration |\n| Assurance | Read-only transport assessment with JSON, SARIF, and JUnit evidence | SAP-provided in-IDE development workflows |\n| Verification | Separates implemented, discovered, authorized, and live-verified capabilities | SAP product support and release documentation |\n\nThis is a deployment-model comparison, not a capability benchmark or a claim\nof SAP endorsement. Official behavior varies by ADT and SAP backend release.\n\n## 90-second workflow\n\n![Synthetic terminal walkthrough of setup, repository inspection, ABAP Unit and ATC, and transport assessment](assets/demo.gif)\n\nThe animation contains synthetic object and transport names and no live SAP\ndata. See the [accessible transcript and exact workflow](docs/demo-script.md).\n\n## Quick start\n\nDetailed references: [profiles and authentication](docs/setup-and-profiles.md),\n[HTTP deployment](docs/http-deployment.md), and [CLI commands](docs/cli-reference.md).\n\nYou need Node.js 20 or later, network or VPN access to SAP, and an SAP HTTPS URL, three-digit client number, username, and ADT Basic Auth permission.\n\n### Recommended: guided onboarding\n\nRun one command and follow the local browser wizard. It checks npm, Claude Code,\nCodex, existing `.claude` and `.codex` settings, and saved SAP profiles. It then\nverifies the SAP login before saving it and registers the MCP server through the\ninstalled client's official CLI. Existing steps are detected and skipped.\n\nWindows:\n\n```powershell\nnpx.cmd -y @coaspe/sap-abap-mcp@latest onboard\n```\n\nmacOS:\n\n```bash\nnpx -y @coaspe/sap-abap-mcp@latest onboard\n```\n\nThe wizard runs only on `127.0.0.1`; SAP credentials do not pass through a\npublisher-operated service. Passwords are protected with Windows DPAPI or macOS\nKeychain. Linux users should use the manual setup because the browser wizard\ndoes not store Linux credentials.\n\n### Manual setup\n\n#### 1. Configure SAP\n\nWindows:\n\n```powershell\nnpx.cmd @coaspe/sap-abap-mcp@latest setup\n```\n\nmacOS or Linux:\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest setup\n```\n\nThe wizard calls the local connection alias `Server name` and the endpoint `SAP URL`. Windows and macOS validate SAP before saving and protect the password with DPAPI or Keychain. Linux saves only non-secret settings and prints the password environment-variable commands to run before starting the MCP client.\n\n#### 2. Register the MCP server\n\nAfter setup, run only the command for your client. On Windows, use `npx.cmd`.\n\nCodex CLI:\n\n```powershell\ncodex mcp add sap-abap -- npx.cmd -y @coaspe/sap-abap-mcp@latest serve\n```\n\nClaude Code:\n\n```powershell\nclaude mcp add --transport stdio --scope user sap-abap -- npx.cmd -y @coaspe/sap-abap-mcp@latest serve\n```\n\nOn macOS or Linux, use `npx`.\n\nCodex CLI:\n\n```bash\ncodex mcp add sap-abap -- npx -y @coaspe/sap-abap-mcp@latest serve\n```\n\nClaude Code:\n\n```bash\nclaude mcp add --transport stdio --scope user sap-abap -- npx -y @coaspe/sap-abap-mcp@latest serve\n```\n\nThis registration exposes all saved SAP profiles; every SAP-facing tool still requires an explicit `connectionId`. Restart the client, then use `codex mcp list`, `claude mcp get sap-abap`, or `/mcp` to confirm that the process starts. The completed wizard already performs live SAP verification; `/mcp` alone does not prove that SAP authentication succeeded.\n\nPrefer a plugin install? Follow [Claude Code and Codex plugin marketplaces](#claude-code-and-codex-plugin-marketplaces); the included setup skill guides the same local wizard without putting the SAP password in chat. See the detailed [Windows](#detailed-setup-on-windows), [macOS](#detailed-setup-on-macos), and [Linux](#linux-and-containers) sections for platform-specific behavior and server management.\n\n## Community and adoption\n\n- Read the public [roadmap](ROADMAP.md).\n- Run or implement the open [SAP ABAP MCP compatibility profile](spec/README.md).\n- Add an opt-in, sanitized entry to [ADOPTERS.md](ADOPTERS.md).\n- Use [GitHub Discussions](https://github.com/Coaspe/sap-abap-mcp/discussions)\n  for implementation questions, compatibility evidence, and RFCs.\n\nNeed a transport-specific release decision and CI evidence from existing ATC\nand ABAP Unit checks? Review the fixed-scope [paid diagnostic and three-day\npilot](SERVICES.md). If your current workflow already preserves the check\nresults, release decision, and evidence together, the service is not a fit.\nNever include SAP credentials, source code, hosts, transport numbers, logs,\ntokens, or other confidential information in a public issue or discussion.\n\n### Current v1 surface\n\nThe v1 catalog contains 120 action-specific tools and seven Resources.\nUnreleased local CLI builds default to the `minimal` preset: five discovery/invocation tools. Other capabilities are loaded on demand.\nUse `--toolsets all` to advertise the complete catalog directly. Use `--api-version v0` only for legacy\nclient compatibility, or select toolsets explicitly when a host should\nadvertise fewer schemas.\nNormal clients should omit both `--api-version` and `--toolsets`.\n\n| Invocation | Advertised surface |\n|---|---|\n| `serve --profile DEV100` | Minimal v1: 5 gateways, all 120 capabilities reachable, seven Resources |\n| `serve --profile DEV100 --toolsets all` | Full direct v1: 120 tools and seven Resources |\n| `serve --profile DEV100 --preset compact` | Token-efficient v1, 12 everyday read/inspect tools |\n| `serve --profile DEV100 --toolsets core,analysis` | Selected v1 toolsets only |\n| `serve --profile DEV100 --api-version v0` | Legacy 53-tool compatibility surface |\n\nSee the\n[v1 migration guide](docs/v1-migration.md) for contracts, Resources, and the\nseparate live-SAP verification boundary.\n\n### Built-in workflow prompts (unreleased)\n\nMCP hosts supporting `prompts/list` and `prompts/get` can select these workflows:\n\n| Prompt | Outcome |\n|---|---|\n| `sap-explain-object` | Explain current source and callers with source-line evidence |\n| `sap-change-object` | Guide a scoped edit through diagnostics, activation, ABAP Unit and ATC |\n| `sap-review-transport` | Assess readiness and incomplete evidence without releasing a transport |\n| `sap-plan-rap` | Discover backend schema, validate inputs and preview RAP generation |\n\nEach prompt accepts `systemId`, `target`, and optional `goal` in your preferred\nlanguage. Prompts appear only when their required tools are enabled; viewer\nsessions never expose the source-change workflow. The legacy v0 API is unchanged.\nFetching a prompt performs no SAP calls. These are agent instructions, not an\nautomatic transaction or an additional authorization grant.\n\nFor local usage and verification, see [workflow prompts](docs/workflow-prompts.md).\nThe [September 2026 competitive assessment](docs/competitive-research-2026-09-07.md)\nseparates implemented improvements from remaining live-SAP and release gaps.\n\n## Live SAP evidence\n\nCapabilities are reported as `unverified` until they succeed against a live\nconnection. [`docs/live-sap-evidence.md`](docs/live-sap-evidence.md) records the\ncurrent sanitized results — no credentials, no customer source, no host names.\n\n| Area | ECC 758 | S/4HANA 758 |\n|---|---|---|\n| `$TMP`-scoped v1 surface | 87 passed, 11 unsupported, 0 failed | 93 passed, 2 unsupported, 0 failed |\n| Self-hosted HTTP mode, roles, and audit | 13 of 13 passed | not run |\n| CI assurance gate and its artifacts | 7 of 7 passed | not run |\n\n200 live checks in total: 180 tool-surface checks across two systems, plus 20\ntransport and CI checks on one. The tool-surface count counts each capability once\nper system, because release coverage is the claim; it is not 180 distinct\ncapabilities.\n\nOn S/4HANA this includes the complete class-runner and debugger chain: a `$TMP`\nclass runner executed, a breakpoint on its own source suspended it, and the\nattached debugger returned a 13-frame stack, variables, an evaluated expression,\nand a completed step. On ECC the ADT class-run endpoint rejects the same class, so\nthe attached debugger is unreachable there; that difference accounts for the nine\nextra `unsupported` results and is documented with its exact SAP message.\n\nReproduce the tool-surface run against your own development system:\n\n```bash\nnpm run evidence:live -- DEV100\n```\n\nThe harness creates exactly one class in the local package `$TMP` under a\nrun-unique name, treats it as owned only after a create receipt and an immediate\nexact read-back agree, refuses in code to mutate anything else, and deletes it\nagain. Existing objects are only ever read. The two `unsupported` results are\nmissing SAP-side prerequisites — the ABAP REPL and the abapGit ADT backend — not\ndefects.\n\n## ABAP FS parity status\n\nThe pinned ABAP FS 2.6.5 source exposes 43 MCP tools. This server provides a strict-compatible subset of 42; the omitted tool is `manage_subagents`, which depends on the VS Code agent host. With 10 headless feature extensions and `read_deferred_result`, this server advertises 53 tools in total.\n\nThe development surface supports create-time source for BDEFs, classes, interfaces, programs/includes, CDS/DCL/metadata extensions, and service definitions, plus structured DDIC reads/writes, one-request batch activation, class and executable-program profiling, the ABAP FS REPL contract, detailed semantic and enhancement inspection, paged repository-child discovery, bounded runtime feeds, and an opt-in classic-object bridge. SAP-dependent capabilities remain `unverified` until they succeed against the selected live connection; call `get_sap_capabilities` for per-connection evidence.\n\nSnippet execution requires `ZCL_ABAP_REPL` and an active SICF service at `/sap/bc/z_abap_repl`. Executable programs use the ADT program-run endpoint through a confirmed one-use plan and request only a bounded server-time profile.\n\n## What it supports\n\nThe server provides all 42 strict-compatible headless tools from the pinned ABAP FS baseline, ten grouped feature extensions, and one infrastructure tool for continuing oversized results.\n\n| Area | Capabilities |\n|---|---|\n| Connections | Multiple SAP profiles, Basic Auth, OAuth client credentials, browser OAuth Authorization Code with PKCE, request-scoped bearer passthrough, lazy login, system metadata, ADT discovery export |\n| Repository reads | Search, metadata, structured DDIC properties, paged package/program/function-group children, source ranges, batch reads, URI reads, source search, enhancement implementations and elements |\n| Semantic services | Completion details, definition lookup, documentation, type hierarchy, components, quick-fix discovery, SAP formatter preview |\n| Source writes | Exact source replacement, typed DDIC updates, create-time source for textual ADT object types, syntax diagnostics, single- and one-request batch activation, text elements |\n| Refactoring | Rename, package move, extract method, quick-fix application, formatting, deletion |\n| Quality | ABAP Unit, ATC, diagnostics, test-include creation |\n| Transports | List, details, objects, read-only release assessment, JSON/SARIF/JUnit evidence, compare, create, release, delete, owner/user management, object resolution |\n| Versions | Active revision history, revision comparison, inactive source, guarded revision restore |\n| abapGit | Repository list, remote information, create, pull, unlink, stage, push, check, branch switch (requires the abapGit ADT backend on the SAP system) |\n| RAP | Availability, paged schema, defaults, validation, preview, generation, service binding details, and OData V2/V4 publication and unpublication |\n| Runtime | Guarded class/program execution with bounded aggregate profiling, fixed-contract ABAP REPL execution, debugger, breakpoints, stack, variables, dumps, traces, Gateway/system feeds, heartbeat checks |\n| Cross-system | Source comparison across configured SAP systems |\n| Dependency analysis | Bounded where-used dependency graph |\n| SAP GUI integration | Validated WebGUI transaction URL generation and optional local launch |\n| Classic objects | Opt-in, same-origin Screen/Dynpro and full GUI Status bridge with confirmed writes |\n| Data | Read-only ADT SQL queries with bounded or file-based output |\n| Artifacts | Mermaid validation/viewer and DOCX test documentation |\n\nThe ten grouped extension tools are:\n\n- `inspect_abap_code`\n- `refactor_abap_code`\n- `manage_abapgit`\n- `manage_rap_generator`\n- `manage_abap_versions`\n- `compare_abap_systems`\n- `get_abap_dependency_graph`\n- `run_sap_transaction`\n- `get_sap_capabilities`\n- `run_abap_application`\n\nGrouping related actions keeps the tool-schema footprint lower than exposing every operation as a separate MCP tool.\n`read_deferred_result` is the additional infrastructure tool; it reads the remaining UTF-8 chunks of a large result without repeating the SAP operation.\n\nSee [advanced ABAP workflows](docs/advanced-workflows.md) for enhancement,\nbehavior implementation, CDS Unit, local test include, and program profiling\nrecipes. See the [classic-object bridge guide](docs/classic-bridge.md) before\nenabling Screen/Dynpro or GUI Status access.\n\n## Transport change assurance\n\n`manage_transport_requests` keeps transport review inside the existing grouped tool. Its read-only `assess_transport` action can run ATC and ABAP Unit for each supported transport object, optionally compare the same objects with a target connection, and emit JSON, SARIF 2.1.0, and JUnit XML reports.\n\nThe returned gate is `passed`, `failed`, or `incomplete`. Truncated object coverage, truncated ATC findings, failed check execution, empty transports, and classes without discoverable tests prevent a pass. A target-system difference is recorded as landscape evidence rather than automatically treated as a failure. Assessment never releases the transport; `release_transport` remains a separate confirmed mutation.\n\nThe plugin includes `sap-abap-change-assurance` for this workflow. In Claude Code run `/sap-abap-mcp:sap-abap-change-assurance`; in Codex ask to use `$sap-abap-change-assurance`.\n\n### Gate a pipeline without an MCP host\n\nChange assurance does not require an AI agent. The `assure` command runs the same\nread-only assessment directly and turns the gate into an exit code:\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest assure DEV100 --transport DEVK900123 \\\n  --checks atc,unit_tests --formats json,sarif,junit \\\n  --report-directory ./reports\n```\n\n| Exit code | Gate | Meaning |\n|---|---|---|\n| 0 | `passed` | Every assessed object passed every requested check |\n| 1 | `failed` | A check produced a definite failure |\n| 2 | `incomplete` | Safety could not be proven — truncated coverage, a check that could not run, an empty transport, or a class with no discoverable tests |\n\n`incomplete` blocks by default. Pass `--fail-on failed` when only definite\nfailures should stop a build. `assure` never releases or modifies the transport.\n\n### GitHub Action\n\n[`action.yml`](action.yml) wraps the same command and uploads SARIF to GitHub code\nscanning, so ABAP findings appear next to the rest of a repository's security\nresults:\n\n```yaml\n- uses: Coaspe/sap-abap-mcp@v1\n  id: assurance\n  with:\n    sap-url: ${{ secrets.SAP_URL }}\n    sap-client: \"100\"\n    sap-username: ${{ secrets.SAP_USERNAME }}\n    sap-password: ${{ secrets.SAP_PASSWORD }}\n    transport: ${{ inputs.transport }}\n    checks: atc,unit_tests\n\n- uses: github/codeql-action/upload-sarif@v3\n  if: always()\n  with:\n    sarif_file: ${{ steps.assurance.outputs.report-sarif }}\n```\n\nThe action outputs `gate`, `report-json`, `report-sarif`, and `report-junit`, and\nwrites a job summary. The SAP password is passed only through a\nprofile-specific environment variable, never as a command argument, so it does\nnot appear in a process list or a command echo. The runner needs network or VPN\naccess to SAP.\n\n## MCP directories and registries\n\nThe canonical registry identity is `io.github.Coaspe/sap-abap-mcp`, defined in [`server.json`](server.json). Directory installs must run this package as a local `stdio` server; SAP profiles and credentials stay on the user's machine and are never hosted by a registry.\n\nBefore the first SAP-facing request, create and verify at least one local SAP profile using the commands in [Quick start](#quick-start) or [`llms-install.md`](llms-install.md). The Claude plugin may start successfully without a profile; after installation, run `/sap-abap-mcp:sap-abap-setup` to complete local SAP setup. A generic registry launch runs `@coaspe/sap-abap-mcp` with the `serve` argument and exposes all locally configured profiles; every SAP-facing tool still requires an explicit `connectionId`.\n\nRegistry publication does not change the live-evidence boundary. SAP-dependent development-parity capabilities remain `unverified` until they succeed against the selected live connection.\n\nThe public [Smithery listing](https://smithery.ai/servers/aspalt85/sap-abap-mcp)\ninstalls the validated local MCPB bundle. Its current catalog contains 120\ntools and seven Resources and is synchronized from the runtime before\npublication.\n\nThe public [LobeHub listing](https://lobehub.com/mcp/coaspe-sap-abap-mcp)\nuses the owner-validated [`lhm.plugin.json`](lhm.plugin.json) manifest. The\ncurrent listing advertises the same default 120 tools and seven Resources.\n\n## Privacy Policy\n\nSAP ABAP MCP runs locally and does not send SAP profiles, credentials, source code, or tool results to a publisher-operated service. It communicates only with destinations selected by the user, including the configured SAP system and the user's MCP host. See the complete [`PRIVACY.md`](PRIVACY.md) and [`TERMS.md`](TERMS.md).\n\n### Claude Code and Codex plugin marketplaces\n\nThis repository is also a dual-compatible plugin marketplace. The plugin starts the same npm `latest` package as a local `stdio` process, so SAP profiles, credentials, and ADT traffic stay on the user's computer. Profiles are user-scoped outside the plugin cache and survive plugin updates.\n\nClaude Code:\n\n```text\n/plugin marketplace add Coaspe/sap-abap-mcp\n/plugin install sap-abap-mcp@coaspe-sap\n/reload-plugins\n```\n\nRun the namespaced setup skill after reloading:\n\n```text\n/sap-abap-mcp:sap-abap-setup\n```\n\nThe skill reuses an existing profile or guides profile creation, local password entry, and live ADT verification. Use `/mcp` to confirm that the `sap-abap` process is connected, but do not treat that status as proof that an SAP profile is authenticated; the setup skill verifies SAP with `doctor`.\n\nCodex:\n\n```bash\ncodex plugin marketplace add Coaspe/sap-abap-mcp\n```\n\nThen install **SAP ABAP MCP** from the `Coaspe SAP Developer Tools` marketplace in the Codex app and start a new task. Ask Codex to set up SAP ABAP MCP; the included `sap-abap-setup` skill keeps passwords out of chat and guides profile creation, authentication, and live ADT verification.\n\nThe plugin also includes `sap-abap-change-assurance`, which assesses an existing transport without releasing it and returns CI-native evidence paths.\n\n## OAuth client credentials\n\nThe interactive `setup` wizard remains the Basic Auth path. OAuth client credentials are an explicit advanced profile type and do not change the defaults for newly created profiles. Create and verify one on Windows or macOS with:\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest profile add BTP100 \\\n  --url https://abap.example.com --client 100 \\\n  --auth-type oauth-client-credentials \\\n  --token-url https://auth.example.com/oauth/token \\\n  --client-id mcp-client --scope \"abap.read abap.write\" --login\n```\n\nThe hidden prompt requests the OAuth client secret. The profile file stores the token URL, client ID, and optional scope, but never the client secret or access token. The token endpoint must use HTTPS and must not contain embedded credentials, query parameters, or a fragment. The client uses HTTP Basic client authentication, requires a Bearer token with a positive `expires_in`, and recreates the ADT client before the cached token expires because `abap-adt-api` 8.4.1 memoizes a bearer fetch.\n\nFor automation, pipe the client secret and add `--password-stdin`. On Linux, create the profile without `--login`, place the client secret in the printed profile-specific `SAP_ABAP_MCP_PASSWORD_<PROFILE>` environment variable, and start the MCP process from that environment. The variable name is retained for backward compatibility even when its value is an OAuth client secret.\n\nBrowser OAuth Authorization Code profiles are also available for identity\nproviders that support a loopback redirect URI and S256 PKCE:\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest profile add DEV100 \\\n  --url https://sap.example.com --client 100 \\\n  --auth-type oauth-authorization-code \\\n  --authorization-url https://login.example.com/oauth2/authorize \\\n  --token-url https://login.example.com/oauth2/token \\\n  --client-id mcp-public-client --scope \"openid abap\" --login\n```\n\nThe command opens the system browser, listens only on a random loopback port,\nvalidates OAuth `state`, exchanges the code with PKCE, and stores the resulting\ncredential in Keychain or DPAPI. Refresh-token rotation is persisted. Browser\nOAuth login is therefore available on macOS and Windows; Linux's environment-\nonly secret store cannot safely persist or rotate this credential.\n\nClient certificates, Kerberos, and user/password OAuth grants remain\nunsupported. OAuth behavior is still live-unverified for a particular SAP\nsystem until `doctor` succeeds there.\n\n### SAP BTP ABAP environment service keys\n\nA service key downloaded from an ABAP environment service instance already\ncontains the endpoint, client id, and client secret, so it can be imported\ndirectly:\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest profile add BTP100 --service-key ./service-key.json\n```\n\nThe command reads `url` for the ABAP endpoint, composes the token endpoint from\n`uaa.url` (or uses an explicit `uaa.tokenurl` when the key provides one), sets SAP\nclient `100`, verifies the credentials against SAP, and stores the client secret\nin the protected credential store. The secret is never typed into a terminal or\npassed as a command argument.\n\n**Delete the service key file afterwards.** BTP delivers it with the client\nsecret in plain text, and importing it does not remove that copy.\n\nService keys that use X.509 client certificates instead of a client secret are\nrejected with `SERVICE_KEY_CERTIFICATE_UNSUPPORTED` rather than producing a\nprofile that could never authenticate.\n\n## SAP data-query policy\n\nDirect SAP table queries are disabled for every new profile. Enable them only on a reviewed development or quality profile:\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest profile add DEV100 \\\n  --url https://sap.example.com --client 100 --username DEVELOPER \\\n  --environment development --allow-data-queries\n```\n\nProduction profiles cannot enable the capability. As in published 1.6.0, an opted-in development or quality profile permits queries that pass read-only SQL validation and SAP authorization; there is no MCP table denylist or per-call risk acknowledgement. Row limits remain enforced and SQL text is redacted even when audit argument capture is enabled.\n\nThis policy applies only to caller-supplied SQL sent to SAP. Processing caller-supplied structured data, reading a cached data view, and bounded internal metadata checks used by connection diagnostics do not require the opt-in.\n\n## Prerequisites\n\nAsk your SAP administrator for:\n\n- The SAP HTTPS base URL, for example `https://sap-dev.company.com`\n- The three-digit SAP client number\n- Your SAP user name\n- ADT development permissions required by the operations you intend to use\n- Confirmation that `/sap/bc/adt` and Basic Auth are enabled\n\nYour machine needs:\n\n- Node.js 20 or later\n- Codex or Claude Code\n- Network or VPN access to SAP\n- npm registry access to install the public package\n\nVerify Node.js first:\n\n```powershell\nnode --version\n```\n\n## Detailed setup on Windows\n\n### 1. Run interactive setup\n\n```powershell\nnpx.cmd @coaspe/sap-abap-mcp@latest setup\n```\n\nThe first run may ask whether npm may download the package; enter `y` to continue. The setup wizard collects the SAP URL, client, username, environment, and optional writable-package restriction. `Server name` is the local name used later as `connectionId`, for example `DEV100`. Keep production servers classified as `production`; they are read-only even if the package restriction is empty.\n\nWhen `SAP password:` appears, enter the password and press Enter; the input remains hidden. The server configuration and password are stored only after the MCP validates the credentials against SAP. Windows protects the password with DPAPI and never writes it to the profile file.\n\nThe setup command is one line in both PowerShell and Command Prompt. For advanced multiline commands, PowerShell continues a line with a backtick (`` ` ``), while Command Prompt (`cmd.exe`) uses a caret (`^`); do not mix them.\n\n### 2. Verify ADT connectivity\n\n```powershell\nnpx.cmd --yes --prefer-online @coaspe/sap-abap-mcp@latest doctor DEV100\n```\n\nA completed setup already performs this live check. Run `doctor` again whenever you want to recheck ADT connectivity; a successful response contains `\"ok\": true`.\n\n### 3. Register the MCP server\n\nCodex CLI:\n\n```powershell\ncodex mcp add sap-abap -- npx.cmd --yes --prefer-online @coaspe/sap-abap-mcp@latest serve --profile DEV100\n```\n\nClaude Code:\n\n```powershell\nclaude mcp add --transport stdio --scope user sap-abap -- npx.cmd --yes --prefer-online @coaspe/sap-abap-mcp@latest serve --profile DEV100\n```\n\nRestart the client after registration. Use `codex mcp list`, `claude mcp get sap-abap`, or the client's `/mcp` command to verify the connection.\n\nThe registration deliberately uses the moving npm tag `@latest` together with `--prefer-online`. Whenever Codex or Claude starts a new MCP process, npm checks which published version `latest` points to and runs that version. For example, a user who originally ran `0.4.7` will automatically run `0.4.8` after `0.4.8` is promoted to `latest` and the client is restarted. An already-running MCP process is not replaced in place. Maintainers should promote only tested releases to `latest`.\n\n### 4. Change or remove a saved server\n\nEdit a server with its current values as defaults. The wizard tests the updated settings and password before replacing the saved configuration:\n\n```powershell\nnpx.cmd @coaspe/sap-abap-mcp@latest setup edit DEV100\n```\n\nRemove a server and its stored SAP and abapGit credentials:\n\n```powershell\nnpx.cmd @coaspe/sap-abap-mcp@latest setup remove DEV100\n```\n\nOmit `DEV100` to choose from the saved servers. Removal always shows the selected server and asks for confirmation; the default answer is `No`.\n\n### 5. Start with read-only requests\n\n```text\nList the configured SAP systems and verify DEV100.\nFind class ZCL_DEMO in DEV100 and read its RUN method.\nRun syntax diagnostics and show a formatter preview without changing the source.\nBuild a depth-1 dependency graph for ZCL_DEMO.\n```\n\n## Detailed setup on macOS\n\nUse `npx` instead of `npx.cmd`:\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest setup\nnpx @coaspe/sap-abap-mcp@latest setup edit DEV100\nnpx @coaspe/sap-abap-mcp@latest setup remove DEV100\ncodex mcp add sap-abap -- npx --yes --prefer-online @coaspe/sap-abap-mcp@latest serve --profile DEV100\n```\n\nThe wizard tests the SAP connection and stores the password in macOS Keychain.\n\n## Linux and containers\n\nLinux runs the same interactive setup, but it does not persist credentials:\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest setup\n```\n\nThe wizard saves the non-secret server configuration and prints the exact hidden-input and `export` commands for its profile-specific password variable. Run those commands in the same shell that starts the MCP client, then run the printed `doctor` command. For example, server name `DEV-100` uses `SAP_ABAP_MCP_PASSWORD_DEV_100`. The Linux environment store is read-only, so `auth login` and `auth logout` are unavailable and no plaintext credential file is created.\n\n## Codex desktop setup\n\nIf the `codex` command is not available, add a stdio MCP server in Codex settings:\n\n- Name: `sap-abap`\n- Command on Windows: `npx.cmd`\n- Command on macOS: `npx`\n- Arguments:\n\n```text\n--yes\n--prefer-online\n@coaspe/sap-abap-mcp@latest\nserve\n--profile\nDEV100\n```\n\n## Multiple SAP systems\n\nCreate one profile per SAP client, for example `DEV100`, `QAS200`, and `PRD100`. To expose all profiles through one MCP server, register `serve` without `--profile`:\n\n```powershell\ncodex mcp add sap-abap -- npx.cmd --yes --prefer-online @coaspe/sap-abap-mcp@latest serve\n```\n\nEvery SAP-facing tool requires an explicit `connectionId`, which prevents accidental cross-system routing. Cross-system comparison requires the same object to exist in both selected profiles.\n\n## abapGit credentials\n\nPublic repositories require no additional setup. Store credentials for each private repository URL separately:\n\n```powershell\nnpx.cmd --yes --prefer-online @coaspe/sap-abap-mcp@latest abapgit auth login DEV100 `\n  --repository-url \"https://github.example.com/team/repo.git\" `\n  --username \"GIT_USER\"\n```\n\nStatus and removal:\n\n```powershell\nnpx.cmd --yes --prefer-online @coaspe/sap-abap-mcp@latest abapgit auth status DEV100 `\n  --repository-url \"https://github.example.com/team/repo.git\"\n\nnpx.cmd --yes --prefer-online @coaspe/sap-abap-mcp@latest abapgit auth logout DEV100 `\n  --repository-url \"https://github.example.com/team/repo.git\"\n```\n\nCredentials are selected by canonical repository URL so credentials for one remote cannot be sent to another. Passwords and tokens are not accepted as MCP tool arguments, and credentials embedded in a repository URL are rejected.\n\n## Write-safety model\n\nRepository-changing operations enforce these rules:\n\n- Profiles marked `production` reject writes.\n- A non-empty `allowedPackages` list restricts writes to those packages; an empty list allows all packages.\n- Packages other than `$TMP` require a transport request.\n- Exact source replacement reads the current source, obtains an SAP lock, rechecks it under the lock, writes, runs syntax diagnostics, optionally activates, and unlocks.\n- Rename, package move, method extraction, quick-fix application, formatting, deletion, and revision restore use a preview plan.\n- Preview plans expire after ten minutes and require the exact returned confirmation value.\n- Execution re-runs the SAP preview or source-state check and rejects stale plans.\n- Multi-object quick-fixes perform syntax preflight and attempt rollback if a later write fails.\n- RAP generation performs initial validation, content validation, and dry-run preview immediately before generation.\n- abapGit push accepts only a fresh SAP staging snapshot and requires explicit object selection or `stageAll=true`.\n- SAP transaction parameters use a restricted character set and are passed to the OS launcher as argument-array values rather than shell text.\n- ADT SQL accepts only `SELECT` and `WITH` statements.\n\nTransport release and deletion can be irreversible. Use a dedicated transport and verify the exact confirmation value before executing either action.\n\n## Audit log\n\nAuditing is off by default and is enabled per server process. When enabled, every\ntool call and Resource read emits exactly one JSON Lines record:\n\n```powershell\nnpx.cmd @coaspe/sap-abap-mcp@latest serve --profile DEV100 `\n  --audit-log file --audit-log-file C:\\ProgramData\\sap-abap-mcp\\audit.jsonl\n```\n\nUse `--audit-log stderr` to send the same records to the MCP host's server log\ninstead of a file. The equivalent environment variables are\n`SAP_ABAP_MCP_AUDIT_LOG`, `SAP_ABAP_MCP_AUDIT_LOG_FILE`, and\n`SAP_ABAP_MCP_AUDIT_INCLUDE_ARGUMENTS=1`, so a managed launcher can enable\nauditing without changing the registered MCP command.\n\nEach record carries the `sap-abap-mcp.audit/v1` schema:\n\n| Field | Meaning |\n|---|---|\n| `principal` | Actor identity; `local-process` uses the OS user running the process |\n| `kind`, `name` | `tool` or `resource`, and the advertised capability name |\n| `mutation` | True when the capability is not advertised with `readOnlyHint: true` |\n| `destructive` | True when the capability advertises `destructiveHint: true` |\n| `outcome` | `succeeded`, `denied` for a guardrail refusal, or `failed` |\n| `errorCode` | Machine-readable code for a `denied` or `failed` outcome |\n| `systemId`, `target` | Selected SAP profile and scalar object identity only |\n| `durationMs`, `timestamp`, `eventId` | Timing and correlation |\n| `argumentsDigest` | SHA-256 prefix of the redacted arguments |\n\n`outcome: \"denied\"` separates policy refusals such as\n`PRODUCTION_WRITE_BLOCKED`, `PACKAGE_NOT_ALLOWED`, `TRANSPORT_REQUIRED`, and\n`QUERY_NOT_READ_ONLY` from technical failures, so blocked attempts can be\ncounted independently.\n\nArguments are excluded unless `--audit-include-arguments` is set. Even then,\ncredential-shaped keys are replaced with `[redacted]`, strings are truncated at\n512 bytes so an ABAP source body is never written whole, arrays and recursion\ndepth are capped, and an oversized argument object is reduced to a byte count.\n`argumentsDigest` is computed from the redacted arguments, so it correlates\nrepeated calls without recording their content.\n\nA file sink creates its parent directory and the log file with owner-only\npermissions, and degrades to a single stderr warning rather than failing a tool\ncall if the file becomes unwritable.\n\nTwo boundaries are deliberate. A request rejected by MCP input-schema\nvalidation never reaches the capability and is not audited, because it never\nreached SAP. In stdio mode the `principal` is the local process identity, not\nthe SAP user; the SAP user is determined by the profile named in `systemId`. In\nHTTP mode the `principal` is the authenticated API key id.\n\n## Self-hosted HTTP mode\n\nThe default runtime is a local `stdio` process. `serve --http` runs the same\nserver over MCP Streamable HTTP so that one team can operate a single instance\nper SAP system with central configuration, central API keys, and one audit\nstream, instead of every developer holding SAP credentials on a laptop.\n\nThe HTTP listener is built directly on `node:http`. This mode adds **no new\nruntime dependency**, so the supply chain and audited attack surface are the\nsame as the stdio runtime.\n\n### 1. Create API keys\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest apikey new alice --role developer\n```\n\nThe command prints the key once together with a `record` object. Add the record\nto the `keys` array of a key file; the file stores only the SHA-256 digest, so a\ndisclosed key file contains no usable credential.\n\nKeys must come from `apikey new` or an equivalent CSPRNG. A generated key is 32\nrandom bytes, which encode to 43 base64url characters, and the server rejects any\ncredential shorter than that or outside that alphabet. SHA-256 is the right\nprimitive for a 256-bit random token: iteration hardening does not change the\nfeasibility of searching that space, and deriving a key on every request would\nlet an unauthenticated caller consume CPU at will, because rate limiting applies\nper principal and a caller has none until its credential is resolved.\n\n### Binding the key file to a server secret\n\nA validator cannot measure entropy, so the rules above raise the floor rather than\nproving strength — a long but non-random key would still be attackable from a\ndisclosed key file. Binding the digest to a server-side secret removes that\nresidual risk entirely, and stays fast, so it does not reintroduce the\ndenial-of-service concern a slow key-derivation function would:\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest apikey pepper > /etc/sap-abap-mcp/pepper\nnpx @coaspe/sap-abap-mcp@latest apikey new alice --role developer \\\n  --pepper-file /etc/sap-abap-mcp/pepper\n```\n\nThat emits `keyHmacSha256` instead of `keySha256`, and the server needs the same\nsecret:\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest serve --http \\\n  --api-keys-file /etc/sap-abap-mcp/api-keys.json \\\n  --api-key-pepper-file /etc/sap-abap-mcp/pepper\n```\n\nEach record names its own algorithm, so a key file is never ambiguous about what\nverifies it, and the two kinds may coexist during a migration. A `keyHmacSha256`\nrecord without the secret is refused rather than downgraded to a plain hash, so a\nmissing secret denies access instead of weakening verification — and `serve`\nrefuses to start if the key file needs a secret that was not supplied.\n\n**Store the secret outside the key file's directory.** Keeping them together\ndefeats the purpose, because one disclosure would yield both. The equivalent\nenvironment variable is `SAP_ABAP_MCP_API_KEY_PEPPER_FILE`.\n\n```json\n{\n  \"keys\": [\n    { \"id\": \"alice\", \"role\": \"developer\", \"keySha256\": \"…\" },\n    { \"id\": \"audit-bot\", \"role\": \"viewer\", \"keySha256\": \"…\" }\n  ]\n}\n```\n\n### 2. Start the server\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest serve --http \\\n  --api-keys-file /etc/sap-abap-mcp/api-keys.json \\\n  --host 0.0.0.0 --port 3000 --allowed-host mcp.internal.example.com\n```\n\n`--api-keys-file` is mandatory: this mode never starts unauthenticated. Clients\nconnect with `Authorization: Bearer <key>`. `GET /healthz` needs no credential\nand performs no SAP call. Auditing defaults to the `stderr` sink in HTTP mode\nbecause a shared server should not run unaudited.\n\n### 3. Roles\n\nA role is bound to an API key and restricts the surface a session can even see;\na hidden tool cannot be called by guessing its name.\n\n| Role | Advertised surface |\n|---|---|\n| `viewer` | Only tools advertised with `readOnlyHint: true` |\n| `developer` | Everything except the admin-only list below |\n| `admin` | The complete selected surface |\n\nAdmin-only tools are the irreversible or landscape-wide ones:\n`sap.transport.release`, `sap.transport.delete`, `sap.transport.owner.set`,\n`sap.transport.user.add`, `sap.repository.delete.execute`,\n`sap.version.restore.execute`, `sap.git.push`, `sap.git.unlink`,\n`sap.git.branch.switch`, `sap.rap.binding.publish`,\n`sap.rap.binding.unpublish`, and `sap.ui.transaction_launch`.\n\nLegacy `--api-version v0` groups many actions behind one tool name, so on that\nsurface only the `viewer` restriction is meaningful. Use the default v1 surface\nwhen roles matter.\n\n### 4. OIDC/JWT instead of static keys\n\nAn existing identity provider can issue MCP credentials, so keys do not have to be\ndistributed and rotated by hand:\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest serve --http \\\n  --oidc-issuer https://login.example.com/oauth2/v2.0 \\\n  --oidc-audience sap-abap-mcp \\\n  --oidc-role-map \"sap.developer=developer,sap.admin=admin\" \\\n  --host 0.0.0.0 --port 3000\n```\n\nClients then present the provider's access token as `Authorization: Bearer <jwt>`.\nAPI keys and OIDC can be enabled together; at least one is required.\n\n| Control | Behaviour |\n|---|---|\n| Algorithms | `RS256/384/512`, `PS256/384/512`, `ES256/384/512`. `HS*` and `none` are refused, because verifying an HMAC would require the server to hold the signing secret |\n| Keys | Fetched from `--oidc-jwks-uri`, defaulting to `<issuer>/.well-known/jwks.json`, cached for five minutes, refreshed once on an unknown `kid` so rotation is picked up |\n| Claims | `iss` and `aud` must match, `exp` is required, `nbf` is honoured, and 60 seconds of clock skew is tolerated |\n| Identity | `sub` becomes the audit principal; `preferred_username` is recorded when present |\n| Role | Read from `--oidc-role-claim`, default `scope`, mapped through `--oidc-role-map`. When several mapped values are present the highest privilege wins. Unmapped tokens fall back to `--oidc-default-role`, default `viewer` |\n\nVerification uses `node:crypto` only, so enabling OIDC still adds no dependency.\nThe equivalent environment variables are `SAP_ABAP_MCP_OIDC_ISSUER`,\n`SAP_ABAP_MCP_OIDC_AUDIENCE`, `SAP_ABAP_MCP_OIDC_JWKS_URI`, and\n`SAP_ABAP_MCP_OIDC_ROLE_MAP`.\n\n### 5. Per-user SAP identity\n\nBy default every session reaches SAP through whichever profile it names. Assigning\nprofiles per person makes SAP-side attribution per person too:\n\n```json\n{\n  \"keys\": [\n    { \"id\": \"alice\", \"role\": \"developer\", \"keySha256\": \"…\", \"systemIds\": [\"DEV100_ALICE\"] },\n    { \"id\": \"bob\", \"role\": \"developer\", \"keySha256\": \"…\", \"systemIds\": [\"DEV100_BOB\"] }\n  ]\n}\n```\n\nRegister one SAP profile per developer, each with that person's own SAP user, and\nlist it in their `systemIds`. Then:\n\n- SAP change documents attribute the work to that person's SAP user, not to one\n  shared technical account.\n- SAP authorization objects apply per person, so the SAP system itself becomes an\n  enforcement layer rather than only this server.\n- `sap.system.list` shows a principal only its own systems, and naming another\n  system returns `PROFILE_NOT_ALLOWED` without disclosing which systems others\n  may use.\n\nOmitting `systemIds` keeps every configured profile reachable, which is the\nsingle-identity default. SAP logins stay pooled across sessions.\n\nFor an OIDC token that SAP accepts directly, create an explicit passthrough\nprofile instead of storing a SAP credential:\n\n```bash\nnpx @coaspe/sap-abap-mcp@latest profile add DEV100_SSO \\\n  --url https://sap.example.com --client 100 \\\n  --auth-type bearer-passthrough\n```\n\nOnly an OIDC-authenticated HTTP session can use this profile. Its incoming JWT\nis forwarded to SAP within a request-scoped client, never for static API-key\nsessions, never for a non-passthrough profile, and never through the shared SAP\nconnection cache. The identity provider token must already be valid for the SAP\naudience; this mode does not perform a BTP token exchange.\n\n### 6. Transport security\n\n| Control | Behaviour |\n|---|---|\n| Bind address | Defaults to `127.0.0.1`; `--host 0.0.0.0` is an explicit opt-in |\n| TLS | Terminate TLS at a reverse proxy; this server speaks plain HTTP |\n| Origin | A request carrying `Origin` is rejected unless listed in `--allowed-origin`, which blocks browser-based cross-site and DNS-rebinding access |\n| Host | `--allowed-host` restricts accepted `Host` header values |\n| Session binding | A session is bound to the API key that opened it; replaying its id under another key returns 403 |\n| Rate limit | `--rate-limit` requests per principal per minute, default 240, reported through `RateLimit-*` and `Retry-After` |\n| Concurrency | `--max-concurrent` bounds in-flight SAP requests, default 8 |\n| Sessions | `--max-sessions` default 64, `--session-timeout` idle seconds default 1800 |\n| Body size | Requests above 4 MiB are rejected with 413 |\n| Headers | HSTS, `nosniff`, `DENY` framing, a `default-src 'none'` CSP, `no-referrer`, and `no-store` on every response |\n| CORS | Off unless `--allowed-origin` is set |\n\nEach session gets its own tool service, so preview plans, staged abapGit\nsnapshots, and execution plans are never shared between principals. SAP logins\nstay pooled across sessions.\n\n### 7. Container deployment\n\n```bash\ndocker build -t sap-abap-mcp .\ndocker run --rm -p 3000:3000 \\\n  -v /etc/sap-abap-mcp/api-keys.json:/run/secrets/sap-abap-mcp-api-keys.json:ro \\\n  -e SAP_ABAP_MCP_PASSWORD_DEV100=\"$SAP_PASSWORD\" \\\n  sap-abap-mcp\n```\n\nThe image contains no SAP credentials and no API keys. It runs as a non-root\nuser, and the Linux secret store is read-only, so SAP passwords are supplied\nonly through profile-specific environment variables.\n\n### Current limitation: token exchange\n\nPer-person SAP profiles give per-person attribution, and `bearer-passthrough`\ncan forward an OIDC user's token when SAP accepts that same token. This checkout\nalso implements an experimental `btp-destination` profile using the SAP Cloud\nSDK for user-token exchange or principal propagation. Its integration is tested\nlocally; live BTP exchange, Cloud Connector and SAP authorization are unverified.\nSee [experimental setup and evidence](docs/btp-destination-integration.md).\nThe HTTP listener speaks plain HTTP; terminate TLS at a reverse proxy.\n\n## Embed in another Node.js application\n\nThe npm package root is a side-effect-free library entry; importing it does not\nstart the CLI. Supply an application-owned `ConnectionProvider`, then connect\nthe returned server to any MCP transport supported by the SDK:\n\n```ts\nimport { createEmbeddedMcpServer } from \"@coaspe/sap-abap-mcp\"\n\nconst runtime = createEmbeddedMcpServer({\n  connectionProvider,\n  serverOptions: { apiVersion: \"v1\" }\n})\n\nawait runtime.server.connect(transport)\n// On application shutdown:\nawait runtime.close()\n```\n\nThe host retains ownership of SAP credentials and connection lifecycle. For\nlower-level composition, the same entry exports `createMcpServer`,\n`AbapToolService`, and the relevant provider/client types. The executable remains\n`sap-abap-mcp serve`; embedding does not change local CLI or registry launches.\n\n## Token-efficient operation\n\nThe server is designed to keep model context usage bounded without removing useful data:\n\n- The local CLI now defaults to 5 gateway tools with on-demand access to the complete 120-capability catalog. `--toolsets all` retains the full direct surface; `createMcpServer(service)` keeps its existing embedding default.\n- Adaptive discovery uses 26,821 minified schema bytes versus 168,227 for the full catalog in this checkout (84.1% less). This measures fixed schema bytes, not actual model tokens or total task cost. See [adaptive mode](docs/adaptive-mode.md).\n- The legacy v0 complete 53-tool schema remains below a 64 KiB automated guardrail.\n- `--preset compact` advertises 12 everyday read/inspect tools at about 22.4 KiB (about 5.6k tokens), below the compared package's measured compact surface.\n- `--preset development` advertises 34 read, edit, quality, Git, and transport tools at about 50.6 KiB (about 12.7k tokens).\n- `--preset assurance` advertises 15 read-only review and transport-assurance tools at about 24.8 KiB (about 6.2k tokens).\n- Source, search, SQL, ATC, dump, trace, transport, version, Git, and RAP schema responses are paged or summarized.\n- Unified diffs are limited by both line count and byte size.\n- Large source responses are bounded by an inline byte budget.\n- Discovery data and large download manifests can be exported to local files.\n- Compact JSON is returned without pretty-print whitespace.\n- Connection discovery returns only the profile ID, environment, and credential availability. Object-info reads normalize useful scalar metadata and return the raw ADT structure only when `includeStructure=true`.\n- Source reads identify the resolved object by name and type without repeating its search description, package, and object URI; `sourceUri` remains available for follow-up operations.\n- `search_abap_object_lines` always merges overlapping source windows into `contextBlocks` and reports matches once in `matchLineNumbers`, including enhancement source groups.\n- `get_sap_capabilities` omits evidence by default; request `includeEvidence=true` only when auditing discovery or execution observations.\n- Semantic, refactoring, ATC, version, activation, navigation, and download responses reuse the same compact object identity policy. Batch reads omit the parent `connectionId` from each nested result.\n- ATC findings reference one response-level object catalog. Dump, trace, and heartbeat list/mutation responses omit raw details that are available through explicit detail actions or options.\n- Compact JSON through 16 KiB is normally returned unchanged. Larger results return a bounded structural summary, an exact UTF-8 preview, and an in-memory `resultId` in a `compact-v1` envelope no larger than 12 KiB.\n- `search_abap_object_lines` switches to its bounded summary at 16 KiB and keeps the exact compact result behind the same `resultId`.\n\nThe complete 53-tool, 150-variant review and fixture measurements are in [`docs/response-token-audit.md`](docs/response-token-audit.md). Re-run `npm run benchmark:surface` for a machine-readable schema-cost report and `npm run benchmark:workflow` for [complete synthetic workflow payload costs](docs/workflow-cost-benchmark.md); see [`docs/compatibility-matrix.md`](docs/compatibility-matrix.md) for the live-evidence boundary.\n\nContinue paged responses with fields such as `nextStartIndex`, `nextLine`, `nextRowStart`, and `nextContentOffset`.\nFor a response with `format: \"compact-v1\"`, use `summary` first. Call `read_deferred_result` with its `resultId` and `nextOffset` only when omitted exact data is needed. A request may ask for up to 24 KiB, while the serialized chunk response remains within the 16 KiB inline budget; continue until `done` is true. Deferred results expire after ten minutes, are never written to disk, and reading them does not repeat the SAP request.\n\nHosts without automatic tool search can register only selected toolsets:\n\n```bash\nsap-abap-mcp serve --profile DEV100 --preset compact\n```\n\nPresets are `minimal`, `single`, `adaptive`, `compact`, `development`, and `assurance`. For custom composition, use `--toolsets core,write,analysis`; available toolsets are `core`, `write`, `analysis`, `debug`, `operations`, `artifacts`, and `all`. `--preset` and `--toolsets` are mutually exclusive. The local CLI default is `minimal`; use `--toolsets all` for direct compatibility.\n\n## Real SAP acceptance testing\n\nRun acceptance tests first against a development system.\nExisting SAP objects may be used for reads, searches, and analysis.\nCreation, modification, activation, execution, restore, debugging mutation,\nand deletion must target only objects created by the current test run in SAP\nlocal package `$TMP`.\n\nA name, prefix, search result, or `$TMP` package membership is not ownership\nevidence. A candidate becomes `RUN_OWNED` only after both a successful create receipt and an immediate exact read-back confirm the same system, package,\nobject type, name, and canonical URI. Every subsequent mutation requires an\nexact ledger match and another read-back. Cleanup may delete only those\n`RUN_OWNED` entries, using a fresh preview and exact confirmation.\n\nThe strict B4D campaign records transport, abapGit remote, and RAP publication\nmutations as `SKIP-SCOPE`: `$TMP` object ownership does not establish ownership\nof those external or system-wide targets. It never converts a skipped mutation\ninto a pass.\n\nFor BDEF creation, batch activation, class execution, the fixed ABAP REPL contract, and detailed semantic inspection, follow the evidence and cleanup procedure in [`docs/live-sap-acceptance.md`](docs/live-sap-acceptance.md). Until those checks succeed on a selected connection, the capabilities remain `unverified`.\n\nFor the complete Windows B4D campaign, use the\n[120-tool v1 `$TMP` acceptance prompt](docs/live-sap-v1-120-tool-tmp-test-prompt.ko.md)\nand the [Windows clone and connection guide](docs/live-sap-b4d-windows-local-test.ko.md).\n\nRecommended order:\n\n1. Connection, discovery, repository reads, semantic reads, versions, transports, and URL-only transaction generation.\n2. Create a dedicated test class and verify source write, diagnostics, activation, formatter, quick-fix, rename, extract method, inactive source, restore, package move, and guarded deletion.\n3. Test transport mutations only with a disposable transport.\n4. Test abapGit only with a disposable remote repository.\n5. Run RAP validation and preview before approving generation or service publication.\n\nWhen reporting a failure, preserve the MCP error code, HTTP status, ADT endpoint, and SAP response text. Do not retry failed ADT operations with guessed parameter variants.\n\n## CLI reference\n\n```text\nsetup\nsetup edit [<server-name>]\nsetup remove [<server-name>]\n\nprofile add <id> --url <url> --client <nnn> [--language EN]\n    [--environment development|quality|production]\n    [--username <user>] [--packages ZPKG1,ZPKG2]\n    [--allow-data-queries]\n    [--classic-bridge-path /sap/<path>]\n    [--auth-type basic|oauth-client-credentials|oauth-authorization-code|bearer-passthrough]\n    [--authorization-url <url>]\n    [--token-url <url> --client-id <id> [--scope <scope>]]\n    [--login [--password-stdin]]\nprofile add <id> --service-key <path> [--language EN]\n    [--environment development|quality|production]\n    [--scope <scope>] [--packages ZPKG1,ZPKG2]\n    [--allow-data-queries]\nprofile list\nprofile remove <id>\n\nauth login <id> [--username <user>] [--password-stdin]\nauth status <id>\nauth logout <id>\n\nabapgit auth login <id> --repository-url <url> --username <user> [--password-stdin]\nabapgit auth status <id> --repository-url <url>\nabapgit auth logout <id> --repository-url <url>\n\napikey new <id> [--role viewer|developer|admin] [--pepper-file <path>]\napikey pepper\n\nassure <id> --transport <trkorr> [--checks atc,unit_tests,target_compare]\n    [--target-system <id>] [--fail-on-atc-warnings] [--max-objects <n>]\n    [--formats json,sarif,junit] [--report-directory <path>]\n    [--fail-on incomplete|failed]\n\ndoctor <id> [--include-components]\nserve [--profile <id>] [--api-version v0|v1]\n    [--preset minimal|single|adaptive|compact|development|assurance]\n    [--toolsets core,write,analysis,debug,operations,artifacts|all]\n    [--audit-log none|stderr|file] [--audit-log-file <path>]\n    [--audit-include-arguments]\n    [--http --api-keys-file <path> [--host <host>] [--port <n>]\n     [--allowed-origin <origin,...>] [--allowed-host <host,...>]\n     [--api-key-pepper-file <path>]\n     [--rate-limit <requests-per-minute>] [--max-concurrent <n>]\n     [--max-sessions <n>] [--session-timeout <seconds>]]\n```\n\nRemoving a profile also removes its SAP password or OAuth client secret and stored abapGit credential vault.\n\n## Troubleshooting\n\n| Problem | Check |\n|---|---|\n| `node` is not found | Install Node.js 20 or later and reopen the terminal. |\n| npm cannot download the package | Check internet access, proxy configuration, and npm registry policy. |\n| `PROFILE_NOT_FOUND` | Run `setup` again and verify the Server name. |\n| SAP login fails | For Basic Auth, verify URL, client, username, password, VPN, and ADT activation. For OAuth, verify the token URL, client ID, client secret, scope, Bearer response, and ADT authorization. |\n| Certificate or connection error | Check the corporate CA, proxy, VPN, and SAP HTTPS endpoint. |\n| MCP `-32000` (`ConnectionClosed`) | The stdio process closed during initialization; this is not an SAP API status. Run `npm run smoke:v1`, then start `node dist/src/index.js serve --profile <id>` directly. If both work, inspect the saved command with `claude mcp get <name>` and start Claude with `claude --debug mcp`. |\n| Tools are missing | Confirm that the MCP command contains `@latest` and `--prefer-online`, restart it, and inspect `/mcp`. |\n| Writes return `PACKAGE_NOT_ALLOWED` | The profile has a non-empty `--packages` restriction; add the target package or remove the restriction. |\n| Writes return `TRANSPORT_REQUIRED` | Supply an open transport for non-local packages. |\n| RAP generator is unavailable | The SAP release or installed components may not expose the RAP generator endpoints. |\n| Private Git access fails | Store credentials for the exact canonical repository URL. |\n\nBrowser SSO-only, MFA-only, certificate-only, and Kerberos-only SAP systems are not supported by this release. Use Basic Auth or an explicitly configured OAuth client-credentials client accepted by the ADT endpoint.\n\n## Local development\n\n```bash\nnpm install\nnpm run check\nnpm audit --omit=dev\nnpm pack --dry-run\n```\n\nRegister the current local build for pre-release testing:\n\n```bash\nnpm run build\ncodex mcp add sap-abap-local -- node \"/absolute/path/to/sap-abap-mcp/dist/src/index.js\" serve --profile DEV100\n```\n\nThe compatibility and toolset manifest is maintained in `src/compat/abap-fs-tools.ts`. ADT wrapper contract tests are in `test/sap-client-contract.test.ts`, and end-to-end in-memory MCP tests are in `test/integration.test.ts`.\n\n## Release status\n\n- Package: `@coaspe/sap-abap-mcp`\n- Checkout manifest version: `1.7.0`\n- Install: `npx @coaspe/sap-abap-mcp@1.7.0`\n- Source lineage and company acceptance scope: [release record](docs/release-1.7.0.md). Default CLI startup exposes five gateways; all 120 capabilities remain discoverable.\n- Runtime: Node.js 20 or later\n- Transport: local MCP over stdio by default; opt-in self-hosted Streamable HTTP\n- SAP authentication: SAP Basic Auth by default; opt-in OAuth client credentials, browser Authorization Code with PKCE, or request-scoped OIDC bearer passthrough\n- HTTP client authentication: mandatory Bearer API keys with viewer/developer/admin roles\n- Secret storage: macOS Keychain, Windows DPAPI, or read-only environment variables on Linux\n- SAP API client: `abap-adt-api` 8.4.1\n- ABAP FS compatibility baseline: 2.6.5, commit `3041418d35558e043993a4d7f9fa6b727fcf9cf1`\n\nThe automated suite validates the MCP contract, ADT argument ordering, safety\npolicies, stale-preview protection, output bounds, all 120 v1 capabilities, the adaptive gateway,\nall seven v1 Resources, and the legacy 53-tool v0 surface with an in-memory SAP\nimplementation. Live SAP acceptance testing is still required because endpoint\navailability and authorization vary by SAP release and system configuration.\n\n## Known limitations\n\nThese reflect ADT behaviour that varies by SAP system. The tools fail safely and report an actionable message when a system does not support the operation.\n\n- **Transport release of requests/tasks that contain objects**: some systems reject the synchronous ADT release endpoint for object-bearing transports and only run release as a background job from the GUI. In that case `release_transport` returns `TRANSPORT_RELEASE_UNSUPPORTED` with guidance to release from SE10/SE09, and the error details carry the ADT endpoint, HTTP status, ADT error type, and the exact SAP response text. The asynchronous background-run path is not implemented because its ADT wire protocol is not publicly documented and is not exposed by `abap-adt-api`; implementing it by guessing endpoints is explicitly out of scope. If you can reproduce this, attach those preserved error details to an issue — they are the evidence the implementation needs. Empty and request-only transports release normally.\n- **abapGit tools require the abapGit ADT backend**: the git",
  "bytes": 60000,
  "sha": "76fd94a3f40fedb7ab43326788589fa79acd788c28e2b41e365a5f6fc24cf5c2",
  "repo_slug": "coaspe/sap-abap-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_coaspe_sap_abap_mcp_a1398268/readme"
}