Repository navigation
Releases: consetto/calmcp
Release list
0.9.2
Clearer errors about Cloud ALM scopes, stricter tool input, a CORS fix for the local endpoint, and current dependencies including zod 4.
Breaking for deployments
CALM_CORS_ORIGINSno longer accepts a wildcard.*, alone or in a list, and any entry that is notscheme://host[:port]stop calmcp at startup with a message naming the fix. List each browser-based client instead, e.g.CALM_CORS_ORIGINS=http://localhost:6274for the MCP Inspector. On the local unauthenticated endpoint a wildcard let any website call calmcp through the developer's browser and read Cloud ALM data (#23, code scanning alert #1). Deployments that leave the variable empty, the default, are not affected.- Unknown tool parameters are rejected. A parameter outside a tool's schema, such as
projectIdinstead ofproject_id, now fails the call and is named in the error (Unrecognized key: "projectId") instead of being silently dropped. Every tool schema again advertisesadditionalProperties: false(#22).
Errors
- A
FORBIDDENerror names the scope the Cloud ALM API service instance is missing, e.g.calm-api.tasks.read, or the write scope forcalm_create. For projects and analytics it also mentionscalm-api.projects.private.readandcalm-api.projects.protected.read(#3). - A
RATE_LIMITEDerror without aRetry-Afterstates Cloud ALM's limit of 500 requests per 5 seconds (#4). - The Tasks, Defects, Requirements and Features analytics providers note which
*.personal.readscope their personal-data field needs, and Tasks notes the scopes for private and protected projects (#3).
Documentation
- The README has a new "Cloud ALM API scopes" section: which scope each part of calmcp needs, and the private-project and personal-data scopes that are easy to leave out (#3).
Dependencies
- zod 3 → 4, MCP SDK 1.30, pino 10, dotenv 18, helmet and express-rate-limit updates (#12, #18, #20, #22).
- Development: TypeScript 7, Vitest 5, Biome 2.5 (#13, #15, #21).
calm_createkeeps accepting any8-4-4-4-12id: zod 4's stricter UUID check is not applied (#22).
Internal
- Every pull request gets a comment showing what changes in the tool surface: instructions, descriptions and schemas as a model sees them, with sizes (#5, #22).
- CI adds the e2e tests, a type-check of the tests,
mbt validateand anxs-security.jsoncheck, a Docker build with a/healthcheck, and dependency review. CodeQL scans every pull request (#6, #7). - Dependabot opens weekly updates: minor and patch grouped, majors one per package, Vitest packages together (#6, #11, #17). GitHub Actions are on v7 (#8).
0.9.1
Security hardening, machine-readable errors and a restructured tool registry. This is the first release whose Claude Desktop bundle is built and attached by CI.
Breaking for deployments
- The HTTP transport fails closed. With neither XSUAA nor
CALM_HTTP_API_KEYconfigured it refuses to start instead of serving an open/mcp. For local development,CALM_HTTP_ALLOW_UNAUTHENTICATED=trueserves an open endpoint bound to127.0.0.1that accepts only loopbackHostheaders. The switch is ignored on Cloud Foundry, and a bound but unreadable XSUAA service is a startup error. calm_createneeds theWriterscope on HTTP.xs-security.jsonadds theWriterscope, theEditorrole template and theCALMCP_Editorrole collection. Update the XSUAA service on redeploy and assignCALMCP_Editorto users who may create. Viewers and API-key callers no longer seecalm_create, even withCALM_WRITE_ENABLED=true.- CORS is off unless configured. Without
CALM_CORS_ORIGINSno CORS headers are sent.
Security
CALM_TENANTmust be a plain subdomain, so it cannot point the OAuth client secret at another host.- OData string literals are escaped, a caller's analytics filter is parenthesised before the server's controls are added, path-segment ids are validated, and URLs in
calm_createpayloads must be http(s). - Request bodies are capped at 1 MB. On Cloud Foundry the gorouter hop is trusted, so rate limiting is per client instead of shared.
- Upstream error bodies are stripped of HTML and length-capped before they reach the model.
Errors and resilience
- A failed call returns a JSON object with a stable
errorcode (NOT_FOUND,FORBIDDEN,RATE_LIMITED,TIMEOUT, ...),retryable,status,messageand ahint. The README lists the codes. - A read answered with 429 or 503 is retried once when Cloud ALM asks for a wait of at most 5 seconds. A create is never retried.
- A call the client cancels stops issuing requests.
Usability
- Tools carry MCP annotations (read-only, non-destructive).
- Unknown field names get a suggestion for the real name.
calm_getacceptsfieldsto project a single entity. - A full
calm_listpage names the next page, and an empty relation list says what was queried. - OData paging follows server-capped pages that announce
@odata.nextLinkinstead of stopping at the first short page. - Grouping by an array field (such as tags) counts each value on its own.
Internal
- The tool registry and constants are split into smaller modules, and duplicate code is removed.
- New tests keep recipes and tool descriptions in sync with the analytics catalog and keep tool schemas within a size budget and widely supported JSON Schema.
- Integration tests run only with live credentials.
CALM_TEST_PROJECT_IDadds the project-scoped checks. - The release workflow tests, builds and smoke-tests
calmcp-<version>.mcpband attaches it to the release.
v0.9.0
Adds opt-in create-only write access. calmcp stays read-only by default: nothing changes for existing deployments unless an operator turns the switch on.
Added
calm_createtool, registered only whenCALM_WRITE_ENABLED=true(or Write Access in the Claude Desktop extension settings). It creates a new document or a new cross-library entry (document,xlib_application,xlib_configuration,xlib_configuration_activity,xlib_development,xlib_interface). It never updates or deletes; calling it twice makes two entries.- Payload validation from the OpenAPI specs. Every field is checked before a request is sent. An unknown field is an error, not something silently dropped. Nested assignments (
toURLReferences,toProcessHierarchyAssignments,toTaskAssignments, ...) are created together with the entity. calm_resourcesdiscovery for write payloads. With write access on,calm_resources({ topic: "document" })returns the field list of eachcalm_createresource.CALM_WRITE_ENABLEDconfig, thecalm-api.doc.writeandcalm-api.lib.writeXSUAA scopes, and a Write Access toggle in the MCPB manifest.
Changed
- README documents the write-access opt-in, its scopes and the recommendation to run a separate app for writers rather than enabling it on a shared viewer deployment.
- Version jumps from 0.2.7 to 0.9.0 to mark the first release that is no longer strictly read-only.
Spec refresh of 2025-09-21
The SAP Business Accelerator Hub republished the Cloud ALM APIs on 21 September 2025. All 19 specs under YAML/ were re-downloaded and compared byte for byte; nine changed (Tasks 1.0.31, Projects 1.0.12, Test Cases 1.0.6, Test Plans 1.0.2, Cross-Library Applications 1.0.4, Configurations 1.0.2, Developments 1.0.4, Interfaces 1.0.3, and Landscape, which changed content while staying at 1.0.0). docs/API_VERSIONS.md carries the new table.
us20region is accepted byCALM_REGIONand the extension settings; every service spec now lists it.- Cross-library classification. Applications, developments and interfaces now carry priority, readiness, usage status, usage number, clean core level and upgrade impact codes; configurations carry priority and readiness. Seventeen new
calm_listcode-list resources (xlib_application_priorities,xlib_development_clean_core_levels,xlib_interface_upgrade_impacts, ...) resolve the codes to labels, andcalm_createaccepts the codes on all four library entries, validated against the spec enums (applicationSuccessorandpackageNameincluded). - Landscape access control lists.
calm_list resource:landscape_access_control_listsreads the new SCIM 2.0 groups endpoint (members and grant levels, filterable bydisplayNameorid). The SCIMResourcesenvelope is unwrapped like the ODatavalueone. Reading it needs thecalm-api.landscape.access-control.adminscope on the technical user; the SCIM PATCH stays out, since calmcp is create-only.
v0.2.0
Refreshes the SAP Cloud ALM OpenAPI specs (2 months stale: 8 of 16 outdated, 10 upstream APIs absent) and extends coverage with what they revealed. All services remain on API version v1.
Fixed
- 5 missing task status codes. The Tasks API accepts 28; calmcp advertised 23.
CIPUSREV,CIPTKREV,CIPRIOPEN,CIPRIINP,CIPRIDONEare now returned bycalm_resources.CIPUSREVoccurs on real projects, so it was unexplainable to clients before. - Sub-status code list.
sub_statuswas an accepted filter with its 19 valid values undocumented. $top/$skip/$orderbystay literal in REST query strings; the process services expect the option name rather than%24top.
Added
- Task filters
lastChangedDate,lastChangedTimestampandid, making incremental "what changed since X" queries possible. - Three services: Process Scopes (
CALM_PM1.1.0), Custom Processes (CALM_PMGE1.0.0) and Test Plans (CALM_TM_PLAN1.0.0, BETA). Process Scopes resolves thescopeId/scopeNamecarried on every task, which no tool could do before. - What the refreshed specs added: program teams and roles (Projects 1.0.11), URL references on all four cross-library services, configuration activities and assignments (Cross Library Configurations 1.0.1), and task solution-process assignments.
The spec provenance table in the README records the artifact version behind each service so the next drift check is a comparison rather than an investigation.
v0.1.1
First tagged release. Deployed to SAP BTP Cloud Foundry and verified against a live Cloud ALM tenant.
Added
Timebox filter and field projection for calm_list — the Tasks REST endpoint returns all 67 attributes of every record and offers no sprint filter, so a query like "open user stories in Sprint 5" meant fetching hundreds of KB and filtering client-side. That overflows smaller agent hosts such as Microsoft Copilot Studio.
fields— comma-separated projection of the returned records, on REST resources as well as OData ones.timebox_id/timebox_name— select the tasks of one sprint or phase. calmcp pages through the project so the filter is complete, and resolves a name such asSprint 5against the project's timeboxes.
Both reject unknown field and timebox names rather than silently ignoring them, since a dropped filter makes an LLM's answer look authoritative and be wrong. On a real project this takes the Sprint 5 query from 263 KB to 3.2 KB.
CI — npm ci, version check, lint, tests and build on Node 22 and 24, for pushes to main and every pull request.
Single-source versioning — the version lived in five hand-maintained places, so cf deploy kept reporting the same number for different builds. scripts/sync-version.mjs propagates package.json to the rest and is wired to the npm version lifecycle, with a --check mode enforced in CI.
Fixed
keep-existing: env on the calmcp-srv MTA module. Without it every redeploy reset the app environment to the descriptor and dropped CALM_HTTP_API_KEY, breaking API-key clients.