Are you the author? Sign in to claim
BlackTwist MCP Server
The BlackTwist MCP (Model Context Protocol) server allows AI assistants like Claude, Cursor, and other MCP-compatible clients to interact with your BlackTwist account — creating posts, checking analytics, managing drafts, and more.
There are two ways to connect to the BlackTwist MCP server: OAuth (recommended for claude.ai) or API Key (for desktop clients and CLI tools).
If you're using claude.ai as a custom connector, OAuth is the easiest option — no API key needed.
https://blacktwist.app/api/mcpOAuth tokens refresh automatically, so you won't need to re-authenticate unless you revoke access.
For Claude Desktop, Claude Code, Cursor, and other MCP clients that don't support OAuth, use an API key.
Add the following to your MCP client configuration:
Claude Desktop (claude_desktop_config.json):
{
"blacktwist": {
"command": "npx",
"args": [
"-y",
"mcp-remote@latest",
"https://blacktwist.app/api/mcp",
"--header",
"Authorization:${BLACKTWIST_TOKEN}"
],
"env": {
"BLACKTWIST_TOKEN": "Bearer YOUR_API_KEY"
}
}
}
You need node.js v22, if you are using nvm be sure to use the correct version:
{
"blacktwist": {
"command": "/Users/<your_user>/.nvm/versions/node/v22.22.0/bin/npx",
"args": [
"-y",
"mcp-remote@latest",
"https://blacktwist.app/api/mcp",
"--header",
"Authorization:${BLACKTWIST_TOKEN}"
],
"env": {
"BLACKTWIST_TOKEN": "Bearer YOUR_API_KEY",
"PATH": "/Users/<your_user>/.nvm/versions/node/v22.22.0/bin:/usr/local/bin:/usr/bin:/bin",
"NODE_PATH": "/Users/<your_user>/.nvm/versions/node/v22.22.0/lib/node_modules"
}
}
}
Claude Code
Run in the terminal:
claude mcp add --transport http blacktwist https://blacktwist.app/api/mcp --header "Authorization: Bearer YOUR_API_KEY"
Or edit the file .mcp.json in project root:
{
"mcpServers": {
"blacktwist": {
"type": "url",
"url": "https://blacktwist.app/api/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}
Cursor (Settings > MCP):
blacktwisturlhttps://blacktwist.app/api/mcpAuthorization: Bearer YOUR_API_KEYOnce connected, you can ask your AI assistant things like:
| Property | Value |
|---|---|
| URL | https://blacktwist.app/api/mcp |
| Auth | OAuth 2.1 (PKCE) or Bearer token (API key) |
| Transport | Streamable HTTP (stateless) |
| Protocol | MCP via JSON-RPC over HTTP POST |
teamId)Most tools accept an optional teamId parameter to scope operations to a specific team.
Behavior:
teamId is a team ID, the tool operates in that team's context (membership is verified).teamId is "personal", the tool operates in personal mode (user's own data only, no team).teamId is omitted, the tool falls back to the user's currently active team (from user settings). If no team is active, this is equivalent to "personal".Tools that support teamId: list_providers, list_posts, list_drafts, create_post, get_thread, delete_thread, reschedule_thread, list_time_slots, get_subscription, get_follow_up_templates, and all analytics tools.
Tools without teamId: list_teams (lists all teams), get_user_settings (personal settings), list_viral_templates / list_viral_template_categories (account-wide content library), edit_post / edit_thread / get_thread_follow_up / set_thread_follow_up (thread-based access handles team auth internally via userCanAccessThread).
Subscription access: Analytics tools that require a paid plan will check the user's own subscription first. If the user doesn't have one, the system also checks whether any team owner the user belongs to has an active plan. This means team members can access paid features through their team owner's subscription.
list_providersList all connected social media accounts (Threads and Bluesky).
| Parameter | Type | Required | Description |
|---|---|---|---|
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. When set to a team, shows only providers linked to that team. |
Returns: Array of providers with id, provider, providerUserId, providerUsername, displayName, profilePicture.
Note: Many other tools require a
providerId(theidfield) orproviderUserIdfrom this response.
list_teamsList all teams the user belongs to, including their role and which team is currently active. Always includes a "personal" entry representing the user's personal (non-team) account.
Parameters: None
Returns: Array of teams with id, name, role (OWNER, ADMIN, MEMBER, GUEST), isActive, createdAt.
The personal entry has id: "personal" and is marked isActive: true when no team is currently selected.
Note: The team
idcan be passed asteamIdto other tools (list_posts,list_drafts,create_post, etc.). Pass"personal"to explicitly use the personal account. WhenteamIdis omitted, those tools automatically use the user's currently active team.
create_postCreate a new post or thread. A thread is multiple posts linked together.
| Parameter | Type | Required | Description |
|---|---|---|---|
providerId | string | Yes | Provider ID from list_providers |
posts | array | Yes | Array of post objects (see below) |
scheduleAt | string | No | ISO 8601 datetime. If omitted, saves as draft. Times without a timezone offset (e.g. 2025-03-15T09:00:00) are interpreted in the user's configured timezone. |
autoRepost | object | No | { enabled: boolean, delays: string[] } where delays are hours, e.g. ["168", "336"] for 7 and 14 days. If omitted, the user's default auto-repost setting is applied. |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
Default behaviors applied automatically:
autoRepost is not provided and the user has auto-repost enabled in settings, the default delays are applied to the first post.autoPlugApplied: true when this happens.notificationsTimezone setting.Each post object:
| Field | Type | Required | Description |
|---|---|---|---|
text | string | Yes | Post content |
topic | string | No | Topic tag |
media | object[] | No | Media attachments via public URL (see Media Attachments) |
spoilerRanges | object[] | No | Text spoiler ranges (see Spoilers) |
isSpoilerMedia | boolean | No | If true, all media in this post is marked as a spoiler (see Spoilers) |
Example — single post:
{
"providerId": "clx...",
"posts": [{ "text": "Hello world!" }],
"scheduleAt": "2025-03-15T09:00:00"
}
Example — thread:
{
"providerId": "clx...",
"posts": [
{ "text": "Thread time! Here's what I learned this week 🧵" },
{ "text": "1/ First lesson: consistency beats perfection" },
{ "text": "2/ Second lesson: engage with your community daily" }
],
"scheduleAt": "2025-03-15T09:00:00"
}
Tools that accept media (create_post, edit_post, edit_thread, set_thread_follow_up) let you attach images and videos via public URLs. The server downloads, validates against Threads specs, and uploads them automatically.
Each media object:
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Public URL of the image or video |
altText | string | No | Alt text for accessibility |
Threads image specs:
Threads video specs:
Example — post with an image:
{
"providerId": "clx...",
"posts": [
{
"text": "Check out this view!",
"media": [
{
"url": "https://example.com/photo.jpg",
"altText": "Sunset over the mountains"
}
]
}
],
"scheduleAt": "2025-03-15T09:00:00"
}
Spoilers allow you to hide portions of text or media behind a blur effect on Threads. Viewers tap to reveal the hidden content.
Text spoilers are defined as an array of character ranges:
| Field | Type | Required | Description |
|---|---|---|---|
offset | number | Yes | Character offset (0-indexed) |
length | number | Yes | Number of characters in the range |
text fieldMedia spoilers are a single boolean flag per post. When isSpoilerMedia is true, all media (images and videos) in the post is blurred until the viewer taps to reveal.
Text and media spoilers are independent — a post can have both, either, or neither.
Example — post with text spoiler:
{
"providerId": "clx...",
"posts": [
{
"text": "The winner is John!",
"spoilerRanges": [{ "offset": 14, "length": 5 }]
}
]
}
Example — post with media spoiler:
{
"providerId": "clx...",
"posts": [
{
"text": "Spoiler alert! Check the image",
"media": [{ "url": "https://example.com/reveal.jpg" }],
"isSpoilerMedia": true
}
]
}
In responses (list_posts, list_drafts, get_thread), each post includes:
spoilerRanges: array of { offset, length } (empty if no text spoilers)isSpoilerMedia: boolean (true if media is spoilered)list_postsList scheduled and published posts within a date range.
| Parameter | Type | Required | Description |
|---|---|---|---|
from | string | Yes | Start date (ISO 8601) |
to | string | Yes | End date (ISO 8601) |
providerId | string | No | Provider ID (from list_providers). If provided, only returns posts for this provider. |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
list_draftsList all draft posts (not yet scheduled).
| Parameter | Type | Required | Description |
|---|---|---|---|
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
get_threadGet a specific thread with all its posts, media, and analytics.
| Parameter | Type | Required | Description |
|---|---|---|---|
threadId | string | Yes | The thread ID |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
edit_postEdit the text content, topic, or media of a single post. Only posts with status READY (drafts or scheduled) can be edited — published, processing, or failed posts are rejected. Use get_thread first to retrieve post IDs.
| Parameter | Type | Required | Description |
|---|---|---|---|
postId | string | Yes | The post ID (from get_thread) |
content | string | No | New text content |
topic | string | No | New topic tag. Pass null to remove the topic. |
media | object[] | No | Replace all media via public URL (see Media Attachments). Omit to keep existing media unchanged. |
spoilerRanges | object[] | No | Replace text spoiler ranges (see Spoilers). Omit to keep unchanged. Pass [] to remove all. |
isSpoilerMedia | boolean | No | Set media spoiler flag. true = blurred, false = remove spoiler. Omit to keep unchanged. |
At least one of content, topic, media, spoilerRanges, or isSpoilerMedia must be provided.
Returns: postId, threadId, updated (object indicating which fields were changed).
Example — update text:
{
"postId": "clx...",
"content": "Updated post content"
}
Example — update text and clear topic:
{
"postId": "clx...",
"content": "New content",
"topic": null
}
edit_threadEdit a thread by adding, removing, or reordering its posts. Provide the full desired list of posts — existing posts (with id) are updated, new posts (without id) are created, and existing posts not in the list are removed. Only threads where all posts have status READY can be edited.
| Parameter | Type | Required | Description |
|---|---|---|---|
threadId | string | Yes | The thread ID |
posts | array | Yes | Ordered array of posts (min 1). Order determines postOrder (0-indexed). See below. |
Each post object:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | No | Post ID for existing posts. Omit to create a new post in this position. |
text | string | Yes | Post content |
topic | string | No | Topic tag |
media | object[] | No | Media attachments via public URL (see Media Attachments) |
spoilerRanges | object[] | No | Text spoiler ranges (see Spoilers) |
isSpoilerMedia | boolean | No | If true, all media in this post is marked as a spoiler |
New posts inherit scheduledAt, provider, providerUserId, and teamId from the existing thread.
Returns: threadId, postsUpdated, postsCreated, postsDeleted, totalPosts.
Example — reorder and add a post:
{
"threadId": "abc123",
"posts": [
{ "id": "existing-post-2", "text": "Now this is first" },
{ "id": "existing-post-1", "text": "Now this is second" },
{ "text": "Brand new third post" }
]
}
Example — remove a post (omit it from the list):
{
"threadId": "abc123",
"posts": [{ "id": "existing-post-1", "text": "Keep only this one" }]
}
delete_threadPermanently delete a thread and all its posts.
| Parameter | Type | Required | Description |
|---|---|---|---|
threadId | string | Yes | The thread ID |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
reschedule_threadChange the scheduled date/time for a thread.
| Parameter | Type | Required | Description |
|---|---|---|---|
threadId | string | Yes | The thread ID |
scheduledAt | string | Yes | New datetime (ISO 8601). Times without a timezone offset are interpreted in the user's configured timezone. |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
All analytics tools require a providerUserId (from list_providers) and accept an optional teamId to scope access.
Paid plan required:
get_metric_timeseries,get_post_analytics,get_follower_growth, andget_best_time_to_postrequire a paid plan (user or team owner). Free-plan users will receive: "A paid plan is required to access the analytics. Subscribe at https://blacktwist.app#pricing". The remaining tools (get_live_metrics,get_consistency,get_daily_recap,get_recommendations) are available on all plans.Date ranges: The
fromandtodates are both inclusive. For example,from: "2026-03-01"andto: "2026-03-08"includes all data from March 1 through the end of March 8.
get_live_metricsGet engagement metrics with percentage change vs. the previous period.
| Parameter | Type | Required | Description |
|---|---|---|---|
providerUserId | string | Yes | Provider user ID |
from | string | No | Start date (defaults to 7 days ago) |
to | string | No | End date (defaults to now) |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
Returns: views, likes, replies, reposts, quotes — each with value and percentageChange.
get_metric_timeseriesGet daily data points for a specific metric over a date range.
| Parameter | Type | Required | Description |
|---|---|---|---|
providerUserId | string | Yes | Provider user ID |
metric | enum | Yes | One of: VIEWS, LIKES, REPLIES, REPOSTS, QUOTES, ENGAGEMENT_RATE, FOLLOWERS_COUNT |
from | string | Yes | Start date (ISO 8601) |
to | string | Yes | End date (ISO 8601) |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
get_post_analyticsGet per-post engagement metrics for posts within a date range. Each post also carries its thread continuation parts (self-replies), so multi-post threads are returned in full.
| Parameter | Type | Required | Description |
|---|---|---|---|
providerUserId | string | Yes | Provider user ID |
from | string | Yes | Start date (ISO 8601) |
to | string | Yes | End date (ISO 8601) |
includeThreadParts | boolean | No | Include each post's thread continuation parts (self-replies) in a thread array. Defaults to true; pass false to omit. |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
Returns: Up to 100 posts with views, likes, replies, reposts, quotes, engagementRate. Each post also includes a thread array of its continuation parts, reconstructed from the user's self-replies — so a multi-post thread comes back with all of its posts. Each part has replyId, text (truncated to 200 characters), permalink, timestamp, partOrder (starting at 2; the root post is part 1), and its own analytics (views, likes, replies, reposts, quotes, engagementRate). Single posts return an empty thread. Pass includeThreadParts: false to skip reconstruction entirely and return empty thread arrays.
get_follower_growthGet daily follower count over time.
| Parameter | Type | Required | Description |
|---|---|---|---|
providerUserId | string | Yes | Provider user ID |
from | string | Yes | Start date (ISO 8601) |
to | string | Yes | End date (ISO 8601) |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
Returns: Daily followers data points and totalGrowth.
get_consistencyGet a 365-day posting consistency heatmap.
| Parameter | Type | Required | Description |
|---|---|---|---|
providerUserId | string | Yes | Provider user ID |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
Returns: days (array of { date, count }), totalPosts, daysWithPosts, currentStreak, recordStreak.
get_daily_recapGet yesterday's summary.
| Parameter | Type | Required | Description |
|---|---|---|---|
providerUserId | string | Yes | Provider user ID |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
Returns: date, newFollowers, postsCount.
get_recommendationsGet posting recommendations based on your analytics patterns.
| Parameter | Type | Required | Description |
|---|---|---|---|
providerUserId | string | Yes | Provider user ID |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
Returns: bestPostingHoursUtc, topPerformingPosts, currentStreak, recordStreak.
get_best_time_to_postGet the best times to post based on historical engagement over the last 10 weeks. Mirrors the "Best time to post" analytics chart — engagement bucketed by hour of day, both averaged across the whole week and broken down per day of the week. Hours are reported in the user's own timezone.
Active subscription required: This tool requires an active subscription — the user must have their own paid plan, or be part of a team whose owner has an active subscription. Otherwise it returns: "The best time to post requires an active subscription. You need your own paid plan, or to be part of a team whose owner has an active subscription. Subscribe at https://blacktwist.app#pricing"
Timezone: Resolved automatically server-side from the user's
notificationsTimezonesetting (defaulting to UTC). MCP callers normally cannot know the user's timezone, so they should leavetimezoneOffsetunset and let it be derived.
| Parameter | Type | Required | Description |
|---|---|---|---|
providerUserId | string | Yes | Provider user ID |
timezoneOffset | number | No | Override for the timezone used to bucket hours. Leave unset to use the user's configured account timezone (recommended). If set, use minutes matching JavaScript's Date.getTimezoneOffset() (behind UTC: UTC+2 is -120). |
view | enum | No | "average", "daily", or "both" (default). Selects which breakdown to return. |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
Returns: provider, timezone (IANA name, or "custom" when an override offset is used), timezoneOffsetMinutes, timezoneInfo (a human-readable note naming the timezone used and linking to https://blacktwist.app/write?settings=notifications so the user can correct it if it's wrong), and (depending on view) averageView (bestHours + 24 hourly averageEngagement values across the whole week) and dailyView (7 days, each with dayName, bestHour, and 24 hourly averageEngagement values).
The follow-up system automatically replies to your post after it reaches engagement thresholds (likes, replies, reposts) or a time delay.
get_follow_up_templatesList saved follow-up templates for a provider.
| Parameter | Type | Required | Description |
|---|---|---|---|
userProviderId | string | Yes | Provider id from list_providers |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. Scopes which team members' templates are included. |
get_thread_follow_upGet the follow-up configuration for a specific thread.
| Parameter | Type | Required | Description |
|---|---|---|---|
threadId | string | Yes | The thread ID |
set_thread_follow_upSet or update the follow-up for a thread.
| Parameter | Type | Required | Description |
|---|---|---|---|
threadId | string | Yes | The thread ID |
isEnabled | boolean | Yes | Enable/disable the follow-up |
text | string | No | Follow-up reply text |
images | string[] | No | Image URLs |
delayTimeMinutes | number | No | Time delay trigger (minutes) |
delayTimeMinutesEnabled | boolean | No | Enable time delay trigger |
numberOfLikes | number | No | Likes threshold |
numberOfLikesEnabled | boolean | No | Enable likes trigger |
numberOfReplies | number | No | Replies threshold |
numberOfRepliesEnabled | boolean | No | Enable replies trigger |
numberOfReposts | number | No | Reposts threshold |
numberOfRepostsEnabled | boolean | No | Enable reposts trigger |
media | object[] | No | Media attachments via public URL (see Media Attachments) |
list_time_slotsList configured posting time slots for a provider. Time slots define preferred scheduling times.
| Parameter | Type | Required | Description |
|---|---|---|---|
providerId | string | Yes | Provider id from list_providers |
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
Returns: Array of { timeSlotHour, timeSlotMinute, weekDays } where weekDays is [0-6] (0 = Sunday).
Browse the library of viral post templates extracted from high-performing posts. Each template includes the structure, usage instructions, and the original example post with its engagement metrics.
Paid plan required: Both tools below require an active paid plan (user-owned plan, Lifetime Deal, or membership in a workspace whose owner has a paid plan). Free-plan users will receive: "A paid plan is required to access viral post templates".
list_viral_templatesList viral post templates with filtering, free-text search, sorting, and pagination.
| Parameter | Type | Required | Description |
|---|---|---|---|
search | string | No | Free-text search. Matches against the example post text (case-insensitive). |
category | string | No | Filter to a single category. Use a value returned by list_viral_template_categories or the categories field of a previous response. |
sort | enum | No | Sort by example-post engagement: views (default), likes, replies, or engagementRate. Descending. |
page | number | No | Page number, 1-indexed. Defaults to 1. |
pageSize | number | No | Items per page (1–50). Defaults to 20. Values above 50 are clamped to 50. |
Returns: { templates, categories, totalCount, page, pageSize }.
Each template:
| Field | Type | Description |
|---|---|---|
id | string | Template ID |
category | string | Template category |
template | string | The template structure |
instructions | string | How to use the template |
exampleText | string | The original viral post text |
views | number | Views on the example post |
likes | number | Likes on the example post |
replies | number | Replies on the example post |
engagementRate | number | Engagement rate of the example post (likes+replies/views) |
list_viral_template_categoriesList all available template categories with the number of templates in each. Useful as a discovery step before calling list_viral_templates with a category filter.
Parameters: None
Returns: { categories: [{ category, templateCount }] }, ordered alphabetically by category.
get_subscriptionGet your current plan, remaining post limits, and account quotas.
| Parameter | Type | Required | Description |
|---|---|---|---|
teamId | string | No | Team ID. If not provided, uses the active team. Pass "personal" for the personal account. |
Returns: planType, planName, isFreePlan, remainingPosts, limits (maxTeams, maxMembers, maxAccounts).
get_user_settingsGet your user settings including timezone, date format, and auto-repost config.
Parameters: None
Returns: notificationsTimezone, dateFormat, autoRepostEnabled, autoRepostDelays, and more.
list_providers → get your provider IDlist_time_slots → find available slotscreate_post → schedule with the next slot timelist_providers → get your provider user IDget_live_metrics → see this week vs. last weekget_recommendations → get improvement suggestionsget_thread → retrieve the thread and its post IDsedit_post → update the text, topic, or media of a specific postget_thread → retrieve current posts with their IDsedit_thread → pass all existing posts (with IDs) plus the new post (without ID)create_post → create and schedule the post (returns threadId)set_thread_follow_up → attach a promotional replyThe MCP server includes built-in prompts — reusable templates that guide your AI assistant through multi-step workflows. In Claude Desktop, access them by typing / in the chat. In Claude Code, run claude prompts to list them.
weekly-reportGenerate a weekly performance report with engagement metrics, top posts, follower growth, and recommendations.
Arguments:
| Parameter | Required | Description |
|---|---|---|
providerUserId | Yes | Your provider user ID |
Example: "Run the weekly-report prompt for my Threads account"
content-ideasGenerate post ideas based on your best-performing content and posting patterns.
Arguments:
| Parameter | Required | Description |
|---|---|---|
providerUserId | Yes | Your provider user ID |
topic | No | Topic to focus on (e.g. "productivity", "startups") |
Example: "Give me content ideas about marketing"
optimize-scheduleAnalyze your posting patterns and suggest an optimal posting schedule for the week.
Arguments:
| Parameter | Required | Description |
|---|---|---|
providerUserId | Yes | Your provider user ID |
providerId | Yes | Your provider ID |
Example: "Help me optimize my posting schedule"
draft-reviewReview your current drafts and get suggestions to improve them before publishing.
Arguments: None
Example: "Review my drafts and tell me how to improve them"
monthly-recapGenerate a comprehensive monthly recap with key metrics, top posts, and growth trends.
Arguments:
| Parameter | Required | Description |
|---|---|---|
providerUserId | Yes | Your provider user ID |
Example: "Generate my monthly recap"
GET/POST/DELETE /api/user/mcp-keysKeys are hashed with SHA-256 before storage. The raw key is only shown once at creation time.
The MCP server supports two authentication methods. Both use the Authorization: Bearer <token> header.
The server implements the MCP Authorization specification with OAuth 2.1 and PKCE (S256). OAuth-capable clients like claude.ai handle the flow automatically.
OAuth endpoints:
| Endpoint | Description |
|---|---|
GET /.well-known/oauth-protected-resource | Resource metadata (RFC 9728) |
GET /.well-known/oauth-authorization-server | Authorization server metadata (RFC 8414) |
POST /api/mcp/oauth/register | Dynamic client registration (RFC 7591) |
GET /api/mcp/oauth/authorize | Authorization endpoint |
POST /api/mcp/oauth/token | Token exchange and refresh |
POST /api/mcp/oauth/revoke | Token revocation (RFC 7009) |
How it works:
API keys are static tokens prefixed with bt_mcp_. They don't expire by default and are suitable for clients that don't support OAuth (Claude Desktop, Cursor, Claude Code CLI).
See API Key Management for how to create and manage keys.
POST /api/mcp (JSON-RPC)WebStandardStreamableHTTPServerTransport from @modelcontextprotocol/sdkAuthorization: Bearer <key> headerinitialize and tools/list can be called without authentication, so MCP registries (e.g. Glama) can inspect available toolssrc/libs/mcp/ (server, auth, oauth, tools), src/app/api/mcp/ (route handler, OAuth endpoints)Run Claude Code as an MCP server so any agent can delegate coding tasks to it
Browser automation using accessibility snapshots instead of screenshots
Google's universal MCP server supporting PostgreSQL, MySQL, MongoDB, Redis, and 10+ databases
Official GitHub integration for repos, issues, PRs, and CI/CD workflows