MCP Integration
Run your entire content pipeline from VS Code, Cursor, or Claude Code.
EditorInChief exposes a Model Context Protocol server that gives any MCP-capable IDE direct access to the pipeline. Create sites, configure beats, ingest articles, and queue approvals — all without opening the dashboard.
Connection
The MCP server uses Streamable HTTP transport (JSON-RPC 2.0 over HTTP POST).
Endpoint: https://api.editorinchief.io/mcp/
Protocol: Streamable HTTP (JSON-RPC 2.0)
Version: 0.7.0
Every request requires an Authorization: Bearer <token> header. Use an API key — easier to configure once and never expires.
VS Code (GitHub Copilot)
Add to your workspace’s .vscode/mcp.json:
{
"servers": {
"editorinchief": {
"type": "http",
"url": "https://api.editorinchief.io/mcp/",
"headers": {
"Authorization": "Bearer eic_YOUR_API_KEY"
}
}
}
}
Cursor
In Cursor’s MCP settings:
{
"mcpServers": {
"editorinchief": {
"type": "http",
"url": "https://api.editorinchief.io/mcp/",
"headers": {
"Authorization": "Bearer eic_YOUR_API_KEY"
}
}
}
}
Claude Code
In ~/.claude/claude_desktop_config.json:
{
"mcpServers": {
"editorinchief": {
"type": "http",
"url": "https://api.editorinchief.io/mcp/",
"headers": {
"Authorization": "Bearer eic_YOUR_API_KEY"
}
}
}
}
Quickstart
Typical first-time setup from inside your IDE:
1. list_sites — confirm you start fresh
2. create_site — define your publication
3. create_beat — add at least one beat
4. ingest_content — push your first article
5. list_queue — see what's pending approval
6. preview_article — read the draft
Setup tools
create_site
Creates a new publication. Returns a site_id to use in subsequent calls.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | ✓ | Human-readable publication name |
domain | string | ✓ | Domain without scheme, e.g. blog.example.com |
editorial_voice | object | ✓ | See Editorial voice |
approval_mode | string | per_article (default), digest, or auto | |
target_frequency_per_week | number | Target publication rate per week | |
omnivocal_api_key | string | Omnivocal API key for publishing | |
financial_ack_at | number | Unix timestamp — required when financial_content_regulated is true |
editorial_voice sub-fields:
| Field | Type | Required | Description |
|---|---|---|---|
mission | string | ✓ | One-sentence mission statement (max 500 chars) |
tone_guardrails | string | Tone rules appended to every prompt (max 500 chars) | |
site_type | string | standard, satire, or financial | |
image_tone | string | Image generation style hint (max 200 chars) | |
financial_content_regulated | boolean | Set true for regulated financial content |
Example request
{
"jsonrpc": "2.0",
"id": 1,
"method": "create_site",
"params": {
"name": "TypeScript Weekly",
"domain": "tsweekly.dev",
"editorial_voice": {
"mission": "Weekly roundup of TypeScript news for working developers.",
"tone_guardrails": "Plain language, no marketing fluff. Short paragraphs.",
"site_type": "standard"
},
"approval_mode": "per_article"
}
}
Response
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"site_id": "site_abc123",
"name": "TypeScript Weekly",
"domain": "tsweekly.dev"
}
}
list_sites
Returns all sites for the authenticated user. No parameters required.
Response
{
"result": {
"sites": [
{
"site_id": "site_abc123",
"name": "TypeScript Weekly",
"domain": "tsweekly.dev",
"status": "active"
}
]
}
}
create_beat
Adds an editorial beat to a site. A beat defines a coverage area and which content types to generate when a matching item arrives.
| Parameter | Type | Required | Description |
|---|---|---|---|
site_id | string | ✓ | Site to add the beat to |
name | string | ✓ | Slug-style, e.g. "releases", "vc-deals" |
content_types | string[] | ✓ | One or more: short_social, status_message, long_form, github_content |
description | string | One-sentence description of what this beat covers | |
coverage | string | selective, balanced (default), or broad | |
generation_guidance | string | Extra prompt guidance for this beat | |
synthesis_mode | string | auto (default), review, or off |
Example
{
"method": "create_beat",
"params": {
"site_id": "site_abc123",
"name": "releases",
"description": "TypeScript and tooling release notes.",
"content_types": ["short_social", "long_form"],
"coverage": "selective"
}
}
Response
{
"result": {
"beat_id": "beat_xyz789",
"name": "releases",
"site_id": "site_abc123"
}
}
list_beats
Returns all beats for a site.
| Parameter | Type | Required | Description |
|---|---|---|---|
site_id | string | ✓ | Site ID |
Content tools
ingest_content
Pushes content into the pipeline and triggers the evaluator. High-scoring items are automatically queued for article generation. At least one of url, text, or repo is required.
| Parameter | Type | Required | Description |
|---|---|---|---|
site_id | string | ✓ | Target site |
url | string | * | Source URL to ingest |
text | string | * | Raw text body |
title | string | Title hint (derived from URL if omitted) | |
repo | string | * | GitHub repo in owner/repo format |
beat_hint | string | Beat name to prefer when routing |
Example — push a GitHub release
{
"method": "ingest_content",
"params": {
"site_id": "site_abc123",
"repo": "microsoft/TypeScript",
"beat_hint": "releases"
}
}
Response
{
"result": {
"item_id": "ci_def456",
"stage": "evaluating"
}
}
Returns { "status": "duplicate" } if the content was already ingested.
generate_content
Forces article generation for an already-ingested item, bypassing the evaluator score threshold.
| Parameter | Type | Required | Description |
|---|---|---|---|
item_id | string | ✓ | ContentItem ID (from ingest_content) |
content_types | string[] | Override the beat’s content types | |
persona_id | string | Override the default persona |
list_queue
Returns all articles in the pending_approval stage — your review queue.
| Parameter | Type | Required | Description |
|---|---|---|---|
site_id | string | ✓ | Site ID |
Response
{
"result": {
"articles": [
{
"article_id": "art_ghi",
"title": "TypeScript 5.8 ships strict config defaults",
"content_type": "long_form",
"beat_name": "releases",
"created_at": 1713456789
}
]
}
}
preview_article
Returns the full generated body and all per-channel variants.
| Parameter | Type | Required | Description |
|---|---|---|---|
article_id | string | ✓ | Article ID |
Response
{
"result": {
"article_id": "art_ghi",
"title": "TypeScript 5.8 ships strict config defaults",
"body": "The TypeScript team released 5.8 today, bringing...",
"stage": "pending_approval",
"content_type": "long_form",
"targets": [
{ "channel": "bluesky", "body": "TypeScript 5.8 is out..." },
{ "channel": "mastodon", "body": "TypeScript 5.8 is out..." }
]
}
}
get_clusters
Returns story clusters for a site. EIC groups related ingested items using vector similarity.
| Parameter | Type | Required | Description |
|---|---|---|---|
site_id | string | ✓ | Site ID |
status | string | Filter: detected, queued_for_synthesis, synthesized, dismissed |
synthesize_cluster
Queues a cluster for synthesis — EIC generates a dedicated article drawing from all items in the cluster.
| Parameter | Type | Required | Description |
|---|---|---|---|
cluster_id | string | ✓ | StoryCluster ID (from get_clusters) |
Error handling
All errors follow JSON-RPC 2.0 error object format:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32000,
"message": "editorial_voice.mission is required"
}
}
| Code | Meaning |
|---|---|
-32700 | Parse error — malformed JSON |
-32600 | Invalid request — not valid JSON-RPC 2.0 |
-32601 | Method not found |
-32000 | Tool error — descriptive message in error.message |
Plan limit errors, validation errors, and access-denied errors all use code -32000 with a human-readable message your IDE will surface directly.