@treeship/mcp 0.1.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/dist/attest.d.ts +2 -0
- package/dist/attest.js +33 -0
- package/dist/client.d.ts +12 -0
- package/dist/client.js +72 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +5 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +4 -0
- package/package.json +35 -0
package/dist/attest.d.ts
ADDED
package/dist/attest.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
const exec = promisify(execFile);
|
|
4
|
+
export async function attestAction(params) {
|
|
5
|
+
const args = [
|
|
6
|
+
'attest', 'action',
|
|
7
|
+
'--actor', params.actor,
|
|
8
|
+
'--action', params.action,
|
|
9
|
+
'--format', 'json',
|
|
10
|
+
];
|
|
11
|
+
if (params.parentId) {
|
|
12
|
+
args.push('--parent', params.parentId);
|
|
13
|
+
}
|
|
14
|
+
const cleanMeta = {};
|
|
15
|
+
for (const [k, v] of Object.entries(params.meta ?? {})) {
|
|
16
|
+
if (v !== undefined && v !== null)
|
|
17
|
+
cleanMeta[k] = v;
|
|
18
|
+
}
|
|
19
|
+
if (Object.keys(cleanMeta).length > 0) {
|
|
20
|
+
args.push('--meta', JSON.stringify(cleanMeta));
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const { stdout } = await exec('treeship', args, { timeout: 5000 });
|
|
24
|
+
const result = JSON.parse(stdout);
|
|
25
|
+
return result.id || result.artifact_id;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
if (process.env.TREESHIP_DEBUG === '1') {
|
|
29
|
+
process.stderr.write(`[treeship] attestAction failed: ${params.action}\n`);
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import type { CallToolRequest, CallToolResultSchema, CompatibilityCallToolResultSchema, Implementation } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import type { RequestOptions } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
4
|
+
import type { ClientOptions } from '@modelcontextprotocol/sdk/client/index.js';
|
|
5
|
+
export declare class TreeshipMCPClient extends Client {
|
|
6
|
+
private _actor;
|
|
7
|
+
private _disabled;
|
|
8
|
+
constructor(clientInfo: Implementation, options?: ClientOptions);
|
|
9
|
+
callTool(params: CallToolRequest['params'], resultSchema?: typeof CallToolResultSchema | typeof CompatibilityCallToolResultSchema, options?: RequestOptions): Promise<any>;
|
|
10
|
+
private _attestIntent;
|
|
11
|
+
private _attestReceipt;
|
|
12
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { attestAction } from './attest.js';
|
|
3
|
+
import { hashPayload } from './utils.js';
|
|
4
|
+
export class TreeshipMCPClient extends Client {
|
|
5
|
+
_actor;
|
|
6
|
+
_disabled;
|
|
7
|
+
constructor(clientInfo, options) {
|
|
8
|
+
super(clientInfo, options);
|
|
9
|
+
this._actor = process.env.TREESHIP_ACTOR ?? `agent://mcp-${clientInfo?.name ?? 'unknown'}`;
|
|
10
|
+
this._disabled = process.env.TREESHIP_DISABLE === '1';
|
|
11
|
+
}
|
|
12
|
+
async callTool(params, resultSchema, options) {
|
|
13
|
+
if (this._disabled) {
|
|
14
|
+
return super.callTool(params, resultSchema, options);
|
|
15
|
+
}
|
|
16
|
+
// Attest INTENT before the call (awaited -- proof of what was about to happen)
|
|
17
|
+
const intentId = await this._attestIntent(params).catch(() => undefined);
|
|
18
|
+
const startMs = Date.now();
|
|
19
|
+
let result;
|
|
20
|
+
let error;
|
|
21
|
+
try {
|
|
22
|
+
result = await super.callTool(params, resultSchema, options);
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
error = e;
|
|
26
|
+
throw e;
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
const elapsedMs = Date.now() - startMs;
|
|
30
|
+
// Attest RECEIPT after the call (fire-and-forget -- never blocks response)
|
|
31
|
+
this._attestReceipt(params, result, intentId, elapsedMs, error).catch(() => { });
|
|
32
|
+
}
|
|
33
|
+
// Attach treeship metadata to result
|
|
34
|
+
if (intentId && result) {
|
|
35
|
+
result._treeship = {
|
|
36
|
+
intent: intentId,
|
|
37
|
+
tool: params.name,
|
|
38
|
+
actor: this._actor,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
async _attestIntent(params) {
|
|
44
|
+
return attestAction({
|
|
45
|
+
actor: this._actor,
|
|
46
|
+
action: `mcp.tool.${params.name}.intent`,
|
|
47
|
+
meta: {
|
|
48
|
+
tool: params.name,
|
|
49
|
+
server: 'mcp',
|
|
50
|
+
args_digest: hashPayload(JSON.stringify(params.arguments ?? {})),
|
|
51
|
+
approval_nonce: process.env.TREESHIP_APPROVAL_NONCE || undefined,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async _attestReceipt(params, result, intentId, elapsedMs, error) {
|
|
56
|
+
await attestAction({
|
|
57
|
+
actor: this._actor,
|
|
58
|
+
action: `mcp.tool.${params.name}.receipt`,
|
|
59
|
+
parentId: intentId,
|
|
60
|
+
meta: {
|
|
61
|
+
tool: params.name,
|
|
62
|
+
elapsed_ms: elapsedMs,
|
|
63
|
+
exit_code: error ? 1 : 0,
|
|
64
|
+
is_error: result?.isError ?? !!error,
|
|
65
|
+
output_digest: result
|
|
66
|
+
? hashPayload(JSON.stringify(result.content ?? result))
|
|
67
|
+
: undefined,
|
|
68
|
+
error_message: error?.message,
|
|
69
|
+
},
|
|
70
|
+
}).catch(() => { });
|
|
71
|
+
}
|
|
72
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Re-export EVERYTHING from @modelcontextprotocol/sdk/client unchanged
|
|
2
|
+
// so existing imports still work after switching to @treeship/mcp
|
|
3
|
+
export * from '@modelcontextprotocol/sdk/client/index.js';
|
|
4
|
+
// Override Client with our wrapped version
|
|
5
|
+
export { TreeshipMCPClient as Client } from './client.js';
|
package/dist/types.d.ts
ADDED
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function hashPayload(content: string): string;
|
package/dist/utils.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@treeship/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Drop-in Treeship attestation for MCP tool calls",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/zerkerlabs/treeship",
|
|
9
|
+
"directory": "bridges/mcp"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://treeship.dev",
|
|
12
|
+
"keywords": ["treeship", "mcp", "attestation", "agents", "tool-calls"],
|
|
13
|
+
"files": ["dist"],
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "dist/index.js",
|
|
16
|
+
"types": "dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"import": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^25.5.0",
|
|
28
|
+
"typescript": "^5.7.0",
|
|
29
|
+
"vitest": "^3.0.0"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc",
|
|
33
|
+
"test": "vitest run"
|
|
34
|
+
}
|
|
35
|
+
}
|