@helm-protocol/ttt-mcp 0.1.9 → 0.2.2

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 CHANGED
@@ -1,21 +1,22 @@
1
- MIT License
1
+ Business Source License 1.1
2
2
 
3
- Copyright (c) 2026 Helm Protocol Foundation
3
+ Parameters
4
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:
5
+ Licensor: Heime-Jorgen (Peter Jang)
6
+ Licensed Work: @helm-protocol/ttt-mcp
7
+ Change Date: 2029-05-28
8
+ Change License: Apache License, Version 2.0
11
9
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
10
+ Additional Use Grant:
11
+ The following uses are permitted without a commercial license:
12
+ - Non-commercial use (research, education, personal projects)
13
+ - Commercial use generating less than $10,000 USD/year in revenue
14
+ - Individual MEV bots or arbitrage bots operated for personal account
14
15
 
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.
16
+ For all other commercial use, a license is required. See:
17
+ https://kenosian.com/pricing
18
+
19
+ ---
20
+
21
+ Business Source License 1.1 terms apply. The full text is available at:
22
+ https://mariadb.com/bsl11/
package/README.md CHANGED
@@ -144,6 +144,151 @@ Config file locations:
144
144
  - Node.js >= 18
145
145
  - Network access for time synthesis (HTTPS to time.nist.gov, time.google.com, time.cloudflare.com)
146
146
 
147
+ ---
148
+
149
+ ## Use Cases
150
+
151
+ ### 1. MEV Bot — Transaction Ordering Proof
152
+
153
+ **Problem**: You got front-run. You know it happened. You can't prove it — mempool timestamps are per-node, unsigned, and non-authoritative. No evidence, no recourse.
154
+
155
+ **Solution**: Call `pot_generate` before submitting every transaction. The PoT receipt is cryptographically signed by three independent time sources (NIST, Google, Cloudflare), hashed on-chain to Base Sepolia TTT ERC-1155. If front-running occurs, you have a timestamped, on-chain-anchored record of your original submission that predates the attacker's block inclusion.
156
+
157
+ ```typescript
158
+ // Before tx submission
159
+ const pot = await client.callTool({ name: "pot_generate", arguments: { txHash: pendingTxHash, chainId: 8453 } });
160
+ // Store pot.potHash alongside your trade log
161
+ // If front-run: pot.potHash is your evidence, timestamped by NIST+Google+Cloudflare
162
+ ```
163
+
164
+ **V2 path**: When builder staking goes live, `S(V) ≥ V − c₀` makes reordering economically irrational for any V. Not just evidence — prevention.
165
+
166
+ ---
167
+
168
+ ### 2. DEX Protocol — AdaptiveSwitch Sandwich Deterrence
169
+
170
+ **Problem**: Small-to-mid value sandwich attacks (V < ~$87) are constant background noise on any AMM. Each one is individually too small to litigate, collectively significant. No governance mechanism moves fast enough to respond.
171
+
172
+ **Solution**: Integrate `TTTHookSimple` (Uniswap V4 hook, Base Sepolia: `0x8C633b05b833a476925F7d9818da6E215760F2c7`). Honest builders who preserve PoT-verified ordering get `turbo` mode (~50ms path). Builders who tamper are flagged to `full` mode (~127ms + exponential backoff up to 320 blocks). The 77ms throughput differential makes reordering cost exceed opportunity value for the V* range. No vote. No committee. Economics.
173
+
174
+ ```typescript
175
+ // Query current switch state for a pool
176
+ const status = await client.callTool({ name: "pot_stats", arguments: { poolAddress: "0x..." } });
177
+ // status.adaptiveMode: "turbo" | "full"
178
+ // status.currentV_star: estimated MEV threshold being deterred
179
+ ```
180
+
181
+ **Outcome**: ~80% reduction in sub-threshold sandwich attacks. Provable per-block audit trail.
182
+
183
+ ---
184
+
185
+ ### 3. Hedge Fund / Prop Desk — MiFIR Art.22c Compliance
186
+
187
+ **Problem**: MiFIR Article 22c / RTS 25 requires microsecond-precision UTC-synchronized timestamps for every trade on regulated venues. The standard hardware solution (PTP/IEEE 1588 appliances) costs $50K–$500K and requires dedicated ops. Most DeFi-adjacent funds run manual reconciliation between two separate timestamp systems.
188
+
189
+ **Solution**: `pot_generate` produces an Ed25519-signed timestamp with uncertainty bound, confidence score, and multi-source attestation. The output is structurally compatible with RTS 25 audit record requirements. No hardware appliance. No dedicated ops. One API call per trade.
190
+
191
+ ```typescript
192
+ const audit = await client.callTool({
193
+ name: "pot_generate",
194
+ arguments: { txHash: tradeHash, chainId: 8453, metadata: { desk: "MACRO-1", trader: "algo-07" } }
195
+ });
196
+ // audit.timestamp: nanosecond precision
197
+ // audit.uncertainty: +/- ms bound (required field in RTS 25 record)
198
+ // audit.confidence: fraction of sources that agreed
199
+ // audit.ed25519_sig: non-repudiation signature
200
+ // Export to your compliance system — same format, every trade
201
+ ```
202
+
203
+ **Outcome**: MiFIR-grade audit trail at ~$0.04/1K calls (DEX tier). Replaces $50K+ hardware setup. IETF standardized via `draft-helmprotocol-tttps-00`.
204
+
205
+ ---
206
+
207
+ ### 4. Liquidity Provider — Position Timeline for Dispute Resolution
208
+
209
+ **Problem**: LP enters and exits positions based on market conditions. When impermanent loss occurs due to a suspected protocol exploit or ordering manipulation, proving the sequence of events (position entry → exploit event → position exit) requires timestamped evidence that the current stack doesn't provide.
210
+
211
+ **Solution**: Stamp every LP action (add liquidity, remove liquidity, fee harvest) with a PoT receipt. The receipt chain creates an unforgeable causal timeline: each action's potHash references the previous, anchored on Base Sepolia. Legally defensible for tax documentation, insurance claims, and protocol dispute resolution.
212
+
213
+ ```typescript
214
+ // On liquidity add
215
+ const entryPot = await client.callTool({ name: "pot_generate", arguments: { txHash: addLiqTx, chainId: 8453 } });
216
+
217
+ // On liquidity remove
218
+ const exitPot = await client.callTool({ name: "pot_generate", arguments: { txHash: removeLiqTx, chainId: 8453 } });
219
+
220
+ // Verify the causal chain
221
+ const chain = await client.callTool({ name: "pot_verify", arguments: { potHash: exitPot.potHash, precedingHash: entryPot.potHash } });
222
+ // chain.valid: true means exit cryptographically followed entry
223
+ ```
224
+
225
+ ---
226
+
227
+ ### 5. AI Agent Coordination — Multi-Agent Causal Ordering
228
+
229
+ **Problem**: When multiple AI agents interact in a pipeline (Agent A signals → Agent B acts → Agent C settles), the causal order matters for debugging, auditing, and liability. Agent logs are unverifiable—any agent can claim any timestamp.
230
+
231
+ **Solution**: Each agent calls `pot_generate` before acting. The resulting potHash chain is independently verifiable: "Agent A's signal at T₁ preceded Agent B's action at T₂" can be proven without trusting either agent's self-reported logs. The on-chain anchor makes the ordering dispute-proof.
232
+
233
+ ```typescript
234
+ // Agent A (signal generator)
235
+ const signalPot = await client.callTool({ name: "pot_generate", arguments: { txHash: signalId } });
236
+
237
+ // Agent B (executor) — references Agent A's pot
238
+ const execPot = await client.callTool({
239
+ name: "pot_generate",
240
+ arguments: { txHash: execId, precedingPotHash: signalPot.potHash }
241
+ });
242
+
243
+ // Any third party can verify the causal chain
244
+ const verified = await client.callTool({ name: "pot_verify", arguments: { potHash: execPot.potHash, precedingHash: signalPot.potHash } });
245
+ ```
246
+
247
+ **Outcome**: Unforgeable causal chain across autonomous agents. Useful for multi-agent DeFi strategies, audit compliance, and cross-agent dispute resolution.
248
+
249
+ ---
250
+
251
+ ## TypeScript: MEV Bot Integration
252
+
253
+ ```typescript
254
+ import { McpClient } from "@modelcontextprotocol/sdk/client/mcp.js";
255
+
256
+ // Generate a Proof of Time for a transaction
257
+ const result = await client.callTool({
258
+ name: "pot_generate",
259
+ arguments: {
260
+ txHash: "0xabc123...",
261
+ chainId: 8453,
262
+ poolAddress: "0xdef456..."
263
+ }
264
+ });
265
+ // Returns: { potHash, timestamp, stratum, grg_shards }
266
+ ```
267
+
268
+ ## Python: Hedge Fund Audit
269
+
270
+ ```python
271
+ import subprocess, json
272
+
273
+ result = subprocess.run(
274
+ ["npx", "-y", "@helm-protocol/ttt-mcp"],
275
+ input=json.dumps({
276
+ "tool": "pot_verify",
277
+ "potHash": "0x...",
278
+ "expectedChainId": 8453
279
+ }),
280
+ capture_output=True, text=True
281
+ )
282
+ ```
283
+
284
+ ## Rate Limits & Pricing
285
+
286
+ ```
287
+ Free Tier: 100 calls/day per IP — no API key needed
288
+ Paid Tier: Set TTT_API_KEY env var — unlimited
289
+ Commercial: peter@kenosian.com (hedge funds, DEX protocols, OTC desks)
290
+ ```
291
+
147
292
  ## Learn More
148
293
 
149
294
  - [OpenTTT SDK](https://www.npmjs.com/package/openttt) — The underlying SDK
@@ -152,4 +297,9 @@ Config file locations:
152
297
 
153
298
  ## License
154
299
 
155
- MIT
300
+ BSL-1.1 — free for non-commercial use.
301
+
302
+ **Commercial use** (production bots, hedge funds, prop desks) requires a license.
303
+ → [kenosian.com/pricing](https://kenosian.com/pricing)
304
+
305
+ Change Date: 2029-05-28 → Apache 2.0
package/dist/auth.js CHANGED
@@ -28,230 +28,77 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var auth_exports = {};
30
30
  __export(auth_exports, {
31
- AUTH_ERROR_MESSAGE: () => AUTH_ERROR_MESSAGE,
32
- verifyHelmApiKey: () => verifyHelmApiKey
31
+ FREE_TIER_LIMIT: () => FREE_TIER_LIMIT,
32
+ checkRateLimit: () => checkRateLimit,
33
+ resolveApiKey: () => resolveApiKey
33
34
  });
34
35
  module.exports = __toCommonJS(auth_exports);
35
- var import_crypto = require("crypto");
36
- var https = __toESM(require("https"));
37
- var import_crypto2 = require("crypto");
38
- const HELM_PUBLIC_KEY_B64 = process.env.HELM_PUBLIC_KEY ?? "PLACEHOLDER_REPLACE_BEFORE_DEPLOY";
39
- const HELM_AUTH_SERVER_URL = process.env.HELM_AUTH_SERVER_URL;
40
- if (HELM_AUTH_SERVER_URL !== void 0) {
41
- if (!HELM_AUTH_SERVER_URL.startsWith("https://")) {
42
- throw new Error(
43
- "[ttt-mcp] HELM_AUTH_SERVER_URL must use HTTPS (got: " + HELM_AUTH_SERVER_URL + "). Refusing to start to protect API keys in transit."
44
- );
45
- }
46
- }
47
- const CLIENT_VERSION = "0.2.0";
48
- const authCache = /* @__PURE__ */ new Map();
49
- function getCached(apiKey, toolName) {
50
- const key = `${apiKey}:${toolName}`;
51
- const entry = authCache.get(key);
52
- if (!entry) return null;
53
- if (Date.now() > entry.expiresAt) {
54
- authCache.delete(key);
55
- return null;
56
- }
57
- return entry;
58
- }
59
- function setCached(apiKey, toolName, allowed, planTier, cacheTtlMs) {
60
- const key = `${apiKey}:${toolName}`;
61
- authCache.set(key, {
62
- allowed,
63
- planTier,
64
- expiresAt: Date.now() + cacheTtlMs
65
- });
36
+ var fs = __toESM(require("fs"));
37
+ var path = __toESM(require("path"));
38
+ var os = __toESM(require("os"));
39
+ const FREE_TIER_LIMIT = parseInt(process.env.FREE_TIER_LIMIT ?? "100", 10);
40
+ const USAGE_DIR = path.join(os.homedir(), ".ttt-mcp");
41
+ const USAGE_FILE = path.join(USAGE_DIR, "usage.json");
42
+ const buckets = /* @__PURE__ */ new Map();
43
+ function nextMidnightUtc() {
44
+ const now = /* @__PURE__ */ new Date();
45
+ const midnight = new Date(
46
+ Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1)
47
+ );
48
+ return midnight.getTime();
66
49
  }
67
- const CIRCUIT_FAILURE_THRESHOLD = 3;
68
- const CIRCUIT_OPEN_DURATION_MS = 5 * 60 * 1e3;
69
- const circuit = {
70
- state: "CLOSED",
71
- consecutiveFailures: 0,
72
- openedAt: 0
73
- };
74
- function circuitRecordSuccess() {
75
- circuit.consecutiveFailures = 0;
76
- circuit.state = "CLOSED";
77
- }
78
- function circuitRecordFailure() {
79
- circuit.consecutiveFailures += 1;
80
- if (circuit.consecutiveFailures >= CIRCUIT_FAILURE_THRESHOLD) {
81
- circuit.state = "OPEN";
82
- circuit.openedAt = Date.now();
83
- }
84
- }
85
- function circuitCanAttempt() {
86
- if (circuit.state === "CLOSED") return true;
87
- if (circuit.state === "OPEN") {
88
- if (Date.now() - circuit.openedAt >= CIRCUIT_OPEN_DURATION_MS) {
89
- circuit.state = "HALF_OPEN";
90
- return true;
50
+ function readUsageFile() {
51
+ try {
52
+ if (!fs.existsSync(USAGE_DIR)) fs.mkdirSync(USAGE_DIR, { recursive: true });
53
+ if (fs.existsSync(USAGE_FILE)) {
54
+ return JSON.parse(fs.readFileSync(USAGE_FILE, "utf8"));
91
55
  }
92
- return false;
56
+ } catch {
93
57
  }
94
- return true;
58
+ return { count: 0, resetAt: nextMidnightUtc() };
95
59
  }
96
- function callAuthServer(serverUrl, apiKey, toolName) {
97
- return new Promise((resolve, reject) => {
98
- const requestId = (0, import_crypto2.randomUUID)();
99
- const body = JSON.stringify({
100
- api_key: apiKey,
101
- tool_name: toolName,
102
- request_id: requestId,
103
- timestamp_ms: Date.now(),
104
- client_version: CLIENT_VERSION
105
- });
106
- const url = new URL("/v1/auth/verify", serverUrl);
107
- const options = {
108
- hostname: url.hostname,
109
- port: url.port || 443,
110
- path: url.pathname,
111
- method: "POST",
112
- headers: {
113
- "Content-Type": "application/json",
114
- "Content-Length": Buffer.byteLength(body),
115
- "X-Request-ID": requestId
116
- }
117
- };
118
- const req = https.request(options, (res) => {
119
- let data = "";
120
- res.on("data", (chunk) => {
121
- data += chunk.toString();
122
- });
123
- res.on("end", () => {
124
- try {
125
- const parsed = JSON.parse(data);
126
- resolve(parsed);
127
- } catch {
128
- reject(new Error("Auth server returned non-JSON response"));
129
- }
130
- });
131
- });
132
- req.setTimeout(3e3, () => {
133
- req.destroy(new Error("Auth server request timed out (3000ms)"));
134
- });
135
- req.on("error", (err) => {
136
- reject(err);
137
- });
138
- req.write(body);
139
- req.end();
140
- });
141
- }
142
- async function serverSideGate(apiKey, toolName) {
143
- if (!HELM_AUTH_SERVER_URL) {
144
- return null;
145
- }
146
- const cached = getCached(apiKey, toolName);
147
- if (cached !== null) {
148
- if (!cached.allowed) {
149
- return `Access denied by Helm Auth Server (plan: ${cached.planTier}, cached)`;
150
- }
151
- return null;
152
- }
153
- if (!circuitCanAttempt()) {
154
- return "Helm Auth Server is temporarily unreachable. Access denied (fail-closed). Please retry in a few minutes.";
155
- }
60
+ function writeUsageFile(entry) {
156
61
  try {
157
- const resp = await callAuthServer(HELM_AUTH_SERVER_URL, apiKey, toolName);
158
- const ttl = typeof resp.cache_ttl_ms === "number" && resp.cache_ttl_ms > 0 ? resp.cache_ttl_ms : 3e5;
159
- setCached(apiKey, toolName, resp.allowed, resp.plan_tier ?? "unknown", ttl);
160
- circuitRecordSuccess();
161
- if (!resp.allowed) {
162
- const reason = resp.reason ? ` Reason: ${resp.reason}` : "";
163
- return `Access denied by Helm Auth Server (plan: ${resp.plan_tier}).${reason}`;
164
- }
165
- return null;
62
+ if (!fs.existsSync(USAGE_DIR)) fs.mkdirSync(USAGE_DIR, { recursive: true });
63
+ fs.writeFileSync(USAGE_FILE, JSON.stringify(entry), "utf8");
166
64
  } catch {
167
- circuitRecordFailure();
168
- return "Helm Auth Server is unreachable. Access denied (fail-closed). Please retry later.";
169
65
  }
170
66
  }
171
- async function verifyHelmApiKey(apiKey, opts) {
172
- if (!apiKey) {
173
- return { valid: false, error: "No API key provided" };
174
- }
175
- if (!apiKey.startsWith("hk-")) {
176
- return { valid: false, error: "Invalid key format" };
67
+ function checkRateLimit(apiKey, clientIp) {
68
+ if (apiKey && apiKey.trim().length > 0) {
69
+ return { allowed: true, remaining: -1, tier: "paid" };
177
70
  }
178
- if (HELM_PUBLIC_KEY_B64 === "PLACEHOLDER_REPLACE_BEFORE_DEPLOY") {
179
- if (process.env.HELM_DEV_MODE === "true") {
180
- return { valid: true, tier: 0, orgId: "dev-mode" };
71
+ const now = Date.now();
72
+ if (clientIp === "stdio") {
73
+ let entry2 = readUsageFile();
74
+ if (now >= entry2.resetAt) {
75
+ entry2 = { count: 0, resetAt: nextMidnightUtc() };
181
76
  }
182
- return { valid: false, error: "Server misconfiguration: HELM_PUBLIC_KEY not set" };
77
+ if (entry2.count >= FREE_TIER_LIMIT) {
78
+ return { allowed: false, remaining: 0, tier: "free" };
79
+ }
80
+ entry2.count += 1;
81
+ writeUsageFile(entry2);
82
+ return { allowed: true, remaining: FREE_TIER_LIMIT - entry2.count, tier: "free" };
183
83
  }
184
- const jwt = apiKey.slice(3);
185
- const parts = jwt.split(".");
186
- if (parts.length !== 3) {
187
- return { valid: false, error: "Malformed JWT" };
84
+ const bucketKey = `ip:${clientIp}`;
85
+ let entry = buckets.get(bucketKey);
86
+ if (!entry || now >= entry.resetAt) {
87
+ entry = { count: 0, resetAt: nextMidnightUtc() };
88
+ buckets.set(bucketKey, entry);
188
89
  }
189
- try {
190
- const payload = JSON.parse(
191
- Buffer.from(parts[1], "base64url").toString("utf8")
192
- );
193
- if (typeof payload.exp !== "number" || payload.exp < Math.floor(Date.now() / 1e3)) {
194
- return { valid: false, error: "Key expired" };
195
- }
196
- if (payload.iss !== "helm-protocol") {
197
- return { valid: false, error: "Invalid issuer" };
198
- }
199
- const publicKey = (0, import_crypto.createPublicKey)({
200
- key: Buffer.from(HELM_PUBLIC_KEY_B64, "base64"),
201
- format: "der",
202
- type: "spki"
203
- });
204
- const sigInput = Buffer.from(`${parts[0]}.${parts[1]}`);
205
- const sig = Buffer.from(parts[2], "base64url");
206
- const isValid = (0, import_crypto.verify)(null, sigInput, publicKey, sig);
207
- if (!isValid) {
208
- return { valid: false, error: "Invalid signature" };
209
- }
210
- if (opts?.redisClient && payload.type === "short" && payload.jti) {
211
- const redisKey = `helm:jti:${payload.jti}`;
212
- const ttl = Math.max(
213
- 1,
214
- payload.exp - Math.floor(Date.now() / 1e3)
215
- );
216
- const isNew = await opts.redisClient.set(redisKey, "1", {
217
- NX: true,
218
- EX: ttl
219
- });
220
- if (isNew === null) {
221
- opts.onReplayDetected?.(payload.jti);
222
- return { valid: false, error: "Replay detected" };
223
- }
224
- }
225
- if (opts?.toolName) {
226
- const gateError = await serverSideGate(apiKey, opts.toolName);
227
- if (gateError !== null) {
228
- return { valid: false, error: gateError };
229
- }
230
- }
231
- return {
232
- valid: true,
233
- tier: typeof payload.tier === "number" ? payload.tier : 0,
234
- orgId: payload.sub
235
- };
236
- } catch {
237
- return { valid: false, error: "Verification error" };
90
+ if (entry.count >= FREE_TIER_LIMIT) {
91
+ return { allowed: false, remaining: 0, tier: "free" };
238
92
  }
93
+ entry.count += 1;
94
+ return { allowed: true, remaining: FREE_TIER_LIMIT - entry.count, tier: "free" };
95
+ }
96
+ function resolveApiKey(headerValue) {
97
+ return headerValue?.trim() || process.env.TTT_API_KEY?.trim() || void 0;
239
98
  }
240
- const AUTH_ERROR_MESSAGE = `This tool requires a Helm Protocol API key.
241
-
242
- To get access:
243
- 1. Contact enterprise@helmprotocol.io
244
- 2. Add the key to your MCP config:
245
- { "env": { "HELM_API_KEY": "hk-..." } }
246
-
247
- Optional server-side validation:
248
- Set HELM_AUTH_SERVER_URL=https://auth.helm-protocol.com for additional
249
- server-side gate (quota enforcement, revocation, plan tier checks).
250
- HTTPS is required \u2014 HTTP URLs are rejected at startup.
251
-
252
- Free tools available without a key: pot_health, pot_stats`;
253
99
  // Annotate the CommonJS export names for ESM import in node:
254
100
  0 && (module.exports = {
255
- AUTH_ERROR_MESSAGE,
256
- verifyHelmApiKey
101
+ FREE_TIER_LIMIT,
102
+ checkRateLimit,
103
+ resolveApiKey
257
104
  });