ctxjev-mcp 0.6.1 → 0.7.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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 x96x64
3
+ Copyright © 2026 Re:COO
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # ctxjev-mcp
4
4
 
5
- **Jev-based context scoring, as MCP tools for Claude Code, Codex, and any other MCP host.**
5
+ **Context scoring (Jev, or offline) as MCP tools for Claude Code, Codex, and any other MCP host.**
6
6
 
7
7
  [![npm](https://img.shields.io/npm/v/ctxjev-mcp.svg)](https://www.npmjs.com/package/ctxjev-mcp)
8
8
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
@@ -27,17 +27,20 @@ config shape differs.
27
27
 
28
28
  ## Setup
29
29
 
30
- Every example below pins the version (`ctxjev-mcp@0.6.1`, the latest on npm), so your host runs the
30
+ Every example below pins the version (`ctxjev-mcp@0.7.1`, the latest on npm), so your host runs the
31
31
  release you chose rather than whatever npm has at the time; change the pin to upgrade.
32
32
 
33
- Get a key at [console.typesafe.ai/settings/keys](https://console.typesafe.ai/settings/keys) (no
34
- waitlist) first. Without one the server still starts and lists its two tools, but every call
35
- returns an error saying `TYPESAFE_API_KEY` isn't set.
33
+ Both tools score with Jev by default (`scorer: "jev"`), which needs a key from
34
+ [console.typesafe.ai/settings/keys](https://console.typesafe.ai/settings/keys) (no waitlist). Without
35
+ one the server still starts and lists its two tools; a call with `scorer: "local"` (keyword overlap
36
+ with the goal) or `scorer: "recency"` (newest first, the same as plain truncation) works offline and
37
+ sends nothing, and a call that uses Jev returns an error saying `TYPESAFE_API_KEY` isn't set. For
38
+ offline use only, leave `--env TYPESAFE_API_KEY=...` (or the `env` block) out of the examples below.
36
39
 
37
40
  **Claude Code:**
38
41
 
39
42
  ```bash
40
- claude mcp add ctxjev --env TYPESAFE_API_KEY=... -- npx ctxjev-mcp@0.6.1
43
+ claude mcp add ctxjev --env TYPESAFE_API_KEY=... -- npx ctxjev-mcp@0.7.1
41
44
  ```
42
45
 
43
46
  The ctxjev repo also carries a project-level `.mcp.json`, which runs the server from
@@ -51,11 +54,11 @@ a local stdio server doesn't use, so it's safe to ignore (or `claude mcp remove
51
54
  **Codex CLI** (verified against `codex-cli` v0.155.1):
52
55
 
53
56
  ```bash
54
- codex mcp add ctxjev --env TYPESAFE_API_KEY=... -- npx ctxjev-mcp@0.6.1
57
+ codex mcp add ctxjev --env TYPESAFE_API_KEY=... -- npx ctxjev-mcp@0.7.1
55
58
  ```
56
59
 
57
60
  Or through the [Agent Plugins](https://agent-plugins.org) bundle in the ctxjev repo
58
- (`.agents/plugins/marketplace.json`), which registers the same `npx ctxjev-mcp@0.6.1` command:
61
+ (`.agents/plugins/marketplace.json`), which registers the same `npx ctxjev-mcp@0.7.1` command:
59
62
 
60
63
  ```bash
61
64
  codex plugin marketplace add x96x64/ctxjev
@@ -71,7 +74,7 @@ codex plugin add ctxjev@ctxjev-plugins
71
74
  "ctxjev": {
72
75
  "type": "stdio",
73
76
  "command": "npx",
74
- "args": ["ctxjev-mcp@0.6.1"],
77
+ "args": ["ctxjev-mcp@0.7.1"],
75
78
  "env": { "TYPESAFE_API_KEY": "..." }
76
79
  }
77
80
  }
@@ -80,14 +83,17 @@ codex plugin add ctxjev@ctxjev-plugins
80
83
 
81
84
  ## Tools
82
85
 
83
- - **`score_relevance`** takes `{ goal, entries, recencyWeight? }` and returns a
86
+ - **`score_relevance`** takes `{ goal, entries, scorer?, recencyWeight? }` and returns a
84
87
  relevance/recency/combined score per entry plus Jev token usage, with no decision made.
88
+ `scorer` is `"jev"` (the default, as before 0.7.1; needs `TYPESAFE_API_KEY`), `"local"`, or
89
+ `"recency"`; the last two run offline and report zero usage.
85
90
  - **`prune_history`** takes the same input plus `{ dropBelow?, summarizeBelow? }` and returns a
86
91
  decision (`keep`/`drop`/`summarize`) per entry, a savings report, and Jev token usage.
87
92
 
88
93
  `entries` is `{ id, role: 'user'|'assistant'|'tool', toolName?, content, timestamp }[]`.
89
94
 
90
- Entry content and the goal are sent to TypeSafe AI's Jev API. Common secret formats (API keys,
95
+ With `scorer: "jev"`, entry content and the goal are sent to TypeSafe AI's Jev API (with `"local"`
96
+ or `"recency"`, nothing is sent anywhere). Common secret formats (API keys,
91
97
  tokens, private-key blocks, `NAME=value` credentials) are masked to `[REDACTED]` first, on a
92
98
  best-effort basis.
93
99
 
package/dist/index.js CHANGED
@@ -3,9 +3,10 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
3
3
  import { createServer } from './server.js';
4
4
  async function main() {
5
5
  // Start either way: exiting here showed up in the host only as "connection closed". Without a
6
- // key, the tools are still listed, and each call returns an error saying what's missing.
6
+ // key, the tools are still listed, scorer 'local' and 'recency' work, and a call that uses Jev
7
+ // returns an error saying what's missing.
7
8
  if (!process.env.TYPESAFE_API_KEY) {
8
- console.error('ctxjev-mcp: TYPESAFE_API_KEY is not set, so every tool call will return an error until it is — get one at console.typesafe.ai/settings/keys');
9
+ console.error('ctxjev-mcp: TYPESAFE_API_KEY is not set, so only scorer "local" and "recency" work; a call that uses Jev (the default) returns an error until it is — get one at console.typesafe.ai/settings/keys');
9
10
  }
10
11
  const server = createServer();
11
12
  await server.connect(new StdioServerTransport());
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,KAAK,UAAU,IAAI;IACjB,8FAA8F;IAC9F,yFAAyF;IACzF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,6IAA6I,CAAC,CAAA;IAC9J,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,EAAE,CAAA;IAC7B,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAA;AAClD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;IAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,KAAK,UAAU,IAAI;IACjB,8FAA8F;IAC9F,+FAA+F;IAC/F,0CAA0C;IAC1C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,oMAAoM,CAAC,CAAA;IACrN,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,EAAE,CAAA;IAC7B,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAA;AAClD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;IAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
package/dist/schemas.d.ts CHANGED
@@ -11,7 +11,14 @@ export declare const entrySchema: z.ZodObject<{
11
11
  timestamp: z.ZodNumber;
12
12
  sourceTokens: z.ZodOptional<z.ZodNumber>;
13
13
  }, z.core.$strip>;
14
+ export declare const SCORERS: readonly ["jev", "local", "recency"];
15
+ export type McpScorer = (typeof SCORERS)[number];
14
16
  export declare const scoreRelevanceInput: {
17
+ scorer: z.ZodDefault<z.ZodEnum<{
18
+ jev: "jev";
19
+ local: "local";
20
+ recency: "recency";
21
+ }>>;
15
22
  goal: z.ZodString;
16
23
  entries: z.ZodArray<z.ZodObject<{
17
24
  id: z.ZodString;
@@ -30,6 +37,11 @@ export declare const scoreRelevanceInput: {
30
37
  export declare const pruneHistoryInput: {
31
38
  dropBelow: z.ZodOptional<z.ZodNumber>;
32
39
  summarizeBelow: z.ZodOptional<z.ZodNumber>;
40
+ scorer: z.ZodDefault<z.ZodEnum<{
41
+ jev: "jev";
42
+ local: "local";
43
+ recency: "recency";
44
+ }>>;
33
45
  goal: z.ZodString;
34
46
  entries: z.ZodArray<z.ZodObject<{
35
47
  id: z.ZodString;
package/dist/schemas.js CHANGED
@@ -28,7 +28,14 @@ export const entrySchema = z.object({
28
28
  .optional()
29
29
  .describe('Tokens in the full payload `content` was excerpted from, so the savings report counts what removing it actually saves.'),
30
30
  });
31
+ // 'jev' stays the default so a call that doesn't name a scorer behaves as in 0.7.0; 'local'
32
+ // (keyword overlap) and 'recency' (plain truncation) run offline, with no key and nothing sent.
33
+ export const SCORERS = ['jev', 'local', 'recency'];
31
34
  export const scoreRelevanceInput = {
35
+ scorer: z
36
+ .enum(SCORERS)
37
+ .default('jev')
38
+ .describe("How to score: 'jev' (TypeSafe AI's Jev; needs TYPESAFE_API_KEY in the server's env, and sends masked excerpts), 'local' (keyword overlap with the goal, offline), or 'recency' (newest first, the same as plain truncation, offline)."),
32
39
  goal: z.string().min(1).max(MAX_GOAL_LENGTH).describe('The current task/goal to judge each entry\'s relevance against.'),
33
40
  entries: z.array(entrySchema).max(MAX_ENTRIES).describe('The agent history entries to score.'),
34
41
  recencyWeight: z
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAEnE,+FAA+F;AAC/F,0FAA0F;AAC1F,8CAA8C;AAC9C,MAAM,WAAW,GAAG,GAAG,CAAA;AACvB,MAAM,kBAAkB,GAAG,IAAI,CAAA;AAC/B,gGAAgG;AAChG,0FAA0F;AAC1F,MAAM,eAAe,GAAG,IAAI,CAAA;AAC5B,mGAAmG;AACnG,yGAAyG;AACzG,MAAM,aAAa,GAAG,GAAG,CAAA;AACzB,MAAM,oBAAoB,GAAG,GAAG,CAAA;AAEhC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC;IACxC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;IAC3C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,QAAQ,EAAE;IACzD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC3C,8FAA8F;IAC9F,8FAA8F;IAC9F,qEAAqE;IACrE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE;IAC9B,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,GAAG,EAAE;SACL,WAAW,EAAE;SACb,QAAQ,EAAE;SACV,QAAQ,CAAC,wHAAwH,CAAC;CACtI,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,iEAAiE,CAAC;IACxH,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,qCAAqC,CAAC;IAC9F,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,QAAQ,CAAC,sGAAsG,cAAc,CAAC,aAAa,GAAG,CAAC;CACnJ,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,GAAG,mBAAmB;IACtB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yEAAyE,cAAc,CAAC,SAAS,GAAG,CAAC;IAC7J,cAAc,EAAE,CAAC;SACd,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,QAAQ,CAAC,kHAAkH,cAAc,CAAC,cAAc,GAAG,CAAC;CAChK,CAAA;AAED;;;6DAG6D;AAC7D,MAAM,UAAU,sBAAsB,CAAC,SAAiB,EAAE,cAAsB;IAC9E,IAAI,CAAC,qBAAqB,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,cAAc,SAAS,8CAA8C,cAAc,GAAG,CAAC,CAAA;IACzG,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -13,28 +13,29 @@ const MISSING_KEY = {
13
13
  content: [
14
14
  {
15
15
  type: 'text',
16
- text: 'TYPESAFE_API_KEY is not set in the environment this MCP server runs in. Both tools score with Jev and need it: get one at console.typesafe.ai/settings/keys and add it to the server\'s env in your MCP host\'s config.',
16
+ text: 'TYPESAFE_API_KEY is not set in the environment this MCP server runs in. scorer "jev" (the default) needs it: get one at console.typesafe.ai/settings/keys and add it to the server\'s env in your MCP host\'s config, or pass scorer "local" (keyword overlap) or "recency" (plain truncation), which run offline.',
17
17
  },
18
18
  ],
19
19
  };
20
- // Checked per call, not at startup, so a server started without a key still connects and lists its tools.
21
- const hasKey = () => Boolean(process.env.TYPESAFE_API_KEY);
20
+ // Checked per call, not at startup, so a server started without a key still connects and lists its
21
+ // tools; and only for scorer 'jev', since 'local' and 'recency' need no key.
22
+ const needsMissingKey = (scorer) => scorer === 'jev' && !process.env.TYPESAFE_API_KEY;
22
23
  export function createServer() {
23
24
  const server = new McpServer({ name: 'ctxjev', version: VERSION });
24
25
  server.registerTool('score_relevance', {
25
- description: "Score a batch of AI agent history entries for relevance to a goal, using Jev. Doesn't decide what to do about it — see prune_history for that.",
26
+ description: "Score a batch of AI agent history entries for relevance to a goal: with Jev by default (needs TYPESAFE_API_KEY), or offline with scorer 'local' or 'recency'. Doesn't decide what to do about it — see prune_history for that.",
26
27
  inputSchema: scoreRelevanceInput,
27
28
  }, async (args) => {
28
- if (!hasKey())
29
+ if (needsMissingKey(args.scorer))
29
30
  return MISSING_KEY;
30
31
  const result = await scoreRelevanceTool(args);
31
32
  return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
32
33
  });
33
34
  server.registerTool('prune_history', {
34
- description: 'Score a batch of AI agent history entries against a goal and decide what to keep, drop, or summarize.',
35
+ description: "Score a batch of AI agent history entries against a goal and decide what to keep, drop, or summarize: with Jev by default (needs TYPESAFE_API_KEY), or offline with scorer 'local' or 'recency'.",
35
36
  inputSchema: pruneHistoryInput,
36
37
  }, async (args) => {
37
- if (!hasKey())
38
+ if (needsMissingKey(args.scorer))
38
39
  return MISSING_KEY;
39
40
  const result = await pruneHistoryTool(args);
40
41
  return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEjE,6FAA6F;AAC7F,2FAA2F;AAC3F,oFAAoF;AACpF,MAAM,OAAO,GAAW,IAAI,CAAC,KAAK,CAChC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,CACvF,CAAC,OAAO,CAAA;AAET,MAAM,WAAW,GAAG;IAClB,OAAO,EAAE,IAAI;IACb,OAAO,EAAE;QACP;YACE,IAAI,EAAE,MAAe;YACrB,IAAI,EAAE,yNAAyN;SAChO;KACF;CACF,CAAA;AAED,0GAA0G;AAC1G,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;AAE1D,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;IAElE,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,WAAW,EACT,gJAAgJ;QAClJ,WAAW,EAAE,mBAAmB;KACjC,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,CAAC,MAAM,EAAE;YAAE,OAAO,WAAW,CAAA;QACjC,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC7C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;IAC/E,CAAC,CACF,CAAA;IAED,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,WAAW,EAAE,uGAAuG;QACpH,WAAW,EAAE,iBAAiB;KAC/B,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,CAAC,MAAM,EAAE;YAAE,OAAO,WAAW,CAAA;QACjC,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAA;QAC3C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;IAC/E,CAAC,CACF,CAAA;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEjE,6FAA6F;AAC7F,2FAA2F;AAC3F,oFAAoF;AACpF,MAAM,OAAO,GAAW,IAAI,CAAC,KAAK,CAChC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,CACvF,CAAC,OAAO,CAAA;AAET,MAAM,WAAW,GAAG;IAClB,OAAO,EAAE,IAAI;IACb,OAAO,EAAE;QACP;YACE,IAAI,EAAE,MAAe;YACrB,IAAI,EAAE,oTAAoT;SAC3T;KACF;CACF,CAAA;AAED,mGAAmG;AACnG,6EAA6E;AAC7E,MAAM,eAAe,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAA;AAE7F,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;IAElE,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,WAAW,EACT,gOAAgO;QAClO,WAAW,EAAE,mBAAmB;KACjC,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,OAAO,WAAW,CAAA;QACpD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC7C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;IAC/E,CAAC,CACF,CAAA;IAED,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,WAAW,EAAE,kMAAkM;QAC/M,WAAW,EAAE,iBAAiB;KAC/B,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,OAAO,WAAW,CAAA;QACpD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAA;QAC3C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;IAC/E,CAAC,CACF,CAAA;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
package/dist/tools.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { type Entry, type ScoreCache } from 'ctxjev-core';
1
+ import { type Entry, type JevClient, type ScoreCache } from 'ctxjev-core';
2
+ import { type McpScorer } from './schemas.js';
2
3
  /**
3
4
  * Plain functions wrapping ctxjev-core, kept independent of the MCP framework so they're
4
5
  * testable without spinning up a server. src/server.ts adapts these into MCP tool handlers.
@@ -7,12 +8,19 @@ export declare const SCORE_CACHE_LIMIT = 5000;
7
8
  export declare function createBoundedScoreCache(limit?: number): ScoreCache & {
8
9
  readonly size: number;
9
10
  };
11
+ /** What a tool talks to: the server's shared cache and the default Jev client, unless a test passes its own. */
12
+ export type ToolDeps = {
13
+ jevClient?: JevClient;
14
+ cache?: ScoreCache;
15
+ };
10
16
  export type ScoreRelevanceArgs = {
17
+ /** Defaults to 'jev', as in 0.7.0; 'local' and 'recency' run offline. */
18
+ scorer?: McpScorer;
11
19
  goal: string;
12
20
  entries: Entry[];
13
21
  recencyWeight?: number;
14
22
  };
15
- export declare function scoreRelevanceTool({ goal, entries, recencyWeight }: ScoreRelevanceArgs): Promise<{
23
+ export declare function scoreRelevanceTool({ scorer, goal, entries, recencyWeight }: ScoreRelevanceArgs, { jevClient, cache }?: ToolDeps): Promise<{
16
24
  scored: import("ctxjev-core").ScoredEntry[];
17
25
  usage: import("ctxjev-core").JevUsage;
18
26
  }>;
@@ -20,7 +28,7 @@ export type PruneHistoryArgs = ScoreRelevanceArgs & {
20
28
  dropBelow?: number;
21
29
  summarizeBelow?: number;
22
30
  };
23
- export declare function pruneHistoryTool({ goal, entries, recencyWeight, dropBelow, summarizeBelow }: PruneHistoryArgs): Promise<{
31
+ export declare function pruneHistoryTool({ scorer, goal, entries, recencyWeight, dropBelow, summarizeBelow }: PruneHistoryArgs, { jevClient, cache }?: ToolDeps): Promise<{
24
32
  decisions: import("ctxjev-core").PruneDecision[];
25
33
  savings: import("ctxjev-core").SavingsReport;
26
34
  usage: import("ctxjev-core").JevUsage;
package/dist/tools.js CHANGED
@@ -30,15 +30,15 @@ export function createBoundedScoreCache(limit = SCORE_CACHE_LIMIT) {
30
30
  };
31
31
  }
32
32
  const scoreCache = createBoundedScoreCache();
33
- export async function scoreRelevanceTool({ goal, entries, recencyWeight }) {
33
+ export async function scoreRelevanceTool({ scorer = 'jev', goal, entries, recencyWeight }, { jevClient, cache = scoreCache } = {}) {
34
34
  const { usage, onUsage } = createUsageAccumulator();
35
35
  // core's own default scorer is 'recency' as of 0.6.0 (see prune.ts), since the holdout eval tied
36
- // Jev on task success. This tool's whole purpose is exposing Jev scoring, so it keeps asking for
37
- // it explicitly rather than silently inheriting that default.
38
- const scored = await scoreEntries(entries, goal, recencyWeight ?? DEFAULT_POLICY.recencyWeight, { onUsage, cache: scoreCache, scorer: 'jev' });
36
+ // Jev on task success. These tools default to 'jev', as they did before `scorer` existed, so a
37
+ // host's existing calls keep their meaning; 'local' and 'recency' are offline.
38
+ const scored = await scoreEntries(entries, goal, recencyWeight ?? DEFAULT_POLICY.recencyWeight, { onUsage, cache, jevClient, scorer });
39
39
  return { scored, usage };
40
40
  }
41
- export async function pruneHistoryTool({ goal, entries, recencyWeight, dropBelow, summarizeBelow }) {
41
+ export async function pruneHistoryTool({ scorer = 'jev', goal, entries, recencyWeight, dropBelow, summarizeBelow }, { jevClient, cache = scoreCache } = {}) {
42
42
  const policy = {
43
43
  dropBelow: dropBelow ?? DEFAULT_POLICY.dropBelow,
44
44
  summarizeBelow: summarizeBelow ?? DEFAULT_POLICY.summarizeBelow,
@@ -46,7 +46,7 @@ export async function pruneHistoryTool({ goal, entries, recencyWeight, dropBelow
46
46
  };
47
47
  validatePolicyOrdering(policy.dropBelow, policy.summarizeBelow);
48
48
  const { usage, onUsage } = createUsageAccumulator();
49
- const decisions = await pruneContext(entries, goal, policy, { onUsage, cache: scoreCache, scorer: 'jev' });
49
+ const decisions = await pruneContext(entries, goal, policy, { onUsage, cache, jevClient, scorer });
50
50
  const savings = summarizeSavings(entries, decisions);
51
51
  return { decisions, savings, usage };
52
52
  }
package/dist/tools.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAmD,MAAM,aAAa,CAAA;AACnK,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAErD;;;GAGG;AAEH,6FAA6F;AAC7F,+FAA+F;AAC/F,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,CAAA;AAEtC,MAAM,UAAU,uBAAuB,CAAC,KAAK,GAAG,iBAAiB;IAC/D,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAA;IACvC,OAAO;QACL,GAAG,CAAC,GAAG;YACL,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAC5B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;gBACjB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YACvB,CAAC;YACD,OAAO,KAAK,CAAA;QACd,CAAC;QACD,GAAG,CAAC,GAAG,EAAE,KAAK;YACZ,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACjB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YACrB,IAAI,KAAK,CAAC,IAAI,GAAG,KAAK;gBAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAM,CAAC,CAAA;QAClE,CAAC;QACD,IAAI,IAAI;YACN,OAAO,KAAK,CAAC,IAAI,CAAA;QACnB,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,GAAG,uBAAuB,EAAE,CAAA;AAQ5C,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAsB;IAC3F,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,sBAAsB,EAAE,CAAA;IACnD,iGAAiG;IACjG,iGAAiG;IACjG,8DAA8D;IAC9D,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE,aAAa,IAAI,cAAc,CAAC,aAAa,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;IAC9I,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;AAC1B,CAAC;AAOD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,cAAc,EAAoB;IAClH,MAAM,MAAM,GAAkB;QAC5B,SAAS,EAAE,SAAS,IAAI,cAAc,CAAC,SAAS;QAChD,cAAc,EAAE,cAAc,IAAI,cAAc,CAAC,cAAc;QAC/D,aAAa,EAAE,aAAa,IAAI,cAAc,CAAC,aAAa;KAC7D,CAAA;IACD,sBAAsB,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,cAAc,CAAC,CAAA;IAE/D,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,sBAAsB,EAAE,CAAA;IACnD,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1G,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;IACpD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;AACtC,CAAC"}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ctxjev-mcp",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "description": "MCP server exposing ctxjev's Jev-based context scoring/pruning as tools for any MCP-capable agent host.",
5
5
  "keywords": [
6
6
  "mcp",
@@ -14,7 +14,7 @@
14
14
  ],
15
15
  "license": "MIT",
16
16
  "author": {
17
- "name": "x96x64",
17
+ "name": "Re:COO",
18
18
  "url": "https://github.com/x96x64"
19
19
  },
20
20
  "repository": {
@@ -40,7 +40,7 @@
40
40
  "dependencies": {
41
41
  "@modelcontextprotocol/sdk": "^1.30.0",
42
42
  "zod": "^4.6.5",
43
- "ctxjev-core": "0.6.1"
43
+ "ctxjev-core": "0.7.1"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/node": "^22",