r2mcp 0.2.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/CHANGELOG.md +66 -0
- package/LICENSE +21 -0
- package/README.md +532 -0
- package/dist/breadcrumbs.d.ts +123 -0
- package/dist/breadcrumbs.js +135 -0
- package/dist/cli/classify-edges.d.ts +2 -0
- package/dist/cli/classify-edges.js +130 -0
- package/dist/cli/compile-wiki.d.ts +2 -0
- package/dist/cli/compile-wiki.js +173 -0
- package/dist/cli/dump-edges-json.d.ts +2 -0
- package/dist/cli/dump-edges-json.js +21 -0
- package/dist/cli/extract-entities.d.ts +17 -0
- package/dist/cli/extract-entities.js +166 -0
- package/dist/cli/lint-memory.d.ts +16 -0
- package/dist/cli/lint-memory.js +94 -0
- package/dist/cli/migrate.d.ts +17 -0
- package/dist/cli/migrate.js +146 -0
- package/dist/cli/setup-helpers.d.ts +7 -0
- package/dist/cli/setup-helpers.js +72 -0
- package/dist/cli/setup.d.ts +15 -0
- package/dist/cli/setup.js +95 -0
- package/dist/compiler/clustering.d.ts +29 -0
- package/dist/compiler/clustering.js +66 -0
- package/dist/compiler/frontmatter.d.ts +35 -0
- package/dist/compiler/frontmatter.js +168 -0
- package/dist/compiler/manifest.d.ts +32 -0
- package/dist/compiler/manifest.js +82 -0
- package/dist/compiler/prompts.d.ts +17 -0
- package/dist/compiler/prompts.js +82 -0
- package/dist/compiler/run.d.ts +52 -0
- package/dist/compiler/run.js +186 -0
- package/dist/compiler/tier.d.ts +10 -0
- package/dist/compiler/tier.js +85 -0
- package/dist/compiler/topic.d.ts +16 -0
- package/dist/compiler/topic.js +105 -0
- package/dist/compiler/types.d.ts +101 -0
- package/dist/compiler/types.js +4 -0
- package/dist/db.d.ts +10 -0
- package/dist/db.js +46 -0
- package/dist/edges/candidate-pairs.d.ts +24 -0
- package/dist/edges/candidate-pairs.js +35 -0
- package/dist/edges/classifier.d.ts +45 -0
- package/dist/edges/classifier.js +172 -0
- package/dist/edges/signals.d.ts +13 -0
- package/dist/edges/signals.js +45 -0
- package/dist/edges/stage1-haiku.d.ts +21 -0
- package/dist/edges/stage1-haiku.js +33 -0
- package/dist/edges/stage2-opus.d.ts +41 -0
- package/dist/edges/stage2-opus.js +101 -0
- package/dist/edges/state.d.ts +44 -0
- package/dist/edges/state.js +79 -0
- package/dist/edges/types.d.ts +20 -0
- package/dist/edges/types.js +1 -0
- package/dist/embeddings.d.ts +13 -0
- package/dist/embeddings.js +54 -0
- package/dist/entities/db.d.ts +49 -0
- package/dist/entities/db.js +109 -0
- package/dist/entities/extractor.d.ts +14 -0
- package/dist/entities/extractor.js +154 -0
- package/dist/entities/normalize.d.ts +5 -0
- package/dist/entities/normalize.js +7 -0
- package/dist/entities/prompt.d.ts +19 -0
- package/dist/entities/prompt.js +100 -0
- package/dist/entities/state.d.ts +44 -0
- package/dist/entities/state.js +99 -0
- package/dist/entities/types.d.ts +62 -0
- package/dist/entities/types.js +6 -0
- package/dist/env.d.ts +13 -0
- package/dist/env.js +32 -0
- package/dist/fingerprint.d.ts +2 -0
- package/dist/fingerprint.js +12 -0
- package/dist/graph-rebuild.d.ts +6 -0
- package/dist/graph-rebuild.js +20 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +403 -0
- package/dist/instrumentation.d.ts +10 -0
- package/dist/instrumentation.js +37 -0
- package/dist/lint/checks/contradictions.d.ts +30 -0
- package/dist/lint/checks/contradictions.js +52 -0
- package/dist/lint/checks/drift.d.ts +5 -0
- package/dist/lint/checks/drift.js +34 -0
- package/dist/lint/checks/orphans.d.ts +5 -0
- package/dist/lint/checks/orphans.js +25 -0
- package/dist/lint/checks/stale.d.ts +6 -0
- package/dist/lint/checks/stale.js +29 -0
- package/dist/lint/checks/superseded-unflagged.d.ts +5 -0
- package/dist/lint/checks/superseded-unflagged.js +47 -0
- package/dist/lint/run.d.ts +11 -0
- package/dist/lint/run.js +95 -0
- package/dist/lint/types.d.ts +60 -0
- package/dist/lint/types.js +13 -0
- package/dist/mcp-response.d.ts +7 -0
- package/dist/mcp-response.js +13 -0
- package/dist/providers/anthropic.d.ts +13 -0
- package/dist/providers/anthropic.js +56 -0
- package/dist/providers/claude-code.d.ts +35 -0
- package/dist/providers/claude-code.js +175 -0
- package/dist/providers/errors.d.ts +12 -0
- package/dist/providers/errors.js +19 -0
- package/dist/providers/index.d.ts +30 -0
- package/dist/providers/index.js +71 -0
- package/dist/providers/openrouter.d.ts +19 -0
- package/dist/providers/openrouter.js +76 -0
- package/dist/providers/semaphore.d.ts +19 -0
- package/dist/providers/semaphore.js +51 -0
- package/dist/providers/types.d.ts +27 -0
- package/dist/providers/types.js +7 -0
- package/dist/schema.sql +116 -0
- package/dist/server-instructions.d.ts +9 -0
- package/dist/server-instructions.js +20 -0
- package/dist/telemetry.d.ts +39 -0
- package/dist/telemetry.js +130 -0
- package/dist/tools/classify.d.ts +44 -0
- package/dist/tools/classify.js +121 -0
- package/dist/tools/compile.d.ts +31 -0
- package/dist/tools/compile.js +132 -0
- package/dist/tools/dump-edges-sidecar.d.ts +37 -0
- package/dist/tools/dump-edges-sidecar.js +80 -0
- package/dist/tools/extract-entities.d.ts +53 -0
- package/dist/tools/extract-entities.js +169 -0
- package/dist/tools/lint.d.ts +10 -0
- package/dist/tools/lint.js +13 -0
- package/dist/tools/meditate.d.ts +25 -0
- package/dist/tools/meditate.js +128 -0
- package/dist/tools/recall.d.ts +66 -0
- package/dist/tools/recall.js +409 -0
- package/dist/tools/reject.d.ts +10 -0
- package/dist/tools/reject.js +24 -0
- package/dist/tools/remember.d.ts +26 -0
- package/dist/tools/remember.js +140 -0
- package/dist/tools/search.d.ts +30 -0
- package/dist/tools/search.js +69 -0
- package/dist/tools/spawn-cli.d.ts +14 -0
- package/dist/tools/spawn-cli.js +41 -0
- package/dist/tools/stats.d.ts +31 -0
- package/dist/tools/stats.js +88 -0
- package/package.json +86 -0
- package/skills/remember/SKILL.md +357 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to r2mcp. Versions follow [semver](https://semver.org/);
|
|
4
|
+
entries reference the internal spec numbers that shipped them.
|
|
5
|
+
|
|
6
|
+
## [0.2.0] — 2026-06-13
|
|
7
|
+
|
|
8
|
+
First release packaged for use beyond the original workspace.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **npm bins**: `r2mcp` (the MCP server) and `r2mcp-setup` (schema provisioner) —
|
|
13
|
+
`.mcp.json` can now use `npx -y r2mcp` instead of an absolute dist path.
|
|
14
|
+
- **MCP server instructions** sent in the initialize response — a fresh project's
|
|
15
|
+
agent learns the recall-at-start / remember-as-you-go loop with zero setup.
|
|
16
|
+
- **`warnings[]` on `remember`/`recall`** when embeddings are unavailable,
|
|
17
|
+
distinguishing *disabled* (no `R2MCP_OPENROUTER_API_KEY`) from *failed*.
|
|
18
|
+
- **Fail-fast configuration**: the server and `npm run setup` refuse to start
|
|
19
|
+
without `R2MCP_DATABASE_URL` (previously defaulted silently to localhost);
|
|
20
|
+
startup logs a warning when embeddings are off.
|
|
21
|
+
- **`extract_entities` tool + entity-scoped `recall`** (SPEC-046): light entity
|
|
22
|
+
extraction (project/person/tool/decision) with alias merging and cost caps.
|
|
23
|
+
- **`next_tools[]` breadcrumbs** on every tool response (SPEC-047): context-aware
|
|
24
|
+
follow-up suggestions, capped at 3.
|
|
25
|
+
- **MCP-only operation** (SPEC-045): `classify` and `dump_edges_sidecar` promoted
|
|
26
|
+
to MCP tools; subprocess spawning centralized via `resolveCliCommand`;
|
|
27
|
+
`R2MCP_CLAUDE_BIN` escape hatch for sanitized-PATH hosts (now documented, and
|
|
28
|
+
named in ENOENT spawn errors).
|
|
29
|
+
- **MIT LICENSE**, engines field, repository metadata, this changelog.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- **Single-rootDir build**: CLI drivers moved from `scripts/` to `src/cli/`;
|
|
34
|
+
the dual compile tree (`dist/` + `dist/src/`, 43 duplicate files) is gone and
|
|
35
|
+
`schema.sql` is copied once. `npm run` script names are unchanged.
|
|
36
|
+
- **README onboarding overhaul**: Supabase **Session pooler** is the recommended
|
|
37
|
+
connection (the Direct connection is IPv6-only without a paid add-on; setup
|
|
38
|
+
classifies `ENETUNREACH` accordingly); `.mcp.json` examples use `${VAR}`
|
|
39
|
+
expansion with a secret-hygiene warning; the bundled `/remember` skill install
|
|
40
|
+
corrected to `.claude/skills/`; new Configuration table and Troubleshooting
|
|
41
|
+
section.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- **`.env` loader regex could not match any `R2MCP_*` key** (the digit excluded
|
|
46
|
+
by `[A-Z_]+`) — every documented fresh-clone setup silently fell back to
|
|
47
|
+
localhost. All five hand-rolled loaders replaced by a shared `loadEnvFile()`.
|
|
48
|
+
- CLI drivers load `.env` only on their CLI entry path, never at module import
|
|
49
|
+
(a module-level load leaked the consumer's DB URL into test processes).
|
|
50
|
+
- `lint:memory` previously loaded no environment at all.
|
|
51
|
+
|
|
52
|
+
## [0.1.0] — 2026-05-09
|
|
53
|
+
|
|
54
|
+
Initial extraction from the ClaudeClaw workspace (SPEC-041 through SPEC-044).
|
|
55
|
+
|
|
56
|
+
- 9 MCP tools: `remember`, `recall`, `search`, `meditate`, `reject`, `stats`,
|
|
57
|
+
`compile`, `lint`, `classify` over PostgreSQL + pgvector (Docker or Supabase
|
|
58
|
+
free tier).
|
|
59
|
+
- 3-tier memory (preferences / project-context / conversations) with semantic +
|
|
60
|
+
full-text hybrid retrieval, MMR diversity, progressive tier search,
|
|
61
|
+
token-budget retrieval (Recall v2).
|
|
62
|
+
- Typed memory edges (SPEC-043) surfaced as `signals[]` on recall.
|
|
63
|
+
- Wiki mode (SPEC-044): regenerable compiled views, SQL-only lint
|
|
64
|
+
(contradictions / stale / orphans / drift / superseded_unflagged).
|
|
65
|
+
- Multi-provider LLM layer: claude-code (Max plan, $0/call), Anthropic API,
|
|
66
|
+
OpenRouter — batch jobs only; the MCP server itself never makes LLM calls.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dustin Cheng
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
# r2mcp — Persistent Memory for Claude Code
|
|
2
|
+
|
|
3
|
+
Persistent, semantic, tiered memory layer for Claude Code sessions.
|
|
4
|
+
|
|
5
|
+
**The problem:** Every Claude Code session starts fresh. Context is lost. You repeat yourself.
|
|
6
|
+
|
|
7
|
+
**The fix:** r2mcp gives Claude a structured, searchable memory that survives session boundaries — stored in PostgreSQL with pgvector semantic search.
|
|
8
|
+
|
|
9
|
+
## What you get
|
|
10
|
+
|
|
11
|
+
- **11 MCP tools:** `remember`, `recall`, `search`, `meditate`, `reject`, `stats`, `compile`, `lint`, `classify`, `dump_edges_sidecar`, `extract_entities`
|
|
12
|
+
- **3-tier memory:** `preferences` (decisions, style) → `project-context` (architecture, state) → `conversations` (relationship, history)
|
|
13
|
+
- **Semantic search:** Progressive tier search with MMR diversity reranking and relevance floor filtering (Recall v2)
|
|
14
|
+
- **Typed memory edges:** `contradicts`, `supersedes`, `supports`, `evolved_into`, `depends_on`, `related_to` — surfaced as signals on `recall()`
|
|
15
|
+
- **Wiki compile:** Regenerable browsable views — `compile()` synthesizes `memory/compiled/` from pgvector
|
|
16
|
+
- **Lint as a first-class op:** SQL-only structural feedback — contradictions, stale, orphans, drift, superseded_unflagged
|
|
17
|
+
- **Multi-provider LLM layer:** Classifier and compile work on a Max plan ($0/call), Anthropic API, or OpenRouter — picked per-invocation
|
|
18
|
+
- **Bundled `/remember` skill:** Client-side judgment pipeline — classify → conflict-check → store
|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
**Prerequisites:** Node.js 20+. An OpenRouter API key is strongly recommended — it powers semantic-search embeddings. Without one, r2mcp still works but degrades to full-text search (and tells you so via a startup warning and `warnings[]` on tool responses). Docker is optional (Option B only).
|
|
23
|
+
|
|
24
|
+
r2mcp works with any PostgreSQL + pgvector backend. The fastest path is Supabase (free tier, no Docker required).
|
|
25
|
+
|
|
26
|
+
### Option A: Supabase (no Docker required)
|
|
27
|
+
|
|
28
|
+
#### 1. Create a Supabase project
|
|
29
|
+
|
|
30
|
+
Create a free project at [supabase.com](https://supabase.com). Once created, click **Connect** (top of the dashboard) and copy the **Session pooler** connection string — port `5432`, host like `aws-0-<region>.pooler.supabase.com`, username `postgres.<project-ref>`.
|
|
31
|
+
|
|
32
|
+
> **Why the Session pooler?** The Direct connection (`db.<ref>.supabase.co:5432`) resolves to an IPv6 address, and IPv4 for direct connections is a paid add-on — on an IPv4-only network it fails with `connect ENETUNREACH`. The Session pooler is IPv4-compatible on every tier and fully supports schema setup. (Do **not** use the Transaction pooler on port `6543` — it can't run DDL; setup will refuse it.) If your network has IPv6, the Direct connection works too.
|
|
33
|
+
|
|
34
|
+
#### 2. Clone and configure
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git clone https://github.com/DMokong/r2mcp.git && cd r2mcp && npm install
|
|
38
|
+
cp .env.example .env
|
|
39
|
+
# Set R2MCP_DATABASE_URL to your Session pooler URL (port 5432, not 6543)
|
|
40
|
+
# Set R2MCP_OPENROUTER_API_KEY to your OpenRouter key (enables semantic search)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
#### 3. Provision schema and build
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm run setup && npm run build
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This creates the `memories` table, pgvector indexes, and full-text search index. **Safe to re-run.**
|
|
50
|
+
|
|
51
|
+
#### 4. Register in Claude Code
|
|
52
|
+
|
|
53
|
+
Add to your project's `.mcp.json`. Use `${VAR}` expansion so credentials stay in your environment instead of the file — **`.mcp.json` is typically committed, so never paste real credentials into it**:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
58
|
+
"memory": {
|
|
59
|
+
"command": "node",
|
|
60
|
+
"args": ["/path/to/r2mcp/dist/index.js"],
|
|
61
|
+
"env": {
|
|
62
|
+
"R2MCP_DATABASE_URL": "${R2MCP_DATABASE_URL}",
|
|
63
|
+
"R2MCP_OPENROUTER_API_KEY": "${R2MCP_OPENROUTER_API_KEY}"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Claude Code expands `${VAR}` (and `${VAR:-default}`) from your environment at launch. Inline literal values are fine only for throwaway local experiments — if you go that route, gitignore `.mcp.json` and treat any committed credential as compromised.
|
|
71
|
+
|
|
72
|
+
Restart Claude Code, then see [After setup](#after-setup-both-options).
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### Option B: Docker (local dev)
|
|
77
|
+
|
|
78
|
+
For local development or air-gapped environments.
|
|
79
|
+
|
|
80
|
+
#### 1. Clone
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
git clone https://github.com/DMokong/r2mcp.git
|
|
84
|
+
cd r2mcp
|
|
85
|
+
npm install
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### 2. Configure
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
cp .env.example .env
|
|
92
|
+
# Edit .env — set R2MCP_DATABASE_URL and R2MCP_OPENROUTER_API_KEY
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### 3. Start Postgres
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
docker compose up -d
|
|
99
|
+
# Wait ~10s for healthy status
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### 4. Provision schema
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npm run setup
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
This creates the `memories` table, pgvector indexes, and full-text search index. **Safe to re-run.**
|
|
109
|
+
|
|
110
|
+
#### 5. Build
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npm run build
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### 6. Register in Claude Code
|
|
117
|
+
|
|
118
|
+
Add to your project's `.mcp.json`:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"mcpServers": {
|
|
123
|
+
"memory": {
|
|
124
|
+
"command": "node",
|
|
125
|
+
"args": ["/path/to/r2mcp/dist/index.js"],
|
|
126
|
+
"env": {
|
|
127
|
+
"R2MCP_DATABASE_URL": "postgresql://r2mcp:r2mcp@localhost:5432/r2mcp",
|
|
128
|
+
"R2MCP_OPENROUTER_API_KEY": "${R2MCP_OPENROUTER_API_KEY}"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
(The local Docker DB URL contains no real secret; the OpenRouter key does — keep it in your environment via `${VAR}` expansion.)
|
|
136
|
+
|
|
137
|
+
Restart Claude Code, then see [After setup](#after-setup-both-options).
|
|
138
|
+
|
|
139
|
+
## After setup (both options)
|
|
140
|
+
|
|
141
|
+
You now have `mcp__memory__remember`, `mcp__memory__recall`, etc. available. Two optional steps make memory actually get used:
|
|
142
|
+
|
|
143
|
+
### Install the /remember skill (recommended)
|
|
144
|
+
|
|
145
|
+
The bundled skill gives Claude a judgment pipeline for memory writes — classify → conflict-check → store. Copy it into your **consuming project** (the one whose `.mcp.json` registers r2mcp):
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
mkdir -p .claude/skills && cp -r /path/to/r2mcp/skills/remember .claude/skills/
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Claude Code auto-discovers project skills from `.claude/skills/<name>/SKILL.md`. (For all your projects at once, use `~/.claude/skills/` instead.) Then `/remember <note>` persists memories through the full pipeline.
|
|
152
|
+
|
|
153
|
+
### Teach your agent the session loop (recommended)
|
|
154
|
+
|
|
155
|
+
r2mcp ships MCP server instructions that Claude Code loads automatically, so the agent knows the basics. For stronger habits, add a short protocol to your project's `CLAUDE.md`:
|
|
156
|
+
|
|
157
|
+
```markdown
|
|
158
|
+
## Memory
|
|
159
|
+
|
|
160
|
+
This project has persistent memory via the `memory` MCP server.
|
|
161
|
+
- At session start, `recall` context relevant to the task at hand.
|
|
162
|
+
- When a durable decision, preference, or correction surfaces, `remember` it
|
|
163
|
+
(tier: preferences = decisions/style, project-context = architecture/state,
|
|
164
|
+
conversations = session continuity).
|
|
165
|
+
- Run `/remember` before ending a work session to persist anything unsaved.
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**First session on an empty database:** `recall` returning zero results is expected — start `remember`-ing as decisions come up and recall pays off within a session or two.
|
|
169
|
+
|
|
170
|
+
## Configuration
|
|
171
|
+
|
|
172
|
+
r2mcp reads its configuration from the MCP transport's environment — for
|
|
173
|
+
consumers, **the `.mcp.json` `env` block is the primary config surface**
|
|
174
|
+
(use `${VAR}` expansion for secrets):
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"mcpServers": {
|
|
179
|
+
"memory": {
|
|
180
|
+
"command": "node",
|
|
181
|
+
"args": ["./node_modules/r2mcp/dist/index.js"],
|
|
182
|
+
"env": {
|
|
183
|
+
"R2MCP_DATABASE_URL": "${R2MCP_DATABASE_URL}",
|
|
184
|
+
"R2MCP_OPENROUTER_API_KEY": "${R2MCP_OPENROUTER_API_KEY}",
|
|
185
|
+
"R2MCP_CLASSIFIER_PROVIDER": "claude-code",
|
|
186
|
+
"R2MCP_EDGE_MAX_USD": "1.00",
|
|
187
|
+
"R2MCP_COMPILE_MAX_USD": "1.00"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
| Variable | Required | What it does |
|
|
195
|
+
|----------|----------|--------------|
|
|
196
|
+
| `R2MCP_DATABASE_URL` | **Yes** | PostgreSQL + pgvector connection string. The server **fails fast at startup** if unset — it never guesses a database. |
|
|
197
|
+
| `R2MCP_OPENROUTER_API_KEY` | Recommended | Enables semantic-search embeddings. When unset, the server logs a startup warning and `remember`/`recall` responses carry a `warnings[]` field — everything still works full-text. |
|
|
198
|
+
| `R2MCP_CLAUDE_BIN` | Sometimes | Absolute path to the `claude` binary for the $0 Max-plan provider. Needed when the spawning process's PATH doesn't include it — common under launchd jobs and some MCP hosts (e.g. `~/.local/bin/claude`). The spawn error names this variable when it's the fix. |
|
|
199
|
+
| `ANTHROPIC_API_KEY` | Optional | Only for `--provider=anthropic` on classifier/compile runs. |
|
|
200
|
+
| `R2MCP_CLASSIFIER_PROVIDER` | Optional | Pin a provider (`claude-code` \| `anthropic` \| `openrouter`) instead of auto-fallback. |
|
|
201
|
+
| `R2MCP_EDGE_MAX_USD` / `R2MCP_COMPILE_MAX_USD` / `R2MCP_ENTITY_MAX_USD` | Optional | Cost caps for the batch jobs (defaults `$1.00`). |
|
|
202
|
+
|
|
203
|
+
The server also loads a `.env` file from its working directory at startup
|
|
204
|
+
(non-clobbering — real environment variables always win). A `.env` at the
|
|
205
|
+
r2mcp source root is the normal path for `npm run` scripts when working from
|
|
206
|
+
a checkout; consumers configuring via `.mcp.json env` don't need one.
|
|
207
|
+
|
|
208
|
+
## Troubleshooting
|
|
209
|
+
|
|
210
|
+
| Symptom | Cause & fix |
|
|
211
|
+
|---------|-------------|
|
|
212
|
+
| `connect ENETUNREACH 2406:...` during setup | Supabase Direct connection is IPv6-only (IPv4 is a paid add-on) and your network is IPv4-only. Use the **Session pooler** string instead: Dashboard → Connect → Session pooler (port 5432). Setup classifies this error and says the same. |
|
|
213
|
+
| `Transaction-pooler URL detected (port 6543)` | The transaction pooler can't run DDL or prepared statements. Use the Session pooler (port 5432). |
|
|
214
|
+
| `R2MCP_DATABASE_URL is not set` | Deliberate fail-fast — set it in `.mcp.json env` or `.env`. The error lists both surfaces and the Docker default URL. |
|
|
215
|
+
| `embeddings disabled` warning at startup or in `warnings[]` | `R2MCP_OPENROUTER_API_KEY` is unset (or the embed call failed — the message distinguishes the two). Full-text search still works; set the key to enable semantic search. |
|
|
216
|
+
| `could not spawn 'claude' (ENOENT)` on classifier/compile runs | The claude CLI isn't on the spawning process's PATH. Set `R2MCP_CLAUDE_BIN` to its absolute path. |
|
|
217
|
+
| Fresh credentials rejected right after a Supabase password reset | The pooler caches auth-rejection state for 30–60s. Wait a minute and retry before assuming the rotation failed. |
|
|
218
|
+
|
|
219
|
+
## Memory Tiers
|
|
220
|
+
|
|
221
|
+
| Tier | What goes here | Auto-archived after |
|
|
222
|
+
|------|---------------|---------------------|
|
|
223
|
+
| `preferences` | Decisions, coding style, tool choices | Never |
|
|
224
|
+
| `project-context` | Architecture, system state, what's built | 180 days |
|
|
225
|
+
| `conversations` | Relationship continuity, session history | 90 days |
|
|
226
|
+
|
|
227
|
+
## Tools Reference
|
|
228
|
+
|
|
229
|
+
| Tool | Description |
|
|
230
|
+
|------|-------------|
|
|
231
|
+
| `remember` | Store/update/archive a memory with tier + metadata |
|
|
232
|
+
| `recall` | Semantic + full-text search with progressive tier search; emits `signals[]` from typed edges |
|
|
233
|
+
| `search` | Filter by type, tier, topics, date range |
|
|
234
|
+
| `meditate` | Archive stale entries, find duplicates; pass `include_lint: true` to fold lint findings in |
|
|
235
|
+
| `reject` | Mark a memory as rejected (excluded from future recall) |
|
|
236
|
+
| `stats` | Health check — counts, staleness, embedding status |
|
|
237
|
+
| `compile` | Regenerate browsable wiki views under `memory/compiled/` (SPEC-044, see below) |
|
|
238
|
+
| `classify` | Classify candidate memory pairs into typed edges (supports, contradicts, supersedes, evolved_into, depends_on, related_to). Subprocess-spawned (SPEC-044 invariant). |
|
|
239
|
+
| `dump_edges_sidecar` | In-process JSON dump of memory_edges + memories to a caller-supplied directory. Used by downstream consumers like Memory Explorer. |
|
|
240
|
+
| `lint` | Surface structural feedback: contradictions, stale, orphans, drift, superseded_unflagged (SPEC-044, see below) |
|
|
241
|
+
| `extract_entities` | Extract structured entities (project / person / tool / decision) from memories. Spawns the entity extractor driver via the shared `resolveCliCommand` helper. Inherits cost cap (`R2MCP_ENTITY_MAX_USD`, default $1.00) and resumability from SPEC-043. Top-N known entities (`R2MCP_ENTITY_CONTEXT_TOP_N`, default 100) seed the LLM context. (SPEC-046, see below) |
|
|
242
|
+
| `recall` (extended) | Accepts an optional `entity` parameter that narrows results to memories linked to a named entity (matched by canonical name or any alias). When `entity` is set, `query` is optional. Response gains `entity_resolved: boolean`, optional `entity_id`, and per-result `entity_links[]`. (SPEC-046) |
|
|
243
|
+
|
|
244
|
+
## Recall v2 — semantic + budget-aware retrieval
|
|
245
|
+
|
|
246
|
+
`recall()` is the workhorse retrieval tool. v2 (xMemory-inspired, 2026-04) layers four retrieval shapes on top of the underlying hybrid semantic + full-text search:
|
|
247
|
+
|
|
248
|
+
### 1. Relevance floor — `min_score`
|
|
249
|
+
|
|
250
|
+
Filter out low-quality matches before they're returned. Without this, semantic search dumps a long tail of weakly-related results.
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
recall({ query: "edge classifier cost cap", min_score: 0.3 })
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Suggested defaults: `0.3` for semantic queries, `0.1` for keyword-driven ones.
|
|
257
|
+
|
|
258
|
+
### 2. MMR diversity — `diversity` (lambda 0.0–1.0)
|
|
259
|
+
|
|
260
|
+
Maximal Marginal Relevance reranks results to balance relevance against redundancy. `1.0` is pure relevance (may return three near-duplicates of the top hit); `0.0` is pure diversity (spreads coverage); the default `0.7` favors relevance with mild diversification.
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
recall({ query: "memory architecture", diversity: 0.5, top_k: 8 })
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Use lower values when you want broad coverage of a topic, higher when you want the single best answer plus close runners-up.
|
|
267
|
+
|
|
268
|
+
### 3. Context budget — `max_tokens`
|
|
269
|
+
|
|
270
|
+
Token-budget retrieval: walks MMR-reranked results in score order and stops when adding the next result would exceed the budget. Returns `tokens_used` in the response so you know how much you actually pulled.
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
recall({ query: "what we learned about classifiers", max_tokens: 4000 })
|
|
274
|
+
// → up to N results, summing to ≤4000 tokens, prioritized by relevance × diversity
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
This is the right call when you're stuffing recall results into a downstream prompt and have a hard context limit. `top_k` is ignored when `max_tokens` is set — the budget decides the cut.
|
|
278
|
+
|
|
279
|
+
### 4. Progressive tier search — `progressive` + `confidence_threshold`
|
|
280
|
+
|
|
281
|
+
Top-down retrieval through the tier hierarchy (`preferences` → `project-context` → `conversations`). High-confidence matches in `preferences` short-circuit the search before lower tiers are consulted, mimicking the xMemory observation that decisions/preferences usually answer questions before context/history needs to.
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
recall({ query: "do we use bun or npm", progressive: true, confidence_threshold: 0.82 })
|
|
285
|
+
// → returns immediately if a preferences-tier match scores ≥0.82, else widens to project-context, then conversations
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Default behavior — turn off with `progressive: false` to force a full sweep across tiers, or pin a single tier with `tier: 'preferences'`.
|
|
289
|
+
|
|
290
|
+
### Composing them
|
|
291
|
+
|
|
292
|
+
The four parameters compose:
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
recall({
|
|
296
|
+
query: "spec-bench cleanup conventions",
|
|
297
|
+
min_score: 0.3, // drop weak matches
|
|
298
|
+
diversity: 0.6, // some diversification
|
|
299
|
+
max_tokens: 3000, // fit in context
|
|
300
|
+
progressive: true, // early-stop on prefs hits
|
|
301
|
+
confidence_threshold: 0.82,
|
|
302
|
+
})
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Plus `signals[]` on the response surfaces typed memory edges (`contradicts`, `superseded_by`) on the returned memories so callers can flag conflicts inline.
|
|
306
|
+
|
|
307
|
+
## Cross-Project Memory
|
|
308
|
+
|
|
309
|
+
All projects pointing at the same `R2MCP_DATABASE_URL` share a single memory pool. This is intentional — your knowledge travels with you. Namespace isolation is a v2 roadmap item.
|
|
310
|
+
|
|
311
|
+
## OpenTelemetry (optional)
|
|
312
|
+
|
|
313
|
+
Enable OTel tracing and metrics:
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
OTEL_ENABLED=true
|
|
317
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Metrics use the `r2mcp.memory.*` namespace.
|
|
321
|
+
|
|
322
|
+
## Prior Art & Acknowledgements
|
|
323
|
+
|
|
324
|
+
r2mcp stands on the shoulders of two projects:
|
|
325
|
+
|
|
326
|
+
**[Open Brain](https://github.com/NateBJones-Projects/OB1) by [Nate B. Jones](https://natesnewsletter.substack.com/)**
|
|
327
|
+
The core architectural insight — "one database, any AI plugs in" — comes from Open Brain. The idea that your knowledge layer should be sovereign and portable (not locked inside a specific tool) is the founding premise of r2mcp. Open Brain proved the PostgreSQL + pgvector substrate works for personal AI memory at minimal cost ($0.10–0.30/month). r2mcp narrows the scope to Claude Code's MCP protocol and adds a more opinionated retrieval layer on top of that foundation.
|
|
328
|
+
|
|
329
|
+
**[xMemory](https://arxiv.org/abs/2602.02007) — "Beyond RAG for Agent Memory: Retrieval by Decoupling and Aggregation"**
|
|
330
|
+
Hu et al. (2026) established the hierarchical tier approach and showed that progressive top-down retrieval with coverage maximization + redundancy minimization cuts token usage ~50% vs. flat RAG while improving accuracy. r2mcp's 3-tier memory (preferences → project-context → conversations) is a hand-crafted simplification of their 4-level hierarchy (messages → episodes → semantics → themes). The MMR diversity reranking in `recall()` directly implements their redundancy minimization insight.
|
|
331
|
+
|
|
332
|
+
## Migrating from ClaudeClaw
|
|
333
|
+
|
|
334
|
+
If you're moving from the ClaudeClaw-internal `memory-mcp-server`:
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
R2MCP_DATABASE_URL=<your-new-url> npx tsx src/cli/migrate.ts /path/to/your/memory/
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
The migration script reads `preferences.md`, `project-context.md`, and `conversations.md` from the specified directory and imports them. It's idempotent — safe to re-run.
|
|
341
|
+
|
|
342
|
+
## Memory edges (SPEC-043)
|
|
343
|
+
|
|
344
|
+
r2mcp supports a typed-relation table (`memory_edges`) that captures structural
|
|
345
|
+
relations between memories — `contradicts`, `supersedes`, `supports`,
|
|
346
|
+
`evolved_into`, `depends_on`, `related_to`. The `recall()` MCP tool surfaces
|
|
347
|
+
`contradicts` / `superseded_by` relations as an optional `signals[]` field on
|
|
348
|
+
the response (additive — existing clients work unchanged).
|
|
349
|
+
|
|
350
|
+
### Running the classifier
|
|
351
|
+
|
|
352
|
+
The classifier is a manual batch process — it is NOT invoked from the MCP server
|
|
353
|
+
hot path. Provider selection follows the SPEC-044 precedence (see below); on a
|
|
354
|
+
Max plan, no API key is required.
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
# Estimate cost without making API calls or writing edges
|
|
358
|
+
npm run edges:classify -- --dry-run
|
|
359
|
+
|
|
360
|
+
# Auto-fallback: prefers claude-code (Max plan, $0/call)
|
|
361
|
+
npm run edges:classify -- --max-cost=1.00
|
|
362
|
+
|
|
363
|
+
# Force a specific provider
|
|
364
|
+
npm run edges:classify -- --provider=anthropic --max-cost=1.00
|
|
365
|
+
npm run edges:classify -- --provider=openrouter --max-cost=1.00
|
|
366
|
+
|
|
367
|
+
# Incremental run on memories from the last 7 days
|
|
368
|
+
npm run edges:classify -- --since=7d --max-cost=0.25
|
|
369
|
+
|
|
370
|
+
# Resume a prior run that hit its cap (the run_id is printed at exit and stored in
|
|
371
|
+
# data/edges-state.last-run)
|
|
372
|
+
npm run edges:classify -- --resume=<run_id>
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
State and run summaries are written under `data/edges-state.*` (JSONL append-log,
|
|
376
|
+
last-run sidecar, per-run JSON summary at `data/edges-state.runs/<run_id>.json`).
|
|
377
|
+
|
|
378
|
+
## LLM provider abstraction (SPEC-044)
|
|
379
|
+
|
|
380
|
+
The classifier and wiki compiler share a small `LLMProvider` abstraction with
|
|
381
|
+
three adapters. Providers run from standalone Node processes only — the MCP
|
|
382
|
+
server itself never makes LLM calls.
|
|
383
|
+
|
|
384
|
+
| Adapter | Auth | Cost per call | Concurrency cap |
|
|
385
|
+
|---------|------|---------------|------------------|
|
|
386
|
+
| `claude-code` | Claude Code OAuth (Max plan) | **$0** (strict equality) | 2 (subprocess overhead) |
|
|
387
|
+
| `anthropic` | `ANTHROPIC_API_KEY` | Per-token (list price) | 10 |
|
|
388
|
+
| `openrouter` | `R2MCP_OPENROUTER_API_KEY` | Per-token (list price) | 10 |
|
|
389
|
+
|
|
390
|
+
### Selection precedence
|
|
391
|
+
|
|
392
|
+
1. `--provider=<name>` CLI flag — highest priority
|
|
393
|
+
2. `R2MCP_CLASSIFIER_PROVIDER` environment variable
|
|
394
|
+
3. Auto-fallback: `claude-code` if logged in → `anthropic` if API key set →
|
|
395
|
+
`openrouter` if API key set → fatal error naming all three remediation paths
|
|
396
|
+
|
|
397
|
+
The fallback prefers `claude-code` so a Max-plan user pays nothing by default.
|
|
398
|
+
|
|
399
|
+
OpenRouter's primary role remains text→vector embeddings. Its classifier /
|
|
400
|
+
compile use is opt-in per invocation, never auto-routed for embeddings.
|
|
401
|
+
|
|
402
|
+
## Wiki compile (SPEC-044)
|
|
403
|
+
|
|
404
|
+
`compile()` regenerates browsable markdown views of the memory store from
|
|
405
|
+
pgvector. Output goes to `memory/compiled/` (gitignored, regenerable).
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
# Compile all three tier files (preferences.md, project-context.md, conversations.md)
|
|
409
|
+
npm run compile-wiki -- --all
|
|
410
|
+
|
|
411
|
+
# Compile a single tier
|
|
412
|
+
npm run compile-wiki -- --tier=preferences
|
|
413
|
+
|
|
414
|
+
# Compile a per-topic page
|
|
415
|
+
npm run compile-wiki -- --topic=wiki-mode
|
|
416
|
+
|
|
417
|
+
# Preview without writing
|
|
418
|
+
npm run compile-wiki -- --all --dry-run
|
|
419
|
+
|
|
420
|
+
# Force a provider (otherwise uses auto-fallback)
|
|
421
|
+
npm run compile-wiki -- --all --provider=claude-code
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Output shape
|
|
425
|
+
|
|
426
|
+
Every compiled file carries YAML frontmatter recording `generated_at`,
|
|
427
|
+
`compile_run_id`, `source_count`, `source_memory_ids`, `provider`,
|
|
428
|
+
`source_git_sha`, and `tier` or `topic`. The body is structured prose with
|
|
429
|
+
inline `<m:id>` citations and a `Sources:` line per cluster.
|
|
430
|
+
|
|
431
|
+
### Structural stability
|
|
432
|
+
|
|
433
|
+
Compile is treated as a regenerable view: across two runs against the same
|
|
434
|
+
input, the set of `## H2` / `### H3` headers and the set of cited memory IDs
|
|
435
|
+
are bit-identical. Prose-level variance is bounded at 5% (Levenshtein ratio
|
|
436
|
+
≥ 0.95) — the only LLM nondeterminism allowance. The compiler controls
|
|
437
|
+
headers and citations; only the prose paragraphs come from the LLM.
|
|
438
|
+
|
|
439
|
+
### Cost cap
|
|
440
|
+
|
|
441
|
+
`R2MCP_COMPILE_MAX_USD` (default `$1.00`) — when exceeded mid-run, compile
|
|
442
|
+
exits cleanly with `hit_cost_cap: true` and partial files. Same shape as the
|
|
443
|
+
classifier cap-hit behavior.
|
|
444
|
+
|
|
445
|
+
### What compile never does
|
|
446
|
+
|
|
447
|
+
- Modifies `memory/MEMORY.md` — the human-curated hub stays invariant
|
|
448
|
+
- Writes outside `memory/compiled/`
|
|
449
|
+
- Touches the live `memories` or `memory_edges` tables — read-only at the DB layer
|
|
450
|
+
- Uses any direct Anthropic SDK call — every synthesis routes through `LLMProvider`
|
|
451
|
+
|
|
452
|
+
## Lint (SPEC-044)
|
|
453
|
+
|
|
454
|
+
`lint()` surfaces five structural checks on the memory store. SQL-only — no
|
|
455
|
+
LLM calls, no cost cap.
|
|
456
|
+
|
|
457
|
+
```bash
|
|
458
|
+
# Run all checks against the live DB and produce a human-readable report
|
|
459
|
+
npm run lint:memory
|
|
460
|
+
|
|
461
|
+
# Run a single check
|
|
462
|
+
npm run lint:memory -- --check=stale
|
|
463
|
+
|
|
464
|
+
# Apply auto-fixes for high-confidence findings
|
|
465
|
+
npm run lint:memory -- --fix
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
| Check | What it surfaces |
|
|
469
|
+
|-------|-------------------|
|
|
470
|
+
| `contradictions` | Edges where `relation='contradicts'` between two unarchived memories |
|
|
471
|
+
| `stale` | Memories older than 90d with zero incoming edges, tier ≠ preferences |
|
|
472
|
+
| `orphans` | Memories with zero edges in either direction, older than 30d |
|
|
473
|
+
| `drift` | Pairs sharing ≥2 topics with no edge yet — classifier hasn't run on this pair |
|
|
474
|
+
| `superseded_unflagged` | `contradicts` edge where the temporal pattern says it should be `supersedes` |
|
|
475
|
+
|
|
476
|
+
### `--fix` semantics
|
|
477
|
+
|
|
478
|
+
`lint --fix` only acts on findings with `confidence ≥ 0.9`:
|
|
479
|
+
|
|
480
|
+
- `stale` → memory is archived (`type='archived'`)
|
|
481
|
+
- `superseded_unflagged` → edge type is rewritten from `contradicts` to `supersedes`
|
|
482
|
+
|
|
483
|
+
Lower-confidence findings are returned as suggestions only, never auto-acted.
|
|
484
|
+
|
|
485
|
+
### `meditate` integration
|
|
486
|
+
|
|
487
|
+
`meditate({include_lint: true})` runs lint first and surfaces findings as a
|
|
488
|
+
`lint_findings` field on the response. The default invocation
|
|
489
|
+
(`meditate({mode: 'full', dry_run: false})`) returns the byte-identical
|
|
490
|
+
pre-spec response shape — backward compatibility for direct callers is
|
|
491
|
+
preserved.
|
|
492
|
+
|
|
493
|
+
## Entity extraction (SPEC-046)
|
|
494
|
+
|
|
495
|
+
Light entity extraction over the memory store — pulls structured `project` /
|
|
496
|
+
`person` / `tool` / `decision` entities out of memories, persists them to two
|
|
497
|
+
new tables (`entities` for canonical names + aliases, `memory_entities` for the
|
|
498
|
+
M:N link to `memories`), and lets `recall()` filter on entity name or alias.
|
|
499
|
+
|
|
500
|
+
The extractor is a subprocess-driven batch process — the MCP server itself
|
|
501
|
+
never makes LLM calls. Provider selection follows the SPEC-044 precedence; on a
|
|
502
|
+
Max plan, no API key is required.
|
|
503
|
+
|
|
504
|
+
```bash
|
|
505
|
+
# One-shot batch extraction over the last week, capped at $0.50
|
|
506
|
+
npm run entities:extract -- --since-days=7 --max-cost=0.5
|
|
507
|
+
|
|
508
|
+
# Or via MCP tool from any client
|
|
509
|
+
# mcp.callTool('extract_entities', { since_days: 7, max_cost_usd: 0.5 })
|
|
510
|
+
|
|
511
|
+
# Then ask for Speculator-scoped recall
|
|
512
|
+
# mcp.callTool('recall', { entity: 'Speculator', query: 'compaction' })
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### Env vars
|
|
516
|
+
|
|
517
|
+
| Variable | Default | What it controls |
|
|
518
|
+
|----------|---------|------------------|
|
|
519
|
+
| `R2MCP_ENTITY_MAX_USD` | `1.00` | Cost cap for a single extraction run. On overrun, the run exits cleanly with `hit_cost_cap: true` (same shape as the classifier and compile caps). |
|
|
520
|
+
| `R2MCP_ENTITY_CONTEXT_TOP_N` | `100` | Number of known entities seeded into the LLM context to bias toward canonical names + alias merging. |
|
|
521
|
+
|
|
522
|
+
### Scoped recall
|
|
523
|
+
|
|
524
|
+
When `recall()` is called with `entity` set:
|
|
525
|
+
|
|
526
|
+
- `query` is optional — entity-only recall returns all memories linked to the entity (matched by canonical name or any alias).
|
|
527
|
+
- The response carries `entity_resolved: boolean` and, when resolved, `entity_id`.
|
|
528
|
+
- Each result carries an `entity_links[]` array describing how that memory connects to the named entity.
|
|
529
|
+
|
|
530
|
+
## License
|
|
531
|
+
|
|
532
|
+
[MIT](LICENSE)
|