@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.
- package/LICENSE +202 -0
- package/README.md +281 -0
- package/dist/auth/request-token.js +117 -0
- package/dist/auth/request-token.js.map +1 -0
- package/dist/config.js +95 -0
- package/dist/config.js.map +1 -0
- package/dist/matcher/client.js +168 -0
- package/dist/matcher/client.js.map +1 -0
- package/dist/observability/otel.js +223 -0
- package/dist/observability/otel.js.map +1 -0
- package/dist/server.js +245 -0
- package/dist/server.js.map +1 -0
- package/dist/spec/curated-operations.js +145 -0
- package/dist/spec/curated-operations.js.map +1 -0
- package/dist/spec/index.js +155 -0
- package/dist/spec/index.js.map +1 -0
- package/dist/spec/load.js +76 -0
- package/dist/spec/load.js.map +1 -0
- package/dist/spec/openapi.yaml +15217 -0
- package/dist/tools/context/create.js +100 -0
- package/dist/tools/context/create.js.map +1 -0
- package/dist/tools/context/get.js +31 -0
- package/dist/tools/context/get.js.map +1 -0
- package/dist/tools/context/index.js +21 -0
- package/dist/tools/context/index.js.map +1 -0
- package/dist/tools/context/list.js +78 -0
- package/dist/tools/context/list.js.map +1 -0
- package/dist/tools/context/shared.js +61 -0
- package/dist/tools/context/shared.js.map +1 -0
- package/dist/tools/context/update.js +105 -0
- package/dist/tools/context/update.js.map +1 -0
- package/dist/tools/dashboard/aggregates.js +34 -0
- package/dist/tools/dashboard/aggregates.js.map +1 -0
- package/dist/tools/dashboard/cash-impact.js +36 -0
- package/dist/tools/dashboard/cash-impact.js.map +1 -0
- package/dist/tools/dashboard/index.js +27 -0
- package/dist/tools/dashboard/index.js.map +1 -0
- package/dist/tools/dashboard/match-rate.js +35 -0
- package/dist/tools/dashboard/match-rate.js.map +1 -0
- package/dist/tools/dashboard/metrics.js +36 -0
- package/dist/tools/dashboard/metrics.js.map +1 -0
- package/dist/tools/dashboard/shared.js +122 -0
- package/dist/tools/dashboard/shared.js.map +1 -0
- package/dist/tools/dashboard/sla.js +33 -0
- package/dist/tools/dashboard/sla.js.map +1 -0
- package/dist/tools/dashboard/source-breakdown.js +36 -0
- package/dist/tools/dashboard/source-breakdown.js.map +1 -0
- package/dist/tools/dashboard/volume.js +35 -0
- package/dist/tools/dashboard/volume.js.map +1 -0
- package/dist/tools/dispute/close.js +49 -0
- package/dist/tools/dispute/close.js.map +1 -0
- package/dist/tools/dispute/get.js +27 -0
- package/dist/tools/dispute/get.js.map +1 -0
- package/dist/tools/dispute/index.js +17 -0
- package/dist/tools/dispute/index.js.map +1 -0
- package/dist/tools/dispute/list.js +137 -0
- package/dist/tools/dispute/list.js.map +1 -0
- package/dist/tools/dispute/shared.js +66 -0
- package/dist/tools/dispute/shared.js.map +1 -0
- package/dist/tools/dispute/submit-evidence.js +58 -0
- package/dist/tools/dispute/submit-evidence.js.map +1 -0
- package/dist/tools/exception/add-comment.js +50 -0
- package/dist/tools/exception/add-comment.js.map +1 -0
- package/dist/tools/exception/adjust-entry.js +71 -0
- package/dist/tools/exception/adjust-entry.js.map +1 -0
- package/dist/tools/exception/bulk-assign.js +47 -0
- package/dist/tools/exception/bulk-assign.js.map +1 -0
- package/dist/tools/exception/bulk-dispatch.js +69 -0
- package/dist/tools/exception/bulk-dispatch.js.map +1 -0
- package/dist/tools/exception/bulk-resolve.js +64 -0
- package/dist/tools/exception/bulk-resolve.js.map +1 -0
- package/dist/tools/exception/delete-comment.js +40 -0
- package/dist/tools/exception/delete-comment.js.map +1 -0
- package/dist/tools/exception/dispatch.js +64 -0
- package/dist/tools/exception/dispatch.js.map +1 -0
- package/dist/tools/exception/force-match.js +55 -0
- package/dist/tools/exception/force-match.js.map +1 -0
- package/dist/tools/exception/get.js +34 -0
- package/dist/tools/exception/get.js.map +1 -0
- package/dist/tools/exception/history.js +61 -0
- package/dist/tools/exception/history.js.map +1 -0
- package/dist/tools/exception/index.js +39 -0
- package/dist/tools/exception/index.js.map +1 -0
- package/dist/tools/exception/list-comments.js +35 -0
- package/dist/tools/exception/list-comments.js.map +1 -0
- package/dist/tools/exception/list.js +169 -0
- package/dist/tools/exception/list.js.map +1 -0
- package/dist/tools/exception/open-dispute.js +53 -0
- package/dist/tools/exception/open-dispute.js.map +1 -0
- package/dist/tools/exception/shared.js +98 -0
- package/dist/tools/exception/shared.js.map +1 -0
- package/dist/tools/fee-rule/create.js +106 -0
- package/dist/tools/fee-rule/create.js.map +1 -0
- package/dist/tools/fee-rule/delete.js +27 -0
- package/dist/tools/fee-rule/delete.js.map +1 -0
- package/dist/tools/fee-rule/get.js +27 -0
- package/dist/tools/fee-rule/get.js.map +1 -0
- package/dist/tools/fee-rule/index.js +21 -0
- package/dist/tools/fee-rule/index.js.map +1 -0
- package/dist/tools/fee-rule/list.js +64 -0
- package/dist/tools/fee-rule/list.js.map +1 -0
- package/dist/tools/fee-rule/shared.js +67 -0
- package/dist/tools/fee-rule/shared.js.map +1 -0
- package/dist/tools/fee-rule/update.js +70 -0
- package/dist/tools/fee-rule/update.js.map +1 -0
- package/dist/tools/fee-schedule/create.js +105 -0
- package/dist/tools/fee-schedule/create.js.map +1 -0
- package/dist/tools/fee-schedule/delete.js +32 -0
- package/dist/tools/fee-schedule/delete.js.map +1 -0
- package/dist/tools/fee-schedule/get.js +30 -0
- package/dist/tools/fee-schedule/get.js.map +1 -0
- package/dist/tools/fee-schedule/index.js +22 -0
- package/dist/tools/fee-schedule/index.js.map +1 -0
- package/dist/tools/fee-schedule/list.js +56 -0
- package/dist/tools/fee-schedule/list.js.map +1 -0
- package/dist/tools/fee-schedule/shared.js +58 -0
- package/dist/tools/fee-schedule/shared.js.map +1 -0
- package/dist/tools/fee-schedule/simulate.js +54 -0
- package/dist/tools/fee-schedule/simulate.js.map +1 -0
- package/dist/tools/fee-schedule/update.js +69 -0
- package/dist/tools/fee-schedule/update.js.map +1 -0
- package/dist/tools/generic/describe-operation.js +157 -0
- package/dist/tools/generic/describe-operation.js.map +1 -0
- package/dist/tools/generic/invoke.js +343 -0
- package/dist/tools/generic/invoke.js.map +1 -0
- package/dist/tools/generic/list-operations.js +73 -0
- package/dist/tools/generic/list-operations.js.map +1 -0
- package/dist/tools/ingestion/index.js +29 -0
- package/dist/tools/ingestion/index.js.map +1 -0
- package/dist/tools/ingestion/job-errors-list.js +45 -0
- package/dist/tools/ingestion/job-errors-list.js.map +1 -0
- package/dist/tools/ingestion/job-get.js +42 -0
- package/dist/tools/ingestion/job-get.js.map +1 -0
- package/dist/tools/ingestion/job-transactions-list.js +93 -0
- package/dist/tools/ingestion/job-transactions-list.js.map +1 -0
- package/dist/tools/ingestion/jobs-list.js +89 -0
- package/dist/tools/ingestion/jobs-list.js.map +1 -0
- package/dist/tools/ingestion/shared.js +84 -0
- package/dist/tools/ingestion/shared.js.map +1 -0
- package/dist/tools/ingestion/transaction-ignore.js +51 -0
- package/dist/tools/ingestion/transaction-ignore.js.map +1 -0
- package/dist/tools/ingestion/transactions-search.js +143 -0
- package/dist/tools/ingestion/transactions-search.js.map +1 -0
- package/dist/tools/match-rule/create.js +64 -0
- package/dist/tools/match-rule/create.js.map +1 -0
- package/dist/tools/match-rule/delete.js +35 -0
- package/dist/tools/match-rule/delete.js.map +1 -0
- package/dist/tools/match-rule/get.js +32 -0
- package/dist/tools/match-rule/get.js.map +1 -0
- package/dist/tools/match-rule/index.js +22 -0
- package/dist/tools/match-rule/index.js.map +1 -0
- package/dist/tools/match-rule/list.js +72 -0
- package/dist/tools/match-rule/list.js.map +1 -0
- package/dist/tools/match-rule/reorder.js +45 -0
- package/dist/tools/match-rule/reorder.js.map +1 -0
- package/dist/tools/match-rule/shared.js +71 -0
- package/dist/tools/match-rule/shared.js.map +1 -0
- package/dist/tools/match-rule/update.js +68 -0
- package/dist/tools/match-rule/update.js.map +1 -0
- package/dist/tools/matching/get.js +48 -0
- package/dist/tools/matching/get.js.map +1 -0
- package/dist/tools/matching/groups.js +98 -0
- package/dist/tools/matching/groups.js.map +1 -0
- package/dist/tools/matching/index.js +19 -0
- package/dist/tools/matching/index.js.map +1 -0
- package/dist/tools/matching/list.js +76 -0
- package/dist/tools/matching/list.js.map +1 -0
- package/dist/tools/matching/shared.js +77 -0
- package/dist/tools/matching/shared.js.map +1 -0
- package/dist/tools/matching/start.js +55 -0
- package/dist/tools/matching/start.js.map +1 -0
- package/dist/tools/report/count-exceptions.js +45 -0
- package/dist/tools/report/count-exceptions.js.map +1 -0
- package/dist/tools/report/count-matched.js +46 -0
- package/dist/tools/report/count-matched.js.map +1 -0
- package/dist/tools/report/count-transactions.js +44 -0
- package/dist/tools/report/count-transactions.js.map +1 -0
- package/dist/tools/report/count-unmatched.js +44 -0
- package/dist/tools/report/count-unmatched.js.map +1 -0
- package/dist/tools/report/export-exceptions.js +46 -0
- package/dist/tools/report/export-exceptions.js.map +1 -0
- package/dist/tools/report/export-matched.js +47 -0
- package/dist/tools/report/export-matched.js.map +1 -0
- package/dist/tools/report/export-summary.js +47 -0
- package/dist/tools/report/export-summary.js.map +1 -0
- package/dist/tools/report/export-unmatched.js +47 -0
- package/dist/tools/report/export-unmatched.js.map +1 -0
- package/dist/tools/report/export-variance.js +46 -0
- package/dist/tools/report/export-variance.js.map +1 -0
- package/dist/tools/report/index.js +40 -0
- package/dist/tools/report/index.js.map +1 -0
- package/dist/tools/report/matched.js +44 -0
- package/dist/tools/report/matched.js.map +1 -0
- package/dist/tools/report/shared.js +176 -0
- package/dist/tools/report/shared.js.map +1 -0
- package/dist/tools/report/summary.js +41 -0
- package/dist/tools/report/summary.js.map +1 -0
- package/dist/tools/report/unmatched.js +44 -0
- package/dist/tools/report/unmatched.js.map +1 -0
- package/dist/tools/report/variance.js +44 -0
- package/dist/tools/report/variance.js.map +1 -0
- package/dist/tools/source/create.js +84 -0
- package/dist/tools/source/create.js.map +1 -0
- package/dist/tools/source/get.js +41 -0
- package/dist/tools/source/get.js.map +1 -0
- package/dist/tools/source/index.js +22 -0
- package/dist/tools/source/index.js.map +1 -0
- package/dist/tools/source/list.js +72 -0
- package/dist/tools/source/list.js.map +1 -0
- package/dist/tools/source/shared.js +63 -0
- package/dist/tools/source/shared.js.map +1 -0
- package/dist/tools/source/update.js +73 -0
- package/dist/tools/source/update.js.map +1 -0
- package/dist/tools/tool-error.js +74 -0
- package/dist/tools/tool-error.js.map +1 -0
- package/dist/transport/body-limit.js +82 -0
- package/dist/transport/body-limit.js.map +1 -0
- package/dist/transport/http.js +154 -0
- package/dist/transport/http.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// `fee_schedule_update` — curated PATCH /v1/fee-schedules/{scheduleId}.
|
|
2
|
+
//
|
|
3
|
+
// Partial update of a fee schedule's top-level fields, mirroring the spec's
|
|
4
|
+
// UpdateFeeScheduleRequest. All body fields are optional (PATCH semantics); the
|
|
5
|
+
// spec's update surface intentionally does NOT include items[] (items are set at
|
|
6
|
+
// create time), so neither does this tool. scheduleId is a UUID path param; no
|
|
7
|
+
// tenant field is accepted (matcher scopes to the relayed token's tenant).
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { APPLICATION_ORDERS, ROUNDING_MODES } from './create.js';
|
|
10
|
+
import { dispatchFeeSchedule, feeSchedulePath } from './shared.js';
|
|
11
|
+
/** Zod raw shape for `fee_schedule_update` input — id (path) + optional fields. */
|
|
12
|
+
export const updateFeeScheduleInputShape = {
|
|
13
|
+
scheduleId: z
|
|
14
|
+
.string()
|
|
15
|
+
.min(1)
|
|
16
|
+
.describe('The fee schedule id (UUID) to update.'),
|
|
17
|
+
name: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('New human-readable name of the fee schedule.'),
|
|
21
|
+
applicationOrder: z
|
|
22
|
+
.enum(APPLICATION_ORDERS)
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('How items combine. PARALLEL applies every item to the same gross base; ' +
|
|
25
|
+
'CASCADING applies each item to the net remaining after prior items.'),
|
|
26
|
+
roundingScale: z
|
|
27
|
+
.number()
|
|
28
|
+
.int()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Number of decimal places fee amounts are rounded to.'),
|
|
31
|
+
roundingMode: z
|
|
32
|
+
.enum(ROUNDING_MODES)
|
|
33
|
+
.optional()
|
|
34
|
+
.describe('Rounding strategy. HALF_UP rounds halves away from zero; BANKERS rounds ' +
|
|
35
|
+
'halves to the nearest even digit; FLOOR rounds down; CEIL rounds up; ' +
|
|
36
|
+
'TRUNCATE drops extra digits.'),
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Build the PATCH body from the input minus the path-only `scheduleId`. Only the
|
|
40
|
+
* fields the caller actually set are sent — matcher treats absent fields as
|
|
41
|
+
* unchanged.
|
|
42
|
+
*/
|
|
43
|
+
export function buildUpdateBody(args) {
|
|
44
|
+
const { scheduleId: _scheduleId, ...body } = args;
|
|
45
|
+
void _scheduleId;
|
|
46
|
+
return body;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Register `fee_schedule_update`. Splits the id (path) from the body fields,
|
|
50
|
+
* dispatches a PATCH through the shared fail-closed relay; a matcher error
|
|
51
|
+
* surfaces via the shared toToolError.
|
|
52
|
+
*/
|
|
53
|
+
export function registerFeeScheduleUpdateTool(server) {
|
|
54
|
+
server.registerTool('fee_schedule_update', {
|
|
55
|
+
description: 'Update top-level fields of a fee schedule by id (UUID). All fields are ' +
|
|
56
|
+
'optional (PATCH): name, applicationOrder (PARALLEL|CASCADING), ' +
|
|
57
|
+
'roundingScale, roundingMode (HALF_UP|BANKERS|FLOOR|CEIL|TRUNCATE). ' +
|
|
58
|
+
'Items are not editable here — set them at create time. No tenant field ' +
|
|
59
|
+
'is accepted. Returns the updated schedule, or a structured RFC 9457 error.',
|
|
60
|
+
inputSchema: updateFeeScheduleInputShape,
|
|
61
|
+
}, async (args, extra) => {
|
|
62
|
+
return dispatchFeeSchedule({
|
|
63
|
+
method: 'PATCH',
|
|
64
|
+
path: feeSchedulePath(args.scheduleId),
|
|
65
|
+
body: buildUpdateBody(args),
|
|
66
|
+
}, extra);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/tools/fee-schedule/update.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,4EAA4E;AAC5E,gFAAgF;AAChF,iFAAiF;AACjF,+EAA+E;AAC/E,2EAA2E;AAE3E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElE,mFAAmF;AACnF,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,uCAAuC,CAAC;IACpD,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,8CAA8C,CAAC;IAC3D,gBAAgB,EAAE,CAAC;SAChB,IAAI,CAAC,kBAAkB,CAAC;SACxB,QAAQ,EAAE;SACV,QAAQ,CACP,yEAAyE;QACvE,qEAAqE,CACxE;IACH,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,QAAQ,CAAC,sDAAsD,CAAC;IACnE,YAAY,EAAE,CAAC;SACZ,IAAI,CAAC,cAAc,CAAC;SACpB,QAAQ,EAAE;SACV,QAAQ,CACP,0EAA0E;QACxE,uEAAuE;QACvE,8BAA8B,CACjC;CACJ,CAAA;AAOD;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,IAA4B;IAE5B,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAA;IACjD,KAAK,WAAW,CAAA;IAChB,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAAC,MAAiB;IAC7D,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,WAAW,EACT,yEAAyE;YACzE,iEAAiE;YACjE,qEAAqE;YACrE,yEAAyE;YACzE,4EAA4E;QAC9E,WAAW,EAAE,2BAA2B;KACzC,EACD,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;QACpB,OAAO,mBAAmB,CACxB;YACE,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC;YACtC,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC;SAC5B,EACD,KAAK,CACN,CAAA;IACH,CAAC,CACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// `matcher_describe_operation` — the second half of the generic discovery surface.
|
|
2
|
+
//
|
|
3
|
+
// A pure read over the boot operation index (spec/index.ts). Given an
|
|
4
|
+
// operationId, it returns the full descriptor the model needs to construct a
|
|
5
|
+
// valid `matcher_invoke` call: method, path (templated), the path-param names,
|
|
6
|
+
// the query-param map, the (already dereferenced) request-body JSON Schema, and
|
|
7
|
+
// the summary.
|
|
8
|
+
//
|
|
9
|
+
// No matcher call and no token — it describes the contract, not tenant data, so
|
|
10
|
+
// it does NOT fail closed.
|
|
11
|
+
//
|
|
12
|
+
// Edge case: an unknown operationId. Rather than a bare "not found", we compute
|
|
13
|
+
// the closest known ids by a cheap edit distance and name them, plus point the
|
|
14
|
+
// model back at matcher_list_operations. The model then self-corrects (typo, or
|
|
15
|
+
// browse the list) instead of guessing again blind.
|
|
16
|
+
import { z } from 'zod';
|
|
17
|
+
/** How many close matches to name in an unknown-id error. */
|
|
18
|
+
const MAX_SUGGESTIONS = 5;
|
|
19
|
+
/**
|
|
20
|
+
* Thrown when `describe` is asked for an operationId not in the index. Carries
|
|
21
|
+
* the offending id and the closest known ids so the tool layer can render a
|
|
22
|
+
* helpful, self-correcting error message.
|
|
23
|
+
*/
|
|
24
|
+
export class UnknownOperationError extends Error {
|
|
25
|
+
operationId;
|
|
26
|
+
suggestions;
|
|
27
|
+
constructor(operationId, suggestions) {
|
|
28
|
+
super(buildUnknownMessage(operationId, suggestions));
|
|
29
|
+
this.name = 'UnknownOperationError';
|
|
30
|
+
this.operationId = operationId;
|
|
31
|
+
this.suggestions = suggestions;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Compose the operator-facing message naming close matches + the list pointer. */
|
|
35
|
+
function buildUnknownMessage(operationId, suggestions) {
|
|
36
|
+
const base = `Unknown operationId "${operationId}".`;
|
|
37
|
+
const closest = suggestions.length > 0
|
|
38
|
+
? ` Did you mean: ${suggestions.join(', ')}?`
|
|
39
|
+
: '';
|
|
40
|
+
return (base +
|
|
41
|
+
closest +
|
|
42
|
+
' Call matcher_list_operations to browse the available operations.');
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Levenshtein edit distance between two strings — cheap (O(a*b)) and adequate
|
|
46
|
+
* for ranking a few hundred operationIds. Iterative two-row DP, no allocation
|
|
47
|
+
* per cell.
|
|
48
|
+
*/
|
|
49
|
+
export function editDistance(a, b) {
|
|
50
|
+
if (a === b) {
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
if (a.length === 0) {
|
|
54
|
+
return b.length;
|
|
55
|
+
}
|
|
56
|
+
if (b.length === 0) {
|
|
57
|
+
return a.length;
|
|
58
|
+
}
|
|
59
|
+
let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
60
|
+
let curr = new Array(b.length + 1);
|
|
61
|
+
for (let i = 1; i <= a.length; i++) {
|
|
62
|
+
curr[0] = i;
|
|
63
|
+
const ai = a.charCodeAt(i - 1);
|
|
64
|
+
for (let j = 1; j <= b.length; j++) {
|
|
65
|
+
const cost = ai === b.charCodeAt(j - 1) ? 0 : 1;
|
|
66
|
+
// prev[j] = delete, curr[j-1] = insert, prev[j-1] = substitute.
|
|
67
|
+
curr[j] = Math.min((prev[j] ?? 0) + 1, (curr[j - 1] ?? 0) + 1, (prev[j - 1] ?? 0) + cost);
|
|
68
|
+
}
|
|
69
|
+
const swap = prev;
|
|
70
|
+
prev = curr;
|
|
71
|
+
curr = swap;
|
|
72
|
+
}
|
|
73
|
+
return prev[b.length] ?? 0;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Rank known operationIds by closeness to `query`, returning up to
|
|
77
|
+
* `MAX_SUGGESTIONS` ids. Case-insensitive distance; ties broken by the index's
|
|
78
|
+
* declaration order (stable sort) for deterministic output.
|
|
79
|
+
*/
|
|
80
|
+
export function closestOperationIds(index, query) {
|
|
81
|
+
const target = query.toLowerCase();
|
|
82
|
+
const scored = [...index.operations.keys()].map((id, position) => ({
|
|
83
|
+
id,
|
|
84
|
+
position,
|
|
85
|
+
distance: editDistance(target, id.toLowerCase()),
|
|
86
|
+
}));
|
|
87
|
+
scored.sort((x, y) => x.distance !== y.distance ? x.distance - y.distance : x.position - y.position);
|
|
88
|
+
return scored.slice(0, MAX_SUGGESTIONS).map((s) => s.id);
|
|
89
|
+
}
|
|
90
|
+
/** Project one indexed operation to the public descriptor shape. */
|
|
91
|
+
function toDescriptor(op) {
|
|
92
|
+
return {
|
|
93
|
+
operationId: op.operationId,
|
|
94
|
+
method: op.method,
|
|
95
|
+
path: op.path,
|
|
96
|
+
pathParams: op.pathParams,
|
|
97
|
+
queryParams: op.queryParams,
|
|
98
|
+
summary: op.summary,
|
|
99
|
+
...(op.requestBodySchema !== undefined
|
|
100
|
+
? { requestBodySchema: op.requestBodySchema }
|
|
101
|
+
: {}),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Describe a single operation. Throws `UnknownOperationError` (carrying close
|
|
106
|
+
* matches) when the id is not indexed.
|
|
107
|
+
*/
|
|
108
|
+
export function describeOperation(index, input) {
|
|
109
|
+
const op = index.operations.get(input.operationId);
|
|
110
|
+
if (op === undefined) {
|
|
111
|
+
throw new UnknownOperationError(input.operationId, closestOperationIds(index, input.operationId));
|
|
112
|
+
}
|
|
113
|
+
return toDescriptor(op);
|
|
114
|
+
}
|
|
115
|
+
/** Zod raw shape for the tool's input — a required operationId. */
|
|
116
|
+
export const describeOperationInputShape = {
|
|
117
|
+
operationId: z
|
|
118
|
+
.string()
|
|
119
|
+
.min(1)
|
|
120
|
+
.describe('The operationId to describe (from matcher_list_operations), e.g. ' +
|
|
121
|
+
'"createFeeSchedule".'),
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Register `matcher_describe_operation` on the given server, closed over the boot
|
|
125
|
+
* operation index. On an unknown id the handler returns a tool error naming the
|
|
126
|
+
* closest matches — it never throws out of the handler.
|
|
127
|
+
*/
|
|
128
|
+
export function registerDescribeOperationTool(server, index) {
|
|
129
|
+
server.registerTool('matcher_describe_operation', {
|
|
130
|
+
description: 'Describe one matcher API operation by operationId: returns { ' +
|
|
131
|
+
'operationId, method, path, pathParams, queryParams, ' +
|
|
132
|
+
'requestBodySchema?, summary }. Pure read over the embedded OpenAPI ' +
|
|
133
|
+
'spec — no matcher call, no credential needed. Use it after ' +
|
|
134
|
+
'matcher_list_operations to learn an operation’s exact shape ' +
|
|
135
|
+
'before calling matcher_invoke.',
|
|
136
|
+
inputSchema: describeOperationInputShape,
|
|
137
|
+
}, (args) => {
|
|
138
|
+
try {
|
|
139
|
+
const descriptor = describeOperation(index, {
|
|
140
|
+
operationId: args.operationId,
|
|
141
|
+
});
|
|
142
|
+
return {
|
|
143
|
+
content: [{ type: 'text', text: JSON.stringify(descriptor) }],
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
if (err instanceof UnknownOperationError) {
|
|
148
|
+
return {
|
|
149
|
+
isError: true,
|
|
150
|
+
content: [{ type: 'text', text: err.message }],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
throw err;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=describe-operation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe-operation.js","sourceRoot":"","sources":["../../../src/tools/generic/describe-operation.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,EAAE;AACF,sEAAsE;AACtE,6EAA6E;AAC7E,+EAA+E;AAC/E,gFAAgF;AAChF,eAAe;AACf,EAAE;AACF,gFAAgF;AAChF,2BAA2B;AAC3B,EAAE;AACF,gFAAgF;AAChF,+EAA+E;AAC/E,gFAAgF;AAChF,oDAAoD;AAEpD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA2BvB,6DAA6D;AAC7D,MAAM,eAAe,GAAG,CAAC,CAAA;AAEzB;;;;GAIG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IACrC,WAAW,CAAQ;IACnB,WAAW,CAAmB;IAEvC,YAAY,WAAmB,EAAE,WAA8B;QAC7D,KAAK,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAA;QACpD,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAA;QACnC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;QAC9B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;IAChC,CAAC;CACF;AAED,mFAAmF;AACnF,SAAS,mBAAmB,CAC1B,WAAmB,EACnB,WAA8B;IAE9B,MAAM,IAAI,GAAG,wBAAwB,WAAW,IAAI,CAAA;IACpD,MAAM,OAAO,GACX,WAAW,CAAC,MAAM,GAAG,CAAC;QACpB,CAAC,CAAC,kBAAkB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;QAC7C,CAAC,CAAC,EAAE,CAAA;IACR,OAAO,CACL,IAAI;QACJ,OAAO;QACP,mEAAmE,CACpE,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,CAAS,EAAE,CAAS;IAC/C,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACZ,OAAO,CAAC,CAAA;IACV,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,CAAC,CAAC,MAAM,CAAA;IACjB,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,CAAC,CAAC,MAAM,CAAA;IACjB,CAAC;IAED,IAAI,IAAI,GAAa,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;IACtE,IAAI,IAAI,GAAa,IAAI,KAAK,CAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAEpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QACX,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,EAAE,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC/C,gEAAgE;YAChE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAChB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAClB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EACtB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAC1B,CAAA;QACH,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAA;QACjB,IAAI,GAAG,IAAI,CAAA;QACX,IAAI,GAAG,IAAI,CAAA;IACb,CAAC;IAED,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAqB,EACrB,KAAa;IAEb,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,EAAE,CAAA;IAClC,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QACjE,EAAE;QACF,QAAQ;QACR,QAAQ,EAAE,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,WAAW,EAAE,CAAC;KACjD,CAAC,CAAC,CAAA;IACH,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACnB,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAC9E,CAAA;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;AAC1D,CAAC;AAED,oEAAoE;AACpE,SAAS,YAAY,CAAC,EAAoB;IACxC,OAAO;QACL,WAAW,EAAE,EAAE,CAAC,WAAW;QAC3B,MAAM,EAAE,EAAE,CAAC,MAAM;QACjB,IAAI,EAAE,EAAE,CAAC,IAAI;QACb,UAAU,EAAE,EAAE,CAAC,UAAU;QACzB,WAAW,EAAE,EAAE,CAAC,WAAW;QAC3B,OAAO,EAAE,EAAE,CAAC,OAAO;QACnB,GAAG,CAAC,EAAE,CAAC,iBAAiB,KAAK,SAAS;YACpC,CAAC,CAAC,EAAE,iBAAiB,EAAE,EAAE,CAAC,iBAAiB,EAAE;YAC7C,CAAC,CAAC,EAAE,CAAC;KACR,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAqB,EACrB,KAA6B;IAE7B,MAAM,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IAClD,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACrB,MAAM,IAAI,qBAAqB,CAC7B,KAAK,CAAC,WAAW,EACjB,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,CAC9C,CAAA;IACH,CAAC;IACD,OAAO,YAAY,CAAC,EAAE,CAAC,CAAA;AACzB,CAAC;AAED,mEAAmE;AACnE,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,WAAW,EAAE,CAAC;SACX,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,mEAAmE;QACjE,sBAAsB,CACzB;CACJ,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAC3C,MAAiB,EACjB,KAAqB;IAErB,MAAM,CAAC,YAAY,CACjB,4BAA4B,EAC5B;QACE,WAAW,EACT,+DAA+D;YAC/D,sDAAsD;YACtD,qEAAqE;YACrE,6DAA6D;YAC7D,8DAA8D;YAC9D,gCAAgC;QAClC,WAAW,EAAE,2BAA2B;KACzC,EACD,CAAC,IAAI,EAAE,EAAE;QACP,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,EAAE;gBAC1C,WAAW,EAAE,IAAI,CAAC,WAAW;aAC9B,CAAC,CAAA;YACF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;aAC9D,CAAA;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,qBAAqB,EAAE,CAAC;gBACzC,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;iBAC/C,CAAA;YACH,CAAC;YACD,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC,CACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
// `matcher_invoke` — the keystone of the generic surface.
|
|
2
|
+
//
|
|
3
|
+
// Turns any (operationId + params) into a validated, authenticated matcher call.
|
|
4
|
+
// Steps, executed strictly in order:
|
|
5
|
+
// 1. Look up the operation in the boot index. Unknown id → close-matches error
|
|
6
|
+
// (reuses describe-operation's suggestion machinery for one consistent
|
|
7
|
+
// "did you mean" experience).
|
|
8
|
+
// 2. Substitute path params into the operation's path template. A missing
|
|
9
|
+
// REQUIRED path param → error naming exactly which one.
|
|
10
|
+
// 3. TENANT GUARDRAIL (third rail — tenant isolation): reject any attempt to
|
|
11
|
+
// set a tenant_id / tenantId / tenant key in pathParams, query, or body.
|
|
12
|
+
// Tenant identity derives solely from the relayed JWT — never from input.
|
|
13
|
+
// 4. Validate `body` against the operation's request-body JSON Schema with
|
|
14
|
+
// ajv. On failure, return the ajv errors WITHOUT sending the request — no
|
|
15
|
+
// round-trip is wasted on a call matcher would reject anyway.
|
|
16
|
+
// 5. requireMatcherClient() (fail-closed on a missing token), then
|
|
17
|
+
// client.request({ method, path, query, body }).
|
|
18
|
+
// 6. On MatcherApiError, map the RFC 9457 problem via the shared toToolError
|
|
19
|
+
// so status/title/detail/code survive — never swallowed into a generic msg.
|
|
20
|
+
// 7. On success, return the parsed JSON.
|
|
21
|
+
//
|
|
22
|
+
// Pagination: `limit`/`cursor` pass through untouched and matcher's
|
|
23
|
+
// { items, nextCursor, hasMore } is returned as-is. NO auto-pagination — a
|
|
24
|
+
// single op can return unbounded data, so the model paginates by re-calling
|
|
25
|
+
// with the cursor.
|
|
26
|
+
// ajv ships CJS with `module.exports = Ajv2020`, which collapses the default
|
|
27
|
+
// export into the module namespace; under NodeNext ESM only the NAMED `Ajv2020`
|
|
28
|
+
// resolves to the constructable class (the default import is the non-constructable
|
|
29
|
+
// namespace object). Matcher's spec is OAS 3.1 (JSON Schema 2020-12), so the 2020
|
|
30
|
+
// build is the right dialect.
|
|
31
|
+
import { Ajv2020 } from 'ajv/dist/2020.js';
|
|
32
|
+
import { z } from 'zod';
|
|
33
|
+
import { requireMatcherClient, UnauthenticatedError, } from '../../auth/request-token.js';
|
|
34
|
+
import { MatcherApiError, } from '../../matcher/client.js';
|
|
35
|
+
import { closestOperationIds } from './describe-operation.js';
|
|
36
|
+
import { isMatcherApiError, toToolError } from '../tool-error.js';
|
|
37
|
+
/** Keys that would let a caller assert a tenant — categorically forbidden. */
|
|
38
|
+
const FORBIDDEN_TENANT_KEYS = ['tenant_id', 'tenantId', 'tenant'];
|
|
39
|
+
/** A param map carrying a forbidden tenant key, surfaced for the error message. */
|
|
40
|
+
function tenantKeyIn(source) {
|
|
41
|
+
if (source === undefined) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
for (const forbidden of FORBIDDEN_TENANT_KEYS) {
|
|
45
|
+
if (Object.prototype.hasOwnProperty.call(source, forbidden)) {
|
|
46
|
+
return forbidden;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
/** Errors `matcher_invoke` raises before any matcher call — each maps to a tool error. */
|
|
52
|
+
export class InvokeError extends Error {
|
|
53
|
+
constructor(message) {
|
|
54
|
+
super(message);
|
|
55
|
+
this.name = 'InvokeError';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** Unknown operationId — names the closest known ids and points at list_operations. */
|
|
59
|
+
export class InvokeUnknownOperationError extends InvokeError {
|
|
60
|
+
suggestions;
|
|
61
|
+
constructor(operationId, suggestions) {
|
|
62
|
+
const closest = suggestions.length > 0 ? ` Did you mean: ${suggestions.join(', ')}?` : '';
|
|
63
|
+
super(`Unknown operationId "${operationId}".${closest} ` +
|
|
64
|
+
'Call matcher_list_operations to browse the available operations.');
|
|
65
|
+
this.name = 'InvokeUnknownOperationError';
|
|
66
|
+
this.suggestions = suggestions;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** A required path param was not supplied — names exactly which one. */
|
|
70
|
+
export class MissingPathParamError extends InvokeError {
|
|
71
|
+
paramName;
|
|
72
|
+
constructor(paramName, operationId) {
|
|
73
|
+
super(`Missing required path parameter "${paramName}" for operation ` +
|
|
74
|
+
`"${operationId}". Provide it under pathParams.`);
|
|
75
|
+
this.name = 'MissingPathParamError';
|
|
76
|
+
this.paramName = paramName;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** A tenant_id/tenantId/tenant key was supplied — the tenant guardrail rejection. */
|
|
80
|
+
export class TenantGuardrailError extends InvokeError {
|
|
81
|
+
key;
|
|
82
|
+
location;
|
|
83
|
+
constructor(key, location) {
|
|
84
|
+
super(`Rejected: "${key}" may not be set in ${location}. Tenant identity is ` +
|
|
85
|
+
'derived solely from your bearer token (the matcher JWT) and can never ' +
|
|
86
|
+
'be supplied as a parameter or body field.');
|
|
87
|
+
this.name = 'TenantGuardrailError';
|
|
88
|
+
this.key = key;
|
|
89
|
+
this.location = location;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** Body failed JSON-Schema validation — carries the ajv errors for the model. */
|
|
93
|
+
export class BodyValidationError extends InvokeError {
|
|
94
|
+
validationErrors;
|
|
95
|
+
constructor(operationId, validationErrors) {
|
|
96
|
+
super(`Request body failed validation for operation "${operationId}". ` +
|
|
97
|
+
'Fix the listed errors and retry; no request was sent.');
|
|
98
|
+
this.name = 'BodyValidationError';
|
|
99
|
+
this.validationErrors = validationErrors;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Substitute path params into a templated path, e.g.
|
|
104
|
+
* `/v1/fee-schedules/{scheduleId}` + `{ scheduleId: 'abc' }` → `/v1/fee-schedules/abc`.
|
|
105
|
+
* A required template segment with no matching param throws MissingPathParamError.
|
|
106
|
+
* Each value is URL-encoded so an id with reserved characters can't break the path.
|
|
107
|
+
*/
|
|
108
|
+
export function substitutePath(op, pathParams) {
|
|
109
|
+
return op.path.replace(/\{([^}]+)\}/g, (_match, rawName) => {
|
|
110
|
+
const name = rawName;
|
|
111
|
+
const value = pathParams?.[name];
|
|
112
|
+
if (value === undefined || value === '') {
|
|
113
|
+
throw new MissingPathParamError(name, op.operationId);
|
|
114
|
+
}
|
|
115
|
+
return encodeURIComponent(value);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Coerce a body that arrived as a JSON string back to its parsed value.
|
|
120
|
+
*
|
|
121
|
+
* `body` carries no concrete type in the tool's input schema — it is per-operation
|
|
122
|
+
* free-form, declared `z.unknown()`, so its advertised JSON Schema is `{}` (no
|
|
123
|
+
* `type`). Faced with an untyped param, some MCP harnesses serialize the value as
|
|
124
|
+
* a JSON string, so matcher receives `"{\"name\":\"x\"}"` (a string) and rejects
|
|
125
|
+
* it with "must be object". Parsing it back here — before the tenant guardrail and
|
|
126
|
+
* the ajv schema validation — makes the generic surface work regardless of how a
|
|
127
|
+
* harness serializes the field. Non-string bodies (already-parsed objects/arrays)
|
|
128
|
+
* and strings that do not parse as JSON pass through untouched, so a real string
|
|
129
|
+
* body still reaches matcher and the authoritative ajv/RFC-9457 error reports it.
|
|
130
|
+
*/
|
|
131
|
+
export function normalizeBody(body) {
|
|
132
|
+
if (typeof body !== 'string') {
|
|
133
|
+
return body;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
return JSON.parse(body);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return body;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Compile (and cache) an ajv validator for an operation's request-body schema.
|
|
144
|
+
* The matcher spec is OAS 3.1 (a JSON Schema 2020-12 dialect), so we use ajv's
|
|
145
|
+
* 2020 build. Compilation is memoized per operation since the schema is immutable
|
|
146
|
+
* boot data. `strict: false` keeps ajv from rejecting OpenAPI vocabulary it does
|
|
147
|
+
* not model (e.g. `example`, `nullable`) — we validate shape, not OpenAPI lint.
|
|
148
|
+
*/
|
|
149
|
+
function makeValidatorFactory() {
|
|
150
|
+
const ajv = new Ajv2020({ strict: false, allErrors: true });
|
|
151
|
+
const cache = new Map();
|
|
152
|
+
return (operationId, schema) => {
|
|
153
|
+
const cached = cache.get(operationId);
|
|
154
|
+
if (cached !== undefined) {
|
|
155
|
+
return cached;
|
|
156
|
+
}
|
|
157
|
+
const validate = ajv.compile(schema);
|
|
158
|
+
cache.set(operationId, validate);
|
|
159
|
+
return validate;
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/** The pure core of invoke: assemble + validate + dispatch, no SDK plumbing. */
|
|
163
|
+
export class Invoker {
|
|
164
|
+
index;
|
|
165
|
+
getValidator;
|
|
166
|
+
constructor(index) {
|
|
167
|
+
this.index = index;
|
|
168
|
+
this.getValidator = makeValidatorFactory();
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Build the MatcherRequest for an invoke input, running steps 1–4 (lookup,
|
|
172
|
+
* path substitution, tenant guardrail, body validation). Throws an InvokeError
|
|
173
|
+
* subclass on any pre-flight failure — nothing reaches matcher until this
|
|
174
|
+
* returns a request.
|
|
175
|
+
*/
|
|
176
|
+
assemble(input) {
|
|
177
|
+
// (1) lookup
|
|
178
|
+
const op = this.index.operations.get(input.operationId);
|
|
179
|
+
if (op === undefined) {
|
|
180
|
+
throw new InvokeUnknownOperationError(input.operationId, closestOperationIds(this.index, input.operationId));
|
|
181
|
+
}
|
|
182
|
+
// Coerce a stringified body back to its real value before any inspection,
|
|
183
|
+
// so the guardrail and validation below see the actual object/array a harness
|
|
184
|
+
// may have serialized as a JSON string. See normalizeBody.
|
|
185
|
+
const body = normalizeBody(input.body);
|
|
186
|
+
// (3a) tenant guardrail on pathParams + query (body checked at 3b).
|
|
187
|
+
// Run before substitution so a tenant key is rejected even if it also
|
|
188
|
+
// happens to be (mis)named like a path segment.
|
|
189
|
+
const pathTenant = tenantKeyIn(input.pathParams);
|
|
190
|
+
if (pathTenant !== undefined) {
|
|
191
|
+
throw new TenantGuardrailError(pathTenant, 'pathParams');
|
|
192
|
+
}
|
|
193
|
+
const queryTenant = tenantKeyIn(input.query);
|
|
194
|
+
if (queryTenant !== undefined) {
|
|
195
|
+
throw new TenantGuardrailError(queryTenant, 'query');
|
|
196
|
+
}
|
|
197
|
+
// (3b) tenant guardrail on a top-level object body.
|
|
198
|
+
if (body !== null && typeof body === 'object' && !Array.isArray(body)) {
|
|
199
|
+
const bodyTenant = tenantKeyIn(body);
|
|
200
|
+
if (bodyTenant !== undefined) {
|
|
201
|
+
throw new TenantGuardrailError(bodyTenant, 'body');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// (2) path substitution (after guardrail, before body validation).
|
|
205
|
+
const path = substitutePath(op, input.pathParams);
|
|
206
|
+
// (4) body validation against the op's request-body schema, if it has one.
|
|
207
|
+
if (op.requestBodySchema !== undefined && body !== undefined) {
|
|
208
|
+
const validate = this.getValidator(op.operationId, op.requestBodySchema);
|
|
209
|
+
if (!validate(body)) {
|
|
210
|
+
throw new BodyValidationError(op.operationId, validate.errors ?? []);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
method: op.method,
|
|
215
|
+
path,
|
|
216
|
+
...(input.query !== undefined ? { query: input.query } : {}),
|
|
217
|
+
...(body !== undefined ? { body } : {}),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/** Render a pre-flight InvokeError (steps 1–4) as a structured MCP tool error. */
|
|
222
|
+
function preflightToToolError(err) {
|
|
223
|
+
const detail = { error: err.name, message: err.message };
|
|
224
|
+
if (err instanceof BodyValidationError) {
|
|
225
|
+
detail.validationErrors = err.validationErrors;
|
|
226
|
+
}
|
|
227
|
+
else if (err instanceof InvokeUnknownOperationError) {
|
|
228
|
+
detail.suggestions = err.suggestions;
|
|
229
|
+
}
|
|
230
|
+
else if (err instanceof MissingPathParamError) {
|
|
231
|
+
detail.paramName = err.paramName;
|
|
232
|
+
}
|
|
233
|
+
else if (err instanceof TenantGuardrailError) {
|
|
234
|
+
detail.key = err.key;
|
|
235
|
+
detail.location = err.location;
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
isError: true,
|
|
239
|
+
content: [
|
|
240
|
+
{ type: 'text', text: err.message },
|
|
241
|
+
{ type: 'text', text: JSON.stringify(detail) },
|
|
242
|
+
],
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/** Zod raw shape for `matcher_invoke` input. */
|
|
246
|
+
export const invokeInputShape = {
|
|
247
|
+
operationId: z
|
|
248
|
+
.string()
|
|
249
|
+
.min(1)
|
|
250
|
+
.describe('The operationId to invoke (from matcher_list_operations / ' +
|
|
251
|
+
'matcher_describe_operation), e.g. "createFeeSchedule".'),
|
|
252
|
+
pathParams: z
|
|
253
|
+
.record(z.string(), z.string())
|
|
254
|
+
.optional()
|
|
255
|
+
.describe('Path parameter values keyed by name, e.g. { "scheduleId": "..." }. ' +
|
|
256
|
+
'Required for any {param} in the operation path. A tenant_id/tenantId/' +
|
|
257
|
+
'tenant key is rejected — tenant comes from your token, never input.'),
|
|
258
|
+
query: z
|
|
259
|
+
.record(z.string(), z.union([z.string(), z.number()]))
|
|
260
|
+
.optional()
|
|
261
|
+
.describe('Query string parameters. Pass limit/cursor here for paginated list ' +
|
|
262
|
+
'operations; the response carries { items, nextCursor, hasMore } and ' +
|
|
263
|
+
'you paginate by re-invoking with the returned cursor (no ' +
|
|
264
|
+
'auto-pagination). A tenant key is rejected.'),
|
|
265
|
+
body: z
|
|
266
|
+
.unknown()
|
|
267
|
+
.optional()
|
|
268
|
+
.describe('JSON request body. Validated against the operation’s request-body ' +
|
|
269
|
+
'schema before sending; on failure the validation errors are returned ' +
|
|
270
|
+
'and no request is made. A tenant key is rejected.'),
|
|
271
|
+
};
|
|
272
|
+
/**
|
|
273
|
+
* Run an already-assembled request through the relay: fail-closed auth, dispatch,
|
|
274
|
+
* and RFC 9457 → tool-error mapping (steps 5–7). Split from `assemble` so the
|
|
275
|
+
* pure pre-flight and the IO-bearing dispatch are independently testable.
|
|
276
|
+
*
|
|
277
|
+
* `clientFor` is injectable for tests; production passes nothing and gets the
|
|
278
|
+
* request-scoped, fail-closed `requireMatcherClient`.
|
|
279
|
+
*/
|
|
280
|
+
export async function dispatch(request, extra, clientFor = requireMatcherClient) {
|
|
281
|
+
let client;
|
|
282
|
+
try {
|
|
283
|
+
// (5) fail-closed on a missing/empty/non-Bearer credential.
|
|
284
|
+
client = clientFor(extra);
|
|
285
|
+
}
|
|
286
|
+
catch (err) {
|
|
287
|
+
if (err instanceof UnauthenticatedError) {
|
|
288
|
+
return { isError: true, content: [{ type: 'text', text: err.message }] };
|
|
289
|
+
}
|
|
290
|
+
throw err;
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
const result = await client.request(request);
|
|
294
|
+
// (7) success → parsed JSON, returned as-is (incl. {items,nextCursor,hasMore}).
|
|
295
|
+
return { content: [{ type: 'text', text: JSON.stringify(result ?? null) }] };
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
// (6) RFC 9457 problem → structured tool error, status/title/detail/code kept.
|
|
299
|
+
if (isMatcherApiError(err)) {
|
|
300
|
+
return toToolError(err);
|
|
301
|
+
}
|
|
302
|
+
throw err;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Register `matcher_invoke` on the given server, closed over the boot operation
|
|
307
|
+
* index. The handler assembles + validates (pre-flight), then dispatches with the
|
|
308
|
+
* caller's relayed token. Every failure becomes a structured tool error; nothing
|
|
309
|
+
* unexpected escapes the handler.
|
|
310
|
+
*/
|
|
311
|
+
export function registerInvokeTool(server, index) {
|
|
312
|
+
const invoker = new Invoker(index);
|
|
313
|
+
server.registerTool('matcher_invoke', {
|
|
314
|
+
description: 'Invoke any matcher API operation by operationId. Substitutes path ' +
|
|
315
|
+
'params, validates the body against the embedded OpenAPI schema (errors ' +
|
|
316
|
+
'are returned without sending the request), relays your bearer token, ' +
|
|
317
|
+
'and returns matcher’s JSON — or a structured error carrying the RFC ' +
|
|
318
|
+
'9457 problem (status/title/detail/code). Tenant is derived from your ' +
|
|
319
|
+
'token; a tenant_id/tenantId/tenant key is rejected. Use ' +
|
|
320
|
+
'matcher_describe_operation first to learn an operation’s exact shape. ' +
|
|
321
|
+
'For paginated lists, pass limit/cursor in query and re-invoke with the ' +
|
|
322
|
+
'returned cursor (no auto-pagination).',
|
|
323
|
+
inputSchema: invokeInputShape,
|
|
324
|
+
}, async (args, extra) => {
|
|
325
|
+
let request;
|
|
326
|
+
try {
|
|
327
|
+
request = invoker.assemble({
|
|
328
|
+
operationId: args.operationId,
|
|
329
|
+
...(args.pathParams !== undefined ? { pathParams: args.pathParams } : {}),
|
|
330
|
+
...(args.query !== undefined ? { query: args.query } : {}),
|
|
331
|
+
...(args.body !== undefined ? { body: args.body } : {}),
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
catch (err) {
|
|
335
|
+
if (err instanceof InvokeError) {
|
|
336
|
+
return preflightToToolError(err);
|
|
337
|
+
}
|
|
338
|
+
throw err;
|
|
339
|
+
}
|
|
340
|
+
return dispatch(request, extra);
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
//# sourceMappingURL=invoke.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invoke.js","sourceRoot":"","sources":["../../../src/tools/generic/invoke.ts"],"names":[],"mappings":"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"}
|