@opennous/mcp 0.26.0 → 0.28.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opennous/mcp",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "description": "Nous MCP Server — Customer graph for GTM agents.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
package/src/client.js CHANGED
@@ -37,22 +37,33 @@ export function runWithApiKey(apiKey, fn) {
37
37
 
38
38
  // Credential written by `nous login` (the browser device-auth flow). The CLI and
39
39
  // the MCP server share ~/.nous/config.json, so a user who runs the login command
40
- // gets a key the MCP picks up on the next callno paste, no env var.
41
- function fileApiKey() {
40
+ // gets a key and, for self-host, the API URLthe MCP picks up on the next
41
+ // call, with no paste and no env var.
42
+ function readFileConfig() {
42
43
  try {
43
44
  const dir = resolvedEnv("NOUS_CONFIG_DIR") || path.join(os.homedir(), ".nous");
44
- const cfg = JSON.parse(fs.readFileSync(path.join(dir, "config.json"), "utf8"));
45
- const k = cfg?.apiKey;
46
- return k && !String(k).includes("${") ? k : undefined;
45
+ return JSON.parse(fs.readFileSync(path.join(dir, "config.json"), "utf8"));
47
46
  } catch {
48
- return undefined;
47
+ return null;
49
48
  }
50
49
  }
50
+ function clean(v) {
51
+ return v && !String(v).includes("${") ? v : undefined; // drop unresolved ${...} markers
52
+ }
53
+ function fileApiKey() { return clean(readFileConfig()?.apiKey); }
54
+ function fileApiUrl() { return clean(readFileConfig()?.apiUrl); }
51
55
 
52
56
  function currentApiKey() {
53
57
  return apiKeyStore.getStore()?.apiKey ?? resolvedEnv("NOUS_API_KEY") ?? fileApiKey();
54
58
  }
55
59
 
60
+ // Resolve the API base per call: env → ~/.nous/config.json (set by `nous login
61
+ // --url` on self-host) → cloud default. So a self-hoster who logs in via the CLI
62
+ // gets the MCP pointed at their own instance automatically.
63
+ function currentApiUrl() {
64
+ return resolvedEnv("NOUS_API_URL") ?? fileApiUrl() ?? "https://api.opennous.cloud";
65
+ }
66
+
56
67
  // stdio-only preflight. A key may come from the env OR from `nous login`'s
57
68
  // credential file. This is advisory — the server still starts without one so
58
69
  // the user can run the login command after installing the plugin, and the key
@@ -72,7 +83,7 @@ async function request(method, path, { body, query } = {}) {
72
83
  throw new Error("Missing Nous API key. Pass it as an Authorization: Bearer header.");
73
84
  }
74
85
 
75
- const url = new URL(path, API_URL);
86
+ const url = new URL(path, currentApiUrl());
76
87
 
77
88
  if (query) {
78
89
  for (const [key, value] of Object.entries(query)) {
package/src/server.js CHANGED
@@ -39,7 +39,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
39
39
  import { z } from "zod";
40
40
  import { get, post } from "./client.js";
41
41
 
42
- export const SERVER_VERSION = "0.26.0";
42
+ export const SERVER_VERSION = "0.28.0";
43
43
 
44
44
  // ─── helpers ──────────────────────────────────────────────────────────────────
45
45
 
@@ -571,6 +571,12 @@ export function createServer() {
571
571
  lines.push(`WORKSPACE: ${ws.name || "(unnamed)"}${ws.website ? ` · ${ws.website}` : ""}${ws.business_type ? ` · ${ws.business_type}` : ""}`);
572
572
  const pl = s.plan ?? {};
573
573
  lines.push(`PLAN: ${pl.name || pl.id || "free"}${pl.crm_sync === false ? " (CRM sync not included — do not offer it)" : ""}`);
574
+ if (s.self_hosted) {
575
+ const e = s.env_integrations ?? {};
576
+ const mk = (b) => (b ? "✓ set" : "✗ NOT set");
577
+ lines.push("SELF-HOSTED — these channels are wired via nous.env (you can't set env vars; tell the operator to set + restart):");
578
+ lines.push(` LinkedIn/Unipile: ${mk(e.linkedin_unipile)} Email/Resend: ${mk(e.email_resend)} Gmail OAuth: ${mk(e.gmail_oauth)}`);
579
+ }
574
580
  lines.push("");
575
581
 
576
582
  const mark = (b) => (b ? "✓" : "✗");