Skip to content

Write to a pinned SAP target

Multi-target writes use the existing pinned URL and the existing SAP_ALLOW_WRITES switch. They require Principal Propagation (PP), target-filtered authorization, destination opt-in, and a separate exact write grant. Enabling the global switch alone grants no multi-target writes.

Connection Reads Scoped object writes
Pinned PP /<SYSTEM-OR-ALIAS>/<CLIENT>/mcp Subject to access grants and SAP authorization Only when every write gate below agrees
Aggregate /multi/mcp Explicit target on each call Never
Copilot /authorize compatibility connection Aggregate reads Never; register a separate pinned connection for writing
Pinned BasicAuthentication Shared technical identity Never
Independent single-target /mcp Existing single-target rules Existing single-target rules; this guide does not change them

Use the CF deployment runbook, multi-target destination setup, and target authorization guide first. Target-filtered mode cannot coexist with an independent single-target destination in the same application. The example below adds writes to a configured target-filtered PP deployment; it is not a second deployment recipe.

Configure one writable and one read-only target

The validated write overlay and destination example provide this configuration with fictional targets. In the application's MTA extension properties: (or equivalently cf set-env), set:

SAP_ALLOW_WRITES: "true"
SAP_ALLOWED_PACKAGES: "$TMP,ZTEAM/**"
SAP_ALLOWED_TRANSPORTS: "DEVK9*"
ARC1_MULTI_TARGET_ENDPOINTS: "true"
ARC1_MULTI_TARGET_AUTHORIZATION: "xsuaa-attribute"
ARC1_CACHE: "none"
ARC1_TOOL_MODE: "standard"
ARC1_UI: "off"

Keep the existing XSUAA/Destination/Connectivity bindings and PP configuration. Do not add a second write-enable parameter. Plugins and shared cookies remain unavailable in multi-target mode. SAP_ALLOW_TRANSPORT_WRITES and SAP_ALLOW_GIT_WRITES need not be enabled: transport/Git management is outside this write surface.

On the enabled PP destination for development target DEV/001, add:

arc1.allow_writes=true
arc1.allowed_packages=$TMP,ZTEAM_COMPONENT/**
arc1.allowed_transports=DEVK900123

Keep the destination's real sap-sysid, sap-client, URL, Cloud Connector location and optional arc1.target_alias from the existing setup. On read-only target QAS/001, omit all three write properties. A pinned URL names the public target ID, including its alias if configured.

Both package lists apply. A package must match the global list and the destination list. Here, ZTEAM_OTHER is not writable merely because it matches the global subtree. Conversely, a destination cannot permit a package excluded globally. Existing-object checks use the real SAP package, not a package supplied by the caller. Package subtree lookup failures deny the write.

Destination package lists support exact names, prefix patterns (ZTEAM*), DEVCLASS subtrees (ZTEAM/**) and explicit *. Transport lists support exact request IDs, prefixes and explicit *. Lists are bounded to 128 entries, 128 characters per entry and 8192 characters total; use ASCII, commas and optional surrounding spaces. Empty entries and malformed values quarantine the destination. A package list is required whenever the destination requests writes, even while the global switch is off. Missing destination transport policy allows only positively verified local objects.

Transport policy authorizes requests and their SAP-managed tasks. In this example only DEVK900123 is allowed. If a caller supplies one of its tasks, ARC-1 verifies membership and uses the parent request for the SAP save. A task-only allowlist entry does not grant its parent. The request must be a modifiable Workbench request; unknown/mismatched recording evidence denies the write. Manage requests in ADT/SAP GUI or a separately authorized single-target connection.

Assign the exact write grant

Deploy the updated xs-security.json to the application's XSUAA service. It adds the MCPTargetDeveloper template; it does not grant users access automatically. In BTP Cockpit, create a concrete role from that template with:

Attribute Example values Meaning
arc1_targets DEV/001, QAS/001 Targets this user may access
arc1_write_targets DEV/001 Exact targets this user may write through pinned PP connections

First enable and verify ARC1_MULTI_TARGET_AUTHORIZATION=xsuaa-attribute on the application. MCPTargetDeveloper carries application-wide read/write scopes; its attributes only restrict access in that enforced multi-target mode. Do not assign it to standard or single-target apps expecting target isolation, or reuse an XSUAA service/role collection across apps without checking each app.

Add that concrete role to a collection and assign the collection to the intended user or identity group. The template supplies read and write scopes. Read * is supported by the existing read contract; write *, globs and comma-separated values inside an attribute value are rejected. Admin does not bypass the exact write grant. A token containing a write-target attribute but only read scope cannot write either.

The equivalent BTP CLI role creation was verified during qualification. Target the intended subaccount first, obtain the actual application ID from btp list security/app, and save:

target-developer-attributes.json
[
  { "attributeName": "arc1_targets", "attributeValueOrigin": "static", "attributeValues": ["DEV/001", "QAS/001"] },
  { "attributeName": "arc1_write_targets", "attributeValueOrigin": "static", "attributeValues": ["DEV/001"] }
]
btp create security/role "Develop DEV, read QAS" --of-app "<application-id>" \
  --of-role-template MCPTargetDeveloper --attributes target-developer-attributes.json
btp create security/role-collection "ARC1 DEV developers"
btp add security/role "Develop DEV, read QAS" --to-role-collection "ARC1 DEV developers" \
  --of-app "<application-id>" --of-role-template MCPTargetDeveloper
btp assign security/role-collection "ARC1 DEV developers" --to-user "<user>" \
  --of-idp "<configured-identity-provider-origin>" --create-user-if-missing false

Use the actual trust origin from your subaccount, not a guessed email-to-SAP mapping. SAP PP maps the signed-in identity to the SAP user; ARC-1 does not use the JWT email as object responsible user.

Restart every ARC-1 application instance after changing destination or server policy. Then register https://<arc1-route>/DEV/001/mcp as a separate MCP connection, request read/write scope, sign in fresh and refresh the tool catalog. Keep /multi/mcp for cross-target reads. A client that exposes only the aggregate compatibility connection cannot write through that connection.

What the writer can do

Action Requirements
SAPWrite.create One CLAS or INTF; explicit package and complete source; required allowed request/task for a transportable package
SAPWrite.update CLAS/INTF main source; expectedSourceHash from SAPRead(format="editable")
SAPWrite.edit_method Existing CLAS main-source method; hash of the complete editable main source
SAPActivate One CLAS/INTF owner; activates all of that owner's existing inactive drafts and includes

Creates and edits save inactive source. Review it before activation. Activation is whole-owner, including drafts created previously or by another session; it is not method-only activation. Use SAP_DENY_ACTIONS=SAPActivate if your team must activate separately in ADT. Hidden actions, other types, deletes, include editing, batches, RAP/DDIC, publication, transport management and Git are refused even if a client sends the call directly. Per-call lint-disable options are unavailable. ABAP Unit can execute newly authored code under the SAP user; deny SAPDiagnose.unittest unless that execution is intended. Global lint configuration applies; SAP_CHECK_BEFORE_WRITE remains advisory. SAP authorization is always required in addition to ARC-1 policy. Live qualification used SAP_BASIS 758 SP02 with Cloud Connector PP. Other releases must affirm the same lock, recording and activation evidence; unrecognized responses fail closed. An activation response without positive execution evidence is reported as unconfirmed, even when the HTTP request succeeded. On the qualified 758 system, activating an already-active owner returned no positive execution evidence and therefore this unconfirmed result. Read the active/inactive state before deciding whether any action is needed.

A hash establishes source freshness, not target identity. Verify the pinned connection before editing. SAP repository objects are generally cross-client: two clients of one physical system are not independent development sandboxes.

Diagnose, disable and recover

SAPTargets is available to readers with more than one visible granted target and to admins; with one target use its pinned connection and tool catalog. On the aggregate connection it reports a bounded pinnedWrite status for configured write targets visible to the caller. Admin diagnostics additionally show configured/effective flags, rule counts and a policy digest. No raw restriction list or destination credential is exposed.

Symptom Check
No write tools on the pinned PP connection Global switch, destination opt-in, target-filtered mode, fresh token's raw write scope, access grant and exact write grant
Destination quarantined Strict property syntax; PP required for write opt-in; standard mode rejects write properties; transport/Git enabling properties are unsupported
Package denied Both independent allowlists and the real SAP owner package; subtree metadata access
CTS denied Explicit destination request allowance, global allowance, modifiable parent and exact task membership
Source changed Read the same owner's editable main source again, review changes, and use its new hash
TARGET_CONFIG_CHANGED Restart all instances after reviewing the changed destination; never silently remap an old ID to another backend
Partial/unknown write result Inspect the object, inactive source, CTS recording and locks. Do not automatically replay; creation may have left a stub or a save may have completed

For immediate administrative disable, set SAP_ALLOW_WRITES: "false" and restart all instances, or turn off the destination's write opt-in. A changed destination fingerprint refuses subsequent lookups immediately; restart every instance to adopt the new snapshot. Already admitted work may complete. Merely removing a role is not immediate revocation: old tokens and refresh sessions can retain grants. Require fresh authorization and verify the new effective permissions after IAM changes.

Keep the prior application artifact/configuration for rollback. Old binaries quarantine destinations containing the new properties. On upgrade, those previously quarantined destinations may become readable (and writable only if all new gates agree); review them before upgrading. Restore the corresponding destination configuration when rolling back. Do not delete an MTA property to turn it off; explicitly set its false value. Audit delivery retains the existing asynchronous BTP Audit Log contract; monitor failures rather than assuming a write waits for a durable audit acknowledgement.