Skip to content

Commit caa9f52

Browse files
authored
fix(plugin): inherit AGENTMEMORY_URL/SECRET via env passthrough (#375) (#460)
The bundled plugin .mcp.json + the `agentmemory connect <agent>` wiring both hardcoded the MCP server to localhost:3111 with no env-var seam. Users running agentmemory remotely (k8s cluster-internal DNS, reverse proxy with API key auth) hit a permanent /doctor warning because they had to add a second entry with the right AGENTMEMORY_URL + SECRET, and both entries fought for the "agentmemory" name. Both files now use ${AGENTMEMORY_URL} / ${AGENTMEMORY_SECRET} expansion. Host (Claude Code, Cursor, etc.) substitutes the shell value at MCP-server launch; when vars are unset the host passes empty string, which the standalone shim treats as missing and falls back to http://localhost:3111. One wired entry now covers both local and remote without duplicates. - plugin/.mcp.json: env block added with ${VAR} expansion - src/cli/connect/util.ts: AGENTMEMORY_MCP_BLOCK env updated; comment documents the empty-string fallback contract - test/cli-connect.test.ts: regression test asserting the env block shape after install() — protects against future regressions where the literal hardcoded URL leaks back in 1008/1008 tests pass.
1 parent abeec1d commit caa9f52

3 files changed

Lines changed: 35 additions & 2 deletions

File tree

plugin/.mcp.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
"mcpServers": {
33
"agentmemory": {
44
"command": "npx",
5-
"args": ["-y", "@agentmemory/mcp"]
5+
"args": ["-y", "@agentmemory/mcp"],
6+
"env": {
7+
"AGENTMEMORY_URL": "${AGENTMEMORY_URL}",
8+
"AGENTMEMORY_SECRET": "${AGENTMEMORY_SECRET}"
9+
}
610
}
711
}
812
}

src/cli/connect/util.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,19 @@ import { dirname, join } from "node:path";
1010
import { homedir } from "node:os";
1111
import * as p from "@clack/prompts";
1212

13+
// Env values use ${VAR} expansion so the wired MCP entry inherits
14+
// AGENTMEMORY_URL / AGENTMEMORY_SECRET from the user's shell. When the
15+
// vars are unset, the host (Claude Code, Cursor, etc.) substitutes an
16+
// empty string; the standalone shim treats empty as missing and falls
17+
// back to http://localhost:3111. This lets a single wired entry serve
18+
// both local and remote (Kubernetes / reverse-proxied) deployments
19+
// without doctor-warning duplicates (#375).
1320
export const AGENTMEMORY_MCP_BLOCK = {
1421
command: "npx",
1522
args: ["-y", "@agentmemory/mcp"],
1623
env: {
17-
AGENTMEMORY_URL: "http://localhost:3111",
24+
AGENTMEMORY_URL: "${AGENTMEMORY_URL}",
25+
AGENTMEMORY_SECRET: "${AGENTMEMORY_SECRET}",
1826
},
1927
};
2028

test/cli-connect.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,27 @@ describe("agentmemory connect — claude-code adapter (mock filesystem)", () =>
112112
expect(second.kind).toBe("already-wired");
113113
});
114114

115+
it("install() writes env passthrough block for AGENTMEMORY_URL + AGENTMEMORY_SECRET (#375)", async () => {
116+
// Remote deployments (k8s, reverse proxy) set AGENTMEMORY_URL +
117+
// AGENTMEMORY_SECRET in the shell. The wired MCP entry must honour
118+
// those via ${VAR} expansion so a single entry covers both local
119+
// and remote without the user needing to add a duplicate config
120+
// that triggers a /doctor duplicate-server warning.
121+
const claudeDir = join(tmpHome, ".claude");
122+
require("node:fs").mkdirSync(claudeDir, { recursive: true });
123+
writeFileSync(join(tmpHome, ".claude.json"), JSON.stringify({}));
124+
125+
const a = await loadAdapter();
126+
const result = await a.install({ dryRun: false, force: false });
127+
expect(result.kind).toBe("installed");
128+
129+
const config = JSON.parse(readFileSync(join(tmpHome, ".claude.json"), "utf-8"));
130+
const entry = config.mcpServers.agentmemory;
131+
expect(entry.env).toBeDefined();
132+
expect(entry.env.AGENTMEMORY_URL).toBe("${AGENTMEMORY_URL}");
133+
expect(entry.env.AGENTMEMORY_SECRET).toBe("${AGENTMEMORY_SECRET}");
134+
});
135+
115136
it("install() with --force re-writes even when already wired", async () => {
116137
require("node:fs").mkdirSync(join(tmpHome, ".claude"), { recursive: true });
117138
writeFileSync(

0 commit comments

Comments
 (0)