@tokenzero/mcp 0.2.6 → 0.2.8

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 CHANGED
@@ -15,6 +15,8 @@ claude mcp add tokenzero -- npx -y @tokenzero/mcp # Claude Code
15
15
  | `audit_repo_token_waste` | locally | Static audit of a local directory (default: the working directory), a public GitHub repo, or a diff. Nothing from a local directory is uploaded. |
16
16
  | `calculate_model_arbitrage` | locally | Prices a workload across models at list prices, with and without prompt caching. |
17
17
  | `optimize_prompt_payload` | TokenZero service | Rewrites a request body so its static prefix is cacheable. Sends the body you pass to the TokenZero service (`https://tokenzero.sh` unless `TOKENZERO_URL` is set); do not include secrets. |
18
+ | `workspace_metrics` | TokenZero service | Reads a workspace's savings scorecard: hard savings and net ROI per window, each engine's contribution and one-click recommendations. Uses `TOKENZERO_KEY` unless a key is passed; `demo: true` returns a labelled sample. |
19
+ | `provision_workspace` | TokenZero service | Creates a free workspace and key with no form. The key is returned once. |
18
20
 
19
21
  Optional environment: `TOKENZERO_URL` (another gateway for `optimize_prompt_payload`; default `https://tokenzero.sh`), `GITHUB_TOKEN` (raises GitHub rate limits for repo audits).
20
22
 
@@ -9,17 +9,21 @@ import readline from "node:readline";
9
9
  import crypto from "node:crypto";
10
10
 
11
11
  // src/pricing.ts
12
- var PRICING_VERSION = "2026-10-26";
12
+ var PRICING_VERSION = "2026-10-27";
13
13
  var P = (provider, tier, input, output, cachedInput, cacheWrite, extra = {}) => ({ provider, tier, input, output, cachedInput, cacheWrite, ...extra });
14
14
  var PRICES = {
15
15
  // ---- OpenAI (standard tier, ≤272K; cache write = 30m TTL rate) ----
16
16
  "gpt-6-astra": P("openai", "frontier", 10, 50, 1, 12.5, { ultrafast: true, longCtxAt: 272e3, longCtx: { input: 20, output: 75, cachedInput: 2, cacheWrite: 25 }, minCacheTokens: 1024 }),
17
17
  "gpt-6.1-sol": P("openai", "mid", 2, 10, 0.1, 2.5, { ultrafast: true, longCtxAt: 272e3, longCtx: { input: 4, output: 15, cachedInput: 0.2, cacheWrite: 5 }, minCacheTokens: 1024 }),
18
+ "gpt-6.1-terra": P("openai", "mid", 1, 5, 0.05, 1.25, { longCtxAt: 272e3, longCtx: { input: 2, output: 7.5, cachedInput: 0.1, cacheWrite: 2.5 }, minCacheTokens: 1024 }),
18
19
  "gpt-6-sol": P("openai", "mid", 2, 10, 0.2, 2.5, { longCtxAt: 272e3, longCtx: { input: 4, output: 15, cachedInput: 0.4, cacheWrite: 5 }, minCacheTokens: 1024 }),
19
20
  "gpt-6-luna": P("openai", "fast", 0.1, 0.5, 0.01, 0.125, { longCtxAt: 272e3, longCtx: { input: 0.2, output: 0.75, cachedInput: 0.02, cacheWrite: 0.25 }, minCacheTokens: 1024 }),
20
21
  "gpt-5.6-sol": P("openai", "frontier", 4, 20, 0.4, 5, { longCtxAt: 272e3, longCtx: { input: 8, output: 30, cachedInput: 0.8, cacheWrite: 10 }, minCacheTokens: 1024 }),
21
22
  "gpt-5.6-terra": P("openai", "mid", 2, 12, 0.2, 2.5, { longCtxAt: 272e3, longCtx: { input: 4, output: 18, cachedInput: 0.4, cacheWrite: 5 }, minCacheTokens: 1024 }),
22
23
  "gpt-5.6-luna": P("openai", "fast", 0.2, 1.2, 0.02, 0.25, { longCtxAt: 272e3, longCtx: { input: 0.4, output: 1.8, cachedInput: 0.04, cacheWrite: 0.5 }, minCacheTokens: 1024 }),
24
+ // Daybreak cyber model: access needs OpenAI approval; 400K window
25
+ "gpt-5.6-cyber": P("openai", "frontier", 12.5, 75, 1.25, 15.625, { longCtxAt: 272e3, longCtx: { input: 25, output: 112.5, cachedInput: 2.5, cacheWrite: 31.25 }, minCacheTokens: 1024 }),
26
+ "gpt-5.3-codex": P("openai", "mid", 1.75, 14, 0.175, void 0, { minCacheTokens: 1024 }),
23
27
  "gpt-5.5": P("openai", "frontier", 5, 30, 0.5, void 0, { fastFactor: 2.5, longCtxAt: 272e3, longCtx: { input: 10, output: 45, cachedInput: 1 }, minCacheTokens: 1024 }),
24
28
  "gpt-5.5-pro": P("openai", "frontier", 30, 180),
25
29
  "gpt-5.4": P("openai", "frontier", 2.5, 15, 0.25, void 0, { longCtxAt: 272e3, longCtx: { input: 5, output: 22.5, cachedInput: 0.5 }, minCacheTokens: 1024 }),
@@ -84,7 +88,8 @@ var PRICES = {
84
88
  var MODEL_ALIASES = { "deepseek-v4-flash": "deepseek-flash", "deepseek-v4-flash-vision-exp": "deepseek-flash" };
85
89
  var CASCADE_TARGET = {
86
90
  "gpt-6-astra": "gpt-6.1-sol",
87
- "gpt-6.1-sol": "gpt-6-luna",
91
+ "gpt-6.1-sol": "gpt-6.1-terra",
92
+ "gpt-6.1-terra": "gpt-6-luna",
88
93
  "gpt-6-sol": "gpt-6-luna",
89
94
  "gpt-5.6-sol": "gpt-5.6-terra",
90
95
  "gpt-5.6-terra": "gpt-5.6-luna",
@@ -157,6 +162,7 @@ var MODEL_SUNSET = {
157
162
  "gpt-5-nano": { retires: "2026-12-11", replacement: "gpt-5.6-luna", announced: "2026-06-11" },
158
163
  "gpt-5-pro": { retires: "2026-12-11", replacement: "gpt-5.6-sol", announced: "2026-06-11" },
159
164
  "gpt-5.1": { retires: "2027-04-01", replacement: "gpt-6-sol", announced: "2026-10-01" },
165
+ "gpt-5.3-codex": { retires: "2027-04-01", replacement: "gpt-6-sol", announced: "2026-10-01" },
160
166
  "gpt-5.4-nano": { retires: "2027-04-01", replacement: "gpt-6-luna", announced: "2026-10-01" },
161
167
  "o1": { retires: "2026-10-23", replacement: "gpt-5.6-sol", announced: "2026-04-22" },
162
168
  "o3": { retires: "2026-12-11", replacement: "gpt-5.6-sol", announced: "2026-06-11" },
@@ -637,7 +643,7 @@ async function fetchRepoFiles(repo, opts = {}) {
637
643
  const meta = await fetch(`${GH}/repos/${repo}`, { headers: ghHeaders(opts.token) });
638
644
  if (meta.status === 404) throw new Error("repository not found (private repos are not supported)");
639
645
  if (!meta.ok) throw new Error(`GitHub API ${meta.status}: ${(await meta.text()).slice(0, 200)}`);
640
- const branch = (await meta.json()).default_branch;
646
+ const metaJson = await meta.json(), branch = metaJson.default_branch, fullName = typeof metaJson.full_name === "string" ? metaJson.full_name : repo;
641
647
  const tree = await fetch(`${GH}/repos/${repo}/git/trees/${encodeURIComponent(branch)}?recursive=1`, { headers: ghHeaders(opts.token) });
642
648
  if (!tree.ok) throw new Error(`GitHub tree ${tree.status}`);
643
649
  const treeAll = (await tree.json()).tree;
@@ -661,7 +667,7 @@ async function fetchRepoFiles(repo, opts = {}) {
661
667
  const r = await fetch(`https://raw.githubusercontent.com/${repo}/${branch}/${n}`, { headers: { "user-agent": UA } });
662
668
  return r.ok ? { path: n, content: await r.text() } : null;
663
669
  }))).filter((m) => !!m);
664
- return { files, manifests: manifests2, branch, total_candidates: entries.length };
670
+ return { files, manifests: manifests2, branch, total_candidates: entries.length, full_name: fullName };
665
671
  }
666
672
 
667
673
  // src/arbitrage.ts
@@ -754,7 +760,7 @@ function manifests(root) {
754
760
  }
755
761
 
756
762
  // mcp/src/main.ts
757
- var VERSION = "0.2.6";
763
+ var VERSION = "0.2.8";
758
764
  var BAKED_URL = true ? "https://tokenzero.sh" : "__TOKENZERO_DEFAULT_URL__";
759
765
  var SUPPORTED = [...MCP_LEGACY_VERSIONS];
760
766
  var SERVER = { name: "tokenzero", version: VERSION };
@@ -764,26 +770,36 @@ var serviceUrl = () => (process.env.TOKENZERO_URL || (BAKED_URL.startsWith("http
764
770
  var TOOLS = [
765
771
  {
766
772
  name: "audit_repo_token_waste",
773
+ title: "Audit a repo or directory for LLM token waste",
774
+ annotations: { title: "Audit a repo or directory for LLM token waste", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
767
775
  description: "Static audit for LLM token waste: uncached static prompts and prompt templates, frontier models on extraction/classification prompts, calls in loops, unpriced models. Give `path` for a local directory (scanned on this machine, nothing uploaded; defaults to the working directory), `repo` (owner/name) for a public GitHub repo, or `diff` for a unified diff. Results are static heuristics, not measurements.",
768
776
  inputSchema: { type: "object", properties: { path: { type: "string", description: "local directory; defaults to the current working directory" }, repo: { type: "string", description: "public GitHub owner/name" }, diff: { type: "string", description: "unified diff text, e.g. from git diff" } }, additionalProperties: false }
769
777
  },
770
778
  {
771
779
  name: "calculate_model_arbitrage",
780
+ title: "Price a workload across models",
781
+ annotations: { title: "Price a workload across models", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
772
782
  description: `Price a workload at list prices (table ${PRICING_VERSION}) for the requested model, its cheaper sibling and any extra models, with and without prompt caching. Runs locally.`,
773
783
  inputSchema: { type: "object", properties: { model: { type: "string" }, input_tokens: { type: "number" }, output_tokens: { type: "number" }, requests_per_month: { type: "number" }, static_tokens: { type: "number", description: "portion of input_tokens that is a fixed prefix (system + tools)" }, compare_to: { type: "array", items: { type: "string" } } }, required: ["model", "input_tokens", "output_tokens"], additionalProperties: false }
774
784
  },
775
785
  {
776
786
  name: "optimize_prompt_payload",
787
+ title: "Make a request body cache-friendly",
788
+ annotations: { title: "Make a request body cache-friendly", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
777
789
  description: "Rewrite an OpenAI Chat/Responses or Anthropic Messages request body so its static prefix is provider-cacheable, and project the saving. Sends the body you pass to the TokenZero service (set TOKENZERO_URL); do not pass secrets in it.",
778
790
  inputSchema: { type: "object", properties: { body: { type: "object" }, endpoint: { type: "string", enum: ["/v1/chat/completions", "/v1/responses", "/v1/messages"] }, strategy: { type: "string", enum: ["static", "conversation"] } }, required: ["body"], additionalProperties: false }
779
791
  },
780
792
  {
781
793
  name: "workspace_metrics",
794
+ title: "Read a workspace savings scorecard",
795
+ annotations: { title: "Read a workspace savings scorecard", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
782
796
  description: "Live value scorecard for a TokenZero workspace (GET /v1/workspaces/me/metrics): hard savings and net ROI per window, per-engine contribution, speed, parity, availability, privacy posture, per-model breakdown and one-click recommendations. Uses TOKENZERO_KEY unless a key is given; demo: true returns a labelled sample.",
783
797
  inputSchema: { type: "object", properties: { key: { type: "string", description: "workspace key (tz_live_\u2026); defaults to TOKENZERO_KEY" }, window: { type: "string", enum: ["24h", "7d", "30d", "all"] }, demo: { type: "boolean" } } }
784
798
  },
785
799
  {
786
800
  name: "provision_workspace",
801
+ title: "Create a free TokenZero workspace",
802
+ annotations: { title: "Create a free TokenZero workspace", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
787
803
  description: "Create a TokenZero workspace and key with no form (POST /v1/workspaces on the TokenZero service). Returns the key once, the base URLs that route through it, the one-click dashboard link (key in the URL fragment, never sent to the server) and the badge URL. Free up to the monthly free tier; nothing is billed.",
788
804
  inputSchema: { type: "object", properties: { name: { type: "string", description: 'workspace name (defaults to "mcp-agent")' } }, additionalProperties: false }
789
805
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tokenzero/mcp",
3
3
  "mcpName": "sh.tokenzero/mcp",
4
- "version": "0.2.6",
4
+ "version": "0.2.8",
5
5
  "description": "TokenZero MCP server (stdio): audit LLM token waste in your project locally, price model alternatives, and make prompts cache-friendly from Claude Code, Cursor, Windsurf or Cline.",
6
6
  "type": "module",
7
7
  "license": "Apache-2.0",