substack-article-mcp 0.1.0 → 0.2.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/README.md CHANGED
@@ -6,10 +6,27 @@ MCP server for Substack — access your articles, notes, and engagement data fro
6
6
 
7
7
  ## Quick Start
8
8
 
9
+ ### Easy install (one command)
10
+
11
+ Like [NotebookLM MCP](https://github.com/jacob-bd/notebooklm-mcp-cli), you can add the MCP to your app without editing config files:
12
+
13
+ ```bash
14
+ # Add to Cursor (writes ~/.cursor/mcp.json)
15
+ npx -y substack-article-mcp setup add cursor
16
+
17
+ # Or Claude Desktop
18
+ npx -y substack-article-mcp setup add claude-desktop
19
+
20
+ # See where it's configured
21
+ npx -y substack-article-mcp setup list
22
+ ```
23
+
24
+ You’ll be prompted for your Substack subdomain (e.g. `buildtolaunch`) if `SUBSTACK_SUBDOMAIN` isn’t set. Then restart Cursor or Claude Desktop.
25
+
9
26
  ### 1. Authenticate
10
27
 
11
28
  ```bash
12
- npx substack-article-mcp login
29
+ npx -y substack-article-mcp login
13
30
  ```
14
31
 
15
32
  This opens Chrome, you log into Substack, and the session cookie is saved automatically. One-time setup that lasts ~2-4 weeks.
@@ -17,12 +34,12 @@ This opens Chrome, you log into Substack, and the session cookie is saved automa
17
34
  **Alternative** (manual cookie paste):
18
35
 
19
36
  ```bash
20
- npx substack-article-mcp login --manual "your-substack-sid-cookie-value"
37
+ npx -y substack-article-mcp login --manual "your-substack-sid-cookie-value"
21
38
  ```
22
39
 
23
- ### 2. Configure Your MCP Client
40
+ ### 2. Configure Your MCP Client (manual)
24
41
 
25
- Add to your MCP configuration:
42
+ If you prefer to edit config yourself, add to your MCP configuration:
26
43
 
27
44
  **Cursor** (`~/.cursor/mcp.json`):
28
45
 
@@ -91,6 +108,10 @@ substack-article-mcp # Start the MCP server
91
108
  substack-article-mcp login # Authenticate via Chrome (automated)
92
109
  substack-article-mcp login --manual <sid> # Authenticate with a pasted cookie value
93
110
  substack-article-mcp login --check # Check authentication status
111
+ substack-article-mcp setup add cursor # Add to Cursor (easy install)
112
+ substack-article-mcp setup add claude-desktop # Add to Claude Desktop
113
+ substack-article-mcp setup list # Show config status
114
+ substack-article-mcp setup remove <client> # Remove from config
94
115
  substack-article-mcp --help # Show help
95
116
  ```
96
117
 
package/dist/index.js CHANGED
@@ -33,12 +33,17 @@ async function main() {
33
33
  await runLogin();
34
34
  return;
35
35
  }
36
+ if (command === "setup") {
37
+ const { runSetup } = await import("./setup-cli.js");
38
+ await runSetup(args.slice(1));
39
+ return;
40
+ }
36
41
  if (command === "--help" || command === "-h") {
37
42
  printHelp();
38
43
  return;
39
44
  }
40
45
  if (command === "--version" || command === "-v") {
41
- console.log("substack-article-mcp v0.1.0");
46
+ console.log("substack-article-mcp v0.2.0");
42
47
  return;
43
48
  }
44
49
  // Default: start MCP server
@@ -55,20 +60,17 @@ USAGE
55
60
  substack-article-mcp login --manual <sid> Manually provide your substack.sid cookie
56
61
  substack-article-mcp login --check Check current authentication status
57
62
 
58
- MCP CLIENT CONFIGURATION
63
+ substack-article-mcp setup add cursor Add to Cursor (~/.cursor/mcp.json)
64
+ substack-article-mcp setup add claude-desktop Add to Claude Desktop
65
+ substack-article-mcp setup add claude-code Show instructions for Claude Code
66
+ substack-article-mcp setup list Show where MCP is configured
67
+ substack-article-mcp setup remove <client> Remove from cursor or claude-desktop
59
68
 
60
- Cursor / Claude Desktop / Claude Code:
61
- {
62
- "mcpServers": {
63
- "substack": {
64
- "command": "npx",
65
- "args": ["-y", "substack-article-mcp"],
66
- "env": {
67
- "SUBSTACK_SUBDOMAIN": "your-subdomain"
68
- }
69
- }
70
- }
71
- }
69
+ Example (easy install):
70
+ npx -y substack-article-mcp setup add cursor
71
+ (prompts for subdomain if needed, then restart Cursor)
72
+
73
+ MCP CLIENT CONFIGURATION (manual)
72
74
 
73
75
  Your subdomain is the part before .substack.com in your newsletter URL.
74
76
  For example: buildtolaunch.substack.com → subdomain is "buildtolaunch"
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAExB,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAErB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YAC9C,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;YACtD,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;YAEvC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;gBAC/B,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;gBAClD,OAAO,CAAC,GAAG,CACT,iBAAiB,MAAM,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,WAAW,EAAE,CACxF,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;gBACnC,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;YAC9E,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,OAAO,CAAC,KAAK,CAAC,iEAAiE,CAAC,CAAC;gBACjF,OAAO,CAAC,KAAK,CACX,kJAAkJ,CACnJ,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;YACrD,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,QAAQ,EAAE,CAAC;QACjB,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAC7C,SAAS,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IAED,4BAA4B;IAC5B,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACpD,MAAM,WAAW,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCb,CAAC,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAExB,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAErB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YAC9C,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;YACtD,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;YAEvC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;gBAC/B,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;gBAClD,OAAO,CAAC,GAAG,CACT,iBAAiB,MAAM,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,WAAW,EAAE,CACxF,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;gBACnC,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;YAC9E,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,OAAO,CAAC,KAAK,CAAC,iEAAiE,CAAC,CAAC;gBACjF,OAAO,CAAC,KAAK,CACX,kJAAkJ,CACnJ,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;YACrD,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,QAAQ,EAAE,CAAC;QACjB,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACpD,MAAM,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9B,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAC7C,SAAS,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IAED,4BAA4B;IAC5B,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACpD,MAAM,WAAW,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCb,CAAC,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runSetup(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=setup-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-cli.d.ts","sourceRoot":"","sources":["../src/setup-cli.ts"],"names":[],"mappings":"AAsBA,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoF5D"}
@@ -0,0 +1,95 @@
1
+ import * as readline from "node:readline";
2
+ import { addToConfig, removeFromConfig, listConfigStatus, getConfigPathsForHelp, } from "./setup.js";
3
+ const CLIENTS = ["cursor", "claude-desktop", "claude-code"];
4
+ function promptSubdomain() {
5
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
6
+ return new Promise((resolve) => {
7
+ rl.question("Your Substack subdomain (e.g. buildtolaunch): ", (answer) => {
8
+ rl.close();
9
+ resolve((answer || "").trim() || "your-subdomain");
10
+ });
11
+ });
12
+ }
13
+ export async function runSetup(args) {
14
+ const sub = args[0];
15
+ const clientArg = args[1];
16
+ if (sub === "add") {
17
+ const client = clientArg;
18
+ if (!client || !CLIENTS.includes(client)) {
19
+ console.error("Usage: substack-article-mcp setup add <cursor | claude-desktop | claude-code>");
20
+ console.error("Example: substack-article-mcp setup add cursor");
21
+ process.exit(1);
22
+ }
23
+ let subdomain = process.env["SUBSTACK_SUBDOMAIN"] || "";
24
+ if (!subdomain) {
25
+ subdomain = await promptSubdomain();
26
+ }
27
+ if (client === "claude-code") {
28
+ console.log("\nClaude Code does not use a config file. Add the MCP manually:");
29
+ console.log(" claude mcp add substack -- npx -y substack-article-mcp");
30
+ console.log("\nThen set your subdomain (e.g. in your shell profile):");
31
+ console.log(' export SUBSTACK_SUBDOMAIN="buildtolaunch"');
32
+ return;
33
+ }
34
+ try {
35
+ const { path, updated } = addToConfig(client, subdomain);
36
+ if (updated) {
37
+ console.log(`\n✅ Added substack-article-mcp to ${client}`);
38
+ console.log(` Config: ${path}`);
39
+ console.log(` Subdomain: ${subdomain}`);
40
+ console.log("\nRestart your app (Cursor or Claude Desktop) to use the MCP.");
41
+ }
42
+ else {
43
+ console.log(`\n✅ Already configured for ${client} (${path})`);
44
+ }
45
+ }
46
+ catch (err) {
47
+ console.error(err instanceof Error ? err.message : String(err));
48
+ process.exit(1);
49
+ }
50
+ return;
51
+ }
52
+ if (sub === "remove") {
53
+ const client = clientArg;
54
+ if (!client || !CLIENTS.includes(client)) {
55
+ console.error("Usage: substack-article-mcp setup remove <cursor | claude-desktop>");
56
+ process.exit(1);
57
+ }
58
+ if (client === "claude-code") {
59
+ console.error("Claude Code has no config file to edit. Remove the MCP with: claude mcp remove substack");
60
+ process.exit(1);
61
+ }
62
+ try {
63
+ const { path, removed } = removeFromConfig(client);
64
+ if (removed) {
65
+ console.log(`\n✅ Removed substack-article-mcp from ${client} (${path})`);
66
+ }
67
+ else {
68
+ console.log(`\nNot configured for ${client} (${path})`);
69
+ }
70
+ }
71
+ catch (err) {
72
+ console.error(err instanceof Error ? err.message : String(err));
73
+ process.exit(1);
74
+ }
75
+ return;
76
+ }
77
+ if (sub === "list") {
78
+ const status = listConfigStatus();
79
+ const paths = getConfigPathsForHelp();
80
+ console.log("\nSubstack Article MCP — config status:\n");
81
+ for (const { client, path, configured } of status) {
82
+ const label = configured ? "✅" : "—";
83
+ const pathDisplay = path.startsWith("(") ? path : path;
84
+ console.log(` ${label} ${client.padEnd(18)} ${pathDisplay}`);
85
+ }
86
+ console.log("\nTo add: substack-article-mcp setup add <cursor | claude-desktop | claude-code>");
87
+ return;
88
+ }
89
+ console.error("Usage:");
90
+ console.error(" substack-article-mcp setup add <cursor | claude-desktop | claude-code>");
91
+ console.error(" substack-article-mcp setup remove <cursor | claude-desktop>");
92
+ console.error(" substack-article-mcp setup list");
93
+ process.exit(1);
94
+ }
95
+ //# sourceMappingURL=setup-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-cli.js","sourceRoot":"","sources":["../src/setup-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ type ClientId = "cursor" | "claude-desktop" | "claude-code";
2
+ interface ConfigPaths {
3
+ cursor: string;
4
+ "claude-desktop": string;
5
+ "claude-code": string | null;
6
+ }
7
+ export declare function addToConfig(client: ClientId, subdomain: string): {
8
+ path: string;
9
+ updated: boolean;
10
+ };
11
+ export declare function removeFromConfig(client: ClientId): {
12
+ path: string;
13
+ removed: boolean;
14
+ };
15
+ export declare function listConfigStatus(): Array<{
16
+ client: string;
17
+ path: string;
18
+ configured: boolean;
19
+ }>;
20
+ export declare function getConfigPathsForHelp(): ConfigPaths;
21
+ export {};
22
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAcA,KAAK,QAAQ,GAAG,QAAQ,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAE5D,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AA8DD,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA+BnG;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAoBrF;AAED,wBAAgB,gBAAgB,IAAI,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAoB/F;AAED,wBAAgB,qBAAqB,IAAI,WAAW,CAEnD"}
package/dist/setup.js ADDED
@@ -0,0 +1,124 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { homedir, platform } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ const MCP_SERVER_NAME = "substack";
5
+ const SERVER_ENTRY = {
6
+ command: "npx",
7
+ args: ["-y", "substack-article-mcp"],
8
+ env: {
9
+ SUBSTACK_SUBDOMAIN: "your-subdomain",
10
+ },
11
+ };
12
+ function getConfigPaths() {
13
+ const home = homedir();
14
+ const isMac = platform() === "darwin";
15
+ const isWin = platform() === "win32";
16
+ const cursorPath = process.env["CURSOR_MCP_CONFIG"] ||
17
+ join(home, ".cursor", "mcp.json");
18
+ let claudeDesktopPath;
19
+ if (isWin) {
20
+ claudeDesktopPath = join(process.env["APPDATA"] || join(home, "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
21
+ }
22
+ else if (isMac) {
23
+ claudeDesktopPath = join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
24
+ }
25
+ else {
26
+ claudeDesktopPath = join(home, ".config", "Claude", "claude_desktop_config.json");
27
+ }
28
+ return {
29
+ cursor: cursorPath,
30
+ "claude-desktop": claudeDesktopPath,
31
+ "claude-code": null,
32
+ };
33
+ }
34
+ function readJsonPath(path) {
35
+ try {
36
+ if (!existsSync(path))
37
+ return null;
38
+ const raw = readFileSync(path, "utf-8");
39
+ return JSON.parse(raw);
40
+ }
41
+ catch {
42
+ return null;
43
+ }
44
+ }
45
+ function writeJsonPath(path, data) {
46
+ const dir = dirname(path);
47
+ if (!existsSync(dir)) {
48
+ mkdirSync(dir, { recursive: true });
49
+ }
50
+ writeFileSync(path, JSON.stringify(data, null, 2), "utf-8");
51
+ }
52
+ function ensureMcpServers(config) {
53
+ if (!config["mcpServers"] || typeof config["mcpServers"] !== "object") {
54
+ return { ...config, mcpServers: {} };
55
+ }
56
+ return config;
57
+ }
58
+ export function addToConfig(client, subdomain) {
59
+ const paths = getConfigPaths();
60
+ const path = paths[client];
61
+ if (!path) {
62
+ throw new Error("claude-code does not use a config file; use: claude mcp add substack -- npx -y substack-article-mcp");
63
+ }
64
+ const config = readJsonPath(path);
65
+ const base = config ? ensureMcpServers(config) : { mcpServers: {} };
66
+ const mcpServers = base.mcpServers;
67
+ const existing = mcpServers[MCP_SERVER_NAME];
68
+ const entry = {
69
+ command: SERVER_ENTRY.command,
70
+ args: SERVER_ENTRY.args,
71
+ env: { SUBSTACK_SUBDOMAIN: subdomain },
72
+ };
73
+ const same = existing &&
74
+ typeof existing === "object" &&
75
+ existing.command === entry.command &&
76
+ JSON.stringify(existing.env) === JSON.stringify(entry.env);
77
+ if (same) {
78
+ return { path, updated: false };
79
+ }
80
+ mcpServers[MCP_SERVER_NAME] = entry;
81
+ writeJsonPath(path, base);
82
+ return { path, updated: true };
83
+ }
84
+ export function removeFromConfig(client) {
85
+ const paths = getConfigPaths();
86
+ const path = paths[client];
87
+ if (!path) {
88
+ throw new Error("claude-code has no config file to edit.");
89
+ }
90
+ const config = readJsonPath(path);
91
+ if (!config?.mcpServers || typeof config.mcpServers !== "object") {
92
+ return { path, removed: false };
93
+ }
94
+ const mcpServers = config.mcpServers;
95
+ if (!(MCP_SERVER_NAME in mcpServers)) {
96
+ return { path, removed: false };
97
+ }
98
+ delete mcpServers[MCP_SERVER_NAME];
99
+ writeJsonPath(path, config);
100
+ return { path, removed: true };
101
+ }
102
+ export function listConfigStatus() {
103
+ const paths = getConfigPaths();
104
+ const results = [];
105
+ for (const [client, path] of Object.entries(paths)) {
106
+ if (!path) {
107
+ results.push({
108
+ client: client,
109
+ path: "(claude mcp add)",
110
+ configured: false,
111
+ });
112
+ continue;
113
+ }
114
+ const config = readJsonPath(path);
115
+ const mcpServers = config?.mcpServers && typeof config.mcpServers === "object" ? config.mcpServers : {};
116
+ const configured = MCP_SERVER_NAME in mcpServers;
117
+ results.push({ client: client, path, configured });
118
+ }
119
+ return results;
120
+ }
121
+ export function getConfigPathsForHelp() {
122
+ return getConfigPaths();
123
+ }
124
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substack-article-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for Substack — access your articles, notes, and engagement data from Claude, Cursor, or any MCP client. Authenticated access to premium/paywalled content.",
5
5
  "type": "module",
6
6
  "bin": {