@0xdivyanshh/tab-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/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # @0xdivyanshh/tab-mcp
2
+
3
+ **Tier 3 · MCP server**
4
+
5
+ Tab's verbs as MCP tools, so an agent in any MCP-capable runtime can transact on a tab with no
6
+ bespoke code. Seven tools; **only `tab_spend` moves money.**
7
+
8
+ ## The decision the old README left open — settled
9
+
10
+ It offered two options: a standalone server (this), or documentation for loading
11
+ `@0xdivyanshh/tab-agentkit-plugin` into `@hashgraph/hedera-agent-kit-mcp`. **Shipping option 1.** Option 2 is
12
+ the better ecosystem story and it is not the one to ship first:
13
+
14
+ - It depends on **two** things that do not exist — the plugin is unwritten — plus an external
15
+ server accepting third-party plugins in a shape nobody here has verified.
16
+ - It cannot be driven by a judge in one step. This can: three lines of config and Claude Desktop is
17
+ spending on a Hedera tab.
18
+ - It is **additive later.** A plugin can wrap the same `@0xdivyanshh/tab-sdk` verbs whenever the Agent Kit path
19
+ is confirmed, and nothing here has to be undone.
20
+
21
+ ## Use it
22
+
23
+ ```jsonc
24
+ // claude_desktop_config.json (or any MCP client)
25
+ {
26
+ "mcpServers": {
27
+ "tab": {
28
+ "command": "node",
29
+ "args": [
30
+ "--experimental-strip-types",
31
+ "/absolute/path/to/ethonline/packages/mcp/src/stdio.ts"
32
+ ],
33
+ "env": {
34
+ "TAB_GATEWAY_URL": "http://localhost:8080",
35
+ "TAB_ACCOUNT_ID": "0.0.10390398"
36
+ }
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+ Then ask the model things like *"what can my tab afford?"*, *"buy the forecast from this URL for at
43
+ most 0.040000"*, or — the one worth trying — ***"why is my ceiling only 0.25?"***
44
+
45
+ That last question is the point of the whole rail. It answers with the published arithmetic and the
46
+ funding-graph evidence:
47
+
48
+ ```
49
+ 0.0.10385196 0% BLOCKED
50
+ COMMON_FUNDER: the same account funded both this counterparty and the agent's tab
51
+ funded by 0.0.8812188 · tab funded by 0.0.8812188 ← SAME, which is what COMMON_FUNDER tests
52
+ ```
53
+
54
+ ## Tools
55
+
56
+ | Tool | Moves money | What it answers |
57
+ |---|---|---|
58
+ | `tab_spend` | **yes** | Pay a seller, up to a cap. Returns paid / refused / failed |
59
+ | `tab_quote` | no | Would this be allowed? Reserves nothing |
60
+ | `tab_balance` | no | Position: balance, outstanding, holds, available, ceiling |
61
+ | `tab_ceiling` | no | The ceiling, what bound it, and the published inputs |
62
+ | `tab_receipts` | no | Recent ledger entries from the HCS receipt topic |
63
+ | `tab_counterparties` | no | Independence weights and the reason for each |
64
+ | `tab_health` | no | Gateway reachability, network, token, window |
65
+
66
+ Every read tool is annotated `readOnlyHint: true`; `tab_spend` is `destructiveHint: true` and
67
+ `idempotentHint: false`, so a client knows which one to confirm with a human.
68
+
69
+ ## Invariants
70
+
71
+ - **A refusal is a structured RESULT, not an error.** `isError: true` makes a client surface a
72
+ failure and invites a model to retry — and a `CEILING_EXCEEDED` retried immediately is refused
73
+ again for the same reason. A refusal returns the rule, the evidence, and what to do instead,
74
+ because choosing different work is the correct response and the agent can only choose it if it is
75
+ told why. A `failed` outcome **is** an error, and hands back the hold id: infrastructure broke
76
+ after the decision to spend, so nobody knows whether the seller was paid, and a retry with a new
77
+ key would be a second payment.
78
+ - **No key material anywhere.** `McpConfig` is a URL and a tab id; `createTab` has no parameter
79
+ that would accept a key, and `boundaries.json` bars this package from `@hiero-ledger/sdk`. An MCP
80
+ server runs on a user's machine inside a client the user did not write — the surface where a
81
+ leaked key would hurt most, and so the one where the constraint is enforced rather than promised.
82
+ - **`stdout` is the protocol.** A single stray `console.log` corrupts the JSON-RPC stream and the
83
+ client reports a parse error rather than whatever actually went wrong. Every diagnostic goes to
84
+ stderr.
85
+ - **Same verbs, same semantics as `@0xdivyanshh/tab-sdk`.** Guidance text comes from `@0xdivyanshh/tab-protocol`, not from
86
+ strings invented here, so an agent that learns the rail through MCP learns the same rail.
87
+ - **Fails at startup on a missing `TAB_ACCOUNT_ID`.** A client shows a server as connected the
88
+ moment the process is alive, so one that starts happily and then refuses every call looks like a
89
+ broken rail rather than a missing variable.
@@ -0,0 +1,17 @@
1
+ import { type Tab } from '@0xdivyanshh/tab-sdk';
2
+ /**
3
+ * How the server is configured, and what it deliberately cannot be given.
4
+ *
5
+ * A URL and a tab id. There is no token, no private key, and `createTab` has no
6
+ * parameter that would accept one — which is the whole product claim holding at
7
+ * the surface most likely to be handed a credential "just for convenience".
8
+ * An MCP server runs on a user's machine, inside a client the user did not
9
+ * write, and is exactly where a key would leak.
10
+ */
11
+ export interface McpConfig {
12
+ gatewayUrl: string;
13
+ tab: string;
14
+ }
15
+ export declare function configFromEnv(env?: NodeJS.ProcessEnv): McpConfig;
16
+ export declare function clientFor(config: McpConfig): Tab;
17
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAE9C;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,SAAS,CAqB7E;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,GAAG,CAehD"}
package/dist/config.js ADDED
@@ -0,0 +1,36 @@
1
+ import { createTab } from '@0xdivyanshh/tab-sdk';
2
+ export function configFromEnv(env = process.env) {
3
+ const gatewayUrl = env['TAB_GATEWAY_URL'] ?? 'http://localhost:8080';
4
+ const tab = env['TAB_ACCOUNT_ID'] ?? '';
5
+ if (!tab) {
6
+ /*
7
+ * Fail at STARTUP, not on the first tool call.
8
+ *
9
+ * An MCP client shows a server as connected the moment the process is
10
+ * alive, so a server that starts happily and then refuses every call looks
11
+ * like a broken rail rather than a missing environment variable. The error
12
+ * goes to stderr, which stdio transports reserve for exactly this — stdout
13
+ * is the JSON-RPC channel and a stray line there corrupts the stream.
14
+ */
15
+ throw new Error('TAB_ACCOUNT_ID is not set. The MCP server needs to know which tab to transact on. ' +
16
+ 'Set it in the mcpServers entry for this server, alongside TAB_GATEWAY_URL.');
17
+ }
18
+ return { gatewayUrl, tab };
19
+ }
20
+ export function clientFor(config) {
21
+ return createTab({
22
+ baseUrl: config.gatewayUrl,
23
+ /*
24
+ * Patient, unlike the console's client.
25
+ *
26
+ * A spend waits on the SELLER, whose x402 facilitator runs a Mirror Node
27
+ * preflight plus signature verification — measured at 25-39s for an HTS
28
+ * token. An MCP client is a foreground tool an agent is waiting on, so
29
+ * giving up at 8s would abandon a payment that was about to succeed and
30
+ * leave the caller unable to tell a slow seller from a failed one.
31
+ */
32
+ timeoutMs: 120_000,
33
+ maxRetries: 1,
34
+ });
35
+ }
36
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,MAAM,UAAU,CAAA;AAgB9C,MAAM,UAAU,aAAa,CAAC,MAAyB,OAAO,CAAC,GAAG;IAChE,MAAM,UAAU,GAAG,GAAG,CAAC,iBAAiB,CAAC,IAAI,uBAAuB,CAAA;IACpE,MAAM,GAAG,GAAG,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAA;IAEvC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT;;;;;;;;WAQG;QACH,MAAM,IAAI,KAAK,CACb,oFAAoF;YAClF,4EAA4E,CAC/E,CAAA;IACH,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,CAAA;AAC5B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAiB;IACzC,OAAO,SAAS,CAAC;QACf,OAAO,EAAE,MAAM,CAAC,UAAU;QAC1B;;;;;;;;WAQG;QACH,SAAS,EAAE,OAAO;QAClB,UAAU,EAAE,CAAC;KACd,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `@0xdivyanshh/tab-mcp` — Tab's verbs as MCP tools.
3
+ *
4
+ * Tier 3. Depends on `@0xdivyanshh/tab-sdk` and nothing lower — `boundaries.json` allows
5
+ * only `money`, `protocol` and `sdk`, so this package is structurally incapable
6
+ * of signing, reading a database, or recomputing a ceiling. An MCP server runs
7
+ * on a user's machine inside a client the user did not write, which makes it the
8
+ * surface where a leaked key would hurt most and the constraint worth enforcing
9
+ * rather than promising.
10
+ *
11
+ * The binary is `src/stdio.ts`. This module exists so a host can embed the
12
+ * server on its own transport.
13
+ */
14
+ export { clientFor, configFromEnv, type McpConfig } from './config.ts';
15
+ export { buildServer } from './server.ts';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAA;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `@0xdivyanshh/tab-mcp` — Tab's verbs as MCP tools.
3
+ *
4
+ * Tier 3. Depends on `@0xdivyanshh/tab-sdk` and nothing lower — `boundaries.json` allows
5
+ * only `money`, `protocol` and `sdk`, so this package is structurally incapable
6
+ * of signing, reading a database, or recomputing a ceiling. An MCP server runs
7
+ * on a user's machine inside a client the user did not write, which makes it the
8
+ * surface where a leaked key would hurt most and the constraint worth enforcing
9
+ * rather than promising.
10
+ *
11
+ * The binary is `src/stdio.ts`. This module exists so a host can embed the
12
+ * server on its own transport.
13
+ */
14
+ export { clientFor, configFromEnv } from "./config.js";
15
+ export { buildServer } from "./server.js";
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAkB,MAAM,aAAa,CAAA;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,8 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { toWire } from '@0xdivyanshh/tab-money';
3
+ import type { Tab } from '@0xdivyanshh/tab-sdk';
4
+ import type { McpConfig } from './config.ts';
5
+ export declare function buildServer(tab: Tab, config: McpConfig): McpServer;
6
+ /** Re-exported so a consumer can serialise an amount the way the tools expect. */
7
+ export { toWire };
8
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAU,MAAM,EAAQ,MAAM,YAAY,CAAA;AAEjD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAEnC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAqD5C,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,GAAG,SAAS,CA4WlE;AAED,kFAAkF;AAClF,OAAO,EAAE,MAAM,EAAE,CAAA"}
package/dist/server.js ADDED
@@ -0,0 +1,343 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { format, toWire, usdc } from '@0xdivyanshh/tab-money';
3
+ import { REFUSAL_GUIDANCE, WEIGHT_REASON_DETAIL } from '@0xdivyanshh/tab-protocol';
4
+ import { z } from 'zod';
5
+ /**
6
+ * `@0xdivyanshh/tab-mcp` — Tab's verbs as MCP tools.
7
+ *
8
+ * ## Why a standalone server, which the README left open
9
+ *
10
+ * The README offered two options: this, or documentation for loading
11
+ * `@0xdivyanshh/tab-agentkit-plugin` into `@hashgraph/hedera-agent-kit-mcp`. Option 2 is
12
+ * the better ecosystem story and it is not the one to ship first, for reasons
13
+ * that are about evidence rather than taste:
14
+ *
15
+ * - It depends on TWO things that do not exist — the plugin is unwritten — and
16
+ * on an external server accepting third-party plugins in a shape nobody here
17
+ * has verified.
18
+ * - It cannot be demonstrated by a judge in one step. This can: three lines in
19
+ * a client config and Claude Desktop is spending on a Hedera tab.
20
+ * - It is additive later. A plugin can wrap the same `@0xdivyanshh/tab-sdk` verbs whenever
21
+ * the Agent Kit path is confirmed, and nothing here has to be undone.
22
+ *
23
+ * So: option 1, and the reason is recorded here rather than in an ADR nobody
24
+ * opens.
25
+ *
26
+ * ## The one invariant
27
+ *
28
+ * **A refusal is a structured result, not an error.** `isError: true` makes an
29
+ * MCP client surface a failure and, worse, invites a model to retry it — and a
30
+ * `CEILING_EXCEEDED` retried immediately is a spend that will be refused again
31
+ * for the same reason. A refusal comes back as content the model can read,
32
+ * carrying the rule, the evidence and what to do instead, because choosing
33
+ * different work is the correct response and the agent can only choose it if it
34
+ * is told why.
35
+ *
36
+ * Infrastructure failure IS an error, and the distinction is preserved from the
37
+ * SDK: a refusal means the rail said no, `failed` means nobody said anything
38
+ * and the caller does not know whether the seller was paid.
39
+ */
40
+ /** Amounts cross MCP as decimal strings — `bigint` does not survive JSON. */
41
+ const AMOUNT = z
42
+ .string()
43
+ .regex(/^\d+\.\d{6}$/, 'six decimal places, e.g. "0.040000"')
44
+ .describe('USDC amount as a decimal string with exactly six decimal places, e.g. "0.040000"');
45
+ /** Every tool returns text content; structured data goes in the same string. */
46
+ function text(body) {
47
+ return { content: [{ type: 'text', text: body }] };
48
+ }
49
+ function errorText(body) {
50
+ return { content: [{ type: 'text', text: body }], isError: true };
51
+ }
52
+ export function buildServer(tab, config) {
53
+ const server = new McpServer({ name: 'tab', version: '0.1.0' }, {
54
+ instructions: `Tab is a credit rail on Hedera for this agent's tab ${config.tab}. The agent holds no ` +
55
+ 'key and signs nothing; the gateway pays sellers on its behalf against an earned ceiling. ' +
56
+ 'Call quote before a batch to learn what is affordable. A refused spend is a normal, ' +
57
+ 'expected answer that names the rule and what to do instead — read the guidance and choose ' +
58
+ 'different work rather than retrying the same call.',
59
+ });
60
+ /* ── spend: the only verb that moves money ───────────────────────────────── */
61
+ server.registerTool('tab_spend', {
62
+ title: 'Spend from the tab',
63
+ description: 'Pay a seller through the tab, up to `max`. The gateway reserves a hold, pays, then ' +
64
+ 'commits — so a crash cannot leave the tab overdrawn. Returns paid, refused or failed. ' +
65
+ 'A REFUSED result is not an error: it names the rule that fired and what to do instead.',
66
+ inputSchema: {
67
+ url: z
68
+ .string()
69
+ .url()
70
+ .describe('The seller URL, including whatever the seller needs to be paid'),
71
+ max: AMOUNT.describe('The most this call may cost. The tab is debited what was actually settled, not this cap.'),
72
+ idempotencyKey: z
73
+ .string()
74
+ .min(8)
75
+ .max(64)
76
+ .optional()
77
+ .describe('Reuse the SAME key when retrying a failed call, or the retry may double-spend. ' +
78
+ 'Generated automatically when omitted.'),
79
+ },
80
+ annotations: {
81
+ title: 'Spend from the tab',
82
+ // MOVES MONEY. The one tool here that is not safe to call speculatively,
83
+ // and the one an MCP client should confirm with a human.
84
+ readOnlyHint: false,
85
+ destructiveHint: true,
86
+ idempotentHint: false,
87
+ openWorldHint: true,
88
+ },
89
+ }, async ({ url, max, idempotencyKey }) => {
90
+ const result = await tab.spend({
91
+ tab: config.tab,
92
+ url,
93
+ max: usdc(max),
94
+ ...(idempotencyKey ? { idempotencyKey } : {}),
95
+ });
96
+ if (result.outcome === 'paid') {
97
+ return text([
98
+ `PAID ${format(result.amount)} USDC to ${result.seller}.`,
99
+ `hold ${result.holdId}` +
100
+ (result.receiptSeq !== null ? ` · receipt seq ${result.receiptSeq} on HCS` : ''),
101
+ `took ${Math.round(result.elapsedMs / 1000)}s`,
102
+ '',
103
+ 'The seller responded:',
104
+ typeof result.body === 'string' ? result.body : JSON.stringify(result.body, null, 2),
105
+ ].join('\n'));
106
+ }
107
+ if (result.outcome === 'refused') {
108
+ /*
109
+ * NOT `isError`. See the header.
110
+ *
111
+ * The guidance comes from `@0xdivyanshh/tab-protocol`, not from a string invented
112
+ * here — the same text the HTTP API and the console show, so an agent
113
+ * that learns the rail through MCP learns the same rail.
114
+ */
115
+ const evidence = result.evidence
116
+ ? Object.entries(result.evidence)
117
+ .map(([k, v]) => ` ${k} ${v}`)
118
+ .join('\n')
119
+ : ' (none published)';
120
+ return text([
121
+ `REFUSED — ${result.rule}`,
122
+ '',
123
+ result.reason,
124
+ '',
125
+ 'Evidence:',
126
+ evidence,
127
+ '',
128
+ `What to do: ${result.guidance}`,
129
+ result.retryable
130
+ ? 'This rule can clear on its own — the same call may succeed later.'
131
+ : 'Retrying this exact call will be refused again for the same reason. Choose different work.',
132
+ ].join('\n'));
133
+ }
134
+ /*
135
+ * `failed` IS an error, and says the one thing that matters.
136
+ *
137
+ * Infrastructure broke AFTER the decision to spend, so nobody knows
138
+ * whether the seller was paid. A caller that retries MUST reuse the hold
139
+ * id as its idempotency key, or the retry is a second payment.
140
+ */
141
+ return errorText([
142
+ `FAILED — ${result.reason}`,
143
+ '',
144
+ 'This is NOT a refusal. The rail did not say no; nobody said anything, and it is ' +
145
+ 'unknown whether the seller was paid.',
146
+ `To retry safely, call tab_spend again with idempotencyKey "${result.holdId}" — the ` +
147
+ 'gateway treats it as the same attempt. A new key would be a second payment.',
148
+ 'The hold expires on its own, so the headroom is not lost permanently.',
149
+ ].join('\n'));
150
+ });
151
+ /* ── quote: what can I afford, reserving nothing ─────────────────────────── */
152
+ server.registerTool('tab_quote', {
153
+ title: 'Check affordability without reserving',
154
+ description: 'Ask whether a spend of `max` would be allowed, WITHOUT taking a hold. Use this before ' +
155
+ 'planning a batch: a hold taken by a quote would be headroom the agent never uses.',
156
+ inputSchema: { max: AMOUNT },
157
+ annotations: {
158
+ readOnlyHint: true,
159
+ destructiveHint: false,
160
+ idempotentHint: true,
161
+ openWorldHint: false,
162
+ },
163
+ }, async ({ max }) => {
164
+ const q = await tab.quote({ tab: config.tab, max: usdc(max) });
165
+ return text([
166
+ q.affordable ? `AFFORDABLE — ${format(usdc(max))} is within the tab.` : 'NOT AFFORDABLE',
167
+ `available ${format(q.available)}`,
168
+ `ceiling ${format(q.ceiling)}`,
169
+ `per-call cap ${format(q.perCallCap)}`,
170
+ ...(q.wouldRefuse
171
+ ? [
172
+ '',
173
+ `would refuse: ${q.wouldRefuse}`,
174
+ `${q.reason ?? ''}`,
175
+ REFUSAL_GUIDANCE[q.wouldRefuse],
176
+ ]
177
+ : []),
178
+ ]
179
+ .filter(Boolean)
180
+ .join('\n'));
181
+ });
182
+ /* ── the read verbs ──────────────────────────────────────────────────────── */
183
+ server.registerTool('tab_balance', {
184
+ title: 'Tab position',
185
+ description: 'The tab’s current position: balance (negative means the agent owes), outstanding, ' +
186
+ 'holds, available headroom and the ceiling in force.',
187
+ annotations: {
188
+ readOnlyHint: true,
189
+ destructiveHint: false,
190
+ idempotentHint: true,
191
+ openWorldHint: false,
192
+ },
193
+ }, async () => {
194
+ const s = await tab.state(config.tab);
195
+ return text([
196
+ `tab ${s.tab}`,
197
+ `balance ${format(s.balance, { sign: 'always' })} (negative means the agent owes)`,
198
+ `outstanding ${format(s.outstanding)}`,
199
+ `holds ${format(s.holds)}`,
200
+ `available ${format(s.available)}`,
201
+ `ceiling ${format(s.ceiling)}`,
202
+ `per-call cap ${format(s.perCallCap)}`,
203
+ `window ${s.window} · ${s.entries} ledger entries`,
204
+ ].join('\n'));
205
+ });
206
+ server.registerTool('tab_ceiling', {
207
+ title: 'The ceiling, and the arithmetic behind it',
208
+ description: 'The credit ceiling in force, what bound it, and the published inputs it was computed ' +
209
+ 'from. Use this to explain to a user WHY the tab can or cannot afford something.',
210
+ annotations: {
211
+ readOnlyHint: true,
212
+ destructiveHint: false,
213
+ idempotentHint: true,
214
+ openWorldHint: false,
215
+ },
216
+ }, async () => {
217
+ const c = await tab.ceiling(config.tab);
218
+ if (!c.published || !c.current) {
219
+ return text([
220
+ `No ceiling published yet for ${c.tab} — normal for a tab's first minutes.`,
221
+ `The gateway is enforcing ${format(c.enforced)} meanwhile (the starter floor).`,
222
+ c.note ?? '',
223
+ ]
224
+ .filter(Boolean)
225
+ .join('\n'));
226
+ }
227
+ const i = c.current.inputs;
228
+ return text([
229
+ `ceiling ${format(c.current.ceiling)} bound by ${c.current.binding}`,
230
+ `enforced now ${format(c.enforced)}` +
231
+ (c.enforced !== c.current.ceiling
232
+ ? ' (the gateway polls the topic every 15s, so this is what a spend is checked against)'
233
+ : ''),
234
+ `cause ${c.current.cause}`,
235
+ '',
236
+ 'Published inputs:',
237
+ ` trailing revenue ${format(i.revenue)} (attested ${format(i.revenueAttested)} · unattested ${format(i.revenueUnattested)})`,
238
+ ` tier ${i.tier} ×${i.multBp / 10_000}`,
239
+ ` earned ramp ${i.rampBp / 100}%`,
240
+ ` hard cap ${format(i.cap)}`,
241
+ ` starter floor ${format(i.floor)}`,
242
+ ...(i.defaulted
243
+ ? [' DEFAULTED this tab has missed a settlement, so the ceiling is zero']
244
+ : []),
245
+ '',
246
+ `model ${c.current.model} · HCS seq ${c.current.seq ?? '?'} · input hash ${c.current.hash}`,
247
+ 'Anyone can recompute this from the public topic: pnpm verify-ceiling.',
248
+ ].join('\n'));
249
+ });
250
+ server.registerTool('tab_receipts', {
251
+ title: 'Recent receipts',
252
+ description: 'The tab’s recent ledger entries from the HCS receipt topic — holds, debits, ' +
253
+ 'credits, refusals and settlements, newest first.',
254
+ inputSchema: {
255
+ limit: z
256
+ .number()
257
+ .int()
258
+ .min(1)
259
+ .max(50)
260
+ .default(10)
261
+ .describe('How many entries, newest first'),
262
+ },
263
+ annotations: {
264
+ readOnlyHint: true,
265
+ destructiveHint: false,
266
+ idempotentHint: true,
267
+ openWorldHint: false,
268
+ },
269
+ }, async ({ limit }) => {
270
+ const rows = await tab.receipts(config.tab);
271
+ const recent = rows.slice(-limit).reverse();
272
+ if (recent.length === 0)
273
+ return text('No receipts yet for this tab.');
274
+ return text(recent
275
+ .map((r) => {
276
+ const amount = r.amount !== undefined ? format(r.amount, { sign: 'always' }) : '—';
277
+ return [
278
+ r.leg.toUpperCase().padEnd(11),
279
+ amount.padStart(10),
280
+ (r.counterparty ?? '—').padEnd(14),
281
+ r.rule ?? '',
282
+ r.seq !== undefined ? `seq ${r.seq}` : 'unpublished',
283
+ ]
284
+ .filter(Boolean)
285
+ .join(' ');
286
+ })
287
+ .join('\n'));
288
+ });
289
+ server.registerTool('tab_counterparties', {
290
+ title: 'Who counts as independent revenue',
291
+ description: 'Published independence weights for the tab’s counterparties, with the reason each ' +
292
+ 'was discounted or blocked. This is why revenue does or does not raise the ceiling.',
293
+ annotations: {
294
+ readOnlyHint: true,
295
+ destructiveHint: false,
296
+ idempotentHint: true,
297
+ openWorldHint: false,
298
+ },
299
+ }, async () => {
300
+ const rows = await tab.counterparties(config.tab);
301
+ if (rows.length === 0)
302
+ return text('No weights published yet. Run the engine.');
303
+ return text(rows
304
+ .map((w) => [
305
+ `${w.counterparty} ${w.bp / 100}%${w.blocking ? ' BLOCKED' : ''}`,
306
+ ` revenue ${format(w.revenue)} · share ${w.shareBp / 100}%`,
307
+ ...w.reasons.map((r) => ` ${r}: ${WEIGHT_REASON_DETAIL[r]}`),
308
+ ...(w.funder && w.tabFunder
309
+ ? [
310
+ ` funded by ${w.funder} · tab funded by ${w.tabFunder}` +
311
+ (w.funder === w.tabFunder
312
+ ? ' ← SAME, which is what COMMON_FUNDER tests'
313
+ : ''),
314
+ ]
315
+ : []),
316
+ ].join('\n'))
317
+ .join('\n\n'));
318
+ });
319
+ server.registerTool('tab_health', {
320
+ title: 'Is the rail up',
321
+ description: 'Gateway reachability, network, token and current window.',
322
+ annotations: {
323
+ readOnlyHint: true,
324
+ destructiveHint: false,
325
+ idempotentHint: true,
326
+ openWorldHint: false,
327
+ },
328
+ }, async () => {
329
+ const h = await tab.health();
330
+ return text([
331
+ h.ok ? 'Gateway is up.' : 'Gateway responded but did not report OK.',
332
+ `network ${h.network} · token ${h.token} · window ${h.window}`,
333
+ h.demoMode ? 'DEMO MODE is on — window length is overridden for demonstration.' : '',
334
+ `gateway ${config.gatewayUrl} · tab ${config.tab}`,
335
+ ]
336
+ .filter(Boolean)
337
+ .join('\n'));
338
+ });
339
+ return server;
340
+ }
341
+ /** Re-exported so a consumer can serialise an amount the way the tools expect. */
342
+ export { toWire };
343
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=stdio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":""}
package/dist/stdio.js ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The stdio entry point.
4
+ *
5
+ * TAB_GATEWAY_URL=... TAB_ACCOUNT_ID=0.0.x node --experimental-strip-types src/stdio.ts
6
+ *
7
+ * ## STDOUT IS THE PROTOCOL
8
+ *
9
+ * A stdio MCP server speaks JSON-RPC on stdout, so a single stray `console.log`
10
+ * anywhere in the process corrupts the stream and the client reports a parse
11
+ * error rather than whatever actually went wrong. Every diagnostic here goes to
12
+ * stderr, deliberately, and nothing else in this package prints at all.
13
+ *
14
+ * That is also why `configFromEnv` throws at startup: a server that connects and
15
+ * then fails every call looks like a broken rail instead of a missing variable.
16
+ */
17
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
18
+ import { clientFor, configFromEnv } from "./config.js";
19
+ import { buildServer } from "./server.js";
20
+ let config;
21
+ try {
22
+ config = configFromEnv();
23
+ }
24
+ catch (error) {
25
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
26
+ process.exit(1);
27
+ }
28
+ const server = buildServer(clientFor(config), config);
29
+ process.stderr.write(`tab-mcp · gateway ${config.gatewayUrl} · tab ${config.tab}\n` +
30
+ 'The agent holds no key and signs nothing. 7 tools; only tab_spend moves money.\n');
31
+ await server.connect(new StdioServerTransport());
32
+ //# sourceMappingURL=stdio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,SAAS,EAAE,aAAa,EAAkB,MAAM,aAAa,CAAA;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC,IAAI,MAAiB,CAAA;AACrB,IAAI,CAAC;IACH,MAAM,GAAG,aAAa,EAAE,CAAA;AAC1B,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACnF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC;AAED,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAA;AAErD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qBAAqB,MAAM,CAAC,UAAU,UAAU,MAAM,CAAC,GAAG,IAAI;IAC5D,kFAAkF,CACrF,CAAA;AAED,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAA"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@0xdivyanshh/tab-mcp",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "bin": {
14
+ "tab-mcp": "dist/stdio.js"
15
+ },
16
+ "dependencies": {
17
+ "@modelcontextprotocol/sdk": "^1.13.0",
18
+ "@0xdivyanshh/tab-money": "0.1.0",
19
+ "@0xdivyanshh/tab-protocol": "0.1.0",
20
+ "@0xdivyanshh/tab-sdk": "0.1.0",
21
+ "zod": "^3.25.0"
22
+ },
23
+ "description": "MCP server for Tab — give any LLM a credit line on Hedera. It holds no key.",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/0xNerd100/Tab.git",
28
+ "directory": "packages/mcp"
29
+ },
30
+ "homepage": "https://github.com/0xNerd100/Tab#readme",
31
+ "files": [
32
+ "dist/**/*.js",
33
+ "dist/**/*.d.ts",
34
+ "dist/**/*.map",
35
+ "README.md"
36
+ ],
37
+ "publishConfig": {
38
+ "access": "public"
39
+ }
40
+ }