Claude & MCP
Brainpercent runs a hosted MCP server. Connect it once and Claude can check your balance, pick a project, turn a URL into branded multi-platform posts, and publish them, without you writing any integration code.
Install in Claude Code
One command. Replace bp_your_key with a key from your developer settings.
claude mcp add --transport http brainpercent https://www.brainpercent.app/api/mcp \
--header "Authorization: Bearer bp_your_key"Confirm it connected:
claude mcp list
# brainpercent: https://www.brainpercent.app/api/mcp (HTTP) - ConnectedScope. claude mcp add writes to the current project by default. Add --scope user to make it available in every project on your machine.
Claude Desktop and other MCP clients
The server speaks Streamable HTTP with a JSON-RPC 2.0 body, so any client that supports remote MCP servers can use the same URL. For clients that take a JSON config file:
{
"mcpServers": {
"brainpercent": {
"type": "http",
"url": "https://www.brainpercent.app/api/mcp",
"headers": {
"Authorization": "Bearer bp_your_key"
}
}
}
}If your client reserves the Authorization header for its own auth, send the key as X-Brainpercent-Key instead. Both are accepted.
What the server exposes
Six tools. One of them spends credits; the other five are free. Only demo_post_from_url works without a key.
| Tool | Arguments | Cost | Returns |
|---|---|---|---|
check_credits | none | 0 | Wallet balance, generation allowance, plan |
list_projects | search, limit | 0 | Your projects with the ids generation accepts |
demo_post_from_url | url (required), platform | 0 | One post as text plus a rendered card. Not saved to your account. |
generate_posts | source_url + platforms (required), source_type, angle, title, project_id | 1 / platform | A content_id to poll. Branded output lands in your dashboard. |
get_content | content_id (required) | 0 | Status plus the caption, first comment and image per platform |
publish | content_id (required), platforms, scheduled_at | 0 | Queues the post to your connected accounts, or schedules it |
Ask Claude for the list yourself, or check the wire format directly:
curl -sX POST https://www.brainpercent.app/api/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "check_credits",
"inputSchema": {
"type": "object",
"properties": {}
}
},
{
"name": "list_projects",
"inputSchema": {
"type": "object",
"properties": {
"search": {
"type": "string"
},
"limit": {
"type": "integer"
}
}
}
},
{
"name": "demo_post_from_url",
"inputSchema": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"platform": {
"type": "string",
"enum": [
"linkedin",
"instagram",
"facebook",
"twitter",
"threads"
]
}
},
"required": [
"url"
]
}
},
{
"name": "generate_posts",
"inputSchema": {
"type": "object",
"properties": {
"source_url": {
"type": "string"
},
"platforms": {
"type": "array",
"items": {
"type": "string",
"enum": [
"instagram",
"facebook",
"linkedin",
"twitter",
"threads",
"tiktok",
"bluesky",
"pinterest",
"google_business",
"telegram"
]
}
},
"source_type": {
"type": "string",
"enum": [
"website",
"blog",
"youtube"
]
},
"angle": {
"type": "string"
},
"title": {
"type": "string"
},
"project_id": {
"type": "string"
}
},
"required": [
"source_url",
"platforms"
]
}
},
{
"name": "get_content",
"inputSchema": {
"type": "object",
"properties": {
"content_id": {
"type": "string"
}
},
"required": [
"content_id"
]
}
},
{
"name": "publish",
"inputSchema": {
"type": "object",
"properties": {
"content_id": {
"type": "string"
},
"platforms": {
"type": "array",
"items": {
"type": "string"
}
},
"scheduled_at": {
"type": "string"
}
},
"required": [
"content_id"
]
}
}
]
}
}A worked example per tool
In Claude you just ask in English and it picks the tool. The raw JSON-RPC below is what goes over the wire, so you can drive the same server from any client. Every call carries your key in the Authorization header; nothing takes a user id, because the server derives the account from the key.
1. check_credits
Ask Claude: "How many Brainpercent credits do I have?"
curl -sX POST https://www.brainpercent.app/api/mcp \
-H "Authorization: Bearer bp_your_key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": { "name": "check_credits", "arguments": {} }
}'2. list_projects
Ask Claude: "Which Brainpercent projects do I have?" Each project carries its own brand voice, language and template, so the id you pass to generate_posts decides how the posts sound.
curl -sX POST https://www.brainpercent.app/api/mcp \
-H "Authorization: Bearer bp_your_key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": {
"name": "list_projects",
"arguments": { "search": "studio", "limit": 5 }
}
}'3. demo_post_from_url
The one tool that needs no key. One post, not saved to any account, capped at one per day per IP.
curl -sX POST https://www.brainpercent.app/api/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": {
"name": "demo_post_from_url",
"arguments": {
"url": "https://example.com/blog/launch",
"platform": "linkedin"
}
}
}'4. generate_posts spends credits
Ask Claude: "Turn https://example.com/blog/launch into LinkedIn and Instagram posts for REI Studio". Three platforms costs 1.8 credits. The key needs the write permission.
curl -sX POST https://www.brainpercent.app/api/mcp \
-H "Authorization: Bearer bp_your_key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0", "id": 4, "method": "tools/call",
"params": {
"name": "generate_posts",
"arguments": {
"source_url": "https://example.com/blog/launch",
"platforms": ["linkedin", "instagram", "twitter"],
"angle": "lead with the pricing change",
"project_id": "fae81600-ba99-4ef7-b2cf-d93566f16ef8"
}
}
}'5. get_content
Generation is asynchronous. Poll this until the status is ready or completed.
curl -sX POST https://www.brainpercent.app/api/mcp \
-H "Authorization: Bearer bp_your_key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0", "id": 5, "method": "tools/call",
"params": {
"name": "get_content",
"arguments": { "content_id": "8629552b-51b5-47b0-acbc-3ab2c3f2029a" }
}
}'6. publish
Ask Claude: "Publish it" or "Schedule it for Monday 9am". Publishing is free; you already paid at generation. You need at least one connected account and a key with write.
curl -sX POST https://www.brainpercent.app/api/mcp \
-H "Authorization: Bearer bp_your_key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0", "id": 6, "method": "tools/call",
"params": {
"name": "publish",
"arguments": {
"content_id": "8629552b-51b5-47b0-acbc-3ab2c3f2029a",
"platforms": ["linkedin"]
}
}
}'Limits and auth
- Without a key:
demo_post_from_urlonly, one generation per day per IP address. Every other tool answers with a link to create a key. - With a key: your account's normal limits apply. Read tools need the
readpermission;generate_postsandpublishneedwrite. - Everything is scoped to the key. No tool takes a user id. The account is derived from the key server-side, and a
project_idorcontent_idyou did not create simply reads as not found. - The server is stateless. There is no session to establish and nothing to keep alive.
- Keys are shown once at creation. If you lose one, revoke it and create another at /chat/developers.
Building your own tools on the REST API
If you are calling the Anthropic API directly rather than using MCP, define the endpoints as tools. These schemas mirror what the OpenAPI spec declares, so they will not drift from the live routes.
[
{
"name": "list_projects",
"description": "List the user's projects. Every generation needs a project_id, so call this first.",
"input_schema": {
"type": "object",
"properties": {
"search": { "type": "string", "description": "Filter by business name" }
}
}
},
{
"name": "generate_social_content",
"description": "Turn a URL into platform-tailored posts. Asynchronous: returns a content_id to poll. Costs 0.6 credits per platform.",
"input_schema": {
"type": "object",
"properties": {
"source_url": { "type": "string", "description": "Public URL to summarize" },
"platforms": {
"type": "array",
"items": {
"type": "string",
"enum": ["instagram", "facebook", "linkedin", "twitter", "threads", "tiktok", "bluesky", "pinterest", "google_business", "telegram"]
}
},
"angle": { "type": "string", "description": "Optional direction hint for the prompt" },
"project_id": { "type": "string", "description": "Defaults to the active project" }
},
"required": ["source_url", "platforms"]
}
},
{
"name": "get_social_content",
"description": "Read one social content item. The captions are in 'platforms', keyed by platform name. Poll until status is 'ready' or 'completed'.",
"input_schema": {
"type": "object",
"properties": {
"content_id": { "type": "string" }
},
"required": ["content_id"]
}
},
{
"name": "generate_article",
"description": "Generate an SEO article. Asynchronous, roughly 10-15 minutes. Costs 1.5 credits.",
"input_schema": {
"type": "object",
"properties": {
"topic": { "type": "string", "description": "Main keyword, 3-500 characters" },
"project_id": { "type": "string", "description": "Required. Supplies brand and language context." },
"keywords": { "type": "array", "items": { "type": "string" } },
"tone": { "type": "string", "enum": ["professional", "casual", "academic", "conversational"] },
"word_count": { "type": "integer", "minimum": 300, "maximum": 5000 }
},
"required": ["topic", "project_id"]
}
},
{
"name": "check_article_status",
"description": "Poll article generation. Status 'cms' or 'needs_editing' means finished. There is no 'published' status.",
"input_schema": {
"type": "object",
"properties": {
"article_id": { "type": "string" }
},
"required": ["article_id"]
}
},
{
"name": "check_credits",
"description": "Read the current credit balance and plan.",
"input_schema": { "type": "object", "properties": {} }
}
]Tool execution handler
const BP_BASE = 'https://www.brainpercent.app/api/v1';
const headers = {
'Authorization': `Bearer ${process.env.BRAINPERCENT_API_KEY}`,
'Content-Type': 'application/json',
};
// Note the www. The apex domain 307-redirects, and a redirected POST
// silently drops its body in most HTTP clients.
async function executeTool(name, input) {
switch (name) {
case 'list_projects': {
const qs = input.search ? `?search=${encodeURIComponent(input.search)}` : '';
const r = await fetch(`${BP_BASE}/projects${qs}`, { headers });
return r.json();
}
case 'generate_social_content': {
const r = await fetch(`${BP_BASE}/social/generate`, {
method: 'POST',
headers,
body: JSON.stringify(input),
});
return r.json(); // 202 { data: { content_id, poll_url, credits_remaining } }
}
case 'get_social_content': {
const r = await fetch(`${BP_BASE}/social/content/${input.content_id}`, { headers });
return r.json();
}
case 'generate_article': {
const r = await fetch(`${BP_BASE}/articles/generate`, {
method: 'POST',
headers,
body: JSON.stringify(input),
});
return r.json(); // 202 { data: { article_id, poll_url } }
}
case 'check_article_status': {
const r = await fetch(`${BP_BASE}/articles/${input.article_id}/status`, { headers });
return r.json();
}
case 'check_credits': {
const r = await fetch(`${BP_BASE}/user/credits`, { headers });
return r.json();
}
default:
return { error: `Unknown tool: ${name}` };
}
}Full conversation loop
import Anthropic from '@anthropic-ai/sdk';
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
async function run(userMessage) {
const messages = [{ role: 'user', content: userMessage }];
while (true) {
const response = await anthropic.messages.create({
model: 'claude-sonnet-5',
max_tokens: 2048,
tools: BRAINPERCENT_TOOLS,
messages,
});
messages.push({ role: 'assistant', content: response.content });
if (response.stop_reason !== 'tool_use') {
return response.content.find((b) => b.type === 'text')?.text ?? '';
}
const results = [];
for (const block of response.content) {
if (block.type !== 'tool_use') continue;
const output = await executeTool(block.name, block.input);
results.push({
type: 'tool_result',
tool_use_id: block.id,
content: JSON.stringify(output),
});
}
messages.push({ role: 'user', content: results });
}
}Prompt examples
Costs are in credits. One credit is one dollar of your single account balance.
| Prompt | Tools used | Cost |
|---|---|---|
| "Turn this blog post into LinkedIn and Instagram posts" | list_projects, generate_social_content, get_social_content | 1.2 |
| "Write an article about AI trends" | generate_article, check_article_status | 1.5 |
| "How many credits do I have left?" | check_credits | 0 |
Things that will bite you
- Use
www.brainpercent.app. The apex domain 307-redirects and most HTTP clients drop the POST body on redirect. - Generation is asynchronous. Both generate endpoints return
202with apoll_url. Nothing is ready at the moment the call returns. - A finished article has status
cms, notpublished. - Social captions live in the
platformsobject, keyed by platform. There is nocontentfield. - Give Claude
check_creditsso it can check the balance before spending. - Over MCP,
generate_postsis the only tool that costs anything, at 0.6 credits per platform, charged the moment the job is queued and refunded automatically if the job fails to start. Asking for ten platforms costs 6 credits. demo_post_from_urlis a preview. It does not save anything to your account, so you cannot publish its output. Usegenerate_postsfor anything you intend to post.