@traceglass/mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +62 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/map.d.ts +40 -0
- package/dist/map.d.ts.map +1 -0
- package/dist/map.js +85 -0
- package/dist/map.js.map +1 -0
- package/dist/mcp-types.d.ts +44 -0
- package/dist/mcp-types.d.ts.map +1 -0
- package/dist/mcp-types.js +14 -0
- package/dist/mcp-types.js.map +1 -0
- package/dist/recorder.d.ts +86 -0
- package/dist/recorder.d.ts.map +1 -0
- package/dist/recorder.js +154 -0
- package/dist/recorder.js.map +1 -0
- package/dist/type-compat.d.ts +3 -0
- package/dist/type-compat.d.ts.map +1 -0
- package/dist/type-compat.js +9 -0
- package/dist/type-compat.js.map +1 -0
- package/package.json +31 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rahul Bhardwaj
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# @traceglass/mcp
|
|
2
|
+
|
|
3
|
+
Record **Model Context Protocol** tool calls as [traceglass](https://www.npmjs.com/package/traceglass)
|
|
4
|
+
runs. One MCP session becomes one hash-chained, signed record: every `tools/call` is
|
|
5
|
+
chained and journaled the moment it returns, so the tamper window closes at capture
|
|
6
|
+
time — not at ingest.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install @traceglass/mcp
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Wrap the client — every tool it calls is recorded
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { startMcpRecording } from '@traceglass/mcp';
|
|
16
|
+
|
|
17
|
+
const rec = startMcpRecording({ name: 'support agent — ticket 8812', currency: 'INR' });
|
|
18
|
+
const mcp = rec.wrapClient(client); // your @modelcontextprotocol/sdk Client
|
|
19
|
+
|
|
20
|
+
rec.step({ type: 'user_input', label: 'Refund request', input: { ticket: '8812' } });
|
|
21
|
+
await mcp.callTool({ name: 'lookup_order', arguments: { id: '4471' } });
|
|
22
|
+
await mcp.callTool({ name: 'issue_refund', arguments: { id: '4471', amount: 1200 } });
|
|
23
|
+
rec.step({ type: 'final_output', label: 'Refund issued' });
|
|
24
|
+
|
|
25
|
+
const run = await rec.end(); // verified, signed (if `traceglass keygen` was run), stored
|
|
26
|
+
console.log(run?.id, run?.runHash);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`wrapClient` returns the same client type — pass it wherever the original went. Replay
|
|
30
|
+
with `npx traceglass open --id <runId>`, verify with `npx traceglass verify <runId>`.
|
|
31
|
+
|
|
32
|
+
## What lands in each step
|
|
33
|
+
|
|
34
|
+
| Step field | From |
|
|
35
|
+
| ------------- | ------------------------------------------------------------------------------ |
|
|
36
|
+
| `type` | `tool_call`, or `error` when the result has `isError: true` or the call throws |
|
|
37
|
+
| `toolName` | the `tools/call` tool name |
|
|
38
|
+
| `input` | the call's `arguments` (`{}` when a tool takes none) |
|
|
39
|
+
| `output` | the whole result, verbatim |
|
|
40
|
+
| `dataPayload` | `structuredContent` — the data the agent actually read |
|
|
41
|
+
| `tokens` | `_meta["traceglass/tokens"]` (or the `usage` hook) |
|
|
42
|
+
| `cost` | `_meta["traceglass/cost"]` (or the `usage` hook) |
|
|
43
|
+
|
|
44
|
+
MCP has no convention for tokens or cost. If your server reports them somewhere else,
|
|
45
|
+
pass `usage: ({ result }) => ({ tokens, cost })` and it wins over the `_meta` reading.
|
|
46
|
+
|
|
47
|
+
## Server side
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
server.registerTool('summarize', schema, rec.wrapToolHandler('summarize', handler));
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- **Order is capture order.** Concurrent tool calls are chained as they complete and are
|
|
54
|
+
never re-sorted afterwards — re-ordering a sealed chain is the one thing a flight
|
|
55
|
+
recorder must not be able to do.
|
|
56
|
+
- **Crash-safe:** if the process dies mid-session, `npx traceglass recover` finalizes the
|
|
57
|
+
journal into a `failed` run whose chain still verifies up to the crash point.
|
|
58
|
+
- **Local-first:** everything is written under `~/.traceglass` (or `TRACEGLASS_HOME`).
|
|
59
|
+
Zero network egress, and no production dependency outside traceglass itself — this
|
|
60
|
+
package speaks MCP structurally, so it works with whatever MCP SDK you already have.
|
|
61
|
+
- `end()` returns `null` for a session in which nothing was recorded: an empty session is
|
|
62
|
+
not evidence of anything, and no journal is left behind for `recover` to trip over.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { startMcpRecording, type McpRecorder, type McpToolCallRecord, type McpUsageContext, type StartMcpRecordingOptions, } from './recorder.js';
|
|
2
|
+
export { COST_META_KEYS, TOKENS_META_KEYS, dataPayloadFromResult, errorOutput, isErrorResult, labelForTool, usageFromResult, } from './map.js';
|
|
3
|
+
export type { CallToolParams, CallToolResultLike, McpToolCaller, McpUsage } from './mcp-types.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,wBAAwB,GAC9B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,eAAe,GAChB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,OAAO,EACL,iBAAiB,GAKlB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,eAAe,GAChB,MAAM,UAAU,CAAC"}
|
package/dist/map.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { McpUsage } from './mcp-types.js';
|
|
2
|
+
/**
|
|
3
|
+
* MCP → traceglass step mapping.
|
|
4
|
+
*
|
|
5
|
+
* MCP has no convention for cost or tokens, so this reads two OPTIONAL `_meta`
|
|
6
|
+
* keys on the tool result. `_meta` keys are namespaced by the spec, hence the
|
|
7
|
+
* `traceglass/` prefix; the dotted spelling is accepted too because plenty of
|
|
8
|
+
* emitters reach for it out of habit.
|
|
9
|
+
*
|
|
10
|
+
* Anything a server reports elsewhere is reachable through the `usage` hook on
|
|
11
|
+
* `startMcpRecording` — this module stays free of per-server guesswork.
|
|
12
|
+
*/
|
|
13
|
+
export declare const TOKENS_META_KEYS: readonly ["traceglass/tokens", "traceglass.tokens"];
|
|
14
|
+
export declare const COST_META_KEYS: readonly ["traceglass/cost", "traceglass.cost"];
|
|
15
|
+
/** Read `_meta`-reported tokens/cost off a tool result. Absent members stay absent. */
|
|
16
|
+
export declare function usageFromResult(result: unknown): McpUsage;
|
|
17
|
+
/**
|
|
18
|
+
* Did the tool answer with a protocol-level error? MCP reports tool failures
|
|
19
|
+
* in-band (`isError: true` on a successful JSON-RPC response), so a failed tool
|
|
20
|
+
* call is invisible unless this flag is read.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isErrorResult(result: unknown): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* The data the agent actually received, for the compliance-critical
|
|
25
|
+
* `dataPayload` field: `structuredContent` when the tool returns it, otherwise
|
|
26
|
+
* undefined (the full result is already recorded verbatim as `output`).
|
|
27
|
+
*/
|
|
28
|
+
export declare function dataPayloadFromResult(result: unknown): unknown;
|
|
29
|
+
/** Human-readable step label, matching the SDK's `Tool: <name>` convention. */
|
|
30
|
+
export declare function labelForTool(toolName: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Normalize a thrown value into something JSON-serializable for the record.
|
|
33
|
+
* A transport rejection must still produce a step, so this never throws:
|
|
34
|
+
* a circular or unserializable value degrades to a placeholder.
|
|
35
|
+
*/
|
|
36
|
+
export declare function errorOutput(err: unknown): {
|
|
37
|
+
error: string;
|
|
38
|
+
name?: string;
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.d.ts","sourceRoot":"","sources":["../src/map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAEnE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,qDAAsD,CAAC;AACpF,eAAO,MAAM,cAAc,iDAAkD,CAAC;AAoB9E,uFAAuF;AACvF,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,QAAQ,CAUzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAG9D;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAW1E"}
|
package/dist/map.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP → traceglass step mapping.
|
|
3
|
+
*
|
|
4
|
+
* MCP has no convention for cost or tokens, so this reads two OPTIONAL `_meta`
|
|
5
|
+
* keys on the tool result. `_meta` keys are namespaced by the spec, hence the
|
|
6
|
+
* `traceglass/` prefix; the dotted spelling is accepted too because plenty of
|
|
7
|
+
* emitters reach for it out of habit.
|
|
8
|
+
*
|
|
9
|
+
* Anything a server reports elsewhere is reachable through the `usage` hook on
|
|
10
|
+
* `startMcpRecording` — this module stays free of per-server guesswork.
|
|
11
|
+
*/
|
|
12
|
+
export const TOKENS_META_KEYS = ['traceglass/tokens', 'traceglass.tokens'];
|
|
13
|
+
export const COST_META_KEYS = ['traceglass/cost', 'traceglass.cost'];
|
|
14
|
+
function isRecord(value) {
|
|
15
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
16
|
+
}
|
|
17
|
+
/** A finite, non-negative number, or undefined. Step fields reject the rest. */
|
|
18
|
+
function nonNegative(value) {
|
|
19
|
+
const n = typeof value === 'number' ? value : typeof value === 'string' ? Number(value) : NaN;
|
|
20
|
+
return Number.isFinite(n) && n >= 0 ? n : undefined;
|
|
21
|
+
}
|
|
22
|
+
function firstOf(meta, keys) {
|
|
23
|
+
for (const key of keys) {
|
|
24
|
+
const n = nonNegative(meta[key]);
|
|
25
|
+
if (n !== undefined)
|
|
26
|
+
return n;
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
/** Read `_meta`-reported tokens/cost off a tool result. Absent members stay absent. */
|
|
31
|
+
export function usageFromResult(result) {
|
|
32
|
+
if (!isRecord(result))
|
|
33
|
+
return {};
|
|
34
|
+
const meta = result._meta;
|
|
35
|
+
if (!isRecord(meta))
|
|
36
|
+
return {};
|
|
37
|
+
const tokens = firstOf(meta, TOKENS_META_KEYS);
|
|
38
|
+
const cost = firstOf(meta, COST_META_KEYS);
|
|
39
|
+
return {
|
|
40
|
+
...(tokens !== undefined ? { tokens } : {}),
|
|
41
|
+
...(cost !== undefined ? { cost } : {}),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Did the tool answer with a protocol-level error? MCP reports tool failures
|
|
46
|
+
* in-band (`isError: true` on a successful JSON-RPC response), so a failed tool
|
|
47
|
+
* call is invisible unless this flag is read.
|
|
48
|
+
*/
|
|
49
|
+
export function isErrorResult(result) {
|
|
50
|
+
return isRecord(result) && result.isError === true;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The data the agent actually received, for the compliance-critical
|
|
54
|
+
* `dataPayload` field: `structuredContent` when the tool returns it, otherwise
|
|
55
|
+
* undefined (the full result is already recorded verbatim as `output`).
|
|
56
|
+
*/
|
|
57
|
+
export function dataPayloadFromResult(result) {
|
|
58
|
+
if (!isRecord(result))
|
|
59
|
+
return undefined;
|
|
60
|
+
return result.structuredContent;
|
|
61
|
+
}
|
|
62
|
+
/** Human-readable step label, matching the SDK's `Tool: <name>` convention. */
|
|
63
|
+
export function labelForTool(toolName) {
|
|
64
|
+
return `Tool: ${toolName}`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Normalize a thrown value into something JSON-serializable for the record.
|
|
68
|
+
* A transport rejection must still produce a step, so this never throws:
|
|
69
|
+
* a circular or unserializable value degrades to a placeholder.
|
|
70
|
+
*/
|
|
71
|
+
export function errorOutput(err) {
|
|
72
|
+
if (err instanceof Error) {
|
|
73
|
+
return { error: err.message, name: err.name };
|
|
74
|
+
}
|
|
75
|
+
if (typeof err === 'string')
|
|
76
|
+
return { error: err };
|
|
77
|
+
try {
|
|
78
|
+
const json = JSON.stringify(err);
|
|
79
|
+
return { error: json ?? `[${typeof err}]` };
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return { error: '[unserializable error]' };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=map.js.map
|
package/dist/map.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.js","sourceRoot":"","sources":["../src/map.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural types for the Model Context Protocol shapes this adapter touches.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately NOT imported from `@modelcontextprotocol/sdk`. This package adds
|
|
5
|
+
* no production dependency of its own, so:
|
|
6
|
+
* - it records whatever MCP SDK version (or hand-rolled client/server) the
|
|
7
|
+
* host application already has, instead of pinning a second copy, and
|
|
8
|
+
* - the supply chain behind an audit record stays two packages wide.
|
|
9
|
+
*
|
|
10
|
+
* Compatibility with the real SDK signatures is asserted at compile time in
|
|
11
|
+
* `type-compat.ts` rather than assumed.
|
|
12
|
+
*/
|
|
13
|
+
/** `tools/call` request params. Extra members are preserved, never required. */
|
|
14
|
+
export interface CallToolParams {
|
|
15
|
+
name: string;
|
|
16
|
+
arguments?: Record<string, unknown> | undefined;
|
|
17
|
+
_meta?: Record<string, unknown> | undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A `tools/call` result. Every member is optional: a tool may answer with
|
|
21
|
+
* content, with `structuredContent`, with both, or with neither.
|
|
22
|
+
*/
|
|
23
|
+
export interface CallToolResultLike {
|
|
24
|
+
content?: unknown;
|
|
25
|
+
structuredContent?: unknown;
|
|
26
|
+
isError?: boolean;
|
|
27
|
+
_meta?: Record<string, unknown> | undefined;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Anything that can invoke an MCP tool — an SDK `Client`, a transport shim, a
|
|
31
|
+
* fake in a test. Method syntax (not a property) is deliberate: TypeScript
|
|
32
|
+
* checks method parameters bivariantly, so a real client whose `callTool` takes
|
|
33
|
+
* extra optional arguments (a result schema, request options) still satisfies
|
|
34
|
+
* this interface.
|
|
35
|
+
*/
|
|
36
|
+
export interface McpToolCaller {
|
|
37
|
+
callTool(params: CallToolParams, ...rest: never[]): Promise<unknown>;
|
|
38
|
+
}
|
|
39
|
+
/** Token/cost figures for one tool call, when the server reports any. */
|
|
40
|
+
export interface McpUsage {
|
|
41
|
+
tokens?: number;
|
|
42
|
+
cost?: number;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=mcp-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-types.d.ts","sourceRoot":"","sources":["../src/mcp-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CAC7C;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CAC7C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACtE;AAED,yEAAyE;AACzE,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural types for the Model Context Protocol shapes this adapter touches.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately NOT imported from `@modelcontextprotocol/sdk`. This package adds
|
|
5
|
+
* no production dependency of its own, so:
|
|
6
|
+
* - it records whatever MCP SDK version (or hand-rolled client/server) the
|
|
7
|
+
* host application already has, instead of pinning a second copy, and
|
|
8
|
+
* - the supply chain behind an audit record stays two packages wide.
|
|
9
|
+
*
|
|
10
|
+
* Compatibility with the real SDK signatures is asserted at compile time in
|
|
11
|
+
* `type-compat.ts` rather than assumed.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=mcp-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-types.js","sourceRoot":"","sources":["../src/mcp-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { Run, Step } from '@traceglass/core';
|
|
2
|
+
import { type RecordStepInput } from '@traceglass/sdk';
|
|
3
|
+
import type { CallToolParams, McpToolCaller, McpUsage } from './mcp-types.js';
|
|
4
|
+
/**
|
|
5
|
+
* MCP session recorder.
|
|
6
|
+
*
|
|
7
|
+
* One MCP session becomes one traceglass run: every `tools/call` is a
|
|
8
|
+
* `tool_call` step, hash-chained the moment it returns and journaled to disk
|
|
9
|
+
* before the caller gets its result back. The chain is therefore fixed at
|
|
10
|
+
* capture time — the same guarantee `@traceglass/sdk` gives, reached without
|
|
11
|
+
* the host application writing any per-tool recording code.
|
|
12
|
+
*
|
|
13
|
+
* Steps land in COMPLETION order, which is the order the agent actually learned
|
|
14
|
+
* things. Concurrent tool calls are not re-sorted by start time afterwards:
|
|
15
|
+
* re-ordering a chain after the fact is exactly what a flight recorder must not
|
|
16
|
+
* be able to do.
|
|
17
|
+
*/
|
|
18
|
+
/** Context handed to the `usage` hook for one completed call. */
|
|
19
|
+
export interface McpUsageContext {
|
|
20
|
+
toolName: string;
|
|
21
|
+
params: CallToolParams;
|
|
22
|
+
/** The tool result, or undefined when the call threw. */
|
|
23
|
+
result: unknown;
|
|
24
|
+
}
|
|
25
|
+
export interface StartMcpRecordingOptions {
|
|
26
|
+
/** Run name. Defaults to `MCP session`. */
|
|
27
|
+
name?: string;
|
|
28
|
+
/** Explicit run id; defaults to `mcp-<date>-<hex>`. */
|
|
29
|
+
id?: string;
|
|
30
|
+
currency?: string;
|
|
31
|
+
/** traceglass data dir; `null` for a memory-only recording. See the SDK. */
|
|
32
|
+
dir?: string | null;
|
|
33
|
+
/** Per-leaf commitments so payloads can be redacted later (default on). */
|
|
34
|
+
redactable?: boolean;
|
|
35
|
+
/** Built-in redaction patterns applied at capture time, before hashing. */
|
|
36
|
+
redactPatterns?: string[];
|
|
37
|
+
/**
|
|
38
|
+
* Pull tokens/cost out of a result when your server reports them somewhere
|
|
39
|
+
* other than the `_meta` keys `map.ts` knows about. Returning `undefined`
|
|
40
|
+
* (or omitting a member) falls back to the `_meta` reading.
|
|
41
|
+
*/
|
|
42
|
+
usage?: (ctx: McpUsageContext) => McpUsage | undefined;
|
|
43
|
+
}
|
|
44
|
+
/** One tool invocation to record. Everything except `name` is optional. */
|
|
45
|
+
export interface McpToolCallRecord {
|
|
46
|
+
/** Tool name as sent in `tools/call`. */
|
|
47
|
+
name: string;
|
|
48
|
+
arguments?: Record<string, unknown> | undefined;
|
|
49
|
+
/** The tool result, when the call completed. */
|
|
50
|
+
result?: unknown;
|
|
51
|
+
/** The thrown value, when the call failed at the transport/protocol level. */
|
|
52
|
+
error?: unknown;
|
|
53
|
+
/** ISO 8601 start time; defaults to now. */
|
|
54
|
+
startedAt?: string;
|
|
55
|
+
durationMs?: number;
|
|
56
|
+
/** Overrides anything derived from the result. */
|
|
57
|
+
usage?: McpUsage;
|
|
58
|
+
}
|
|
59
|
+
export interface McpRecorder {
|
|
60
|
+
readonly runId: string;
|
|
61
|
+
/** Record one tool invocation. Returns the chained step. */
|
|
62
|
+
recordToolCall(call: McpToolCallRecord): Step;
|
|
63
|
+
/**
|
|
64
|
+
* Wrap an MCP client so every `tools/call` it makes is recorded. The returned
|
|
65
|
+
* value is the same client type — pass it wherever the original went.
|
|
66
|
+
*/
|
|
67
|
+
wrapClient<T extends McpToolCaller>(client: T): T;
|
|
68
|
+
/**
|
|
69
|
+
* Server side: wrap one tool handler so every invocation it serves is
|
|
70
|
+
* recorded. `args` is the tool's argument object as MCP delivers it.
|
|
71
|
+
*/
|
|
72
|
+
wrapToolHandler<A extends unknown[], R>(name: string, handler: (...args: A) => R | Promise<R>): (...args: A) => Promise<R>;
|
|
73
|
+
/** Record a non-tool step (user input, final output, an approval, ...). */
|
|
74
|
+
step(input: RecordStepInput): Step;
|
|
75
|
+
/**
|
|
76
|
+
* Finalize: totals, warnings, anchor, signature (if `traceglass keygen` was
|
|
77
|
+
* run), store. Returns `null` for a session in which nothing was recorded —
|
|
78
|
+
* an empty session is not evidence of anything, and a run with no steps
|
|
79
|
+
* cannot be anchored (SPEC §6.1).
|
|
80
|
+
*/
|
|
81
|
+
end(opts?: {
|
|
82
|
+
status?: 'completed' | 'failed';
|
|
83
|
+
}): Promise<Run | null>;
|
|
84
|
+
}
|
|
85
|
+
export declare function startMcpRecording(opts?: StartMcpRecordingOptions): McpRecorder;
|
|
86
|
+
//# sourceMappingURL=recorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../src/recorder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAkB,KAAK,eAAe,EAAiB,MAAM,iBAAiB,CAAC;AAQtF,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE9E;;;;;;;;;;;;;GAaG;AAEH,iEAAiE;AACjE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,cAAc,CAAC;IACvB,yDAAyD;IACzD,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,QAAQ,GAAG,SAAS,CAAC;CACxD;AAED,2EAA2E;AAC3E,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAChD,gDAAgD;IAChD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,4DAA4D;IAC5D,cAAc,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC9C;;;OAGG;IACH,UAAU,CAAC,CAAC,SAAS,aAAa,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;IAClD;;;OAGG;IACH,eAAe,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC,EACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACtC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9B,2EAA2E;IAC3E,IAAI,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC;;;;;OAKG;IACH,GAAG,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;CACtE;AAMD,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,wBAA6B,GAAG,WAAW,CA+JlF"}
|
package/dist/recorder.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { startRecording } from '@traceglass/sdk';
|
|
3
|
+
import { dataPayloadFromResult, errorOutput, isErrorResult, labelForTool, usageFromResult, } from './map.js';
|
|
4
|
+
function nowMs() {
|
|
5
|
+
return performance.now();
|
|
6
|
+
}
|
|
7
|
+
export function startMcpRecording(opts = {}) {
|
|
8
|
+
const runId = opts.id ?? `mcp-${new Date().toISOString().slice(0, 10)}-${randomBytes(3).toString('hex')}`;
|
|
9
|
+
/**
|
|
10
|
+
* The underlying recorder is created on the FIRST recorded step, not here.
|
|
11
|
+
* An MCP session that never calls a tool would otherwise leave a stepless
|
|
12
|
+
* journal on disk, which `traceglass recover` cannot finalize (a run with no
|
|
13
|
+
* steps is not a record of anything). The run id is fixed up front so callers
|
|
14
|
+
* can log or correlate it before anything is recorded.
|
|
15
|
+
*/
|
|
16
|
+
let inner = null;
|
|
17
|
+
function recorder() {
|
|
18
|
+
inner ??= startRecording({
|
|
19
|
+
name: opts.name ?? 'MCP session',
|
|
20
|
+
id: runId,
|
|
21
|
+
...(opts.currency !== undefined ? { currency: opts.currency } : {}),
|
|
22
|
+
...(opts.dir !== undefined ? { dir: opts.dir } : {}),
|
|
23
|
+
...(opts.redactable !== undefined ? { redactable: opts.redactable } : {}),
|
|
24
|
+
...(opts.redactPatterns !== undefined ? { redactPatterns: opts.redactPatterns } : {}),
|
|
25
|
+
});
|
|
26
|
+
return inner;
|
|
27
|
+
}
|
|
28
|
+
let count = 0;
|
|
29
|
+
let ended = false;
|
|
30
|
+
function recordToolCall(call) {
|
|
31
|
+
if (ended) {
|
|
32
|
+
throw new Error(`MCP recording "${runId}" has already ended.`);
|
|
33
|
+
}
|
|
34
|
+
const failed = call.error !== undefined || isErrorResult(call.result);
|
|
35
|
+
const output = call.error !== undefined ? errorOutput(call.error) : call.result;
|
|
36
|
+
const dataPayload = dataPayloadFromResult(call.result);
|
|
37
|
+
const fromResult = usageFromResult(call.result);
|
|
38
|
+
const hook = opts.usage?.({
|
|
39
|
+
toolName: call.name,
|
|
40
|
+
params: { name: call.name, arguments: call.arguments },
|
|
41
|
+
result: call.result,
|
|
42
|
+
});
|
|
43
|
+
const usage = { ...fromResult, ...hook, ...call.usage };
|
|
44
|
+
const step = recorder().step({
|
|
45
|
+
type: failed ? 'error' : 'tool_call',
|
|
46
|
+
label: labelForTool(call.name),
|
|
47
|
+
toolName: call.name,
|
|
48
|
+
// `arguments` may legitimately be absent (a tool that takes none); an
|
|
49
|
+
// empty object records "called with nothing" rather than "not recorded".
|
|
50
|
+
input: call.arguments ?? {},
|
|
51
|
+
...(output !== undefined ? { output } : {}),
|
|
52
|
+
...(dataPayload !== undefined ? { dataPayload } : {}),
|
|
53
|
+
...(usage.tokens !== undefined ? { tokens: usage.tokens } : {}),
|
|
54
|
+
...(usage.cost !== undefined ? { cost: usage.cost } : {}),
|
|
55
|
+
...(call.startedAt !== undefined ? { startedAt: call.startedAt } : {}),
|
|
56
|
+
...(call.durationMs !== undefined ? { durationMs: call.durationMs } : {}),
|
|
57
|
+
});
|
|
58
|
+
count += 1;
|
|
59
|
+
return step;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
runId,
|
|
63
|
+
recordToolCall,
|
|
64
|
+
wrapClient(client) {
|
|
65
|
+
const original = client.callTool.bind(client);
|
|
66
|
+
const wrapped = async (params, ...rest) => {
|
|
67
|
+
const startedAt = new Date().toISOString();
|
|
68
|
+
const t0 = nowMs();
|
|
69
|
+
try {
|
|
70
|
+
const result = await original(params, ...rest);
|
|
71
|
+
recordToolCall({
|
|
72
|
+
name: params.name,
|
|
73
|
+
arguments: params.arguments,
|
|
74
|
+
result,
|
|
75
|
+
startedAt,
|
|
76
|
+
durationMs: Math.round(nowMs() - t0),
|
|
77
|
+
});
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
recordToolCall({
|
|
82
|
+
name: params.name,
|
|
83
|
+
arguments: params.arguments,
|
|
84
|
+
error: err,
|
|
85
|
+
startedAt,
|
|
86
|
+
durationMs: Math.round(nowMs() - t0),
|
|
87
|
+
});
|
|
88
|
+
throw err;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
// A Proxy keeps the wrapped value assignment-compatible with the original
|
|
92
|
+
// client (same type, same extra methods). Every non-intercepted member is
|
|
93
|
+
// read with the TARGET as receiver and bound to it, so methods that touch
|
|
94
|
+
// private state still run on the real object rather than on the proxy.
|
|
95
|
+
return new Proxy(client, {
|
|
96
|
+
get(target, prop, _receiver) {
|
|
97
|
+
if (prop === 'callTool')
|
|
98
|
+
return wrapped;
|
|
99
|
+
const value = Reflect.get(target, prop, target);
|
|
100
|
+
return typeof value === 'function'
|
|
101
|
+
? value.bind(target)
|
|
102
|
+
: value;
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
wrapToolHandler(name, handler) {
|
|
107
|
+
return async (...args) => {
|
|
108
|
+
const startedAt = new Date().toISOString();
|
|
109
|
+
const t0 = nowMs();
|
|
110
|
+
const first = args[0];
|
|
111
|
+
const argObject = typeof first === 'object' && first !== null && !Array.isArray(first)
|
|
112
|
+
? first
|
|
113
|
+
: undefined;
|
|
114
|
+
try {
|
|
115
|
+
const result = await handler(...args);
|
|
116
|
+
recordToolCall({
|
|
117
|
+
name,
|
|
118
|
+
arguments: argObject,
|
|
119
|
+
result,
|
|
120
|
+
startedAt,
|
|
121
|
+
durationMs: Math.round(nowMs() - t0),
|
|
122
|
+
});
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
recordToolCall({
|
|
127
|
+
name,
|
|
128
|
+
arguments: argObject,
|
|
129
|
+
error: err,
|
|
130
|
+
startedAt,
|
|
131
|
+
durationMs: Math.round(nowMs() - t0),
|
|
132
|
+
});
|
|
133
|
+
throw err;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
step(input) {
|
|
138
|
+
if (ended)
|
|
139
|
+
throw new Error(`MCP recording "${runId}" has already ended.`);
|
|
140
|
+
const step = recorder().step(input);
|
|
141
|
+
count += 1;
|
|
142
|
+
return step;
|
|
143
|
+
},
|
|
144
|
+
async end(endOpts = {}) {
|
|
145
|
+
if (ended)
|
|
146
|
+
throw new Error(`MCP recording "${runId}" has already ended.`);
|
|
147
|
+
ended = true;
|
|
148
|
+
if (count === 0 || inner === null)
|
|
149
|
+
return null;
|
|
150
|
+
return inner.end(endOpts);
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=recorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.js","sourceRoot":"","sources":["../src/recorder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,cAAc,EAAuC,MAAM,iBAAiB,CAAC;AACtF,OAAO,EACL,qBAAqB,EACrB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,eAAe,GAChB,MAAM,UAAU,CAAC;AA0FlB,SAAS,KAAK;IACZ,OAAO,WAAW,CAAC,GAAG,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAiC,EAAE;IACnE,MAAM,KAAK,GACT,IAAI,CAAC,EAAE,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IAE9F;;;;;;OAMG;IACH,IAAI,KAAK,GAAoB,IAAI,CAAC;IAClC,SAAS,QAAQ;QACf,KAAK,KAAK,cAAc,CAAC;YACvB,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,aAAa;YAChC,EAAE,EAAE,KAAK;YACT,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpD,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzE,GAAG,CAAC,IAAI,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtF,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,KAAK,CAAC;IAElB,SAAS,cAAc,CAAC,IAAuB;QAC7C,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,sBAAsB,CAAC,CAAC;QACjE,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;QAChF,MAAM,WAAW,GAAG,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YACxB,QAAQ,EAAE,IAAI,CAAC,IAAI;YACnB,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;YACtD,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,MAAM,KAAK,GAAa,EAAE,GAAG,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAElE,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC;YAC3B,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW;YACpC,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;YAC9B,QAAQ,EAAE,IAAI,CAAC,IAAI;YACnB,sEAAsE;YACtE,yEAAyE;YACzE,KAAK,EAAE,IAAI,CAAC,SAAS,IAAI,EAAE;YAC3B,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/D,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,GAAG,CAAC,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1E,CAAC,CAAC;QACH,KAAK,IAAI,CAAC,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,KAAK;QAEL,cAAc;QAEd,UAAU,CAA0B,MAAS;YAC3C,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAGvB,CAAC;YAEtB,MAAM,OAAO,GAAG,KAAK,EAAE,MAAsB,EAAE,GAAG,IAAe,EAAoB,EAAE;gBACrF,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;gBAC3C,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;gBACnB,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;oBAC/C,cAAc,CAAC;wBACb,IAAI,EAAE,MAAM,CAAC,IAAI;wBACjB,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,MAAM;wBACN,SAAS;wBACT,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;qBACrC,CAAC,CAAC;oBACH,OAAO,MAAM,CAAC;gBAChB,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,cAAc,CAAC;wBACb,IAAI,EAAE,MAAM,CAAC,IAAI;wBACjB,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,KAAK,EAAE,GAAG;wBACV,SAAS;wBACT,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;qBACrC,CAAC,CAAC;oBACH,MAAM,GAAG,CAAC;gBACZ,CAAC;YACH,CAAC,CAAC;YAEF,0EAA0E;YAC1E,0EAA0E;YAC1E,0EAA0E;YAC1E,uEAAuE;YACvE,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE;gBACvB,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS;oBACzB,IAAI,IAAI,KAAK,UAAU;wBAAE,OAAO,OAAO,CAAC;oBACxC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAY,CAAC;oBAC3D,OAAO,OAAO,KAAK,KAAK,UAAU;wBAChC,CAAC,CAAE,KAAsC,CAAC,IAAI,CAAC,MAAM,CAAC;wBACtD,CAAC,CAAC,KAAK,CAAC;gBACZ,CAAC;aACF,CAAC,CAAC;QACL,CAAC;QAED,eAAe,CACb,IAAY,EACZ,OAAuC;YAEvC,OAAO,KAAK,EAAE,GAAG,IAAO,EAAc,EAAE;gBACtC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;gBAC3C,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;gBACnB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,SAAS,GACb,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;oBAClE,CAAC,CAAE,KAAiC;oBACpC,CAAC,CAAC,SAAS,CAAC;gBAChB,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;oBACtC,cAAc,CAAC;wBACb,IAAI;wBACJ,SAAS,EAAE,SAAS;wBACpB,MAAM;wBACN,SAAS;wBACT,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;qBACrC,CAAC,CAAC;oBACH,OAAO,MAAM,CAAC;gBAChB,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,cAAc,CAAC;wBACb,IAAI;wBACJ,SAAS,EAAE,SAAS;wBACpB,KAAK,EAAE,GAAG;wBACV,SAAS;wBACT,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;qBACrC,CAAC,CAAC;oBACH,MAAM,GAAG,CAAC;gBACZ,CAAC;YACH,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,KAAsB;YACzB,IAAI,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,sBAAsB,CAAC,CAAC;YAC1E,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpC,KAAK,IAAI,CAAC,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,CAAC,GAAG,CAAC,UAA+C,EAAE;YACzD,IAAI,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,sBAAsB,CAAC,CAAC;YAC1E,KAAK,GAAG,IAAI,CAAC;YACb,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC;YAC/C,OAAO,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-compat.d.ts","sourceRoot":"","sources":["../src/type-compat.ts"],"names":[],"mappings":"AA4DA,kFAAkF;AAClF,eAAO,MAAM,sBAAsB,IAAI,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const _clientIsCaller = true;
|
|
2
|
+
const _wrappedKeepsType = wrapLike(_upstream);
|
|
3
|
+
const _wrappedHandler = wrapHandlerLike('t', _upstreamHandler);
|
|
4
|
+
/** Nothing here is meant to be imported; the assertions above are the payload. */
|
|
5
|
+
export const TYPE_COMPAT_ASSERTIONS = 3;
|
|
6
|
+
void _clientIsCaller;
|
|
7
|
+
void _wrappedKeepsType;
|
|
8
|
+
void _wrappedHandler;
|
|
9
|
+
//# sourceMappingURL=type-compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-compat.js","sourceRoot":"","sources":["../src/type-compat.ts"],"names":[],"mappings":"AAoCA,MAAM,eAAe,GAAoB,IAAI,CAAC;AAK9C,MAAM,iBAAiB,GAAmB,QAAQ,CAAC,SAAS,CAAC,CAAC;AAiB9D,MAAM,eAAe,GAAwB,eAAe,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;AAEpF,kFAAkF;AAClF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACxC,KAAK,eAAe,CAAC;AACrB,KAAK,iBAAiB,CAAC;AACvB,KAAK,eAAe,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@traceglass/mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Record Model Context Protocol tool calls as tamper-evident traceglass runs",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"mcp",
|
|
16
|
+
"model-context-protocol",
|
|
17
|
+
"ai",
|
|
18
|
+
"agents",
|
|
19
|
+
"audit",
|
|
20
|
+
"compliance"
|
|
21
|
+
],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc -b",
|
|
25
|
+
"test": "vitest run"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@traceglass/core": "1.0.0",
|
|
29
|
+
"@traceglass/sdk": "1.0.0"
|
|
30
|
+
}
|
|
31
|
+
}
|