@lerianstudio/matcher-mcp 1.3.0 → 1.4.0-beta.1
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/README.md +26 -0
- package/dist/auth/request-token.js +50 -2
- package/dist/auth/request-token.js.map +1 -1
- package/dist/config.js +61 -0
- package/dist/config.js.map +1 -1
- package/dist/copilot/agent.js +181 -0
- package/dist/copilot/agent.js.map +1 -0
- package/dist/copilot/provider-anthropic.js +151 -0
- package/dist/copilot/provider-anthropic.js.map +1 -0
- package/dist/copilot/provider-factory.js +46 -0
- package/dist/copilot/provider-factory.js.map +1 -0
- package/dist/copilot/provider-openrouter.js +154 -0
- package/dist/copilot/provider-openrouter.js.map +1 -0
- package/dist/copilot/provider-shared.js +23 -0
- package/dist/copilot/provider-shared.js.map +1 -0
- package/dist/copilot/provider.js +15 -0
- package/dist/copilot/provider.js.map +1 -0
- package/dist/copilot/rate-limit.js +77 -0
- package/dist/copilot/rate-limit.js.map +1 -0
- package/dist/copilot/sse.js +69 -0
- package/dist/copilot/sse.js.map +1 -0
- package/dist/copilot/system-prompt.js +80 -0
- package/dist/copilot/system-prompt.js.map +1 -0
- package/dist/copilot/tenant-config.js +145 -0
- package/dist/copilot/tenant-config.js.map +1 -0
- package/dist/copilot/tools.js +241 -0
- package/dist/copilot/tools.js.map +1 -0
- package/dist/copilot/turns-handler.js +322 -0
- package/dist/copilot/turns-handler.js.map +1 -0
- package/dist/observability/otel.js +184 -2
- package/dist/observability/otel.js.map +1 -1
- package/dist/spec/openapi.yaml +1 -1
- package/dist/transport/body-limit.js +27 -0
- package/dist/transport/body-limit.js.map +1 -1
- package/dist/transport/http.js +35 -25
- package/dist/transport/http.js.map +1 -1
- package/package.json +3 -1
|
@@ -19,8 +19,14 @@
|
|
|
19
19
|
// Token-relay rule (NON-NEGOTIABLE): telemetry records ONLY the tool name, the
|
|
20
20
|
// call outcome (ok / error), and — on a matcher API failure — the matcher HTTP
|
|
21
21
|
// status. It NEVER records the caller's bearer token, raw arguments, or request
|
|
22
|
-
// headers, in any span attribute, metric attribute, event, or log.
|
|
23
|
-
//
|
|
22
|
+
// headers, in any span attribute, metric attribute, event, or log.
|
|
23
|
+
//
|
|
24
|
+
// Tenant labelling (copilot loop, task 4.2.1): the copilot span tree MAY carry a
|
|
25
|
+
// `copilot.tenant` attribute — the UNVERIFIED, key-only org identifier decoded
|
|
26
|
+
// from the relayed JWT (getRequestTenantId). It is an organization label for
|
|
27
|
+
// scoping/aggregation, token-free and not a credential; matcher still owns
|
|
28
|
+
// enforcement via the relayed token. It is kept on SPANS only (per-turn), never
|
|
29
|
+
// pushed as a metric label (cardinality), and NEVER accompanies a token/secret.
|
|
24
30
|
import { context, metrics, propagation, SpanStatusCode, trace, ValueType, } from '@opentelemetry/api';
|
|
25
31
|
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
|
|
26
32
|
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
|
@@ -35,6 +41,17 @@ const INSTRUMENTATION_SCOPE = 'matcher-mcp';
|
|
|
35
41
|
const ATTR_TOOL_NAME = 'mcp.tool.name';
|
|
36
42
|
const ATTR_OUTCOME = 'mcp.tool.outcome';
|
|
37
43
|
const ATTR_MATCHER_STATUS = 'matcher.http.status';
|
|
44
|
+
/**
|
|
45
|
+
* Copilot-loop attribute keys (task 4.2.1). `copilot.tenant` is the key-only org
|
|
46
|
+
* identifier — a span label only, never a metric label or a credential.
|
|
47
|
+
*/
|
|
48
|
+
const ATTR_COPILOT_PROVIDER = 'copilot.provider';
|
|
49
|
+
const ATTR_COPILOT_MODEL = 'copilot.model';
|
|
50
|
+
const ATTR_COPILOT_TENANT = 'copilot.tenant';
|
|
51
|
+
const ATTR_COPILOT_MAX_ITERATIONS = 'copilot.max_iterations';
|
|
52
|
+
const ATTR_COPILOT_STOP = 'copilot.stop';
|
|
53
|
+
const ATTR_COPILOT_TOOL_OUTCOME = 'copilot.tool.outcome';
|
|
54
|
+
const ATTR_COPILOT_TOKEN_DIRECTION = 'copilot.token.direction';
|
|
38
55
|
/** Outcome attribute values — the only two states a tool call reports. */
|
|
39
56
|
const OUTCOME_OK = 'ok';
|
|
40
57
|
const OUTCOME_ERROR = 'error';
|
|
@@ -205,6 +222,171 @@ export async function instrumentToolCall(name, fn) {
|
|
|
205
222
|
}
|
|
206
223
|
});
|
|
207
224
|
}
|
|
225
|
+
// --- Copilot agent-loop instrumentation (task 4.2.1) ---------------------------
|
|
226
|
+
//
|
|
227
|
+
// The copilot loop opens a `copilot.turn` parent span with `copilot.provider.stream`
|
|
228
|
+
// and `copilot.tool.<name>` children. Wrapping the tool execution in an ACTIVE
|
|
229
|
+
// child span ALSO fixes the previously-dead matcher trace correlation: with a
|
|
230
|
+
// span active, `injectTraceContext` in the matcher client writes a real
|
|
231
|
+
// traceparent instead of an empty context.
|
|
232
|
+
//
|
|
233
|
+
// The tool wrapper deliberately does NOT reuse `instrumentToolCall`: the copilot
|
|
234
|
+
// read executor (`executeReadTool`) swallows every error into an `isError` result
|
|
235
|
+
// rather than throwing, so `instrumentToolCall`'s catch never fires and every
|
|
236
|
+
// span would falsely read `ok`. `instrumentCopilotTool` inspects the returned
|
|
237
|
+
// result's `isError` instead.
|
|
238
|
+
/** Lazily-created copilot metrics, shared across turns (no-op when telemetry off). */
|
|
239
|
+
let copilotTurnCounter;
|
|
240
|
+
let copilotTurnDuration;
|
|
241
|
+
let copilotTokenCounter;
|
|
242
|
+
function getCopilotTurnCounter() {
|
|
243
|
+
copilotTurnCounter ??= getMeter().createCounter('copilot.turns', {
|
|
244
|
+
description: 'Count of copilot agent turns, labeled by provider + stop reason.',
|
|
245
|
+
valueType: ValueType.INT,
|
|
246
|
+
});
|
|
247
|
+
return copilotTurnCounter;
|
|
248
|
+
}
|
|
249
|
+
function getCopilotTurnDuration() {
|
|
250
|
+
copilotTurnDuration ??= getMeter().createHistogram('copilot.turn.duration', {
|
|
251
|
+
description: 'Latency of a copilot agent turn in milliseconds.',
|
|
252
|
+
unit: 'ms',
|
|
253
|
+
valueType: ValueType.DOUBLE,
|
|
254
|
+
});
|
|
255
|
+
return copilotTurnDuration;
|
|
256
|
+
}
|
|
257
|
+
function getCopilotTokenCounter() {
|
|
258
|
+
copilotTokenCounter ??= getMeter().createCounter('copilot.tokens', {
|
|
259
|
+
description: 'Copilot LLM token usage, labeled by provider + direction (input/output).',
|
|
260
|
+
valueType: ValueType.INT,
|
|
261
|
+
});
|
|
262
|
+
return copilotTokenCounter;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Wrap one agent turn in a `copilot.turn` active parent span + turn metrics. The
|
|
266
|
+
* span carries provider/model/tenant/max_iterations and, set on exit via the
|
|
267
|
+
* `setStop` callback, `copilot.stop` (`end` | `proposal` | `token_limit` |
|
|
268
|
+
* `iteration_limit` | `aborted`). Records `copilot.turns` + `copilot.turn.duration`
|
|
269
|
+
* labeled by provider + stop (tenant is NOT a metric label — cardinality). No-op
|
|
270
|
+
* safe: with telemetry disabled this is just `fn(setStop)`.
|
|
271
|
+
*/
|
|
272
|
+
export async function instrumentCopilotTurn(attrs, fn) {
|
|
273
|
+
const tracer = getTracer();
|
|
274
|
+
const counter = getCopilotTurnCounter();
|
|
275
|
+
const histogram = getCopilotTurnDuration();
|
|
276
|
+
const startedAt = Date.now();
|
|
277
|
+
let stop = 'end';
|
|
278
|
+
const setStop = (next) => {
|
|
279
|
+
stop = next;
|
|
280
|
+
};
|
|
281
|
+
return tracer.startActiveSpan('copilot.turn', async (span) => {
|
|
282
|
+
span.setAttribute(ATTR_COPILOT_PROVIDER, attrs.provider);
|
|
283
|
+
if (attrs.model !== undefined) {
|
|
284
|
+
span.setAttribute(ATTR_COPILOT_MODEL, attrs.model);
|
|
285
|
+
}
|
|
286
|
+
if (attrs.tenant !== undefined) {
|
|
287
|
+
span.setAttribute(ATTR_COPILOT_TENANT, attrs.tenant);
|
|
288
|
+
}
|
|
289
|
+
span.setAttribute(ATTR_COPILOT_MAX_ITERATIONS, attrs.maxIterations);
|
|
290
|
+
try {
|
|
291
|
+
await fn(setStop);
|
|
292
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
// A crashed turn is its own terminal label: without this it defaults to
|
|
296
|
+
// 'end' and records under the clean-completion series, hiding the error
|
|
297
|
+
// rate in the very copilot.turns counter that scopes it.
|
|
298
|
+
stop = 'error';
|
|
299
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
300
|
+
throw err;
|
|
301
|
+
}
|
|
302
|
+
finally {
|
|
303
|
+
span.setAttribute(ATTR_COPILOT_STOP, stop);
|
|
304
|
+
counter.add(1, { [ATTR_COPILOT_PROVIDER]: attrs.provider, [ATTR_COPILOT_STOP]: stop });
|
|
305
|
+
histogram.record(Date.now() - startedAt, { [ATTR_COPILOT_PROVIDER]: attrs.provider });
|
|
306
|
+
span.end();
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Wrap one provider round-trip in a `copilot.provider.stream` child span. Records
|
|
312
|
+
* only provider/model (no prompt content, no token). No-op safe.
|
|
313
|
+
*/
|
|
314
|
+
export async function instrumentProviderStream(attrs, fn) {
|
|
315
|
+
const tracer = getTracer();
|
|
316
|
+
return tracer.startActiveSpan('copilot.provider.stream', async (span) => {
|
|
317
|
+
span.setAttribute(ATTR_COPILOT_PROVIDER, attrs.provider);
|
|
318
|
+
if (attrs.model !== undefined) {
|
|
319
|
+
span.setAttribute(ATTR_COPILOT_MODEL, attrs.model);
|
|
320
|
+
}
|
|
321
|
+
try {
|
|
322
|
+
const result = await fn();
|
|
323
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
324
|
+
return result;
|
|
325
|
+
}
|
|
326
|
+
catch (err) {
|
|
327
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
328
|
+
throw err;
|
|
329
|
+
}
|
|
330
|
+
finally {
|
|
331
|
+
span.end();
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Wrap one tool execution in a `copilot.tool.<name>` active child span. The tool
|
|
337
|
+
* result is inspected for `isError` (the read executor never throws — it swallows
|
|
338
|
+
* every error into `isError`), so a swallowed matcher failure records
|
|
339
|
+
* `outcome=error`, not a false `ok`. The active span also gives the inner matcher
|
|
340
|
+
* HTTP call a real parent for trace correlation. No-op safe. Rethrows only on an
|
|
341
|
+
* unexpected throw (defensive; the executor does not throw).
|
|
342
|
+
*/
|
|
343
|
+
export async function instrumentCopilotTool(name, fn) {
|
|
344
|
+
const tracer = getTracer();
|
|
345
|
+
return tracer.startActiveSpan(`copilot.tool.${name}`, async (span) => {
|
|
346
|
+
span.setAttribute(ATTR_TOOL_NAME, name);
|
|
347
|
+
try {
|
|
348
|
+
const result = await fn();
|
|
349
|
+
const outcome = result.isError === true ? OUTCOME_ERROR : OUTCOME_OK;
|
|
350
|
+
span.setAttribute(ATTR_COPILOT_TOOL_OUTCOME, outcome);
|
|
351
|
+
span.setStatus({
|
|
352
|
+
code: result.isError === true ? SpanStatusCode.ERROR : SpanStatusCode.OK,
|
|
353
|
+
});
|
|
354
|
+
return result;
|
|
355
|
+
}
|
|
356
|
+
catch (err) {
|
|
357
|
+
span.setAttribute(ATTR_COPILOT_TOOL_OUTCOME, OUTCOME_ERROR);
|
|
358
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
359
|
+
throw err;
|
|
360
|
+
}
|
|
361
|
+
finally {
|
|
362
|
+
span.end();
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Record a round's token usage on the `copilot.tokens` counter, split by
|
|
368
|
+
* direction (input/output) and labeled by provider. A no-op when usage is
|
|
369
|
+
* undefined (a provider that omits it) — metering fails open, never throws.
|
|
370
|
+
*/
|
|
371
|
+
export function recordCopilotTokens(provider, usage) {
|
|
372
|
+
if (usage === undefined) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
const counter = getCopilotTokenCounter();
|
|
376
|
+
// Coalesce a non-finite field to 0 — symmetric with the running-sum path's
|
|
377
|
+
// usageTokens (agent.ts). Providers already coalesce, so this is defense in
|
|
378
|
+
// depth: a misreporting NaN/±Infinity never reaches the counter as NaN.
|
|
379
|
+
const input = Number.isFinite(usage.inputTokens) ? usage.inputTokens : 0;
|
|
380
|
+
const output = Number.isFinite(usage.outputTokens) ? usage.outputTokens : 0;
|
|
381
|
+
counter.add(input, {
|
|
382
|
+
[ATTR_COPILOT_PROVIDER]: provider,
|
|
383
|
+
[ATTR_COPILOT_TOKEN_DIRECTION]: 'input',
|
|
384
|
+
});
|
|
385
|
+
counter.add(output, {
|
|
386
|
+
[ATTR_COPILOT_PROVIDER]: provider,
|
|
387
|
+
[ATTR_COPILOT_TOKEN_DIRECTION]: 'output',
|
|
388
|
+
});
|
|
389
|
+
}
|
|
208
390
|
/**
|
|
209
391
|
* Inject the current W3C trace context into an outbound header object so the
|
|
210
392
|
* matcher call is a child of the tool-call span (MCP → matcher correlation in
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otel.js","sourceRoot":"","sources":["../../src/observability/otel.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,EAAE;AACF,8EAA8E;AAC9E,+EAA+E;AAC/E,8EAA8E;AAC9E,gFAAgF;AAChF,sFAAsF;AACtF,mDAAmD;AACnD,EAAE;AACF,iEAAiE;AACjE,gFAAgF;AAChF,gFAAgF;AAChF,sEAAsE;AACtE,wCAAwC;AACxC,iFAAiF;AACjF,+EAA+E;AAC/E,iCAAiC;AACjC,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,gFAAgF;AAChF,6EAA6E;AAC7E,
|
|
1
|
+
{"version":3,"file":"otel.js","sourceRoot":"","sources":["../../src/observability/otel.ts"],"names":[],"mappings":"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"}
|
package/dist/spec/openapi.yaml
CHANGED
|
@@ -3834,7 +3834,7 @@ components:
|
|
|
3834
3834
|
droppedDuplicateReason:
|
|
3835
3835
|
description: "Display-only explanation of why droppedDuplicateRows rows were dropped: names the (source, external_id) collapsing key and the field mapping to check so the count does not read as silent data loss. Empty unless droppedDuplicateRows > 0"
|
|
3836
3836
|
examples:
|
|
3837
|
-
- Rows repeated a (source, external_id) key already present in this source and were dropped
|
|
3837
|
+
- Rows repeated a (source, external_id) key already present in this source and were dropped as duplicates. If unexpected, verify the field mapped to external_id is unique per row (a coarse or truncated mapping collapses distinct rows onto one key).
|
|
3838
3838
|
type: string
|
|
3839
3839
|
droppedDuplicateRows:
|
|
3840
3840
|
description: Number of rows dropped as duplicates under the keep-first policy (same external_id within the upload or already persisted)
|
|
@@ -79,4 +79,31 @@ export class BodySizeGuard {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Read the request body and return it as a string, bounded by `maxBodyBytes`.
|
|
84
|
+
* The SDK's Node transport can parse the body itself, but reading it here lets
|
|
85
|
+
* callers pass a pre-parsed JSON body and keeps the handler in control of
|
|
86
|
+
* malformed input — and, critically, lets us cap an unbounded read.
|
|
87
|
+
*
|
|
88
|
+
* The size guard is checked BEFORE each chunk is retained, so an over-limit
|
|
89
|
+
* payload is rejected (via `BodyTooLargeError`) without ever buffering more than
|
|
90
|
+
* the limit (+ one chunk) of an attacker's body. The guard counts only bytes —
|
|
91
|
+
* it never inspects body content, headers, or any token.
|
|
92
|
+
*
|
|
93
|
+
* Lives here (next to `BodySizeGuard`, which it uses) rather than in
|
|
94
|
+
* `transport/http.ts` so the copilot's `turns-handler.ts` can import it without
|
|
95
|
+
* creating an import cycle with `http.ts` (which imports the turns handler).
|
|
96
|
+
*/
|
|
97
|
+
export async function readBody(req, maxBodyBytes) {
|
|
98
|
+
const guard = new BodySizeGuard(maxBodyBytes);
|
|
99
|
+
const chunks = [];
|
|
100
|
+
for await (const chunk of req) {
|
|
101
|
+
const buf = chunk;
|
|
102
|
+
// Throws BodyTooLargeError the moment the running total exceeds the limit,
|
|
103
|
+
// before the over-limit chunk is appended to memory.
|
|
104
|
+
guard.add(buf.length);
|
|
105
|
+
chunks.push(buf);
|
|
106
|
+
}
|
|
107
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
108
|
+
}
|
|
82
109
|
//# sourceMappingURL=body-limit.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"body-limit.js","sourceRoot":"","sources":["../../src/transport/body-limit.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,6EAA6E;AAC7E,gFAAgF;AAChF,6EAA6E;AAC7E,EAAE;AACF,2EAA2E;AAC3E,+EAA+E;AAC/E,8CAA8C;
|
|
1
|
+
{"version":3,"file":"body-limit.js","sourceRoot":"","sources":["../../src/transport/body-limit.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,6EAA6E;AAC7E,gFAAgF;AAChF,6EAA6E;AAC7E,EAAE;AACF,2EAA2E;AAC3E,+EAA+E;AAC/E,8CAA8C;AAI9C,mFAAmF;AACnF,MAAM,CAAC,MAAM,sBAAsB,GAAG,SAAS,CAAA,CAAC,QAAQ;AAExD;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAA;AAExC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAA;AAExC;;;;GAIG;AACH,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,kEAAkE;IACzD,MAAM,GAAG,GAAG,CAAA;IACrB,wCAAwC;IAC/B,UAAU,CAAQ;IAC3B,2DAA2D;IAClD,aAAa,CAAQ;IAE9B,YAAY,UAAkB,EAAE,aAAqB;QACnD,KAAK,CACH,4BAA4B,UAAU,cAAc;YAClD,sBAAsB,aAAa,SAAS,CAC/C,CAAA;QACD,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAA;QAC/B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA;IACpC,CAAC;CACF;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,aAAa;IACP,YAAY,CAAQ;IAC7B,KAAK,GAAG,CAAC,CAAA;IAEjB,YAAY,eAAuB,sBAAsB;QACvD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CACb,yBAAyB,YAAY,gCAAgC,CACtE,CAAA;QACH,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,YAAY,CAAA;IAClC,CAAC;IAED,gCAAgC;IAChC,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,WAAmB;QACrB,IAAI,CAAC,KAAK,IAAI,WAAW,CAAA;QACzB,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YACnC,MAAM,IAAI,iBAAiB,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QAC5D,CAAC;IACH,CAAC;CACF;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAoB,EAAE,YAAoB;IACvE,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC,YAAY,CAAC,CAAA;IAC7C,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,KAAe,CAAA;QAC3B,2EAA2E;QAC3E,qDAAqD;QACrD,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACrB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAClB,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;AAC/C,CAAC"}
|
package/dist/transport/http.js
CHANGED
|
@@ -12,35 +12,15 @@ import { createServer } from 'node:http';
|
|
|
12
12
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
13
13
|
import { runWithBearerToken } from '../auth/request-token.js';
|
|
14
14
|
import { loadConfig } from '../config.js';
|
|
15
|
+
import { handleAgentTurn } from '../copilot/turns-handler.js';
|
|
15
16
|
import { buildMcpServer } from '../server.js';
|
|
16
|
-
import {
|
|
17
|
+
import { BodyTooLargeError, HEADERS_TIMEOUT_MS, readBody, REQUEST_TIMEOUT_MS, } from './body-limit.js';
|
|
17
18
|
/** The conventional MCP protocol endpoint path. */
|
|
18
19
|
const MCP_PATH = '/mcp';
|
|
20
|
+
/** The copilot agent turn endpoint (SSE). */
|
|
21
|
+
const AGENT_PATH = '/agent/turns';
|
|
19
22
|
/** Liveness endpoint, separate from the MCP protocol (used by the container). */
|
|
20
23
|
const HEALTHZ_PATH = '/healthz';
|
|
21
|
-
/**
|
|
22
|
-
* Read the request body and return it as a string, bounded by `maxBodyBytes`.
|
|
23
|
-
* The SDK's Node transport can parse the body itself, but reading it here lets
|
|
24
|
-
* us pass a pre-parsed JSON body and keeps the handler in control of malformed
|
|
25
|
-
* input — and, critically, lets us cap an unbounded read.
|
|
26
|
-
*
|
|
27
|
-
* The size guard is checked BEFORE each chunk is retained, so an over-limit
|
|
28
|
-
* payload is rejected (via `BodyTooLargeError`) without ever buffering more than
|
|
29
|
-
* the limit (+ one chunk) of an attacker's body. The guard counts only bytes —
|
|
30
|
-
* it never inspects body content, headers, or any token.
|
|
31
|
-
*/
|
|
32
|
-
async function readBody(req, maxBodyBytes) {
|
|
33
|
-
const guard = new BodySizeGuard(maxBodyBytes);
|
|
34
|
-
const chunks = [];
|
|
35
|
-
for await (const chunk of req) {
|
|
36
|
-
const buf = chunk;
|
|
37
|
-
// Throws BodyTooLargeError the moment the running total exceeds the limit,
|
|
38
|
-
// before the over-limit chunk is appended to memory.
|
|
39
|
-
guard.add(buf.length);
|
|
40
|
-
chunks.push(buf);
|
|
41
|
-
}
|
|
42
|
-
return Buffer.concat(chunks).toString('utf8');
|
|
43
|
-
}
|
|
44
24
|
/**
|
|
45
25
|
* Handle a single MCP protocol request in stateless mode: spin up a transport
|
|
46
26
|
* + server, connect, dispatch, and tear both down when the response finishes.
|
|
@@ -87,6 +67,33 @@ export function createHttpServer(info, config = loadConfig()) {
|
|
|
87
67
|
res.end('ok');
|
|
88
68
|
return;
|
|
89
69
|
}
|
|
70
|
+
if (req.method === 'POST' && path === AGENT_PATH) {
|
|
71
|
+
// Same bearer relay as /mcp: seed the request-scoped auth store so the
|
|
72
|
+
// agent's read tools recover the caller's token from the ALS store. The
|
|
73
|
+
// header is forwarded verbatim and never logged here (token-relay rule).
|
|
74
|
+
// Per-tenant rate limiting (task 4.2.2) lives INSIDE handleAgentTurn as its
|
|
75
|
+
// first action after the bearer check — it needs the request-scoped tenant
|
|
76
|
+
// decode and the SSE sink (to emit `rate_limited`), and still gates before
|
|
77
|
+
// the body read and any provider spin-up.
|
|
78
|
+
runWithBearerToken(req.headers.authorization, () => {
|
|
79
|
+
// handleAgentTurn owns its own SSE error+done on every named failure and
|
|
80
|
+
// does not rethrow; this catch is a last resort if it throws before the
|
|
81
|
+
// sink could emit. Never leak a token or a stack into the response.
|
|
82
|
+
handleAgentTurn(config, req, res).catch((err) => {
|
|
83
|
+
if (!res.headersSent) {
|
|
84
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
85
|
+
res.end(JSON.stringify({ error: 'internal server error' }));
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
res.end();
|
|
89
|
+
}
|
|
90
|
+
// Log only the message string, never the raw error object (it may
|
|
91
|
+
// carry request context) — token-relay rule.
|
|
92
|
+
console.error('matcher-mcp agent turn handling failed:', err instanceof Error ? err.message : String(err));
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
90
97
|
if (path === MCP_PATH) {
|
|
91
98
|
// Seed the request-scoped auth store at the boundary so tool handlers can
|
|
92
99
|
// recover the caller's bearer token even when the SDK does not thread the
|
|
@@ -117,7 +124,10 @@ export function createHttpServer(info, config = loadConfig()) {
|
|
|
117
124
|
error: { code: -32603, message: 'internal server error' },
|
|
118
125
|
id: null,
|
|
119
126
|
}));
|
|
120
|
-
|
|
127
|
+
// Log only the message string, never the raw error object (it may
|
|
128
|
+
// carry request context) — token-relay rule, matching the sibling
|
|
129
|
+
// /agent/turns and turns-handler paths.
|
|
130
|
+
console.error('matcher-mcp request handling failed:', err instanceof Error ? err.message : String(err));
|
|
121
131
|
});
|
|
122
132
|
});
|
|
123
133
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,2EAA2E;AAC3E,qEAAqE;AACrE,8EAA8E;AAC9E,2EAA2E;AAC3E,yEAAyE;AACzE,+EAA+E;AAC/E,wEAAwE;AACxE,6BAA6B;AAE7B,OAAO,EAAE,YAAY,EAA0D,MAAM,WAAW,CAAA;AAEhG,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAA;AAElG,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,EAAE,UAAU,EAAe,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,cAAc,EAAmB,MAAM,cAAc,CAAA;AAC9D,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lerianstudio/matcher-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0-beta.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Model Context Protocol server for the Matcher reconciliation engine",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"lint": "eslint ."
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
+
"@anthropic-ai/sdk": "^0.110.0",
|
|
48
49
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
49
50
|
"@opentelemetry/api": "1.9.1",
|
|
50
51
|
"@opentelemetry/exporter-metrics-otlp-http": "0.219.0",
|
|
@@ -54,6 +55,7 @@
|
|
|
54
55
|
"@opentelemetry/sdk-node": "0.219.0",
|
|
55
56
|
"@opentelemetry/semantic-conventions": "1.41.1",
|
|
56
57
|
"ajv": "^8.20.0",
|
|
58
|
+
"openai": "^6.45.0",
|
|
57
59
|
"yaml": "^2.9.0",
|
|
58
60
|
"zod": "^4.4.3"
|
|
59
61
|
},
|