kyp-mem 0.2.1 → 0.2.2
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/README.md +4 -14
- package/kyp_mem/cli.py +128 -43
- package/kyp_mem/server.py +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@ Opens a rich interface at `localhost:3333` with:
|
|
|
65
65
|
| Command | What it does |
|
|
66
66
|
|---------|-------------|
|
|
67
67
|
| `kyp-mem init` | First-time setup — choose vault location |
|
|
68
|
-
| `kyp-mem setup-claude` |
|
|
68
|
+
| `kyp-mem setup-claude` | Register the MCP server with Claude Code for this project |
|
|
69
69
|
| `kyp-mem setup-claude --global` | Configure globally (all projects) |
|
|
70
70
|
| `kyp-mem serve` | Start MCP server (used by Claude, not you) |
|
|
71
71
|
| `kyp-mem ui` | Open web UI at localhost:3333 |
|
|
@@ -110,21 +110,11 @@ Settings are defined in `HedgeConfig`. See [[Risk Management]] for safety checks
|
|
|
110
110
|
|
|
111
111
|
If you prefer to configure manually instead of using `setup-claude`:
|
|
112
112
|
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
"mcpServers": {
|
|
116
|
-
"kyp-mem": {
|
|
117
|
-
"command": "npx",
|
|
118
|
-
"args": ["-y", "kyp-mem", "serve"],
|
|
119
|
-
"env": {
|
|
120
|
-
"KYP_VAULT": "~/.kyp-mem/vault"
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
113
|
+
```bash
|
|
114
|
+
claude mcp add -s local -e KYP_VAULT="$HOME/.kyp-mem/vault" kyp-mem -- npx -y kyp-mem serve
|
|
125
115
|
```
|
|
126
116
|
|
|
127
|
-
|
|
117
|
+
Use `-s user` instead of `-s local` to make it available in all projects.
|
|
128
118
|
|
|
129
119
|
## Architecture
|
|
130
120
|
|
package/kyp_mem/cli.py
CHANGED
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
import json
|
|
5
5
|
import shutil
|
|
6
6
|
import argparse
|
|
7
|
+
import subprocess
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
|
|
9
10
|
C = "\033[36m" # cyan
|
|
@@ -107,28 +108,112 @@ def _run_setup_claude(global_config: bool = False):
|
|
|
107
108
|
from .config import get_vault_path
|
|
108
109
|
|
|
109
110
|
vault_path = get_vault_path()
|
|
111
|
+
mcp_command, mcp_args = _get_mcp_command()
|
|
112
|
+
claude_scope = "user" if global_config else "local"
|
|
113
|
+
scope_label = "global user" if global_config else "local project"
|
|
114
|
+
|
|
115
|
+
registered, detail = _register_with_claude_mcp(
|
|
116
|
+
claude_scope,
|
|
117
|
+
mcp_command,
|
|
118
|
+
mcp_args,
|
|
119
|
+
vault_path,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
print()
|
|
123
|
+
print(f" {C}KYP-MEM{R} — Claude Code Setup")
|
|
124
|
+
print()
|
|
125
|
+
if registered:
|
|
126
|
+
print(f" {G}✓{R} MCP server registered with Claude Code ({scope_label})")
|
|
127
|
+
else:
|
|
128
|
+
settings_path = _write_legacy_claude_settings(global_config, mcp_command, mcp_args, vault_path)
|
|
129
|
+
print(f" {Y}✗{R} Could not register with Claude Code's MCP manager")
|
|
130
|
+
print(f" {D} Reason: {detail}{R}")
|
|
131
|
+
print(f" {Y}!{R} Wrote legacy settings as a fallback")
|
|
132
|
+
print(f" {D} File: {settings_path}{R}")
|
|
133
|
+
print(f" {D} Command: {mcp_command} {' '.join(mcp_args)}{R}")
|
|
134
|
+
print(f" {D} Vault: {vault_path}{R}")
|
|
135
|
+
print()
|
|
136
|
+
print(f" {C}Done!{R} Restart Claude Code and kyp-mem will run automatically.")
|
|
137
|
+
print(f" Claude gets these tools: kyp_list, kyp_read, kyp_write, kyp_delete,")
|
|
138
|
+
print(f" kyp_search, kyp_tags, kyp_related, kyp_recent, kyp_stats")
|
|
139
|
+
print()
|
|
140
|
+
print(f" {D}To open the web UI anytime:{R} {Y}kyp-mem ui{R}")
|
|
141
|
+
print()
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _get_mcp_command() -> tuple[str, list[str]]:
|
|
110
145
|
kyp_mem_bin = shutil.which("kyp-mem")
|
|
111
146
|
npx_bin = shutil.which("npx")
|
|
112
147
|
|
|
113
148
|
if kyp_mem_bin and "_npx" not in Path(kyp_mem_bin).parts:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
149
|
+
return kyp_mem_bin, ["serve"]
|
|
150
|
+
if npx_bin:
|
|
151
|
+
return npx_bin, ["-y", "kyp-mem", "serve"]
|
|
152
|
+
|
|
153
|
+
print(f" {Y}Warning:{R} 'kyp-mem' not found in PATH.")
|
|
154
|
+
print(f" {D}Make sure you installed with: npm install -g kyp-mem{R}")
|
|
155
|
+
print()
|
|
156
|
+
return "kyp-mem", ["serve"]
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _register_with_claude_mcp(
|
|
160
|
+
scope: str,
|
|
161
|
+
mcp_command: str,
|
|
162
|
+
mcp_args: list[str],
|
|
163
|
+
vault_path: str,
|
|
164
|
+
) -> tuple[bool, str]:
|
|
165
|
+
claude_bin = shutil.which("claude")
|
|
166
|
+
if not claude_bin:
|
|
167
|
+
return False, "'claude' CLI not found in PATH"
|
|
168
|
+
|
|
169
|
+
server_config = {
|
|
170
|
+
"type": "stdio",
|
|
171
|
+
"command": mcp_command,
|
|
172
|
+
"args": mcp_args,
|
|
173
|
+
"env": {
|
|
174
|
+
"KYP_VAULT": vault_path,
|
|
175
|
+
},
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
# Make setup idempotent when the user reruns it with a new vault or binary.
|
|
179
|
+
subprocess.run(
|
|
180
|
+
[claude_bin, "mcp", "remove", "-s", scope, "kyp-mem"],
|
|
181
|
+
stdout=subprocess.DEVNULL,
|
|
182
|
+
stderr=subprocess.DEVNULL,
|
|
183
|
+
text=True,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
result = subprocess.run(
|
|
187
|
+
[
|
|
188
|
+
claude_bin,
|
|
189
|
+
"mcp",
|
|
190
|
+
"add-json",
|
|
191
|
+
"-s",
|
|
192
|
+
scope,
|
|
193
|
+
"kyp-mem",
|
|
194
|
+
json.dumps(server_config),
|
|
195
|
+
],
|
|
196
|
+
capture_output=True,
|
|
197
|
+
text=True,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
if result.returncode == 0:
|
|
201
|
+
return True, result.stdout.strip()
|
|
202
|
+
|
|
203
|
+
detail = (result.stderr or result.stdout or "unknown error").strip()
|
|
204
|
+
return False, detail
|
|
125
205
|
|
|
206
|
+
|
|
207
|
+
def _write_legacy_claude_settings(
|
|
208
|
+
global_config: bool,
|
|
209
|
+
mcp_command: str,
|
|
210
|
+
mcp_args: list[str],
|
|
211
|
+
vault_path: str,
|
|
212
|
+
) -> Path:
|
|
126
213
|
if global_config:
|
|
127
214
|
settings_path = Path.home() / ".claude" / "settings.json"
|
|
128
|
-
scope = "global"
|
|
129
215
|
else:
|
|
130
216
|
settings_path = Path.cwd() / ".claude" / "settings.json"
|
|
131
|
-
scope = "project"
|
|
132
217
|
|
|
133
218
|
settings_path.parent.mkdir(parents=True, exist_ok=True)
|
|
134
219
|
|
|
@@ -140,7 +225,6 @@ def _run_setup_claude(global_config: bool = False):
|
|
|
140
225
|
settings = {}
|
|
141
226
|
|
|
142
227
|
mcp_servers = settings.setdefault("mcpServers", {})
|
|
143
|
-
|
|
144
228
|
mcp_servers["kyp-mem"] = {
|
|
145
229
|
"command": mcp_command,
|
|
146
230
|
"args": mcp_args,
|
|
@@ -150,21 +234,7 @@ def _run_setup_claude(global_config: bool = False):
|
|
|
150
234
|
}
|
|
151
235
|
|
|
152
236
|
settings_path.write_text(json.dumps(settings, indent=2) + "\n")
|
|
153
|
-
|
|
154
|
-
print()
|
|
155
|
-
print(f" {C}KYP-MEM{R} — Claude Code Setup")
|
|
156
|
-
print()
|
|
157
|
-
print(f" {G}✓{R} MCP server added to {scope} settings")
|
|
158
|
-
print(f" {D} File: {settings_path}{R}")
|
|
159
|
-
print(f" {D} Command: {mcp_command} {' '.join(mcp_args)}{R}")
|
|
160
|
-
print(f" {D} Vault: {vault_path}{R}")
|
|
161
|
-
print()
|
|
162
|
-
print(f" {C}Done!{R} Restart Claude Code and kyp-mem will run automatically.")
|
|
163
|
-
print(f" Claude gets these tools: kyp_list, kyp_read, kyp_write, kyp_delete,")
|
|
164
|
-
print(f" kyp_search, kyp_tags, kyp_related, kyp_recent, kyp_stats")
|
|
165
|
-
print()
|
|
166
|
-
print(f" {D}To open the web UI anytime:{R} {Y}kyp-mem ui{R}")
|
|
167
|
-
print()
|
|
237
|
+
return settings_path
|
|
168
238
|
|
|
169
239
|
|
|
170
240
|
def _run_stats():
|
|
@@ -212,22 +282,37 @@ def _run_doctor():
|
|
|
212
282
|
else:
|
|
213
283
|
print(f" {Y}✗{R} Vault not found: {vault_path}")
|
|
214
284
|
|
|
215
|
-
# Claude Code
|
|
216
|
-
|
|
285
|
+
# Claude Code MCP registration
|
|
286
|
+
claude_bin = shutil.which("claude")
|
|
287
|
+
if claude_bin:
|
|
288
|
+
result = subprocess.run(
|
|
289
|
+
[claude_bin, "mcp", "get", "kyp-mem"],
|
|
290
|
+
capture_output=True,
|
|
291
|
+
text=True,
|
|
292
|
+
)
|
|
293
|
+
if result.returncode == 0 and "Status: ✓ Connected" in result.stdout:
|
|
294
|
+
print(f" {G}✓{R} Claude Code MCP: kyp-mem connected")
|
|
295
|
+
elif result.returncode == 0:
|
|
296
|
+
print(f" {Y}✗{R} Claude Code MCP: kyp-mem registered but not connected")
|
|
297
|
+
else:
|
|
298
|
+
print(f" {Y}✗{R} Claude Code MCP: kyp-mem not active")
|
|
299
|
+
else:
|
|
300
|
+
print(f" {Y}✗{R} Claude Code CLI not found in PATH")
|
|
301
|
+
|
|
302
|
+
legacy_paths = [
|
|
217
303
|
("project", Path.cwd() / ".claude" / "settings.json"),
|
|
218
304
|
("global", Path.home() / ".claude" / "settings.json"),
|
|
219
|
-
]
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
print(f" {D}·{R} Claude Code ({label}): no settings file")
|
|
305
|
+
]
|
|
306
|
+
for label, path in legacy_paths:
|
|
307
|
+
if not path.exists():
|
|
308
|
+
continue
|
|
309
|
+
try:
|
|
310
|
+
s = json.loads(path.read_text())
|
|
311
|
+
except json.JSONDecodeError:
|
|
312
|
+
print(f" {Y}✗{R} Legacy Claude settings ({label}): invalid JSON")
|
|
313
|
+
continue
|
|
314
|
+
if "kyp-mem" in s.get("mcpServers", {}):
|
|
315
|
+
print(f" {D}·{R} Legacy Claude settings ({label}): kyp-mem entry present")
|
|
231
316
|
|
|
232
317
|
# Binary
|
|
233
318
|
kyp_bin = shutil.which("kyp-mem")
|
package/kyp_mem/server.py
CHANGED
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "kyp-mem"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Know Your Project — Headless knowledge base for AI agents. MCP-powered with wikilinks, backlinks, and neon web UI."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|