token-counter-mcp 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,196 @@
1
+ # Token Counter MCP
2
+
3
+ An MCP server that accurately counts and tracks every Claude token — input, output, cache read/write, and planning. Uses the official Anthropic token-counting API for **exact** counts (not estimates).
4
+
5
+ ## Hosted Service — One Command Setup
6
+
7
+ We run a hosted instance so you don't need your own Anthropic API key or any deployment:
8
+
9
+ ```bash
10
+ claude mcp add --transport sse token-counter https://proud-motivation-production-c4ab.up.railway.app/sse
11
+ ```
12
+
13
+ Restart Claude Code and the tools are ready.
14
+
15
+ ### Interactive Setup (with Dashboard)
16
+
17
+ For a guided setup that also configures the live dashboard token:
18
+
19
+ ```bash
20
+ npx -y token-counter-mcp --setup
21
+ ```
22
+
23
+ This updates `~/.claude.json` automatically and prints your personal dashboard URL.
24
+
25
+ ---
26
+
27
+ ## Available Tools
28
+
29
+ | Tool | What it does |
30
+ |------|-------------|
31
+ | `count_tokens` | Exact token count for any text or conversation via Anthropic API |
32
+ | `log_usage` | Record actual token usage after an API call (input, output, cache) |
33
+ | `get_session_stats` | Running totals and USD cost for the current session |
34
+ | `get_usage_history` | Last N usage entries across all sessions |
35
+ | `reset_session` | Zero out session totals (history is preserved) |
36
+ | `estimate_cost` | Calculate USD cost for a given token count without making an API call |
37
+
38
+ ---
39
+
40
+ ## Usage in Claude Code
41
+
42
+ Once added, ask Claude things like:
43
+
44
+ ```
45
+ How many tokens is this conversation so far?
46
+ Log my last API call: 1500 input, 300 output, claude-opus-4-6
47
+ What's my total spend this session?
48
+ How much would 50k input + 10k output tokens cost on claude-sonnet-4-6?
49
+ Show me my usage history for the last 10 entries.
50
+ Reset my session totals.
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Self-Hosted Deployment
56
+
57
+ Want to run your own instance with your own API key?
58
+
59
+ ### macOS
60
+
61
+ ```bash
62
+ # Install Railway CLI
63
+ brew install railway
64
+
65
+ # Clone and build
66
+ git clone https://github.com/krishnakantparashar/TokenCounterMCP
67
+ cd TokenCounterMCP
68
+ npm install && npm run build
69
+
70
+ # Deploy
71
+ railway login
72
+ railway init
73
+ railway up
74
+ railway domain
75
+
76
+ # Set your Anthropic API key
77
+ railway variables set ANTHROPIC_API_KEY=sk-ant-YOUR_KEY_HERE
78
+ ```
79
+
80
+ ### Windows (PowerShell)
81
+
82
+ ```powershell
83
+ # Install Railway CLI (requires Node.js)
84
+ npm install -g @railway/cli
85
+
86
+ # Clone and build
87
+ git clone https://github.com/krishnakantparashar/TokenCounterMCP
88
+ cd TokenCounterMCP
89
+ npm install
90
+ npm run build
91
+
92
+ # Deploy
93
+ railway login
94
+ railway init
95
+ railway up
96
+ railway domain
97
+
98
+ # Set your Anthropic API key
99
+ railway variables set ANTHROPIC_API_KEY=sk-ant-YOUR_KEY_HERE
100
+ ```
101
+
102
+ After deployment, connect with:
103
+ ```bash
104
+ claude mcp add --transport sse token-counter https://YOUR-URL.up.railway.app/sse
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Local stdio Mode
110
+
111
+ Runs entirely on your machine. Requires Node.js 18+.
112
+
113
+ ### Quickstart (no clone needed)
114
+
115
+ ```bash
116
+ claude mcp add token-counter -- npx -y token-counter-mcp
117
+ ```
118
+
119
+ That's it. Restart Claude Code — the server starts on demand via `npx`.
120
+
121
+ ### Manual install (if you prefer)
122
+
123
+ ```bash
124
+ git clone https://github.com/krishnakantparashar/TokenCounterMCP
125
+ cd TokenCounterMCP
126
+ npm install && npm run build
127
+ ```
128
+
129
+ Set your API key for exact counts (optional — falls back to ~97–99% accurate local counting without it):
130
+
131
+ ```bash
132
+ export ANTHROPIC_API_KEY=sk-ant-YOUR_KEY_HERE # macOS/Linux
133
+ $env:ANTHROPIC_API_KEY="sk-ant-YOUR_KEY_HERE" # Windows PowerShell
134
+ ```
135
+
136
+ Add to Claude Code:
137
+
138
+ ```bash
139
+ # macOS/Linux
140
+ claude mcp add token-counter -- node "/absolute/path/to/TokenCounterMCP/dist/index.js"
141
+
142
+ # Windows
143
+ claude mcp add token-counter -- node "C:\path\to\TokenCounterMCP\dist\index.js"
144
+ ```
145
+
146
+ ### Local Dashboard
147
+
148
+ When running in local stdio mode, a live dashboard is available at:
149
+
150
+ ```
151
+ http://localhost:8899
152
+ ```
153
+
154
+ Open it in your browser to see session totals, per-project cost breakdowns, and usage history.
155
+
156
+ ---
157
+
158
+ ## Counting Modes
159
+
160
+ | Mode | Accuracy | Requires |
161
+ |------|----------|----------|
162
+ | Exact (Anthropic API) | 100% | `ANTHROPIC_API_KEY` set on server |
163
+ | Local approximation | ~97–99% | Nothing — works offline |
164
+
165
+ The hosted service uses exact counting. Local mode without a key uses `gpt-tokenizer` (cl100k_base BPE) as a fallback.
166
+
167
+ ---
168
+
169
+ ## Supported Models & Pricing
170
+
171
+ | Model | Input | Output | Cache Read | Cache Write |
172
+ |-------|-------|--------|------------|-------------|
173
+ | `claude-opus-4-6` | $5.00 / 1M | $25.00 / 1M | $0.50 / 1M | $1.25 / 1M |
174
+ | `claude-sonnet-4-6` | $3.00 / 1M | $15.00 / 1M | $0.30 / 1M | $0.75 / 1M |
175
+ | `claude-haiku-4-5` | $1.00 / 1M | $5.00 / 1M | $0.10 / 1M | $0.25 / 1M |
176
+
177
+ Models not in the table fall back to Sonnet pricing. Versioned model IDs (e.g. `claude-opus-4-6-20260101`) are matched by prefix.
178
+
179
+ ---
180
+
181
+ ## Rate Limits
182
+
183
+ The hosted service allows **60 requests per minute** per IP. For higher limits, deploy your own instance.
184
+
185
+ ---
186
+
187
+ ## Token Storage (local mode only)
188
+
189
+ Usage history is stored at `~/.claude/token-counter/` (macOS/Linux) or `%USERPROFILE%\.claude\token-counter\` (Windows):
190
+
191
+ | File | Contents |
192
+ |------|----------|
193
+ | `session.json` | Current session totals (reset with `reset_session`) |
194
+ | `history.json` | All-time log, capped at 10,000 entries |
195
+
196
+ The hosted service does not persist your usage data between sessions.
@@ -0,0 +1,19 @@
1
+ export interface ModelPricing {
2
+ inputPerMillion: number;
3
+ outputPerMillion: number;
4
+ cacheReadPerMillion: number;
5
+ cacheWritePerMillion: number;
6
+ }
7
+ export declare const MODEL_PRICING: Record<string, ModelPricing>;
8
+ export declare function getPricing(model: string): ModelPricing;
9
+ export interface TokenCost {
10
+ inputCost: number;
11
+ outputCost: number;
12
+ cacheReadCost: number;
13
+ cacheWriteCost: number;
14
+ totalCost: number;
15
+ }
16
+ export declare function calculateCost(model: string, inputTokens: number, outputTokens: number, cacheReadTokens?: number, cacheWriteTokens?: number): TokenCost;
17
+ export declare function formatCost(usd: number): string;
18
+ export declare function formatTokens(n: number): string;
19
+ //# sourceMappingURL=costs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"costs.d.ts","sourceRoot":"","sources":["../src/costs.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAgCtD,CAAC;AASF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAUtD;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,eAAe,SAAI,EACnB,gBAAgB,SAAI,GACnB,SAAS,CAQX;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI9C"}
package/dist/costs.js ADDED
@@ -0,0 +1,72 @@
1
+ export const MODEL_PRICING = {
2
+ "claude-opus-4-6": {
3
+ inputPerMillion: 5.0,
4
+ outputPerMillion: 25.0,
5
+ cacheReadPerMillion: 0.5, // 10% of input
6
+ cacheWritePerMillion: 1.25, // 25% of input
7
+ },
8
+ "claude-sonnet-4-6": {
9
+ inputPerMillion: 3.0,
10
+ outputPerMillion: 15.0,
11
+ cacheReadPerMillion: 0.3,
12
+ cacheWritePerMillion: 0.75,
13
+ },
14
+ "claude-haiku-4-5": {
15
+ inputPerMillion: 1.0,
16
+ outputPerMillion: 5.0,
17
+ cacheReadPerMillion: 0.1,
18
+ cacheWritePerMillion: 0.25,
19
+ },
20
+ // Legacy / fallback
21
+ "claude-opus-4-5": {
22
+ inputPerMillion: 5.0,
23
+ outputPerMillion: 25.0,
24
+ cacheReadPerMillion: 0.5,
25
+ cacheWritePerMillion: 1.25,
26
+ },
27
+ "claude-sonnet-4-5": {
28
+ inputPerMillion: 3.0,
29
+ outputPerMillion: 15.0,
30
+ cacheReadPerMillion: 0.3,
31
+ cacheWritePerMillion: 0.75,
32
+ },
33
+ };
34
+ const DEFAULT_PRICING = {
35
+ inputPerMillion: 3.0,
36
+ outputPerMillion: 15.0,
37
+ cacheReadPerMillion: 0.3,
38
+ cacheWritePerMillion: 0.75,
39
+ };
40
+ export function getPricing(model) {
41
+ // Try exact match first
42
+ if (MODEL_PRICING[model])
43
+ return MODEL_PRICING[model];
44
+ // Try prefix match (e.g. "claude-opus-4-6-20260101" → "claude-opus-4-6")
45
+ for (const key of Object.keys(MODEL_PRICING)) {
46
+ if (model.startsWith(key))
47
+ return MODEL_PRICING[key];
48
+ }
49
+ return DEFAULT_PRICING;
50
+ }
51
+ export function calculateCost(model, inputTokens, outputTokens, cacheReadTokens = 0, cacheWriteTokens = 0) {
52
+ const pricing = getPricing(model);
53
+ const inputCost = (inputTokens / 1_000_000) * pricing.inputPerMillion;
54
+ const outputCost = (outputTokens / 1_000_000) * pricing.outputPerMillion;
55
+ const cacheReadCost = (cacheReadTokens / 1_000_000) * pricing.cacheReadPerMillion;
56
+ const cacheWriteCost = (cacheWriteTokens / 1_000_000) * pricing.cacheWritePerMillion;
57
+ const totalCost = inputCost + outputCost + cacheReadCost + cacheWriteCost;
58
+ return { inputCost, outputCost, cacheReadCost, cacheWriteCost, totalCost };
59
+ }
60
+ export function formatCost(usd) {
61
+ if (usd < 0.001)
62
+ return `$${(usd * 1000).toFixed(4)}m`; // show in milli-dollars
63
+ return `$${usd.toFixed(6)}`;
64
+ }
65
+ export function formatTokens(n) {
66
+ if (n >= 1_000_000)
67
+ return `${(n / 1_000_000).toFixed(2)}M`;
68
+ if (n >= 1_000)
69
+ return `${(n / 1_000).toFixed(1)}K`;
70
+ return `${n}`;
71
+ }
72
+ //# sourceMappingURL=costs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"costs.js","sourceRoot":"","sources":["../src/costs.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,aAAa,GAAiC;IACzD,iBAAiB,EAAE;QACjB,eAAe,EAAE,GAAG;QACpB,gBAAgB,EAAE,IAAI;QACtB,mBAAmB,EAAE,GAAG,EAAK,eAAe;QAC5C,oBAAoB,EAAE,IAAI,EAAG,eAAe;KAC7C;IACD,mBAAmB,EAAE;QACnB,eAAe,EAAE,GAAG;QACpB,gBAAgB,EAAE,IAAI;QACtB,mBAAmB,EAAE,GAAG;QACxB,oBAAoB,EAAE,IAAI;KAC3B;IACD,kBAAkB,EAAE;QAClB,eAAe,EAAE,GAAG;QACpB,gBAAgB,EAAE,GAAG;QACrB,mBAAmB,EAAE,GAAG;QACxB,oBAAoB,EAAE,IAAI;KAC3B;IACD,oBAAoB;IACpB,iBAAiB,EAAE;QACjB,eAAe,EAAE,GAAG;QACpB,gBAAgB,EAAE,IAAI;QACtB,mBAAmB,EAAE,GAAG;QACxB,oBAAoB,EAAE,IAAI;KAC3B;IACD,mBAAmB,EAAE;QACnB,eAAe,EAAE,GAAG;QACpB,gBAAgB,EAAE,IAAI;QACtB,mBAAmB,EAAE,GAAG;QACxB,oBAAoB,EAAE,IAAI;KAC3B;CACF,CAAC;AAEF,MAAM,eAAe,GAAiB;IACpC,eAAe,EAAE,GAAG;IACpB,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,GAAG;IACxB,oBAAoB,EAAE,IAAI;CAC3B,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,wBAAwB;IACxB,IAAI,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC;IAEtD,yEAAyE;IACzE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QAC7C,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,aAAa,CAAC,GAAG,CAAE,CAAC;IACxD,CAAC;IAED,OAAO,eAAe,CAAC;AACzB,CAAC;AAUD,MAAM,UAAU,aAAa,CAC3B,KAAa,EACb,WAAmB,EACnB,YAAoB,EACpB,eAAe,GAAG,CAAC,EACnB,gBAAgB,GAAG,CAAC;IAEpB,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC;IACtE,MAAM,UAAU,GAAG,CAAC,YAAY,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC;IACzE,MAAM,aAAa,GAAG,CAAC,eAAe,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAClF,MAAM,cAAc,GAAG,CAAC,gBAAgB,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC;IACrF,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa,GAAG,cAAc,CAAC;IAC1E,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,GAAG,GAAG,KAAK;QAAE,OAAO,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAE,CAAC,wBAAwB;IACjF,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,IAAI,CAAC,IAAI,SAAS;QAAE,OAAO,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC5D,IAAI,CAAC,IAAI,KAAK;QAAE,OAAO,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IACpD,OAAO,GAAG,CAAC,EAAE,CAAC;AAChB,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}