aipou-mcp-server 0.2.2 → 0.3.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 +19 -0
- package/dist/canonical.test.d.ts +1 -0
- package/dist/canonical.test.js +49 -0
- package/dist/demo.d.ts +30 -0
- package/dist/demo.js +97 -0
- package/dist/demo.test.d.ts +1 -0
- package/dist/demo.test.js +27 -0
- package/dist/index.js +20 -2
- package/dist/rewards.test.d.ts +1 -0
- package/dist/rewards.test.js +132 -0
- package/package.json +4 -2
- package/server.json +2 -2
package/README.md
CHANGED
|
@@ -6,6 +6,25 @@ It does not detect hidden AI use, prove task quality, replace payment rails, or
|
|
|
6
6
|
|
|
7
7
|
## Fast Local Adoption Test
|
|
8
8
|
|
|
9
|
+
From a source checkout, create and verify one disposable local receipt:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install
|
|
13
|
+
npm run demo -w mcp-server
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The command needs no wallet setup, funds, network, or claims. It prints a
|
|
17
|
+
framework-ready `workReceiptId` object and deletes its ephemeral wallet,
|
|
18
|
+
collector key, and receipt state before exiting.
|
|
19
|
+
|
|
20
|
+
After the next npm release, the same check will run without cloning:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx -y aipou-mcp-server --demo
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For a complete framework lifecycle example, continue with the adapter below.
|
|
27
|
+
|
|
9
28
|
If you are evaluating AIPOU for an agent framework, start with the lifecycle adapter example:
|
|
10
29
|
|
|
11
30
|
```bash
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { canonicalJson, sha256Hex } from "./canonical.js";
|
|
4
|
+
test("canonicalJson serializes primitives correctly", () => {
|
|
5
|
+
assert.equal(canonicalJson(42), "42");
|
|
6
|
+
assert.equal(canonicalJson("hello"), "\"hello\"");
|
|
7
|
+
assert.equal(canonicalJson(true), "true");
|
|
8
|
+
assert.equal(canonicalJson(null), "null");
|
|
9
|
+
});
|
|
10
|
+
test("canonicalJson sorts object keys lexicographically", () => {
|
|
11
|
+
const unsorted = { b: 1, a: 2, c: 3 };
|
|
12
|
+
const sorted = { a: 2, b: 1, c: 3 };
|
|
13
|
+
assert.equal(canonicalJson(unsorted), canonicalJson(sorted));
|
|
14
|
+
assert.equal(canonicalJson(unsorted), "{\"a\":2,\"b\":1,\"c\":3}");
|
|
15
|
+
});
|
|
16
|
+
test("canonicalJson omits undefined values from objects", () => {
|
|
17
|
+
const obj = { a: 1, b: undefined, c: 3 };
|
|
18
|
+
assert.equal(canonicalJson(obj), "{\"a\":1,\"c\":3}");
|
|
19
|
+
});
|
|
20
|
+
test("canonicalJson handles nested objects with sorted keys", () => {
|
|
21
|
+
const obj = { outer: { z: 1, a: 2 } };
|
|
22
|
+
assert.equal(canonicalJson(obj), "{\"outer\":{\"a\":2,\"z\":1}}");
|
|
23
|
+
});
|
|
24
|
+
test("canonicalJson handles arrays preserving order", () => {
|
|
25
|
+
assert.equal(canonicalJson([3, 1, 2]), "[3,1,2]");
|
|
26
|
+
assert.equal(canonicalJson([{ b: 1, a: 2 }]), "[{\"a\":2,\"b\":1}]");
|
|
27
|
+
});
|
|
28
|
+
test("canonicalJson is deterministic for deeply nested mixed structures", () => {
|
|
29
|
+
const a = { z: [1, 2], y: { b: 2, a: 1 } };
|
|
30
|
+
const b = { y: { a: 1, b: 2 }, z: [1, 2] };
|
|
31
|
+
assert.equal(canonicalJson(a), canonicalJson(b));
|
|
32
|
+
});
|
|
33
|
+
test("sha256Hex produces a 0x-prefixed 64-char hex string", () => {
|
|
34
|
+
const hash = sha256Hex("test");
|
|
35
|
+
assert.match(hash, /^0x[0-9a-f]{64}$/);
|
|
36
|
+
assert.equal(hash, "0x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08");
|
|
37
|
+
});
|
|
38
|
+
test("sha256Hex is deterministic for the same input", () => {
|
|
39
|
+
assert.equal(sha256Hex("hello"), sha256Hex("hello"));
|
|
40
|
+
assert.notEqual(sha256Hex("hello"), sha256Hex("world"));
|
|
41
|
+
});
|
|
42
|
+
test("canonicalJson handles empty objects and arrays", () => {
|
|
43
|
+
assert.equal(canonicalJson({}), "{}");
|
|
44
|
+
assert.equal(canonicalJson([]), "[]");
|
|
45
|
+
});
|
|
46
|
+
test("canonicalJson handles mixed undefined and null values", () => {
|
|
47
|
+
const obj = { a: null, b: undefined, c: 0, d: "" };
|
|
48
|
+
assert.equal(canonicalJson(obj), "{\"a\":null,\"c\":0,\"d\":\"\"}");
|
|
49
|
+
});
|
package/dist/demo.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface LocalDemoResult {
|
|
2
|
+
mode: "local_receipt_demo";
|
|
3
|
+
wallet: string;
|
|
4
|
+
storage: "removed_after_demo";
|
|
5
|
+
frameworkMetadata: {
|
|
6
|
+
aipou: {
|
|
7
|
+
type: "aipou.receipt";
|
|
8
|
+
workReceiptId: string;
|
|
9
|
+
receiptId: string;
|
|
10
|
+
factId: string;
|
|
11
|
+
evidenceClass: "issuer_asserted";
|
|
12
|
+
scheme: "aipou-receipt-v1";
|
|
13
|
+
status: "local_demo";
|
|
14
|
+
trustTier: "client_signed" | "provider_signed";
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
verification: {
|
|
18
|
+
walletAuthorization: boolean;
|
|
19
|
+
collectorSignature: boolean;
|
|
20
|
+
};
|
|
21
|
+
safety: {
|
|
22
|
+
networkRequired: false;
|
|
23
|
+
fundsMoved: false;
|
|
24
|
+
claimSubmitted: false;
|
|
25
|
+
rawPromptStored: false;
|
|
26
|
+
rawOutputStored: false;
|
|
27
|
+
privateKeyPrinted: false;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export declare function runLocalReceiptDemo(): Promise<LocalDemoResult>;
|
package/dist/demo.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { Wallet } from "ethers";
|
|
6
|
+
import { canonicalJson, sha256Hex } from "./canonical.js";
|
|
7
|
+
import { collectorFingerprint, verifyCollectorPayload } from "./collector.js";
|
|
8
|
+
import { verifyTaskAuthorization } from "./identity.js";
|
|
9
|
+
import { beginTask, completeTask } from "./receipts.js";
|
|
10
|
+
const TOKEN_ADDRESS = "0x55f0Cc5e51A1284D20337d6cbb18938C8A1ABCbB";
|
|
11
|
+
const CLAIMS_ADDRESS = "0x4ca4C98fB784D20EdC8E2A7F531dAab4c6e53058";
|
|
12
|
+
const RECEIPT_SCHEME = "aipou-receipt-v1";
|
|
13
|
+
const DEMO_ENVIRONMENT_KEYS = [
|
|
14
|
+
"AIPOU_AGENT_PRIVATE_KEY",
|
|
15
|
+
"AIPOU_CONTRACT_ADDRESS",
|
|
16
|
+
"AIPOU_CLAIMS_ADDRESS",
|
|
17
|
+
"AIPOU_DATA_DIR"
|
|
18
|
+
];
|
|
19
|
+
function deriveFactId(publicKey, nonce) {
|
|
20
|
+
const fingerprint = collectorFingerprint(publicKey);
|
|
21
|
+
const material = `${RECEIPT_SCHEME}\n${fingerprint}\n${nonce.toLowerCase()}`;
|
|
22
|
+
return `0x${createHash("sha256").update(material).digest("hex")}`;
|
|
23
|
+
}
|
|
24
|
+
export async function runLocalReceiptDemo() {
|
|
25
|
+
const previousEnvironment = new Map(DEMO_ENVIRONMENT_KEYS.map((key) => [key, process.env[key]]));
|
|
26
|
+
const dataDir = await mkdtemp(path.join(os.tmpdir(), "aipou-one-command-demo-"));
|
|
27
|
+
const wallet = Wallet.createRandom();
|
|
28
|
+
process.env.AIPOU_AGENT_PRIVATE_KEY = wallet.privateKey;
|
|
29
|
+
process.env.AIPOU_CONTRACT_ADDRESS = TOKEN_ADDRESS;
|
|
30
|
+
process.env.AIPOU_CLAIMS_ADDRESS = CLAIMS_ADDRESS;
|
|
31
|
+
process.env.AIPOU_DATA_DIR = dataDir;
|
|
32
|
+
try {
|
|
33
|
+
const taskHash = sha256Hex(canonicalJson({
|
|
34
|
+
kind: "demo.one-command-adoption",
|
|
35
|
+
intent: "create a private local AIPOU receipt without setup"
|
|
36
|
+
}));
|
|
37
|
+
const outputHash = sha256Hex(canonicalJson({
|
|
38
|
+
status: "ok",
|
|
39
|
+
artifact: "local receipt reference"
|
|
40
|
+
}));
|
|
41
|
+
const session = await beginTask({
|
|
42
|
+
provider: "local-demo",
|
|
43
|
+
model: "aipou-one-command-demo",
|
|
44
|
+
client: "aipou-cli",
|
|
45
|
+
taskHash,
|
|
46
|
+
chainId: 8453,
|
|
47
|
+
verifyingContract: CLAIMS_ADDRESS
|
|
48
|
+
});
|
|
49
|
+
const receipt = await completeTask({
|
|
50
|
+
nonce: session.nonce,
|
|
51
|
+
inputTokens: 18,
|
|
52
|
+
outputTokens: 12,
|
|
53
|
+
durationSeconds: 1,
|
|
54
|
+
outputHash
|
|
55
|
+
});
|
|
56
|
+
const { collectorSignature, ...signedPayload } = receipt;
|
|
57
|
+
return {
|
|
58
|
+
mode: "local_receipt_demo",
|
|
59
|
+
wallet: receipt.wallet,
|
|
60
|
+
storage: "removed_after_demo",
|
|
61
|
+
frameworkMetadata: {
|
|
62
|
+
aipou: {
|
|
63
|
+
type: "aipou.receipt",
|
|
64
|
+
workReceiptId: receipt.receiptId,
|
|
65
|
+
receiptId: receipt.receiptId,
|
|
66
|
+
factId: deriveFactId(receipt.collectorPublicKey, receipt.nonce),
|
|
67
|
+
evidenceClass: "issuer_asserted",
|
|
68
|
+
scheme: RECEIPT_SCHEME,
|
|
69
|
+
status: "local_demo",
|
|
70
|
+
trustTier: receipt.trustTier
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
verification: {
|
|
74
|
+
walletAuthorization: verifyTaskAuthorization(session),
|
|
75
|
+
collectorSignature: verifyCollectorPayload(signedPayload, collectorSignature, receipt.collectorPublicKey)
|
|
76
|
+
},
|
|
77
|
+
safety: {
|
|
78
|
+
networkRequired: false,
|
|
79
|
+
fundsMoved: false,
|
|
80
|
+
claimSubmitted: false,
|
|
81
|
+
rawPromptStored: false,
|
|
82
|
+
rawOutputStored: false,
|
|
83
|
+
privateKeyPrinted: false
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
await rm(dataDir, { recursive: true, force: true });
|
|
89
|
+
for (const key of DEMO_ENVIRONMENT_KEYS) {
|
|
90
|
+
const previous = previousEnvironment.get(key);
|
|
91
|
+
if (previous === undefined)
|
|
92
|
+
delete process.env[key];
|
|
93
|
+
else
|
|
94
|
+
process.env[key] = previous;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { runLocalReceiptDemo } from "./demo.js";
|
|
4
|
+
test("one-command demo creates a verified receipt without persistent secrets or claims", async () => {
|
|
5
|
+
const previousPrivateKey = process.env.AIPOU_AGENT_PRIVATE_KEY;
|
|
6
|
+
const previousDataDir = process.env.AIPOU_DATA_DIR;
|
|
7
|
+
const result = await runLocalReceiptDemo();
|
|
8
|
+
assert.equal(result.mode, "local_receipt_demo");
|
|
9
|
+
assert.match(result.wallet, /^0x[0-9a-fA-F]{40}$/);
|
|
10
|
+
assert.match(result.frameworkMetadata.aipou.workReceiptId, /^0x[0-9a-f]{64}$/);
|
|
11
|
+
assert.equal(result.frameworkMetadata.aipou.workReceiptId, result.frameworkMetadata.aipou.receiptId);
|
|
12
|
+
assert.match(result.frameworkMetadata.aipou.factId, /^0x[0-9a-f]{64}$/);
|
|
13
|
+
assert.deepEqual(result.verification, {
|
|
14
|
+
walletAuthorization: true,
|
|
15
|
+
collectorSignature: true
|
|
16
|
+
});
|
|
17
|
+
assert.deepEqual(result.safety, {
|
|
18
|
+
networkRequired: false,
|
|
19
|
+
fundsMoved: false,
|
|
20
|
+
claimSubmitted: false,
|
|
21
|
+
rawPromptStored: false,
|
|
22
|
+
rawOutputStored: false,
|
|
23
|
+
privateKeyPrinted: false
|
|
24
|
+
});
|
|
25
|
+
assert.equal(process.env.AIPOU_AGENT_PRIVATE_KEY, previousPrivateKey);
|
|
26
|
+
assert.equal(process.env.AIPOU_DATA_DIR, previousDataDir);
|
|
27
|
+
});
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { z } from "zod";
|
|
|
6
6
|
import { settleAllRewards, settleRewards } from "./claims.js";
|
|
7
7
|
import { collectorFingerprint, getCollectorPublicKey } from "./collector.js";
|
|
8
8
|
import { aipouClaimsAbi, aipouTokenAbi, getTokenContractConfig } from "./contract.js";
|
|
9
|
+
import { runLocalReceiptDemo } from "./demo.js";
|
|
9
10
|
import { agentWallet } from "./identity.js";
|
|
10
11
|
import { beginTask, completeTask, exportReceipts } from "./receipts.js";
|
|
11
12
|
import { estimateReward } from "./rewards.js";
|
|
@@ -93,5 +94,22 @@ server.tool("settle_all_ai_rewards", "After an explicit broad claim request, set
|
|
|
93
94
|
const result = await settleAllRewards(batchSize, maxBatches);
|
|
94
95
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
95
96
|
});
|
|
96
|
-
const
|
|
97
|
-
|
|
97
|
+
const cliArguments = new Set(process.argv.slice(2));
|
|
98
|
+
if (cliArguments.has("--demo")) {
|
|
99
|
+
console.log(JSON.stringify(await runLocalReceiptDemo(), null, 2));
|
|
100
|
+
}
|
|
101
|
+
else if (cliArguments.has("--help") || cliArguments.has("-h")) {
|
|
102
|
+
console.log(`AIPOU MCP Server
|
|
103
|
+
|
|
104
|
+
Usage:
|
|
105
|
+
aipou-mcp Start the MCP stdio server
|
|
106
|
+
aipou-mcp --demo Create and verify one disposable local receipt
|
|
107
|
+
aipou-mcp --help Show this help
|
|
108
|
+
|
|
109
|
+
The demo needs no wallet, funds, network, or configuration. Its temporary
|
|
110
|
+
wallet, collector key, and receipt state are removed before the command exits.`);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
const transport = new StdioServerTransport();
|
|
114
|
+
await server.connect(transport);
|
|
115
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { estimateReward } from "./rewards.js";
|
|
4
|
+
test("client_signed tier applies 0.75 multiplier", () => {
|
|
5
|
+
const reward = estimateReward({
|
|
6
|
+
inputTokens: 1000,
|
|
7
|
+
outputTokens: 500,
|
|
8
|
+
durationSeconds: 300,
|
|
9
|
+
trustTier: "client_signed"
|
|
10
|
+
});
|
|
11
|
+
const tokenScore = Math.min(1500 / 1000, 30);
|
|
12
|
+
const durationScore = Math.min(300 / 300, 12);
|
|
13
|
+
const expected = (tokenScore + durationScore) * 0.75;
|
|
14
|
+
assert.equal(reward, expected.toFixed(4));
|
|
15
|
+
});
|
|
16
|
+
test("provider_signed tier applies 1.5 multiplier", () => {
|
|
17
|
+
const reward = estimateReward({
|
|
18
|
+
inputTokens: 1000,
|
|
19
|
+
outputTokens: 500,
|
|
20
|
+
durationSeconds: 300,
|
|
21
|
+
trustTier: "provider_signed"
|
|
22
|
+
});
|
|
23
|
+
const tokenScore = Math.min(1500 / 1000, 30);
|
|
24
|
+
const durationScore = Math.min(300 / 300, 12);
|
|
25
|
+
const expected = (tokenScore + durationScore) * 1.5;
|
|
26
|
+
assert.equal(reward, expected.toFixed(4));
|
|
27
|
+
});
|
|
28
|
+
test("provider_signed yields higher reward than client_signed for same input", () => {
|
|
29
|
+
const clientReward = Number(estimateReward({
|
|
30
|
+
inputTokens: 2000,
|
|
31
|
+
outputTokens: 800,
|
|
32
|
+
durationSeconds: 600,
|
|
33
|
+
trustTier: "client_signed"
|
|
34
|
+
}));
|
|
35
|
+
const providerReward = Number(estimateReward({
|
|
36
|
+
inputTokens: 2000,
|
|
37
|
+
outputTokens: 800,
|
|
38
|
+
durationSeconds: 600,
|
|
39
|
+
trustTier: "provider_signed"
|
|
40
|
+
}));
|
|
41
|
+
assert.ok(providerReward > clientReward);
|
|
42
|
+
});
|
|
43
|
+
test("token score is capped at 30", () => {
|
|
44
|
+
const lowTokens = estimateReward({
|
|
45
|
+
inputTokens: 500,
|
|
46
|
+
outputTokens: 500,
|
|
47
|
+
durationSeconds: 0,
|
|
48
|
+
trustTier: "client_signed"
|
|
49
|
+
});
|
|
50
|
+
const cappedTokens = estimateReward({
|
|
51
|
+
inputTokens: 100000,
|
|
52
|
+
outputTokens: 100000,
|
|
53
|
+
durationSeconds: 0,
|
|
54
|
+
trustTier: "client_signed"
|
|
55
|
+
});
|
|
56
|
+
assert.equal(Number(cappedTokens), 30 * 0.75);
|
|
57
|
+
assert.ok(Number(cappedTokens) > Number(lowTokens));
|
|
58
|
+
});
|
|
59
|
+
test("duration score is capped at 12", () => {
|
|
60
|
+
const lowDuration = estimateReward({
|
|
61
|
+
inputTokens: 0,
|
|
62
|
+
outputTokens: 0,
|
|
63
|
+
durationSeconds: 60,
|
|
64
|
+
trustTier: "client_signed"
|
|
65
|
+
});
|
|
66
|
+
const cappedDuration = estimateReward({
|
|
67
|
+
inputTokens: 0,
|
|
68
|
+
outputTokens: 0,
|
|
69
|
+
durationSeconds: 99999,
|
|
70
|
+
trustTier: "client_signed"
|
|
71
|
+
});
|
|
72
|
+
assert.equal(Number(cappedDuration), 12 * 0.75);
|
|
73
|
+
assert.ok(Number(cappedDuration) > Number(lowDuration));
|
|
74
|
+
});
|
|
75
|
+
test("total reward is capped at 50", () => {
|
|
76
|
+
const maxReward = estimateReward({
|
|
77
|
+
inputTokens: 1000000,
|
|
78
|
+
outputTokens: 1000000,
|
|
79
|
+
durationSeconds: 100000,
|
|
80
|
+
trustTier: "provider_signed"
|
|
81
|
+
});
|
|
82
|
+
assert.equal(Number(maxReward), 50);
|
|
83
|
+
});
|
|
84
|
+
test("zero input yields zero reward", () => {
|
|
85
|
+
const reward = estimateReward({
|
|
86
|
+
inputTokens: 0,
|
|
87
|
+
outputTokens: 0,
|
|
88
|
+
durationSeconds: 0,
|
|
89
|
+
trustTier: "client_signed"
|
|
90
|
+
});
|
|
91
|
+
assert.equal(reward, "0.0000");
|
|
92
|
+
});
|
|
93
|
+
test("negative token counts are treated as zero", () => {
|
|
94
|
+
const reward = estimateReward({
|
|
95
|
+
inputTokens: -500,
|
|
96
|
+
outputTokens: -200,
|
|
97
|
+
durationSeconds: 300,
|
|
98
|
+
trustTier: "client_signed"
|
|
99
|
+
});
|
|
100
|
+
const durationScore = Math.min(300 / 300, 12);
|
|
101
|
+
const expected = durationScore * 0.75;
|
|
102
|
+
assert.equal(reward, expected.toFixed(4));
|
|
103
|
+
});
|
|
104
|
+
test("negative duration is treated as zero", () => {
|
|
105
|
+
const reward = estimateReward({
|
|
106
|
+
inputTokens: 1000,
|
|
107
|
+
outputTokens: 0,
|
|
108
|
+
durationSeconds: -100,
|
|
109
|
+
trustTier: "client_signed"
|
|
110
|
+
});
|
|
111
|
+
const tokenScore = Math.min(1000 / 1000, 30);
|
|
112
|
+
const expected = tokenScore * 0.75;
|
|
113
|
+
assert.equal(reward, expected.toFixed(4));
|
|
114
|
+
});
|
|
115
|
+
test("reward is always a fixed 4-decimal string", () => {
|
|
116
|
+
const reward = estimateReward({
|
|
117
|
+
inputTokens: 100,
|
|
118
|
+
outputTokens: 100,
|
|
119
|
+
durationSeconds: 30,
|
|
120
|
+
trustTier: "client_signed"
|
|
121
|
+
});
|
|
122
|
+
assert.match(reward, /^\d+\.\d{4}$/);
|
|
123
|
+
});
|
|
124
|
+
test("high token count with low duration hits token cap but not total cap", () => {
|
|
125
|
+
const reward = estimateReward({
|
|
126
|
+
inputTokens: 50000,
|
|
127
|
+
outputTokens: 50000,
|
|
128
|
+
durationSeconds: 0,
|
|
129
|
+
trustTier: "client_signed"
|
|
130
|
+
});
|
|
131
|
+
assert.equal(Number(reward), 30 * 0.75);
|
|
132
|
+
});
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aipou-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"mcpName": "io.github.0xddneto/ai-proof-of-us",
|
|
5
5
|
"description": "MCP server for private, signed AI task receipts and optional validated AIPOU claims.",
|
|
6
|
+
"author": "0xddneto",
|
|
6
7
|
"keywords": [
|
|
7
8
|
"mcp",
|
|
8
9
|
"model-context-protocol",
|
|
@@ -35,8 +36,9 @@
|
|
|
35
36
|
},
|
|
36
37
|
"scripts": {
|
|
37
38
|
"build": "tsc -p tsconfig.json",
|
|
38
|
-
"test": "npm run build && node --test dist/protocol.test.js",
|
|
39
|
+
"test": "npm run build && node --test dist/protocol.test.js dist/rewards.test.js dist/canonical.test.js dist/demo.test.js",
|
|
39
40
|
"pack:check": "npm test && npm pack --dry-run",
|
|
41
|
+
"demo": "npm run build && node dist/index.js --demo",
|
|
40
42
|
"dev": "tsx src/index.ts",
|
|
41
43
|
"start": "node dist/index.js",
|
|
42
44
|
"prepublishOnly": "npm test"
|
package/server.json
CHANGED
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
"source": "github",
|
|
10
10
|
"subfolder": "mcp-server"
|
|
11
11
|
},
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.3.0",
|
|
13
13
|
"packages": [
|
|
14
14
|
{
|
|
15
15
|
"registryType": "npm",
|
|
16
16
|
"identifier": "aipou-mcp-server",
|
|
17
|
-
"version": "0.
|
|
17
|
+
"version": "0.3.0",
|
|
18
18
|
"transport": {
|
|
19
19
|
"type": "stdio"
|
|
20
20
|
},
|