@llmnesia/mcp 0.2.5 → 0.2.7
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/dist/{chunk-BDR4JVMF.js → chunk-CMQHGLAD.js} +1 -1
- package/dist/{chunk-MTPXE734.js → chunk-O34A5U2L.js} +41 -11
- package/dist/{cli-OXKBAUBE.js → cli-XQUMZ3BU.js} +5 -4
- package/dist/cli.js +2 -2
- package/dist/llmnesia.mcpb +0 -0
- package/dist/mcp.js +40 -9
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -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-CMQHGLAD.js";
|
|
7
7
|
|
|
8
8
|
// src/config.ts
|
|
9
9
|
import { readFileSync } from "fs";
|
|
@@ -13,14 +13,22 @@ var CORPUS_FORMAT_VERSION = 2;
|
|
|
13
13
|
function nativeHostConfigPath() {
|
|
14
14
|
return join(homedir(), ".llmnesia", "config.json");
|
|
15
15
|
}
|
|
16
|
-
function
|
|
16
|
+
function readNativeHostConfig() {
|
|
17
17
|
try {
|
|
18
18
|
const parsed = JSON.parse(readFileSync(nativeHostConfigPath(), "utf8"));
|
|
19
|
-
return typeof parsed
|
|
19
|
+
return parsed && typeof parsed === "object" ? parsed : void 0;
|
|
20
20
|
} catch {
|
|
21
21
|
return void 0;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
function readNativeHostCorpusRoot() {
|
|
25
|
+
const root = readNativeHostConfig()?.corpusRoot;
|
|
26
|
+
return typeof root === "string" ? root : void 0;
|
|
27
|
+
}
|
|
28
|
+
function readNativeHostViewerExtensionId() {
|
|
29
|
+
const id = readNativeHostConfig()?.viewerExtensionId;
|
|
30
|
+
return typeof id === "string" ? id : void 0;
|
|
31
|
+
}
|
|
24
32
|
function resolveCorpusDir(explicit) {
|
|
25
33
|
const raw = explicit ?? process.env.LLMNESIA_CORPUS_DIR ?? readNativeHostCorpusRoot() ?? "~/.llmnesia/corpus";
|
|
26
34
|
return expandHome(raw);
|
|
@@ -39,7 +47,7 @@ function expandHome(p) {
|
|
|
39
47
|
import { join as join2 } from "path";
|
|
40
48
|
import { readdir } from "fs/promises";
|
|
41
49
|
import { createHash } from "crypto";
|
|
42
|
-
var INDEX_FORMAT_VERSION =
|
|
50
|
+
var INDEX_FORMAT_VERSION = 4;
|
|
43
51
|
function indexDbFilename(version) {
|
|
44
52
|
return version === 1 ? "llmnesia.db" : `llmnesia-v${version}.db`;
|
|
45
53
|
}
|
|
@@ -200,6 +208,8 @@ function canonicalConversationDoc(c) {
|
|
|
200
208
|
assignIfDefined(out, "origin", c.origin);
|
|
201
209
|
assignIfDefined(out, "accountId", c.accountId);
|
|
202
210
|
assignIfDefined(out, "accountLabel", c.accountLabel);
|
|
211
|
+
if (c.models && c.models.length > 0) out.models = [...c.models];
|
|
212
|
+
assignIfDefined(out, "modelMetadataUpdatedAt", c.modelMetadataUpdatedAt);
|
|
203
213
|
if (c.summary) {
|
|
204
214
|
out.summary = {
|
|
205
215
|
text: c.summary.text,
|
|
@@ -219,6 +229,7 @@ function canonicalMessageDoc(m) {
|
|
|
219
229
|
text: m.text
|
|
220
230
|
};
|
|
221
231
|
assignIfDefined(out, "formattedText", m.formattedText);
|
|
232
|
+
assignIfDefined(out, "model", m.model);
|
|
222
233
|
out.createdAt = m.createdAt;
|
|
223
234
|
out.updatedAt = m.updatedAt;
|
|
224
235
|
out.contentHash = m.contentHash;
|
|
@@ -896,6 +907,9 @@ function coerceMessage(docId, value) {
|
|
|
896
907
|
if (typeof m.formattedText === "string") {
|
|
897
908
|
message.formattedText = m.formattedText;
|
|
898
909
|
}
|
|
910
|
+
if (typeof m.model === "string" && m.model.trim()) {
|
|
911
|
+
message.model = m.model.trim();
|
|
912
|
+
}
|
|
899
913
|
if (typeof m.platformMessageId === "string") {
|
|
900
914
|
message.platformMessageId = m.platformMessageId;
|
|
901
915
|
} else if (m.platformMessageId === null) {
|
|
@@ -1000,7 +1014,8 @@ CREATE TABLE IF NOT EXISTS conversations (
|
|
|
1000
1014
|
preview TEXT NOT NULL,
|
|
1001
1015
|
pinned INTEGER NOT NULL,
|
|
1002
1016
|
accountId TEXT,
|
|
1003
|
-
accountLabel TEXT
|
|
1017
|
+
accountLabel TEXT,
|
|
1018
|
+
models TEXT
|
|
1004
1019
|
);
|
|
1005
1020
|
CREATE INDEX IF NOT EXISTS idx_conversations_platform ON conversations(platform);
|
|
1006
1021
|
CREATE INDEX IF NOT EXISTS idx_conversations_createdAt ON conversations(createdAt);
|
|
@@ -1074,8 +1089,8 @@ var SearchIndex = class {
|
|
|
1074
1089
|
deleteConversation: this.db.prepare("DELETE FROM conversations WHERE docId = ?"),
|
|
1075
1090
|
insertConversation: this.db.prepare(
|
|
1076
1091
|
`INSERT INTO conversations
|
|
1077
|
-
(docId, platform, title, url, createdAt, updatedAt, messageCount, preview, pinned, accountId, accountLabel)
|
|
1078
|
-
VALUES (@docId, @platform, @title, @url, @createdAt, @updatedAt, @messageCount, @preview, @pinned, @accountId, @accountLabel)`
|
|
1092
|
+
(docId, platform, title, url, createdAt, updatedAt, messageCount, preview, pinned, accountId, accountLabel, models)
|
|
1093
|
+
VALUES (@docId, @platform, @title, @url, @createdAt, @updatedAt, @messageCount, @preview, @pinned, @accountId, @accountLabel, @models)`
|
|
1079
1094
|
),
|
|
1080
1095
|
deleteMemoryFts: this.db.prepare("DELETE FROM memories_fts WHERE memoryId = ?"),
|
|
1081
1096
|
insertMemoryFts: this.db.prepare(
|
|
@@ -1119,14 +1134,16 @@ var SearchIndex = class {
|
|
|
1119
1134
|
const orderBy = sort === "oldest" ? "createdAt ASC, updatedAt ASC" : sort === "newest" ? "createdAt DESC, updatedAt DESC" : "updatedAt DESC, createdAt DESC";
|
|
1120
1135
|
const rows = this.db.prepare(
|
|
1121
1136
|
`SELECT docId, platform, title, url, createdAt, updatedAt, messageCount, preview, pinned,
|
|
1122
|
-
accountId, accountLabel
|
|
1137
|
+
accountId, accountLabel, models
|
|
1123
1138
|
FROM conversations ORDER BY ${orderBy} LIMIT ?`
|
|
1124
1139
|
).all(limit);
|
|
1125
1140
|
return rows.map((r) => {
|
|
1126
|
-
const { accountId, accountLabel, ...rest } = r;
|
|
1141
|
+
const { accountId, accountLabel, models, ...rest } = r;
|
|
1127
1142
|
const entry = { ...rest, pinned: r.pinned === 1 };
|
|
1128
1143
|
if (accountId) entry.accountId = accountId;
|
|
1129
1144
|
if (accountLabel) entry.accountLabel = accountLabel;
|
|
1145
|
+
const parsedModels = parseModels(models);
|
|
1146
|
+
if (parsedModels.length > 0) entry.models = parsedModels;
|
|
1130
1147
|
return entry;
|
|
1131
1148
|
});
|
|
1132
1149
|
}
|
|
@@ -1213,7 +1230,8 @@ var SearchIndex = class {
|
|
|
1213
1230
|
preview: conversation.preview ?? "",
|
|
1214
1231
|
pinned: conversation.pinned ? 1 : 0,
|
|
1215
1232
|
accountId: conversation.accountId ?? null,
|
|
1216
|
-
accountLabel: conversation.accountLabel ?? null
|
|
1233
|
+
accountLabel: conversation.accountLabel ?? null,
|
|
1234
|
+
models: conversation.models?.length ? JSON.stringify(conversation.models) : null
|
|
1217
1235
|
});
|
|
1218
1236
|
}
|
|
1219
1237
|
insertFtsRow(docId, msgIndex, role, text) {
|
|
@@ -1278,7 +1296,7 @@ var SearchIndex = class {
|
|
|
1278
1296
|
const sql = `
|
|
1279
1297
|
SELECT
|
|
1280
1298
|
c.docId, c.platform, c.title, c.url, c.createdAt, c.updatedAt,
|
|
1281
|
-
c.messageCount, c.preview, c.pinned, c.accountId, c.accountLabel,
|
|
1299
|
+
c.messageCount, c.preview, c.pinned, c.accountId, c.accountLabel, c.models,
|
|
1282
1300
|
m.msgIndex AS msgIndex, m.role AS role,
|
|
1283
1301
|
bm25(messages_fts) AS bm25
|
|
1284
1302
|
FROM messages_fts
|
|
@@ -1314,6 +1332,8 @@ var SearchIndex = class {
|
|
|
1314
1332
|
};
|
|
1315
1333
|
if (row.accountId) hit.accountId = row.accountId;
|
|
1316
1334
|
if (row.accountLabel) hit.accountLabel = row.accountLabel;
|
|
1335
|
+
const models = parseModels(row.models);
|
|
1336
|
+
if (models.length > 0) hit.models = models;
|
|
1317
1337
|
hits.push(hit);
|
|
1318
1338
|
if (hits.length >= limit) {
|
|
1319
1339
|
break;
|
|
@@ -1394,6 +1414,15 @@ function normalizeMatchRole(role) {
|
|
|
1394
1414
|
}
|
|
1395
1415
|
return role === "assistant" || role === "user" || role === "system" ? role : "unknown";
|
|
1396
1416
|
}
|
|
1417
|
+
function parseModels(value) {
|
|
1418
|
+
if (!value) return [];
|
|
1419
|
+
try {
|
|
1420
|
+
const parsed = JSON.parse(value);
|
|
1421
|
+
return Array.isArray(parsed) ? parsed.filter((model) => typeof model === "string" && model.trim().length > 0) : [];
|
|
1422
|
+
} catch {
|
|
1423
|
+
return [];
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1397
1426
|
|
|
1398
1427
|
// src/storageMaintenance.ts
|
|
1399
1428
|
import { promises as fs4 } from "fs";
|
|
@@ -2063,6 +2092,7 @@ function describeOutcome(outcome) {
|
|
|
2063
2092
|
}
|
|
2064
2093
|
|
|
2065
2094
|
export {
|
|
2095
|
+
readNativeHostViewerExtensionId,
|
|
2066
2096
|
resolveCorpusDir,
|
|
2067
2097
|
staleIndexFiles,
|
|
2068
2098
|
Corpus,
|
|
@@ -17,13 +17,13 @@ import {
|
|
|
17
17
|
runtimeBinDir,
|
|
18
18
|
staleIndexFiles,
|
|
19
19
|
uninstallRuntime
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-O34A5U2L.js";
|
|
21
21
|
import {
|
|
22
22
|
VERSION,
|
|
23
23
|
__commonJS,
|
|
24
24
|
__require,
|
|
25
25
|
__toESM
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-CMQHGLAD.js";
|
|
27
27
|
|
|
28
28
|
// ../node_modules/isexe/windows.js
|
|
29
29
|
var require_windows = __commonJS({
|
|
@@ -687,6 +687,7 @@ async function installNativeHost({ ids = [], corpus, codexHome, force = false, q
|
|
|
687
687
|
}
|
|
688
688
|
const allIds = [.../* @__PURE__ */ new Set([STORE_EXTENSION_ID, ...ids])];
|
|
689
689
|
const allowedOrigins = allIds.map((id) => `chrome-extension://${id}/`);
|
|
690
|
+
const viewerExtensionId = ids[0] ?? STORE_EXTENSION_ID;
|
|
690
691
|
if (await supportedBrowserCount(isWindows2) === 0) {
|
|
691
692
|
throw new Error(
|
|
692
693
|
"LLMnesia couldn't find Chrome, Brave, Edge, or Chromium. Open your browser once so it creates a profile, then retry. Safari and Firefox are not supported yet. Nothing was installed."
|
|
@@ -720,7 +721,7 @@ async function installNativeHost({ ids = [], corpus, codexHome, force = false, q
|
|
|
720
721
|
corpusRootChanged = false;
|
|
721
722
|
await writeFile(
|
|
722
723
|
configPath,
|
|
723
|
-
`${JSON.stringify({ ...existing, corpusRoot: existingRoot, codexHome: resolvedCodexHome }, null, 2)}
|
|
724
|
+
`${JSON.stringify({ ...existing, corpusRoot: existingRoot, codexHome: resolvedCodexHome, viewerExtensionId }, null, 2)}
|
|
724
725
|
`,
|
|
725
726
|
{ encoding: "utf8", mode: 384 }
|
|
726
727
|
);
|
|
@@ -732,7 +733,7 @@ async function installNativeHost({ ids = [], corpus, codexHome, force = false, q
|
|
|
732
733
|
} else {
|
|
733
734
|
await writeFile(
|
|
734
735
|
configPath,
|
|
735
|
-
`${JSON.stringify({ ...existing ?? {}, corpusRoot, codexHome: resolvedCodexHome }, null, 2)}
|
|
736
|
+
`${JSON.stringify({ ...existing ?? {}, corpusRoot, codexHome: resolvedCodexHome, viewerExtensionId }, null, 2)}
|
|
736
737
|
`,
|
|
737
738
|
{ encoding: "utf8", mode: 384 }
|
|
738
739
|
);
|
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-CMQHGLAD.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-XQUMZ3BU.js");
|
|
145
145
|
return main();
|
|
146
146
|
}
|
|
147
147
|
bootstrap().then((code) => {
|
package/dist/llmnesia.mcpb
CHANGED
|
Binary file
|
package/dist/mcp.js
CHANGED
|
@@ -8,16 +8,17 @@ import {
|
|
|
8
8
|
drainInbox,
|
|
9
9
|
openSearchIndex,
|
|
10
10
|
pendingInboxFiles,
|
|
11
|
+
readNativeHostViewerExtensionId,
|
|
11
12
|
resolveCorpusDir,
|
|
12
13
|
runAutomaticMaintenance,
|
|
13
14
|
scheduleSelfUpdate
|
|
14
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-O34A5U2L.js";
|
|
15
16
|
import {
|
|
16
17
|
VERSION,
|
|
17
18
|
__commonJS,
|
|
18
19
|
__export,
|
|
19
20
|
__toESM
|
|
20
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-CMQHGLAD.js";
|
|
21
22
|
|
|
22
23
|
// ../node_modules/ajv/dist/compile/codegen/code.js
|
|
23
24
|
var require_code = __commonJS({
|
|
@@ -21677,7 +21678,27 @@ var LazyResource = class {
|
|
|
21677
21678
|
function jsonResult(payload) {
|
|
21678
21679
|
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|
|
21679
21680
|
}
|
|
21680
|
-
var SOURCE_LINK_INSTRUCTION = "When answering from these conversations, always include a Sources section with a clickable Markdown link to every
|
|
21681
|
+
var SOURCE_LINK_INSTRUCTION = "When answering from these conversations, always include a Sources section with a clickable Markdown link to every chat you relied on. Link its `sourceUrl`: this is the original chat URL when available, otherwise an HTTPS hand-off that opens the local LLMnesia Viewer without sending the conversation id to the website. Do this automatically; do not wait for the user to ask for links.";
|
|
21682
|
+
var STORE_EXTENSION_ID = "leekfgbdojiaabifbjbbgiiclannjdkf";
|
|
21683
|
+
var EXTENSION_ID_RE = /^[a-p]{32}$/;
|
|
21684
|
+
var VIEWER_HANDOFF_URL = "https://llmnesia.com/open";
|
|
21685
|
+
function viewerExtensionId() {
|
|
21686
|
+
const configured = process.env.LLMNESIA_VIEWER_EXTENSION_ID?.trim() ?? readNativeHostViewerExtensionId();
|
|
21687
|
+
return configured && EXTENSION_ID_RE.test(configured) ? configured : STORE_EXTENSION_ID;
|
|
21688
|
+
}
|
|
21689
|
+
function viewerSourceUrl(docId, extensionId) {
|
|
21690
|
+
const fragment = new URLSearchParams({ docId, extensionId });
|
|
21691
|
+
return `${VIEWER_HANDOFF_URL}#${fragment.toString()}`;
|
|
21692
|
+
}
|
|
21693
|
+
function sourceLinks(docId, originalUrl) {
|
|
21694
|
+
const extensionId = viewerExtensionId();
|
|
21695
|
+
const localViewerUrl = `chrome-extension://${extensionId}/viewer.html?docId=${encodeURIComponent(docId)}`;
|
|
21696
|
+
return originalUrl ? { viewerUrl: localViewerUrl, sourceUrl: originalUrl, sourceKind: "original" } : {
|
|
21697
|
+
viewerUrl: localViewerUrl,
|
|
21698
|
+
sourceUrl: viewerSourceUrl(docId, extensionId),
|
|
21699
|
+
sourceKind: "viewer"
|
|
21700
|
+
};
|
|
21701
|
+
}
|
|
21681
21702
|
function sourcedJsonResult(payload) {
|
|
21682
21703
|
return jsonResult({ responseInstruction: SOURCE_LINK_INSTRUCTION, ...payload });
|
|
21683
21704
|
}
|
|
@@ -21743,14 +21764,14 @@ async function runServe() {
|
|
|
21743
21764
|
const server = new McpServer(
|
|
21744
21765
|
{ name: "llmnesia", version: VERSION },
|
|
21745
21766
|
{
|
|
21746
|
-
instructions: "LLMnesia is the user's searchable archive of past AI chats. Whenever the user asks about 'my chats', 'my conversations', or anything they previously said, discussed, decided, or worked on, use LLMnesia before built-in task/thread lists, local file scans, or memory, unless they explicitly ask only about Codex tasks. Use list_conversations with sort='oldest' for their earliest chat, search_conversations to find relevant prior chats, get_conversation to read a full transcript, and list_recent to see what they worked on lately. Search and list results carry a `corpus` block saying when the corpus last received data; if a chat the user expects is missing, check corpus_status before concluding it does not exist. Whenever you answer using LLMnesia, always include a Sources section with clickable links to the
|
|
21767
|
+
instructions: "LLMnesia is the user's searchable archive of past AI chats. Whenever the user asks about 'my chats', 'my conversations', or anything they previously said, discussed, decided, or worked on, use LLMnesia before built-in task/thread lists, local file scans, or memory, unless they explicitly ask only about Codex tasks. Use list_conversations with sort='oldest' for their earliest chat, search_conversations to find relevant prior chats, get_conversation to read a full transcript, and list_recent to see what they worked on lately. Search and list results carry a `corpus` block saying when the corpus last received data; if a chat the user expects is missing, check corpus_status before concluding it does not exist. Whenever you answer using LLMnesia, always include a Sources section with clickable links to the chats you used. Link each result's `sourceUrl`, which is its original URL when available or a clickable HTTPS hand-off to its local LLMnesia Viewer otherwise; never wait for the user to ask."
|
|
21747
21768
|
}
|
|
21748
21769
|
);
|
|
21749
21770
|
server.registerTool(
|
|
21750
21771
|
"search_conversations",
|
|
21751
21772
|
{
|
|
21752
21773
|
title: "Search conversations",
|
|
21753
|
-
description: "Full-text search across the user's past AI conversations. Call this whenever the user asks what they said, thought, discussed, decided, or worked on previously \u2014 even if the question doesn't say 'search' \u2014 rather than answering from conversation memory alone or claiming no record exists. Returns matching conversations with a highlighted snippet, ranked by relevance. Defaults to recall-first matching (any term); pass match_mode to answer questions where a wrong hit matters, such as whether or how often something was discussed. Every result includes
|
|
21774
|
+
description: "Full-text search across the user's past AI conversations. Call this whenever the user asks what they said, thought, discussed, decided, or worked on previously \u2014 even if the question doesn't say 'search' \u2014 rather than answering from conversation memory alone or claiming no record exists. Returns matching conversations with a highlighted snippet, ranked by relevance. Defaults to recall-first matching (any term); pass match_mode to answer questions where a wrong hit matters, such as whether or how often something was discussed. Every result includes `sourceUrl`: the original chat URL when available, otherwise a clickable HTTPS hand-off to its local LLMnesia Viewer. Always link the chats used in the answer.",
|
|
21754
21775
|
inputSchema: {
|
|
21755
21776
|
query: external_exports.string().describe("Search terms (natural words; FTS operators are not needed)."),
|
|
21756
21777
|
match_mode: external_exports.enum(["any", "all", "phrase"]).optional().describe(
|
|
@@ -21789,6 +21810,7 @@ async function runServe() {
|
|
|
21789
21810
|
title: h.title,
|
|
21790
21811
|
platform: h.platform,
|
|
21791
21812
|
url: h.url,
|
|
21813
|
+
...sourceLinks(h.docId, h.url),
|
|
21792
21814
|
createdAt: h.createdAt,
|
|
21793
21815
|
score: Number(h.score.toFixed(4)),
|
|
21794
21816
|
snippet: h.snippet,
|
|
@@ -21798,6 +21820,7 @@ async function runServe() {
|
|
|
21798
21820
|
};
|
|
21799
21821
|
if (h.accountId) entry.accountId = h.accountId;
|
|
21800
21822
|
if (h.accountLabel) entry.accountLabel = h.accountLabel;
|
|
21823
|
+
if (h.models?.length) entry.models = h.models;
|
|
21801
21824
|
return entry;
|
|
21802
21825
|
})
|
|
21803
21826
|
});
|
|
@@ -21807,7 +21830,7 @@ async function runServe() {
|
|
|
21807
21830
|
"get_conversation",
|
|
21808
21831
|
{
|
|
21809
21832
|
title: "Get conversation",
|
|
21810
|
-
description: "Return the full transcript of one conversation by its id (the `id` from search results). The conversation includes its original-chat URL when available
|
|
21833
|
+
description: "Return the full transcript of one conversation by its id (the `id` from search results). The conversation includes `sourceUrl`: its original-chat URL when available, otherwise a clickable HTTPS hand-off to its local LLMnesia Viewer. Always link it in an answer based on this transcript.",
|
|
21811
21834
|
inputSchema: {
|
|
21812
21835
|
id: external_exports.string().describe("The conversation id (docId), e.g. 'claude:abc-123'.")
|
|
21813
21836
|
},
|
|
@@ -21824,10 +21847,14 @@ async function runServe() {
|
|
|
21824
21847
|
return errorResult(`No conversation found with id '${args.id}'.`);
|
|
21825
21848
|
}
|
|
21826
21849
|
return sourcedJsonResult({
|
|
21827
|
-
conversation:
|
|
21850
|
+
conversation: {
|
|
21851
|
+
...record2.conversation,
|
|
21852
|
+
...sourceLinks(record2.conversation.docId, record2.conversation.url)
|
|
21853
|
+
},
|
|
21828
21854
|
messages: record2.messages.map((m) => ({
|
|
21829
21855
|
index: m.msgIndex,
|
|
21830
21856
|
role: m.role,
|
|
21857
|
+
...m.model ? { model: m.model } : {},
|
|
21831
21858
|
// Prefer the block-formatted copy; fall back to the search-collapsed text.
|
|
21832
21859
|
text: m.formattedText ?? m.text
|
|
21833
21860
|
}))
|
|
@@ -21838,7 +21865,7 @@ async function runServe() {
|
|
|
21838
21865
|
"list_recent",
|
|
21839
21866
|
{
|
|
21840
21867
|
title: "List recent conversations",
|
|
21841
|
-
description: "List the user's most recently updated conversations (title + summary +
|
|
21868
|
+
description: "List the user's most recently updated conversations (title + summary + source URL), newest first. `sourceUrl` is the original chat URL when available, otherwise a clickable HTTPS hand-off to its local LLMnesia Viewer. Always link the chats used in the answer.",
|
|
21842
21869
|
inputSchema: {
|
|
21843
21870
|
limit: external_exports.number().int().min(1).max(100).optional().describe("How many to return (default 10).")
|
|
21844
21871
|
},
|
|
@@ -21861,6 +21888,7 @@ async function runServe() {
|
|
|
21861
21888
|
title: e.title,
|
|
21862
21889
|
platform: e.platform,
|
|
21863
21890
|
url: e.url,
|
|
21891
|
+
...sourceLinks(e.docId, e.url),
|
|
21864
21892
|
updatedAt: e.updatedAt,
|
|
21865
21893
|
messageCount: e.messageCount,
|
|
21866
21894
|
pinned: e.pinned,
|
|
@@ -21868,6 +21896,7 @@ async function runServe() {
|
|
|
21868
21896
|
};
|
|
21869
21897
|
if (e.accountId) entry.accountId = e.accountId;
|
|
21870
21898
|
if (e.accountLabel) entry.accountLabel = e.accountLabel;
|
|
21899
|
+
if (e.models?.length) entry.models = e.models;
|
|
21871
21900
|
return entry;
|
|
21872
21901
|
})
|
|
21873
21902
|
});
|
|
@@ -21877,7 +21906,7 @@ async function runServe() {
|
|
|
21877
21906
|
"list_conversations",
|
|
21878
21907
|
{
|
|
21879
21908
|
title: "List conversations by date",
|
|
21880
|
-
description: "List conversation metadata in chronological order. Use sort='oldest' for the user's earliest or oldest chat, sort='newest' for most recently created chats, and sort='recent' for most recently updated chats. This is the complete corpus chronology, so do not scan LLMnesia's private files with shell commands. Entries include original
|
|
21909
|
+
description: "List conversation metadata in chronological order. Use sort='oldest' for the user's earliest or oldest chat, sort='newest' for most recently created chats, and sort='recent' for most recently updated chats. This is the complete corpus chronology, so do not scan LLMnesia's private files with shell commands. Entries include `sourceUrl`: the original chat URL when available, otherwise a clickable HTTPS hand-off to the local LLMnesia Viewer. Always link the chats used in the answer.",
|
|
21881
21910
|
inputSchema: {
|
|
21882
21911
|
sort: external_exports.enum(["recent", "oldest", "newest"]).optional().describe("Chronology: recent (default, updated), oldest (created), or newest (created)."),
|
|
21883
21912
|
limit: external_exports.number().int().min(1).max(100).optional().describe("How many to return (default 10).")
|
|
@@ -21902,6 +21931,7 @@ async function runServe() {
|
|
|
21902
21931
|
title: e.title,
|
|
21903
21932
|
platform: e.platform,
|
|
21904
21933
|
url: e.url,
|
|
21934
|
+
...sourceLinks(e.docId, e.url),
|
|
21905
21935
|
createdAt: e.createdAt,
|
|
21906
21936
|
updatedAt: e.updatedAt,
|
|
21907
21937
|
messageCount: e.messageCount,
|
|
@@ -21910,6 +21940,7 @@ async function runServe() {
|
|
|
21910
21940
|
};
|
|
21911
21941
|
if (e.accountId) entry.accountId = e.accountId;
|
|
21912
21942
|
if (e.accountLabel) entry.accountLabel = e.accountLabel;
|
|
21943
|
+
if (e.models?.length) entry.models = e.models;
|
|
21913
21944
|
return entry;
|
|
21914
21945
|
})
|
|
21915
21946
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llmnesia/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
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.",
|
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.2.
|
|
6
|
+
"version": "0.2.7",
|
|
7
7
|
"packages": [
|
|
8
8
|
{
|
|
9
9
|
"registryType": "npm",
|
|
10
10
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
11
11
|
"identifier": "@llmnesia/mcp",
|
|
12
|
-
"version": "0.2.
|
|
12
|
+
"version": "0.2.7",
|
|
13
13
|
"transport": {
|
|
14
14
|
"type": "stdio"
|
|
15
15
|
}
|