substack-api-mcp 1.0.3__tar.gz → 1.0.4__tar.gz

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 (100) hide show
  1. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/PKG-INFO +22 -22
  2. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/README.md +21 -21
  3. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/pyproject.toml +1 -1
  4. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/__init__.py +1 -1
  5. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/.github/workflows/ci.yml +0 -0
  6. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/.github/workflows/publish.yml +0 -0
  7. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/.gitignore +0 -0
  8. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/AGENTS.md +0 -0
  9. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/CLAUDE.md +0 -0
  10. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/LICENSE +0 -0
  11. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/assets/logo-white.svg +0 -0
  12. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/assets/logo.svg +0 -0
  13. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/add_subscribers.py +0 -0
  14. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/daily_stats.py +0 -0
  15. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/draft_from_markdown.py +0 -0
  16. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/export_subscribers.py +0 -0
  17. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/get_post.py +0 -0
  18. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/list_posts.py +0 -0
  19. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/list_subscribers.py +0 -0
  20. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/post_stats.py +0 -0
  21. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/publish_note.py +0 -0
  22. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/reply_to_comment.py +0 -0
  23. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/schedule_post.py +0 -0
  24. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/traffic_sources.py +0 -0
  25. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/unanswered_comments.py +0 -0
  26. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/examples/weekly_report.py +0 -0
  27. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/glama.json +0 -0
  28. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/mcp.json +0 -0
  29. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/api.py +0 -0
  30. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/app.py +0 -0
  31. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/cli.py +0 -0
  32. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/core/__init__.py +0 -0
  33. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/core/account_guard.py +0 -0
  34. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/core/context.py +0 -0
  35. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/core/errors.py +0 -0
  36. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/core/helpers.py +0 -0
  37. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/core/tools.py +0 -0
  38. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/mcp_context.py +0 -0
  39. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/mcp_server.py +0 -0
  40. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/runner.py +0 -0
  41. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/scripting.py +0 -0
  42. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/session.py +0 -0
  43. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/__init__.py +0 -0
  44. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/auth.py +0 -0
  45. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/client.py +0 -0
  46. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/feed.py +0 -0
  47. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/markdown.py +0 -0
  48. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/publishing.py +0 -0
  49. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/subscribers.py +0 -0
  50. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/__init__.py +0 -0
  51. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/add_subscriber.py +0 -0
  52. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/cancel_scheduled_post.py +0 -0
  53. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/create_draft.py +0 -0
  54. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/create_post_tag.py +0 -0
  55. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/create_subscriber_tag.py +0 -0
  56. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/delete_comment.py +0 -0
  57. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/delete_post.py +0 -0
  58. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/duplicate_post.py +0 -0
  59. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/export_subscribers.py +0 -0
  60. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/follow_user.py +0 -0
  61. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/get_audience_insights.py +0 -0
  62. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/get_conversation.py +0 -0
  63. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/get_daily_stats.py +0 -0
  64. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/get_feed.py +0 -0
  65. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/get_post.py +0 -0
  66. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/get_post_engagement.py +0 -0
  67. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/get_post_stats.py +0 -0
  68. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/get_post_traffic.py +0 -0
  69. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/get_publication_stats.py +0 -0
  70. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/get_unread_counts.py +0 -0
  71. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/like_comment.py +0 -0
  72. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/like_post.py +0 -0
  73. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_activity.py +0 -0
  74. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_comments.py +0 -0
  75. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_conversations.py +0 -0
  76. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_note_replies.py +0 -0
  77. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_notes.py +0 -0
  78. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_post_tags.py +0 -0
  79. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_posts.py +0 -0
  80. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_recommendations.py +0 -0
  81. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_sections.py +0 -0
  82. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_subscriber_tags.py +0 -0
  83. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_subscribers.py +0 -0
  84. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_subscriptions.py +0 -0
  85. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/list_traffic_sources.py +0 -0
  86. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/pin_comment.py +0 -0
  87. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/publish_note.py +0 -0
  88. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/publish_post.py +0 -0
  89. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/recommend_publication.py +0 -0
  90. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/remove_comment.py +0 -0
  91. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/remove_subscriber.py +0 -0
  92. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/reply_to_comment.py +0 -0
  93. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/reply_to_note.py +0 -0
  94. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/schedule_post.py +0 -0
  95. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/search_substack.py +0 -0
  96. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/send_message.py +0 -0
  97. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/tag_post.py +0 -0
  98. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/tag_subscribers.py +0 -0
  99. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/unpublish_post.py +0 -0
  100. {substack_api_mcp-1.0.3 → substack_api_mcp-1.0.4}/substack_api_mcp/substack/tools/update_draft.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: substack-api-mcp
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: Self-hosted Substack API and MCP server on your own Chrome session. Noncommercial use (PolyForm Noncommercial 1.0.0).
5
5
  Project-URL: Homepage, https://cotlet.dev/integrations/substack-api-mcp-server
6
6
  Project-URL: Source, https://github.com/cotletdev/substack-api-mcp-server
@@ -29,13 +29,13 @@ Substack has no public API to write posts, publish Notes or manage subscribers,
29
29
 
30
30
  - **MCP server** for Claude Code, Claude Desktop, Cursor, Codex and any MCP client, over stdio or HTTP. [Setup](#mcp-server)
31
31
  - **REST API** on `http://127.0.0.1:8787/api/v1/substack`, with OpenAPI docs at `/docs`. [Setup](#rest-api)
32
- - **Python**: `call("list_posts", status="draft")`, plus 14 ready scripts in [`examples/`](examples/).
32
+ - **Python**: `call("list_posts", status="draft")`, plus 14 ready scripts in [`examples/`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/).
33
33
 
34
34
  It is for technical people who want to run it themselves, **for noncommercial use only** ([license](#license)). If you want it running 24/7 on a server, kept working when Substack changes its site, for a team or a business, use the [hosted version at cotlet.dev](https://cotlet.dev/integrations/substack-api-mcp-server).
35
35
 
36
36
  [![Substack MCP server](https://img.shields.io/badge/Substack%20MCP-50%20tools-ff6719)](#all-50-tools)
37
37
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-141318)](#requirements)
38
- [![License: PolyForm Noncommercial 1.0.0](https://img.shields.io/badge/license-PolyForm%20Noncommercial-141318)](LICENSE)
38
+ [![License: PolyForm Noncommercial 1.0.0](https://img.shields.io/badge/license-PolyForm%20Noncommercial-141318)](https://github.com/cotletdev/substack-api-mcp-server/blob/main/LICENSE)
39
39
  [![MCP Badge](https://lobehub.com/badge/mcp/cotletdev-substack-api-mcp-server)](https://lobehub.com/mcp/cotletdev-substack-api-mcp-server)
40
40
 
41
41
  ```bash
@@ -107,7 +107,7 @@ substack-mcp --version
107
107
 
108
108
  With [uv](https://docs.astral.sh/uv/): `uv venv && uv pip install -e .`, then `uv run substack-mcp ...`.
109
109
 
110
- Setting it up with an AI agent (Claude Code, Codex, Cursor)? Open it in this folder and ask it to set up the repo: [`AGENTS.md`](AGENTS.md) tells it every step, and it asks you only for the steps in Chrome.
110
+ Setting it up with an AI agent (Claude Code, Codex, Cursor)? Open it in this folder and ask it to set up the repo: [`AGENTS.md`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/AGENTS.md) tells it every step, and it asks you only for the steps in Chrome.
111
111
 
112
112
  To update: `uv tool upgrade substack-api-mcp` (or `pip install -U substack-api-mcp`), from source `git pull && pip install -e .`. We copy every change of the hosted Substack tools into this repo.
113
113
 
@@ -198,7 +198,7 @@ claude mcp add substack -- uvx substack-api-mcp mcp --read-only
198
198
 
199
199
  ### Cursor
200
200
 
201
- `~/.cursor/mcp.json`, the same block as Claude Desktop. A ready copy is in [`mcp.json`](mcp.json).
201
+ `~/.cursor/mcp.json`, the same block as Claude Desktop. A ready copy is in [`mcp.json`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/mcp.json).
202
202
 
203
203
  ### Codex
204
204
 
@@ -277,24 +277,24 @@ call("schedule_post", post_id=draft["post_id"], publish_at="2026-11-03T08:00:00-
277
277
 
278
278
  Or one tool from the shell: `substack-mcp call get_post_stats post_id=148213977`, or with a JSON object.
279
279
 
280
- Ready scripts in [`examples/`](examples/). Each prints JSON, takes `--out file.csv` or `--out file.json` where it makes sense, and `--help`:
280
+ Ready scripts in [`examples/`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/). Each prints JSON, takes `--out file.csv` or `--out file.json` where it makes sense, and `--help`:
281
281
 
282
282
  | Script | What it does |
283
283
  |---|---|
284
- | [`draft_from_markdown.py`](examples/draft_from_markdown.py) | A `.md` file to a draft: the first heading is the title, headings, links and lists are kept. `--publish-at` schedules it. |
285
- | [`schedule_post.py`](examples/schedule_post.py) | Schedules a draft for a set time, or `--cancel` takes it back to drafts. |
286
- | [`publish_note.py`](examples/publish_note.py) | A Note now or at a set time, `--link-latest` adds a link card to your newest post. |
287
- | [`list_posts.py`](examples/list_posts.py) | Published, draft or scheduled posts: title, audience, dates, URL. |
288
- | [`get_post.py`](examples/get_post.py) | One post saved as a Markdown file. |
289
- | [`weekly_report.py`](examples/weekly_report.py) | New and paid subscribers, cancellations, revenue, and each new post's opens and new subscribers. |
290
- | [`post_stats.py`](examples/post_stats.py) | Opens, open rate, views, likes, restacks and new subscribers for your last N posts. |
291
- | [`daily_stats.py`](examples/daily_stats.py) | Subscribers, paid subscribers, followers and views day by day. |
292
- | [`traffic_sources.py`](examples/traffic_sources.py) | Where your visitors came from, most views first. |
293
- | [`unanswered_comments.py`](examples/unanswered_comments.py) | Comments on your last N posts that you have not replied to. |
294
- | [`reply_to_comment.py`](examples/reply_to_comment.py) | A reply under one comment. |
295
- | [`list_subscribers.py`](examples/list_subscribers.py) | Subscribers by plan or join date, with activity rating. |
296
- | [`export_subscribers.py`](examples/export_subscribers.py) | The full list as the CSV that Export gives in the dashboard. |
297
- | [`add_subscribers.py`](examples/add_subscribers.py) | Adds emails from a text or CSV file as free subscribers, after asking you. |
284
+ | [`draft_from_markdown.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/draft_from_markdown.py) | A `.md` file to a draft: the first heading is the title, headings, links and lists are kept. `--publish-at` schedules it. |
285
+ | [`schedule_post.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/schedule_post.py) | Schedules a draft for a set time, or `--cancel` takes it back to drafts. |
286
+ | [`publish_note.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/publish_note.py) | A Note now or at a set time, `--link-latest` adds a link card to your newest post. |
287
+ | [`list_posts.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/list_posts.py) | Published, draft or scheduled posts: title, audience, dates, URL. |
288
+ | [`get_post.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/get_post.py) | One post saved as a Markdown file. |
289
+ | [`weekly_report.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/weekly_report.py) | New and paid subscribers, cancellations, revenue, and each new post's opens and new subscribers. |
290
+ | [`post_stats.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/post_stats.py) | Opens, open rate, views, likes, restacks and new subscribers for your last N posts. |
291
+ | [`daily_stats.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/daily_stats.py) | Subscribers, paid subscribers, followers and views day by day. |
292
+ | [`traffic_sources.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/traffic_sources.py) | Where your visitors came from, most views first. |
293
+ | [`unanswered_comments.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/unanswered_comments.py) | Comments on your last N posts that you have not replied to. |
294
+ | [`reply_to_comment.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/reply_to_comment.py) | A reply under one comment. |
295
+ | [`list_subscribers.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/list_subscribers.py) | Subscribers by plan or join date, with activity rating. |
296
+ | [`export_subscribers.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/export_subscribers.py) | The full list as the CSV that Export gives in the dashboard. |
297
+ | [`add_subscribers.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/add_subscribers.py) | Adds emails from a text or CSV file as free subscribers, after asking you. |
298
298
 
299
299
  ```bash
300
300
  python examples/draft_from_markdown.py essay.md --publish-at 2026-11-03T08:00:00-05:00
@@ -507,7 +507,7 @@ The source is public, the license is not an open source license: noncommercial u
507
507
 
508
508
  ## License
509
509
 
510
- [PolyForm Noncommercial License 1.0.0](LICENSE). In short:
510
+ [PolyForm Noncommercial License 1.0.0](https://github.com/cotletdev/substack-api-mcp-server/blob/main/LICENSE). In short:
511
511
 
512
512
  - **Allowed:** noncommercial use: you, for your own personal purposes with your own Substack account, or a charity, school, public research or government body. Changing the code, and sharing it under the same license.
513
513
  - **Not allowed:** any commercial use, your own business included; client work; selling or offering it, or a service built on it.
@@ -520,7 +520,7 @@ Earlier versions of this repo (the scripts for the hosted API, up to commit 4399
520
520
  <a href="https://cotlet.dev">
521
521
  <picture>
522
522
  <source media="(prefers-color-scheme: dark)" srcset="assets/logo-white.svg">
523
- <img src="assets/logo.svg" alt="Cotlet" width="120">
523
+ <img src="https://raw.githubusercontent.com/cotletdev/substack-api-mcp-server/main/assets/logo.svg" alt="Cotlet" width="120">
524
524
  </picture>
525
525
  </a>
526
526
  </p>
@@ -8,13 +8,13 @@ Substack has no public API to write posts, publish Notes or manage subscribers,
8
8
 
9
9
  - **MCP server** for Claude Code, Claude Desktop, Cursor, Codex and any MCP client, over stdio or HTTP. [Setup](#mcp-server)
10
10
  - **REST API** on `http://127.0.0.1:8787/api/v1/substack`, with OpenAPI docs at `/docs`. [Setup](#rest-api)
11
- - **Python**: `call("list_posts", status="draft")`, plus 14 ready scripts in [`examples/`](examples/).
11
+ - **Python**: `call("list_posts", status="draft")`, plus 14 ready scripts in [`examples/`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/).
12
12
 
13
13
  It is for technical people who want to run it themselves, **for noncommercial use only** ([license](#license)). If you want it running 24/7 on a server, kept working when Substack changes its site, for a team or a business, use the [hosted version at cotlet.dev](https://cotlet.dev/integrations/substack-api-mcp-server).
14
14
 
15
15
  [![Substack MCP server](https://img.shields.io/badge/Substack%20MCP-50%20tools-ff6719)](#all-50-tools)
16
16
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-141318)](#requirements)
17
- [![License: PolyForm Noncommercial 1.0.0](https://img.shields.io/badge/license-PolyForm%20Noncommercial-141318)](LICENSE)
17
+ [![License: PolyForm Noncommercial 1.0.0](https://img.shields.io/badge/license-PolyForm%20Noncommercial-141318)](https://github.com/cotletdev/substack-api-mcp-server/blob/main/LICENSE)
18
18
  [![MCP Badge](https://lobehub.com/badge/mcp/cotletdev-substack-api-mcp-server)](https://lobehub.com/mcp/cotletdev-substack-api-mcp-server)
19
19
 
20
20
  ```bash
@@ -86,7 +86,7 @@ substack-mcp --version
86
86
 
87
87
  With [uv](https://docs.astral.sh/uv/): `uv venv && uv pip install -e .`, then `uv run substack-mcp ...`.
88
88
 
89
- Setting it up with an AI agent (Claude Code, Codex, Cursor)? Open it in this folder and ask it to set up the repo: [`AGENTS.md`](AGENTS.md) tells it every step, and it asks you only for the steps in Chrome.
89
+ Setting it up with an AI agent (Claude Code, Codex, Cursor)? Open it in this folder and ask it to set up the repo: [`AGENTS.md`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/AGENTS.md) tells it every step, and it asks you only for the steps in Chrome.
90
90
 
91
91
  To update: `uv tool upgrade substack-api-mcp` (or `pip install -U substack-api-mcp`), from source `git pull && pip install -e .`. We copy every change of the hosted Substack tools into this repo.
92
92
 
@@ -177,7 +177,7 @@ claude mcp add substack -- uvx substack-api-mcp mcp --read-only
177
177
 
178
178
  ### Cursor
179
179
 
180
- `~/.cursor/mcp.json`, the same block as Claude Desktop. A ready copy is in [`mcp.json`](mcp.json).
180
+ `~/.cursor/mcp.json`, the same block as Claude Desktop. A ready copy is in [`mcp.json`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/mcp.json).
181
181
 
182
182
  ### Codex
183
183
 
@@ -256,24 +256,24 @@ call("schedule_post", post_id=draft["post_id"], publish_at="2026-11-03T08:00:00-
256
256
 
257
257
  Or one tool from the shell: `substack-mcp call get_post_stats post_id=148213977`, or with a JSON object.
258
258
 
259
- Ready scripts in [`examples/`](examples/). Each prints JSON, takes `--out file.csv` or `--out file.json` where it makes sense, and `--help`:
259
+ Ready scripts in [`examples/`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/). Each prints JSON, takes `--out file.csv` or `--out file.json` where it makes sense, and `--help`:
260
260
 
261
261
  | Script | What it does |
262
262
  |---|---|
263
- | [`draft_from_markdown.py`](examples/draft_from_markdown.py) | A `.md` file to a draft: the first heading is the title, headings, links and lists are kept. `--publish-at` schedules it. |
264
- | [`schedule_post.py`](examples/schedule_post.py) | Schedules a draft for a set time, or `--cancel` takes it back to drafts. |
265
- | [`publish_note.py`](examples/publish_note.py) | A Note now or at a set time, `--link-latest` adds a link card to your newest post. |
266
- | [`list_posts.py`](examples/list_posts.py) | Published, draft or scheduled posts: title, audience, dates, URL. |
267
- | [`get_post.py`](examples/get_post.py) | One post saved as a Markdown file. |
268
- | [`weekly_report.py`](examples/weekly_report.py) | New and paid subscribers, cancellations, revenue, and each new post's opens and new subscribers. |
269
- | [`post_stats.py`](examples/post_stats.py) | Opens, open rate, views, likes, restacks and new subscribers for your last N posts. |
270
- | [`daily_stats.py`](examples/daily_stats.py) | Subscribers, paid subscribers, followers and views day by day. |
271
- | [`traffic_sources.py`](examples/traffic_sources.py) | Where your visitors came from, most views first. |
272
- | [`unanswered_comments.py`](examples/unanswered_comments.py) | Comments on your last N posts that you have not replied to. |
273
- | [`reply_to_comment.py`](examples/reply_to_comment.py) | A reply under one comment. |
274
- | [`list_subscribers.py`](examples/list_subscribers.py) | Subscribers by plan or join date, with activity rating. |
275
- | [`export_subscribers.py`](examples/export_subscribers.py) | The full list as the CSV that Export gives in the dashboard. |
276
- | [`add_subscribers.py`](examples/add_subscribers.py) | Adds emails from a text or CSV file as free subscribers, after asking you. |
263
+ | [`draft_from_markdown.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/draft_from_markdown.py) | A `.md` file to a draft: the first heading is the title, headings, links and lists are kept. `--publish-at` schedules it. |
264
+ | [`schedule_post.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/schedule_post.py) | Schedules a draft for a set time, or `--cancel` takes it back to drafts. |
265
+ | [`publish_note.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/publish_note.py) | A Note now or at a set time, `--link-latest` adds a link card to your newest post. |
266
+ | [`list_posts.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/list_posts.py) | Published, draft or scheduled posts: title, audience, dates, URL. |
267
+ | [`get_post.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/get_post.py) | One post saved as a Markdown file. |
268
+ | [`weekly_report.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/weekly_report.py) | New and paid subscribers, cancellations, revenue, and each new post's opens and new subscribers. |
269
+ | [`post_stats.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/post_stats.py) | Opens, open rate, views, likes, restacks and new subscribers for your last N posts. |
270
+ | [`daily_stats.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/daily_stats.py) | Subscribers, paid subscribers, followers and views day by day. |
271
+ | [`traffic_sources.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/traffic_sources.py) | Where your visitors came from, most views first. |
272
+ | [`unanswered_comments.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/unanswered_comments.py) | Comments on your last N posts that you have not replied to. |
273
+ | [`reply_to_comment.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/reply_to_comment.py) | A reply under one comment. |
274
+ | [`list_subscribers.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/list_subscribers.py) | Subscribers by plan or join date, with activity rating. |
275
+ | [`export_subscribers.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/export_subscribers.py) | The full list as the CSV that Export gives in the dashboard. |
276
+ | [`add_subscribers.py`](https://github.com/cotletdev/substack-api-mcp-server/blob/main/examples/add_subscribers.py) | Adds emails from a text or CSV file as free subscribers, after asking you. |
277
277
 
278
278
  ```bash
279
279
  python examples/draft_from_markdown.py essay.md --publish-at 2026-11-03T08:00:00-05:00
@@ -486,7 +486,7 @@ The source is public, the license is not an open source license: noncommercial u
486
486
 
487
487
  ## License
488
488
 
489
- [PolyForm Noncommercial License 1.0.0](LICENSE). In short:
489
+ [PolyForm Noncommercial License 1.0.0](https://github.com/cotletdev/substack-api-mcp-server/blob/main/LICENSE). In short:
490
490
 
491
491
  - **Allowed:** noncommercial use: you, for your own personal purposes with your own Substack account, or a charity, school, public research or government body. Changing the code, and sharing it under the same license.
492
492
  - **Not allowed:** any commercial use, your own business included; client work; selling or offering it, or a service built on it.
@@ -499,7 +499,7 @@ Earlier versions of this repo (the scripts for the hosted API, up to commit 4399
499
499
  <a href="https://cotlet.dev">
500
500
  <picture>
501
501
  <source media="(prefers-color-scheme: dark)" srcset="assets/logo-white.svg">
502
- <img src="assets/logo.svg" alt="Cotlet" width="120">
502
+ <img src="https://raw.githubusercontent.com/cotletdev/substack-api-mcp-server/main/assets/logo.svg" alt="Cotlet" width="120">
503
503
  </picture>
504
504
  </a>
505
505
  </p>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "substack-api-mcp"
3
- version = "1.0.3"
3
+ version = "1.0.4"
4
4
  description = "Self-hosted Substack API and MCP server on your own Chrome session. Noncommercial use (PolyForm Noncommercial 1.0.0)."
5
5
  readme = "README.md"
6
6
  license = "PolyForm-Noncommercial-1.0.0"
@@ -11,7 +11,7 @@ from __future__ import annotations
11
11
  import asyncio
12
12
  from typing import Any
13
13
 
14
- __version__ = "1.0.3"
14
+ __version__ = "1.0.4"
15
15
 
16
16
 
17
17
  def call(tool: str, args: dict[str, Any] | None = None, **kwargs: Any) -> Any: