feat(mcp): expose orders.quote_match_sweep
Hermes (n8n) drops the AGENT_API_KEY on direct REST calls, so anything n8n needs to run must exist as an MCP tool. This forwards the agent's JSON-RPC call to POST /api/v1/orders/quote-match/sweep, mirroring the existing orders.set_quote forwarding pattern. Updated the tools/list expected-list test to include the new tool so the catalog stays self-documenting. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
4e54fd6218
commit
e374513fba
2 changed files with 66 additions and 0 deletions
|
|
@ -229,6 +229,9 @@ const toolNames = body.result.tools.map((t: { name: string }) => t.name);
|
|||
// Hermes unblock (PR 1, 2026-08-21):
|
||||
// set_quote writes the orders.quote relation for an existing order
|
||||
"orders.set_quote",
|
||||
// Backlog sweep for the historical orders the intake matcher
|
||||
// never saw (2026-08-30).
|
||||
"orders.quote_match_sweep",
|
||||
"orders.add_note",
|
||||
"collection_pool.list",
|
||||
"order_items.update_status",
|
||||
|
|
|
|||
|
|
@ -870,6 +870,31 @@ const tools = [
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "orders.quote_match_sweep",
|
||||
description:
|
||||
"Run quote auto-detection over orders that have never been attempted. Mirrors the REST " +
|
||||
"POST /api/v1/orders/quote-match/sweep endpoint.\n\n" +
|
||||
"Why this exists: orders created from now on are matched automatically at intake. This is the " +
|
||||
"catch-up path for the historical backlog and for orders whose line items changed after " +
|
||||
"creation.\n\n" +
|
||||
"Writes ONLY the soft suggestion (`potential_quote` + `potential_quote_confidence`). It never " +
|
||||
"writes the hard `orders.quote` link — promoting a suggestion is a deliberate human action via " +
|
||||
"`orders.set_quote`.\n\n" +
|
||||
"Processes one batch per call. Re-run until the returned `remaining` is 0.\n\n" +
|
||||
"Returns `{ processed, suggested, noMatch, failed, remaining, ageGaps }`. `ageGaps` buckets the " +
|
||||
"quote-to-order age in days for every match found (d0_30, d31_60, d61_90, d91_180, d181_365, " +
|
||||
"d365_plus, total) — use it to check whether the 90-day fuzzy search window is set correctly.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
limit: {
|
||||
type: "number",
|
||||
description: "Orders to process in this batch. 1..500, default 100.",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "orders.add_note",
|
||||
description:
|
||||
|
|
@ -3922,6 +3947,44 @@ export async function POST(req: NextRequest) {
|
|||
});
|
||||
}
|
||||
|
||||
if (toolName === "orders.quote_match_sweep") {
|
||||
// Forward to the REST route — keeps the surface in lock-step
|
||||
// with the agent-auth route and surfaces the structured 4xx/5xx
|
||||
// data without re-implementing the error envelope here.
|
||||
const limit = typeof args.limit === "number" ? args.limit : undefined;
|
||||
const upstreamRes = await fetch(
|
||||
`${upstreamOrigin(req)}/api/v1/orders/quote-match/sweep`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}`,
|
||||
},
|
||||
body: JSON.stringify(limit === undefined ? {} : { limit }),
|
||||
},
|
||||
);
|
||||
const data = await upstreamRes.json().catch(() => ({}));
|
||||
if (!upstreamRes.ok) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
jsonrpc: "2.0",
|
||||
id: body.id ?? null,
|
||||
error: {
|
||||
code: -32010,
|
||||
message: `orders.quote_match_sweep upstream ${upstreamRes.status}: ${data?.error ?? "unknown"}`,
|
||||
data,
|
||||
},
|
||||
},
|
||||
{ status: 200 },
|
||||
);
|
||||
}
|
||||
return NextResponse.json({
|
||||
jsonrpc: "2.0",
|
||||
id: body.id ?? null,
|
||||
result: { content: [{ type: "text", text: JSON.stringify(data) }] },
|
||||
});
|
||||
}
|
||||
|
||||
if (toolName === "orders.add_note") {
|
||||
const orderId = String(args.id || "").trim();
|
||||
if (!orderId) throw new Error("Missing id for orders.add_note.");
|
||||
|
|
|
|||
Loading…
Reference in a new issue