# Meridian MCP Server Meridian exposes a [Model Context Protocol (MCP)](https://modelcontextprotocol.io) endpoint that lets external AI agents interact with the blogging platform — discovering content, publishing posts, and managing contributor accounts. ## Transport **Streamable HTTP** (MCP spec 2024-11-05) — stateless, JSON-RPC 2.0 over a single POST endpoint. | Environment | MCP Endpoint URL | |---|---| | Local dev | `http://localhost:3000/api/mcp` | | Docker (local) | `http://localhost:7860/api/mcp` | | HuggingFace Spaces | `https://mishrabp-myblogs.hf.space/api/mcp` | ## Authentication All requests require an `Authorization` header carrying the `MCP_API_KEY` configured in the server's `.env`: ``` Authorization: Bearer ``` Set `MCP_API_KEY` in `.env` (see `.env.example`). If `MCP_API_KEY` is unset the server accepts all requests — suitable only for local development. ## Protocol Handshake Before calling tools, clients must complete the initialize handshake: ```jsonc // 1. Client → Server: initialize POST /api/mcp Content-Type: application/json Authorization: Bearer { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": { "name": "my-agent", "version": "1.0" } } } // 2. Server → Client: capabilities { "jsonrpc": "2.0", "id": 1, "result": { "protocolVersion": "2024-11-05", "capabilities": { "tools": {} }, "serverInfo": { "name": "meridian-mcp", "version": "1.0.0" } } } // 3. Client → Server: initialized notification (no response expected) { "jsonrpc": "2.0", "method": "notifications/initialized" } ``` ## Available Tools ### 1. `manage_guest_user` Create, update, or delete guest contributor accounts. > **The `admin@myblogs.com` account is permanently protected and cannot be touched by this tool.** | Parameter | Type | Required | Description | |---|---|---|---| | `action` | `"create" \| "update" \| "delete"` | ✅ | Operation to perform | | `email` | string | ✅ | User's email address | | `name` | string | for create | Full display name | | `password` | string | for create | Login password (min 8 chars) | | `bio` | string | — | Short author bio | | `is_active` | boolean | — | `false` suspends without deleting | ```jsonc // Create a guest writer { "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "manage_guest_user", "arguments": { "action": "create", "email": "alice@example.com", "name": "Alice Smith", "password": "securePass123", "bio": "Tech writer and open-source enthusiast." } } } ``` --- ### 2. `list_blogs` Retrieve published posts with optional filtering. | Parameter | Type | Default | Description | |---|---|---|---| | `filter` | `"latest" \| "featured" \| "recent"` | `"latest"` | `latest` = newest-first paginated; `featured` = top 5 by views; `recent` = last 6 published | | `category` | string | — | Filter by category slug (use `list_categories`) | | `tag` | string | — | Filter by tag slug (use `list_tags`) | | `page` | integer | 1 | Page number (latest only) | | `limit` | integer | 10 | Results per page, max 50 (latest only) | ```jsonc // Get the 5 most popular posts { "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "list_blogs", "arguments": { "filter": "featured" } } } // Latest 10 posts in the "technology" category { "jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": { "name": "list_blogs", "arguments": { "category": "technology", "limit": 10 } } } ``` --- ### 3. `get_blog` Fetch the full content of a post by its URL slug. | Parameter | Type | Required | Description | |---|---|---|---| | `slug` | string | ✅ | URL slug (e.g. `"understanding-react-hooks"`) | | `summarize` | boolean | — | Generate a 2-3 sentence AI summary (requires `OPENAI_API_KEY`) | ```jsonc { "jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": { "name": "get_blog", "arguments": { "slug": "understanding-react-hooks", "summarize": true } } } ``` --- ### 4. `search_blogs` Full-text keyword search across titles, excerpts, and body content (case-insensitive SQL ILIKE). | Parameter | Type | Default | Description | |---|---|---|---| | `query` | string | ✅ required | Search term (e.g. `"machine learning"`) | | `limit` | integer | 10 | Max results, max 50 | | `include_content` | boolean | false | Append a 500-char body snippet to each result | ```jsonc { "jsonrpc": "2.0", "id": 6, "method": "tools/call", "params": { "name": "search_blogs", "arguments": { "query": "docker kubernetes", "limit": 5 } } } ``` --- ### 5. `create_blog` Publish a new blog post with rich HTML content. | Parameter | Type | Required | Description | |---|---|---|---| | `title` | string | ✅ | Post title (50-70 chars ideal) | | `content` | string | ✅ | Full HTML body — see supported tags below | | `excerpt` | string | ✅ | ~120-160 char summary for listing cards | | `category_id` | integer | — | From `list_categories` | | `tag_ids` | integer[] | — | From `list_tags` (3-6 tags recommended) | | `featured_image` | string | — | Image URL (1200×630 px, Unsplash etc.) | | `status` | `"draft" \| "published"` | `"draft"` | Visibility | | `author_name` | string | `"MCP Agent"` | Display name shown on the post | **Supported HTML tags in `content`:** ```

,

,

— Section headings

— Paragraphs , — Bold, italic — Links