codex-dev-mcp-suite 1.0.0 → 1.1.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/.env.example CHANGED
@@ -1,19 +1,39 @@
1
1
  # All network features are OPTIONAL. Without them, recall falls back to keyword
2
2
  # search (fully offline). Any OpenAI-compatible endpoint works: OpenAI, Ollama,
3
- # LM Studio, OpenRouter, vLLM, LiteLLM, 9router, etc.
3
+ # LM Studio, Groq, Cerebras, OpenRouter, vLLM, LiteLLM, 9router, etc.
4
+
5
+ # Hard no-network mode. When true, disables embeddings/rerank even if keys exist.
6
+ # Accepted true values: true, 1, yes, on.
7
+ # MCP_DETERMINISTIC_FALLBACK=true
8
+
9
+ # Optional provider chain for chat/rerank. Configure only primary, or add
10
+ # numbered fallbacks. Groq/Cerebras/OpenRouter are recommended examples; any
11
+ # OpenAI-compatible base URL + API key + model ID works.
12
+ # MCP_PROVIDER_PRIMARY=groq
13
+ # MCP_PROVIDER_PRIMARY_BASE_URL=https://api.groq.com/openai/v1
14
+ # MCP_PROVIDER_PRIMARY_API_KEY=<groq-key>
15
+ # MCP_PROVIDER_PRIMARY_MODEL=llama-3.3-70b-versatile
16
+ # MCP_PROVIDER_CHAIN2=cerebras
17
+ # MCP_PROVIDER_CHAIN2_BASE_URL=https://api.cerebras.ai/v1
18
+ # MCP_PROVIDER_CHAIN2_API_KEY=<cerebras-key>
19
+ # MCP_PROVIDER_CHAIN2_MODEL=llama-3.3-70b
20
+ # MCP_PROVIDER_CHAIN3=openrouter
21
+ # MCP_PROVIDER_CHAIN3_BASE_URL=https://openrouter.ai/api/v1
22
+ # MCP_PROVIDER_CHAIN3_API_KEY=<openrouter-key>
23
+ # MCP_PROVIDER_CHAIN3_MODEL=openai/gpt-4o-mini
4
24
 
5
25
  # Base URL of an OpenAI-compatible API (must expose /v1/...)
6
- LLM_BASE_URL=http://localhost:11434/v1
26
+ MCP_LLM_BASE_URL=http://localhost:11434/v1
7
27
  # API key for that endpoint (leave blank for local servers that don't need one)
8
- LLM_API_KEY=
28
+ MCP_LLM_API_KEY=
9
29
 
10
30
  # Optional: semantic embedding recall (needs /v1/embeddings)
11
- EMBED_MODEL=nomic-embed-text
31
+ MCP_EMBED_MODEL=nomic-embed-text
12
32
  EMBED_TIMEOUT_MS=12000
13
33
 
14
34
  # Optional: LLM rerank recall (needs /v1/chat/completions)
15
35
  # Used automatically when embeddings are unavailable.
16
- RERANK_MODEL=llama3.1:8b
36
+ MCP_RERANK_MODEL=llama3.1:8b
17
37
  RERANK_TIMEOUT_MS=30000
18
38
  RERANK_ENABLED=1
19
39
 
@@ -22,5 +42,6 @@ RERANK_ENABLED=1
22
42
  # JOURNAL_DIR=~/.codex/memories/journal
23
43
  # CHECKPOINT_DIR=~/.codex/memories/checkpoints
24
44
 
25
- # Backward-compatible aliases (still honored): NINEROUTER_URL, NINEROUTER_KEY,
26
- # EMBED_URL, EMBED_KEY, RERANK_URL, RERANK_KEY
45
+ # Backward-compatible aliases (still honored): LLM_BASE_URL, LLM_API_KEY,
46
+ # NINEROUTER_URL, NINEROUTER_KEY, EMBED_MODEL, RERANK_MODEL, EMBED_URL,
47
+ # EMBED_KEY, RERANK_URL, RERANK_KEY
package/CHANGELOG.md ADDED
@@ -0,0 +1,34 @@
1
+ # Changelog
2
+
3
+ ## 1.1.0 - 2026-06-15
4
+
5
+ ### Added
6
+ - Added optional numbered provider chain for chat/rerank fallback: `MCP_PROVIDER_PRIMARY_*`, `MCP_PROVIDER_CHAIN2_*`, `MCP_PROVIDER_CHAIN3_*`, and higher.
7
+ - Added provider-chain tests for ordered fallback, incomplete slot skipping, deterministic disable, and legacy fallback.
8
+
9
+ ## 1.0.1 - 2026-06-15
10
+
11
+ ### Added
12
+ - Added neutral `MCP_*` environment variables for model configuration:
13
+ - `MCP_LLM_BASE_URL`, `MCP_LLM_API_KEY`
14
+ - `MCP_RERANK_BASE_URL`, `MCP_RERANK_API_KEY`, `MCP_RERANK_MODEL`
15
+ - `MCP_EMBED_BASE_URL`, `MCP_EMBED_API_KEY`, `MCP_EMBED_MODEL`
16
+ - Added client-agnostic docs:
17
+ - `docs/configuration.md`
18
+ - `docs/clients/codex.md`
19
+ - `docs/clients/claude-code.md`
20
+ - `docs/clients/generic-mcp.md`
21
+ - Added tests proving `MCP_*` env vars override legacy aliases.
22
+ - Added `MCP_DETERMINISTIC_FALLBACK` hard no-network mode for deterministic local-only recall.
23
+ - Added `docs/privacy.md` covering local storage, data flow, and remote provider boundaries.
24
+ - Added provider guidance for Groq, Cerebras, and OpenRouter as optional external endpoints.
25
+
26
+ ### Changed
27
+ - README now presents the project as **Dev MCP Suite** while keeping the npm package name `codex-dev-mcp-suite` for compatibility.
28
+ - Rerank and embedding helpers now describe any OpenAI-compatible endpoint, not 9Router only.
29
+ - `.env.example` now recommends `MCP_*` names for new installs.
30
+ - `memory_recall`, `journal_search`, and `memory_reindex` now explicitly respect deterministic no-network mode.
31
+
32
+ ### Compatibility
33
+ - Legacy env names remain supported: `LLM_*`, `NINEROUTER_*`, `EMBED_*`, and `RERANK_*`.
34
+ - Offline keyword search remains the default if no model endpoint is configured.
package/README.md CHANGED
@@ -1,6 +1,9 @@
1
- # Codex Dev MCP Suite
1
+ # Dev MCP Suite
2
2
 
3
3
  [![CI](https://github.com/verrysimatupang99/codex-dev-mcp-suite/actions/workflows/ci.yml/badge.svg)](https://github.com/verrysimatupang99/codex-dev-mcp-suite/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/codex-dev-mcp-suite.svg)](https://www.npmjs.com/package/codex-dev-mcp-suite)
5
+
6
+ Published as `codex-dev-mcp-suite` for backward compatibility.
4
7
 
5
8
  Four local, file-based MCP servers for solo developers and vibecoders who keep
6
9
  losing context when sessions hit "input too long" / get compacted / restart.
@@ -8,7 +11,8 @@ Stop re-pasting context across sessions.
8
11
 
9
12
  All servers are **local, dependency-light (only the MCP SDK), and split storage
10
13
  per-project** by the working directory. Works with any MCP-capable client
11
- (Codex CLI, Claude Code, Cursor, Cline, etc.).
14
+ (Codex CLI, Claude Code, Cursor, Cline, Gemini-compatible launchers, Hermes,
15
+ or any stdio MCP host).
12
16
 
13
17
  ## The four servers
14
18
 
@@ -28,11 +32,46 @@ Recall auto-selects the best available mode:
28
32
  3. **keyword** — always-available offline fallback
29
33
 
30
34
  All network features degrade gracefully: no endpoint = keyword mode, never an error.
35
+ Use the neutral `MCP_*` environment variables for new installs; legacy
36
+ `NINEROUTER_*` and `LLM_*` variables are still supported. See
37
+ [`docs/configuration.md`](docs/configuration.md).
38
+
39
+ Need hard local-only behavior? Set `MCP_DETERMINISTIC_FALLBACK=true` to disable
40
+ embeddings/rerank even if model keys are present; results are labeled
41
+ `[deterministic]`.
31
42
 
32
43
  ## Install
33
44
 
34
45
  Requires Node.js >= 18.
35
46
 
47
+ ### Quickest: run via npx (no clone)
48
+
49
+ Point your MCP client at the published package — no install step needed:
50
+
51
+ ```toml
52
+ # Codex CLI ~/.codex/config.toml
53
+ [mcp_servers.project-memory]
54
+ command = "npx"
55
+ args = ["-y", "-p", "codex-dev-mcp-suite", "project-memory-mcp"]
56
+
57
+ [mcp_servers.devjournal]
58
+ command = "npx"
59
+ args = ["-y", "-p", "codex-dev-mcp-suite", "devjournal-mcp"]
60
+
61
+ [mcp_servers.checkpoint]
62
+ command = "npx"
63
+ args = ["-y", "-p", "codex-dev-mcp-suite", "checkpoint-mcp"]
64
+
65
+ [mcp_servers.context-pack]
66
+ command = "npx"
67
+ args = ["-y", "-p", "codex-dev-mcp-suite", "context-pack-mcp"]
68
+ ```
69
+
70
+ Or install globally: `npm i -g codex-dev-mcp-suite` → commands
71
+ `project-memory-mcp`, `devjournal-mcp`, `checkpoint-mcp`, `context-pack-mcp`.
72
+
73
+ ### From source
74
+
36
75
  ```bash
37
76
  git clone https://github.com/<you>/codex-dev-mcp-suite.git
38
77
  cd codex-dev-mcp-suite
@@ -42,6 +81,12 @@ for s in project-memory checkpoint context-pack devjournal; do (cd "$s" && npm i
42
81
 
43
82
  ### Register with your MCP client
44
83
 
84
+ Client-specific examples:
85
+
86
+ - [Codex CLI](docs/clients/codex.md)
87
+ - [Claude Code](docs/clients/claude-code.md)
88
+ - [Generic MCP JSON](docs/clients/generic-mcp.md)
89
+
45
90
  **Codex CLI** (`~/.codex/config.toml`):
46
91
 
47
92
  ```toml
@@ -50,10 +95,10 @@ command = "node"
50
95
  args = ["/abs/path/codex-dev-mcp-suite/project-memory/server.js"]
51
96
  [mcp_servers.project-memory.env]
52
97
  MEMORY_VAULT_DIR = "~/.codex/memories/vault"
53
- # optional recall upgrades (see .env.example)
54
- # LLM_BASE_URL = "http://localhost:11434/v1" # any OpenAI-compatible endpoint
55
- # LLM_API_KEY = "..."
56
- # RERANK_MODEL = "llama3.1:8b"
98
+ # optional recall upgrades (see .env.example and docs/configuration.md)
99
+ # MCP_LLM_BASE_URL = "http://localhost:11434/v1" # any OpenAI-compatible endpoint
100
+ # MCP_LLM_API_KEY = "..."
101
+ # MCP_RERANK_MODEL = "llama3.1:8b"
57
102
 
58
103
  [mcp_servers.checkpoint]
59
104
  command = "node"
@@ -70,8 +115,10 @@ args = ["/abs/path/codex-dev-mcp-suite/devjournal/server.js"]
70
115
  JOURNAL_DIR = "~/.codex/memories/journal"
71
116
  ```
72
117
 
73
- **Claude Code / Cursor / Cline** (`mcpServers` JSON): same idea — `command: "node"`,
74
- `args: ["/abs/path/<server>/server.js"]`, optional `env`.
118
+ **Claude Code / Cursor / Cline / other MCP clients** (`mcpServers` JSON): same
119
+ idea use the npm bin commands (`project-memory-mcp`, `devjournal-mcp`,
120
+ `checkpoint-mcp`, `context-pack-mcp`) or `node /abs/path/<server>/server.js`,
121
+ with optional `env`.
75
122
 
76
123
  ## Daily workflow
77
124
 
@@ -100,8 +147,10 @@ cd project-memory && npm test
100
147
 
101
148
  ## Privacy
102
149
 
103
- Everything is stored as plain files on your machine. No data leaves your
104
- computer unless you explicitly configure an embeddings/rerank endpoint. Your
150
+ Local-first by default: no hosted backend, no built-in telemetry, no project
151
+ account system. Everything is stored as files on your machine. No data leaves
152
+ your machine unless you explicitly configure an external model/API endpoint for
153
+ rerank or embeddings. See [privacy and data flow](docs/privacy.md). Your
105
154
  personal vault/journal/checkpoints are gitignored.
106
155
 
107
156
  ## License
@@ -0,0 +1,3 @@
1
+ export function deterministicEnabled() {
2
+ return /^(1|true|yes|on)$/i.test(String(process.env.MCP_DETERMINISTIC_FALLBACK || "").trim());
3
+ }
@@ -0,0 +1,56 @@
1
+ import { deterministicEnabled } from "./env.js";
2
+
3
+ const DEFAULT_BASE = "http://localhost:20128";
4
+ const DEFAULT_MODEL = "kr/claude-haiku-4.5";
5
+
6
+ function value(name) {
7
+ return String(process.env[name] || "").trim();
8
+ }
9
+
10
+ function providerEnv(prefix) {
11
+ const label = value(prefix);
12
+ const base = value(`${prefix}_BASE_URL`);
13
+ const key = value(`${prefix}_API_KEY`);
14
+ const model = value(`${prefix}_MODEL`);
15
+ if (!label || !base || !key || !model) return null;
16
+ return { label, base, key, model };
17
+ }
18
+
19
+ function numberedProviders() {
20
+ const providers = [];
21
+ const primary = providerEnv("MCP_PROVIDER_PRIMARY");
22
+ if (primary) providers.push(primary);
23
+
24
+ const slots = Object.keys(process.env)
25
+ .map((name) => name.match(/^MCP_PROVIDER_CHAIN(\d+)$/)?.[1])
26
+ .filter(Boolean)
27
+ .map(Number)
28
+ .filter((n) => n >= 2)
29
+ .sort((a, b) => a - b);
30
+
31
+ for (const n of slots) {
32
+ const provider = providerEnv(`MCP_PROVIDER_CHAIN${n}`);
33
+ if (provider) providers.push(provider);
34
+ }
35
+ return providers;
36
+ }
37
+
38
+ function legacyProvider() {
39
+ const base = value("MCP_RERANK_BASE_URL") || value("MCP_LLM_BASE_URL") || value("LLM_BASE_URL") || value("RERANK_URL") || value("NINEROUTER_URL") || DEFAULT_BASE;
40
+ const key = value("MCP_RERANK_API_KEY") || value("MCP_LLM_API_KEY") || value("LLM_API_KEY") || value("RERANK_KEY") || value("NINEROUTER_KEY");
41
+ const model = value("MCP_RERANK_MODEL") || value("RERANK_MODEL") || DEFAULT_MODEL;
42
+ if (!key) return null;
43
+ return { label: "legacy", base, key, model };
44
+ }
45
+
46
+ export function providerChainConfig() {
47
+ const deterministic = deterministicEnabled();
48
+ const rerankEnabled = process.env.RERANK_ENABLED !== "0";
49
+ if (deterministic || !rerankEnabled) return { providers: [], enabled: false, deterministic };
50
+ const providers = numberedProviders();
51
+ if (providers.length === 0) {
52
+ const legacy = legacyProvider();
53
+ if (legacy) providers.push(legacy);
54
+ }
55
+ return { providers, enabled: providers.length > 0, deterministic };
56
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * LLM reranker via 9router chat models (e.g. Kiro kr/claude-haiku-4.5).
2
+ * LLM reranker via any OpenAI-compatible /v1/chat/completions model.
3
3
  * Used when embeddings are unavailable: keyword prefilter -> LLM picks the
4
4
  * most relevant candidates. Degrades gracefully: returns null on any failure
5
5
  * so callers fall back to keyword ordering. Never throws.
@@ -7,23 +7,29 @@
7
7
  import http from "http";
8
8
  import https from "https";
9
9
  import { URL } from "url";
10
+ import { deterministicEnabled } from "./env.js";
11
+ import { providerChainConfig } from "./provider-chain.js";
10
12
 
11
- const BASE = process.env.LLM_BASE_URL || process.env.RERANK_URL || process.env.NINEROUTER_URL || "http://localhost:20128";
12
- const KEY = process.env.LLM_API_KEY || process.env.RERANK_KEY || process.env.NINEROUTER_KEY || "";
13
- const MODEL = process.env.RERANK_MODEL || "kr/claude-haiku-4.5";
14
13
  const TIMEOUT_MS = Number(process.env.RERANK_TIMEOUT_MS || 30000);
15
14
  const ENABLED = process.env.RERANK_ENABLED !== "0";
16
15
 
17
16
  export function rerankConfig() {
18
- return { base: BASE, model: MODEL, enabled: Boolean(KEY) && ENABLED };
17
+ const cfg = providerChainConfig();
18
+ const first = cfg.providers[0] || {};
19
+ return {
20
+ base: first.base,
21
+ model: first.model,
22
+ providers: cfg.providers.map(({ label, base, model }) => ({ label, base, model })),
23
+ enabled: ENABLED && cfg.enabled && !deterministicEnabled(),
24
+ deterministic: deterministicEnabled(),
25
+ };
19
26
  }
20
27
 
21
- function chat(messages) {
28
+ function chatWithProvider(provider, messages) {
22
29
  return new Promise((resolve) => {
23
- if (!KEY || !ENABLED) return resolve(null);
24
30
  let u;
25
- try { u = new URL("/v1/chat/completions", BASE); } catch { return resolve(null); }
26
- const payload = Buffer.from(JSON.stringify({ model: MODEL, stream: false, temperature: 0, max_tokens: 200, messages }));
31
+ try { u = new URL("/v1/chat/completions", provider.base); } catch { return resolve(null); }
32
+ const payload = Buffer.from(JSON.stringify({ model: provider.model, stream: false, temperature: 0, max_tokens: 200, messages }));
27
33
  const lib = u.protocol === "https:" ? https : http;
28
34
  const req = lib.request(
29
35
  {
@@ -31,7 +37,7 @@ function chat(messages) {
31
37
  port: u.port || (u.protocol === "https:" ? 443 : 80),
32
38
  path: u.pathname,
33
39
  method: "POST",
34
- headers: { "Content-Type": "application/json", "Content-Length": payload.length, Authorization: `Bearer ${KEY}` },
40
+ headers: { "Content-Type": "application/json", "Content-Length": payload.length, Authorization: `Bearer ${provider.key}` },
35
41
  timeout: TIMEOUT_MS,
36
42
  },
37
43
  (res) => {
@@ -39,7 +45,6 @@ function chat(messages) {
39
45
  res.on("data", (c) => (body += c));
40
46
  res.on("end", () => {
41
47
  if (res.statusCode !== 200) return resolve(null);
42
- // handle plain JSON or SSE stream just in case
43
48
  try {
44
49
  const j = JSON.parse(body);
45
50
  return resolve(j?.choices?.[0]?.message?.content ?? null);
@@ -66,12 +71,22 @@ function chat(messages) {
66
71
  });
67
72
  }
68
73
 
74
+ async function chat(messages) {
75
+ if (!ENABLED || deterministicEnabled()) return null;
76
+ const { providers } = providerChainConfig();
77
+ for (const provider of providers) {
78
+ const out = await chatWithProvider(provider, messages);
79
+ if (out) return out;
80
+ }
81
+ return null;
82
+ }
83
+
69
84
  /**
70
85
  * Given a query and candidates [{id, title, snippet}], ask the model to return
71
86
  * the ids ordered by relevance. Returns an array of ids, or null on failure.
72
87
  */
73
88
  export async function rerank(query, candidates, topK = 5) {
74
- if (!KEY || !ENABLED || !candidates || candidates.length === 0) return null;
89
+ if (!ENABLED || deterministicEnabled() || !candidates || candidates.length === 0 || !providerChainConfig().enabled) return null;
75
90
  const list = candidates.map((c, i) => `[${i + 1}] (id:${c.id}) ${c.title}\n ${String(c.snippet || "").replace(/\s+/g, " ").slice(0, 200)}`).join("\n");
76
91
  const sys = "You are a search reranker. Given a user query and a numbered list of notes, return the most relevant notes ordered best-first. Respond with ONLY a comma-separated list of the bracket numbers, e.g. 3,1,5. No prose.";
77
92
  const user = `Query: ${query}\n\nNotes:\n${list}\n\nReturn the top ${topK} bracket numbers, best first, comma-separated:`;
@@ -32,6 +32,7 @@ import path from "path";
32
32
  import os from "os";
33
33
  import crypto from "crypto";
34
34
  import { rerank, rerankConfig } from "./rerank.js";
35
+ import { deterministicEnabled } from "./env.js";
35
36
 
36
37
  const ROOT =
37
38
  process.env.JOURNAL_DIR ||
@@ -272,7 +273,7 @@ class DevJournalServer {
272
273
  let ranked = entries.map((e, i) => ({ e, i, sc: score(e) }))
273
274
  .sort((a, b) => b.sc - a.sc || b.i - a.i);
274
275
  let pool = ranked.filter((x) => x.sc > 0).slice(0, 20);
275
- let mode = "keyword";
276
+ let mode = deterministicEnabled() ? "deterministic" : "keyword";
276
277
  if (pool.length === 0 && rerankConfig().enabled) {
277
278
  pool = ranked.slice(0, 20); // fall back to recent for semantic-style queries
278
279
  }
@@ -0,0 +1,46 @@
1
+ # Claude Code Setup
2
+
3
+ Install globally:
4
+
5
+ ```bash
6
+ npm i -g codex-dev-mcp-suite
7
+ ```
8
+
9
+ Add MCP servers using your Claude Code MCP configuration flow. Generic JSON shape:
10
+
11
+ ```json
12
+ {
13
+ "mcpServers": {
14
+ "project-memory": {
15
+ "command": "project-memory-mcp",
16
+ "env": {
17
+ "MEMORY_VAULT_DIR": "~/.local/share/dev-mcp-suite/memories/vault",
18
+ "MCP_LLM_BASE_URL": "http://localhost:11434/v1",
19
+ "MCP_LLM_API_KEY": "",
20
+ "MCP_RERANK_MODEL": "llama3.1:8b",
21
+ "MCP_EMBED_MODEL": "nomic-embed-text"
22
+ }
23
+ },
24
+ "devjournal": {
25
+ "command": "devjournal-mcp",
26
+ "env": {
27
+ "JOURNAL_DIR": "~/.local/share/dev-mcp-suite/memories/journal",
28
+ "MCP_LLM_BASE_URL": "http://localhost:11434/v1",
29
+ "MCP_LLM_API_KEY": "",
30
+ "MCP_RERANK_MODEL": "llama3.1:8b"
31
+ }
32
+ },
33
+ "checkpoint": {
34
+ "command": "checkpoint-mcp",
35
+ "env": {
36
+ "CHECKPOINT_DIR": "~/.local/share/dev-mcp-suite/memories/checkpoints"
37
+ }
38
+ },
39
+ "context-pack": {
40
+ "command": "context-pack-mcp"
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ If you do not configure model env vars, `memory_recall` and `journal_search` still work in offline keyword mode.
@@ -0,0 +1,39 @@
1
+ # Codex CLI Setup
2
+
3
+ Install globally:
4
+
5
+ ```bash
6
+ npm i -g codex-dev-mcp-suite
7
+ ```
8
+
9
+ Add to `~/.codex/config.toml`:
10
+
11
+ ```toml
12
+ [mcp_servers.project-memory]
13
+ command = "project-memory-mcp"
14
+ [mcp_servers.project-memory.env]
15
+ MEMORY_VAULT_DIR = "~/.codex/memories/vault"
16
+ # Optional model features; omit for offline keyword mode.
17
+ MCP_LLM_BASE_URL = "http://localhost:20128"
18
+ MCP_LLM_API_KEY = "sk-..."
19
+ MCP_RERANK_MODEL = "kr/claude-haiku-4.5"
20
+ MCP_EMBED_MODEL = "bm/baai/bge-m3"
21
+
22
+ [mcp_servers.devjournal]
23
+ command = "devjournal-mcp"
24
+ [mcp_servers.devjournal.env]
25
+ JOURNAL_DIR = "~/.codex/memories/journal"
26
+ MCP_LLM_BASE_URL = "http://localhost:20128"
27
+ MCP_LLM_API_KEY = "sk-..."
28
+ MCP_RERANK_MODEL = "kr/claude-haiku-4.5"
29
+
30
+ [mcp_servers.checkpoint]
31
+ command = "checkpoint-mcp"
32
+ [mcp_servers.checkpoint.env]
33
+ CHECKPOINT_DIR = "~/.codex/memories/checkpoints"
34
+
35
+ [mcp_servers.context-pack]
36
+ command = "context-pack-mcp"
37
+ ```
38
+
39
+ Important: the server name is `project-memory` with a hyphen. `project_memory` is not a configured MCP server name in Codex.
@@ -0,0 +1,45 @@
1
+ # Generic MCP Client Setup
2
+
3
+ Any MCP client that can start stdio servers can use Dev MCP Suite.
4
+
5
+ Install globally:
6
+
7
+ ```bash
8
+ npm i -g codex-dev-mcp-suite
9
+ ```
10
+
11
+ Generic server definitions:
12
+
13
+ ```json
14
+ {
15
+ "mcpServers": {
16
+ "project-memory": {
17
+ "command": "project-memory-mcp",
18
+ "args": [],
19
+ "env": {
20
+ "MEMORY_VAULT_DIR": "~/.local/share/dev-mcp-suite/memories/vault"
21
+ }
22
+ },
23
+ "devjournal": {
24
+ "command": "devjournal-mcp",
25
+ "args": [],
26
+ "env": {
27
+ "JOURNAL_DIR": "~/.local/share/dev-mcp-suite/memories/journal"
28
+ }
29
+ },
30
+ "checkpoint": {
31
+ "command": "checkpoint-mcp",
32
+ "args": [],
33
+ "env": {
34
+ "CHECKPOINT_DIR": "~/.local/share/dev-mcp-suite/memories/checkpoints"
35
+ }
36
+ },
37
+ "context-pack": {
38
+ "command": "context-pack-mcp",
39
+ "args": []
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ Optional model configuration can be added to `project-memory` and `devjournal` env blocks. See `docs/configuration.md`.
@@ -0,0 +1,109 @@
1
+ # Configuration
2
+
3
+ Dev MCP Suite is MCP-client agnostic. The servers run locally over stdio and work in any client that can launch MCP servers: Codex CLI, Claude Code, Cursor, Cline, Gemini-compatible launchers, Hermes, and generic MCP hosts.
4
+
5
+ ## Storage
6
+
7
+ All storage is local and file-based.
8
+
9
+ | Env var | Used by | Default |
10
+ |---|---|---|
11
+ | `MEMORY_VAULT_DIR` | `project-memory` | `~/.codex/memories/vault` |
12
+ | `JOURNAL_DIR` | `devjournal` | `~/.codex/memories/journal` |
13
+ | `CHECKPOINT_DIR` | `checkpoint` | `~/.codex/memories/checkpoints` |
14
+
15
+ Use a different base path if your MCP client is not Codex, for example `~/.local/share/dev-mcp-suite/...`.
16
+
17
+ ## Optional model features
18
+
19
+ `context-pack` and `checkpoint` never need a model. `project-memory` and `devjournal` work offline by keyword search and can optionally use an OpenAI-compatible API for better recall.
20
+
21
+ No remote calls are made unless you configure a model endpoint. For strict local-only behavior even when model env vars are present, set `MCP_DETERMINISTIC_FALLBACK=true`.
22
+
23
+ | Env var | Purpose |
24
+ |---|---|
25
+ | `MCP_LLM_BASE_URL` | Base URL for an OpenAI-compatible API, e.g. `http://localhost:11434/v1` or `http://localhost:20128` |
26
+ | `MCP_LLM_API_KEY` | API key for that endpoint; leave blank for local servers that do not require auth |
27
+ | `MCP_RERANK_MODEL` | Chat model for LLM reranking, e.g. `llama3.1:8b`, `kr/claude-haiku-4.5`, `gpt-4o-mini` |
28
+ | `MCP_RERANK_BASE_URL` | Optional rerank-specific base URL; falls back to `MCP_LLM_BASE_URL` |
29
+ | `MCP_RERANK_API_KEY` | Optional rerank-specific API key; falls back to `MCP_LLM_API_KEY` |
30
+ | `RERANK_ENABLED` | Set `0` to disable reranking |
31
+ | `RERANK_TIMEOUT_MS` | Rerank request timeout; default `30000` |
32
+ | `MCP_EMBED_MODEL` | Embedding model for semantic recall, e.g. `nomic-embed-text`, `text-embedding-3-small`, `bm/baai/bge-m3` |
33
+ | `MCP_EMBED_BASE_URL` | Optional embedding-specific base URL; falls back to `MCP_LLM_BASE_URL` |
34
+ | `MCP_EMBED_API_KEY` | Optional embedding-specific API key; falls back to `MCP_LLM_API_KEY` |
35
+ | `EMBED_TIMEOUT_MS` | Embedding request timeout; default `15000` |
36
+ | `MCP_DETERMINISTIC_FALLBACK` | Hard no-network fallback when true; accepts `true`, `1`, `yes`, `on` |
37
+
38
+ Recall mode order:
39
+
40
+ 1. `deterministic` if `MCP_DETERMINISTIC_FALLBACK=true`.
41
+ 2. `semantic` if embeddings are configured and available.
42
+ 3. `rerank` if a chat model is configured and enabled.
43
+ 4. `keyword` offline fallback, always available.
44
+
45
+ Failures degrade gracefully. If your embedding endpoint returns `503`, recall falls back to rerank/keyword instead of failing the tool call.
46
+
47
+ ## Provider strategy
48
+
49
+ The suite is provider-neutral. A practical remote setup is:
50
+
51
+ 1. **Groq** for fast rerank/chat when model quality is sufficient.
52
+ 2. **Cerebras** as a second fast provider for outages or model fit.
53
+ 3. **OpenRouter** as broad fallback for many OpenAI-compatible models.
54
+
55
+ In `v1.1`, chat/rerank can use built-in numbered fallback slots. Configure only primary if you want one provider, or add more numbered chain entries.
56
+
57
+ ```bash
58
+ MCP_PROVIDER_PRIMARY=groq
59
+ MCP_PROVIDER_PRIMARY_BASE_URL=https://api.groq.com/openai/v1
60
+ MCP_PROVIDER_PRIMARY_API_KEY=<groq-key>
61
+ MCP_PROVIDER_PRIMARY_MODEL=llama-3.3-70b-versatile
62
+
63
+ MCP_PROVIDER_CHAIN2=cerebras
64
+ MCP_PROVIDER_CHAIN2_BASE_URL=https://api.cerebras.ai/v1
65
+ MCP_PROVIDER_CHAIN2_API_KEY=<cerebras-key>
66
+ MCP_PROVIDER_CHAIN2_MODEL=llama-3.3-70b
67
+
68
+ MCP_PROVIDER_CHAIN3=openrouter
69
+ MCP_PROVIDER_CHAIN3_BASE_URL=https://openrouter.ai/api/v1
70
+ MCP_PROVIDER_CHAIN3_API_KEY=<openrouter-key>
71
+ MCP_PROVIDER_CHAIN3_MODEL=openai/gpt-4o-mini
72
+ ```
73
+
74
+ You can add `MCP_PROVIDER_CHAIN4_*`, `MCP_PROVIDER_CHAIN5_*`, and so on. The provider name is only a label; any OpenAI-compatible endpoint works when `BASE_URL`, `API_KEY`, and `MODEL` are set.
75
+
76
+ Example OpenRouter-style config:
77
+
78
+ ```bash
79
+ MCP_LLM_BASE_URL=https://openrouter.ai/api/v1
80
+ MCP_LLM_API_KEY=<your-key>
81
+ MCP_RERANK_MODEL=openai/gpt-4o-mini
82
+ ```
83
+
84
+ Example local-only deterministic config:
85
+
86
+ ```bash
87
+ MCP_DETERMINISTIC_FALLBACK=true
88
+ ```
89
+
90
+ See [privacy and data flow](privacy.md) before using remote providers with sensitive projects.
91
+
92
+ ## Legacy aliases
93
+
94
+ These older names still work for backward compatibility:
95
+
96
+ | Legacy | Preferred |
97
+ |---|---|
98
+ | `LLM_BASE_URL` | `MCP_LLM_BASE_URL` |
99
+ | `LLM_API_KEY` | `MCP_LLM_API_KEY` |
100
+ | `NINEROUTER_URL` | `MCP_LLM_BASE_URL` |
101
+ | `NINEROUTER_KEY` | `MCP_LLM_API_KEY` |
102
+ | `EMBED_MODEL` | `MCP_EMBED_MODEL` |
103
+ | `RERANK_MODEL` | `MCP_RERANK_MODEL` |
104
+ | `EMBED_URL` | `MCP_EMBED_BASE_URL` |
105
+ | `EMBED_KEY` | `MCP_EMBED_API_KEY` |
106
+ | `RERANK_URL` | `MCP_RERANK_BASE_URL` |
107
+ | `RERANK_KEY` | `MCP_RERANK_API_KEY` |
108
+
109
+ Prefer the `MCP_*` names for new installs.
@@ -0,0 +1,39 @@
1
+ # Privacy and Data Flow
2
+
3
+ Dev MCP Suite is local-first. It has no hosted backend, no built-in telemetry, and no account system owned by this project.
4
+
5
+ ## What is stored locally
6
+
7
+ | Server | Local data |
8
+ |---|---|
9
+ | `project-memory` | Markdown notes, keyword index, optional embedding vectors if you run `memory_reindex` with embeddings configured |
10
+ | `devjournal` | Session logs, handoff files, timeline entries |
11
+ | `checkpoint` | Text-file snapshots for rollback |
12
+ | `context-pack` | No persistent project data by default |
13
+
14
+ Default storage paths are under `~/.codex/memories/...`; you can override them with `MEMORY_VAULT_DIR`, `JOURNAL_DIR`, and `CHECKPOINT_DIR`.
15
+
16
+ ## What can leave your machine
17
+
18
+ Nothing leaves your machine by default. `project-memory` and `devjournal` use offline keyword scoring unless you configure an external OpenAI-compatible model endpoint.
19
+
20
+ If you set model environment variables such as `MCP_LLM_BASE_URL`, `MCP_EMBED_BASE_URL`, `MCP_RERANK_BASE_URL`, or numbered provider slots like `MCP_PROVIDER_PRIMARY_BASE_URL`, the related query text and candidate snippets may be sent to that endpoint for embeddings or reranking. The endpoint can be local (Ollama, LM Studio, vLLM, LiteLLM) or remote (Groq, Cerebras, OpenRouter, 9Router, OpenAI-compatible gateways).
21
+
22
+ ## Hard no-network mode
23
+
24
+ Set this when you want deterministic local-only recall even if model keys are present:
25
+
26
+ ```bash
27
+ MCP_DETERMINISTIC_FALLBACK=true
28
+ ```
29
+
30
+ Accepted true values: `true`, `1`, `yes`, `on` (case-insensitive). In this mode:
31
+
32
+ - Embeddings are disabled.
33
+ - LLM reranking is disabled.
34
+ - `memory_reindex` skips embedding generation.
35
+ - Results are labeled `[deterministic]`.
36
+
37
+ ## Recommended provider posture
38
+
39
+ For remote providers, use least-privilege API keys and configure them per MCP client environment. Do not commit API keys to this repository or project repos. Prefer local models for sensitive work; use remote providers only for projects where sending snippets to that provider is acceptable.