# Mcp Calm Server

> MCP server + reusable tool primitives for SAP Cloud ALM, built on @mcp-abap-adt/calm-client

- **Type:** MCP server
- **Install:** `agentstack add mcp-fr0ster-mcp-calm-server`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [fr0ster](https://agentstack.voostack.com/s/fr0ster)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [fr0ster](https://github.com/fr0ster)
- **Source:** https://github.com/fr0ster/mcp-calm-server

## Install

```sh
agentstack add mcp-fr0ster-mcp-calm-server
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## 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`](https://github.com/fr0ster/mcp-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

```bash
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)

```bash
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:

```bash
cp .env.example .env
```

**OAuth2 mode (real tenant)** — paste values from an XSUAA service key:

```env
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)**:

```env
CALM_MODE=sandbox
CALM_API_KEY=
# CALM_BASE_URL defaults to https://sandbox.api.sap.com/SAPCALM
```

### 2. Launch

```bash
# 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`](https://www.npmjs.com/package/@mcp-abap-adt/auth-broker)
CLI to convert a BTP service key into a token-bearing `.env`:

```bash
# 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):

```json
{
  "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.

```ts
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:

```ts
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`, `fields` default ≈ 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

```bash
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

```bash
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](https://github.com/fr0ster)
- **Source:** [fr0ster/mcp-calm-server](https://github.com/fr0ster/mcp-calm-server)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-fr0ster-mcp-calm-server
- Seller: https://agentstack.voostack.com/s/fr0ster
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
