Install
$ agentstack add mcp-fr0ster-mcp-calm-server ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
@mcp-abap-adt/calm-server
[](https://stand-with-ukraine.pp.ua)
MCP server for SAP Cloud ALM, built on @mcp-abap-adt/calm-client. Ships 54 MCP tools covering all 9 Cloud ALM services — full CRUD where the service supports it, plus a wide read surface — with rich JSON Schema descriptions that let an LLM plan multi-step workflows.
This package is dual-purpose:
- Runnable stdio server —
npx @mcp-abap-adt/calm-server. Plug
directly into Claude Desktop, Claude Code, or any MCP-compatible host.
- Reusable library of tool primitives — import individual tools
(FEATURES_GROUP, TASKS_GROUP, …) and embed them in a larger composed MCP server without reimplementing anything.
Status
0.2.0 — 54 tools, 232 tests (224 unit + integration, 7 env-gated skips, 1 todo), full build green. Integration suite runs live against the SAP sandbox (api.sap.com) or any OAuth2 Cloud ALM tenant with a single .env switch; gates skip cleanly when no backend is wired.
Installation
As a standalone MCP server
npm install -g @mcp-abap-adt/calm-server
# or per-project:
npm install @mcp-abap-adt/calm-server
As a library (compose into your own MCP server)
npm install @mcp-abap-adt/calm-server
# peers:
npm install @mcp-abap-adt/calm-client @mcp-abap-adt/interfaces @modelcontextprotocol/sdk
Standalone: running the server
1. Configure credentials
Copy the template and fill in:
cp .env.example .env
OAuth2 mode (real tenant) — paste values from an XSUAA service key:
CALM_MODE=oauth2
CALM_BASE_URL=https://..alm.cloud.sap
CALM_UAA_URL=https://.authentication..hana.ondemand.com
CALM_UAA_CLIENT_ID=sb-…!b…|calm!b…
CALM_UAA_CLIENT_SECRET=…
Sandbox mode (SAP API Business Hub):
CALM_MODE=sandbox
CALM_API_KEY=
# CALM_BASE_URL defaults to https://sandbox.api.sap.com/SAPCALM
2. Launch
# Global install:
calm-mcp
# Or via npx without install:
npx @mcp-abap-adt/calm-server
# Or from a clone:
npm run build && node dist/bin/stdio.js
The server speaks MCP over stdio. Misconfiguration is reported to stderr with a non-zero exit code.
Authentication setup
calm-mcp supports two OAuth2 flows for live tenants, selectable via CALM_AUTH_FLOW:
| Flow | Use case | Browser? | Refresh token? | |---|---|---|---| | client_credentials (default) | technical service-binding (sb-* client) | no | no | | authorization_code | end-user dev workflow, full user scope | once | yes |
Option A — quick CC setup (technical user)
Plain .env with inline CALM_UAA_URL / CALM_UAA_CLIENT_ID / CALM_UAA_CLIENT_SECRET works as before — no extra steps. The broker uses an in-memory session shim for these inline creds.
Option B — broker-backed setup (CC or AC)
Use the bundled mcp-auth CLI to convert a BTP service key into a token-bearing .env:
# CC (no browser)
npx mcp-auth --service-key ./sk.json --output ./DEFAULT.env \
--type xsuaa --credential
# AC (browser pops once; refresh_token persists)
npx mcp-auth --service-key ./sk.json --output ./DEFAULT.env \
--type xsuaa --browser auto
Then in your .env:
CALM_MODE=oauth2
CALM_BASE_URL=https://..alm.cloud.sap
CALM_AUTH_FLOW=authorization_code # or client_credentials
CALM_DESTINATION=DEFAULT
The server's runtime auth pipeline is @mcp-abap-adt/auth-broker.
> Note: buildCalmClient is async since v0.4.0 (was sync in v0.3.x). Library > consumers must await it.
3. Wire into Claude Desktop
Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"calm": {
"command": "npx",
"args": ["-y", "@mcp-abap-adt/calm-server"],
"env": {
"CALM_MODE": "sandbox",
"CALM_API_KEY": ""
}
}
}
}
Restart Claude Desktop; the 54 calm_* tools become available to the model.
Library: composing into another MCP server
Useful when you want to expose Cloud ALM tools alongside ADT tools, Reports tools, or your own domain tools in a single MCP process.
import { CalmClient, CalmConnection } from '@mcp-abap-adt/calm-client';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import {
ALL_GROUPS,
BaseCalmMcpServer,
CalmToolRegistry,
FEATURES_GROUP,
TASKS_GROUP,
} from '@mcp-abap-adt/calm-server';
// Option A — BaseCalmMcpServer with a curated subset
const calm = new CalmClient(
new CalmConnection({ baseUrl, apiKey }),
);
const server = new BaseCalmMcpServer({
name: 'my-mcp',
version: '1.0.0',
calm,
groups: [FEATURES_GROUP, TASKS_GROUP], // only these land as tools
});
// Option B — embed into your existing McpServer
const existing = new McpServer({ name: 'combined', version: '1.0.0' });
const registry = new CalmToolRegistry([...ALL_GROUPS]);
registry.registerAll(existing, () => ({ calm }));
// Now `existing` serves Cloud ALM tools + whatever else you registered.
Subpath exports:
import { ALL_GROUPS } from '@mcp-abap-adt/calm-server/tools';
import { CalmToolRegistry } from '@mcp-abap-adt/calm-server/registry';
Tool surface (54 tools across 9 services)
| Service | Tools | |---|---| | Features (11) | list, get, get_by_display_id, create, update, delete, create_external_reference, delete_external_reference, list_external_references, list_statuses, list_priorities | | Tasks (10) | list, get, create, update, delete, list_comments, create_comment, list_references, list_deliverables, list_workstreams | | TestCases (9) | list, get, create, update, delete, create_activity, create_action, list_activities, list_actions | | Documents (7) | list, get, create, update, delete, list_statuses, list_types | | Projects (7) | list, get, create, list_programs, get_program, list_team_members, list_timeboxes | | Hierarchy (5) | list, get_with_children, create_node, update_node, delete_node | | Analytics (2, read-only) | query (17 endpoints), list_providers (static catalog) | | Logs (2, domain-specific REST) | get (provider + serviceId + time window), post (inbound log records) | | ProcessMonitoring (1, read-only) | list_processes |
Every MCP tool:
- Has a full JSON Schema with descriptions — the LLM reads these to plan.
- Wraps arguments into OData
$filter/$select/$top/$skip
internally — the LLM never sees raw OData syntax.
- Returns compact records by default (
limit=20,fieldsdefault ≈ 6
columns per entity); callers opt into more via fields, limit, withCount, offset.
- Maps
CalmApiError→ a typed MCP error the LLM can branch on
(NOT_FOUND, NETWORK, ODATA_ERROR with serviceCode, …).
See src/tools//*.ts for per-tool argument schemas.
Destructive tools (write operations)
Every Cloud ALM service that supports writes is now exposed:
- Features:
create,update,delete, plus external-reference
create / delete
- Tasks:
create,update,delete,create_comment - TestCases:
create,update,delete, plus nested
create_activity / create_action
- Documents:
create,update,delete - Hierarchy:
create_node,update_node,delete_node - Projects:
create - Logs:
post(inbound OpenTelemetry-style record ingestion)
The shared SAP sandbox at api.sap.com is read-friendly only — mutation integration tests are opt-in (see Live-tenant integration below).
Debug logging
CALM_LOG_LEVEL=debug # error | warn | info | debug
DEBUG_CALM_CONNECTORS=true # CalmConnection retries, 401 refresh, URLs
DEBUG_CALM_LIBS=true # resource-client internals
DEBUG_CALM_TESTS=true # test execution progress
Logging goes to stderr (stdout is reserved for the MCP protocol stream).
Development
git clone git@github.com:fr0ster/mcp-calm-server.git
cd mcp-calm-server
npm install
npm run test # 224 unit + integration tests
npm run build # emits dist/, includes executable bin
npm run lint:check # biome
Live-tenant integration
src/__tests__/integration/ runs against a real backend when env is present, and skips cleanly when it isn't (so npm test without secrets is always green). Five gates, drop them into .env:
| Gate | Env trigger | What it unlocks | |---|---|---| | describeSandbox | CALM_MODE=sandbox + CALM_API_KEY | The api.sap.com sandbox | | describeOAuth2 | CALM_MODE=oauth2 + CALM_BASE_URL + 3× UAA env | Live tenant (incl. endpoints absent from the sandbox catalog, e.g. Business Processes) | | describeWhenLive | either of the above | Read-side tests that work in either mode | | describeWithProject | live backend + CALM_PROJECT_ID | Project-scoped chains (features list→get, tasks list→get→comments, …) | | describeMutating | live + CALM_PROJECT_ID + CALM_ALLOW_MUTATIONS=1 | Write tests (every mutation finalises via try/finally { delete }) |
A quick smoke script lives at scripts/smoke-sandbox.mjs — spawns the stdio bin, lists tools, calls a handful of read endpoints, and exits 1 on any non-skip failure.
License
MIT — see [LICENSE](LICENSE).
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: fr0ster
- Source: fr0ster/mcp-calm-server
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.