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 +196 -0
- package/dist/costs.d.ts +19 -0
- package/dist/costs.d.ts.map +1 -0
- package/dist/costs.js +72 -0
- package/dist/costs.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1008 -0
- package/dist/index.js.map +1 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +61 -0
- package/dist/setup.js.map +1 -0
- package/dist/storage.d.ts +54 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +176 -0
- package/dist/storage.js.map +1 -0
- package/dist/tokenizer.d.ts +25 -0
- package/dist/tokenizer.d.ts.map +1 -0
- package/dist/tokenizer.js +83 -0
- package/dist/tokenizer.js.map +1 -0
- package/package.json +29 -0
- package/setup.sh +58 -0
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.
|
package/dist/costs.d.ts
ADDED
|
@@ -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":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|