@mcp-abap-adt/calm-server 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/LICENSE +22 -0
  3. package/README.md +213 -0
  4. package/dist/bin/stdio.d.ts +3 -0
  5. package/dist/bin/stdio.d.ts.map +1 -0
  6. package/dist/bin/stdio.js +15 -0
  7. package/dist/bin/stdio.js.map +1 -0
  8. package/dist/index.d.ts +14 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +34 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/registry/CalmToolRegistry.d.ts +27 -0
  13. package/dist/registry/CalmToolRegistry.d.ts.map +1 -0
  14. package/dist/registry/CalmToolRegistry.js +62 -0
  15. package/dist/registry/CalmToolRegistry.js.map +1 -0
  16. package/dist/registry/HandlerGroup.d.ts +14 -0
  17. package/dist/registry/HandlerGroup.d.ts.map +1 -0
  18. package/dist/registry/HandlerGroup.js +24 -0
  19. package/dist/registry/HandlerGroup.js.map +1 -0
  20. package/dist/registry/index.d.ts +5 -0
  21. package/dist/registry/index.d.ts.map +1 -0
  22. package/dist/registry/index.js +10 -0
  23. package/dist/registry/index.js.map +1 -0
  24. package/dist/registry/jsonSchemaToZod.d.ts +13 -0
  25. package/dist/registry/jsonSchemaToZod.d.ts.map +1 -0
  26. package/dist/registry/jsonSchemaToZod.js +57 -0
  27. package/dist/registry/jsonSchemaToZod.js.map +1 -0
  28. package/dist/registry/types.d.ts +59 -0
  29. package/dist/registry/types.d.ts.map +1 -0
  30. package/dist/registry/types.js +3 -0
  31. package/dist/registry/types.js.map +1 -0
  32. package/dist/server/BaseCalmMcpServer.d.ts +37 -0
  33. package/dist/server/BaseCalmMcpServer.d.ts.map +1 -0
  34. package/dist/server/BaseCalmMcpServer.js +44 -0
  35. package/dist/server/BaseCalmMcpServer.js.map +1 -0
  36. package/dist/server/buildClient.d.ts +10 -0
  37. package/dist/server/buildClient.d.ts.map +1 -0
  38. package/dist/server/buildClient.js +74 -0
  39. package/dist/server/buildClient.js.map +1 -0
  40. package/dist/server/config.d.ts +18 -0
  41. package/dist/server/config.d.ts.map +1 -0
  42. package/dist/server/config.js +58 -0
  43. package/dist/server/config.js.map +1 -0
  44. package/dist/server/index.d.ts +5 -0
  45. package/dist/server/index.d.ts.map +1 -0
  46. package/dist/server/index.js +13 -0
  47. package/dist/server/index.js.map +1 -0
  48. package/dist/server/runStdio.d.ts +12 -0
  49. package/dist/server/runStdio.d.ts.map +1 -0
  50. package/dist/server/runStdio.js +48 -0
  51. package/dist/server/runStdio.js.map +1 -0
  52. package/dist/tools/analytics/index.d.ts +8 -0
  53. package/dist/tools/analytics/index.d.ts.map +1 -0
  54. package/dist/tools/analytics/index.js +16 -0
  55. package/dist/tools/analytics/index.js.map +1 -0
  56. package/dist/tools/analytics/listAnalyticsProviders.d.ts +5 -0
  57. package/dist/tools/analytics/listAnalyticsProviders.d.ts.map +1 -0
  58. package/dist/tools/analytics/listAnalyticsProviders.js +16 -0
  59. package/dist/tools/analytics/listAnalyticsProviders.js.map +1 -0
  60. package/dist/tools/analytics/queryAnalytics.d.ts +15 -0
  61. package/dist/tools/analytics/queryAnalytics.d.ts.map +1 -0
  62. package/dist/tools/analytics/queryAnalytics.js +61 -0
  63. package/dist/tools/analytics/queryAnalytics.js.map +1 -0
  64. package/dist/tools/documents/getDocument.d.ts +7 -0
  65. package/dist/tools/documents/getDocument.d.ts.map +1 -0
  66. package/dist/tools/documents/getDocument.js +34 -0
  67. package/dist/tools/documents/getDocument.js.map +1 -0
  68. package/dist/tools/documents/index.d.ts +9 -0
  69. package/dist/tools/documents/index.d.ts.map +1 -0
  70. package/dist/tools/documents/index.js +16 -0
  71. package/dist/tools/documents/index.js.map +1 -0
  72. package/dist/tools/documents/listDocuments.d.ts +16 -0
  73. package/dist/tools/documents/listDocuments.d.ts.map +1 -0
  74. package/dist/tools/documents/listDocuments.js +85 -0
  75. package/dist/tools/documents/listDocuments.js.map +1 -0
  76. package/dist/tools/features/createFeature.d.ts +5 -0
  77. package/dist/tools/features/createFeature.d.ts.map +1 -0
  78. package/dist/tools/features/createFeature.js +55 -0
  79. package/dist/tools/features/createFeature.js.map +1 -0
  80. package/dist/tools/features/deleteFeature.d.ts +10 -0
  81. package/dist/tools/features/deleteFeature.d.ts.map +1 -0
  82. package/dist/tools/features/deleteFeature.js +35 -0
  83. package/dist/tools/features/deleteFeature.js.map +1 -0
  84. package/dist/tools/features/getFeature.d.ts +7 -0
  85. package/dist/tools/features/getFeature.d.ts.map +1 -0
  86. package/dist/tools/features/getFeature.js +37 -0
  87. package/dist/tools/features/getFeature.js.map +1 -0
  88. package/dist/tools/features/getFeatureByDisplayId.d.ts +7 -0
  89. package/dist/tools/features/getFeatureByDisplayId.d.ts.map +1 -0
  90. package/dist/tools/features/getFeatureByDisplayId.js +37 -0
  91. package/dist/tools/features/getFeatureByDisplayId.js.map +1 -0
  92. package/dist/tools/features/index.d.ts +21 -0
  93. package/dist/tools/features/index.d.ts.map +1 -0
  94. package/dist/tools/features/index.js +40 -0
  95. package/dist/tools/features/index.js.map +1 -0
  96. package/dist/tools/features/listFeaturePriorities.d.ts +7 -0
  97. package/dist/tools/features/listFeaturePriorities.d.ts.map +1 -0
  98. package/dist/tools/features/listFeaturePriorities.js +23 -0
  99. package/dist/tools/features/listFeaturePriorities.js.map +1 -0
  100. package/dist/tools/features/listFeatureStatuses.d.ts +7 -0
  101. package/dist/tools/features/listFeatureStatuses.d.ts.map +1 -0
  102. package/dist/tools/features/listFeatureStatuses.js +23 -0
  103. package/dist/tools/features/listFeatureStatuses.js.map +1 -0
  104. package/dist/tools/features/listFeatures.d.ts +19 -0
  105. package/dist/tools/features/listFeatures.d.ts.map +1 -0
  106. package/dist/tools/features/listFeatures.js +123 -0
  107. package/dist/tools/features/listFeatures.js.map +1 -0
  108. package/dist/tools/features/updateFeature.d.ts +7 -0
  109. package/dist/tools/features/updateFeature.d.ts.map +1 -0
  110. package/dist/tools/features/updateFeature.js +44 -0
  111. package/dist/tools/features/updateFeature.js.map +1 -0
  112. package/dist/tools/hierarchy/getHierarchyWithChildren.d.ts +10 -0
  113. package/dist/tools/hierarchy/getHierarchyWithChildren.d.ts.map +1 -0
  114. package/dist/tools/hierarchy/getHierarchyWithChildren.js +45 -0
  115. package/dist/tools/hierarchy/getHierarchyWithChildren.js.map +1 -0
  116. package/dist/tools/hierarchy/index.d.ts +9 -0
  117. package/dist/tools/hierarchy/index.d.ts.map +1 -0
  118. package/dist/tools/hierarchy/index.js +16 -0
  119. package/dist/tools/hierarchy/index.js.map +1 -0
  120. package/dist/tools/hierarchy/listHierarchy.d.ts +16 -0
  121. package/dist/tools/hierarchy/listHierarchy.d.ts.map +1 -0
  122. package/dist/tools/hierarchy/listHierarchy.js +74 -0
  123. package/dist/tools/hierarchy/listHierarchy.js.map +1 -0
  124. package/dist/tools/index.d.ts +16 -0
  125. package/dist/tools/index.d.ts.map +1 -0
  126. package/dist/tools/index.js +45 -0
  127. package/dist/tools/index.js.map +1 -0
  128. package/dist/tools/logs/getLogs.d.ts +15 -0
  129. package/dist/tools/logs/getLogs.d.ts.map +1 -0
  130. package/dist/tools/logs/getLogs.js +55 -0
  131. package/dist/tools/logs/getLogs.js.map +1 -0
  132. package/dist/tools/logs/index.d.ts +7 -0
  133. package/dist/tools/logs/index.d.ts.map +1 -0
  134. package/dist/tools/logs/index.js +10 -0
  135. package/dist/tools/logs/index.js.map +1 -0
  136. package/dist/tools/processMonitoring/index.d.ts +7 -0
  137. package/dist/tools/processMonitoring/index.d.ts.map +1 -0
  138. package/dist/tools/processMonitoring/index.js +12 -0
  139. package/dist/tools/processMonitoring/index.js.map +1 -0
  140. package/dist/tools/processMonitoring/listBusinessProcesses.d.ts +10 -0
  141. package/dist/tools/processMonitoring/listBusinessProcesses.d.ts.map +1 -0
  142. package/dist/tools/processMonitoring/listBusinessProcesses.js +36 -0
  143. package/dist/tools/processMonitoring/listBusinessProcesses.js.map +1 -0
  144. package/dist/tools/projects/getProject.d.ts +7 -0
  145. package/dist/tools/projects/getProject.d.ts.map +1 -0
  146. package/dist/tools/projects/getProject.js +32 -0
  147. package/dist/tools/projects/getProject.js.map +1 -0
  148. package/dist/tools/projects/index.d.ts +9 -0
  149. package/dist/tools/projects/index.d.ts.map +1 -0
  150. package/dist/tools/projects/index.js +16 -0
  151. package/dist/tools/projects/index.js.map +1 -0
  152. package/dist/tools/projects/listProjects.d.ts +16 -0
  153. package/dist/tools/projects/listProjects.d.ts.map +1 -0
  154. package/dist/tools/projects/listProjects.js +69 -0
  155. package/dist/tools/projects/listProjects.js.map +1 -0
  156. package/dist/tools/tasks/getTask.d.ts +7 -0
  157. package/dist/tools/tasks/getTask.d.ts.map +1 -0
  158. package/dist/tools/tasks/getTask.js +34 -0
  159. package/dist/tools/tasks/getTask.js.map +1 -0
  160. package/dist/tools/tasks/index.d.ts +11 -0
  161. package/dist/tools/tasks/index.d.ts.map +1 -0
  162. package/dist/tools/tasks/index.js +20 -0
  163. package/dist/tools/tasks/index.js.map +1 -0
  164. package/dist/tools/tasks/listTaskComments.d.ts +11 -0
  165. package/dist/tools/tasks/listTaskComments.d.ts.map +1 -0
  166. package/dist/tools/tasks/listTaskComments.js +46 -0
  167. package/dist/tools/tasks/listTaskComments.js.map +1 -0
  168. package/dist/tools/tasks/listTasks.d.ts +17 -0
  169. package/dist/tools/tasks/listTasks.d.ts.map +1 -0
  170. package/dist/tools/tasks/listTasks.js +89 -0
  171. package/dist/tools/tasks/listTasks.js.map +1 -0
  172. package/dist/tools/testCases/getTestCase.d.ts +7 -0
  173. package/dist/tools/testCases/getTestCase.d.ts.map +1 -0
  174. package/dist/tools/testCases/getTestCase.js +34 -0
  175. package/dist/tools/testCases/getTestCase.js.map +1 -0
  176. package/dist/tools/testCases/index.d.ts +9 -0
  177. package/dist/tools/testCases/index.d.ts.map +1 -0
  178. package/dist/tools/testCases/index.js +16 -0
  179. package/dist/tools/testCases/index.js.map +1 -0
  180. package/dist/tools/testCases/listTestCases.d.ts +16 -0
  181. package/dist/tools/testCases/listTestCases.d.ts.map +1 -0
  182. package/dist/tools/testCases/listTestCases.js +69 -0
  183. package/dist/tools/testCases/listTestCases.js.map +1 -0
  184. package/dist/utils/errorMapping.d.ts +28 -0
  185. package/dist/utils/errorMapping.d.ts.map +1 -0
  186. package/dist/utils/errorMapping.js +88 -0
  187. package/dist/utils/errorMapping.js.map +1 -0
  188. package/dist/utils/index.d.ts +4 -0
  189. package/dist/utils/index.d.ts.map +1 -0
  190. package/dist/utils/index.js +15 -0
  191. package/dist/utils/index.js.map +1 -0
  192. package/dist/utils/odataFilter.d.ts +15 -0
  193. package/dist/utils/odataFilter.d.ts.map +1 -0
  194. package/dist/utils/odataFilter.js +24 -0
  195. package/dist/utils/odataFilter.js.map +1 -0
  196. package/dist/utils/tokenEconomy.d.ts +36 -0
  197. package/dist/utils/tokenEconomy.d.ts.map +1 -0
  198. package/dist/utils/tokenEconomy.js +37 -0
  199. package/dist/utils/tokenEconomy.js.map +1 -0
  200. package/package.json +86 -0
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listTestCasesTool = void 0;
4
+ const calm_client_1 = require("@mcp-abap-adt/calm-client");
5
+ const utils_1 = require("../../utils");
6
+ const DEFAULT_FIELDS = [
7
+ 'uuid',
8
+ 'title',
9
+ 'statusCode',
10
+ 'projectId',
11
+ 'modifiedAt',
12
+ ];
13
+ const ALLOWED_FIELDS = [
14
+ 'uuid',
15
+ 'title',
16
+ 'description',
17
+ 'statusCode',
18
+ 'projectId',
19
+ 'modifiedAt',
20
+ 'createdAt',
21
+ ];
22
+ const definition = {
23
+ name: 'calm_test_cases_list',
24
+ description: 'List manual test cases, optionally scoped to a project or status. Returns compact records.',
25
+ inputSchema: {
26
+ type: 'object',
27
+ properties: {
28
+ projectId: { type: 'string' },
29
+ status: { type: 'string', description: 'Filter by statusCode.' },
30
+ fields: {
31
+ type: 'array',
32
+ items: { type: 'string', enum: [...ALLOWED_FIELDS] },
33
+ },
34
+ limit: { type: 'integer', minimum: 1, maximum: utils_1.MAX_LIST_LIMIT },
35
+ offset: { type: 'integer', minimum: 0 },
36
+ withCount: { type: 'boolean' },
37
+ },
38
+ },
39
+ };
40
+ const handler = async (ctx, args) => {
41
+ const limit = (0, utils_1.clampListLimit)(args?.limit);
42
+ const offset = args?.offset && args.offset > 0 ? Math.floor(args.offset) : 0;
43
+ const filter = (0, utils_1.joinAndFilters)(args?.projectId
44
+ ? `projectId eq '${(0, utils_1.escapeODataString)(args.projectId)}'`
45
+ : undefined, args?.status
46
+ ? `statusCode eq '${(0, utils_1.escapeODataString)(args.status)}'`
47
+ : undefined);
48
+ const fields = args?.fields && args.fields.length > 0 ? args.fields : DEFAULT_FIELDS;
49
+ let query = calm_client_1.ODataQuery.new()
50
+ .select([...fields])
51
+ .top(limit)
52
+ .skip(offset);
53
+ if (filter)
54
+ query = query.filter(filter);
55
+ if (args?.withCount)
56
+ query = query.count();
57
+ try {
58
+ const collection = await ctx.calm.getTestCases().list(query);
59
+ return (0, utils_1.toListResponse)(collection, { limit, offset });
60
+ }
61
+ catch (err) {
62
+ throw (0, utils_1.mapCalmErrorForTool)(err);
63
+ }
64
+ };
65
+ exports.listTestCasesTool = {
66
+ toolDefinition: definition,
67
+ handler,
68
+ };
69
+ //# sourceMappingURL=listTestCases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listTestCases.js","sourceRoot":"","sources":["../../../src/tools/testCases/listTestCases.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * MCP-facing error shape. Thrown from tool handlers; caught by the
3
+ * registry wrapper and surfaced as an MCP tool-call error to the LLM.
4
+ *
5
+ * The `code` stays machine-readable so the LLM can branch (retry vs
6
+ * give up vs ask user). The `message` is user-facing — stripped of
7
+ * stack traces and internal detail.
8
+ */
9
+ export declare class CalmToolError extends Error {
10
+ readonly code: string;
11
+ readonly status?: number;
12
+ readonly serviceCode?: string;
13
+ readonly cause?: unknown;
14
+ constructor(opts: {
15
+ code: string;
16
+ message: string;
17
+ status?: number;
18
+ serviceCode?: string;
19
+ cause?: unknown;
20
+ });
21
+ }
22
+ /**
23
+ * Translate any thrown value from a CalmClient call into a
24
+ * CalmToolError the LLM can reason about. CalmApiError codes become
25
+ * LLM-friendly messages; other errors fall through as `UNKNOWN`.
26
+ */
27
+ export declare function mapCalmErrorForTool(err: unknown): CalmToolError;
28
+ //# sourceMappingURL=errorMapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorMapping.d.ts","sourceRoot":"","sources":["../../src/utils/errorMapping.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEb,IAAI,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB;CASF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,CAoD/D"}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CalmToolError = void 0;
4
+ exports.mapCalmErrorForTool = mapCalmErrorForTool;
5
+ const calm_client_1 = require("@mcp-abap-adt/calm-client");
6
+ /**
7
+ * MCP-facing error shape. Thrown from tool handlers; caught by the
8
+ * registry wrapper and surfaced as an MCP tool-call error to the LLM.
9
+ *
10
+ * The `code` stays machine-readable so the LLM can branch (retry vs
11
+ * give up vs ask user). The `message` is user-facing — stripped of
12
+ * stack traces and internal detail.
13
+ */
14
+ class CalmToolError extends Error {
15
+ code;
16
+ status;
17
+ serviceCode;
18
+ cause;
19
+ constructor(opts) {
20
+ super(opts.message);
21
+ this.name = 'CalmToolError';
22
+ this.code = opts.code;
23
+ this.status = opts.status;
24
+ this.serviceCode = opts.serviceCode;
25
+ if (opts.cause !== undefined)
26
+ this.cause = opts.cause;
27
+ Object.setPrototypeOf(this, CalmToolError.prototype);
28
+ }
29
+ }
30
+ exports.CalmToolError = CalmToolError;
31
+ /**
32
+ * Translate any thrown value from a CalmClient call into a
33
+ * CalmToolError the LLM can reason about. CalmApiError codes become
34
+ * LLM-friendly messages; other errors fall through as `UNKNOWN`.
35
+ */
36
+ function mapCalmErrorForTool(err) {
37
+ if (err instanceof calm_client_1.CalmApiError) {
38
+ switch (err.code) {
39
+ case 'NOT_FOUND':
40
+ return new CalmToolError({
41
+ code: 'NOT_FOUND',
42
+ message: err.message,
43
+ status: 404,
44
+ cause: err,
45
+ });
46
+ case 'ODATA_ERROR':
47
+ return new CalmToolError({
48
+ code: 'ODATA_ERROR',
49
+ message: `Cloud ALM rejected the request: ${err.message}`,
50
+ status: err.status,
51
+ serviceCode: err.serviceCode,
52
+ cause: err,
53
+ });
54
+ case 'HTTP_ERROR':
55
+ return new CalmToolError({
56
+ code: 'HTTP_ERROR',
57
+ message: `Cloud ALM returned HTTP ${err.status ?? '?'}: ${err.message.slice(0, 160)}`,
58
+ status: err.status,
59
+ cause: err,
60
+ });
61
+ case 'NETWORK':
62
+ return new CalmToolError({
63
+ code: 'NETWORK',
64
+ message: 'Cloud ALM is unreachable — check connectivity and retry.',
65
+ cause: err,
66
+ });
67
+ case 'JSON_PARSE':
68
+ return new CalmToolError({
69
+ code: 'JSON_PARSE',
70
+ message: 'Cloud ALM returned malformed JSON — likely a tenant configuration issue.',
71
+ cause: err,
72
+ });
73
+ default:
74
+ return new CalmToolError({
75
+ code: 'UNKNOWN',
76
+ message: err.message,
77
+ status: err.status,
78
+ cause: err,
79
+ });
80
+ }
81
+ }
82
+ return new CalmToolError({
83
+ code: 'UNKNOWN',
84
+ message: err instanceof Error ? err.message : String(err),
85
+ cause: err,
86
+ });
87
+ }
88
+ //# sourceMappingURL=errorMapping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorMapping.js","sourceRoot":"","sources":["../../src/utils/errorMapping.ts"],"names":[],"mappings":";;;AAsCA,kDAoDC;AA1FD,2DAAyD;AAEzD;;;;;;;GAOG;AACH,MAAa,aAAc,SAAQ,KAAK;IAC7B,IAAI,CAAS;IACb,MAAM,CAAU;IAChB,WAAW,CAAU;IACrB,KAAK,CAAW;IAEzB,YAAY,IAMX;QACC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACtD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACvD,CAAC;CACF;AArBD,sCAqBC;AAED;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,GAAY;IAC9C,IAAI,GAAG,YAAY,0BAAY,EAAE,CAAC;QAChC,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,WAAW;gBACd,OAAO,IAAI,aAAa,CAAC;oBACvB,IAAI,EAAE,WAAW;oBACjB,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,MAAM,EAAE,GAAG;oBACX,KAAK,EAAE,GAAG;iBACX,CAAC,CAAC;YACL,KAAK,aAAa;gBAChB,OAAO,IAAI,aAAa,CAAC;oBACvB,IAAI,EAAE,aAAa;oBACnB,OAAO,EAAE,mCAAmC,GAAG,CAAC,OAAO,EAAE;oBACzD,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,WAAW,EAAE,GAAG,CAAC,WAAW;oBAC5B,KAAK,EAAE,GAAG;iBACX,CAAC,CAAC;YACL,KAAK,YAAY;gBACf,OAAO,IAAI,aAAa,CAAC;oBACvB,IAAI,EAAE,YAAY;oBAClB,OAAO,EAAE,2BAA2B,GAAG,CAAC,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;oBACrF,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,KAAK,EAAE,GAAG;iBACX,CAAC,CAAC;YACL,KAAK,SAAS;gBACZ,OAAO,IAAI,aAAa,CAAC;oBACvB,IAAI,EAAE,SAAS;oBACf,OAAO,EAAE,0DAA0D;oBACnE,KAAK,EAAE,GAAG;iBACX,CAAC,CAAC;YACL,KAAK,YAAY;gBACf,OAAO,IAAI,aAAa,CAAC;oBACvB,IAAI,EAAE,YAAY;oBAClB,OAAO,EACL,0EAA0E;oBAC5E,KAAK,EAAE,GAAG;iBACX,CAAC,CAAC;YACL;gBACE,OAAO,IAAI,aAAa,CAAC;oBACvB,IAAI,EAAE,SAAS;oBACf,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,KAAK,EAAE,GAAG;iBACX,CAAC,CAAC;QACP,CAAC;IACH,CAAC;IACD,OAAO,IAAI,aAAa,CAAC;QACvB,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QACzD,KAAK,EAAE,GAAG;KACX,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { CalmToolError, mapCalmErrorForTool, } from './errorMapping';
2
+ export { escapeODataString, joinAndFilters } from './odataFilter';
3
+ export { clampListLimit, DEFAULT_LIST_LIMIT, type IListResponse, MAX_LIST_LIMIT, toListResponse, } from './tokenEconomy';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,KAAK,aAAa,EAClB,cAAc,EACd,cAAc,GACf,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toListResponse = exports.MAX_LIST_LIMIT = exports.DEFAULT_LIST_LIMIT = exports.clampListLimit = exports.joinAndFilters = exports.escapeODataString = exports.mapCalmErrorForTool = exports.CalmToolError = void 0;
4
+ var errorMapping_1 = require("./errorMapping");
5
+ Object.defineProperty(exports, "CalmToolError", { enumerable: true, get: function () { return errorMapping_1.CalmToolError; } });
6
+ Object.defineProperty(exports, "mapCalmErrorForTool", { enumerable: true, get: function () { return errorMapping_1.mapCalmErrorForTool; } });
7
+ var odataFilter_1 = require("./odataFilter");
8
+ Object.defineProperty(exports, "escapeODataString", { enumerable: true, get: function () { return odataFilter_1.escapeODataString; } });
9
+ Object.defineProperty(exports, "joinAndFilters", { enumerable: true, get: function () { return odataFilter_1.joinAndFilters; } });
10
+ var tokenEconomy_1 = require("./tokenEconomy");
11
+ Object.defineProperty(exports, "clampListLimit", { enumerable: true, get: function () { return tokenEconomy_1.clampListLimit; } });
12
+ Object.defineProperty(exports, "DEFAULT_LIST_LIMIT", { enumerable: true, get: function () { return tokenEconomy_1.DEFAULT_LIST_LIMIT; } });
13
+ Object.defineProperty(exports, "MAX_LIST_LIMIT", { enumerable: true, get: function () { return tokenEconomy_1.MAX_LIST_LIMIT; } });
14
+ Object.defineProperty(exports, "toListResponse", { enumerable: true, get: function () { return tokenEconomy_1.toListResponse; } });
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;AAAA,+CAGwB;AAFtB,6GAAA,aAAa,OAAA;AACb,mHAAA,mBAAmB,OAAA;AAErB,6CAAkE;AAAzD,gHAAA,iBAAiB,OAAA;AAAE,6GAAA,cAAc,OAAA;AAC1C,+CAMwB;AALtB,8GAAA,cAAc,OAAA;AACd,kHAAA,kBAAkB,OAAA;AAElB,8GAAA,cAAc,OAAA;AACd,8GAAA,cAAc,OAAA"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Small helpers for building OData filter expressions safely from
3
+ * user-provided strings.
4
+ */
5
+ /**
6
+ * Escape a string value for use inside OData single-quoted literals.
7
+ * `don't` → `don''t`.
8
+ */
9
+ export declare function escapeODataString(value: string): string;
10
+ /**
11
+ * Join multiple filter predicates with `and`. Undefined / empty
12
+ * entries are skipped; if nothing is left, returns `undefined`.
13
+ */
14
+ export declare function joinAndFilters(...parts: (string | undefined)[]): string | undefined;
15
+ //# sourceMappingURL=odataFilter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"odataFilter.d.ts","sourceRoot":"","sources":["../../src/utils/odataFilter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,GAAG,KAAK,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GAC/B,MAAM,GAAG,SAAS,CAGpB"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /**
3
+ * Small helpers for building OData filter expressions safely from
4
+ * user-provided strings.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.escapeODataString = escapeODataString;
8
+ exports.joinAndFilters = joinAndFilters;
9
+ /**
10
+ * Escape a string value for use inside OData single-quoted literals.
11
+ * `don't` → `don''t`.
12
+ */
13
+ function escapeODataString(value) {
14
+ return value.replace(/'/g, "''");
15
+ }
16
+ /**
17
+ * Join multiple filter predicates with `and`. Undefined / empty
18
+ * entries are skipped; if nothing is left, returns `undefined`.
19
+ */
20
+ function joinAndFilters(...parts) {
21
+ const kept = parts.filter((p) => !!p && p.trim().length > 0);
22
+ return kept.length === 0 ? undefined : kept.join(' and ');
23
+ }
24
+ //# sourceMappingURL=odataFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"odataFilter.js","sourceRoot":"","sources":["../../src/utils/odataFilter.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAMH,8CAEC;AAMD,wCAKC;AAjBD;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,KAAa;IAC7C,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAC5B,GAAG,KAA6B;IAEhC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC1E,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Token-economy helpers. LLM context is expensive — every list tool
3
+ * should cap result size, trim unrequested fields, and expose the
4
+ * count so the LLM can decide whether to paginate.
5
+ */
6
+ export declare const DEFAULT_LIST_LIMIT = 20;
7
+ export declare const MAX_LIST_LIMIT = 200;
8
+ /**
9
+ * Clamp a user-provided limit to sane bounds for LLM list-tool
10
+ * responses. `undefined` → `DEFAULT_LIST_LIMIT`; non-positive → 1;
11
+ * over `MAX_LIST_LIMIT` → capped.
12
+ */
13
+ export declare function clampListLimit(limit: number | undefined): number;
14
+ /**
15
+ * Shape of a compact list-tool response — items + count hint. Keeping
16
+ * OData metadata (`@odata.context`, nextLink) out of the LLM's view.
17
+ */
18
+ export interface IListResponse<T> {
19
+ items: T[];
20
+ /** Total count if the caller requested `$count=true`; otherwise undefined. */
21
+ count?: number;
22
+ /** Index of the next page (for follow-up calls). */
23
+ nextOffset?: number;
24
+ }
25
+ /**
26
+ * Normalize an OData-style collection (`{ value, @odata.count }`) into
27
+ * the flat shape we return to the LLM.
28
+ */
29
+ export declare function toListResponse<T>(collection: {
30
+ value: T[];
31
+ '@odata.count'?: number;
32
+ }, opts: {
33
+ limit: number;
34
+ offset: number;
35
+ }): IListResponse<T>;
36
+ //# sourceMappingURL=tokenEconomy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenEconomy.d.ts","sourceRoot":"","sources":["../../src/utils/tokenEconomy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKhE;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,UAAU,EAAE;IACV,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,EACD,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACtC,aAAa,CAAC,CAAC,CAAC,CAMlB"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ /**
3
+ * Token-economy helpers. LLM context is expensive — every list tool
4
+ * should cap result size, trim unrequested fields, and expose the
5
+ * count so the LLM can decide whether to paginate.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.MAX_LIST_LIMIT = exports.DEFAULT_LIST_LIMIT = void 0;
9
+ exports.clampListLimit = clampListLimit;
10
+ exports.toListResponse = toListResponse;
11
+ exports.DEFAULT_LIST_LIMIT = 20;
12
+ exports.MAX_LIST_LIMIT = 200;
13
+ /**
14
+ * Clamp a user-provided limit to sane bounds for LLM list-tool
15
+ * responses. `undefined` → `DEFAULT_LIST_LIMIT`; non-positive → 1;
16
+ * over `MAX_LIST_LIMIT` → capped.
17
+ */
18
+ function clampListLimit(limit) {
19
+ if (limit === undefined)
20
+ return exports.DEFAULT_LIST_LIMIT;
21
+ if (!Number.isFinite(limit) || limit < 1)
22
+ return 1;
23
+ if (limit > exports.MAX_LIST_LIMIT)
24
+ return exports.MAX_LIST_LIMIT;
25
+ return Math.floor(limit);
26
+ }
27
+ /**
28
+ * Normalize an OData-style collection (`{ value, @odata.count }`) into
29
+ * the flat shape we return to the LLM.
30
+ */
31
+ function toListResponse(collection, opts) {
32
+ const items = collection.value ?? [];
33
+ const count = collection['@odata.count'];
34
+ const nextOffset = items.length === opts.limit ? opts.offset + opts.limit : undefined;
35
+ return { items, count, nextOffset };
36
+ }
37
+ //# sourceMappingURL=tokenEconomy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenEconomy.js","sourceRoot":"","sources":["../../src/utils/tokenEconomy.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAUH,wCAKC;AAkBD,wCAYC;AA3CY,QAAA,kBAAkB,GAAG,EAAE,CAAC;AACxB,QAAA,cAAc,GAAG,GAAG,CAAC;AAElC;;;;GAIG;AACH,SAAgB,cAAc,CAAC,KAAyB;IACtD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,0BAAkB,CAAC;IACnD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACnD,IAAI,KAAK,GAAG,sBAAc;QAAE,OAAO,sBAAc,CAAC;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAcD;;;GAGG;AACH,SAAgB,cAAc,CAC5B,UAGC,EACD,IAAuC;IAEvC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,IAAI,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IACzC,MAAM,UAAU,GACd,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IACrE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;AACtC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@mcp-abap-adt/calm-server",
3
+ "version": "0.1.0",
4
+ "description": "MCP server + reusable tool primitives for SAP Cloud ALM, backed by @mcp-abap-adt/calm-client.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "calm-mcp": "dist/bin/stdio.js"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./tools": {
16
+ "types": "./dist/tools/index.d.ts",
17
+ "default": "./dist/tools/index.js"
18
+ },
19
+ "./registry": {
20
+ "types": "./dist/registry/index.d.ts",
21
+ "default": "./dist/registry/index.js"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "README.md",
27
+ "CHANGELOG.md",
28
+ "LICENSE"
29
+ ],
30
+ "scripts": {
31
+ "clean": "node -e \"const fs=require('fs');['dist','tsconfig.tsbuildinfo'].forEach(p=>{try{fs.rmSync(p,{recursive:true,force:true})}catch{}})\"",
32
+ "lint": "npx biome check --write src",
33
+ "lint:check": "npx biome check src",
34
+ "format": "npx biome format --write src",
35
+ "build": "npm run --silent clean && npx biome check src --diagnostic-level=error && npx tsc -p tsconfig.json",
36
+ "build:fast": "npx tsc -p tsconfig.json",
37
+ "test": "npx jest --runInBand",
38
+ "test:check": "npx tsc --noEmit --project tsconfig.test.integration.json",
39
+ "prepublishOnly": "npm run build"
40
+ },
41
+ "engines": {
42
+ "node": ">=18.0.0"
43
+ },
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/fr0ster/mcp-calm-server.git"
47
+ },
48
+ "homepage": "https://github.com/fr0ster/mcp-calm-server#readme",
49
+ "bugs": {
50
+ "url": "https://github.com/fr0ster/mcp-calm-server/issues"
51
+ },
52
+ "author": "Oleksii Kyslytsia <oleksij.kyslytsja@gmail.com>",
53
+ "license": "MIT",
54
+ "publishConfig": {
55
+ "access": "public"
56
+ },
57
+ "keywords": [
58
+ "sap",
59
+ "cloud-alm",
60
+ "calm",
61
+ "mcp",
62
+ "mcp-server",
63
+ "tools"
64
+ ],
65
+ "peerDependencies": {
66
+ "@mcp-abap-adt/calm-client": "^0.1.0",
67
+ "@mcp-abap-adt/interfaces": "^7.1.0",
68
+ "@modelcontextprotocol/sdk": "^1.0.0"
69
+ },
70
+ "devDependencies": {
71
+ "@biomejs/biome": "^2.4.4",
72
+ "@mcp-abap-adt/auth-broker": "^1.0.5",
73
+ "@mcp-abap-adt/auth-providers": "^1.0.5",
74
+ "@mcp-abap-adt/auth-stores": "^1.0.4",
75
+ "@mcp-abap-adt/calm-client": "^0.1.0",
76
+ "@mcp-abap-adt/interfaces": "^7.1.0",
77
+ "@mcp-abap-adt/logger": "^0.1.4",
78
+ "@modelcontextprotocol/sdk": "^1.0.0",
79
+ "@types/jest": "^30.0.0",
80
+ "@types/node": "^24.2.1",
81
+ "dotenv": "^17.3.1",
82
+ "jest": "^30.0.5",
83
+ "ts-jest": "^29.4.1",
84
+ "typescript": "^5.9.2"
85
+ }
86
+ }