@memly/mcp-server 0.2.6 → 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/index.js +73 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19967,7 +19967,7 @@ class MemlyClient {
|
|
|
19967
19967
|
}
|
|
19968
19968
|
|
|
19969
19969
|
// src/tools.ts
|
|
19970
|
-
function registerTools(server, client) {
|
|
19970
|
+
function registerTools(server, client, projectId) {
|
|
19971
19971
|
server.tool("load_context", [
|
|
19972
19972
|
"ALWAYS call this tool FIRST, before responding to any message in a new conversation.",
|
|
19973
19973
|
"It loads your persistent memory from previous sessions so you can provide accurate, context-aware assistance.",
|
|
@@ -19977,7 +19977,7 @@ function registerTools(server, client) {
|
|
|
19977
19977
|
}, async ({ topic }) => {
|
|
19978
19978
|
try {
|
|
19979
19979
|
const query = topic ?? "recent technical decisions architecture patterns current work";
|
|
19980
|
-
const result = await client.searchMemories(query,
|
|
19980
|
+
const result = await client.searchMemories(query, projectId, 20);
|
|
19981
19981
|
if (result.is_cold_start || result.memories.length === 0) {
|
|
19982
19982
|
return {
|
|
19983
19983
|
content: [{
|
|
@@ -20045,9 +20045,9 @@ Then answer normally. Use the memories above to inform your response.`
|
|
|
20045
20045
|
};
|
|
20046
20046
|
}
|
|
20047
20047
|
});
|
|
20048
|
-
server.tool("search_memories", "Search your stored memories semantically. Call this when you need to recall a specific previous decision, code pattern, or technical context
|
|
20048
|
+
server.tool("search_memories", "Search your stored memories semantically across ALL projects (cross-project by default). Call this when you need to recall a specific previous decision, code pattern, or technical context. Pass project_id to scope to a specific project.", {
|
|
20049
20049
|
query: exports_external.string().min(1).describe("What to search for (natural language)"),
|
|
20050
|
-
project_id: exports_external.string().uuid().optional().describe("
|
|
20050
|
+
project_id: exports_external.string().uuid().optional().describe("Scope to a specific project UUID. Omit to search across all projects."),
|
|
20051
20051
|
limit: exports_external.number().int().min(1).max(20).optional().describe("Max results (default: 5)")
|
|
20052
20052
|
}, async ({ query, project_id, limit }) => {
|
|
20053
20053
|
try {
|
|
@@ -20085,7 +20085,7 @@ ${formatted}`
|
|
|
20085
20085
|
project_id: exports_external.string().uuid().optional().describe("Associate with a specific project")
|
|
20086
20086
|
}, async ({ content, project_id }) => {
|
|
20087
20087
|
try {
|
|
20088
|
-
await client.saveMemory(content, project_id, "user");
|
|
20088
|
+
await client.saveMemory(content, project_id ?? projectId, "user");
|
|
20089
20089
|
return {
|
|
20090
20090
|
content: [{
|
|
20091
20091
|
type: "text",
|
|
@@ -20561,6 +20561,27 @@ function writeClaudeDesktop() {
|
|
|
20561
20561
|
};
|
|
20562
20562
|
}
|
|
20563
20563
|
}
|
|
20564
|
+
async function resolveProjectId(apiKey, projectRoot) {
|
|
20565
|
+
try {
|
|
20566
|
+
const pkgPath = join(projectRoot, "package.json");
|
|
20567
|
+
const fingerprint = existsSync(pkgPath) ? readFileSync(pkgPath, "utf-8").slice(0, 500) : `Project path: ${projectRoot}/src/index`;
|
|
20568
|
+
const controller = new AbortController;
|
|
20569
|
+
const timeout = setTimeout(() => controller.abort(), 8000);
|
|
20570
|
+
const res = await fetch("https://api.memly.site/v1/chat/completions", {
|
|
20571
|
+
method: "POST",
|
|
20572
|
+
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
20573
|
+
body: JSON.stringify({ model: "gpt-4.1-nano", stream: false, messages: [{ role: "user", content: fingerprint }] }),
|
|
20574
|
+
signal: controller.signal
|
|
20575
|
+
});
|
|
20576
|
+
clearTimeout(timeout);
|
|
20577
|
+
const id = res.headers.get("X-Memly-Project-Id");
|
|
20578
|
+
if (id && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id))
|
|
20579
|
+
return id;
|
|
20580
|
+
return null;
|
|
20581
|
+
} catch {
|
|
20582
|
+
return null;
|
|
20583
|
+
}
|
|
20584
|
+
}
|
|
20564
20585
|
async function reportTelemetry(results) {
|
|
20565
20586
|
try {
|
|
20566
20587
|
const controller = new AbortController;
|
|
@@ -20667,6 +20688,34 @@ async function runInit() {
|
|
|
20667
20688
|
try {
|
|
20668
20689
|
writeFileSync(join(projectRoot, ".memly-initialized"), new Date().toISOString());
|
|
20669
20690
|
} catch {}
|
|
20691
|
+
process.stdout.write(`
|
|
20692
|
+
Resolving project ID... `);
|
|
20693
|
+
const projectId = await resolveProjectId(apiKey, projectRoot);
|
|
20694
|
+
if (projectId) {
|
|
20695
|
+
try {
|
|
20696
|
+
writeFileSync(join(projectRoot, ".memly-project"), JSON.stringify({ project_id: projectId }, null, 2));
|
|
20697
|
+
console.log(`✓ ${projectId}`);
|
|
20698
|
+
const MARKER = `<!-- memly-project:${projectId} -->`;
|
|
20699
|
+
const ideFiles = [
|
|
20700
|
+
join(projectRoot, ".cursorrules"),
|
|
20701
|
+
join(projectRoot, ".github", "copilot-instructions.md"),
|
|
20702
|
+
join(projectRoot, ".clinerules"),
|
|
20703
|
+
join(projectRoot, ".windsurfrules")
|
|
20704
|
+
];
|
|
20705
|
+
for (const f of ideFiles) {
|
|
20706
|
+
if (existsSync(f)) {
|
|
20707
|
+
const content = readFileSync(f, "utf-8");
|
|
20708
|
+
if (!content.includes(MARKER)) {
|
|
20709
|
+
writeFileSync(f, content.trimEnd() + `
|
|
20710
|
+
` + MARKER + `
|
|
20711
|
+
`);
|
|
20712
|
+
}
|
|
20713
|
+
}
|
|
20714
|
+
}
|
|
20715
|
+
} catch {}
|
|
20716
|
+
} else {
|
|
20717
|
+
console.log("⊘ skipped (proxy unreachable — run init again after connecting)");
|
|
20718
|
+
}
|
|
20670
20719
|
await reportTelemetry(results);
|
|
20671
20720
|
console.log(`
|
|
20672
20721
|
â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”
|
|
@@ -20683,6 +20732,8 @@ async function runInit() {
|
|
|
20683
20732
|
}
|
|
20684
20733
|
|
|
20685
20734
|
// src/index.ts
|
|
20735
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
20736
|
+
import { join as join2 } from "node:path";
|
|
20686
20737
|
var apiKey = process.env.MEMLY_API_KEY;
|
|
20687
20738
|
if (process.argv.includes("--init") || process.argv.includes("init")) {
|
|
20688
20739
|
await runInit();
|
|
@@ -20696,6 +20747,21 @@ if (!apiKey) {
|
|
|
20696
20747
|
var apiUrl = process.env.MEMLY_API_URL ?? "https://api.memly.site";
|
|
20697
20748
|
var client = new MemlyClient(apiUrl, apiKey);
|
|
20698
20749
|
var isHttp = process.argv.includes("--http");
|
|
20750
|
+
function readProjectId() {
|
|
20751
|
+
if (process.env.MEMLY_PROJECT_ID)
|
|
20752
|
+
return process.env.MEMLY_PROJECT_ID;
|
|
20753
|
+
try {
|
|
20754
|
+
const file = join2(process.cwd(), ".memly-project");
|
|
20755
|
+
if (existsSync2(file)) {
|
|
20756
|
+
const data = JSON.parse(readFileSync2(file, "utf-8"));
|
|
20757
|
+
if (data.project_id && /^[0-9a-f-]{36}$/i.test(data.project_id)) {
|
|
20758
|
+
return data.project_id;
|
|
20759
|
+
}
|
|
20760
|
+
}
|
|
20761
|
+
} catch {}
|
|
20762
|
+
return;
|
|
20763
|
+
}
|
|
20764
|
+
var projectId = readProjectId();
|
|
20699
20765
|
if (isHttp) {
|
|
20700
20766
|
const port = Number(process.env.MEMLY_PORT ?? 3800);
|
|
20701
20767
|
const httpServer = Bun.serve({
|
|
@@ -20707,7 +20773,7 @@ if (isHttp) {
|
|
|
20707
20773
|
}
|
|
20708
20774
|
if (url.pathname === "/mcp") {
|
|
20709
20775
|
const server = new McpServer({ name: "memly", version: "0.1.0" });
|
|
20710
|
-
registerTools(server, client);
|
|
20776
|
+
registerTools(server, client, projectId);
|
|
20711
20777
|
registerResources(server, client);
|
|
20712
20778
|
registerPrompts(server, client);
|
|
20713
20779
|
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
@@ -20724,7 +20790,7 @@ if (isHttp) {
|
|
|
20724
20790
|
console.log(` Health: http://localhost:${httpServer.port}/health`);
|
|
20725
20791
|
} else {
|
|
20726
20792
|
const server = new McpServer({ name: "memly", version: "0.1.0" });
|
|
20727
|
-
registerTools(server, client);
|
|
20793
|
+
registerTools(server, client, projectId);
|
|
20728
20794
|
registerResources(server, client);
|
|
20729
20795
|
registerPrompts(server, client);
|
|
20730
20796
|
const transport = new StdioServerTransport;
|