@llmnesia/mcp 0.1.10 → 0.1.12
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 +8 -1
- package/dist/{chunk-LA3BU5ZR.js → chunk-MI5RBP7Y.js} +1 -1
- package/dist/{cli-VUTW2WGY.js → cli-GKHVUCEP.js} +77 -23
- package/dist/cli.js +2 -2
- package/dist/llmnesia.mcpb +0 -0
- package/dist/mcp.js +116 -46
- package/package.json +6 -3
- package/server.json +2 -2
package/README.md
CHANGED
|
@@ -55,6 +55,13 @@ The installer:
|
|
|
55
55
|
of those standard config paths, so an app installed later does not require
|
|
56
56
|
running setup again.
|
|
57
57
|
|
|
58
|
+
On Windows, Claude Desktop uses its supported packaged-extension flow instead
|
|
59
|
+
of the legacy JSON config. If Claude is installed, its normal LLMnesia install
|
|
60
|
+
window opens during setup; click **Install** once. Claude can run that extension
|
|
61
|
+
with its built-in Node.js, while the system Node installation continues to run
|
|
62
|
+
the browser helper and other desktop AI integrations. If Claude is installed
|
|
63
|
+
later, run the same LLMnesia setup command once more.
|
|
64
|
+
|
|
58
65
|
The `install` command is the approval to perform those setup steps. It does not
|
|
59
66
|
interrupt setup with a separate prompt for every detected app, and it never
|
|
60
67
|
prints existing client configurations or their credentials.
|
|
@@ -121,7 +128,7 @@ received data — check it before concluding a chat does not exist.
|
|
|
121
128
|
| Client | How `install` wires it |
|
|
122
129
|
| --- | --- |
|
|
123
130
|
| Claude Code | Runs `claude mcp add --scope user` with the absolute Node and installed runtime paths when available. Otherwise it writes the documented user-scope `~/.claude.json` entry, so Windows users do not need the `claude` command on PATH. |
|
|
124
|
-
| Claude Desktop |
|
|
131
|
+
| Claude Desktop | Windows opens Claude's regular packaged-extension installer and removes obsolete LLMnesia JSON entries. macOS keeps the working local JSON registration. |
|
|
125
132
|
| Cursor | Edits `~/.cursor/mcp.json`, preparing it in advance if Cursor is installed later. |
|
|
126
133
|
| Codex / ChatGPT desktop | Runs `codex mcp add` with the absolute runtime paths when available. If the bundled CLI is unavailable, the installer safely edits `~/.codex/config.toml` itself and backs up existing settings first, including preparing it for a later installation. Read-only LLMnesia tools are configured to run without repeated approval prompts; writes still ask. |
|
|
127
134
|
| Others (Windsurf, Zed, LM Studio, …) | Prints the generic stdio block for you to paste. |
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
__commonJS,
|
|
16
16
|
__require,
|
|
17
17
|
__toESM
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-MI5RBP7Y.js";
|
|
19
19
|
|
|
20
20
|
// ../node_modules/isexe/windows.js
|
|
21
21
|
var require_windows = __commonJS({
|
|
@@ -41,15 +41,15 @@ var require_windows = __commonJS({
|
|
|
41
41
|
}
|
|
42
42
|
return false;
|
|
43
43
|
}
|
|
44
|
-
function checkStat(
|
|
45
|
-
if (!
|
|
44
|
+
function checkStat(stat7, path, options) {
|
|
45
|
+
if (!stat7.isSymbolicLink() && !stat7.isFile()) {
|
|
46
46
|
return false;
|
|
47
47
|
}
|
|
48
48
|
return checkPathExt(path, options);
|
|
49
49
|
}
|
|
50
50
|
function isexe(path, options, cb) {
|
|
51
|
-
fs.stat(path, function(er,
|
|
52
|
-
cb(er, er ? false : checkStat(
|
|
51
|
+
fs.stat(path, function(er, stat7) {
|
|
52
|
+
cb(er, er ? false : checkStat(stat7, path, options));
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
55
|
function sync(path, options) {
|
|
@@ -66,20 +66,20 @@ var require_mode = __commonJS({
|
|
|
66
66
|
isexe.sync = sync;
|
|
67
67
|
var fs = __require("fs");
|
|
68
68
|
function isexe(path, options, cb) {
|
|
69
|
-
fs.stat(path, function(er,
|
|
70
|
-
cb(er, er ? false : checkStat(
|
|
69
|
+
fs.stat(path, function(er, stat7) {
|
|
70
|
+
cb(er, er ? false : checkStat(stat7, options));
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
73
|
function sync(path, options) {
|
|
74
74
|
return checkStat(fs.statSync(path), options);
|
|
75
75
|
}
|
|
76
|
-
function checkStat(
|
|
77
|
-
return
|
|
76
|
+
function checkStat(stat7, options) {
|
|
77
|
+
return stat7.isFile() && checkMode(stat7, options);
|
|
78
78
|
}
|
|
79
|
-
function checkMode(
|
|
80
|
-
var mod =
|
|
81
|
-
var uid =
|
|
82
|
-
var gid =
|
|
79
|
+
function checkMode(stat7, options) {
|
|
80
|
+
var mod = stat7.mode;
|
|
81
|
+
var uid = stat7.uid;
|
|
82
|
+
var gid = stat7.gid;
|
|
83
83
|
var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
|
|
84
84
|
var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
|
|
85
85
|
var u = parseInt("100", 8);
|
|
@@ -251,8 +251,8 @@ var require_path_key = __commonJS({
|
|
|
251
251
|
"use strict";
|
|
252
252
|
var pathKey = (options = {}) => {
|
|
253
253
|
const environment = options.env || process.env;
|
|
254
|
-
const
|
|
255
|
-
if (
|
|
254
|
+
const platform5 = options.platform || process.platform;
|
|
255
|
+
if (platform5 !== "win32") {
|
|
256
256
|
return "PATH";
|
|
257
257
|
}
|
|
258
258
|
return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path";
|
|
@@ -2439,8 +2439,8 @@ var FSWatcher = class extends EventEmitter {
|
|
|
2439
2439
|
}
|
|
2440
2440
|
return this._userIgnored(path, stats);
|
|
2441
2441
|
}
|
|
2442
|
-
_isntIgnored(path,
|
|
2443
|
-
return !this._isIgnored(path,
|
|
2442
|
+
_isntIgnored(path, stat7) {
|
|
2443
|
+
return !this._isIgnored(path, stat7);
|
|
2444
2444
|
}
|
|
2445
2445
|
/**
|
|
2446
2446
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
@@ -3258,12 +3258,23 @@ async function registerClients(options) {
|
|
|
3258
3258
|
)
|
|
3259
3259
|
);
|
|
3260
3260
|
if (claudeDesktop) {
|
|
3261
|
-
|
|
3262
|
-
await safe(
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3261
|
+
if (osPlatform2 === "win32") {
|
|
3262
|
+
const cleanup = await safe("Claude Desktop", () => unregisterJsonClient("Claude Desktop", claudeDesktop, now));
|
|
3263
|
+
results.push(
|
|
3264
|
+
cleanup.action === "error" ? cleanup : {
|
|
3265
|
+
client: "Claude Desktop",
|
|
3266
|
+
action: "skipped",
|
|
3267
|
+
detail: "Claude Desktop uses the packaged LLMnesia extension on Windows."
|
|
3268
|
+
}
|
|
3269
|
+
);
|
|
3270
|
+
} else {
|
|
3271
|
+
results.push(
|
|
3272
|
+
await safe(
|
|
3273
|
+
"Claude Desktop",
|
|
3274
|
+
() => registerJsonClient("Claude Desktop", claudeDesktop, options.serve, options.confirm, now, prepareMissing, false, false)
|
|
3275
|
+
)
|
|
3276
|
+
);
|
|
3277
|
+
}
|
|
3267
3278
|
}
|
|
3268
3279
|
results.push(
|
|
3269
3280
|
await safe("Cursor", () => registerJsonClient("Cursor", cursor, options.serve, options.confirm, now, prepareMissing))
|
|
@@ -3777,6 +3788,36 @@ function formatDoctorReport(report) {
|
|
|
3777
3788
|
return report.checks.map((c) => `${icon[c.status]} ${c.name}: ${c.detail}`).join("\n");
|
|
3778
3789
|
}
|
|
3779
3790
|
|
|
3791
|
+
// src/claudeDesktopExtension.ts
|
|
3792
|
+
import { execFile as execFile3 } from "child_process";
|
|
3793
|
+
import { access as access2, stat as stat6 } from "fs/promises";
|
|
3794
|
+
import { homedir as homedir5, platform as platform4 } from "os";
|
|
3795
|
+
import { join as join7 } from "path";
|
|
3796
|
+
import { promisify as promisify3 } from "util";
|
|
3797
|
+
var execFileAsync3 = promisify3(execFile3);
|
|
3798
|
+
async function defaultOpenBundle(bundlePath) {
|
|
3799
|
+
await execFileAsync3("rundll32.exe", ["url.dll,FileProtocolHandler", bundlePath], { windowsHide: true });
|
|
3800
|
+
}
|
|
3801
|
+
async function promptClaudeDesktopExtension(options) {
|
|
3802
|
+
const home2 = options.home ?? homedir5();
|
|
3803
|
+
const osPlatform2 = options.osPlatform ?? platform4();
|
|
3804
|
+
const bundlePath = join7(options.binDir, "llmnesia.mcpb");
|
|
3805
|
+
if (osPlatform2 !== "win32") {
|
|
3806
|
+
return { status: "unsupported", bundlePath };
|
|
3807
|
+
}
|
|
3808
|
+
const appData = options.appData ?? process.env.APPDATA ?? join7(home2, "AppData", "Roaming");
|
|
3809
|
+
try {
|
|
3810
|
+
if (!(await stat6(join7(appData, "Claude"))).isDirectory()) {
|
|
3811
|
+
return { status: "not-installed", bundlePath };
|
|
3812
|
+
}
|
|
3813
|
+
} catch {
|
|
3814
|
+
return { status: "not-installed", bundlePath };
|
|
3815
|
+
}
|
|
3816
|
+
await access2(bundlePath);
|
|
3817
|
+
await (options.openBundle ?? defaultOpenBundle)(bundlePath);
|
|
3818
|
+
return { status: "opened", bundlePath };
|
|
3819
|
+
}
|
|
3820
|
+
|
|
3780
3821
|
// src/cli.ts
|
|
3781
3822
|
var USAGE = `llmnesia-mcp ${VERSION}
|
|
3782
3823
|
|
|
@@ -3888,6 +3929,19 @@ async function runInstall(positionals, options, flags) {
|
|
|
3888
3929
|
`);
|
|
3889
3930
|
}
|
|
3890
3931
|
hadProblems ||= registrations.errors.length > 0;
|
|
3932
|
+
if (process.platform === "win32") {
|
|
3933
|
+
try {
|
|
3934
|
+
const claude = await promptClaudeDesktopExtension({ binDir: runtime.binDir });
|
|
3935
|
+
if (claude.status === "opened") {
|
|
3936
|
+
process.stdout.write("Claude opened. Click Install to add LLMnesia.\n");
|
|
3937
|
+
}
|
|
3938
|
+
} catch (err) {
|
|
3939
|
+
process.stderr.write(
|
|
3940
|
+
`Claude Desktop needs one more step: open ${runtime.binDir}\\llmnesia.mcpb and click Install. (${err instanceof Error ? err.message : String(err)})
|
|
3941
|
+
`
|
|
3942
|
+
);
|
|
3943
|
+
}
|
|
3944
|
+
}
|
|
3891
3945
|
if (hadProblems) {
|
|
3892
3946
|
process.stderr.write("\nSetup needs attention. Fix the message above, then run the same command again.\n");
|
|
3893
3947
|
return 1;
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire as __llmnesiaCreateRequire } from "node:module";
|
|
|
3
3
|
const require = __llmnesiaCreateRequire(import.meta.url);
|
|
4
4
|
import {
|
|
5
5
|
VERSION
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-MI5RBP7Y.js";
|
|
7
7
|
|
|
8
8
|
// src/nodeDownload.ts
|
|
9
9
|
var NODE_DOWNLOAD_URLS = {
|
|
@@ -141,7 +141,7 @@ async function bootstrap() {
|
|
|
141
141
|
await guideUnsupportedNodeVersion(process.versions.node);
|
|
142
142
|
return 1;
|
|
143
143
|
}
|
|
144
|
-
const { main } = await import("./cli-
|
|
144
|
+
const { main } = await import("./cli-GKHVUCEP.js");
|
|
145
145
|
return main();
|
|
146
146
|
}
|
|
147
147
|
bootstrap().then((code) => {
|
|
Binary file
|
package/dist/mcp.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
__commonJS,
|
|
14
14
|
__export,
|
|
15
15
|
__toESM
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-MI5RBP7Y.js";
|
|
17
17
|
|
|
18
18
|
// ../node_modules/ajv/dist/compile/codegen/code.js
|
|
19
19
|
var require_code = __commonJS({
|
|
@@ -3211,8 +3211,8 @@ var require_utils = __commonJS({
|
|
|
3211
3211
|
}
|
|
3212
3212
|
return ind;
|
|
3213
3213
|
}
|
|
3214
|
-
function removeDotSegments(
|
|
3215
|
-
let input =
|
|
3214
|
+
function removeDotSegments(path2) {
|
|
3215
|
+
let input = path2;
|
|
3216
3216
|
const output = [];
|
|
3217
3217
|
let nextSlash = -1;
|
|
3218
3218
|
let len = 0;
|
|
@@ -3464,8 +3464,8 @@ var require_schemes = __commonJS({
|
|
|
3464
3464
|
wsComponent.secure = void 0;
|
|
3465
3465
|
}
|
|
3466
3466
|
if (wsComponent.resourceName) {
|
|
3467
|
-
const [
|
|
3468
|
-
wsComponent.path =
|
|
3467
|
+
const [path2, query] = wsComponent.resourceName.split("?");
|
|
3468
|
+
wsComponent.path = path2 && path2 !== "/" ? path2 : void 0;
|
|
3469
3469
|
wsComponent.query = query;
|
|
3470
3470
|
wsComponent.resourceName = void 0;
|
|
3471
3471
|
}
|
|
@@ -7375,8 +7375,8 @@ function getErrorMap() {
|
|
|
7375
7375
|
|
|
7376
7376
|
// ../node_modules/zod/v3/helpers/parseUtil.js
|
|
7377
7377
|
var makeIssue = (params) => {
|
|
7378
|
-
const { data, path, errorMaps, issueData } = params;
|
|
7379
|
-
const fullPath = [...
|
|
7378
|
+
const { data, path: path2, errorMaps, issueData } = params;
|
|
7379
|
+
const fullPath = [...path2, ...issueData.path || []];
|
|
7380
7380
|
const fullIssue = {
|
|
7381
7381
|
...issueData,
|
|
7382
7382
|
path: fullPath
|
|
@@ -7492,11 +7492,11 @@ var errorUtil;
|
|
|
7492
7492
|
|
|
7493
7493
|
// ../node_modules/zod/v3/types.js
|
|
7494
7494
|
var ParseInputLazyPath = class {
|
|
7495
|
-
constructor(parent, value,
|
|
7495
|
+
constructor(parent, value, path2, key) {
|
|
7496
7496
|
this._cachedPath = [];
|
|
7497
7497
|
this.parent = parent;
|
|
7498
7498
|
this.data = value;
|
|
7499
|
-
this._path =
|
|
7499
|
+
this._path = path2;
|
|
7500
7500
|
this._key = key;
|
|
7501
7501
|
}
|
|
7502
7502
|
get path() {
|
|
@@ -11133,10 +11133,10 @@ function assignProp(target, prop, value) {
|
|
|
11133
11133
|
configurable: true
|
|
11134
11134
|
});
|
|
11135
11135
|
}
|
|
11136
|
-
function getElementAtPath(obj,
|
|
11137
|
-
if (!
|
|
11136
|
+
function getElementAtPath(obj, path2) {
|
|
11137
|
+
if (!path2)
|
|
11138
11138
|
return obj;
|
|
11139
|
-
return
|
|
11139
|
+
return path2.reduce((acc, key) => acc?.[key], obj);
|
|
11140
11140
|
}
|
|
11141
11141
|
function promiseAllObject(promisesObj) {
|
|
11142
11142
|
const keys = Object.keys(promisesObj);
|
|
@@ -11456,11 +11456,11 @@ function aborted(x, startIndex = 0) {
|
|
|
11456
11456
|
}
|
|
11457
11457
|
return false;
|
|
11458
11458
|
}
|
|
11459
|
-
function prefixIssues(
|
|
11459
|
+
function prefixIssues(path2, issues) {
|
|
11460
11460
|
return issues.map((iss) => {
|
|
11461
11461
|
var _a;
|
|
11462
11462
|
(_a = iss).path ?? (_a.path = []);
|
|
11463
|
-
iss.path.unshift(
|
|
11463
|
+
iss.path.unshift(path2);
|
|
11464
11464
|
return iss;
|
|
11465
11465
|
});
|
|
11466
11466
|
}
|
|
@@ -14871,11 +14871,11 @@ function normalizeObjectSchema(schema) {
|
|
|
14871
14871
|
}
|
|
14872
14872
|
return void 0;
|
|
14873
14873
|
}
|
|
14874
|
-
function getDotPath(
|
|
14875
|
-
if (
|
|
14874
|
+
function getDotPath(path2) {
|
|
14875
|
+
if (path2.length === 0) {
|
|
14876
14876
|
return "object root";
|
|
14877
14877
|
}
|
|
14878
|
-
return
|
|
14878
|
+
return path2.reduce((acc, seg, index) => {
|
|
14879
14879
|
if (index === 0) {
|
|
14880
14880
|
return String(seg);
|
|
14881
14881
|
}
|
|
@@ -21131,6 +21131,11 @@ var StdioServerTransport = class {
|
|
|
21131
21131
|
}
|
|
21132
21132
|
};
|
|
21133
21133
|
|
|
21134
|
+
// src/mcp.ts
|
|
21135
|
+
import { realpathSync } from "fs";
|
|
21136
|
+
import { fileURLToPath } from "url";
|
|
21137
|
+
import path from "path";
|
|
21138
|
+
|
|
21134
21139
|
// src/saveSchema.ts
|
|
21135
21140
|
import { createHash } from "crypto";
|
|
21136
21141
|
var saveMessageSchema = external_exports.object({
|
|
@@ -21360,6 +21365,51 @@ var CompanionService = class _CompanionService {
|
|
|
21360
21365
|
function noop() {
|
|
21361
21366
|
}
|
|
21362
21367
|
|
|
21368
|
+
// src/lazyResource.ts
|
|
21369
|
+
var ResourcePreparingError = class extends Error {
|
|
21370
|
+
constructor() {
|
|
21371
|
+
super("Resource is still preparing");
|
|
21372
|
+
this.name = "ResourcePreparingError";
|
|
21373
|
+
}
|
|
21374
|
+
};
|
|
21375
|
+
var LazyResource = class {
|
|
21376
|
+
constructor(open) {
|
|
21377
|
+
this.open = open;
|
|
21378
|
+
}
|
|
21379
|
+
open;
|
|
21380
|
+
resource = null;
|
|
21381
|
+
failure;
|
|
21382
|
+
completion = null;
|
|
21383
|
+
start() {
|
|
21384
|
+
if (this.completion) return;
|
|
21385
|
+
this.completion = Promise.resolve().then(() => this.open()).then(
|
|
21386
|
+
(resource) => {
|
|
21387
|
+
this.resource = resource;
|
|
21388
|
+
},
|
|
21389
|
+
(error2) => {
|
|
21390
|
+
this.failure = error2;
|
|
21391
|
+
}
|
|
21392
|
+
);
|
|
21393
|
+
}
|
|
21394
|
+
async get(waitMs) {
|
|
21395
|
+
this.start();
|
|
21396
|
+
if (this.resource) return this.resource;
|
|
21397
|
+
let timeout;
|
|
21398
|
+
await Promise.race([
|
|
21399
|
+
this.completion,
|
|
21400
|
+
new Promise((resolve) => {
|
|
21401
|
+
timeout = setTimeout(resolve, waitMs);
|
|
21402
|
+
})
|
|
21403
|
+
]);
|
|
21404
|
+
if (timeout) clearTimeout(timeout);
|
|
21405
|
+
if (this.resource) return this.resource;
|
|
21406
|
+
if (this.failure) {
|
|
21407
|
+
throw this.failure;
|
|
21408
|
+
}
|
|
21409
|
+
throw new ResourcePreparingError();
|
|
21410
|
+
}
|
|
21411
|
+
};
|
|
21412
|
+
|
|
21363
21413
|
// src/mcp.ts
|
|
21364
21414
|
function jsonResult(payload) {
|
|
21365
21415
|
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|
|
@@ -21387,13 +21437,25 @@ function parseDate(value) {
|
|
|
21387
21437
|
}
|
|
21388
21438
|
async function runServe() {
|
|
21389
21439
|
const root = resolveCorpusDir(process.env.LLMNESIA_CORPUS_DIR);
|
|
21390
|
-
const service =
|
|
21391
|
-
|
|
21392
|
-
|
|
21393
|
-
|
|
21440
|
+
const service = new LazyResource(
|
|
21441
|
+
() => CompanionService.open(root, {
|
|
21442
|
+
// stdout is the MCP JSON-RPC channel, so diagnostics go to stderr.
|
|
21443
|
+
onDrainError: (error2) => process.stderr.write(
|
|
21444
|
+
`llmnesia: inbox drain failed, serving the existing index: ${error2 instanceof Error ? error2.message : String(error2)}
|
|
21394
21445
|
`
|
|
21395
|
-
|
|
21396
|
-
|
|
21446
|
+
)
|
|
21447
|
+
})
|
|
21448
|
+
);
|
|
21449
|
+
const withService = async (operation) => {
|
|
21450
|
+
try {
|
|
21451
|
+
return await operation(await service.get(5e3));
|
|
21452
|
+
} catch (err) {
|
|
21453
|
+
if (err instanceof ResourcePreparingError) {
|
|
21454
|
+
return errorResult("LLMnesia is still preparing the local conversation index. Retry this tool shortly.");
|
|
21455
|
+
}
|
|
21456
|
+
return errorResult(`LLMnesia could not open the local conversation index: ${err instanceof Error ? err.message : String(err)}`);
|
|
21457
|
+
}
|
|
21458
|
+
};
|
|
21397
21459
|
const server = new McpServer(
|
|
21398
21460
|
{ name: "llmnesia", version: VERSION },
|
|
21399
21461
|
{
|
|
@@ -21423,7 +21485,7 @@ async function runServe() {
|
|
|
21423
21485
|
openWorldHint: false
|
|
21424
21486
|
}
|
|
21425
21487
|
},
|
|
21426
|
-
async (args) => {
|
|
21488
|
+
async (args) => withService(async (service2) => {
|
|
21427
21489
|
const filters = {
|
|
21428
21490
|
platform: args.platform,
|
|
21429
21491
|
title: args.title,
|
|
@@ -21432,8 +21494,8 @@ async function runServe() {
|
|
|
21432
21494
|
limit: args.limit,
|
|
21433
21495
|
matchMode: args.match_mode
|
|
21434
21496
|
};
|
|
21435
|
-
const hits = await
|
|
21436
|
-
const status = await
|
|
21497
|
+
const hits = await service2.search(args.query, filters);
|
|
21498
|
+
const status = await service2.corpusStatus({ refresh: false });
|
|
21437
21499
|
return jsonResult({
|
|
21438
21500
|
count: hits.length,
|
|
21439
21501
|
corpus: corpusField(status),
|
|
@@ -21450,7 +21512,7 @@ async function runServe() {
|
|
|
21450
21512
|
messageCount: h.messageCount
|
|
21451
21513
|
}))
|
|
21452
21514
|
});
|
|
21453
|
-
}
|
|
21515
|
+
})
|
|
21454
21516
|
);
|
|
21455
21517
|
server.registerTool(
|
|
21456
21518
|
"get_conversation",
|
|
@@ -21467,8 +21529,8 @@ async function runServe() {
|
|
|
21467
21529
|
openWorldHint: false
|
|
21468
21530
|
}
|
|
21469
21531
|
},
|
|
21470
|
-
async (args) => {
|
|
21471
|
-
const record2 = await
|
|
21532
|
+
async (args) => withService(async (service2) => {
|
|
21533
|
+
const record2 = await service2.getConversation(args.id);
|
|
21472
21534
|
if (!record2) {
|
|
21473
21535
|
return errorResult(`No conversation found with id '${args.id}'.`);
|
|
21474
21536
|
}
|
|
@@ -21481,7 +21543,7 @@ async function runServe() {
|
|
|
21481
21543
|
text: m.formattedText ?? m.text
|
|
21482
21544
|
}))
|
|
21483
21545
|
});
|
|
21484
|
-
}
|
|
21546
|
+
})
|
|
21485
21547
|
);
|
|
21486
21548
|
server.registerTool(
|
|
21487
21549
|
"list_recent",
|
|
@@ -21498,9 +21560,9 @@ async function runServe() {
|
|
|
21498
21560
|
openWorldHint: false
|
|
21499
21561
|
}
|
|
21500
21562
|
},
|
|
21501
|
-
async (args) => {
|
|
21502
|
-
const entries = await
|
|
21503
|
-
const status = await
|
|
21563
|
+
async (args) => withService(async (service2) => {
|
|
21564
|
+
const entries = await service2.listRecent(args.limit ?? 10);
|
|
21565
|
+
const status = await service2.corpusStatus({ refresh: false });
|
|
21504
21566
|
return jsonResult({
|
|
21505
21567
|
count: entries.length,
|
|
21506
21568
|
corpus: corpusField(status),
|
|
@@ -21514,7 +21576,7 @@ async function runServe() {
|
|
|
21514
21576
|
summary: e.summary ?? e.preview
|
|
21515
21577
|
}))
|
|
21516
21578
|
});
|
|
21517
|
-
}
|
|
21579
|
+
})
|
|
21518
21580
|
);
|
|
21519
21581
|
server.registerTool(
|
|
21520
21582
|
"list_conversations",
|
|
@@ -21532,9 +21594,9 @@ async function runServe() {
|
|
|
21532
21594
|
openWorldHint: false
|
|
21533
21595
|
}
|
|
21534
21596
|
},
|
|
21535
|
-
async (args) => {
|
|
21536
|
-
const entries = await
|
|
21537
|
-
const status = await
|
|
21597
|
+
async (args) => withService(async (service2) => {
|
|
21598
|
+
const entries = await service2.listConversations(args.limit ?? 10, args.sort ?? "recent");
|
|
21599
|
+
const status = await service2.corpusStatus({ refresh: false });
|
|
21538
21600
|
return jsonResult({
|
|
21539
21601
|
count: entries.length,
|
|
21540
21602
|
sort: args.sort ?? "recent",
|
|
@@ -21550,7 +21612,7 @@ async function runServe() {
|
|
|
21550
21612
|
summary: e.summary ?? e.preview
|
|
21551
21613
|
}))
|
|
21552
21614
|
});
|
|
21553
|
-
}
|
|
21615
|
+
})
|
|
21554
21616
|
);
|
|
21555
21617
|
server.registerTool(
|
|
21556
21618
|
"corpus_status",
|
|
@@ -21565,10 +21627,10 @@ async function runServe() {
|
|
|
21565
21627
|
openWorldHint: false
|
|
21566
21628
|
}
|
|
21567
21629
|
},
|
|
21568
|
-
async () => {
|
|
21569
|
-
const status = await
|
|
21630
|
+
async () => withService(async (service2) => {
|
|
21631
|
+
const status = await service2.corpusStatus();
|
|
21570
21632
|
return jsonResult(status);
|
|
21571
|
-
}
|
|
21633
|
+
})
|
|
21572
21634
|
);
|
|
21573
21635
|
server.registerTool(
|
|
21574
21636
|
"save_conversation",
|
|
@@ -21583,21 +21645,29 @@ async function runServe() {
|
|
|
21583
21645
|
openWorldHint: false
|
|
21584
21646
|
}
|
|
21585
21647
|
},
|
|
21586
|
-
async (args) => {
|
|
21648
|
+
async (args) => withService(async (service2) => {
|
|
21587
21649
|
try {
|
|
21588
|
-
const result = await
|
|
21650
|
+
const result = await service2.saveConversation(args);
|
|
21589
21651
|
return jsonResult(result);
|
|
21590
21652
|
} catch (err) {
|
|
21591
21653
|
return errorResult(`save_conversation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
21592
21654
|
}
|
|
21593
|
-
}
|
|
21655
|
+
})
|
|
21594
21656
|
);
|
|
21657
|
+
server.server.oninitialized = () => service.start();
|
|
21595
21658
|
const transport = new StdioServerTransport();
|
|
21596
21659
|
await server.connect(transport);
|
|
21597
|
-
process.stderr.write(`llmnesia MCP
|
|
21660
|
+
process.stderr.write(`llmnesia MCP protocol ready; waiting for client initialization (${root})
|
|
21598
21661
|
`);
|
|
21599
21662
|
}
|
|
21600
|
-
var isMain =
|
|
21663
|
+
var isMain = (() => {
|
|
21664
|
+
if (!process.argv[1]) return false;
|
|
21665
|
+
try {
|
|
21666
|
+
return realpathSync(fileURLToPath(import.meta.url)) === realpathSync(process.argv[1]);
|
|
21667
|
+
} catch {
|
|
21668
|
+
return path.resolve(fileURLToPath(import.meta.url)) === path.resolve(process.argv[1]);
|
|
21669
|
+
}
|
|
21670
|
+
})();
|
|
21601
21671
|
if (isMain) {
|
|
21602
21672
|
runServe().catch((err) => {
|
|
21603
21673
|
process.stderr.write(`Fatal: ${err instanceof Error ? err.stack ?? err.message : String(err)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llmnesia/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"comment:mcpName": "The MCP Registry's ownership marker: it must equal server.json's `name`, and the namespace must match how you authenticate with mcp-publisher. `com.llmnesia/...` requires DNS auth (a TXT record on llmnesia.com) — see docs/MCP_INSTALLER_BOARD.md.",
|
|
@@ -39,12 +39,14 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
|
-
"build": "tsup",
|
|
42
|
+
"build": "tsup && npm run build:mcpb",
|
|
43
|
+
"build:mcpb": "node scripts/build-mcpb.mjs",
|
|
43
44
|
"prepack": "npm run build",
|
|
44
45
|
"dev": "tsx src/cli.ts",
|
|
45
46
|
"mcp": "tsx src/mcp.ts",
|
|
46
47
|
"typecheck": "tsc --noEmit",
|
|
47
|
-
"test": "vitest run"
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"test:mcpb": "node scripts/smoke-mcpb.mjs"
|
|
48
50
|
},
|
|
49
51
|
"comment:deps": "This package publishes with ZERO runtime dependencies — everything is bundled into dist by tsup (see noExternal in tsup.config.ts). That is not just an optimisation: `install` copies dist/ to ~/.llmnesia/bin so MCP clients can spawn it by absolute path, and nothing puts a node_modules beside that copy, so any unbundled import would fail there with ERR_MODULE_NOT_FOUND. Listing them as runtime deps would also be false comfort — npm would install them next to the package, not next to the copy that actually runs. The workspace packages additionally must not appear in the install graph at all: shared-types does not exist on the registry, and the published claude-code-host is an older build without the exports this package needs.",
|
|
50
52
|
"devDependencies": {
|
|
@@ -52,6 +54,7 @@
|
|
|
52
54
|
"@llmnesia/shared-types": "*",
|
|
53
55
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
54
56
|
"@types/node": "^22.13.0",
|
|
57
|
+
"adm-zip": "^0.5.18",
|
|
55
58
|
"chokidar": "^4.0.3",
|
|
56
59
|
"cross-spawn": "^7.0.6",
|
|
57
60
|
"fast-uri": "^3.1.5",
|
package/server.json
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"name": "com.llmnesia/mcp",
|
|
4
4
|
"title": "LLMnesia",
|
|
5
5
|
"description": "Search your AI chat history from Claude, Cursor, Codex, and other MCP clients.",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.12",
|
|
7
7
|
"packages": [
|
|
8
8
|
{
|
|
9
9
|
"registryType": "npm",
|
|
10
10
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
11
11
|
"identifier": "@llmnesia/mcp",
|
|
12
|
-
"version": "0.1.
|
|
12
|
+
"version": "0.1.12",
|
|
13
13
|
"transport": {
|
|
14
14
|
"type": "stdio"
|
|
15
15
|
}
|