BlogPublisher
Multi-platform blog publishing system that integrates with ResearchAgent for automated content distribution.
Overview
BlogPublisher receives SEO-optimized articles from ResearchAgent and publishes them to multiple platforms:
- Personal website blog
- Twitter/X (as threads)
- Substack (email newsletter)
- Facebook (planned)
- Instagram (planned)
Architecture
ResearchAgent (SEO writing) → BlogPublisher (distribution) → Multiple Platforms
Features
✅ Article Management
- Save articles with SEO metadata
- Draft/scheduled/published status tracking
- PostgreSQL storage
✅ Multi-Platform Publishing
- Publish to 4+ platforms simultaneously
- Platform-specific content formatting
- Publication tracking and analytics
✅ Scheduling
- Schedule posts for future publication
- Automated cron-based publishing
- Retry logic for failures
✅ MCP Integration
- 7 MCP tools for Claude Desktop
- Seamless integration with ResearchAgent
- Single conversation workflow
Quick Start
1. Prerequisites
- Python 3.10+
- PostgreSQL 14+
- Platform API credentials (see API Setup below)
2. Installation
cd ~/1_REPOS/BlogPublisher
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Setup environment
cp .env.example .env
# Edit .env with your credentials
3. Database Setup
# Create PostgreSQL database
createdb blogpublisher
# Update DATABASE_URL in .env
DATABASE_URL=postgresql://user:password@localhost:5432/blogpublisher
# Initialize database (tables auto-created on first run)
python backend/app.py # Runs migrations
4. Claude Desktop Configuration
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"research-agent": {
"command": "python",
"args": ["/Users/tmac/1_REPOS/ResearchAgent/backend/mcp_server.py"]
},
"blogpublisher": {
"command": "python",
"args": ["/Users/tmac/1_REPOS/BlogPublisher/backend/mcp_server.py"],
"env": {
"DATABASE_URL": "postgresql://localhost:5432/blogpublisher"
}
}
}
}
Restart Claude Desktop.
Usage
Daily Blogging Workflow
In Claude Desktop:
1. "Write SEO article about [topic]"
→ ResearchAgent creates optimized article
2. "Save this article to BlogPublisher"
→ Returns article_id
3. "Publish to website and LinkedIn immediately"
→ Publishes to both platforms
4. "Schedule Twitter thread for tomorrow at 10 AM"
→ Queues Twitter publication
MCP Tools
save_article ``json { "title": "Article Title", "content": "Markdown content...", "summary": "Brief summary", "keywords": ["seo", "keywords"], "seo_score": {"score": 85} } ` Returns: article_id`
publish_article ``json { "article_id": "uuid", "platforms": ["website", "linkedin", "twitter", "substack"] } `` Returns: Publication results per platform
schedule_article ``json { "article_id": "uuid", "platforms": ["linkedin", "twitter"], "publish_time": "tomorrow at 6 AM" } `` Returns: Schedule confirmation
get_article ``json { "article_id": "uuid" } `` Returns: Full article with publication status
list_articles ``json { "status": "published", "limit": 10 } `` Returns: List of articles
format_for_platform ``json { "article_id": "uuid", "platform": "twitter" } `` Returns: Platform-optimized content
generate_social_posts ``json { "article_id": "uuid" } `` Returns: Social media variants for all platforms
API Setup
Required Credentials
Website Blog
WEBSITE_API_URL: Your blog API endpointWEBSITE_API_KEY: API authentication key
- Create LinkedIn App: https://www.linkedin.com/developers/apps
- Get OAuth 2.0 access token
- Set
LINKEDIN_ACCESS_TOKEN
Twitter/X
- Create Twitter Developer account: https://developer.twitter.com
- Create App and get API keys
- Set:
TWITTER_API_KEYTWITTER_API_SECRETTWITTER_ACCESS_TOKENTWITTER_ACCESS_SECRET
Substack
- Get Substack API credentials from your publication settings
- Set:
SUBSTACK_API_KEYSUBSTACK_PUBLICATION_ID
Optional: Facebook & Instagram
FACEBOOK_ACCESS_TOKENFACEBOOK_PAGE_IDINSTAGRAM_USERNAMEINSTAGRAM_PASSWORD
Platform-Specific Formatting
- First 3 sentences as hook
- Professional tone
- 1-3 hashtags
- Link at end
Twitter/X
- Converts to thread (280 chars/tweet)
- Numbered tweets (1/N)
- Link in last tweet
- Key points extracted
Substack
- Full article as HTML email
- Subject line from title
- Preview text from summary
- Created as draft (manual publish)
Website
- Markdown to HTML conversion
- SEO frontmatter
- Categories/tags
- Featured image support
Automation
Scheduler (Cron Jobs)
Start the scheduler:
python backend/scheduler/cron.py
Or run as background service:
# Using systemd (Linux)
sudo systemctl enable blogpublisher-scheduler
sudo systemctl start blogpublisher-scheduler
# Using launchd (macOS)
# See docs/deployment/macos-launchd.md
The scheduler runs every minute and publishes any pending scheduled posts.
REST API
Optional REST API for programmatic access:
# Start API server
python backend/app.py
# Runs on http://localhost:8001
# API docs
open http://localhost:8001/docs
Endpoints
POST /articles- Create articleGET /articles- List articlesGET /articles/{id}- Get articleGET /health- Health check
Development
Project Structure
BlogPublisher/
├── backend/
│ ├── database/
│ │ ├── models.py # SQLAlchemy models
│ │ └── db.py # Database connection
│ ├── publishers/
│ │ ├── base.py # Abstract publisher
│ │ ├── website.py # Website publisher
│ │ ├── linkedin.py # LinkedIn publisher
│ │ ├── twitter.py # Twitter publisher
│ │ └── substack.py # Substack publisher
│ ├── scheduler/
│ │ └── cron.py # Automated publishing
│ ├── mcp_server.py # MCP integration
│ └── app.py # FastAPI server
├── data/
│ ├── articles/ # Article storage
│ └── media/ # Images
├── requirements.txt
├── .env.example
└── README.md
Adding New Platforms
- Create publisher class in
backend/publishers/yourplatform.py - Inherit from
BasePublisher - Implement required methods:
validate_config()format_content()publish()
- Add to
Platformenum inmodels.py - Update
get_publisher()inmcp_server.pyandcron.py
Example:
from .base import BasePublisher
class NewPlatformPublisher(BasePublisher):
def validate_config(self):
if "api_key" not in self.config:
raise ValueError("Missing api_key")
def format_content(self, content, metadata=None):
# Platform-specific formatting
return formatted_content
def publish(self, title, content, metadata=None):
# API call to publish
return {
"success": True,
"post_id": "...",
"url": "..."
}
Troubleshooting
Database Connection Issues
# Check PostgreSQL is running
pg_isready
# Test connection
psql -U user -d blogpublisher
MCP Tools Not Showing
- Check Claude Desktop config file location
- Verify Python path in config
- Restart Claude Desktop
- Check logs:
~/Library/Logs/Claude/mcp.log
Publishing Failures
Check platform API credentials:
# Test LinkedIn token
curl -H "Authorization: Bearer $LINKEDIN_ACCESS_TOKEN" \
https://api.linkedin.com/v2/me
# Test Twitter credentials
# Use backend/publishers/test_publisher.py
Testing
# Test database
python backend/database/db.py
# Test publishers
python backend/publishers/test_publisher.py
# Test MCP tools (requires running server)
python backend/mcp_server.py
Roadmap
- [x] Core article storage
- [x] Website/LinkedIn/Twitter/Substack publishers
- [x] MCP integration
- [x] Scheduling system
- [ ] Facebook & Instagram publishers
- [ ] Analytics dashboard
- [ ] Content calendar UI
- [ ] Image optimization
- [ ] Link shortening
- [ ] A/B testing
- [ ] Performance metrics
License
MIT
Support
For issues or questions:
- Create GitHub issue
- Check documentation in
/docs - See ResearchAgent integration guide











