@pyxmate/memory 1.0.1 → 1.1.1

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.
Files changed (2) hide show
  1. package/dist/cli/pyx-mem.mjs +148 -55
  2. package/package.json +1 -1
@@ -563,9 +563,91 @@ function createReadCredentials(providerFactory) {
563
563
  };
564
564
  }
565
565
 
566
+ // src/mcp/proxy-server.ts
567
+ import { Client as McpClient } from "@modelcontextprotocol/sdk/client/index.js";
568
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
569
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
570
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
571
+ import {
572
+ CallToolRequestSchema,
573
+ GetPromptRequestSchema,
574
+ ListPromptsRequestSchema,
575
+ ListToolsRequestSchema
576
+ } from "@modelcontextprotocol/sdk/types.js";
577
+ var REMOTE_MCP_PATH = "/mcp";
578
+ function createProxyServer(client, version) {
579
+ const caps = client.getServerCapabilities();
580
+ const server = new Server(client.getServerVersion() ?? { name: "pyx-memory", version }, {
581
+ capabilities: {
582
+ // Advertise the PRESENCE of tools/prompts, but NOT their `listChanged`
583
+ // sub-capability: this proxy does not relay the remote's list_changed
584
+ // notifications, so claiming listChanged would be a capability the host
585
+ // could rely on but we never honor (Codex: keep the proxy transparent).
586
+ ...caps?.tools ? { tools: {} } : {},
587
+ ...caps?.prompts ? { prompts: {} } : {}
588
+ },
589
+ instructions: client.getInstructions()
590
+ });
591
+ if (caps?.tools) {
592
+ server.setRequestHandler(
593
+ ListToolsRequestSchema,
594
+ (req) => client.listTools(req.params)
595
+ );
596
+ server.setRequestHandler(
597
+ CallToolRequestSchema,
598
+ (req) => client.callTool(req.params)
599
+ );
600
+ }
601
+ if (caps?.prompts) {
602
+ server.setRequestHandler(
603
+ ListPromptsRequestSchema,
604
+ (req) => client.listPrompts(req.params)
605
+ );
606
+ server.setRequestHandler(
607
+ GetPromptRequestSchema,
608
+ (req) => client.getPrompt(req.params)
609
+ );
610
+ }
611
+ return server;
612
+ }
613
+ async function runMcpProxyServer(opts) {
614
+ const version = opts.version ?? (true ? "1.1.1" : "0.0.0-dev");
615
+ const read = await opts.readCredentials();
616
+ if (!read.ok) {
617
+ const text = read.result.content.map((c) => c.type === "text" ? c.text : "").join(" ").trim();
618
+ throw new Error(text || "pyx-memory credentials are unavailable. Run: pyx-mem login");
619
+ }
620
+ const { endpoint, apiKey } = read.credentials;
621
+ const url = new URL(`${endpoint.replace(/\/+$/, "")}${REMOTE_MCP_PATH}`);
622
+ const client = new McpClient({ name: "pyx-mem-proxy", version }, { capabilities: {} });
623
+ const clientTransport = new StreamableHTTPClientTransport(url, {
624
+ requestInit: { headers: { Authorization: `Bearer ${apiKey}` } }
625
+ });
626
+ try {
627
+ await client.connect(clientTransport);
628
+ } catch (err) {
629
+ const msg = err instanceof Error ? err.message : String(err);
630
+ throw new Error(
631
+ `Could not reach the pyx-memory remote MCP at ${url.href}: ${msg}. Verify the endpoint and key with \`pyx-mem doctor\`, or run the bundled server with \`pyx-mem mcp\`.`
632
+ );
633
+ }
634
+ try {
635
+ const server = createProxyServer(client, version);
636
+ const transport = new StdioServerTransport();
637
+ const closed = new Promise((resolve3) => {
638
+ transport.onclose = () => resolve3();
639
+ });
640
+ await server.connect(transport);
641
+ await closed;
642
+ } finally {
643
+ await client.close().catch(() => {
644
+ });
645
+ }
646
+ }
647
+
566
648
  // src/mcp/server.ts
567
649
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
568
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
650
+ import { StdioServerTransport as StdioServerTransport2 } from "@modelcontextprotocol/sdk/server/stdio.js";
569
651
 
570
652
  // src/mcp/prompts/index.ts
571
653
  import { z } from "zod";
@@ -1377,7 +1459,7 @@ var ALL_TOOL_NAMES = ALL_TOOLS.map((t) => t.name);
1377
1459
  // src/mcp/server.ts
1378
1460
  async function runMcpServer(opts) {
1379
1461
  const fetchImpl = opts.fetchImpl ?? fetch;
1380
- const version = opts.version ?? (true ? "1.0.1" : "0.0.0-dev");
1462
+ const version = opts.version ?? (true ? "1.1.1" : "0.0.0-dev");
1381
1463
  const server = new McpServer(
1382
1464
  { name: "pyx-memory", version },
1383
1465
  { instructions: PYX_MEMORY_INSTRUCTIONS, capabilities: { tools: {}, prompts: {} } }
@@ -1396,7 +1478,7 @@ async function runMcpServer(opts) {
1396
1478
  for (const prompt of ALL_PROMPTS) {
1397
1479
  prompt.register(server);
1398
1480
  }
1399
- const transport = new StdioServerTransport();
1481
+ const transport = new StdioServerTransport2();
1400
1482
  const closed = new Promise((resolve3) => {
1401
1483
  transport.onclose = () => resolve3();
1402
1484
  });
@@ -1405,14 +1487,15 @@ async function runMcpServer(opts) {
1405
1487
  }
1406
1488
 
1407
1489
  // src/cli/commands/mcp.ts
1408
- async function mcpCommand() {
1490
+ async function mcpCommand(opts = {}) {
1409
1491
  const readCredentials = createReadCredentials(() => getDefaultKeychain());
1410
1492
  const onStdinEnd = new Promise((resolve3) => {
1411
1493
  process.stdin.once("end", resolve3);
1412
1494
  process.stdin.once("close", resolve3);
1413
1495
  });
1414
1496
  try {
1415
- await Promise.race([runMcpServer({ readCredentials }), onStdinEnd]);
1497
+ const run = opts.remote ? runMcpProxyServer({ readCredentials }) : runMcpServer({ readCredentials });
1498
+ await Promise.race([run, onStdinEnd]);
1416
1499
  return EXIT.OK;
1417
1500
  } catch (err) {
1418
1501
  process.stderr.write(`Internal error: ${err instanceof Error ? err.message : String(err)}
@@ -1544,22 +1627,28 @@ function indent(text) {
1544
1627
  // src/cli/commands/mcp-install.ts
1545
1628
  var VALID_SCOPES = /* @__PURE__ */ new Set(["local", "user", "project"]);
1546
1629
  var SERVER_NAME = "pyx-memory";
1547
- var ENTRY = { command: "pyx-mem", args: ["mcp"] };
1630
+ function pyxMemArgs(remote) {
1631
+ return remote ? ["mcp", "--remote"] : ["mcp"];
1632
+ }
1633
+ function mcpEntry(remote) {
1634
+ return { command: "pyx-mem", args: pyxMemArgs(remote) };
1635
+ }
1548
1636
  function mcpInstallClaudeCodeCommand(opts = {}) {
1549
1637
  const scope = opts.scope ?? "local";
1550
1638
  if (!validateScope(scope)) return EXIT.USAGE;
1639
+ const remote = opts.remote ?? false;
1551
1640
  const spawnSync = opts._spawnSync ?? nodeSpawnSync;
1552
1641
  const probe = spawnSync("claude", ["--version"], { stdio: "pipe" });
1553
1642
  if (probe.error || probe.status !== 0) {
1554
- printClaudeCodeManualInstructions(scope);
1643
+ printClaudeCodeManualInstructions(scope, remote);
1555
1644
  return EXIT.OK;
1556
1645
  }
1557
- const cmd = ["mcp", "add", SERVER_NAME, "-s", scope, "--", "pyx-mem", "mcp"];
1646
+ const cmd = ["mcp", "add", SERVER_NAME, "-s", scope, "--", "pyx-mem", ...pyxMemArgs(remote)];
1558
1647
  const res = spawnSync("claude", cmd, { stdio: "inherit" });
1559
1648
  if (res.status !== 0) {
1560
1649
  process.stderr.write(`\`claude ${cmd.join(" ")}\` exited with code ${res.status ?? "null"}.
1561
1650
  `);
1562
- printClaudeCodeManualInstructions(scope);
1651
+ printClaudeCodeManualInstructions(scope, remote);
1563
1652
  return EXIT.USAGE;
1564
1653
  }
1565
1654
  process.stdout.write(
@@ -1570,20 +1659,16 @@ To populate the knowledge graph, YOU pass entities and relationships (or triples
1570
1659
  );
1571
1660
  return EXIT.OK;
1572
1661
  }
1573
- function printClaudeCodeManualInstructions(scope) {
1662
+ function printClaudeCodeManualInstructions(scope, remote) {
1574
1663
  process.stdout.write(
1575
1664
  [
1576
1665
  "The `claude` CLI is not on PATH, or the install command failed.",
1577
1666
  "",
1578
1667
  "Run this once Claude Code is installed:",
1579
- ` claude mcp add ${SERVER_NAME} -s ${scope} -- pyx-mem mcp`,
1668
+ ` claude mcp add ${SERVER_NAME} -s ${scope} -- pyx-mem ${pyxMemArgs(remote).join(" ")}`,
1580
1669
  "",
1581
1670
  "Or add this entry manually to your Claude Code MCP config (.mcp.json):",
1582
- JSON.stringify(
1583
- { mcpServers: { [SERVER_NAME]: { command: "pyx-mem", args: ["mcp"] } } },
1584
- null,
1585
- 2
1586
- ),
1671
+ JSON.stringify({ mcpServers: { [SERVER_NAME]: mcpEntry(remote) } }, null, 2),
1587
1672
  "",
1588
1673
  "Do NOT add your pyx-memory API key here. Run `pyx-mem login` to store it in the OS credential store.",
1589
1674
  ""
@@ -1593,19 +1678,20 @@ function printClaudeCodeManualInstructions(scope) {
1593
1678
  function mcpInstallCodexCommand(opts = {}) {
1594
1679
  const scope = opts.scope ?? "user";
1595
1680
  if (!validateScope(scope)) return EXIT.USAGE;
1681
+ const remote = opts.remote ?? false;
1596
1682
  const spawnSync = opts._spawnSync ?? nodeSpawnSync;
1597
1683
  const home = opts._homeDir ?? homedir();
1598
1684
  const probe = spawnSync("codex", ["--version"], { stdio: "pipe" });
1599
1685
  if (probe.error || probe.status !== 0) {
1600
- printCodexManualInstructions(home);
1686
+ printCodexManualInstructions(home, remote);
1601
1687
  return EXIT.OK;
1602
1688
  }
1603
- const cmd = ["mcp", "add", SERVER_NAME, "--", "pyx-mem", "mcp"];
1689
+ const cmd = ["mcp", "add", SERVER_NAME, "--", "pyx-mem", ...pyxMemArgs(remote)];
1604
1690
  const res = spawnSync("codex", cmd, { stdio: "inherit" });
1605
1691
  if (res.status !== 0) {
1606
1692
  process.stderr.write(`\`codex ${cmd.join(" ")}\` exited with code ${res.status ?? "null"}.
1607
1693
  `);
1608
- printCodexManualInstructions(home);
1694
+ printCodexManualInstructions(home, remote);
1609
1695
  return EXIT.USAGE;
1610
1696
  }
1611
1697
  process.stdout.write(
@@ -1615,20 +1701,20 @@ Restart Codex CLI to make the tools available. No API key was written to config.
1615
1701
  );
1616
1702
  return EXIT.OK;
1617
1703
  }
1618
- function printCodexManualInstructions(home) {
1704
+ function printCodexManualInstructions(home, remote) {
1619
1705
  const configPath = join(home, ".codex", "config.toml");
1620
1706
  process.stdout.write(
1621
1707
  [
1622
1708
  "The `codex` CLI is not on PATH, or the install command failed.",
1623
1709
  "",
1624
1710
  "Run this once Codex CLI is installed:",
1625
- ` codex mcp add ${SERVER_NAME} -- pyx-mem mcp`,
1711
+ ` codex mcp add ${SERVER_NAME} -- pyx-mem ${pyxMemArgs(remote).join(" ")}`,
1626
1712
  "",
1627
1713
  `Or add this section manually to ${configPath}:`,
1628
1714
  "",
1629
1715
  `[mcp_servers.${SERVER_NAME}]`,
1630
1716
  `command = "pyx-mem"`,
1631
- `args = ["mcp"]`,
1717
+ `args = ${JSON.stringify(pyxMemArgs(remote))}`,
1632
1718
  "",
1633
1719
  "Do NOT add your pyx-memory API key here. Run `pyx-mem login` to store it in the OS credential store.",
1634
1720
  ""
@@ -1640,11 +1726,12 @@ function mcpInstallCursorCommand(opts = {}) {
1640
1726
  if (!validateScope(scope)) return EXIT.USAGE;
1641
1727
  const home = opts._homeDir ?? homedir();
1642
1728
  const filePath = scope === "project" ? join(process.cwd(), ".cursor", "mcp.json") : join(home, ".cursor", "mcp.json");
1643
- return writeJsonAndReport(filePath, "Cursor");
1729
+ return writeJsonAndReport(filePath, "Cursor", mcpEntry(opts.remote ?? false));
1644
1730
  }
1645
1731
  function mcpInstallClineCommand(opts = {}) {
1646
1732
  const scope = opts.scope ?? "user";
1647
1733
  if (!validateScope(scope)) return EXIT.USAGE;
1734
+ const remote = opts.remote ?? false;
1648
1735
  process.stdout.write(
1649
1736
  [
1650
1737
  "Cline MCP config is managed through the Cline UI in VS Code (the file",
@@ -1655,11 +1742,7 @@ function mcpInstallClineCommand(opts = {}) {
1655
1742
  '3. Click "MCP Servers" \u2192 "Configure MCP Servers".',
1656
1743
  `4. Add this entry under "mcpServers":`,
1657
1744
  "",
1658
- JSON.stringify(
1659
- { mcpServers: { [SERVER_NAME]: { command: "pyx-mem", args: ["mcp"] } } },
1660
- null,
1661
- 2
1662
- ),
1745
+ JSON.stringify({ mcpServers: { [SERVER_NAME]: mcpEntry(remote) } }, null, 2),
1663
1746
  "",
1664
1747
  "5. Save the file. Cline will reload the MCP servers automatically.",
1665
1748
  "",
@@ -1672,6 +1755,7 @@ function mcpInstallClineCommand(opts = {}) {
1672
1755
  function mcpInstallContinueCommand(opts = {}) {
1673
1756
  const scope = opts.scope ?? "user";
1674
1757
  if (!validateScope(scope)) return EXIT.USAGE;
1758
+ const remote = opts.remote ?? false;
1675
1759
  const home = opts._homeDir ?? homedir();
1676
1760
  const yamlPath = join(home, ".continue", "mcpServers", `${SERVER_NAME}.yaml`);
1677
1761
  process.stdout.write(
@@ -1690,7 +1774,7 @@ function mcpInstallContinueCommand(opts = {}) {
1690
1774
  ` - name: ${SERVER_NAME}`,
1691
1775
  ` command: pyx-mem`,
1692
1776
  ` args:`,
1693
- ` - mcp`,
1777
+ ...pyxMemArgs(remote).map((arg) => ` - ${arg}`),
1694
1778
  "",
1695
1779
  "Continue auto-loads new YAML blocks on next chat session \u2014 no restart",
1696
1780
  "needed in most setups.",
@@ -1706,24 +1790,25 @@ function mcpInstallWindsurfCommand(opts = {}) {
1706
1790
  if (!validateScope(scope)) return EXIT.USAGE;
1707
1791
  const home = opts._homeDir ?? homedir();
1708
1792
  const filePath = join(home, ".codeium", "windsurf", "mcp_config.json");
1709
- return writeJsonAndReport(filePath, "Windsurf");
1793
+ return writeJsonAndReport(filePath, "Windsurf", mcpEntry(opts.remote ?? false));
1710
1794
  }
1711
1795
  function mcpInstallGeminiCliCommand(opts = {}) {
1712
1796
  const scope = opts.scope ?? "user";
1713
1797
  if (!validateScope(scope)) return EXIT.USAGE;
1798
+ const remote = opts.remote ?? false;
1714
1799
  const spawnSync = opts._spawnSync ?? nodeSpawnSync;
1715
1800
  const home = opts._homeDir ?? homedir();
1716
1801
  const probe = spawnSync("gemini", ["--version"], { stdio: "pipe" });
1717
1802
  if (probe.error || probe.status !== 0) {
1718
- return writeJsonAndReport(geminiConfigPath(home, scope), "Gemini CLI");
1803
+ return writeJsonAndReport(geminiConfigPath(home, scope), "Gemini CLI", mcpEntry(remote));
1719
1804
  }
1720
1805
  const geminiScope = scope === "local" ? "project" : scope;
1721
- const cmd = ["mcp", "add", "-s", geminiScope, SERVER_NAME, "pyx-mem", "mcp"];
1806
+ const cmd = ["mcp", "add", "-s", geminiScope, SERVER_NAME, "pyx-mem", ...pyxMemArgs(remote)];
1722
1807
  const res = spawnSync("gemini", cmd, { stdio: "inherit" });
1723
1808
  if (res.status !== 0) {
1724
1809
  process.stderr.write(`\`gemini ${cmd.join(" ")}\` exited with code ${res.status ?? "null"}.
1725
1810
  `);
1726
- return writeJsonAndReport(geminiConfigPath(home, scope), "Gemini CLI");
1811
+ return writeJsonAndReport(geminiConfigPath(home, scope), "Gemini CLI", mcpEntry(remote));
1727
1812
  }
1728
1813
  process.stdout.write(
1729
1814
  `Installed pyx-memory MCP server in Gemini CLI (scope: ${geminiScope}).
@@ -1740,7 +1825,7 @@ function mcpInstallPiCommand(opts = {}) {
1740
1825
  if (!validateScope(scope)) return EXIT.USAGE;
1741
1826
  const home = opts._homeDir ?? homedir();
1742
1827
  const filePath = scope === "user" ? join(home, ".pi", "agent", "mcp.json") : join(process.cwd(), ".pi", "mcp.json");
1743
- return writeJsonAndReport(filePath, "Pi", {
1828
+ return writeJsonAndReport(filePath, "Pi", mcpEntry(opts.remote ?? false), {
1744
1829
  prereq: "pi has no native MCP support \u2014 install the third-party adapter once:\n pi install npm:pi-mcp-adapter"
1745
1830
  });
1746
1831
  }
@@ -1749,18 +1834,19 @@ function mcpInstallOhMyPiCommand(opts = {}) {
1749
1834
  if (!validateScope(scope)) return EXIT.USAGE;
1750
1835
  const home = opts._homeDir ?? homedir();
1751
1836
  const filePath = scope === "user" ? join(home, ".omp", "agent", "mcp.json") : join(process.cwd(), ".omp", "mcp.json");
1752
- return writeJsonAndReport(filePath, "oh-my-pi");
1837
+ return writeJsonAndReport(filePath, "oh-my-pi", mcpEntry(opts.remote ?? false));
1753
1838
  }
1754
1839
  function mcpInstallOpenClawCommand(opts = {}) {
1755
1840
  const scope = opts.scope ?? "user";
1756
1841
  if (!validateScope(scope)) return EXIT.USAGE;
1842
+ const remote = opts.remote ?? false;
1757
1843
  const spawnSync = opts._spawnSync ?? nodeSpawnSync;
1758
1844
  const probe = spawnSync("openclaw", ["--version"], { stdio: "pipe" });
1759
1845
  if (probe.error || probe.status !== 0) {
1760
- printOpenClawManualInstructions();
1846
+ printOpenClawManualInstructions(remote);
1761
1847
  return EXIT.OK;
1762
1848
  }
1763
- const entryJson = JSON.stringify(ENTRY);
1849
+ const entryJson = JSON.stringify(mcpEntry(remote));
1764
1850
  const cmd = ["mcp", "set", SERVER_NAME, entryJson];
1765
1851
  const res = spawnSync("openclaw", cmd, { stdio: "inherit" });
1766
1852
  if (res.status !== 0) {
@@ -1768,7 +1854,7 @@ function mcpInstallOpenClawCommand(opts = {}) {
1768
1854
  `\`openclaw ${cmd.join(" ")}\` exited with code ${res.status ?? "null"}.
1769
1855
  `
1770
1856
  );
1771
- printOpenClawManualInstructions();
1857
+ printOpenClawManualInstructions(remote);
1772
1858
  return EXIT.USAGE;
1773
1859
  }
1774
1860
  process.stdout.write(
@@ -1778,8 +1864,9 @@ Restart OpenClaw to make the tools available. No API key was written to openclaw
1778
1864
  );
1779
1865
  return EXIT.OK;
1780
1866
  }
1781
- function printOpenClawManualInstructions() {
1782
- const entryJson = JSON.stringify(ENTRY);
1867
+ function printOpenClawManualInstructions(remote) {
1868
+ const entry = mcpEntry(remote);
1869
+ const entryJson = JSON.stringify(entry);
1783
1870
  process.stdout.write(
1784
1871
  [
1785
1872
  "The `openclaw` CLI is not on PATH, or the install command failed.",
@@ -1790,7 +1877,7 @@ function printOpenClawManualInstructions() {
1790
1877
  "Or add this entry manually under `mcp.servers` in your OpenClaw config",
1791
1878
  "(run `openclaw config file` to print the active config path):",
1792
1879
  "",
1793
- JSON.stringify({ mcp: { servers: { [SERVER_NAME]: ENTRY } } }, null, 2),
1880
+ JSON.stringify({ mcp: { servers: { [SERVER_NAME]: entry } } }, null, 2),
1794
1881
  "",
1795
1882
  "Do NOT add your pyx-memory API key here. Run `pyx-mem login` to store it in the OS credential store.",
1796
1883
  ""
@@ -1800,18 +1887,19 @@ function printOpenClawManualInstructions() {
1800
1887
  function mcpInstallHermesCommand(opts = {}) {
1801
1888
  const scope = opts.scope ?? "user";
1802
1889
  if (!validateScope(scope)) return EXIT.USAGE;
1890
+ const remote = opts.remote ?? false;
1803
1891
  const spawnSync = opts._spawnSync ?? nodeSpawnSync;
1804
1892
  const probe = spawnSync("hermes", ["--version"], { stdio: "pipe" });
1805
1893
  if (probe.error || probe.status !== 0) {
1806
- printHermesManualInstructions();
1894
+ printHermesManualInstructions(remote);
1807
1895
  return EXIT.OK;
1808
1896
  }
1809
- const cmd = ["mcp", "add", SERVER_NAME, "--command", "pyx-mem", "--args", "mcp"];
1897
+ const cmd = ["mcp", "add", SERVER_NAME, "--command", "pyx-mem", "--args", ...pyxMemArgs(remote)];
1810
1898
  const res = spawnSync("hermes", cmd, { stdio: "inherit" });
1811
1899
  if (res.status !== 0) {
1812
1900
  process.stderr.write(`\`hermes ${cmd.join(" ")}\` exited with code ${res.status ?? "null"}.
1813
1901
  `);
1814
- printHermesManualInstructions();
1902
+ printHermesManualInstructions(remote);
1815
1903
  return EXIT.USAGE;
1816
1904
  }
1817
1905
  process.stdout.write(
@@ -1821,13 +1909,13 @@ Restart Hermes to make the tools available. No API key was written to config.yam
1821
1909
  );
1822
1910
  return EXIT.OK;
1823
1911
  }
1824
- function printHermesManualInstructions() {
1912
+ function printHermesManualInstructions(remote) {
1825
1913
  process.stdout.write(
1826
1914
  [
1827
1915
  "The `hermes` CLI is not on PATH, or the install command failed.",
1828
1916
  "",
1829
1917
  "Run this once Hermes is installed:",
1830
- ` hermes mcp add ${SERVER_NAME} --command pyx-mem --args mcp`,
1918
+ ` hermes mcp add ${SERVER_NAME} --command pyx-mem --args ${pyxMemArgs(remote).join(" ")}`,
1831
1919
  "",
1832
1920
  "Or add this block under `mcp_servers:` in your Hermes config",
1833
1921
  "(typically ~/.hermes/config.yaml):",
@@ -1835,7 +1923,7 @@ function printHermesManualInstructions() {
1835
1923
  `${SERVER_NAME}:`,
1836
1924
  " command: pyx-mem",
1837
1925
  " args:",
1838
- " - mcp",
1926
+ ...pyxMemArgs(remote).map((arg) => ` - ${arg}`),
1839
1927
  "",
1840
1928
  "Do NOT add your pyx-memory API key here. Run `pyx-mem login` to store it in the OS credential store.",
1841
1929
  ""
@@ -1848,11 +1936,11 @@ function validateScope(scope) {
1848
1936
  `);
1849
1937
  return false;
1850
1938
  }
1851
- function writeJsonAndReport(filePath, agentLabel, opts = {}) {
1939
+ function writeJsonAndReport(filePath, agentLabel, entry, opts = {}) {
1852
1940
  const result = mergeWriteJsonMcpEntry({
1853
1941
  filePath,
1854
1942
  serverName: SERVER_NAME,
1855
- entry: ENTRY
1943
+ entry
1856
1944
  });
1857
1945
  const stream = result.exitCode === EXIT.OK ? process.stdout : process.stderr;
1858
1946
  stream.write(result.message);
@@ -2101,9 +2189,14 @@ Commands:
2101
2189
  logout Delete stored pyx-memory credentials.
2102
2190
  doctor [--json] Diagnose keychain, credentials, backend, MCP startup.
2103
2191
  scaffold [--name <dir>] Generate Docker, env, SDK, and memory design-guide starter files.
2104
- mcp Start stdio MCP server.
2105
- mcp install <target> [--scope user|local|project]
2192
+ mcp [--remote] Start stdio MCP server. --remote proxies to the hosted
2193
+ server so tools + instructions stay server-owned
2194
+ (zero-touch updates; key stays in the keychain).
2195
+ mcp install <target> [--scope user|local|project] [--remote]
2106
2196
  Install pyx-memory MCP config for your AI agent.
2197
+ --remote installs the hosted thin-proxy (zero-touch
2198
+ updates; key stays in the keychain) instead of the
2199
+ bundled stdio server.
2107
2200
  Targets: claude-code, codex, cursor, cline, continue, windsurf, gemini-cli, pi, oh-my-pi, openclaw, hermes.
2108
2201
 
2109
2202
  Notes:
@@ -2171,7 +2264,7 @@ var INSTALL_TARGETS = {
2171
2264
  hermes: mcpInstallHermesCommand
2172
2265
  };
2173
2266
  var VALID_TARGETS = Object.keys(INSTALL_TARGETS);
2174
- function runMcpInstall(target, scope) {
2267
+ function runMcpInstall(target, scope, remote) {
2175
2268
  if (target === void 0 || !Object.hasOwn(INSTALL_TARGETS, target)) {
2176
2269
  process.stderr.write(
2177
2270
  `Error: unknown install target \`${target ?? ""}\`. Expected: ${VALID_TARGETS.join(", ")}.
@@ -2180,14 +2273,14 @@ function runMcpInstall(target, scope) {
2180
2273
  return EXIT.USAGE;
2181
2274
  }
2182
2275
  const handler = INSTALL_TARGETS[target];
2183
- return handler({ scope });
2276
+ return handler({ scope, remote });
2184
2277
  }
2185
2278
  function runMcpCommand(parsed) {
2186
- if (parsed.subcommand === void 0) return mcpCommand();
2279
+ if (parsed.subcommand === void 0) return mcpCommand({ remote: parsed.flags.remote === true });
2187
2280
  if (parsed.subcommand === "install") {
2188
2281
  const target = parsed.positional[0];
2189
2282
  const scope = typeof parsed.flags.scope === "string" ? parsed.flags.scope : void 0;
2190
- return runMcpInstall(target, scope);
2283
+ return runMcpInstall(target, scope, parsed.flags.remote === true);
2191
2284
  }
2192
2285
  process.stderr.write(
2193
2286
  `Error: unknown subcommand \`mcp ${parsed.subcommand}\`. Run \`pyx-mem --help\`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyxmate/memory",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "type": "module",
5
5
  "description": "SDK for pyx-memory — Memory as a Service for AI agents",
6
6
  "license": "MIT",