From ee524a8d2df0d34113f06cd25301b48f7d2e2811 Mon Sep 17 00:00:00 2001
From: Ignazio De Santis
- Substack MCP server for AI clients — draft, publish, schedule, analyze, and research Substack publications from Claude, Cursor, Codex, Windsurf, Antigravity, and any Model Context Protocol client. + Substack MCP server for AI clients — draft, publish, schedule, analyze, and research Substack publications from clients that support stdio MCP servers, including Claude, Cursor, Codex, Windsurf, and other compatible MCP hosts.
@@ -83,19 +83,25 @@ npm install -g github:IgnazioDS/Substak-MCP This installs two commands: ```bash -substack-mcp-plus -substack-mcp-plus-setup +substack-mcp +substack-mcp-setup ``` +Naming note: +- the repository is `IgnazioDS/Substak-MCP` +- the current npm package is `@ignaziods/substack-mcp` +- the installed commands are `substack-mcp` and `substack-mcp-setup` +- the default MCP server key in examples is `substack-mcp` + ### Migrating From the Old Package -If you previously installed another package variant, remove it before +If you previously installed the older plus-era package, remove it before installing from this repository: ```bash -npm uninstall -g substack-mcp-plus +npm uninstall -g @ignaziods/substack-mcp-plus npm install -g github:IgnazioDS/Substak-MCP -substack-mcp-plus-setup +substack-mcp-setup ``` After reinstalling, fully restart your MCP client so it reloads the command. @@ -105,7 +111,7 @@ After reinstalling, fully restart your MCP client so it reloads the command. Run the setup wizard: ```bash -substack-mcp-plus-setup +substack-mcp-setup ``` The setup flow will: @@ -114,11 +120,13 @@ The setup flow will: - handle CAPTCHA/manual login flow - store an encrypted browser session locally for later use -The local auth file lives at `~/.substack-mcp-plus/auth.json`. The setup stores +The local auth file lives at `~/.substack-mcp/auth.json`. The setup stores the browser session cookie jar after login, not your Substack password. +If you already have auth stored under `~/.substack-mcp-plus/`, the runtime +reuses that legacy directory until you migrate it. If Substack sends an email sign-in link, open or paste that link in the same -browser window opened by `substack-mcp-plus-setup`. That same-browser step is +browser window opened by `substack-mcp-setup`. That same-browser step is what lets the setup capture the final authenticated session. If your client later says authentication failed, run the setup again. @@ -132,8 +140,8 @@ Server block: ```json { "mcpServers": { - "substack-mcp-plus": { - "command": "substack-mcp-plus", + "substack-mcp": { + "command": "substack-mcp", "env": { "SUBSTACK_PUBLICATION_URL": "https://YOUR_PUBLICATION.substack.com", "SUBSTACK_DEVELOPER_API_TOKEN": "optional-developer-api-token" @@ -143,13 +151,17 @@ Server block: } ``` +`SUBSTACK_DEVELOPER_API_TOKEN` is only needed for the limited Developer API +profile-lookup surface. Most account tools and public research flows do not +require it. + If your GUI client does not inherit your shell `PATH`, use an absolute path instead: ```bash -which substack-mcp-plus +which substack-mcp ``` -Then replace `"substack-mcp-plus"` with the full path to the binary. +Then replace `"substack-mcp"` with the full path to the binary. ### Client Notes @@ -159,15 +171,15 @@ Then replace `"substack-mcp-plus"` with the full path to the binary. - Windows: `%APPDATA%\\Claude\\claude_desktop_config.json` - Linux: `~/.config/Claude/claude_desktop_config.json` - Claude Code - Add the same `mcpServers.substack-mcp-plus` block to `~/.claude.json`. + Add the same `mcpServers.substack-mcp` block to `~/.claude.json`. - Codex Add this to `~/.codex/config.toml`: ```toml - [mcp_servers.substack-mcp-plus] - command = "substack-mcp-plus" + [mcp_servers.substack-mcp] + command = "substack-mcp" - [mcp_servers.substack-mcp-plus.env] + [mcp_servers.substack-mcp.env] SUBSTACK_PUBLICATION_URL = "https://YOUR_PUBLICATION.substack.com" SUBSTACK_DEVELOPER_API_TOKEN = "optional-developer-api-token" ``` @@ -184,6 +196,8 @@ After updating the config, fully restart the client. ## Tool List +The server currently registers 29 tools. + ### Publishing and Account Tools - `create_formatted_post` @@ -296,7 +310,7 @@ Your client may not inherit your shell `PATH`. Find the installed binary: ```bash -which substack-mcp-plus +which substack-mcp ``` Then use the absolute path in the client config. @@ -306,7 +320,7 @@ Then use the absolute path in the client config. Run setup again: ```bash -substack-mcp-plus-setup +substack-mcp-setup ``` If Substack sent a sign-in email, paste the email link into the same setup @@ -337,33 +351,47 @@ Usually weaker: ### GUI client still cannot launch the server -Use an absolute command path instead of `substack-mcp-plus`. +Use an absolute command path instead of `substack-mcp`. ## Development -Install editable Python dependencies in the project venv: +For local development, activate the project virtual environment first: ```bash -./venv/bin/python -m pip install -e '.[dev]' +source venv/bin/activate +python3 -m pip install -e '.[dev]' ``` Run tests: ```bash -./venv/bin/python -m pytest -q +python3 -m pytest -q ``` -Run the server directly: +Run the Python server directly: + +```bash +python3 -m src.server +``` + +Run the npm wrapper entrypoint used by the installed CLI: ```bash node src/index.js ``` +If you are developing from the repository and the auth setup cannot launch +Chromium, install the Playwright browser once: + +```bash +python3 -m playwright install chromium +``` + ## Security - Do not commit tokens, passwords, or private keys. - Prefer interactive setup over hardcoded credentials. -- Stored browser session data is encrypted under `~/.substack-mcp-plus/`. +- Stored browser session data is encrypted under `~/.substack-mcp/`. - Use obvious placeholders in configs and examples. - Re-run authentication if a stored Substack session expires. @@ -371,7 +399,7 @@ See [SECURITY.md](SECURITY.md) for project security notes. ## 💖 Sponsor This Project -Substak‑MCP is built and maintained in the open by [@IgnazioDS](https://github.com/IgnazioDS). If your team relies on it, or you'd like to support continued development of new tools, integrations, and improvements, please consider sponsoring: +`Substak-MCP` is built and maintained in the open by [@IgnazioDS](https://github.com/IgnazioDS). If your team relies on it, or you'd like to support continued development of new tools, integrations, and improvements, please consider sponsoring: - ❤️ **GitHub Sponsors:** https://github.com/sponsors/IgnazioDS diff --git a/SECURITY.md b/SECURITY.md index 7d5a874..bd0acd8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,7 +10,7 @@ ## 🔐 Security Best Practices -When using Substack MCP Plus, please follow these security best practices: +When using Substack MCP, please follow these security best practices: ### Environment Variables - **Never commit your `.env` file** to version control @@ -20,7 +20,7 @@ When using Substack MCP Plus, please follow these security best practices: ### Authentication - **Browser Setup Method** (Recommended): - - Use `substack-mcp-plus-setup` + - Use `substack-mcp-setup` - Complete CAPTCHA, password, magic-link, or email verification in the setup browser - If Substack emails a sign-in link, paste it into the same setup browser - The tool stores encrypted session cookies, not your Substack password @@ -31,7 +31,7 @@ When using Substack MCP Plus, please follow these security best practices: - Revoke tokens immediately if compromised ### Local Auth Storage -- Browser session data is encrypted at `~/.substack-mcp-plus/auth.json` +- Browser session data is encrypted at `~/.substack-mcp/auth.json` - The auth file is written with owner-only permissions (`600`) - The auth directory is written with owner-only permissions (`700`) - Never commit `auth.json`, `.key`, `.env`, cookies, tokens, or terminal logs that contain secrets @@ -43,7 +43,7 @@ When using Substack MCP Plus, please follow these security best practices: ## 🚨 Reporting Security Vulnerabilities -We take security seriously. If you discover a security vulnerability in Substack MCP Plus, please follow these steps: +We take security seriously. If you discover a security vulnerability in Substack MCP, please follow these steps: ### 1. Do NOT Create a Public Issue Security vulnerabilities should be reported privately to prevent exploitation. @@ -103,4 +103,4 @@ Security updates will be released as soon as possible after discovery and fix. U --- -Thank you for helping keep Substack MCP Plus secure! +Thank you for helping keep Substack MCP secure! diff --git a/docs/CLAUDE_DESKTOP_QUICK_TEST.md b/docs/CLAUDE_DESKTOP_QUICK_TEST.md index fc7347f..9b57242 100644 --- a/docs/CLAUDE_DESKTOP_QUICK_TEST.md +++ b/docs/CLAUDE_DESKTOP_QUICK_TEST.md @@ -1,4 +1,4 @@ -# Claude Desktop Test Checklist for Substack MCP Plus +# Claude Desktop Test Checklist for Substack MCP ## Quick Test Order (Safest First) diff --git a/docs/ERROR_HANDLING_FIXES.md b/docs/ERROR_HANDLING_FIXES.md index 08efc6e..481496a 100644 --- a/docs/ERROR_HANDLING_FIXES.md +++ b/docs/ERROR_HANDLING_FIXES.md @@ -1,6 +1,6 @@ # Error Handling Fixes Summary -This document captures the debugging path I used to fix critical errors in Substack MCP Plus, especially the `"'str' object has no attribute 'get'"` failures that affected multiple tools. +This document captures the debugging path I used to fix critical errors in Substack MCP, especially the `"'str' object has no attribute 'get'"` failures that affected multiple tools. ## The Problem diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index 461743c..822418c 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -1,6 +1,6 @@ -# Substack MCP Plus - Quick Start Guide +# Substack MCP - Quick Start Guide -This is the fastest setup path I recommend for Substack MCP Plus. +This is the fastest setup path I recommend for Substack MCP. ## 🚀 Quick Setup @@ -9,7 +9,7 @@ This is the fastest setup path I recommend for Substack MCP Plus. npm install -g github:IgnazioDS/Substak-MCP # Run the authentication setup wizard -substack-mcp-plus-setup +substack-mcp-setup ``` The setup wizard handles the heavy lifting: @@ -20,17 +20,17 @@ The setup wizard handles the heavy lifting: - ✅ Automatic configuration If Substack sends an email sign-in link, open or paste that link in the same -browser window opened by `substack-mcp-plus-setup`. The setup captures the final +browser window opened by `substack-mcp-setup`. The setup captures the final browser cookies after that window reaches a signed-in Substack page. ## 🔄 Existing Users -If you installed another package variant, reinstall from this repository and rerun setup: +If you installed the older plus-era package, reinstall from this repository and rerun setup: ```bash -npm uninstall -g substack-mcp-plus +npm uninstall -g @ignaziods/substack-mcp-plus npm install -g github:IgnazioDS/Substak-MCP -substack-mcp-plus-setup +substack-mcp-setup ``` Then fully restart your MCP client. @@ -42,8 +42,8 @@ After running setup, add this minimal config to Claude Desktop: ```json { "mcpServers": { - "substack-mcp-plus": { - "command": "substack-mcp-plus", + "substack-mcp": { + "command": "substack-mcp", "env": { "SUBSTACK_PUBLICATION_URL": "https://YOUR-PUBLICATION.substack.com" } @@ -63,8 +63,8 @@ If you already have other MCP servers configured, add this alongside them: "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/directory"] }, - "substack-mcp-plus": { - "command": "substack-mcp-plus", + "substack-mcp": { + "command": "substack-mcp", "env": { "SUBSTACK_PUBLICATION_URL": "https://YOUR-PUBLICATION.substack.com" } @@ -116,10 +116,10 @@ Upload image from https://picsum.photos/800/400 optimized for web | Issue | Solution | |-------|----------| -| "No authentication found" | Run `substack-mcp-plus-setup` | +| "No authentication found" | Run `substack-mcp-setup` | | CAPTCHA appears | Solve it in the browser window | | Email link opens elsewhere | Copy the link and paste it into the setup browser | -| Session expired | Run `substack-mcp-plus-setup` again | +| Session expired | Run `substack-mcp-setup` again | | Import errors | Reinstall with `npm install -g github:IgnazioDS/Substak-MCP` | ## 🎯 Pro Tips @@ -155,4 +155,4 @@ export SUBSTACK_PUBLICATION_URL="https://YOUR_PUBLICATION.substack.com" --- -**Need help?** I kept the setup flow opinionated on purpose. In most cases, rerunning `substack-mcp-plus-setup` is the right fix. +**Need help?** I kept the setup flow opinionated on purpose. In most cases, rerunning `substack-mcp-setup` is the right fix. diff --git a/docs/README.md b/docs/README.md index 4a82cd2..ec5d312 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ -# Substack MCP Plus Documentation +# Substack MCP Documentation -Welcome to the Substack MCP Plus documentation! This directory contains all the guides and references you need to use and understand the project. +Welcome to the Substack MCP documentation! This directory contains all the guides and references you need to use and understand the project. ## 📚 User Documentation @@ -35,7 +35,8 @@ For contributors and developers working on the project: ## 🔗 Quick Links - [Main README](../README.md) -- [Roadmap & Next Steps](ROADMAP.md) +- [Current TODOs](TODO.md) +- [Vision & Roadmap](VISION.md) - [Contributing Guide](../CONTRIBUTING.md) - [Security Policy](../SECURITY.md) - [Claude Code Configuration](../CLAUDE.md) @@ -49,7 +50,6 @@ docs/ ├── README.md # Documentation index (this file) ├── QUICKSTART.md # Get started in 5 minutes ├── TODO.md # Current work items with subtasks -├── ROADMAP.md # Long-term vision and features ├── authentication.md # Authentication setup guide ├── formatting.md # Content formatting guide ├── TESTING.md # Comprehensive testing documentation @@ -82,4 +82,4 @@ If you'd like to contribute to the documentation: 3. Include examples where helpful 4. Update this README when adding new docs -For more information about contributing to the project, see the main [README](../README.md). \ No newline at end of file +For more information about contributing to the project, see the main [README](../README.md). diff --git a/docs/TESTING.md b/docs/TESTING.md index 2cf382a..c87d020 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -23,7 +23,7 @@ tests/ ```bash # Clone the repository git clone [repository-url] -cd substack-mcp-plus +cd Substak-MCP # Run the automated setup ./setup.sh @@ -334,7 +334,7 @@ When adding features: "substack": { "command": "python", "args": ["-m", "src.server"], - "cwd": "/path/to/substack-mcp-plus", + "cwd": "/path/to/Substak-MCP", "env": { "SUBSTACK_PUBLICATION_URL": "https://yourpublication.substack.com", "SUBSTACK_EMAIL": "your-email@example.com", @@ -351,7 +351,7 @@ When adding features: ```bash # Kill any existing MCP processes -pkill -f substack-mcp-plus +pkill -f substack-mcp # Clear any test drafts from your Substack account (optional) # Log into Substack web UI and delete test drafts diff --git a/docs/TEST_INSTALLATION.md b/docs/TEST_INSTALLATION.md index d5347fb..e694e39 100644 --- a/docs/TEST_INSTALLATION.md +++ b/docs/TEST_INSTALLATION.md @@ -4,18 +4,18 @@ ```bash # 1. First uninstall any existing version -npm uninstall -g substack-mcp-plus +npm uninstall -g @ignaziods/substack-mcp # 2. Build and install from the tarball TARBALL="$(npm pack)" npm install -g "./$TARBALL" # 3. Verify installation -which substack-mcp-plus -# Should show: /opt/homebrew/bin/substack-mcp-plus +which substack-mcp +# Should show: /opt/homebrew/bin/substack-mcp # 4. Test the command works -substack-mcp-plus-setup --help +substack-mcp-setup --help ``` ## Method 2: Test in Isolated Directory @@ -26,21 +26,21 @@ mkdir -p ~/test-substack-mcp cd ~/test-substack-mcp # 2. Install the package locally -TARBALL="$(ls ../myApps/substack-mcp-plus/*.tgz | tail -n 1)" +TARBALL="$(ls ../myApps/substack-mcp/*.tgz | tail -n 1)" npm install "$TARBALL" # 3. Run from node_modules -./node_modules/.bin/substack-mcp-plus +./node_modules/.bin/substack-mcp # 4. Or configure Claude Desktop to use this path: -# "command": "/Users/Matt/test-substack-mcp/node_modules/.bin/substack-mcp-plus" +# "command": "/Users/Matt/test-substack-mcp/node_modules/.bin/substack-mcp" ``` ## Method 3: Direct Test Without NPM ```bash # From the project directory, you can test directly: -cd /Users/Matt/myApps/substack-mcp-plus +cd /Users/Matt/myApps/substack-mcp # Run the server directly node src/index.js @@ -55,7 +55,7 @@ python -m src.server To revert to the published version: ```bash # Uninstall test version -npm uninstall -g substack-mcp-plus +npm uninstall -g @ignaziods/substack-mcp # Install from the GitHub repository npm install -g github:IgnazioDS/Substak-MCP diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index d9ecdd1..ba9a524 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -1,4 +1,4 @@ -# Substack MCP Plus Troubleshooting Guide +# Substack MCP Troubleshooting Guide ## Common Issues and Solutions @@ -33,7 +33,7 @@ **Solutions:** 1. Verify your authentication has admin/owner privileges 2. Check if subscriber count is visible in Substack dashboard -3. Try re-authenticating with `substack-mcp-plus-setup` +3. Try re-authenticating with `substack-mcp-setup` ### 3. Authentication Issues @@ -45,17 +45,17 @@ **Solutions:** 1. If you installed another package variant, reinstall from this repository: ```bash - npm uninstall -g substack-mcp-plus + npm uninstall -g @ignaziods/substack-mcp-plus npm install -g github:IgnazioDS/Substak-MCP ``` 2. Re-run authentication setup: ```bash - substack-mcp-plus-setup + substack-mcp-setup ``` 3. Fully restart your MCP client. 4. Clear cached credentials only if setup still fails: ```bash - rm -i ~/.substack-mcp-plus/auth.json ~/.substack-mcp-plus/.key + rm -i ~/.substack-mcp/auth.json ~/.substack-mcp/.key ``` 5. Use the same setup browser for CAPTCHA, password, and email-link verification @@ -68,7 +68,7 @@ **Solution:** 1. Copy the sign-in link from the email. -2. Paste it into the browser window opened by `substack-mcp-plus-setup`. +2. Paste it into the browser window opened by `substack-mcp-setup`. 3. Wait for the setup browser to show a signed-in Substack page. 4. Return to the terminal and let setup finish storing the session. @@ -144,7 +144,7 @@ If you see "API returned invalid data format", it usually means: ## Quick Fixes ### "It was working yesterday" -→ Re-authenticate: `substack-mcp-plus-setup` +→ Re-authenticate: `substack-mcp-setup` ### "Can't find my post" → Use `list_drafts` to see all available posts with IDs @@ -152,6 +152,6 @@ If you see "API returned invalid data format", it usually means: ### "Everything is broken" → Clear cache and re-authenticate: ```bash -rm -i ~/.substack-mcp-plus/auth.json ~/.substack-mcp-plus/.key -substack-mcp-plus-setup +rm -i ~/.substack-mcp/auth.json ~/.substack-mcp/.key +substack-mcp-setup ``` diff --git a/docs/VISION.md b/docs/VISION.md index 6552a13..318a8d5 100644 --- a/docs/VISION.md +++ b/docs/VISION.md @@ -1,4 +1,4 @@ -# The Vision for Substack MCP Plus +# The Vision for Substack MCP ## 🎯 Why I Maintain This diff --git a/docs/authentication.md b/docs/authentication.md index 957849a..75741c7 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -1,6 +1,6 @@ -# Authentication Guide for Substack MCP Plus +# Authentication Guide for Substack MCP -This guide explains how to set up authentication for Substack MCP Plus. The +This guide explains how to set up authentication for Substack MCP. The recommended setup uses a real browser login so Substack can show CAPTCHA, password, magic-link, or email-verification steps normally. @@ -9,7 +9,7 @@ password, magic-link, or email-verification steps normally. The setup path I recommend is the interactive setup wizard included in this repo: ```bash -substack-mcp-plus-setup +substack-mcp-setup ``` This wizard will: @@ -48,7 +48,7 @@ For local development from the repository, use: I designed the authentication flow with three layers so it stays usable when one path fails: 1. **Secure Browser Session Storage** (Primary) - - Session cookies are encrypted and stored at `~/.substack-mcp-plus/auth.json` + - Session cookies are encrypted and stored at `~/.substack-mcp/auth.json` - The auth file is owner-readable only (`600`) - The auth directory is owner-only (`700`) - Automatically used when available @@ -64,13 +64,13 @@ I designed the authentication flow with three layers so it stays usable when one ## 📝 Configuration -After running `substack-mcp-plus-setup`, you only need to provide the publication URL in your Claude Desktop config: +After running `substack-mcp-setup`, you only need to provide the publication URL in your Claude Desktop config: ```json { "mcpServers": { - "substack-mcp-plus": { - "command": "substack-mcp-plus", + "substack-mcp": { + "command": "substack-mcp", "env": { "SUBSTACK_PUBLICATION_URL": "https://yourpublication.substack.com" } @@ -84,7 +84,7 @@ After running `substack-mcp-plus-setup`, you only need to provide the publicatio ## 🔄 Session Management ### Automatic Features -- **Secure Storage**: Browser session cookies are encrypted in `~/.substack-mcp-plus/auth.json` +- **Secure Storage**: Browser session cookies are encrypted in `~/.substack-mcp/auth.json` - **Expiration Tracking**: Monitors session age and prompts for refresh - **Cache Management**: Reuses authenticated sessions for performance - **Clear Error Messages**: Helpful guidance when authentication fails @@ -92,7 +92,7 @@ After running `substack-mcp-plus-setup`, you only need to provide the publicatio ### Manual Session Refresh If needed, simply run the setup wizard again: ```bash -substack-mcp-plus-setup +substack-mcp-setup ``` It will detect existing authentication and ask if you want to replace it. @@ -129,7 +129,7 @@ SUBSTACK_PUBLICATION_URL=https://YOUR_PUBLICATION.substack.com ## 🚨 Troubleshooting ### "No authentication found" Error -**Solution**: Run `substack-mcp-plus-setup` +**Solution**: Run `substack-mcp-setup` ### CAPTCHA Issues The setup wizard handles CAPTCHA automatically. If you still have issues: @@ -137,15 +137,15 @@ The setup wizard handles CAPTCHA automatically. If you still have issues: 2. Try using magic link authentication instead of password 3. Log in manually once in your browser 4. Wait 5 minutes -5. Run `substack-mcp-plus-setup` again +5. Run `substack-mcp-setup` again ### Email Link Opened in Another Browser **Solution**: Copy the email link and paste it into the browser window opened by -`substack-mcp-plus-setup`. The setup must see the final signed-in browser state +`substack-mcp-setup`. The setup must see the final signed-in browser state before it can store the session. ### Session Expired -**Solution**: Run `substack-mcp-plus-setup` to refresh +**Solution**: Run `substack-mcp-setup` to refresh ### "Authentication failed" Error 1. Verify your email is correct @@ -158,7 +158,7 @@ before it can store the session. 1. **Never commit credentials** to version control 2. **Use the setup wizard** for the most secure configuration -3. **Session cookies are encrypted** in `~/.substack-mcp-plus/auth.json` +3. **Session cookies are encrypted** in `~/.substack-mcp/auth.json` 4. **Enable 2FA** on your Substack account 5. **Rotate passwords** periodically @@ -167,7 +167,7 @@ before it can store the session. ### How Sessions Are Stored Sessions are stored using: -- **Encrypted local file**: `~/.substack-mcp-plus/auth.json` +- **Encrypted local file**: `~/.substack-mcp/auth.json` - **Encryption**: Additional layer using Fernet symmetric encryption - **Permissions**: auth file `600`, config directory `700` - **Metadata**: Expiration tracking and email association @@ -191,7 +191,7 @@ The system tries authentication in this order: For 99% of users, just run: ```bash -substack-mcp-plus-setup +substack-mcp-setup ``` Follow the prompts, and you're done! The system handles everything else automatically. diff --git a/docs/claude_desktop_test_checklist.md b/docs/claude_desktop_test_checklist.md index 176025e..182f948 100644 --- a/docs/claude_desktop_test_checklist.md +++ b/docs/claude_desktop_test_checklist.md @@ -1,11 +1,11 @@ -# Claude Desktop MCP Test Checklist for Substack MCP Plus v1.0.3 +# Claude Desktop MCP Test Checklist for Substack MCP v1.0.3 ## Pre-Test Setup 1. **Clean Installation** ```bash # Uninstall current version - npm uninstall -g substack-mcp-plus + npm uninstall -g @ignaziods/substack-mcp # Clear npm cache npm cache clean --force @@ -16,18 +16,18 @@ 2. **Verify Installation** ```bash - which substack-mcp-plus - # Should show: /opt/homebrew/bin/substack-mcp-plus + which substack-mcp + # Should show: /opt/homebrew/bin/substack-mcp ``` 3. **Configure Claude Desktop** - - Remove existing substack-mcp-plus entry from Claude Desktop config + - Remove existing substack-mcp entry from Claude Desktop config - Re-add with fresh configuration: ```json { "mcpServers": { - "substack-mcp-plus": { - "command": "/opt/homebrew/bin/substack-mcp-plus", + "substack-mcp": { + "command": "/opt/homebrew/bin/substack-mcp", "env": { "SUBSTACK_PUBLICATION_URL": "https://neroaugustus.substack.com/" } @@ -40,7 +40,7 @@ 4. **Authentication Setup** ```bash # Run setup command - substack-mcp-plus-setup + substack-mcp-setup # Should open browser for authentication # Complete login process @@ -160,14 +160,14 @@ def hello(): ## Error Handling Tests ### Test Authentication Errors -1. **Test**: Temporarily rename ~/.substack-mcp-plus/auth.json +1. **Test**: Temporarily rename ~/.substack-mcp/auth.json ```bash - mv ~/.substack-mcp-plus/auth.json ~/.substack-mcp-plus/auth.json.bak + mv ~/.substack-mcp/auth.json ~/.substack-mcp/auth.json.bak ``` 2. Try "list drafts" - should show authentication error 3. Restore file: ```bash - mv ~/.substack-mcp-plus/auth.json.bak ~/.substack-mcp-plus/auth.json + mv ~/.substack-mcp/auth.json.bak ~/.substack-mcp/auth.json ``` ### Test Invalid Post IDs @@ -216,7 +216,7 @@ def hello(): 1. **Check Logs** ```bash - tail -100 ~/Library/Logs/Claude/mcp-server-substack-mcp-plus.log + tail -100 ~/Library/Logs/Claude/mcp-server-substack-mcp.log ``` - [ ] No Python tracebacks - [ ] No "ERROR" level messages (except for tested errors) @@ -235,4 +235,4 @@ def hello(): **Tested by**: ________________ **Date**: ________________ -**Claude Desktop Version**: ________________ \ No newline at end of file +**Claude Desktop Version**: ________________ diff --git a/docs/formatting.md b/docs/formatting.md index 8ed1224..f2df223 100644 --- a/docs/formatting.md +++ b/docs/formatting.md @@ -1,6 +1,6 @@ -# Formatting Guide for Substack MCP Plus +# Formatting Guide for Substack MCP -This guide demonstrates all the formatting options available when creating posts with Substack MCP Plus. The server accepts Markdown, HTML, or plain text and converts it to Substack's rich text format. +This guide demonstrates all the formatting options available when creating posts with Substack MCP. The server accepts Markdown, HTML, or plain text and converts it to Substack's rich text format. ## Table of Contents @@ -120,10 +120,10 @@ function greetReaders() { ```bash # Install the package -pip install substack-mcp-plus +npm install -g github:IgnazioDS/Substak-MCP # Run the server -python -m src.server +substack-mcp ``` ```` @@ -405,4 +405,4 @@ Once uploaded, use the CDN URL in your markdown: Substack supports most CommonMark specifications. If something doesn't work: - Try alternative syntax (e.g., `*` vs `-` for lists) - Simplify complex nested structures -- Use HTML as a fallback for advanced formatting \ No newline at end of file +- Use HTML as a fallback for advanced formatting diff --git a/examples/README.md b/examples/README.md index 0436ba0..796c872 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,6 +1,6 @@ -# Substack MCP Plus Examples +# Substack MCP Examples -This directory contains examples demonstrating how to use the Substack MCP Plus server. +This directory contains examples demonstrating how to use the Substack MCP server. ## 📁 Directory Structure @@ -18,10 +18,10 @@ This directory contains examples demonstrating how to use the Substack MCP Plus 1. **First Time Setup**: ```bash # Install the package - npm install -g @abanoub-ashraf/substack-mcp-plus + npm install -g github:IgnazioDS/Substak-MCP # Run authentication setup - substack-mcp-plus-setup + substack-mcp-setup ``` 2. **Configure Claude Desktop** - See [cli/direct-usage.md](cli/direct-usage.md) @@ -51,7 +51,7 @@ For building on top of the MCP server: ## 💡 Tips -1. **Always authenticate first** - Run `substack-mcp-plus-setup` before using any tools +1. **Always authenticate first** - Run `substack-mcp-setup` before using any tools 2. **Test with drafts** - Create drafts before publishing to production 3. **Check formatting** - Use `get_post_content` to verify formatting 4. **Use the right tool** - Each tool has a specific purpose (see main README) diff --git a/examples/claude-desktop-config.json b/examples/claude-desktop-config.json index 6f5422a..757b95d 100644 --- a/examples/claude-desktop-config.json +++ b/examples/claude-desktop-config.json @@ -1,7 +1,7 @@ { "mcpServers": { - "substack-mcp-plus": { - "command": "substack-mcp-plus", + "substack-mcp": { + "command": "substack-mcp", "env": { "SUBSTACK_PUBLICATION_URL": "https://YOUR-PUBLICATION.substack.com" } diff --git a/examples/cli/direct-usage.md b/examples/cli/direct-usage.md index f8a4db5..1fabac9 100644 --- a/examples/cli/direct-usage.md +++ b/examples/cli/direct-usage.md @@ -6,10 +6,10 @@ This example shows how to interact with the MCP server directly from the command ```bash # Start the server -substack-mcp-plus +substack-mcp # In another terminal, send a test request -echo '{"jsonrpc": "2.0", "method": "tools/list", "params": {}, "id": 1}' | substack-mcp-plus +echo '{"jsonrpc": "2.0", "method": "tools/list", "params": {}, "id": 1}' | substack-mcp ``` ## Claude Desktop Configuration @@ -28,8 +28,8 @@ Add to your Claude Desktop config file: ```json { "mcpServers": { - "substack-mcp-plus": { - "command": "substack-mcp-plus", + "substack-mcp": { + "command": "substack-mcp", "env": { "SUBSTACK_PUBLICATION_URL": "https://YOUR-PUBLICATION.substack.com" } @@ -46,7 +46,7 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; const transport = new StdioClientTransport({ - command: 'substack-mcp-plus' + command: 'substack-mcp' }); const client = new Client({ @@ -78,14 +78,14 @@ const result = await client.callTool({ ```bash # Enable debug logging export DEBUG=mcp:* -substack-mcp-plus +substack-mcp # Check server info -echo '{"jsonrpc": "2.0", "method": "initialize", "params": {"capabilities": {}}, "id": 1}' | substack-mcp-plus +echo '{"jsonrpc": "2.0", "method": "initialize", "params": {"capabilities": {}}, "id": 1}' | substack-mcp ``` ## Common Issues 1. **"Python not found"**: Make sure Python 3.10+ is installed 2. **"Module not found"**: Run `pip install -e .` in the project directory -3. **"Authentication failed"**: Run `substack-mcp-plus-setup` to re-authenticate \ No newline at end of file +3. **"Authentication failed"**: Run `substack-mcp-setup` to re-authenticate \ No newline at end of file diff --git a/ops/publish-npm.sh b/ops/publish-npm.sh index 055260b..090fbeb 100755 --- a/ops/publish-npm.sh +++ b/ops/publish-npm.sh @@ -27,4 +27,4 @@ echo "Publishing to npm..." npm publish --access public echo "✅ Package published successfully to npm!" -echo "📦 View at: https://www.npmjs.com/package/substack-mcp-plus" +echo "📦 View at: https://www.npmjs.com/package/substack-mcp" diff --git a/package-lock.json b/package-lock.json index f4ca88c..11f5c97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "@ignaziods/substack-mcp-plus", + "name": "@ignaziods/substack-mcp", "version": "1.0.5", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@ignaziods/substack-mcp-plus", + "name": "@ignaziods/substack-mcp", "version": "1.0.5", "hasInstallScript": true, "license": "MIT", @@ -13,8 +13,8 @@ "node-pty": "^1.0.0" }, "bin": { - "substack-mcp-plus": "src/index.js", - "substack-mcp-plus-setup": "src/setup.js" + "substack-mcp": "src/index.js", + "substack-mcp-setup": "src/setup.js" }, "engines": { "node": ">=16.0.0", diff --git a/package.json b/package.json index d08291d..ee7cce5 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { - "name": "@ignaziods/substack-mcp-plus", + "name": "@ignaziods/substack-mcp", "version": "1.0.5", "description": "Unofficial Substack MCP server with 29 tools, browser auth, rich text support, public research, and strategy helpers. Not affiliated with Substack Inc.", "type": "module", "main": "src/index.js", "bin": { - "substack-mcp-plus": "src/index.js", - "substack-mcp-plus-setup": "src/setup.js" + "substack-mcp": "src/index.js", + "substack-mcp-setup": "src/setup.js" }, "preferGlobal": true, "scripts": { diff --git a/pyproject.toml b/pyproject.toml index ad7d2d7..f7e36d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["setuptools>=68.0"] build-backend = "setuptools.build_meta" [project] -name = "substack-mcp-plus" +name = "substack-mcp" version = "1.0.5" description = "Unofficial MCP server for Substack with rich text formatting (not affiliated with Substack Inc.)" requires-python = ">=3.10" diff --git a/scripts/postinstall.js b/scripts/postinstall.js index f33ff4c..7b176a3 100644 --- a/scripts/postinstall.js +++ b/scripts/postinstall.js @@ -22,7 +22,7 @@ function getPythonVersion(cmd) { } function supportsVirtualEnv(cmd) { - const probeRoot = mkdtempSync(join(tmpdir(), 'substack-mcp-plus-venv-probe-')); + const probeRoot = mkdtempSync(join(tmpdir(), 'substack-mcp-venv-probe-')); const probeVenv = join(probeRoot, 'venv'); try { @@ -90,7 +90,7 @@ export function findPython() { } export function runPostInstall() { - console.log('🔧 Setting up Substack MCP Plus...'); + console.log('🔧 Setting up Substack MCP...'); try { const pythonCmd = findPython(); @@ -113,12 +113,12 @@ export function runPostInstall() { console.log('✅ Setup complete!'); console.log(''); console.log('🎯 Next steps:'); - console.log(' 1. Run: python setup_auth.py'); + console.log(' 1. Run: substack-mcp-setup'); console.log(' 2. Add to Claude Desktop config:'); console.log(' {'); console.log(' "mcpServers": {'); - console.log(' "substack-mcp-plus": {'); - console.log(' "command": "substack-mcp-plus"'); + console.log(' "substack-mcp": {'); + console.log(' "command": "substack-mcp"'); console.log(' }'); console.log(' }'); console.log(' }'); diff --git a/setup.sh b/setup.sh index 29fc4fa..89c1957 100755 --- a/setup.sh +++ b/setup.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Substack MCP Plus - Quick Setup Script +# Substack MCP - Quick Setup Script # This script sets up your development environment automatically set -e # Exit on error @@ -13,7 +13,7 @@ NC='\033[0m' # No Color # Header echo -e "${BLUE}================================================${NC}" -echo -e "${BLUE} Substack MCP Plus - Environment Setup${NC}" +echo -e "${BLUE} Substack MCP - Environment Setup${NC}" echo -e "${BLUE}================================================${NC}" echo "" @@ -173,4 +173,4 @@ else echo " source venv/bin/activate" fi echo "" -echo -e "${GREEN}Happy testing! 🚀${NC}" \ No newline at end of file +echo -e "${GREEN}Happy testing! 🚀${NC}" diff --git a/setup_auth.py b/setup_auth.py index 92e1814..e4bacf7 100755 --- a/setup_auth.py +++ b/setup_auth.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 -# ABOUTME: Interactive browser authentication setup for Substack MCP Plus. +# ABOUTME: Interactive browser authentication setup for Substack MCP. # ABOUTME: Captures Substack session cookies after user-driven CAPTCHA/login. """ -Interactive authentication setup for Substack MCP Plus +Interactive authentication setup for Substack MCP Handles browser automation and CAPTCHA challenges """ @@ -39,7 +39,7 @@ def __init__(self): async def run(self): """Run the interactive setup process""" - print("\n🚀 Substack MCP Plus - Authentication Setup") + print("\n🚀 Substack MCP - Authentication Setup") print("=" * 50) print("\nThis wizard will help you set up secure authentication.") print("Your credentials will be encrypted and stored securely.\n") @@ -78,7 +78,7 @@ async def run(self): # Test the authentication if await self._test_authentication(session_cookies): - print("\n🎉 Setup complete! You can now use Substack MCP Plus.") + print("\n🎉 Setup complete! You can now use Substack MCP.") self._show_config_example() return True else: @@ -397,9 +397,8 @@ def _show_config_example(self): { "mcpServers": { - "substack-mcp-plus": { - "command": "python", - "args": ["-m", "src.server"], + "substack-mcp": { + "command": "substack-mcp", "env": { "SUBSTACK_PUBLICATION_URL": "%s" } diff --git a/src/__init__.py b/src/__init__.py index b63d305..3ecf61c 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,2 +1,2 @@ -# ABOUTME: Package initialization for substack-mcp-plus +# ABOUTME: Package initialization for substack-mcp. # ABOUTME: This makes the src directory a Python package diff --git a/src/handlers/auth_handler.py b/src/handlers/auth_handler.py index aa91999..39e1424 100644 --- a/src/handlers/auth_handler.py +++ b/src/handlers/auth_handler.py @@ -83,7 +83,7 @@ def __init__(self) -> None: if not has_stored_auth and not has_env_auth: raise ValueError( - "No authentication found. Please run 'substack-mcp-plus-setup' to configure authentication, " + "No authentication found. Please run 'substack-mcp-setup' to configure authentication, " "or provide SUBSTACK_EMAIL/SUBSTACK_PASSWORD or SUBSTACK_SESSION_TOKEN environment variables." ) @@ -252,14 +252,14 @@ async def authenticate(self) -> SubstackApi: logger.error(f"Email/password authentication failed: {e}") if "captcha" in str(e).lower(): raise Exception( - "CAPTCHA detected. Please run 'substack-mcp-plus-setup' to authenticate " + "CAPTCHA detected. Please run 'substack-mcp-setup' to authenticate " "through the browser and set up automatic token management." ) raise raise Exception( "No valid authentication method available. " - "Please run 'substack-mcp-plus-setup' to configure authentication." + "Please run 'substack-mcp-setup' to configure authentication." ) def _create_session_client(self, session_token: str) -> _CookieClientResource: @@ -313,7 +313,7 @@ async def _refresh_token_background(self) -> None: # This would require re-authenticating through the browser # For now, we just log that refresh is needed logger.info( - "Token refresh needed - user should run substack-mcp-plus-setup again" + "Token refresh needed - user should run substack-mcp-setup again" ) # In a future enhancement, we could: @@ -331,7 +331,7 @@ def get_headers(self) -> Dict[str, str]: Headers dict with authentication cookies """ headers = { - "User-Agent": "substack-mcp-plus/2.0.0", + "User-Agent": "substack-mcp/2.0.0", "Content-Type": "application/json", } diff --git a/src/handlers/research_handler.py b/src/handlers/research_handler.py index 353cab8..9786de8 100644 --- a/src/handlers/research_handler.py +++ b/src/handlers/research_handler.py @@ -176,7 +176,7 @@ class ResearchHandler: """Discovers and summarizes Substack research results.""" USER_AGENT = ( - f"substack-mcp-plus-research/{SERVER_VERSION} " + f"substack-mcp-research/{SERVER_VERSION} " "(+https://github.com/IgnazioDS/Substak-MCP)" ) diff --git a/src/index.js b/src/index.js index ea6ce29..8342af9 100755 --- a/src/index.js +++ b/src/index.js @@ -108,7 +108,7 @@ pythonProcess.on('exit', (code, signal) => { console.error('\n❌ Python server exited with an error'); console.error('💡 Common solutions:'); console.error(' 1. Install dependencies: pip install -e .'); - console.error(' 2. Run setup: substack-mcp-plus-setup'); + console.error(' 2. Run setup: substack-mcp-setup'); console.error(' 3. Check your Python environment has required packages'); } process.exit(code || 0); diff --git a/src/server.py b/src/server.py index c501bbf..a587257 100644 --- a/src/server.py +++ b/src/server.py @@ -1,4 +1,4 @@ -# ABOUTME: Main MCP server implementation for Substack MCP Plus +# ABOUTME: Main MCP server implementation for Substack MCP. # ABOUTME: Provides tools for creating, updating, publishing posts with rich formatting import asyncio @@ -38,7 +38,7 @@ class SubstackMCPServer: def __init__(self) -> None: """Initialize the MCP server""" - self.server = Server("substack-mcp-plus") + self.server = Server("substack-mcp") self._listed_tool_names: tuple[str, ...] = () self._dispatch_tool_names: tuple[str, ...] = () self._confirmation_tokens: Dict[str, Dict[str, Any]] = {} @@ -2002,7 +2002,7 @@ async def run(self) -> None: read_stream, write_stream, InitializationOptions( - server_name="substack-mcp-plus", + server_name="substack-mcp", server_version=SERVER_VERSION, capabilities=self.server.get_capabilities( NotificationOptions(), diff --git a/src/setup.js b/src/setup.js index 7b82b83..2d9b29c 100755 --- a/src/setup.js +++ b/src/setup.js @@ -15,7 +15,7 @@ const venvPython = process.platform === 'win32' const setupScript = join(projectRoot, 'setup_auth.py'); -console.log('🔧 Starting Substack MCP Plus authentication setup...\n'); +console.log('🔧 Starting Substack MCP authentication setup...\n'); // Spawn the Python setup script const setupProcess = spawn(venvPython, [setupScript], { diff --git a/src/simple_auth_manager.py b/src/simple_auth_manager.py index d39f6e8..fc2fac4 100644 --- a/src/simple_auth_manager.py +++ b/src/simple_auth_manager.py @@ -1,5 +1,5 @@ -# ABOUTME: SimpleAuthManager class for file-based token storage without keychain -# ABOUTME: Uses encrypted local file storage to avoid macOS keychain password prompts +# ABOUTME: SimpleAuthManager handles encrypted local auth storage without keychain use. +# ABOUTME: It prefers the current auth directory and reuses the legacy one when present. import base64 import json @@ -25,8 +25,16 @@ def __init__(self, publication_url: str): """ self.publication_url = publication_url - # Use a consistent location in user's home directory - self.config_dir = Path.home() / ".substack-mcp-plus" + # Prefer the current config directory but reuse the legacy one so + # existing installs keep working after the rename. + home_dir = Path.home() + legacy_config_dir = home_dir / ".substack-mcp-plus" + current_config_dir = home_dir / ".substack-mcp" + self.config_dir = ( + legacy_config_dir + if legacy_config_dir.exists() and not current_config_dir.exists() + else current_config_dir + ) self.config_dir.mkdir(exist_ok=True) os.chmod(self.config_dir, 0o700) diff --git a/tests/README.md b/tests/README.md index 0a26cd1..be5e843 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,6 +1,6 @@ # Test Suite Documentation -This directory contains all tests for the Substack MCP Plus project. We practice Test-Driven Development (TDD) to ensure code quality and reliability. +This directory contains all tests for the Substack MCP project. We practice Test-Driven Development (TDD) to ensure code quality and reliability. ## Test Structure @@ -113,4 +113,4 @@ Tests run automatically on: - Multiple Python versions (3.10, 3.11, 3.12) - Multiple Node versions (18.x, 20.x) -See `.github/workflows/ci.yml` for CI configuration. \ No newline at end of file +See `.github/workflows/ci.yml` for CI configuration. diff --git a/tests/__init__.py b/tests/__init__.py index 0465fd7..70474e1 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,2 +1,2 @@ -# ABOUTME: Test package for substack-mcp-plus +# ABOUTME: Test package for substack-mcp. # ABOUTME: Contains unit and integration tests diff --git a/tests/integration/fixed_comprehensive_test.py b/tests/integration/fixed_comprehensive_test.py index 524b6c1..337f2d3 100644 --- a/tests/integration/fixed_comprehensive_test.py +++ b/tests/integration/fixed_comprehensive_test.py @@ -27,7 +27,7 @@ async def create_fixed_comprehensive_test(): # Create comprehensive test content with ALL formatting types content = """# 🎯 FIXED Comprehensive Markdown Test -Welcome to the **FIXED** comprehensive test of all markdown formatting features! This post demonstrates that our Substack MCP Plus server now works correctly with the python-substack library. +Welcome to the **FIXED** comprehensive test of all markdown formatting features! This post demonstrates that our Substack MCP server now works correctly with the python-substack library. ## Text Formatting Showcase @@ -139,7 +139,7 @@ def convert_markdown(self, content: str) -> list: ```javascript /* - * Substack MCP Plus - JavaScript Integration Example + * Substack MCP - JavaScript Integration Example */ class SubstackConnector { @@ -308,7 +308,7 @@ def process_paywall_markers(content: str, blocks: list) -> list: ## Comprehensive Testing Summary -This comprehensive test post demonstrates **ALL** the markdown formatting capabilities of our Substack MCP Plus server: +This comprehensive test post demonstrates **ALL** the markdown formatting capabilities of our Substack MCP server: ### ✅ Successfully Tested Features: @@ -334,7 +334,7 @@ def process_paywall_markers(content: str, blocks: list) -> list: ## Final Conclusion -**🎉 Our Substack MCP Plus server is now fully functional and ready for production use!** +**🎉 Our Substack MCP server is now fully functional and ready for production use!** This comprehensive test demonstrates that we've successfully: @@ -344,7 +344,7 @@ def process_paywall_markers(content: str, blocks: list) -> list: - ✅ **Enabled seamless Claude Desktop integration** - ✅ **Delivered professional-grade content creation tools** -Thank you for testing our **Substack MCP Plus** server! 🚀✨ +Thank you for testing our **Substack MCP** server! 🚀✨ --- diff --git a/tests/integration/full_test_post.py b/tests/integration/full_test_post.py index 3daea3a..611aeb1 100644 --- a/tests/integration/full_test_post.py +++ b/tests/integration/full_test_post.py @@ -27,7 +27,7 @@ async def create_comprehensive_test_post(): # Create comprehensive test content content = """# Comprehensive Markdown Test Post -Welcome to this **comprehensive test** of all markdown formatting features available in our Substack MCP Plus server! +Welcome to this **comprehensive test** of all markdown formatting features available in our Substack MCP server! ## Text Formatting @@ -79,7 +79,7 @@ async def create_comprehensive_test_post(): ```python def hello_world(): - print("Hello from Substack MCP Plus!") + print("Hello from Substack MCP!") # This is a comment numbers = [1, 2, 3, 4, 5] @@ -150,7 +150,7 @@ def hello_world(): ## Conclusion -This comprehensive test post demonstrates all the markdown formatting capabilities of our Substack MCP Plus server: +This comprehensive test post demonstrates all the markdown formatting capabilities of our Substack MCP server: 1. ✅ Headers (H1-H6) 2. ✅ Text formatting (bold, italic, code) @@ -162,7 +162,7 @@ def hello_world(): 8. ✅ Mixed formatting 9. ✅ Paywall integration -**Thank you for testing our Substack MCP Plus server!** 🚀""" +**Thank you for testing our Substack MCP server!** 🚀""" # Create the post handler post_handler = PostHandler(client) @@ -174,7 +174,7 @@ def hello_world(): result = await post_handler.create_draft( title="🧪 Comprehensive Markdown Test - All Formatting Types", content=content, - subtitle="Testing every markdown feature supported by Substack MCP Plus", + subtitle="Testing every markdown feature supported by Substack MCP", content_type="markdown", ) diff --git a/tests/integration/test_claude_desktop_integration.py b/tests/integration/test_claude_desktop_integration.py index db23d69..df4891e 100644 --- a/tests/integration/test_claude_desktop_integration.py +++ b/tests/integration/test_claude_desktop_integration.py @@ -28,7 +28,7 @@ async def test_claude_desktop_integration(): print("\n🔧 Step 1: Initializing MCP Server...") server = SubstackMCPServer() print("✅ MCP Server initialized successfully") - print(f" Server name: substack-mcp-plus") + print(f" Server name: substack-mcp") print(f" Handlers: {type(server.auth_handler).__name__}") # Test all tools are available @@ -89,7 +89,7 @@ async def test_claude_desktop_integration(): # This represents the MCP integration class ClaudeDesktopIntegration: def __init__(self): - self.mcp_server = "substack-mcp-plus" + self.mcp_server = "substack-mcp" self.tools = 7 self.status = "fully_operational" @@ -256,8 +256,8 @@ def create_post(self, title, content): with open(config_path, "r") as f: config = json.load(f) - if "substack-mcp-plus" in config.get("mcpServers", {}): - server_config = config["mcpServers"]["substack-mcp-plus"] + if "substack-mcp" in config.get("mcpServers", {}): + server_config = config["mcpServers"]["substack-mcp"] print(f"✅ MCP server configuration verified:") print(f" Command: {server_config.get('command', 'Not found')}") print(f" Args: {server_config.get('args', [])}") @@ -268,7 +268,7 @@ def create_post(self, title, content): if "SUBSTACK_PUBLICATION_URL" in env_vars: print(f" ✅ Publication URL configured") else: - print(f"⚠️ substack-mcp-plus not found in Claude Desktop config") + print(f"⚠️ substack-mcp not found in Claude Desktop config") except Exception as e: print(f"⚠️ Could not read config: {str(e)[:100]}...") diff --git a/tests/integration/test_final_comprehensive.py b/tests/integration/test_final_comprehensive.py index ae11716..a0993b8 100644 --- a/tests/integration/test_final_comprehensive.py +++ b/tests/integration/test_final_comprehensive.py @@ -170,7 +170,7 @@ def substack_mcp_demo(): --- -*Created with Substack MCP Plus - Making newsletter writing effortless!*""" +*Created with Substack MCP - Making newsletter writing effortless!*""" print("📝 Creating final comprehensive test post...") diff --git a/tests/integration/test_safe_approach_final.py b/tests/integration/test_safe_approach_final.py index f21a7f6..ca363e9 100644 --- a/tests/integration/test_safe_approach_final.py +++ b/tests/integration/test_safe_approach_final.py @@ -110,7 +110,7 @@ def substack_mcp(): --- -🎉 **The Substack MCP Plus server is ready for production use!**""" +🎉 **The Substack MCP server is ready for production use!**""" print("📝 Creating final test post...") diff --git a/tests/test_research_handler.py b/tests/test_research_handler.py index e371f34..de1d0a8 100644 --- a/tests/test_research_handler.py +++ b/tests/test_research_handler.py @@ -10,7 +10,7 @@ def test_user_agent_is_transparent(): handler = ResearchHandler() - assert f"substack-mcp-plus-research/{SERVER_VERSION}" in handler.USER_AGENT + assert f"substack-mcp-research/{SERVER_VERSION}" in handler.USER_AGENT assert "github.com/IgnazioDS/Substak-MCP" in handler.USER_AGENT diff --git a/tests/test_runtime_identifiers.py b/tests/test_runtime_identifiers.py new file mode 100644 index 0000000..43db999 --- /dev/null +++ b/tests/test_runtime_identifiers.py @@ -0,0 +1,29 @@ +# ABOUTME: Verifies package and runtime identifiers use the current repo naming. +# ABOUTME: Guards the CLI, auth storage, and MCP server against stale plus-era names. + +import json +from pathlib import Path + +from src.server import SubstackMCPServer + + +def test_package_json_uses_substack_mcp_names(): + package_json = json.loads(Path("package.json").read_text()) + + assert package_json["name"] == "@ignaziods/substack-mcp" + assert package_json["bin"] == { + "substack-mcp": "src/index.js", + "substack-mcp-setup": "src/setup.js", + } + + +def test_pyproject_uses_substack_mcp_name(): + pyproject_text = Path("pyproject.toml").read_text() + + assert 'name = "substack-mcp"' in pyproject_text + + +def test_server_registers_substack_mcp_name(): + server = SubstackMCPServer() + + assert server.server.name == "substack-mcp" diff --git a/tests/test_simple_auth_manager.py b/tests/test_simple_auth_manager.py index f710acc..342f03d 100644 --- a/tests/test_simple_auth_manager.py +++ b/tests/test_simple_auth_manager.py @@ -31,12 +31,12 @@ def test_init_creates_directories(self, temp_dir): manager = SimpleAuthManager("https://test.substack.com") assert manager.config_dir.exists() - assert manager.config_dir.name == ".substack-mcp-plus" + assert manager.config_dir.name == ".substack-mcp" assert manager.config_dir.stat().st_mode & 0o777 == 0o700 def test_init_tightens_existing_directory_permissions(self, temp_dir): """Test that initialization tightens an existing config directory""" - config_dir = Path(temp_dir) / ".substack-mcp-plus" + config_dir = Path(temp_dir) / ".substack-mcp" config_dir.mkdir() os.chmod(config_dir, 0o755) @@ -45,6 +45,17 @@ def test_init_tightens_existing_directory_permissions(self, temp_dir): assert manager.config_dir.stat().st_mode & 0o777 == 0o700 + def test_init_reuses_legacy_directory_when_present(self, temp_dir): + """Test that existing plus-era auth storage is reused for compatibility.""" + legacy_dir = Path(temp_dir) / ".substack-mcp-plus" + legacy_dir.mkdir() + os.chmod(legacy_dir, 0o700) + + with patch("src.simple_auth_manager.Path.home", return_value=Path(temp_dir)): + manager = SimpleAuthManager("https://test.substack.com") + + assert manager.config_dir == legacy_dir + def test_store_and_retrieve_token(self, auth_manager): """Test storing and retrieving a token""" # Store a token diff --git a/tests/unit/test_auth_handler.py b/tests/unit/test_auth_handler.py index 8a5843b..f3909d5 100644 --- a/tests/unit/test_auth_handler.py +++ b/tests/unit/test_auth_handler.py @@ -346,7 +346,7 @@ def test_get_headers_with_session(self): headers = handler.get_headers() assert headers["Cookie"] == "substack.sid=test-session-token" - assert headers["User-Agent"].startswith("substack-mcp-plus/") + assert headers["User-Agent"].startswith("substack-mcp/") assert "Content-Type" in headers def test_create_session_client(self):