@proofai/mcp-server 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/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # @proofai/mcp-server
2
+
3
+ MCP Server for ProofAI — plug AI compliance into Claude Code.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g @proofai/mcp-server
9
+ ```
10
+
11
+ ## Configure Claude Code
12
+
13
+ Add to `~/.claude/claude_desktop_config.json`:
14
+
15
+ ```json
16
+ {
17
+ "mcpServers": {
18
+ "proofai": {
19
+ "command": "proofai-mcp",
20
+ "env": {
21
+ "PROOFAI_API_KEY": "pk_live_xxx",
22
+ "PROOFAI_ANON_KEY": "your-supabase-anon-key"
23
+ }
24
+ }
25
+ }
26
+ }
27
+ ```
28
+
29
+ ## Tools
30
+
31
+ ### `proofai_certify`
32
+ Certify an AI decision with cryptographic proof. Full pipeline in one call.
33
+
34
+ ```
35
+ > Use proofai_certify to certify my analysis of this contract
36
+ ```
37
+
38
+ ### `proofai_log`
39
+ Log an AI decision that already happened (prompt + response you provide).
40
+
41
+ ```
42
+ > Use proofai_log to record this decision with prompt "..." and response "..."
43
+ ```
44
+
45
+ ### `proofai_verify`
46
+ Verify a bundle's integrity and blockchain anchoring.
47
+
48
+ ```
49
+ > Use proofai_verify to check bundle bnd_8019b37a7f44_1774735436195
50
+ ```
51
+
52
+ ### `proofai_polygonscan`
53
+ Get the Polygonscan URL for independent verification.
54
+
55
+ ```
56
+ > Use proofai_polygonscan for tx 0xbbf92ceb6354a066...
57
+ ```
58
+
59
+ ### `proofai_monitor`
60
+ Get AI compliance monitoring stats (EU AI Act Article 72).
61
+
62
+ ```
63
+ > Use proofai_monitor to check compliance status
64
+ ```
65
+
66
+ ## Why MCP?
67
+
68
+ Developers use Claude Code, not web dashboards. This MCP server brings AI compliance directly into the coding workflow:
69
+
70
+ - Every AI decision can be certified without leaving the terminal
71
+ - Verification is one tool call away
72
+ - Monitoring happens alongside development
73
+ - No context switching between coding and compliance
package/SKILL.md ADDED
@@ -0,0 +1,53 @@
1
+ # proofai
2
+
3
+ Cryptographic proof that AI thought before it answered. EU AI Act Article 12 compliant.
4
+
5
+ ## Tools
6
+
7
+ ### proofai_certify
8
+ Certify an AI decision with cryptographic proof. Runs the full ProofAI pipeline: compress, execute AI, analyze cognitive graph, sign with Ed25519, bundle evidence, anchor to Polygon blockchain, and verify. Returns a blockchain-verified evidence bundle with Polygonscan URL.
9
+
10
+ **When to use:** When you need tamper-evident proof of an AI decision for compliance, audit, or legal purposes.
11
+
12
+ ### proofai_log
13
+ Log an AI decision that already happened. Provide the original prompt and AI response — ProofAI signs it with Ed25519, bundles the evidence, and anchors the hash to Polygon. No AI execution needed.
14
+
15
+ **When to use:** When you want to retroactively certify an AI interaction that already occurred.
16
+
17
+ ### proofai_verify
18
+ Verify an evidence bundle's integrity and blockchain anchoring. Checks data integrity, timestamp validity, ledger anchoring, and hash matching against EU AI Act requirements.
19
+
20
+ **When to use:** When you need to confirm a bundle hasn't been tampered with.
21
+
22
+ ### proofai_polygonscan
23
+ Get the Polygonscan verification URL for a Polygon transaction hash. Anyone can independently verify the proof without an account.
24
+
25
+ **When to use:** When you need to share a verification link with a regulator, client, or auditor.
26
+
27
+ ### proofai_monitor
28
+ Get post-market monitoring statistics for AI compliance (EU AI Act Article 72). Returns anomaly counts, risk distribution, human review stats, and overall compliance status for the last 30 days.
29
+
30
+ **When to use:** When you need a compliance health check of your AI system.
31
+
32
+ ## Setup
33
+
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "proofai": {
38
+ "command": "npx",
39
+ "args": ["-y", "@proofai/mcp-server"],
40
+ "env": {
41
+ "PROOFAI_API_KEY": "pk_live_xxx",
42
+ "PROOFAI_ANON_KEY": "your-supabase-anon-key"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ ## Links
50
+
51
+ - GitHub: https://github.com/proof-ai/proofai
52
+ - npm SDK: https://www.npmjs.com/package/@proofai/sdk
53
+ - Regulator Portal: https://proofai-ochre.vercel.app/regulator
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,232 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const zod_1 = require("zod");
7
+ const API_BASE = process.env.PROOFAI_API_URL || "https://apzgbajvwzykygrxxrwm.supabase.co/functions/v1";
8
+ const API_KEY = process.env.PROOFAI_API_KEY || "";
9
+ const ANON_KEY = process.env.PROOFAI_ANON_KEY || "";
10
+ async function callAPI(path, body) {
11
+ const headers = { "Content-Type": "application/json" };
12
+ if (API_KEY.startsWith("pk_live_")) {
13
+ headers["x-api-key"] = API_KEY;
14
+ }
15
+ if (ANON_KEY) {
16
+ headers["Authorization"] = `Bearer ${ANON_KEY}`;
17
+ }
18
+ const res = await fetch(`${API_BASE}/${path}`, {
19
+ method: "POST",
20
+ headers,
21
+ body: JSON.stringify(body),
22
+ });
23
+ if (!res.ok) {
24
+ const text = await res.text();
25
+ throw new Error(`ProofAI API error ${res.status}: ${text}`);
26
+ }
27
+ return res.json();
28
+ }
29
+ const server = new mcp_js_1.McpServer({
30
+ name: "proofai",
31
+ version: "1.0.0",
32
+ });
33
+ // --- Tool: Log an AI decision (full pipeline) ---
34
+ server.tool("proofai_certify", "Certify an AI decision with cryptographic proof. Runs the full ProofAI pipeline: compress → execute → analyze → sign → bundle → anchor → verify. Returns a blockchain-verified evidence bundle.", {
35
+ prompt: zod_1.z.string().describe("The AI prompt to certify"),
36
+ provider: zod_1.z.enum(["anthropic", "openai", "gemini"]).default("anthropic").describe("AI provider"),
37
+ temperature: zod_1.z.number().default(0.7).describe("Generation temperature"),
38
+ maxTokens: zod_1.z.number().default(1024).describe("Max output tokens"),
39
+ }, async ({ prompt, provider, temperature, maxTokens }) => {
40
+ try {
41
+ // 1. Compress
42
+ const compressed = (await callAPI("compress", { prompt, options: { compressionLevel: "medium" } }));
43
+ // 2. Execute
44
+ const execution = (await callAPI("execute", {
45
+ promptRef: compressed.id,
46
+ options: { provider, modelId: "auto", temperature, maxTokens },
47
+ }));
48
+ // 3. Analyze
49
+ const analysis = (await callAPI("analyze", {
50
+ executionId: execution.id,
51
+ analysisText: execution.output,
52
+ }));
53
+ // 4. Sign
54
+ const signature = (await callAPI("sign", {
55
+ executionId: execution.id,
56
+ rawOutput: execution.output,
57
+ modelProvider: execution.metadata.provider,
58
+ modelId: execution.metadata.model,
59
+ modelVersion: "latest",
60
+ modelParameters: { temperature },
61
+ executionMetrics: { tokens: execution.metadata.tokens.total },
62
+ requesterInfo: { source: "mcp-server" },
63
+ timestamps: { request_received: new Date().toISOString() },
64
+ }));
65
+ // 5. Bundle
66
+ const bundle = (await callAPI("bundle", {
67
+ promptId: compressed.id,
68
+ executionId: execution.id,
69
+ analysisId: analysis.id,
70
+ signatureId: signature.signatureId,
71
+ cognitiveHash: analysis.cognitiveHash,
72
+ promptContent: prompt,
73
+ aiResponse: execution.output,
74
+ }));
75
+ // 6. Anchor
76
+ let anchor = {};
77
+ try {
78
+ anchor = (await callAPI("anchor", { bundleId: bundle.id, network: "polygon" }));
79
+ }
80
+ catch { /* anchor is best-effort */ }
81
+ // 7. Verify
82
+ const verification = (await callAPI("verify", { bundleId: bundle.id }));
83
+ return {
84
+ content: [
85
+ {
86
+ type: "text",
87
+ text: JSON.stringify({
88
+ status: "certified",
89
+ bundleId: bundle.id,
90
+ bundleHash: bundle.bundleHash,
91
+ verified: verification.verified,
92
+ explorerUrl: anchor.explorerUrl || null,
93
+ transactionHash: anchor.transactionHash || null,
94
+ provider: execution.metadata.provider,
95
+ model: execution.metadata.model,
96
+ tokens: execution.metadata.tokens.total,
97
+ cognitiveNodes: analysis.metrics.nodeCount,
98
+ consistencyScore: analysis.metrics.consistencyScore,
99
+ aiResponse: execution.output.substring(0, 500) + (execution.output.length > 500 ? "..." : ""),
100
+ }, null, 2),
101
+ },
102
+ ],
103
+ };
104
+ }
105
+ catch (err) {
106
+ return {
107
+ content: [{ type: "text", text: `Error: ${err.message}` }],
108
+ isError: true,
109
+ };
110
+ }
111
+ });
112
+ // --- Tool: Log a decision (just record, don't execute AI) ---
113
+ server.tool("proofai_log", "Log an AI decision that already happened. Creates an evidence bundle with the prompt and response you provide, signs it with Ed25519, and anchors to Polygon.", {
114
+ prompt: zod_1.z.string().describe("The original prompt"),
115
+ response: zod_1.z.string().describe("The AI response to log"),
116
+ provider: zod_1.z.string().default("unknown").describe("Which AI provider generated the response"),
117
+ model: zod_1.z.string().default("unknown").describe("Which model was used"),
118
+ }, async ({ prompt, response, provider, model }) => {
119
+ try {
120
+ // Compress
121
+ const compressed = (await callAPI("compress", { prompt, options: {} }));
122
+ // Analyze
123
+ const analysis = (await callAPI("analyze", {
124
+ executionId: `ext_${Date.now()}`,
125
+ analysisText: response,
126
+ }));
127
+ // Sign
128
+ const signature = (await callAPI("sign", {
129
+ executionId: `ext_${Date.now()}`,
130
+ rawOutput: response,
131
+ modelProvider: provider,
132
+ modelId: model,
133
+ modelVersion: "external",
134
+ modelParameters: {},
135
+ executionMetrics: {},
136
+ requesterInfo: { source: "mcp-server-log" },
137
+ timestamps: { logged_at: new Date().toISOString() },
138
+ }));
139
+ // Bundle
140
+ const bundle = (await callAPI("bundle", {
141
+ promptId: compressed.id,
142
+ executionId: `ext_${Date.now()}`,
143
+ analysisId: analysis.id,
144
+ signatureId: signature.signatureId,
145
+ cognitiveHash: analysis.cognitiveHash,
146
+ promptContent: prompt,
147
+ aiResponse: response,
148
+ provider,
149
+ model,
150
+ }));
151
+ // Anchor
152
+ let explorerUrl = null;
153
+ try {
154
+ const anchor = (await callAPI("anchor", { bundleId: bundle.id, network: "polygon" }));
155
+ explorerUrl = anchor.explorerUrl;
156
+ }
157
+ catch { /* best-effort */ }
158
+ return {
159
+ content: [{
160
+ type: "text",
161
+ text: `Logged and certified.\n\nBundle ID: ${bundle.id}\nBundle Hash: ${bundle.bundleHash}\nPolygonscan: ${explorerUrl || "pending"}\n\nThis decision is now tamper-evident and blockchain-anchored.`,
162
+ }],
163
+ };
164
+ }
165
+ catch (err) {
166
+ return {
167
+ content: [{ type: "text", text: `Error: ${err.message}` }],
168
+ isError: true,
169
+ };
170
+ }
171
+ });
172
+ // --- Tool: Verify a bundle ---
173
+ server.tool("proofai_verify", "Verify an evidence bundle's integrity and blockchain anchoring. Returns compliance checks against EU AI Act articles.", {
174
+ bundleId: zod_1.z.string().describe("The bundle ID to verify (e.g., bnd_xxx)"),
175
+ }, async ({ bundleId }) => {
176
+ try {
177
+ const result = (await callAPI("verify", { bundleId }));
178
+ const checksText = Object.entries(result.checks)
179
+ .map(([k, v]) => ` ${v ? "✅" : "❌"} ${k}`)
180
+ .join("\n");
181
+ return {
182
+ content: [{
183
+ type: "text",
184
+ text: `Bundle: ${result.bundleId}\nVerified: ${result.verified ? "✅ YES" : "❌ NO"}\n\nChecks:\n${checksText}${result.ledgerInfo
185
+ ? `\n\nBlockchain:\n Network: ${result.ledgerInfo.network}\n Block: #${result.ledgerInfo.blockNumber}\n Tx: ${result.ledgerInfo.transactionHash}`
186
+ : ""}`,
187
+ }],
188
+ };
189
+ }
190
+ catch (err) {
191
+ return {
192
+ content: [{ type: "text", text: `Error: ${err.message}` }],
193
+ isError: true,
194
+ };
195
+ }
196
+ });
197
+ // --- Tool: Get Polygonscan link ---
198
+ server.tool("proofai_polygonscan", "Get the Polygonscan verification URL for a transaction hash. Anyone can verify the proof independently.", {
199
+ txHash: zod_1.z.string().describe("The Polygon transaction hash (0x...)"),
200
+ }, async ({ txHash }) => {
201
+ const url = `https://amoy.polygonscan.com/tx/${txHash}`;
202
+ return {
203
+ content: [{
204
+ type: "text",
205
+ text: `Polygonscan verification URL:\n${url}\n\nAnyone can verify this proof — no account, no login, no middleman. Just math.`,
206
+ }],
207
+ };
208
+ });
209
+ // --- Tool: Get monitoring stats ---
210
+ server.tool("proofai_monitor", "Get post-market monitoring statistics for AI compliance (EU AI Act Article 72). Shows anomalies, risk distribution, and compliance status.", {}, async () => {
211
+ try {
212
+ const stats = await callAPI("monitor", {});
213
+ return {
214
+ content: [{
215
+ type: "text",
216
+ text: JSON.stringify(stats, null, 2),
217
+ }],
218
+ };
219
+ }
220
+ catch (err) {
221
+ return {
222
+ content: [{ type: "text", text: `Error: ${err.message}` }],
223
+ isError: true,
224
+ };
225
+ }
226
+ });
227
+ // Start server
228
+ async function main() {
229
+ const transport = new stdio_js_1.StdioServerTransport();
230
+ await server.connect(transport);
231
+ }
232
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@proofai/mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "ProofAI MCP Server — AI compliance tools for Claude Code",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "proofai-mcp": "dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "start": "node dist/index.js"
12
+ },
13
+ "author": "HIRAM",
14
+ "license": "MIT",
15
+ "dependencies": {
16
+ "@modelcontextprotocol/sdk": "^1.0.0",
17
+ "zod": "^4.3.6"
18
+ },
19
+ "devDependencies": {
20
+ "@types/node": "^22.0.0",
21
+ "typescript": "^5.8.0"
22
+ }
23
+ }
package/src/index.ts ADDED
@@ -0,0 +1,282 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { z } from "zod";
6
+
7
+ const API_BASE = process.env.PROOFAI_API_URL || "https://apzgbajvwzykygrxxrwm.supabase.co/functions/v1";
8
+ const API_KEY = process.env.PROOFAI_API_KEY || "";
9
+ const ANON_KEY = process.env.PROOFAI_ANON_KEY || "";
10
+
11
+ async function callAPI(path: string, body: Record<string, unknown>): Promise<unknown> {
12
+ const headers: Record<string, string> = { "Content-Type": "application/json" };
13
+ if (API_KEY.startsWith("pk_live_")) {
14
+ headers["x-api-key"] = API_KEY;
15
+ }
16
+ if (ANON_KEY) {
17
+ headers["Authorization"] = `Bearer ${ANON_KEY}`;
18
+ }
19
+
20
+ const res = await fetch(`${API_BASE}/${path}`, {
21
+ method: "POST",
22
+ headers,
23
+ body: JSON.stringify(body),
24
+ });
25
+ if (!res.ok) {
26
+ const text = await res.text();
27
+ throw new Error(`ProofAI API error ${res.status}: ${text}`);
28
+ }
29
+ return res.json();
30
+ }
31
+
32
+ const server = new McpServer({
33
+ name: "proofai",
34
+ version: "1.0.0",
35
+ });
36
+
37
+ // --- Tool: Log an AI decision (full pipeline) ---
38
+ server.tool(
39
+ "proofai_certify",
40
+ "Certify an AI decision with cryptographic proof. Runs the full ProofAI pipeline: compress → execute → analyze → sign → bundle → anchor → verify. Returns a blockchain-verified evidence bundle.",
41
+ {
42
+ prompt: z.string().describe("The AI prompt to certify"),
43
+ provider: z.enum(["anthropic", "openai", "gemini"]).default("anthropic").describe("AI provider"),
44
+ temperature: z.number().default(0.7).describe("Generation temperature"),
45
+ maxTokens: z.number().default(1024).describe("Max output tokens"),
46
+ },
47
+ async ({ prompt, provider, temperature, maxTokens }) => {
48
+ try {
49
+ // 1. Compress
50
+ const compressed = (await callAPI("compress", { prompt, options: { compressionLevel: "medium" } })) as { id: string; compressedDsl: string };
51
+
52
+ // 2. Execute
53
+ const execution = (await callAPI("execute", {
54
+ promptRef: compressed.id,
55
+ options: { provider, modelId: "auto", temperature, maxTokens },
56
+ })) as { id: string; output: string; metadata: { provider: string; model: string; tokens: { total: number } } };
57
+
58
+ // 3. Analyze
59
+ const analysis = (await callAPI("analyze", {
60
+ executionId: execution.id,
61
+ analysisText: execution.output,
62
+ })) as { id: string; cognitiveHash: string; metrics: { nodeCount: number; consistencyScore: number } };
63
+
64
+ // 4. Sign
65
+ const signature = (await callAPI("sign", {
66
+ executionId: execution.id,
67
+ rawOutput: execution.output,
68
+ modelProvider: execution.metadata.provider,
69
+ modelId: execution.metadata.model,
70
+ modelVersion: "latest",
71
+ modelParameters: { temperature },
72
+ executionMetrics: { tokens: execution.metadata.tokens.total },
73
+ requesterInfo: { source: "mcp-server" },
74
+ timestamps: { request_received: new Date().toISOString() },
75
+ })) as { signatureId: string };
76
+
77
+ // 5. Bundle
78
+ const bundle = (await callAPI("bundle", {
79
+ promptId: compressed.id,
80
+ executionId: execution.id,
81
+ analysisId: analysis.id,
82
+ signatureId: signature.signatureId,
83
+ cognitiveHash: analysis.cognitiveHash,
84
+ promptContent: prompt,
85
+ aiResponse: execution.output,
86
+ })) as { id: string; bundleHash: string };
87
+
88
+ // 6. Anchor
89
+ let anchor: { transactionHash?: string; explorerUrl?: string; status?: string } = {};
90
+ try {
91
+ anchor = (await callAPI("anchor", { bundleId: bundle.id, network: "polygon" })) as typeof anchor;
92
+ } catch { /* anchor is best-effort */ }
93
+
94
+ // 7. Verify
95
+ const verification = (await callAPI("verify", { bundleId: bundle.id })) as { verified: boolean };
96
+
97
+ return {
98
+ content: [
99
+ {
100
+ type: "text" as const,
101
+ text: JSON.stringify({
102
+ status: "certified",
103
+ bundleId: bundle.id,
104
+ bundleHash: bundle.bundleHash,
105
+ verified: verification.verified,
106
+ explorerUrl: anchor.explorerUrl || null,
107
+ transactionHash: anchor.transactionHash || null,
108
+ provider: execution.metadata.provider,
109
+ model: execution.metadata.model,
110
+ tokens: execution.metadata.tokens.total,
111
+ cognitiveNodes: analysis.metrics.nodeCount,
112
+ consistencyScore: analysis.metrics.consistencyScore,
113
+ aiResponse: execution.output.substring(0, 500) + (execution.output.length > 500 ? "..." : ""),
114
+ }, null, 2),
115
+ },
116
+ ],
117
+ };
118
+ } catch (err) {
119
+ return {
120
+ content: [{ type: "text" as const, text: `Error: ${(err as Error).message}` }],
121
+ isError: true,
122
+ };
123
+ }
124
+ }
125
+ );
126
+
127
+ // --- Tool: Log a decision (just record, don't execute AI) ---
128
+ server.tool(
129
+ "proofai_log",
130
+ "Log an AI decision that already happened. Creates an evidence bundle with the prompt and response you provide, signs it with Ed25519, and anchors to Polygon.",
131
+ {
132
+ prompt: z.string().describe("The original prompt"),
133
+ response: z.string().describe("The AI response to log"),
134
+ provider: z.string().default("unknown").describe("Which AI provider generated the response"),
135
+ model: z.string().default("unknown").describe("Which model was used"),
136
+ },
137
+ async ({ prompt, response, provider, model }) => {
138
+ try {
139
+ // Compress
140
+ const compressed = (await callAPI("compress", { prompt, options: {} })) as { id: string };
141
+
142
+ // Analyze
143
+ const analysis = (await callAPI("analyze", {
144
+ executionId: `ext_${Date.now()}`,
145
+ analysisText: response,
146
+ })) as { id: string; cognitiveHash: string };
147
+
148
+ // Sign
149
+ const signature = (await callAPI("sign", {
150
+ executionId: `ext_${Date.now()}`,
151
+ rawOutput: response,
152
+ modelProvider: provider,
153
+ modelId: model,
154
+ modelVersion: "external",
155
+ modelParameters: {},
156
+ executionMetrics: {},
157
+ requesterInfo: { source: "mcp-server-log" },
158
+ timestamps: { logged_at: new Date().toISOString() },
159
+ })) as { signatureId: string };
160
+
161
+ // Bundle
162
+ const bundle = (await callAPI("bundle", {
163
+ promptId: compressed.id,
164
+ executionId: `ext_${Date.now()}`,
165
+ analysisId: analysis.id,
166
+ signatureId: signature.signatureId,
167
+ cognitiveHash: analysis.cognitiveHash,
168
+ promptContent: prompt,
169
+ aiResponse: response,
170
+ provider,
171
+ model,
172
+ })) as { id: string; bundleHash: string };
173
+
174
+ // Anchor
175
+ let explorerUrl: string | null = null;
176
+ try {
177
+ const anchor = (await callAPI("anchor", { bundleId: bundle.id, network: "polygon" })) as { explorerUrl: string };
178
+ explorerUrl = anchor.explorerUrl;
179
+ } catch { /* best-effort */ }
180
+
181
+ return {
182
+ content: [{
183
+ type: "text" as const,
184
+ text: `Logged and certified.\n\nBundle ID: ${bundle.id}\nBundle Hash: ${bundle.bundleHash}\nPolygonscan: ${explorerUrl || "pending"}\n\nThis decision is now tamper-evident and blockchain-anchored.`,
185
+ }],
186
+ };
187
+ } catch (err) {
188
+ return {
189
+ content: [{ type: "text" as const, text: `Error: ${(err as Error).message}` }],
190
+ isError: true,
191
+ };
192
+ }
193
+ }
194
+ );
195
+
196
+ // --- Tool: Verify a bundle ---
197
+ server.tool(
198
+ "proofai_verify",
199
+ "Verify an evidence bundle's integrity and blockchain anchoring. Returns compliance checks against EU AI Act articles.",
200
+ {
201
+ bundleId: z.string().describe("The bundle ID to verify (e.g., bnd_xxx)"),
202
+ },
203
+ async ({ bundleId }) => {
204
+ try {
205
+ const result = (await callAPI("verify", { bundleId })) as {
206
+ bundleId: string;
207
+ verified: boolean;
208
+ checks: Record<string, boolean>;
209
+ ledgerInfo?: { transactionHash: string; blockNumber: number; network: string };
210
+ };
211
+
212
+ const checksText = Object.entries(result.checks)
213
+ .map(([k, v]) => ` ${v ? "✅" : "❌"} ${k}`)
214
+ .join("\n");
215
+
216
+ return {
217
+ content: [{
218
+ type: "text" as const,
219
+ text: `Bundle: ${result.bundleId}\nVerified: ${result.verified ? "✅ YES" : "❌ NO"}\n\nChecks:\n${checksText}${
220
+ result.ledgerInfo
221
+ ? `\n\nBlockchain:\n Network: ${result.ledgerInfo.network}\n Block: #${result.ledgerInfo.blockNumber}\n Tx: ${result.ledgerInfo.transactionHash}`
222
+ : ""
223
+ }`,
224
+ }],
225
+ };
226
+ } catch (err) {
227
+ return {
228
+ content: [{ type: "text" as const, text: `Error: ${(err as Error).message}` }],
229
+ isError: true,
230
+ };
231
+ }
232
+ }
233
+ );
234
+
235
+ // --- Tool: Get Polygonscan link ---
236
+ server.tool(
237
+ "proofai_polygonscan",
238
+ "Get the Polygonscan verification URL for a transaction hash. Anyone can verify the proof independently.",
239
+ {
240
+ txHash: z.string().describe("The Polygon transaction hash (0x...)"),
241
+ },
242
+ async ({ txHash }) => {
243
+ const url = `https://amoy.polygonscan.com/tx/${txHash}`;
244
+ return {
245
+ content: [{
246
+ type: "text" as const,
247
+ text: `Polygonscan verification URL:\n${url}\n\nAnyone can verify this proof — no account, no login, no middleman. Just math.`,
248
+ }],
249
+ };
250
+ }
251
+ );
252
+
253
+ // --- Tool: Get monitoring stats ---
254
+ server.tool(
255
+ "proofai_monitor",
256
+ "Get post-market monitoring statistics for AI compliance (EU AI Act Article 72). Shows anomalies, risk distribution, and compliance status.",
257
+ {},
258
+ async () => {
259
+ try {
260
+ const stats = await callAPI("monitor", {});
261
+ return {
262
+ content: [{
263
+ type: "text" as const,
264
+ text: JSON.stringify(stats, null, 2),
265
+ }],
266
+ };
267
+ } catch (err) {
268
+ return {
269
+ content: [{ type: "text" as const, text: `Error: ${(err as Error).message}` }],
270
+ isError: true,
271
+ };
272
+ }
273
+ }
274
+ );
275
+
276
+ // Start server
277
+ async function main() {
278
+ const transport = new StdioServerTransport();
279
+ await server.connect(transport);
280
+ }
281
+
282
+ main().catch(console.error);
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "skipLibCheck": true,
7
+ "declaration": true,
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "outDir": "dist",
11
+ "rootDir": "src"
12
+ },
13
+ "include": ["src"]
14
+ }