Skip to content

Commit f7e1b44

Browse files
chore(release): v0.3.3 mcp install helper
1 parent 398e126 commit f7e1b44

6 files changed

Lines changed: 238 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
All notable changes to `state-trace` are documented here. The format roughly follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres to [Semantic Versioning](https://semver.org/) (with the usual pre-1.0 caveat that minor bumps may include breaking changes).
44

5+
## [Unreleased]
6+
7+
## [0.3.3] — 2026-04-25
8+
9+
### Added
10+
11+
- `state-trace-mcp-config` helper command, plus `python -m state_trace.mcp_config`, to generate project-scoped `.mcp.json` with an absolute installed `state-trace-mcp` command path. This makes Codex and other MCP clients more reliable when they launch servers with a minimal PATH.
12+
13+
### Changed
14+
15+
- README MCP install docs now separate official PyPI installs from editable source installs and lead with per-repo Codex `.mcp.json` setup.
16+
- `server.json` package metadata now matches the current `0.3.3` PyPI version.
17+
518
## [0.3.2] — 2026-04-25
619

720
### Fixed
@@ -92,6 +105,9 @@ All 52 tests pass. No public API changes.
92105
- FastAPI surface with `/store`, `/retrieve`, `/retrieve_brief`, `/graph` endpoints.
93106
- Repo-local benchmark suite: held-out live, offline retrieval, Graphiti head-to-head, budgeted harness proxy, live harness replay, long-horizon memory pressure.
94107

108+
[Unreleased]: https://github.com/razroo/state-trace/compare/v0.3.3...HEAD
109+
[0.3.3]: https://github.com/razroo/state-trace/compare/v0.3.2...v0.3.3
110+
[0.3.2]: https://github.com/razroo/state-trace/compare/v0.3.1...v0.3.2
95111
[0.3.1]: https://github.com/razroo/state-trace/compare/v0.3.0...v0.3.1
96112
[0.3.0]: https://github.com/razroo/state-trace/compare/v0.2.1...v0.3.0
97113
[0.2.1]: https://github.com/razroo/state-trace/compare/v0.2.0...v0.2.1

README.md

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,11 @@ They solve adjacent problems. The only reason a comparison is even interesting i
143143
## Installation
144144

145145
```bash
146-
uv sync # or: pip install -e .
147-
pip install -e ".[mcp]" # stdio MCP server for Claude Code / Cursor / Codex CLI
146+
pip install "state-trace" # library
147+
pip install "state-trace[mcp]" # stdio MCP server for Claude Code / Cursor / Codex CLI
148+
149+
uv sync # repo development
150+
pip install -e ".[mcp]" # editable MCP install for local development
148151
pip install -e ".[bench]" # graphiti-core[kuzu] + datasets (for the headline benchmark)
149152
pip install -e ".[llm]" # OpenAI-backed live benchmarks + LLM ingestion
150153
pip install -e ".[adapters]" # LangGraph / LlamaIndex adapter shims
@@ -194,11 +197,22 @@ failures = engine.failed_hypotheses(session="auth-debug")
194197

195198
## MCP Server
196199

200+
Install the official PyPI package:
201+
197202
```bash
198-
pip install -e ".[mcp]"
203+
python3 -m pip install --upgrade "state-trace[mcp]"
199204
state-trace-mcp
200205
```
201206

207+
For project-scoped MCP installs, generate a local `.mcp.json` from the installed package. The generated config uses an absolute `state-trace-mcp` path so clients with a minimal PATH can still start it.
208+
209+
```bash
210+
cd /path/to/your/repo
211+
state-trace-mcp-config --namespace "$(basename "$PWD")" > .mcp.json
212+
# If your shell cannot find the console script:
213+
python3 -m state_trace.mcp_config --namespace "$(basename "$PWD")" > .mcp.json
214+
```
215+
202216
Environment config:
203217

204218
- `STATE_TRACE_STORAGE_PATH` — durable path; `.db`/`.sqlite` uses the SQLite backend. Default: `~/.state-trace/memory.db`.
@@ -207,22 +221,79 @@ Environment config:
207221

208222
Tools exposed: `store`, `retrieve`, `retrieve_brief`, `record_action`, `record_observation`, `record_test_result`, `ingest_agent_log_file`, `current_state`, `failed_hypotheses`, `list_namespaces`, `graph_snapshot`.
209223

210-
Example Claude Code config (`~/.claude/settings.json`):
224+
### OpenAI Codex
225+
226+
Recommended per-repo install:
227+
228+
```bash
229+
python3 -m pip install --upgrade "state-trace[mcp]"
230+
cd /path/to/your/repo
231+
state-trace-mcp-config --namespace "$(basename "$PWD")" > .mcp.json
232+
# If your shell cannot find the console script:
233+
python3 -m state_trace.mcp_config --namespace "$(basename "$PWD")" > .mcp.json
234+
```
235+
236+
Manual project-level `.mcp.json`:
211237

212238
```json
213239
{
214240
"mcpServers": {
215241
"state-trace": {
216-
"command": "state-trace-mcp",
242+
"command": "/absolute/path/to/state-trace-mcp",
217243
"env": {
218-
"STATE_TRACE_STORAGE_PATH": "/Users/me/.state-trace/memory.db",
219-
"STATE_TRACE_NAMESPACE": "repo-x"
244+
"STATE_TRACE_STORAGE_PATH": "/Users/me/.state-trace/repo-x.db",
245+
"STATE_TRACE_NAMESPACE": "repo-x",
246+
"STATE_TRACE_CAPACITY_LIMIT": "256"
220247
}
221248
}
222249
}
223250
}
224251
```
225252

253+
Restart Codex after adding or changing `.mcp.json`.
254+
255+
Codex also supports global MCP config:
256+
257+
```bash
258+
STATE_TRACE_MCP="$(python3 -c 'from state_trace.mcp_config import resolve_entrypoint; print(resolve_entrypoint())')"
259+
codex mcp add state-trace \
260+
--env STATE_TRACE_NAMESPACE=repo-x \
261+
--env STATE_TRACE_STORAGE_PATH=/Users/me/.state-trace/repo-x.db \
262+
-- "$STATE_TRACE_MCP"
263+
```
264+
265+
Use the project `.mcp.json` path when you want state-trace mounted one repo at a time.
266+
267+
### Claude Code
268+
269+
Project-level `.mcp.json` is the same as Codex. For a global install:
270+
271+
```bash
272+
claude mcp add state-trace -- state-trace-mcp
273+
```
274+
275+
To uninstall:
276+
277+
```bash
278+
claude mcp remove state-trace
279+
```
280+
281+
### Cursor
282+
283+
Open Settings → MCP → Add new MCP server, or add the same `mcpServers.state-trace` entry to `.cursor/mcp.json`.
284+
285+
### Other MCP clients
286+
287+
Any MCP client that supports stdio transport can run:
288+
289+
```json
290+
{
291+
"command": "/absolute/path/to/state-trace-mcp"
292+
}
293+
```
294+
295+
Use `python3 -m state_trace.mcp_config` to print a complete config with storage, namespace, and capacity env vars.
296+
226297
## Online agent loop
227298

228299
```python

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "state-trace"
7-
version = "0.3.2"
7+
version = "0.3.3"
88
description = "Graph-native working memory for coding agents with causal retrieval and bounded capacity."
99
readme = "README.md"
1010
requires-python = ">=3.11"
@@ -43,6 +43,7 @@ adapters = ["langchain-core>=0.3.0", "llama-index-core>=0.11.0"]
4343

4444
[project.scripts]
4545
state-trace-mcp = "state_trace.mcp_server:main"
46+
state-trace-mcp-config = "state_trace.mcp_config:main"
4647

4748
[dependency-groups]
4849
dev = [

server.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
"url": "https://github.com/razroo/state-trace",
88
"source": "github"
99
},
10-
"version": "0.3.1",
10+
"version": "0.3.3",
1111
"packages": [
1212
{
1313
"registryType": "pypi",
1414
"identifier": "state-trace",
15-
"version": "0.3.1",
15+
"version": "0.3.3",
1616
"transport": {
1717
"type": "stdio"
1818
},

state_trace/mcp_config.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
"""Generate project-scoped MCP client config for state-trace."""
2+
3+
from __future__ import annotations
4+
5+
import argparse
6+
import json
7+
import os
8+
import shutil
9+
import sysconfig
10+
from pathlib import Path
11+
from typing import Any
12+
13+
14+
def _script_names() -> tuple[str, ...]:
15+
if os.name == "nt":
16+
return ("state-trace-mcp.exe", "state-trace-mcp")
17+
return ("state-trace-mcp",)
18+
19+
20+
def resolve_entrypoint() -> str:
21+
"""Return an absolute path to the installed state-trace-mcp script."""
22+
scripts_dir = sysconfig.get_path("scripts")
23+
if scripts_dir:
24+
for name in _script_names():
25+
candidate = Path(scripts_dir) / name
26+
if candidate.exists():
27+
return str(candidate)
28+
29+
found = shutil.which("state-trace-mcp")
30+
if found:
31+
return found
32+
33+
return "state-trace-mcp"
34+
35+
36+
def build_mcp_config(
37+
*,
38+
name: str = "state-trace",
39+
namespace: str,
40+
storage_path: str,
41+
capacity_limit: float = 256.0,
42+
command: str | None = None,
43+
) -> dict[str, Any]:
44+
capacity = float(capacity_limit)
45+
env: dict[str, str] = {
46+
"STATE_TRACE_STORAGE_PATH": storage_path,
47+
"STATE_TRACE_NAMESPACE": namespace,
48+
"STATE_TRACE_CAPACITY_LIMIT": str(int(capacity) if capacity.is_integer() else capacity),
49+
}
50+
return {
51+
"mcpServers": {
52+
name: {
53+
"command": command or resolve_entrypoint(),
54+
"env": env,
55+
}
56+
}
57+
}
58+
59+
60+
def _default_namespace() -> str:
61+
name = Path.cwd().name.strip()
62+
return name or "state-trace"
63+
64+
65+
def _default_storage(namespace: str) -> str:
66+
return str(Path.home() / ".state-trace" / f"{namespace}.db")
67+
68+
69+
def main() -> None:
70+
parser = argparse.ArgumentParser(
71+
description="Print a project-level .mcp.json config for the installed state-trace MCP server."
72+
)
73+
parser.add_argument("--name", default="state-trace", help="MCP server name in the client config.")
74+
parser.add_argument(
75+
"--namespace",
76+
default=None,
77+
help="state-trace namespace. Defaults to the current directory name.",
78+
)
79+
parser.add_argument(
80+
"--storage-path",
81+
default=None,
82+
help="SQLite/JSON memory path. Defaults to ~/.state-trace/<namespace>.db.",
83+
)
84+
parser.add_argument(
85+
"--capacity-limit",
86+
type=float,
87+
default=256.0,
88+
help="Working-memory budget in capacity units.",
89+
)
90+
parser.add_argument(
91+
"--command",
92+
default=None,
93+
help="Override the state-trace-mcp command path.",
94+
)
95+
args = parser.parse_args()
96+
97+
namespace = args.namespace or _default_namespace()
98+
storage_path = args.storage_path or _default_storage(namespace)
99+
config = build_mcp_config(
100+
name=args.name,
101+
namespace=namespace,
102+
storage_path=storage_path,
103+
capacity_limit=args.capacity_limit,
104+
command=args.command,
105+
)
106+
print(json.dumps(config, indent=2))
107+
108+
109+
if __name__ == "__main__": # pragma: no cover
110+
main()

tests/test_mcp_config.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from __future__ import annotations
2+
3+
from state_trace.mcp_config import build_mcp_config
4+
5+
6+
def test_build_mcp_config_uses_project_namespace_and_absolute_command() -> None:
7+
config = build_mcp_config(
8+
namespace="repo-x",
9+
storage_path="/Users/me/.state-trace/repo-x.db",
10+
command="/opt/bin/state-trace-mcp",
11+
)
12+
13+
server = config["mcpServers"]["state-trace"]
14+
assert server["command"] == "/opt/bin/state-trace-mcp"
15+
assert server["env"] == {
16+
"STATE_TRACE_STORAGE_PATH": "/Users/me/.state-trace/repo-x.db",
17+
"STATE_TRACE_NAMESPACE": "repo-x",
18+
"STATE_TRACE_CAPACITY_LIMIT": "256",
19+
}
20+
21+
22+
def test_build_mcp_config_keeps_fractional_capacity_limit() -> None:
23+
config = build_mcp_config(
24+
namespace="repo-x",
25+
storage_path="/tmp/repo-x.db",
26+
capacity_limit=128.5,
27+
command="state-trace-mcp",
28+
)
29+
30+
assert config["mcpServers"]["state-trace"]["env"]["STATE_TRACE_CAPACITY_LIMIT"] == "128.5"

0 commit comments

Comments
 (0)