btp-cf-mcp
An MCP server over an SAP BTP account and its Cloud Foundry runtime that acts as the person who logged in, so their own global-account and space roles decide what an agent can see.
An assistant asked which applications are running, or what a subaccount is entitled to, normally needs a technical user with rights nobody wants to hand it. This is its own OAuth authorization server: it proxies login to SAP Cloud Identity Services, seals the user's credential into an audience-bound JWE of its own, and on every call unseals it, does the app-to-app exchange and calls Cloud Controller v3 and the btp CLI server protocol as that user, so the audit trail names the real person. Reads and writes are separate tools, which is what lets each read tool declare readOnlyHint:true and a read-only deployment render only CFInspect and BTPInspect. CFInspect covers orgs, spaces, applications, services, routes and instance health; BTPInspect covers subaccounts, the global account, environments, entitlements and subscriptions. A shared read-only technical user is the second identity model, for headless callers with an API key, and both run on one instance. It reimplements the btp CLI server protocol over HTTPS, so no CLI binary sits in the container, and it is deployed to Cloud Foundry rather than run from npm.
Facts
Where it sits
Who is behind it
In the atlas: maintains 35, contributes to 86, wrote 25@marianfoomaintainer
Before choosing this
Conditions
PolicySAP API Policy 4.2026a§ 1.1, 1.2, 2.2.2from Serve your application over MCPAn MCP server exposes an SAP API, or uses SAP APIs to supply tools, resources or data to an agent.
- § 1.1 Published APIs. Published APIs are made available for the documented purposes identified by SAP, including integration, extensions and data exchange.
- § 1.2 Non-Published APIs. Customer and third-party applications must not access non-published APIs except where documentation permits it or SAP otherwise authorizes it.
- § 2.2.2 AI call sequences and data extraction. Outside SAP-endorsed architectures, data services or expressly identified pathways, the policy prohibits specified agentic API use and systematic or large-scale extraction.
MCP does not replace the API's documented-use boundary. Check that every endpoint is published for the intended use and whether the policy's AI-call or extraction provisions apply to the design.
SAP API Policy 4.2026a →What it declares
Every artifact
- Type
- MCP server
- Origin
- Independently maintained
- Runtime
- Node.js
- Runs on
- Cloud Foundry
As an MCP server
- Runs as
- central server
- Transport
- HTTP
- Authentication
- OAuth / OIDCAPI key
- Read-only
- yesstates it is
- Guardrails
4 quoted from README, Safety show all
Scopes (
read/write/admin) prune the tool list — the LLM only sees what the caller may do.Two authz layers — the server's scope gate and the user's real BTP/CF roles (defense in depth).
Consent gate on the OAuth proxy (confused-deputy defense); secrets never logged; sealed tokens are audience-bound so they can't be replayed at a sibling service.
CFApps gates on the app's server-resolved space (never a caller-supplied value).
Connections
Exposing application data and operations to agents over MCP
Cloud Foundry runtime of SAP BTP for polyglot applications
MCP server over the ADT REST API for ABAP objects
Download
Architecture
Download
npx @modelcontextprotocol/inspector) at https://<route>/mcp”README
quoted from marianfoo/btp-cf-mcp under MIT, readbtp-cf-mcp
An MCP server that lets an AI assistant inspect and manage your SAP BTP account and Cloud Foundry — as you. A user signs in once via IAS; the server then calls the BTP and Cloud Foundry APIs under that person's own identity, so their real roles are enforced and the audit trail shows the real human — no shared technical password, no second login. A shared read-only technical user mode is also available for headless/automation callers.
Status: a working proof-of-concept, read-only by default. Reads are live-verified on a free-tier BTP account; writes (app lifecycle, service create/delete) execute only when explicitly enabled and only against allowlisted targets. See Status.
What it is
An MCP server (same lineage as arc-1, which does this for ABAP) that gives Claude — or any MCP client — a small, safe set of tools over:
- SAP BTP account — subaccounts, environments, entitlements (via the
btpCLI server APIs). - Cloud Foundry — orgs, spaces, apps, services (via the Cloud Controller v3 API).
The point of difference is identity: the server is its own OAuth authorization server that proxies
login to IAS, seals the user's credential into its own token, and then acts as that user on every
call — CF enforces their org/space roles, BTP enforces their global-account roles. It reimplements the
btp CLI server protocol over plain HTTPS, so there is no CLI binary in the container.
What you can do
Reads and writes are separate tools so each read tool is honestly readOnlyHint:true (hosts
auto-approve, no confirm friction), and a read-only deployment renders only the two Inspect tools:
| Tool | Actions | Notes |
|---|---|---|
CFInspect (read) | orgs, spaces, apps, services, routes, app_detail, app_processes | Cloud Controller v3; as the user or a shared CF token. app_processes = instance health/state |
BTPInspect (read) | subaccount, subaccounts, global_account, environments, entitlements, subscriptions | entitlements = global-account catalog, or a subaccount's plan assignments if you pass a subaccount |
whoami | — | diagnostic: resolved scopes + token claims |
CFApps / BTPServices (write) | restart/stop/start an app · create/delete service instances | per-user (OAuth) only; hidden unless ALLOW_WRITES=true; targets must be allowlisted — CFApps resolves the app's real space server-side |
A deliberately small surface (fewer tools select more accurately). Every action is defined once in a
single-source registry (src/registry.ts); the schema, scopes, MCP annotations, and dispatch all
derive from it — so growing capability is adding a row, not a tool.
Use cases
- "Which of my apps are running, and is anything crashed?" — an AI ops helper over
CFInspect.appsfor a developer, scoped to exactly the spaces they have roles in. - "What service plans is this account entitled to, and how much quota is left?" —
BTPInspect.entitlementsfor capacity/licensing questions, without opening the cockpit. - "List my subaccounts and their environments" — a quick BTP-account overview from chat.
- Team read-only assistant — point a shared, read-only technical user (Global Account Viewer + Subaccount Viewer) at a support channel so anyone can ask about the landscape, with one auditable identity.
- Per-developer accountability — each developer's assistant logs in as them, so it sees only what they're entitled to and every action is attributed to the real person.
How it works
MCP client ──OAuth (this server IS the auth server, proxying to IAS)──▶ [btp-cf-mcp]
│ or Authorization: Bearer <api-key> │ MCP token = a sealed JWE
▼ │ holding the user's IAS credential
IAS login (browser, once) ◀───────────────────────────────────────────────┤
per request: unseal → IAS app-to-app exchange │
┌───────────────────────────────────────────────────────────┘
▼ CFInspect ▼ BTPInspect
CF UAA → Cloud Controller v3 (as you) btp CLI *server* REST (as you) — no binary
- Inbound — the server exposes OAuth (
/authorize/token/register+ discovery), proxies login to IAS, and issues its own token: a sealed, audience-bound JWE of the IAS credential (never a passthrough). DCR is guarded by a consent gate so a user always sees which client they're authorizing. - Outbound — per request it unseals the credential, does the IAS app-to-app exchange, and calls CF (via CF UAA) and BTP (via the CLI-server protocol) as the user.
Full design + the hard-won auth details: docs/guides/per-user-ias-auth-setup.md.
Two identity models
- Per-user ("acts as you") — best audit + least-privilege; each user logs in via IAS.
- Shared read-only technical user — one service account (Global Account Viewer + Subaccount Viewer) for headless/API-key callers; simpler, one audited identity.
Both can run on the same instance — an OAuth caller runs per-user, an API-key caller uses the tech user. Setup + trade-offs: docs/guides/admin-deployment.md → "Identity models".
Safety
- Read-only by default (
ALLOW_WRITES=false); writes need explicit enablement + a fail-closed target allowlist (ALLOWED_SUBACCOUNTS/ORGS/SPACES) + per-actionDENY_ACTIONS. - Scopes (
read/write/admin) prune the tool list — the LLM only sees what the caller may do. - Two authz layers — the server's scope gate and the user's real BTP/CF roles (defense in depth).
- Consent gate on the OAuth proxy (confused-deputy defense); secrets never logged; sealed tokens are audience-bound so they can't be replayed at a sibling service.
Quick start
Deploy to BTP Cloud Foundry (IAS-first, per-user):
npm ci && npm run build # dist/ is not committed — build before pushing
cf push btp-cf-mcp # or: mbt build && cf deploy (secrets via an mtaext OUTSIDE the repo — see mta.yaml)
# then set the IAS-first config (secrets via cf set-env, never manifest.yml):
cf set-env btp-cf-mcp SEALING_SECRET "$(openssl rand -hex 32)"
cf set-env btp-cf-mcp IAS_ISSUER https://<tenant>.accounts.ondemand.com
cf set-env btp-cf-mcp IAS_CLIENT_ID <id> # + IAS_CLIENT_SECRET, CF_PLATFORM_CLIENT_ID,
cf set-env btp-cf-mcp CF_UAA_URL ... # CF_UAA_URL, CF_API, BTP_GA_SUBDOMAIN, PUBLIC_URL
cf restage btp-cf-mcp
Point an MCP client (Claude, npx @modelcontextprotocol/inspector) at https://<route>/mcp → it
discovers OAuth, you log in via IAS, and tool calls run as you. Full step-by-step (IAS app, the roles
that make reads return data, troubleshooting, caveats): docs/guides/admin-deployment.md.
Status
Shipped + live-verified (free-tier BTP account):
-
✅ IAS-first per-user inbound (OAuth proxy) + a signed, browser-bound consent gate.
-
✅ Per-user Cloud Foundry (Cloud Controller, as the user) and BTP account reads (CLI-server protocol, no binary).
-
✅ Shared read-only technical user mode (username/password login).
-
✅ Read-only safety gate + scope-based tool pruning; sealing-key rotation; refresh-token rotation; session caching.
-
✅ Read/write-split tool surface (
CFInspect/BTPInspect+ write tools) with honest MCP annotations. -
✅ Writes: CF app lifecycle (restart/stop/start) + Service Manager create/delete — off by default, fail-closed target allowlists, and CFApps gates on the app's server-resolved space (never a caller-supplied value).
PoC boundaries:
- ⏳ Async job polling for service create/delete is manual (verify via
BTPInspect.service_instances). - ⏳ Mapping IAS groups → scopes and an MTA-only deploy are future work.
Documentation
- docs/guides/admin-deployment.md — deploy + configure (start here)
- docs/guides/connect-mcp-clients.md — connect Copilot / Claude Desktop / Codex / VS Code / Cursor
- docs/guides/per-user-ias-auth-setup.md — the IAS per-user auth recipe
- ROADMAP.md — what works today vs what's planned · CONTRIBUTING.md — dev setup
- docs/README.md — full docs index · AGENTS.md — codebase guide for AI agents
Others providing
Compare all 2 on the Serve your application over MCP page →- API ManagementAPI ManagementAPI proxies in front of backend services, with security and traffic management policies attached to them, and Developer Hub where consumers subscribe.sap official, btpAPI proxies with security and traffic policies and Developer Hub
Details
Sources
Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.
Compatibility and provenance
History in the atlas
- Read out of the marianfoo account listing. Entered as a starting-point, since the maintainer's own status line calls it "a working proof-of-concept", so its boundaries sit in description.to_build_on_it rather than in a warning. capability:mcp-servers already reads core-only on the BTP door because every provider there is SAP-published; this is an independent one, which is a reading the capability will have to move.
- First seen.
For your agent
- Ref
artifact:marianfoo-btp-cf-mcp- JSON
- /artifacts/marianfoo-btp-cf-mcp.json
- MCP
- Connecting an agent