context-doctor 0.30.0 → 0.30.1

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.
@@ -0,0 +1,20 @@
1
+ /**
2
+ * How Claude Desktop's chat actually uses the MCP server, from Desktop's own
3
+ * log. Desktop gives an MCP server no hook and no transcript, so its
4
+ * per-server log (mcp-server-context-doctor.log: initialize, tools/list,
5
+ * tools/call) is the only evidence that the tools are offered and called.
6
+ * Desktop does not log which pages are opened, so chat activity itself cannot
7
+ * be measured locally; Code-tab sessions can (Claude Code transcripts record
8
+ * the desktop app as their entrypoint), and those reach context-doctor
9
+ * through Claude Code's hook and MCP config, not through this server.
10
+ */
11
+ export interface DesktopUsage {
12
+ launches: number;
13
+ toolLists: number;
14
+ toolCalls: number;
15
+ lastCall?: string;
16
+ }
17
+ export declare function desktopLogDir(home?: string): string;
18
+ export declare function desktopUsage(dir?: string): DesktopUsage | undefined;
19
+ /** One line for `doctor`: the numbers, and what to do with them. `codeTabSessions`: this week's Claude Code sessions run in Desktop's Code tab. */
20
+ export declare function describeDesktopUsage(u: DesktopUsage, codeTabSessions?: number): string;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * How Claude Desktop's chat actually uses the MCP server, from Desktop's own
3
+ * log. Desktop gives an MCP server no hook and no transcript, so its
4
+ * per-server log (mcp-server-context-doctor.log: initialize, tools/list,
5
+ * tools/call) is the only evidence that the tools are offered and called.
6
+ * Desktop does not log which pages are opened, so chat activity itself cannot
7
+ * be measured locally; Code-tab sessions can (Claude Code transcripts record
8
+ * the desktop app as their entrypoint), and those reach context-doctor
9
+ * through Claude Code's hook and MCP config, not through this server.
10
+ */
11
+ import { existsSync, readFileSync } from "node:fs";
12
+ import { homedir, platform } from "node:os";
13
+ import { join } from "node:path";
14
+ export function desktopLogDir(home = homedir()) {
15
+ switch (platform()) {
16
+ case "darwin": return join(home, "Library", "Logs", "Claude");
17
+ case "win32": return join(process.env.APPDATA ?? join(home, "AppData", "Roaming"), "Claude", "logs");
18
+ default: return join(home, ".config", "Claude", "logs");
19
+ }
20
+ }
21
+ export function desktopUsage(dir = desktopLogDir()) {
22
+ const server = join(dir, "mcp-server-context-doctor.log");
23
+ if (!existsSync(server))
24
+ return undefined;
25
+ const text = readFileSync(server, "utf8");
26
+ const count = (m) => text.split(`method="${m}"`).length - 1;
27
+ const calls = [...text.matchAll(/^(\d{4}-\d\d-\d\d)T[^\n]*method="tools\/call"/gm)];
28
+ return { launches: count("initialize"), toolLists: count("tools/list"), toolCalls: count("tools/call"), lastCall: calls.at(-1)?.[1] };
29
+ }
30
+ /** One line for `doctor`: the numbers, and what to do with them. `codeTabSessions`: this week's Claude Code sessions run in Desktop's Code tab. */
31
+ export function describeDesktopUsage(u, codeTabSessions = 0) {
32
+ const base = `tools offered in ${u.toolLists} of ${u.launches} launches, called ${u.toolCalls} time(s)${u.lastCall ? ` (last ${u.lastCall})` : ""}`;
33
+ const code = codeTabSessions > 0 ? `; your ${codeTabSessions} Code-tab sessions this week use the hook instead` : "";
34
+ return `${base}${code}. In a chat the model decides when to call them: the + menu's context_checkup prompt runs one on demand`;
35
+ }
package/dist/doctor.js CHANGED
@@ -14,6 +14,7 @@ import { fileURLToPath } from "node:url";
14
14
  import { ledgerPath } from "./ledger.js";
15
15
  import { loadConfig } from "./config.js";
16
16
  import { geminiCliPresent, geminiSettingsPath } from "./install.js";
17
+ import { describeDesktopUsage, desktopUsage } from "./desktopusage.js";
17
18
  function claudeDesktopConfigPath() {
18
19
  switch (platform()) {
19
20
  case "darwin": return join(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
@@ -108,6 +109,10 @@ function checkMcpHandshake() {
108
109
  export async function runDoctor() {
109
110
  const checks = [];
110
111
  checks.push(checkMcpEntry("Claude Desktop", claudeDesktopConfigPath()));
112
+ // Desktop chat has no hook or transcript; its own logs are the only evidence the tools are used.
113
+ const desktop = desktopUsage();
114
+ if (desktop)
115
+ checks.push({ label: "Desktop chat tool use", status: "ok", detail: describeDesktopUsage(desktop, recentSurfaces(7).get("claude-desktop") ?? 0) });
111
116
  checks.push(checkMcpEntry("Claude Code", join(homedir(), ".claude.json")));
112
117
  checks.push(checkMcpEntry("Cursor", join(homedir(), ".cursor", "mcp.json")));
113
118
  // Hook registration
package/dist/mcp.js CHANGED
@@ -52,7 +52,7 @@ const STRATEGY_IDS = ["dedupe", "trim-tool-results", "trim-tool-calls", "strip-b
52
52
  * recommended pattern.
53
53
  */
54
54
  function createServer({ fileAccess = true } = {}) {
55
- const server = new McpServer({ name: "context-doctor", version: "0.30.0" }, { instructions: SERVER_INSTRUCTIONS });
55
+ const server = new McpServer({ name: "context-doctor", version: "0.30.1" }, { instructions: SERVER_INSTRUCTIONS });
56
56
  server.tool("profile_context", "Profile an LLM conversation or prompt: token breakdown, largest blocks, and actionable findings about wasted context (duplicates, oversized pastes or tool results, base64 blobs, long history). Two inputs, pass ONE: `conversation` (full OpenAI/Anthropic JSON or raw text, for agents, files and proxies) or `sketch` (for chat apps such as Claude Desktop or ChatGPT where you cannot export the conversation: the turn count plus the few blocks that matter, ~120 tokens to write). Call it whenever the user asks about token usage, context size, cost, speed or limits, and on your own once the conversation passes ~30 turns or holds 3+ large pastes. Act on the top finding in your reply.", {
57
57
  conversation: z.string().optional().describe("Conversation JSON (OpenAI or Anthropic format, or bare message array) or raw prompt text. Omit in chat apps and pass `sketch`."),
58
58
  sketch: z.object({
package/dist/proxy.d.ts CHANGED
@@ -48,7 +48,7 @@ export interface ProxyOptions extends OptimizeOptions {
48
48
  googleUpstream?: string;
49
49
  }
50
50
  /** Reported by /health so `autopilot status` can tell an outdated service from a current one. */
51
- export declare const PROXY_VERSION = "0.30.0";
51
+ export declare const PROXY_VERSION = "0.30.1";
52
52
  /**
53
53
  * Remove a leading `/t/<token>` from a request path, or return undefined when
54
54
  * the prefix is absent or the token differs. The comparison is constant time
package/dist/proxy.js CHANGED
@@ -20,7 +20,7 @@ import { formatTokens, CHARS_PER_TOKEN, providerFor } from "./tokens.js";
20
20
  import { formatUsd, inputCostUsd, pricingFor } from "./pricing.js";
21
21
  import { recordLedger } from "./ledger.js";
22
22
  /** Reported by /health so `autopilot status` can tell an outdated service from a current one. */
23
- export const PROXY_VERSION = "0.30.0";
23
+ export const PROXY_VERSION = "0.30.1";
24
24
  /** Connection-level headers that must not be forwarded. */
25
25
  const SKIP_REQUEST_HEADERS = new Set(["host", "content-length", "connection", "transfer-encoding", "accept-encoding", "expect"]);
26
26
  const SKIP_RESPONSE_HEADERS = new Set(["content-length", "content-encoding", "transfer-encoding", "connection"]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-doctor",
3
- "version": "0.30.0",
3
+ "version": "0.30.1",
4
4
  "description": "Cut your Claude Code bill, measured on your own sessions: `npx context-doctor savings` shows what each lever saves, then the hook, autopilot and an earlier auto-compact window do it. Also Cursor, Codex, Claude Desktop and any Anthropic or OpenAI API app. MCP server and Claude Code plugin.",
5
5
  "keywords": [
6
6
  "agent",