@lerianstudio/matcher-mcp 1.0.0-beta.5

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 (220) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +281 -0
  3. package/dist/auth/request-token.js +117 -0
  4. package/dist/auth/request-token.js.map +1 -0
  5. package/dist/config.js +95 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/matcher/client.js +168 -0
  8. package/dist/matcher/client.js.map +1 -0
  9. package/dist/observability/otel.js +223 -0
  10. package/dist/observability/otel.js.map +1 -0
  11. package/dist/server.js +245 -0
  12. package/dist/server.js.map +1 -0
  13. package/dist/spec/curated-operations.js +145 -0
  14. package/dist/spec/curated-operations.js.map +1 -0
  15. package/dist/spec/index.js +155 -0
  16. package/dist/spec/index.js.map +1 -0
  17. package/dist/spec/load.js +76 -0
  18. package/dist/spec/load.js.map +1 -0
  19. package/dist/spec/openapi.yaml +15217 -0
  20. package/dist/tools/context/create.js +100 -0
  21. package/dist/tools/context/create.js.map +1 -0
  22. package/dist/tools/context/get.js +31 -0
  23. package/dist/tools/context/get.js.map +1 -0
  24. package/dist/tools/context/index.js +21 -0
  25. package/dist/tools/context/index.js.map +1 -0
  26. package/dist/tools/context/list.js +78 -0
  27. package/dist/tools/context/list.js.map +1 -0
  28. package/dist/tools/context/shared.js +61 -0
  29. package/dist/tools/context/shared.js.map +1 -0
  30. package/dist/tools/context/update.js +105 -0
  31. package/dist/tools/context/update.js.map +1 -0
  32. package/dist/tools/dashboard/aggregates.js +34 -0
  33. package/dist/tools/dashboard/aggregates.js.map +1 -0
  34. package/dist/tools/dashboard/cash-impact.js +36 -0
  35. package/dist/tools/dashboard/cash-impact.js.map +1 -0
  36. package/dist/tools/dashboard/index.js +27 -0
  37. package/dist/tools/dashboard/index.js.map +1 -0
  38. package/dist/tools/dashboard/match-rate.js +35 -0
  39. package/dist/tools/dashboard/match-rate.js.map +1 -0
  40. package/dist/tools/dashboard/metrics.js +36 -0
  41. package/dist/tools/dashboard/metrics.js.map +1 -0
  42. package/dist/tools/dashboard/shared.js +122 -0
  43. package/dist/tools/dashboard/shared.js.map +1 -0
  44. package/dist/tools/dashboard/sla.js +33 -0
  45. package/dist/tools/dashboard/sla.js.map +1 -0
  46. package/dist/tools/dashboard/source-breakdown.js +36 -0
  47. package/dist/tools/dashboard/source-breakdown.js.map +1 -0
  48. package/dist/tools/dashboard/volume.js +35 -0
  49. package/dist/tools/dashboard/volume.js.map +1 -0
  50. package/dist/tools/dispute/close.js +49 -0
  51. package/dist/tools/dispute/close.js.map +1 -0
  52. package/dist/tools/dispute/get.js +27 -0
  53. package/dist/tools/dispute/get.js.map +1 -0
  54. package/dist/tools/dispute/index.js +17 -0
  55. package/dist/tools/dispute/index.js.map +1 -0
  56. package/dist/tools/dispute/list.js +137 -0
  57. package/dist/tools/dispute/list.js.map +1 -0
  58. package/dist/tools/dispute/shared.js +66 -0
  59. package/dist/tools/dispute/shared.js.map +1 -0
  60. package/dist/tools/dispute/submit-evidence.js +58 -0
  61. package/dist/tools/dispute/submit-evidence.js.map +1 -0
  62. package/dist/tools/exception/add-comment.js +50 -0
  63. package/dist/tools/exception/add-comment.js.map +1 -0
  64. package/dist/tools/exception/adjust-entry.js +71 -0
  65. package/dist/tools/exception/adjust-entry.js.map +1 -0
  66. package/dist/tools/exception/bulk-assign.js +47 -0
  67. package/dist/tools/exception/bulk-assign.js.map +1 -0
  68. package/dist/tools/exception/bulk-dispatch.js +69 -0
  69. package/dist/tools/exception/bulk-dispatch.js.map +1 -0
  70. package/dist/tools/exception/bulk-resolve.js +64 -0
  71. package/dist/tools/exception/bulk-resolve.js.map +1 -0
  72. package/dist/tools/exception/delete-comment.js +40 -0
  73. package/dist/tools/exception/delete-comment.js.map +1 -0
  74. package/dist/tools/exception/dispatch.js +64 -0
  75. package/dist/tools/exception/dispatch.js.map +1 -0
  76. package/dist/tools/exception/force-match.js +55 -0
  77. package/dist/tools/exception/force-match.js.map +1 -0
  78. package/dist/tools/exception/get.js +34 -0
  79. package/dist/tools/exception/get.js.map +1 -0
  80. package/dist/tools/exception/history.js +61 -0
  81. package/dist/tools/exception/history.js.map +1 -0
  82. package/dist/tools/exception/index.js +39 -0
  83. package/dist/tools/exception/index.js.map +1 -0
  84. package/dist/tools/exception/list-comments.js +35 -0
  85. package/dist/tools/exception/list-comments.js.map +1 -0
  86. package/dist/tools/exception/list.js +169 -0
  87. package/dist/tools/exception/list.js.map +1 -0
  88. package/dist/tools/exception/open-dispute.js +53 -0
  89. package/dist/tools/exception/open-dispute.js.map +1 -0
  90. package/dist/tools/exception/shared.js +98 -0
  91. package/dist/tools/exception/shared.js.map +1 -0
  92. package/dist/tools/fee-rule/create.js +106 -0
  93. package/dist/tools/fee-rule/create.js.map +1 -0
  94. package/dist/tools/fee-rule/delete.js +27 -0
  95. package/dist/tools/fee-rule/delete.js.map +1 -0
  96. package/dist/tools/fee-rule/get.js +27 -0
  97. package/dist/tools/fee-rule/get.js.map +1 -0
  98. package/dist/tools/fee-rule/index.js +21 -0
  99. package/dist/tools/fee-rule/index.js.map +1 -0
  100. package/dist/tools/fee-rule/list.js +64 -0
  101. package/dist/tools/fee-rule/list.js.map +1 -0
  102. package/dist/tools/fee-rule/shared.js +67 -0
  103. package/dist/tools/fee-rule/shared.js.map +1 -0
  104. package/dist/tools/fee-rule/update.js +70 -0
  105. package/dist/tools/fee-rule/update.js.map +1 -0
  106. package/dist/tools/fee-schedule/create.js +105 -0
  107. package/dist/tools/fee-schedule/create.js.map +1 -0
  108. package/dist/tools/fee-schedule/delete.js +32 -0
  109. package/dist/tools/fee-schedule/delete.js.map +1 -0
  110. package/dist/tools/fee-schedule/get.js +30 -0
  111. package/dist/tools/fee-schedule/get.js.map +1 -0
  112. package/dist/tools/fee-schedule/index.js +22 -0
  113. package/dist/tools/fee-schedule/index.js.map +1 -0
  114. package/dist/tools/fee-schedule/list.js +56 -0
  115. package/dist/tools/fee-schedule/list.js.map +1 -0
  116. package/dist/tools/fee-schedule/shared.js +58 -0
  117. package/dist/tools/fee-schedule/shared.js.map +1 -0
  118. package/dist/tools/fee-schedule/simulate.js +54 -0
  119. package/dist/tools/fee-schedule/simulate.js.map +1 -0
  120. package/dist/tools/fee-schedule/update.js +69 -0
  121. package/dist/tools/fee-schedule/update.js.map +1 -0
  122. package/dist/tools/generic/describe-operation.js +157 -0
  123. package/dist/tools/generic/describe-operation.js.map +1 -0
  124. package/dist/tools/generic/invoke.js +343 -0
  125. package/dist/tools/generic/invoke.js.map +1 -0
  126. package/dist/tools/generic/list-operations.js +73 -0
  127. package/dist/tools/generic/list-operations.js.map +1 -0
  128. package/dist/tools/ingestion/index.js +29 -0
  129. package/dist/tools/ingestion/index.js.map +1 -0
  130. package/dist/tools/ingestion/job-errors-list.js +45 -0
  131. package/dist/tools/ingestion/job-errors-list.js.map +1 -0
  132. package/dist/tools/ingestion/job-get.js +42 -0
  133. package/dist/tools/ingestion/job-get.js.map +1 -0
  134. package/dist/tools/ingestion/job-transactions-list.js +93 -0
  135. package/dist/tools/ingestion/job-transactions-list.js.map +1 -0
  136. package/dist/tools/ingestion/jobs-list.js +89 -0
  137. package/dist/tools/ingestion/jobs-list.js.map +1 -0
  138. package/dist/tools/ingestion/shared.js +84 -0
  139. package/dist/tools/ingestion/shared.js.map +1 -0
  140. package/dist/tools/ingestion/transaction-ignore.js +51 -0
  141. package/dist/tools/ingestion/transaction-ignore.js.map +1 -0
  142. package/dist/tools/ingestion/transactions-search.js +143 -0
  143. package/dist/tools/ingestion/transactions-search.js.map +1 -0
  144. package/dist/tools/match-rule/create.js +64 -0
  145. package/dist/tools/match-rule/create.js.map +1 -0
  146. package/dist/tools/match-rule/delete.js +35 -0
  147. package/dist/tools/match-rule/delete.js.map +1 -0
  148. package/dist/tools/match-rule/get.js +32 -0
  149. package/dist/tools/match-rule/get.js.map +1 -0
  150. package/dist/tools/match-rule/index.js +22 -0
  151. package/dist/tools/match-rule/index.js.map +1 -0
  152. package/dist/tools/match-rule/list.js +72 -0
  153. package/dist/tools/match-rule/list.js.map +1 -0
  154. package/dist/tools/match-rule/reorder.js +45 -0
  155. package/dist/tools/match-rule/reorder.js.map +1 -0
  156. package/dist/tools/match-rule/shared.js +71 -0
  157. package/dist/tools/match-rule/shared.js.map +1 -0
  158. package/dist/tools/match-rule/update.js +68 -0
  159. package/dist/tools/match-rule/update.js.map +1 -0
  160. package/dist/tools/matching/get.js +48 -0
  161. package/dist/tools/matching/get.js.map +1 -0
  162. package/dist/tools/matching/groups.js +98 -0
  163. package/dist/tools/matching/groups.js.map +1 -0
  164. package/dist/tools/matching/index.js +19 -0
  165. package/dist/tools/matching/index.js.map +1 -0
  166. package/dist/tools/matching/list.js +76 -0
  167. package/dist/tools/matching/list.js.map +1 -0
  168. package/dist/tools/matching/shared.js +77 -0
  169. package/dist/tools/matching/shared.js.map +1 -0
  170. package/dist/tools/matching/start.js +55 -0
  171. package/dist/tools/matching/start.js.map +1 -0
  172. package/dist/tools/report/count-exceptions.js +45 -0
  173. package/dist/tools/report/count-exceptions.js.map +1 -0
  174. package/dist/tools/report/count-matched.js +46 -0
  175. package/dist/tools/report/count-matched.js.map +1 -0
  176. package/dist/tools/report/count-transactions.js +44 -0
  177. package/dist/tools/report/count-transactions.js.map +1 -0
  178. package/dist/tools/report/count-unmatched.js +44 -0
  179. package/dist/tools/report/count-unmatched.js.map +1 -0
  180. package/dist/tools/report/export-exceptions.js +46 -0
  181. package/dist/tools/report/export-exceptions.js.map +1 -0
  182. package/dist/tools/report/export-matched.js +47 -0
  183. package/dist/tools/report/export-matched.js.map +1 -0
  184. package/dist/tools/report/export-summary.js +47 -0
  185. package/dist/tools/report/export-summary.js.map +1 -0
  186. package/dist/tools/report/export-unmatched.js +47 -0
  187. package/dist/tools/report/export-unmatched.js.map +1 -0
  188. package/dist/tools/report/export-variance.js +46 -0
  189. package/dist/tools/report/export-variance.js.map +1 -0
  190. package/dist/tools/report/index.js +40 -0
  191. package/dist/tools/report/index.js.map +1 -0
  192. package/dist/tools/report/matched.js +44 -0
  193. package/dist/tools/report/matched.js.map +1 -0
  194. package/dist/tools/report/shared.js +176 -0
  195. package/dist/tools/report/shared.js.map +1 -0
  196. package/dist/tools/report/summary.js +41 -0
  197. package/dist/tools/report/summary.js.map +1 -0
  198. package/dist/tools/report/unmatched.js +44 -0
  199. package/dist/tools/report/unmatched.js.map +1 -0
  200. package/dist/tools/report/variance.js +44 -0
  201. package/dist/tools/report/variance.js.map +1 -0
  202. package/dist/tools/source/create.js +84 -0
  203. package/dist/tools/source/create.js.map +1 -0
  204. package/dist/tools/source/get.js +41 -0
  205. package/dist/tools/source/get.js.map +1 -0
  206. package/dist/tools/source/index.js +22 -0
  207. package/dist/tools/source/index.js.map +1 -0
  208. package/dist/tools/source/list.js +72 -0
  209. package/dist/tools/source/list.js.map +1 -0
  210. package/dist/tools/source/shared.js +63 -0
  211. package/dist/tools/source/shared.js.map +1 -0
  212. package/dist/tools/source/update.js +73 -0
  213. package/dist/tools/source/update.js.map +1 -0
  214. package/dist/tools/tool-error.js +74 -0
  215. package/dist/tools/tool-error.js.map +1 -0
  216. package/dist/transport/body-limit.js +82 -0
  217. package/dist/transport/body-limit.js.map +1 -0
  218. package/dist/transport/http.js +154 -0
  219. package/dist/transport/http.js.map +1 -0
  220. package/package.json +68 -0
package/dist/server.js ADDED
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env node
2
+ // Entry point for the Matcher MCP server.
3
+ //
4
+ // Task 1.1.2: instantiate an McpServer (name/version from package.json), mount
5
+ // the SDK's Streamable HTTP transport on a Node HTTP server (MCP_PORT, default
6
+ // 4019), register a placeholder `mcp_ping` tool so tools/list has content,
7
+ // expose a plain GET /healthz, read MATCHER_API_URL via the config module, and
8
+ // shut down gracefully on SIGTERM.
9
+ //
10
+ // The transport runs in the SDK's documented stateless mode — a fresh McpServer
11
+ // is built per request via `buildMcpServer` (see transport/http.ts). Real tools
12
+ // (generic invoke trio, curated fee-schedule vertical) register here in later
13
+ // tasks; for now only the placeholder lives in `registerTools`.
14
+ import { readFileSync } from 'node:fs';
15
+ import { fileURLToPath } from 'node:url';
16
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
17
+ import { requireMatcherClient, UnauthenticatedError, } from './auth/request-token.js';
18
+ import { loadConfig } from './config.js';
19
+ import { initTelemetry, instrumentToolCall, shutdownTelemetry, } from './observability/otel.js';
20
+ import { loadSpec } from './spec/load.js';
21
+ import { registerContextTools } from './tools/context/index.js';
22
+ import { registerDashboardTools } from './tools/dashboard/index.js';
23
+ import { registerDisputeTools } from './tools/dispute/index.js';
24
+ import { registerExceptionTools } from './tools/exception/index.js';
25
+ import { registerFeeRuleTools } from './tools/fee-rule/index.js';
26
+ import { registerFeeScheduleTools } from './tools/fee-schedule/index.js';
27
+ import { registerDescribeOperationTool } from './tools/generic/describe-operation.js';
28
+ import { registerInvokeTool } from './tools/generic/invoke.js';
29
+ import { registerListOperationsTool } from './tools/generic/list-operations.js';
30
+ import { registerIngestionTools } from './tools/ingestion/index.js';
31
+ import { registerMatchRuleTools } from './tools/match-rule/index.js';
32
+ import { registerMatchingTools } from './tools/matching/index.js';
33
+ import { registerReportTools } from './tools/report/index.js';
34
+ import { registerSourceTools } from './tools/source/index.js';
35
+ import { start } from './transport/http.js';
36
+ /** The static reply the placeholder tool returns. */
37
+ export const PING_REPLY = 'pong';
38
+ /**
39
+ * Read `name` and `version` from package.json. Resolved relative to this module
40
+ * so it works both in dev (src/server.ts → ../package.json) and in the built
41
+ * artifact (dist/server.js → ../package.json), since both sit one level below
42
+ * the project root.
43
+ */
44
+ export function readServerInfo() {
45
+ const pkgPath = fileURLToPath(new URL('../package.json', import.meta.url));
46
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
47
+ if (!pkg.name || !pkg.version) {
48
+ throw new Error('package.json is missing name or version');
49
+ }
50
+ return { name: pkg.name, version: pkg.version };
51
+ }
52
+ /** Tool reply confirming a caller credential was relayed (never its value). */
53
+ export const WHOAMI_AUTHENTICATED = 'matcher credential present (relayed)';
54
+ /**
55
+ * The boot operation index, loaded once and memoized. `buildMcpServer` runs per
56
+ * inbound request (stateless transport), but the embedded spec is immutable boot
57
+ * data, so we parse + index it exactly once and share the read-only result.
58
+ * Loading is lazy so importing this module never reads the filesystem (keeps
59
+ * config/lifecycle tests side-effect free); a missing/unparseable spec still
60
+ * fails loudly the first time a server is built.
61
+ */
62
+ let operationIndexCache;
63
+ function getOperationIndex() {
64
+ if (operationIndexCache === undefined) {
65
+ operationIndexCache = loadSpec().index;
66
+ }
67
+ return operationIndexCache;
68
+ }
69
+ /**
70
+ * Register all tools on an McpServer. The placeholders `mcp_ping` (proves
71
+ * transport wiring) and `mcp_whoami` (proves the request-scoped token relay),
72
+ * plus the generic discovery pair `matcher_list_operations` /
73
+ * `matcher_describe_operation` over the embedded operation index. Extended by
74
+ * the rest of the real tool surface in tasks 1.2.3 / 1.3.x.
75
+ */
76
+ function registerTools(server) {
77
+ server.registerTool('mcp_ping', {
78
+ description: 'Placeholder liveness tool. Returns a static string to prove the ' +
79
+ 'MCP transport is wired. Replaced by real tools in later tasks.',
80
+ }, () => ({
81
+ content: [{ type: 'text', text: PING_REPLY }],
82
+ }));
83
+ // Reports ONLY whether a usable bearer credential reached the handler —
84
+ // never the token itself. It exercises the relay's fail-closed guard via
85
+ // requireMatcherClient: an UnauthenticatedError means no credential was
86
+ // relayed. Any other outcome (a client, or — until task 1.3.1 — the client
87
+ // factory's "not implemented" throw) means the credential WAS present, since
88
+ // execution got past the fail-closed guard. We therefore treat only
89
+ // UnauthenticatedError as "absent" and never inspect the token value.
90
+ server.registerTool('mcp_whoami', {
91
+ description: 'Reports whether the caller relayed a matcher bearer credential. ' +
92
+ 'Returns presence only — never the token value. Use it to confirm ' +
93
+ 'your MCP client is sending an `Authorization: Bearer <jwt>` header.',
94
+ }, (extra) => {
95
+ try {
96
+ requireMatcherClient(extra);
97
+ }
98
+ catch (err) {
99
+ if (err instanceof UnauthenticatedError) {
100
+ // Fail-closed: surface the operator remediation text as a tool error.
101
+ // The message contains no token material.
102
+ return { isError: true, content: [{ type: 'text', text: err.message }] };
103
+ }
104
+ // Got past the credential guard (e.g. client factory not yet
105
+ // implemented) — the credential was present.
106
+ }
107
+ return { content: [{ type: 'text', text: WHOAMI_AUTHENTICATED }] };
108
+ });
109
+ // Generic discovery surface (task 1.2.2): pure reads over the boot operation
110
+ // index. No matcher call, no token — they describe the contract, not data.
111
+ const index = getOperationIndex();
112
+ registerListOperationsTool(server, index);
113
+ registerDescribeOperationTool(server, index);
114
+ // Generic invoke (task 1.2.3): assembles + validates + dispatches any of the
115
+ // 167 operations with the caller's relayed token (fail-closed). Shares the
116
+ // RFC 9457 → tool-error mapping (toToolError) with the curated surface.
117
+ registerInvokeTool(server, index);
118
+ // Curated fee-schedule vertical (task 1.3.2): six typed tools (create/list/
119
+ // get/update/delete/simulate). They share the fail-closed relay and the
120
+ // toToolError mapping with the generic invoke, so both surfaces map matcher
121
+ // errors identically.
122
+ registerFeeScheduleTools(server);
123
+ // Phase 2 curated verticals (task 2.2.4): the remaining five families, each
124
+ // built in parallel and registered here to avoid concurrent server.ts edits.
125
+ // Every family shares the same fail-closed relay + toToolError mapping as the
126
+ // fee-schedule vertical and the generic invoke. None carries a tenant field.
127
+ // fee_rule_* (5): create/list/get/update/delete — hybrid path
128
+ // match_rule_* (6): create/list/get/update/delete/reorder — context-nested
129
+ // context_* (5): create/list/get/update/delete
130
+ // source_* (5): create/list/get/update/delete — context-nested
131
+ // match_run_* (4): start/list/get/groups — verbs over /v1/matching
132
+ registerFeeRuleTools(server);
133
+ registerMatchRuleTools(server);
134
+ registerContextTools(server);
135
+ registerSourceTools(server);
136
+ registerMatchingTools(server);
137
+ // Phase 4.2 curated verticals: the remaining five families, each built in
138
+ // parallel and registered here to avoid concurrent server.ts edits. Every
139
+ // family shares the same fail-closed relay + toToolError mapping as the
140
+ // fee-schedule vertical and the generic invoke. None carries a tenant field.
141
+ // exception_* (13): list/get, history, comments (list/add/delete), action
142
+ // verbs (dispatch/open-dispute/force-match/adjust-entry),
143
+ // and bulk actions (assign/resolve/dispatch)
144
+ // dispute_* (4): list/get/close/submit-evidence
145
+ // ingestion_* (6): jobs-list/job-get/job-errors-list/job-transactions-list/
146
+ // transactions-search/transaction-ignore — context-nested
147
+ // dashboard_* (7): aggregates + cash-impact/match-rate/metrics/sla/
148
+ // source-breakdown/volume — context-nested reads
149
+ // report_* (13): matched/unmatched/variance/summary, four counts, and
150
+ // five base64 exports — context-nested reads
151
+ registerExceptionTools(server);
152
+ registerDisputeTools(server);
153
+ registerIngestionTools(server);
154
+ registerDashboardTools(server);
155
+ registerReportTools(server);
156
+ }
157
+ /**
158
+ * Wrap `server.registerTool` so EVERY tool — curated, generic, and the
159
+ * placeholders — has its handler routed through `instrumentToolCall(name, fn)`
160
+ * exactly once, without touching any family tool dir or introducing a single
161
+ * dispatch chokepoint that doesn't exist. There is no central dispatch in the
162
+ * SDK (each tool registers its own callback), so the registration boundary IS
163
+ * the one place that sees every tool exactly once.
164
+ *
165
+ * The wrapper preserves the original `registerTool` signature (name + config +
166
+ * callback). It only swaps the callback for one that opens the tool span/metrics
167
+ * around the real callback and forwards the same arguments verbatim. The span
168
+ * records ONLY the tool name + outcome (+ matcher status on failure) — never the
169
+ * caller's args, headers, or token (enforced inside `instrumentToolCall`).
170
+ *
171
+ * Idempotent per server: applied once before `registerTools`, so each tool is
172
+ * wrapped a single time (no double-counting).
173
+ */
174
+ function instrumentRegistrations(server) {
175
+ const original = server.registerTool.bind(server);
176
+ const wrapped = (name, config, cb) => {
177
+ // `cb`'s arity varies (`(args, extra)` vs `(extra)`) across the SDK's tool
178
+ // callback overloads; forward whatever it was given verbatim. The result is
179
+ // `CallToolResult | Promise<CallToolResult>` — normalize to a promise for
180
+ // the instrumentation wrapper, which re-throws on error so the SDK still
181
+ // sees the original failure.
182
+ const instrumented = ((...callArgs) => instrumentToolCall(name, () => Promise.resolve(cb(...callArgs))));
183
+ return original(name, config, instrumented);
184
+ };
185
+ server.registerTool = wrapped;
186
+ }
187
+ /**
188
+ * Build a fresh McpServer with all tools registered. Called per request by the
189
+ * stateless transport (transport/http.ts), so it must be cheap and side-effect
190
+ * free beyond constructing the server.
191
+ *
192
+ * Tool registration is instrumented at the registration boundary first, so the
193
+ * subsequent `registerTools` call wraps every curated + generic tool's handler
194
+ * in a span/metrics scope (token-free) without any family dir change.
195
+ */
196
+ export function buildMcpServer(info) {
197
+ const server = new McpServer({ name: info.name, version: info.version });
198
+ instrumentRegistrations(server);
199
+ registerTools(server);
200
+ return server;
201
+ }
202
+ /**
203
+ * Boot the server: load config, read identity, start the HTTP transport, and
204
+ * wire SIGTERM/SIGINT to a graceful shutdown. Resolves to the running handle so
205
+ * callers (and tests) can close it deterministically.
206
+ */
207
+ export async function main(config = loadConfig()) {
208
+ const info = readServerInfo();
209
+ // Start telemetry before serving so the first request is already instrumented.
210
+ // A COMPLETE no-op when ENABLE_TELEMETRY is false (no SDK, no exporters, no
211
+ // network), so dev/test and single-operator runs pay nothing.
212
+ initTelemetry(config, { version: info.version });
213
+ const running = await start(config, info);
214
+ const shutdown = (signal) => {
215
+ console.error(`matcher-mcp received ${signal}, shutting down`);
216
+ running
217
+ .close()
218
+ // Flush + stop telemetry as part of the graceful close so buffered
219
+ // traces/metrics are exported before exit. A no-op when telemetry was
220
+ // never started.
221
+ .then(() => shutdownTelemetry())
222
+ .then(() => {
223
+ process.exitCode = 0;
224
+ })
225
+ .catch((err) => {
226
+ console.error('matcher-mcp shutdown failed:', err);
227
+ process.exitCode = 1;
228
+ });
229
+ };
230
+ process.once('SIGTERM', () => shutdown('SIGTERM'));
231
+ process.once('SIGINT', () => shutdown('SIGINT'));
232
+ console.error(`matcher-mcp ${info.version} listening on :${config.port} ` +
233
+ `(matcher API ${config.matcherApiUrl})`);
234
+ return running;
235
+ }
236
+ // Run only when invoked directly (not when imported by a test).
237
+ // import.meta.url vs the resolved argv[1] is the standard ESM "main module" check.
238
+ if (process.argv[1] &&
239
+ import.meta.url === new URL(`file://${process.argv[1]}`).href) {
240
+ main().catch((err) => {
241
+ console.error('matcher-mcp failed to start:', err);
242
+ process.exitCode = 1;
243
+ });
244
+ }
245
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,145 @@
1
+ // Canonical record of which matcher OpenAPI operations the CURATED tool surface
2
+ // covers — the registry the drift guard checks against.
3
+ //
4
+ // WHY THIS EXISTS
5
+ // The server exposes two surfaces over the 167-operation matcher spec:
6
+ // 1. The GENERIC trio (matcher_list_operations / describe / invoke) reads the
7
+ // spec at runtime, so it tracks the spec automatically. `load.test.ts`
8
+ // already pins `index.operations.size === 167` as that side's canary.
9
+ // 2. The CURATED tools (the ~72 hand-written Zod tools under `src/tools/*/`)
10
+ // hard-code their own method+path. NOTHING in those tools consults the
11
+ // spec, and their unit tests assert against the same hard-coded literal —
12
+ // tautological w.r.t. the spec. So if matcher renames or removes an
13
+ // operation, a curated tool silently keeps sending the stale contract.
14
+ //
15
+ // This file closes that gap: it is the single, hand-curated list of which
16
+ // operationIds each curated tool covers, plus the operationIds we deliberately
17
+ // leave to generic-invoke only. `curated-operations.test.ts` keeps it honest
18
+ // against the real spec — STRUCTURAL drift (a covered op no longer exists) and
19
+ // COVERAGE drift (a new op nobody triaged) both fail that test. It does NOT
20
+ // attempt deep Zod-vs-JSONSchema field equivalence — that is out of scope and a
21
+ // false-positive factory; this is a cheap "layer 1" tripwire.
22
+ //
23
+ // HOW IT WAS DERIVED (and how to keep it correct)
24
+ // Each entry was reconciled from the curated tool's dispatched `{ method, path }`
25
+ // (see each `src/tools/<family>/*.ts` and its `shared.ts` path helper) against
26
+ // the spec's method+path → operationId map. It is NOT copied from any external
27
+ // list. When a curated tool is added/removed/retargeted, update the matching
28
+ // array below and re-run `curated-operations.test.ts`.
29
+ /**
30
+ * Every operationId covered by a curated Zod tool, grouped by tool family.
31
+ * Order within a family follows the tool files; the test treats this as a set.
32
+ */
33
+ export const CURATED_OPERATION_IDS = [
34
+ // fee-schedule (src/tools/fee-schedule/) — 6
35
+ 'createFeeSchedule', // fee_schedule_create — POST /v1/fee-schedules
36
+ 'deleteFeeSchedule', // fee_schedule_delete — DELETE /v1/fee-schedules/{scheduleId}
37
+ 'getFeeSchedule', // fee_schedule_get — GET /v1/fee-schedules/{scheduleId}
38
+ 'listFeeSchedules', // fee_schedule_list — GET /v1/fee-schedules
39
+ 'simulateFeeSchedule', // fee_schedule_simulate — POST /v1/fee-schedules/{scheduleId}/simulate
40
+ 'updateFeeSchedule', // fee_schedule_update — PATCH /v1/fee-schedules/{scheduleId}
41
+ // fee-rule (src/tools/fee-rule/) — 5
42
+ 'createFeeRule', // fee_rule_create — POST /v1/contexts/{contextId}/fee-rules
43
+ 'deleteFeeRule', // fee_rule_delete — DELETE /v1/fee-rules/{feeRuleId}
44
+ 'getFeeRule', // fee_rule_get — GET /v1/fee-rules/{feeRuleId}
45
+ 'listFeeRules', // fee_rule_list — GET /v1/contexts/{contextId}/fee-rules
46
+ 'updateFeeRule', // fee_rule_update — PATCH /v1/fee-rules/{feeRuleId}
47
+ // match-rule (src/tools/match-rule/) — 6
48
+ 'createMatchRule', // match_rule_create — POST /v1/contexts/{contextId}/rules
49
+ 'deleteMatchRule', // match_rule_delete — DELETE /v1/contexts/{contextId}/rules/{ruleId}
50
+ 'getMatchRule', // match_rule_get — GET /v1/contexts/{contextId}/rules/{ruleId}
51
+ 'listMatchRules', // match_rule_list — GET /v1/contexts/{contextId}/rules
52
+ 'reorderMatchRules', // match_rule_reorder — POST /v1/contexts/{contextId}/rules/reorder
53
+ 'updateMatchRule', // match_rule_update — PATCH /v1/contexts/{contextId}/rules/{ruleId}
54
+ // context (src/tools/context/) — 4 (delete removed: hard-delete → archive/restore lifecycle)
55
+ 'createContext', // context_create — POST /v1/contexts
56
+ 'getContext', // context_get — GET /v1/contexts/{contextId}
57
+ 'listContexts', // context_list — GET /v1/contexts
58
+ 'updateContext', // context_update — PATCH /v1/contexts/{contextId}
59
+ // source (src/tools/source/) — 4 (delete removed: hard-delete → archive/restore lifecycle)
60
+ 'createSource', // source_create — POST /v1/contexts/{contextId}/sources
61
+ 'getSource', // source_get — GET /v1/contexts/{contextId}/sources/{sourceId}
62
+ 'listSources', // source_list — GET /v1/contexts/{contextId}/sources
63
+ 'updateSource', // source_update — PATCH /v1/contexts/{contextId}/sources/{sourceId}
64
+ // matching (src/tools/matching/) — 4
65
+ 'getMatchRun', // match_run_get — GET /v1/matching/runs/{runId}
66
+ 'getMatchRunGroups', // match_run_groups — GET /v1/matching/runs/{runId}/groups
67
+ 'listMatchRuns', // match_run_list — GET /v1/matching/contexts/{contextId}/runs
68
+ 'runMatch', // match_run_start — POST /v1/matching/contexts/{contextId}/run
69
+ // exception (src/tools/exception/) — 13
70
+ 'addComment', // exception_add_comment — POST /v1/exceptions/{exceptionId}/comments
71
+ 'adjustEntryException', // exception_adjust_entry — POST /v1/exceptions/{exceptionId}/adjust-entry
72
+ 'bulkAssignExceptions', // exception_bulk_assign — POST /v1/exceptions/bulk/assign
73
+ 'bulkDispatchExceptions', // exception_bulk_dispatch — POST /v1/exceptions/bulk/dispatch
74
+ 'bulkResolveExceptions', // exception_bulk_resolve — POST /v1/exceptions/bulk/resolve
75
+ 'deleteComment', // exception_delete_comment — DELETE /v1/exceptions/{exceptionId}/comments/{commentId}
76
+ 'dispatchException', // exception_dispatch — POST /v1/exceptions/{exceptionId}/dispatch
77
+ 'forceMatchException', // exception_force_match — POST /v1/exceptions/{exceptionId}/force-match
78
+ 'getException', // exception_get — GET /v1/exceptions/{exceptionId}
79
+ 'getExceptionHistory', // exception_history — GET /v1/exceptions/{exceptionId}/history
80
+ 'listComments', // exception_list_comments — GET /v1/exceptions/{exceptionId}/comments
81
+ 'listExceptions', // exception_list — GET /v1/exceptions
82
+ 'openDispute', // exception_open_dispute — POST /v1/exceptions/{exceptionId}/disputes
83
+ // dispute (src/tools/dispute/) — 4
84
+ 'closeDispute', // dispute_close — POST /v1/disputes/{disputeId}/close
85
+ 'getDispute', // dispute_get — GET /v1/disputes/{disputeId}
86
+ 'listDisputes', // dispute_list — GET /v1/disputes
87
+ 'submitEvidence', // dispute_submit_evidence — POST /v1/disputes/{disputeId}/evidence
88
+ // ingestion (src/tools/ingestion/) — 6
89
+ 'listIngestionJobErrors', // ingestion_job_errors_list — GET /v1/imports/contexts/{contextId}/jobs/{jobId}/errors
90
+ 'getIngestionJob', // ingestion_job_get — GET /v1/imports/contexts/{contextId}/jobs/{jobId}
91
+ 'listJobTransactions', // ingestion_job_transactions_list — GET /v1/imports/contexts/{contextId}/jobs/{jobId}/transactions
92
+ 'listIngestionJobs', // ingestion_jobs_list — GET /v1/imports/contexts/{contextId}/jobs
93
+ 'ignoreTransaction', // ingestion_transaction_ignore — POST /v1/imports/contexts/{contextId}/transactions/{transactionId}/ignore
94
+ 'searchTransactions', // ingestion_transactions_search — GET /v1/imports/contexts/{contextId}/transactions/search
95
+ // dashboard (src/tools/dashboard/) — 7
96
+ 'getDashboardAggregates', // dashboard_aggregates — GET /v1/reports/contexts/{contextId}/dashboard
97
+ 'getCashImpactSummary', // dashboard_cash_impact — GET /v1/reports/contexts/{contextId}/dashboard/cash-impact
98
+ 'getMatchRateStats', // dashboard_match_rate — GET /v1/reports/contexts/{contextId}/dashboard/match-rate
99
+ 'getMatcherDashboardMetrics', // dashboard_metrics — GET /v1/reports/contexts/{contextId}/dashboard/metrics
100
+ 'getSLAStats', // dashboard_sla — GET /v1/reports/contexts/{contextId}/dashboard/sla
101
+ 'getSourceBreakdown', // dashboard_source_breakdown — GET /v1/reports/contexts/{contextId}/dashboard/source-breakdown
102
+ 'getVolumeStats', // dashboard_volume — GET /v1/reports/contexts/{contextId}/dashboard/volume
103
+ // report (src/tools/report/) — 13
104
+ 'countExceptions', // report_count_exceptions — GET /v1/reports/contexts/{contextId}/exceptions/count
105
+ 'countMatched', // report_count_matched — GET /v1/reports/contexts/{contextId}/matches/count
106
+ 'countTransactions', // report_count_transactions — GET /v1/reports/contexts/{contextId}/transactions/count
107
+ 'countUnmatched', // report_count_unmatched — GET /v1/reports/contexts/{contextId}/unmatched/count
108
+ 'exportExceptionsReport', // report_export_exceptions — GET /v1/reports/contexts/{contextId}/exceptions/export
109
+ 'exportMatchedReport', // report_export_matched — GET /v1/reports/contexts/{contextId}/matched/export
110
+ 'exportSummaryReport', // report_export_summary — GET /v1/reports/contexts/{contextId}/summary/export
111
+ 'exportUnmatchedReport', // report_export_unmatched — GET /v1/reports/contexts/{contextId}/unmatched/export
112
+ 'exportVarianceReport', // report_export_variance — GET /v1/reports/contexts/{contextId}/variance/export
113
+ 'getMatchedReport', // report_matched — GET /v1/reports/contexts/{contextId}/matched
114
+ 'getSummaryReport', // report_summary — GET /v1/reports/contexts/{contextId}/summary
115
+ 'getUnmatchedReport', // report_unmatched — GET /v1/reports/contexts/{contextId}/unmatched
116
+ 'getVarianceReport', // report_variance — GET /v1/reports/contexts/{contextId}/variance
117
+ ];
118
+ /**
119
+ * Operations DELIBERATELY left to generic-invoke only — a JSON-shaped curated
120
+ * tool can't (or shouldn't) express them. Each carries the reason inline. The
121
+ * drift guard asserts these exist in the spec (so a rename here also fails) and
122
+ * counts them against total coverage. To curate one later, move it into
123
+ * `CURATED_OPERATION_IDS` and adjust the frozen counts in the test.
124
+ */
125
+ export const GENERIC_ONLY_OPERATION_IDS = [
126
+ // POST /v1/imports/contexts/{contextId}/sources/{sourceId}/upload —
127
+ // multipart/form-data binary file upload; a JSON tool can't carry the body.
128
+ 'uploadFile',
129
+ // POST /v1/imports/contexts/{contextId}/sources/{sourceId}/extract-document —
130
+ // multipart/form-data binary document upload; same as uploadFile.
131
+ 'extractDocument',
132
+ // POST /v1/exceptions/{exceptionId}/callback — inbound webhook receiver for
133
+ // external dispatch systems, not an operator-initiated action.
134
+ 'processCallback',
135
+ // callback-credential (generic-only) — HMAC machine-auth credential lifecycle;
136
+ // straightforward JSON CRUD nobody has hand-curated a Zod tool for yet.
137
+ 'mintCallbackCredential', // POST /v1/exceptions/callbacks/credentials
138
+ 'listCallbackCredentials', // GET /v1/exceptions/callbacks/credentials
139
+ 'rotateCallbackCredential', // POST /v1/exceptions/callbacks/credentials/{credentialId}/rotate
140
+ 'revokeCallbackCredential', // DELETE /v1/exceptions/callbacks/credentials/{credentialId}
141
+ // discovery webhook (generic-only) — inbound aggregator webhook receiver, not
142
+ // an operator-initiated action (cf. processCallback above).
143
+ 'receiveAggregatorWebhook', // POST /v1/discovery/webhooks/{provider}/{webhookToken}
144
+ ];
145
+ //# sourceMappingURL=curated-operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"curated-operations.js","sourceRoot":"","sources":["../../src/spec/curated-operations.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,wDAAwD;AACxD,EAAE;AACF,kBAAkB;AAClB,uEAAuE;AACvE,gFAAgF;AAChF,4EAA4E;AAC5E,2EAA2E;AAC3E,+EAA+E;AAC/E,4EAA4E;AAC5E,+EAA+E;AAC/E,yEAAyE;AACzE,4EAA4E;AAC5E,EAAE;AACF,0EAA0E;AAC1E,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAC/E,4EAA4E;AAC5E,gFAAgF;AAChF,8DAA8D;AAC9D,EAAE;AACF,kDAAkD;AAClD,kFAAkF;AAClF,+EAA+E;AAC/E,+EAA+E;AAC/E,6EAA6E;AAC7E,uDAAuD;AAEvD;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,6CAA6C;IAC7C,mBAAmB,EAAE,mDAAmD;IACxE,mBAAmB,EAAE,gEAAgE;IACrF,gBAAgB,EAAE,gEAAgE;IAClF,kBAAkB,EAAE,mDAAmD;IACvE,qBAAqB,EAAE,yEAAyE;IAChG,mBAAmB,EAAE,gEAAgE;IAErF,qCAAqC;IACrC,eAAe,EAAE,8DAA8D;IAC/E,eAAe,EAAE,qDAAqD;IACtE,YAAY,EAAE,qDAAqD;IACnE,cAAc,EAAE,8DAA8D;IAC9E,eAAe,EAAE,qDAAqD;IAEtE,yCAAyC;IACzC,iBAAiB,EAAE,6DAA6D;IAChF,iBAAiB,EAAE,sEAAsE;IACzF,cAAc,EAAE,sEAAsE;IACtF,gBAAgB,EAAE,6DAA6D;IAC/E,mBAAmB,EAAE,qEAAqE;IAC1F,iBAAiB,EAAE,sEAAsE;IAEzF,6FAA6F;IAC7F,eAAe,EAAE,uCAAuC;IACxD,YAAY,EAAE,mDAAmD;IACjE,cAAc,EAAE,uCAAuC;IACvD,eAAe,EAAE,mDAAmD;IAEpE,2FAA2F;IAC3F,cAAc,EAAE,0DAA0D;IAC1E,WAAW,EAAE,qEAAqE;IAClF,aAAa,EAAE,0DAA0D;IACzE,cAAc,EAAE,qEAAqE;IAErF,qCAAqC;IACrC,aAAa,EAAE,oDAAoD;IACnE,mBAAmB,EAAE,2DAA2D;IAChF,eAAe,EAAE,iEAAiE;IAClF,UAAU,EAAE,gEAAgE;IAE5E,wCAAwC;IACxC,YAAY,EAAE,0EAA0E;IACxF,sBAAsB,EAAE,8EAA8E;IACtG,sBAAsB,EAAE,+DAA+D;IACvF,wBAAwB,EAAE,iEAAiE;IAC3F,uBAAuB,EAAE,gEAAgE;IACzF,eAAe,EAAE,sFAAsF;IACvG,mBAAmB,EAAE,0EAA0E;IAC/F,qBAAqB,EAAE,6EAA6E;IACpG,cAAc,EAAE,iEAAiE;IACjF,qBAAqB,EAAE,yEAAyE;IAChG,cAAc,EAAE,0EAA0E;IAC1F,gBAAgB,EAAE,mDAAmD;IACrE,aAAa,EAAE,0EAA0E;IAEzF,mCAAmC;IACnC,cAAc,EAAE,gEAAgE;IAChF,YAAY,EAAE,0DAA0D;IACxE,cAAc,EAAE,8CAA8C;IAC9D,gBAAgB,EAAE,mEAAmE;IAErF,uCAAuC;IACvC,wBAAwB,EAAE,+FAA+F;IACzH,iBAAiB,EAAE,wFAAwF;IAC3G,qBAAqB,EAAE,qGAAqG;IAC5H,mBAAmB,EAAE,gFAAgF;IACrG,mBAAmB,EAAE,+GAA+G;IACpI,oBAAoB,EAAE,+FAA+F;IAErH,uCAAuC;IACvC,wBAAwB,EAAE,8EAA8E;IACxG,sBAAsB,EAAE,0FAA0F;IAClH,mBAAmB,EAAE,yFAAyF;IAC9G,4BAA4B,EAAE,sFAAsF;IACpH,aAAa,EAAE,kFAAkF;IACjG,oBAAoB,EAAE,+FAA+F;IACrH,gBAAgB,EAAE,qFAAqF;IAEvG,kCAAkC;IAClC,iBAAiB,EAAE,oFAAoF;IACvG,cAAc,EAAE,iFAAiF;IACjG,mBAAmB,EAAE,sFAAsF;IAC3G,gBAAgB,EAAE,mFAAmF;IACrG,wBAAwB,EAAE,qFAAqF;IAC/G,qBAAqB,EAAE,kFAAkF;IACzG,qBAAqB,EAAE,kFAAkF;IACzG,uBAAuB,EAAE,oFAAoF;IAC7G,sBAAsB,EAAE,mFAAmF;IAC3G,kBAAkB,EAAE,2EAA2E;IAC/F,kBAAkB,EAAE,2EAA2E;IAC/F,oBAAoB,EAAE,6EAA6E;IACnG,mBAAmB,EAAE,4EAA4E;CACzF,CAAA;AAEV;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,oEAAoE;IACpE,4EAA4E;IAC5E,YAAY;IACZ,8EAA8E;IAC9E,kEAAkE;IAClE,iBAAiB;IACjB,4EAA4E;IAC5E,+DAA+D;IAC/D,iBAAiB;IACjB,+EAA+E;IAC/E,wEAAwE;IACxE,wBAAwB,EAAE,8CAA8C;IACxE,yBAAyB,EAAE,8CAA8C;IACzE,0BAA0B,EAAE,oEAAoE;IAChG,0BAA0B,EAAE,6DAA6D;IACzF,8EAA8E;IAC9E,4DAA4D;IAC5D,0BAA0B,EAAE,wDAAwD;CAC5E,CAAA"}
@@ -0,0 +1,155 @@
1
+ // Operation index over the embedded matcher OpenAPI spec.
2
+ //
3
+ // `buildOperationIndex` walks the parsed spec's `paths` × HTTP methods into a
4
+ // flat, in-memory map keyed by `operationId`. Each entry carries everything the
5
+ // generic-invoke trio (task 1.2.2 / 1.2.3) needs to list, describe, and dispatch
6
+ // an operation: method, path, tag, summary, path/query params, and a lightly
7
+ // dereferenced request-body JSON Schema.
8
+ //
9
+ // "Lightly dereferenced" means: request-body `$ref`s are resolved against the
10
+ // spec's `components.schemas` recursively (so nested `$ref`s like a list item's
11
+ // schema are inlined too), enough that `matcher_describe_operation` can hand the
12
+ // model a self-contained JSON Schema. It is NOT a full RFC-compliant resolver —
13
+ // no external documents, and a `$ref` cycle is broken with a placeholder rather
14
+ // than recursing forever.
15
+ /** The HTTP methods we index (lowercased OpenAPI path-item keys). */
16
+ export const HTTP_METHODS = [
17
+ 'get',
18
+ 'put',
19
+ 'post',
20
+ 'delete',
21
+ 'patch',
22
+ ];
23
+ const REF_PREFIX = '#/components/schemas/';
24
+ /**
25
+ * Recursively inline `$ref`s pointing at `#/components/schemas/*` against the
26
+ * provided schema map. External refs (any `$ref` not under that prefix) and
27
+ * unresolvable names are left as-is so the caller can still see the dangling
28
+ * pointer. A `$ref` cycle is broken by tracking the chain of schema names
29
+ * currently being resolved and replacing a repeat with a `$ref`-only stub.
30
+ */
31
+ function deref(node, schemas, seen) {
32
+ if (Array.isArray(node)) {
33
+ return node.map((item) => deref(item, schemas, seen));
34
+ }
35
+ if (node === null || typeof node !== 'object') {
36
+ return node;
37
+ }
38
+ const obj = node;
39
+ const ref = obj['$ref'];
40
+ if (typeof ref === 'string' && ref.startsWith(REF_PREFIX)) {
41
+ const name = ref.slice(REF_PREFIX.length);
42
+ // Cycle guard: if we're already resolving this schema, stop and keep the ref.
43
+ if (seen.has(name)) {
44
+ return { $ref: ref };
45
+ }
46
+ const target = schemas[name];
47
+ if (target === undefined) {
48
+ // Dangling ref — leave it visible rather than silently dropping it.
49
+ return { $ref: ref };
50
+ }
51
+ const nextSeen = new Set(seen);
52
+ nextSeen.add(name);
53
+ return deref(target, schemas, nextSeen);
54
+ }
55
+ const out = {};
56
+ for (const [key, value] of Object.entries(obj)) {
57
+ out[key] = deref(value, schemas, seen);
58
+ }
59
+ return out;
60
+ }
61
+ /** Coerce the spec's `parameters` array into typed param objects. */
62
+ function parseParameters(raw) {
63
+ if (!Array.isArray(raw)) {
64
+ return [];
65
+ }
66
+ return raw.filter((p) => p !== null && typeof p === 'object');
67
+ }
68
+ /** Pull the dereferenced `application/json` request-body schema, if present. */
69
+ function extractRequestBodySchema(op, schemas) {
70
+ const json = op.requestBody?.content?.['application/json'];
71
+ const schema = json?.schema;
72
+ if (schema === null || typeof schema !== 'object') {
73
+ return undefined;
74
+ }
75
+ const resolved = deref(schema, schemas, new Set());
76
+ if (resolved === null || typeof resolved !== 'object') {
77
+ return undefined;
78
+ }
79
+ return resolved;
80
+ }
81
+ /** Stable synthetic id for an operation missing one: `METHOD path`. */
82
+ function synthesizeOperationId(method, path) {
83
+ return `${method.toUpperCase()} ${path}`;
84
+ }
85
+ /**
86
+ * Build the operation index from a parsed spec. Pure and deterministic: a given
87
+ * spec always yields the same map and the same warnings (insertion order follows
88
+ * the spec's path/method declaration order).
89
+ */
90
+ export function buildOperationIndex(spec) {
91
+ const operations = new Map();
92
+ const warnings = [];
93
+ const schemas = spec.components?.schemas ?? {};
94
+ const paths = spec.paths ?? {};
95
+ for (const [path, pathItem] of Object.entries(paths)) {
96
+ if (pathItem === null || pathItem === undefined) {
97
+ continue;
98
+ }
99
+ for (const method of HTTP_METHODS) {
100
+ const rawOp = pathItem[method];
101
+ if (rawOp === null || typeof rawOp !== 'object') {
102
+ continue;
103
+ }
104
+ const op = rawOp;
105
+ let operationId = typeof op.operationId === 'string' && op.operationId.length > 0
106
+ ? op.operationId
107
+ : undefined;
108
+ if (operationId === undefined) {
109
+ operationId = synthesizeOperationId(method, path);
110
+ warnings.push(`operation ${method.toUpperCase()} ${path} has no operationId; ` +
111
+ `synthesized "${operationId}"`);
112
+ }
113
+ const params = parseParameters(op.parameters);
114
+ const pathParams = [];
115
+ const queryParams = {};
116
+ for (const p of params) {
117
+ const name = typeof p.name === 'string' ? p.name : undefined;
118
+ if (name === undefined) {
119
+ continue;
120
+ }
121
+ if (p.in === 'path') {
122
+ pathParams.push(name);
123
+ }
124
+ else if (p.in === 'query') {
125
+ const type = typeof p.schema?.type === 'string' ? p.schema.type : 'string';
126
+ queryParams[name] = { required: p.required === true, type };
127
+ }
128
+ }
129
+ const tags = op.tags;
130
+ const tag = Array.isArray(tags) && typeof tags[0] === 'string'
131
+ ? tags[0]
132
+ : 'Untagged';
133
+ const summary = typeof op.summary === 'string' ? op.summary : '';
134
+ const requestBodySchema = extractRequestBodySchema(op, schemas);
135
+ const indexed = {
136
+ operationId,
137
+ method: method.toUpperCase(),
138
+ path,
139
+ tag,
140
+ summary,
141
+ pathParams,
142
+ queryParams,
143
+ ...(requestBodySchema !== undefined ? { requestBodySchema } : {}),
144
+ };
145
+ if (operations.has(operationId)) {
146
+ warnings.push(`duplicate operationId "${operationId}" ` +
147
+ `(${method.toUpperCase()} ${path}); keeping the first occurrence`);
148
+ continue;
149
+ }
150
+ operations.set(operationId, indexed);
151
+ }
152
+ }
153
+ return { operations, warnings };
154
+ }
155
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/spec/index.ts"],"names":[],"mappings":"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"}