Misar.Blog MCP
Publish blog posts, manage drafts, generate AI cover images, and pull analytics from Misar.Blog via Claude Code, Cursor, or Windsurf.
Documentation
Misar.Blog MCP Server
Connect Claude Code, Cursor, Windsurf, or any MCP-compatible AI assistant to your Misar.Blog account. Publish articles, manage drafts, generate cover images, and pull analytics — all from your AI coding environment.
Two runtimes are available — choose based on what you already have installed:
| Runtime | Requires | Best for |
|---|---|---|
| Python (recommended) | Python 3.11+ · stdlib only | Claude Code, any lightweight setup |
| npm / npx | Node.js 18+ | Node-first workflows, CI/CD |
Contents
- Quick Start
- Option A — Python
- Option B — npm / npx
- Client Setup
- Claude Code
- Cursor
- Windsurf
- VS Code (Copilot)
- Any other MCP client
- Authentication
- API Key (recommended)
- Browser login (no copy-paste)
- Tools reference
- Usage examples
- Self-hosted Misar.Blog
- Troubleshooting
Quick Start
Fastest path — Python + Claude Code:
1. Copy the server script
cp packages/mcp/misarblog-mcp.py ~/.claude/scripts/misarblog-mcp.py chmod +x ~/.claude/scripts/misarblog-mcp.py
2. Add to Claude Code MCP settings (see below)
3. Run login in Claude Code to authenticate via browser
Fastest path — npx + any MCP client:
No install needed — just add the config below and run login
Option A — Python (no dependencies)
Uses Python's standard library only. No pip install required. Works on macOS, Linux, and Windows (with Python 3.11+).
1 · Download the script
If you cloned the MisarBlog repo:
cp packages/mcp/misarblog-mcp.py ~/.claude/scripts/misarblog-mcp.py chmod +x ~/.claude/scripts/misarblog-mcp.py
Direct download (one-liner):
mkdir -p ~/.claude/scripts curl -fsSL https://www.misar.blog/mcp/misarblog-mcp.py -o ~/.claude/scripts/misarblog-mcp.py chmod +x ~/.claude/scripts/misarblog-mcp.py
2 · Verify Python version
python3 --version # must be 3.11 or later
If you're on macOS with an older system Python, use Homebrew: brew install python.
3 · Add to your MCP client config
{ "mcpServers": { "misarblog": { "command": "python3", "args": ["~/.claude/scripts/misarblog-mcp.py"], "env": { "MISARBLOG_API_KEY": "mbk_your_key_here" } } } }
You can omit
MISARBLOG_API_KEYif you plan to use theloginbrowser flow.
Option B — npm / npx
Uses Node.js 18+ with the @modelcontextprotocol/sdk. npx fetches and caches the package on first run — no manual install needed.
Option B1 — Zero-install via npx (recommended)
{ "mcpServers": { "misarblog": { "command": "npx", "args": ["-y", "@misarblog/mcp"], "env": { "MISARBLOG_API_KEY": "mbk_your_key_here" } } } }
Option B2 — Global install
npm install -g @misarblog/mcp
Then use misarblog-mcp as the command:
{ "mcpServers": { "misarblog": { "command": "misarblog-mcp", "env": { "MISARBLOG_API_KEY": "mbk_your_key_here" } } } }
Option B3 — pnpm / yarn
pnpm add -g @misarblog/mcp
or
yarn global add @misarblog/mcp
Verify Node version
node --version # must be v18 or later
Client Setup
Claude Code
Claude Code stores MCP server config in ~/.claude/settings.json.
Edit the file:
Open in your editor
code ~/.claude/settings.json
Add the mcpServers block (create settings.json if it doesn't exist):
Reload Claude Code — MCP servers start automatically on the next session. You'll seemisarblog listed when you run /mcp in any Claude Code session.
Verify the connection:
> call get_profile
Claude Code should return your username, display name, and account status.
Cursor
Cursor stores MCP config at ~/.cursor/mcp.json (global) or .cursor/mcp.json inside a project (project-scoped, takes priority).
Global config (~/.cursor/mcp.json):
Alternative — via Cursor Settings UI:
- Open Cursor → Settings → MCP
- Click + Add new MCP server
- Fill in:
- Name:
misarblog - Command:
npx - Args:
-y @misarblog/mcp - Env:
MISARBLOG_API_KEY=mbk_your_key_here
- Name:
- Click Save — Cursor restarts the MCP daemon automatically.
Verify: open Cursor Agent mode → type use get_profile — the tool card should appear.
Windsurf
Windsurf reads MCP config from ~/.codeium/windsurf/mcp_config.json.
Reload Windsurf after saving. The MCP tools appear under the Cascade panel → Tools.
VS Code (Copilot)
VS Code reads MCP config from .vscode/mcp.json in the workspace root, or fromUser Settings (settings.json) under "mcp".
Workspace config (.vscode/mcp.json):
{ "servers": { "misarblog": { "type": "stdio", "command": "npx", "args": ["-y", "@misarblog/mcp"], "env": { "MISARBLOG_API_KEY": "mbk_your_key_here" } } } }
User settings (settings.json):
{ "mcp": { "servers": { "misarblog": { "type": "stdio", "command": "npx", "args": ["-y", "@misarblog/mcp"], "env": { "MISARBLOG_API_KEY": "mbk_your_key_here" } } } } }
Restart VS Code after saving. The Misar.Blog tools appear in GitHub Copilot Chat when you enable Agent mode (the @ icon in the chat panel).
Any other MCP client
Any MCP-compatible client that supports stdio servers works with the same pattern:
- Command:
python3(Python) ornpx(npm) - Args:
["~/.claude/scripts/misarblog-mcp.py"]or["-y", "@misarblog/mcp"] - Transport:
stdio - Env:
MISARBLOG_API_KEY=mbk_...(or useloginafter connecting)
Authentication
API Key (recommended)
- Go to Misar.Blog → Dashboard → Settings → API Keys
- Click Generate API Key — your key starts with
mbk_ - Copy it and paste into the
MISARBLOG_API_KEYenv var in your MCP config
Keys have a 100 req/min rate limit. You can revoke and regenerate at any time from the settings page.
Precedence order:
MISARBLOG_API_KEY env var → ~/.misarblog/config.json → prompt to run login
Browser login (no copy-paste)
If you'd rather not handle the key manually, omit MISARBLOG_API_KEY from the config and runlogin as your first tool call. The flow:
- The MCP server starts a temporary HTTP listener on
127.0.0.1(random port 9001–9099) - Your default browser opens to
https://www.misar.blog/dashboard/settings/api?mcp_port=<port> - You click Authorize MCP Access — you must be logged in to Misar.Blog
- The page sends your API key directly to the local listener
- The key is saved to
~/.misarblog/config.json— no clipboard involved - All subsequent tool calls use this saved key automatically
The listener accepts connections from 127.0.0.1 only and shuts down after 120 seconds.
Example prompt:
Connect my Misar.Blog account using login
Claude will call the tool, open your browser, and confirm once you've authorized.
Tools reference
The server exposes 23 tools. Names are unprefixed — call them exactly as shown (e.g. login, publish_article, get_analytics_summary).
Auth
| Tool | Description | Required params |
|---|---|---|
| login | Browser-based auth — saves key to ~/.misarblog/config.json | — |
| status | Check whether you're authenticated and which account is connected | — |
Articles
| Tool | Description | Required params |
|---|---|---|
| list_my_articles | List your articles, optionally filtered by status | — |
| get_article | Fetch a single article by slug, including full markdown | slug |
| publish_article | Publish now or schedule via ISO 8601 datetime | title, body_markdown |
| create_draft | Save a draft for review in the web editor | title, body_markdown |
AI
| Tool | Description | Required params |
|---|---|---|
| research_topic | Research a topic — insights, sources, and a content outline | query |
| generate_title_seo | Generate 5 SEO/AEO/GEO-optimized titles from a topic or keyword | prompt |
| suggest_titles | Generate 5 title options from your existing article content | context |
Images
| Tool | Description | Required params |
|---|---|---|
| upload_image | Upload a local image file to the Misar.Blog CDN | file_path |
| generate_cover_image | Generate an AI cover image and upload it to the CDN | prompt |
Series
| Tool | Description | Required params |
|---|---|---|
| get_series | List all your series | — |
| create_series | Create a new series to group related articles | title |
| add_to_series | Add an existing article to a series | series_slug, article_slug |
Comments
| Tool | Description | Required params |
|---|---|---|
| list_comments | Get public comments for an article (no API key required) | article_id |
Follows
| Tool | Description | Required params |
|---|---|---|
| get_follow_status | Get public follow status and follower count for a user (no API key required) | user_id |
Newsletter
| Tool | Description | Required params |
|---|---|---|
| list_newsletter_subscribers | Get your newsletter subscriber list | — |
| list_newsletter_issues | Get your sent and scheduled newsletter issues | — |
Reactions
| Tool | Description | Required params |
|---|---|---|
| get_reactions | Get reaction counts and your reactions for an article | article_id |
| add_reaction | Add a reaction to an article (no-ops if already reacted) | article_id, type |
| remove_reaction | Remove a specific reaction from an article | article_id, type |
Analytics
| Tool | Description | Required params |
|---|---|---|
| get_analytics_summary | Views, revenue, and subscribers for a time period (up to 365 days) | — |
Profile
| Tool | Description | Required params |
|---|---|---|
| get_profile | Your creator profile — username, display name, bio, Stripe status | — |
Tool parameters
login
| Param | Type | Default | Description |
|---|---|---|---|
| port | number | random 9001–9099 | Local callback port (9001–9099) |
| base_url | string | https://www.misar.blog | Misar.Blog base URL for self-hosted instances |
| force | boolean | false | Force re-authentication even if already logged in (rotates your API key) |
list_my_articles
| Param | Type | Default | Description |
|---|---|---|---|
| status | string | all | Filter: draft · published · scheduled · archived (omit for all) |
| limit | number | 20 | Number of articles to return, 1–100 |
get_article
| Param | Type | Required | Description |
|---|---|---|---|
| slug | string | yes | The article slug |
publish_article
| Param | Type | Required | Description |
|---|---|---|---|
| title | string | yes | Article title (max 250 chars) |
| body_markdown | string | yes | Full article body in Markdown |
| tags | string[] | no | Up to 10 tags |
| cover_image_url | string | no | URL of the cover image |
| schedule_at | string | no | ISO 8601 timestamp to schedule; omit to publish immediately |
| visibility | string | no | public · subscribers · paid · private (default: public) |
create_draft
| Param | Type | Required | Description |
|---|---|---|---|
| title | string | yes | Draft title |
| body_markdown | string | yes | Full article body in Markdown |
| tags | string[] | no | Tags for the draft |
research_topic
| Param | Type | Required | Description |
|---|---|---|---|
| query | string | yes | Research topic or question (5–500 chars). Be specific for best results |
generate_title_seo
| Param | Type | Required | Description |
|---|---|---|---|
| prompt | string | yes | Your topic or target keywords (3–500 chars) |
| context | string | no | Existing article content (plain text or markdown, max 8000 chars) to align titles |
suggest_titles
| Param | Type | Required | Description |
|---|---|---|---|
| context | string | yes | Your article content in plain text or markdown (20–8000 chars) |
upload_image
| Param | Type | Required | Description |
|---|---|---|---|
| file_path | string | yes | Absolute path to the image file (JPEG, PNG, WebP, or GIF) |
generate_cover_image
| Param | Type | Default | Description |
|---|---|---|---|
| prompt | string | — | Description of the image to generate (max 1000 chars) |
| size | string | 1792x1024 | 1024x1024 · 1792x1024 · 1024x1792 |
create_series
| Param | Type | Required | Description |
|---|---|---|---|
| title | string | yes | Series title |
| description | string | no | Short description of the series |
add_to_series
| Param | Type | Required | Description |
|---|---|---|---|
| series_slug | string | yes | The series slug |
| article_slug | string | yes | The article slug to add |
| position | number | no | 1-indexed position; appends to end if omitted |
list_comments
| Param | Type | Default | Description |
|---|---|---|---|
| article_id | string | — | UUID of the article to fetch comments for (required) |
| limit | number | 20 | Max results, 1–100 |
| offset | number | 0 | Pagination offset |
get_follow_status
| Param | Type | Required | Description |
|---|---|---|---|
| user_id | string | yes | UUID of the profile to check follow status for |
list_newsletter_subscribers
| Param | Type | Default | Description |
|---|---|---|---|
| limit | number | 20 | Max results, 1–100 |
| offset | number | 0 | Pagination offset |
list_newsletter_issues
| Param | Type | Default | Description |
|---|---|---|---|
| limit | number | 10 | Max results, 1–50 |
get_reactions
| Param | Type | Required | Description |
|---|---|---|---|
| article_id | string | yes | UUID of the article |
add_reaction
| Param | Type | Required | Description |
|---|---|---|---|
| article_id | string | yes | UUID of the article |
| type | string | yes | Reaction type: like · clap · bookmark |
remove_reaction
| Param | Type | Required | Description |
|---|---|---|---|
| article_id | string | yes | UUID of the article |
| type | string | yes | Reaction type to remove: like · clap · bookmark |
get_analytics_summary
| Param | Type | Default | Description |
|---|---|---|---|
| days | number | 30 | Look-back window, 1–365 |
Usage examples
These are prompts you can send directly in Claude Code or Cursor Agent mode:
Publish a new article:
Write a 1000-word article about "Why AI-first blogging changes SEO forever"
and publish it on my Misar.Blog with tags ["AI", "SEO", "blogging"].
Draft with a generated cover image:
Generate a dark, futuristic cover image for an article titled "Building with MCP".
Then create a draft with that image as the cover.
Check performance:
Show me my analytics for the last 90 days.
Publish on a schedule:
Write a short announcement post and schedule it to publish tomorrow at 9am UTC.
Organize a series:
List my articles with status "published", then create a series called "AI Writing Guide"
and add the last 3 articles to it in chronological order.
Self-hosted Misar.Blog
If you run your own Misar.Blog instance, set MISARBLOG_BASE_URL to your domain:
{ "mcpServers": { "misarblog": { "command": "python3", "args": ["~/.claude/scripts/misarblog-mcp.py"], "env": { "MISARBLOG_API_KEY": "mbk_your_key_here", "MISARBLOG_BASE_URL": "https://blog.yourdomain.com" } } } }
MISARBLOG_BASE_URL can also be stored in ~/.misarblog/config.json (written by login):
{ "api_key": "mbk_...", "username": "yourname", "base_url": "https://blog.yourdomain.com" }
Troubleshooting
"Not configured" on every tool call
The server can't find your API key. Either:
- Set
MISARBLOG_API_KEYin the MCP config env block, or - Run
loginonce to save it to~/.misarblog/config.json
"API key invalid or expired"
Your key was revoked. Go to Dashboard → Settings → API Keys and generate a new one, or run login again to get a fresh key via the browser flow.
"Rate limited (100 req/min)"
You've exceeded the API rate limit. Wait 60 seconds and retry. If you're running automated pipelines, add a short delay between tool calls.
Browser doesn't open during login
The server prints the URL to stderr when webbrowser.open() fails. Copy and open it manually:
Open this URL in your browser:
https://www.misar.blog/dashboard/settings/api?mcp_port=9042
You have 120 seconds from when the tool runs to click Authorize MCP Access.
python3: command not found
- macOS:
brew install pythonor install from python.org - Linux:
sudo apt install python3/sudo dnf install python3 - Windows: Install from python.org and ensure
python3is inPATH
Alternatively, switch to the npm/npx option — it only requires Node.js.
npx is slow on first run
npx -y @misarblog/mcp downloads the package on first run and caches it locally. Subsequent starts are instant. If startup time matters, use npm install -g @misarblog/mcp instead.
MCP server doesn't appear in Claude Code
Run /mcp in a Claude Code session to list active servers. If misarblog is missing:
- Check
~/.claude/settings.json— ensure themcpServers.misarblogblock is valid JSON - Verify the script path:
ls -la ~/.claude/scripts/misarblog-mcp.py - Test the server directly:
printf '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}\n' \
| MISARBLOG_API_KEY=mbk_test python3 ~/.claude/scripts/misarblog-mcp.py
You should see a JSON response listing 23 tools.
Connection refused on login callback
The local HTTP server binds to 127.0.0.1. If your browser opens on a different machine (e.g. remote VS Code over SSH), the callback won't reach the MCP server. In that case, use the API Key method instead.
Requirements
- Python runtime: Python 3.11+ · no external packages
- npm runtime: Node.js 18+ · package fetched automatically via npx
- Account: Misar.Blog creator account (sign up free)