Announcing CIMD support for MCP Client registration
Learn more

YouTube MCP vs YouTube API for AI Agents (2026)

Varun Krishnan
Senior Content Marketer

TL;DR

  • Google ships no official YouTube MCP server. Its managed MCP catalog covers Gmail, Drive, Calendar, and Cloud products, not YouTube. Community servers are mostly local and single-user.
  • YouTube does not support service accounts, and API keys read only public data. Every write needs a per-user OAuth grant, on either path.
  • Quota is per Google Cloud project: 10,000 units a day shared by all your tenants, most writes at 50 units, plus 100-call daily buckets for search.list and videos.insert.
  • Scalekit's YouTube connector ships 45 prebuilt tools. Uploads, thumbnails, and caption files sit outside them; call those endpoints directly or through Scalekit's API proxy.
  • One connector backs both paths: execute_tool for tool calling, Virtual MCP servers for a scoped MCP endpoint, one token vault underneath.

Why YouTube breaks the usual MCP vs API framing

Your agent needs to act on YouTube: pull channel analytics, triage comments, reply to viewers, manage playlists, maybe schedule a live broadcast. For most tools, the question is whether to build against the vendor's hosted MCP server or its REST API. YouTube removes one option. There is no first-party MCP server to connect to. So the real decision is narrower and more practical: integrate the YouTube APIs directly, or expose YouTube to your agent as MCP tools through infrastructure you control. Both paths land on the same Google OAuth model and the same project-wide quota. Here is how to pick.

What YouTube MCP and YouTube API actually are

The two objects in this comparison are not symmetric. One is a family of Google APIs with a decade of production use. The other is a protocol surface that someone other than Google has to build and operate.

YouTube MCP

Google's list of managed remote MCP servers, last updated in September 2026, includes BigQuery, Cloud Run, Maps Grounding Lite, and Workspace servers for Gmail, Drive, Calendar, Chat, and People in developer preview. YouTube is not on it.

What exists instead are community-built servers. Most run locally over stdio and authenticate with either an API key, which limits them to public data, or one user's OAuth token cached on the machine. That shape works for a creator automating their own channel in Claude Desktop. It does not survive a second user.

The production-grade MCP path is to generate an MCP endpoint from a managed connector. Scalekit's Virtual MCP servers do this on top of the YouTube connector, exposing only the YouTube tools you select, with per-user credentials.

YouTube API

"The YouTube API" is really three APIs. The YouTube Data API v3 handles channels, videos, playlists, comments, captions, subscriptions, and search; the Live Streaming API methods are technically part of it. The YouTube Analytics API answers targeted metric queries. The YouTube Reporting API schedules bulk daily reports as downloadable CSV files.

Auth options are narrower than most Google APIs. An API key covers only unauthenticated reads of public data. Every insert, update, and delete requires OAuth 2.0 user authorization. Service accounts are not supported; Google's docs note that trying one returns a NoLinkedYouTubeAccount error. Content partners act across managed channels with the onBehalfOfContentOwner parameter, which still rides on an OAuth grant.

The official references are the YouTube Data API, Analytics API, and Reporting API docs on Google for Developers.

Comparing them where it matters for agents

The four dimensions below are the same across every article in this series. For YouTube, the "MCP" column means the Scalekit YouTube connector exposed through a Virtual MCP server, because that is the MCP surface a multi-tenant agent can actually use today. The same 45 tools are available through execute_tool.

What your agent can actually do

The connector covers the read, reply, and moderate loop that most YouTube agents run. The gaps sit in media upload and a few channel-admin surfaces.

Capability
MCP path (Scalekit YouTube tools)
Direct YouTube APIs
Channel lookup and statistics
Yes: youtube_channels_list
Yes: channels.list
Video metadata read, update, rate, delete
Yes: youtube_videos_list, youtube_videos_update and related tools
Yes
Video upload
No
Yes: videos.insert, resumable upload
Custom thumbnails
No
Yes: thumbnails.set
Comment threads, replies, edits, moderation
Yes: seven comment tools including youtube_comments_set_moderation_status
Yes
Captions
List only: youtube_captions_list
Yes: list, insert, update, download, delete
Playlists and playlist items
Yes: create, update, delete playlists; add, remove, list items
Yes, plus playlistItems.update
Search across YouTube
Yes: youtube_search
Yes: search.list
Live broadcasts and streams
Partial: create, list, bind, transition
Yes, plus update, delete, cuepoints, live chat
Analytics queries and groups
Yes: youtube_analytics_query plus group management
Yes: YouTube Analytics API
Bulk reporting jobs
Partial: create, list, delete jobs; list reports
Yes, including report file download
Channel branding, sections, memberships
No
Yes

Where the tool surface stops

Upload is the gap that matters most. If your agent's job is publishing, not operating, the prebuilt tools will not carry it. Thumbnail changes, caption file management, and live chat moderation fall in the same bucket.

Scalekit's custom tools close part of this without leaving the connected-account model. actions.request forwards a call to the provider endpoint and injects the user's credentials; you define the tool contract. JSON endpoints such as channelSections.list fit naturally. Test media uploads like videos.insert and thumbnails.set against the proxy before designing around them.

The reverse gap is real too. On the direct API path you write and maintain every schema yourself. Scalekit's tool schemas already encode YouTube's rules, such as requiring exactly one filter on channel and playlist lookups.

The auth path each one puts you on

Both paths use Google OAuth 2.0 with the Authorization Code flow and the same scopes: youtube.readonly for reads, youtube or youtube.force-ssl for writes, yt-analytics.readonly for Analytics and Reporting. YouTube has no comment-only write scope. youtube.force-ssl, which comment writes need, also permits deleting videos. Scopes cannot fence a comment agent; tool-level scoping has to.

Community MCP servers usually complete this flow once on a laptop and keep the token in a local file. That is one identity, one channel, no revocation story.

With Scalekit, you register your own Google OAuth client, add the Scalekit redirect URI, and pick scopes on the connection. Each user authorizes once through a Scalekit authorization link. The consent screen, verification status, and quota belong to your Google Cloud project on both paths.

Why YouTube has no clean headless credential

Many agent backends lean on a service account for scheduled work. YouTube does not allow it. A nightly analytics digest or an overnight comment sweep has to run on a stored user refresh token, consented in advance.

Three Google rules shape that token's life. In Testing status with an External user type, refresh tokens expire after 7 days and you are capped at 100 test users. YouTube management scopes are sensitive; Google cites deleting a YouTube video as its own example, so production needs app verification. And videos uploaded via videos.insert from unverified projects created after July 28, 2020 stay private until the project passes a compliance audit.

None of these are MCP or API decisions. They are Google project decisions you make once.

What you own in production

On the MCP path through Scalekit, you do not host a server, write tool schemas, or store tokens. You still own scope selection, Google app verification, quota planning, and the decision about which tools each agent role can see.

On the direct API path, you own all of that plus token storage and encryption, refresh handling, revocation, part and fields selection, pagination, and error mapping for three APIs with different hosts and response shapes. You also absorb YouTube's API changes directly. In 2026 alone, the Data API moved videos.insert and search.list into their own quota buckets, added videos.batchGetStats, and changed how public view counts are recorded.

A community MCP server leaves you owning its code, update cadence, and security posture. That surface is larger than it looks.

Quota is per project, not per user

This is the constraint most YouTube agents hit first. Quota belongs to the Cloud project behind your OAuth client: 10,000 units a day for most methods, reset at midnight Pacific Time. Reads usually cost 1 unit. Writes such as comment replies and moderation usually cost 50, as does captions.list. Since June 2026, search.list and videos.insert have their own buckets of 100 calls a day each.

Do the math for a multi-tenant product. At 50 units per write, 10,000 units is about 200 writes a day across every creator you serve, plus 100 searches a day for your whole customer base. Raising either means a compliance audit and a quota extension request. Neither path changes this; tool scoping helps by keeping youtube_search away from agents that do not need it.

When to use MCP, when to use the API

Pick by what the agent does and who it runs for, not by which interface feels more modern.

Use the MCP path (Scalekit Virtual MCP over the YouTube connector) when:

  • You are building a creator-facing assistant in Claude, Cursor, or a chat product where users ask "which of this week's comments need a reply?" and the agent chooses tools at runtime.
  • The agent combines YouTube with other tools, for example posting a daily comment digest to Slack or logging sponsor mentions to a CRM, and you want one MCP endpoint per agent role.
  • You serve many creators or brand channels and need per-user credential isolation without running a server per user.
  • The work stays inside comments, analytics, playlists, metadata, and live broadcast scheduling.

When the direct API is the better fit

Some YouTube work sits outside any prebuilt tool surface, or needs no model at all.

Use the direct YouTube APIs when:

  • The agent publishes content: resumable video uploads, custom thumbnails, or caption file uploads and downloads.
  • You need surfaces outside the prebuilt tools, such as live chat moderation, channel sections, memberships, or bulk Reporting API file downloads.
  • You run a deterministic pipeline, like a nightly Reporting API ingest into your warehouse, where no model chooses the calls.
  • You are a content partner using onBehalfOfContentOwner across hundreds of managed channels and need exact control over every request's quota cost.

The credential problem that exists on both paths

Whichever interface you choose, the credential model underneath is identical. Google issues one OAuth grant per YouTube account, and your agent holds it.

N creators, N Google grants

Take a creator-tools SaaS serving 300 channels. That is 300 refresh tokens tied to your Google OAuth client, each carrying the scopes that creator approved. Access tokens expire hourly and need refreshing before background runs. A creator who revokes access from their Google account invalidates their token immediately, and your agent should notice before its next scheduled job, not during it.

Brand Accounts add a wrinkle: one Google user may manage several channels, so "which channel is this token for" needs an explicit answer in your data model.

Not every YouTube connection needs per-user isolation. A research agent that reads only public data can share one connected account under a fixed identifier. Anything touching a creator's own channel cannot.

What neither path gives you

MCP gives you a token per user. The direct API gives you a credential per user. Neither gives you an encrypted vault, proactive refresh, revocation detection, or an audit trail that ties each YouTube call back to the person who triggered it. The token type is the same on both paths; the infrastructure required is the same too.

Scalekit's YouTube connector handles the OAuth flow, token storage, and refresh for both paths, so the MCP vs API decision does not change your credential infrastructure. For the refresh mechanics specifically, see how to handle token refresh for AI agents.

Building a YouTube agent with Scalekit

The example below is a channel-operations agent in Python using the Anthropic SDK. It reads channel analytics, lists comment threads, and replies to or moderates comments for one creator at a time. The same code runs for every creator; only the identifier changes.

Set up the connection once

In Google Cloud, create an OAuth 2.0 client with the Web application type and enable the YouTube Data API v3, plus the YouTube Analytics and Reporting APIs if your agent uses them. In the Scalekit dashboard, go to AgentKit, then Connections, create a YouTube connection, and copy its redirect URI into the Google client's authorized redirect URIs.

Paste the Google client ID and secret into the connection and select only the scopes the agent needs. For this example: youtube.force-ssl for comments and yt-analytics.readonly for metrics. Full steps are in the YouTube connector docs.

Two setup mistakes that look like auth bugs

The connection name you set in the dashboard, youtube in this example, must match the connection_name string in your code exactly. A mismatch is the most common integration error.

The second one is YouTube-specific. A connected account can show ACTIVE while every tool call returns permission_denied, because the YouTube Data API v3 is not enabled in your Google Cloud project. The token is valid; the API is off. Enable it and existing tokens start working with no re-authorization.

Install and initialize

Install the Scalekit Python SDK and the Anthropic SDK, then set SCALEKIT_ENVIRONMENT_URL, SCALEKIT_CLIENT_ID, SCALEKIT_CLIENT_SECRET, and ANTHROPIC_API_KEY in your .env file.

pip install scalekit-sdk-python anthropic python-dotenv
import json import os import anthropic from dotenv import load_dotenv from google.protobuf.json_format import MessageToDict from scalekit import ScalekitClient load_dotenv() scalekit_client = ScalekitClient( env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"), client_id=os.getenv("SCALEKIT_CLIENT_ID"), client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), ) actions = scalekit_client.actions claude = anthropic.Anthropic() # reads ANTHROPIC_API_KEY # Must match the connection name configured in the Scalekit dashboard CONNECTION_NAME = "youtube"

Authorize a creator

Each creator connects their YouTube account once. get_or_create_connected_account returns the connected account for this user, and get_authorization_link produces the Google consent URL if the account is not yet active. In production, send the link through your app's UI instead of printing it.

def ensure_youtube_connected(identifier: str) -> None: response = actions.get_or_create_connected_account( connection_name=CONNECTION_NAME, identifier=identifier ) if response.connected_account.status == "ACTIVE": return link = actions.get_authorization_link( connection_name=CONNECTION_NAME, identifier=identifier ) print("Authorize YouTube:", link.link) input("Press Enter after authorizing...") # Fetch the account again to pick up the new status response = actions.get_or_create_connected_account( connection_name=CONNECTION_NAME, identifier=identifier ) if response.connected_account.status != "ACTIVE": raise RuntimeError( f"YouTube is {response.connected_account.status}, not ACTIVE." )

Retrieve the authorized tool surface

The agent does not load a flat connector catalog. list_scoped_tools returns the tools this creator's connected account is authorized to call. The code then narrows that set to five tools for this agent role.

That narrowing does two jobs on YouTube. It keeps destructive tools such as youtube_videos_delete out of reach, and it keeps youtube_search away from an agent that does not need to spend your project's 100 daily searches. Five tool definitions instead of 45 also means far fewer tokens in every request.

ALLOWED_TOOLS = { "youtube_channels_list", "youtube_analytics_query", "youtube_comment_threads_list", "youtube_comments_insert", "youtube_comments_set_moderation_status", } def load_youtube_tools(identifier: str) -> list[dict]: scoped_response, _ = actions.tools.list_scoped_tools( identifier=identifier, filter={"connection_names": [CONNECTION_NAME]}, page_size=100, # the connector has 45 tools; fetch them in one page ) tools = [] for scoped_tool in scoped_response.tools: definition = MessageToDict(scoped_tool.tool).get("definition", {}) if definition.get("name") in ALLOWED_TOOLS: tools.append( { "name": definition["name"], "description": definition.get("description", ""), "input_schema": definition.get("input_schema", {}), } ) return tools

Run the tool-use loop

Claude picks tools, execute_tool runs each one with the creator's credentials, and results go back as tool_result blocks. The loop ends when Claude stops asking for tools. Failed calls return an is_error result so the model can recover instead of crashing the run.

SYSTEM_PROMPT = ( "You operate a creator's YouTube channel. Look up the channel ID with " "youtube_channels_list before querying analytics. Never reply to or " "moderate a comment you have not read in this session." ) def run_agent(identifier: str, prompt: str) -> str: tools = load_youtube_tools(identifier) messages = [{"role": "user", "content": prompt}] while True: response = claude.messages.create( model="claude-sonnet-5", max_tokens=2048, system=SYSTEM_PROMPT, tools=tools, messages=messages, ) messages.append({"role": "assistant", "content": response.content}) if response.stop_reason != "tool_use": return "".join( block.text for block in response.content if block.type == "text" ) tool_results = [] for block in response.content: if block.type != "tool_use": continue try: result = actions.execute_tool( tool_name=block.name, identifier=identifier, connection_name=CONNECTION_NAME, tool_input=block.input, ) tool_results.append( { "type": "tool_result", "tool_use_id": block.id, "content": json.dumps(result.data, default=str), } ) except Exception as exc: tool_results.append( { "type": "tool_result", "tool_use_id": block.id, "content": f"Tool call failed: {exc}", "is_error": True, } ) messages.append({"role": "user", "content": tool_results}) if __name__ == "__main__": creator_id = "creator_123" # your app's unique ID for this user ensure_youtube_connected(creator_id) print( run_agent( creator_id, "Summarize my channel's views and watch time for the last 28 days. " "Then list the 20 most recent comment threads on video VIDEO_ID " "and flag viewer questions that have no reply yet.", ) )

Replace VIDEO_ID with a real video ID from the creator's channel. For the full SDK surface, see the Python SDK reference and the Anthropic example.

Virtual MCP servers for multi-tool, multi-tenant YouTube agents

The tool-calling loop above is the right shape when you own the agent runtime. When the agent runs in an MCP host, or when one agent role spans several connectors, a Virtual MCP server gives you a single scoped endpoint instead.

Define the server once per agent role

A Virtual MCP server declares which connections and which tools an agent role can see. You create it once, not once per user, and it returns a static mcp_server_url. This community-manager role gets four YouTube tools and one Slack tool for posting digests. Both connection names must already exist in AgentKit, then Connections.

import os from scalekit import ScalekitClient from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping scalekit_client = ScalekitClient( env_url=os.environ["SCALEKIT_ENVIRONMENT_URL"], client_id=os.environ["SCALEKIT_CLIENT_ID"], client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], ) vmcp_response = scalekit_client.actions.mcp.create_config( name="youtube-community-manager", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name="youtube", tools=[ "youtube_channels_list", "youtube_comment_threads_list", "youtube_comments_insert", "youtube_comments_set_moderation_status", ], ), McpConfigConnectionToolMapping( connection_name="slack", tools=["slack_send_message"], ), ], ) config_id = vmcp_response.config.id mcp_server_url = vmcp_response.config.mcp_server_url

Check connections, then mint a session token

Before each run, confirm the creator's YouTube and Slack connections are still active, then mint a short-lived session token bound to that creator. There is no refresh endpoint; call create_session_token again for a new token. The Node.js SDK does not mint MCP session tokens yet, so do this step in Python on your backend.

from datetime import timedelta identifier = "creator_123" accounts_response = scalekit_client.actions.mcp.list_mcp_connected_accounts( config_id=config_id, identifier=identifier, include_auth_link=True, ) inactive = [ account for account in accounts_response.connected_accounts if (account.connected_account_status or "").upper() != "ACTIVE" ] for account in inactive: print(f"{account.connection_name} needs auth: {account.authentication_link}") if inactive: raise SystemExit("Authorize the connections above, then run again.") token = scalekit_client.actions.mcp.create_session_token( mcp_config_id=config_id, identifier=identifier, expiry=timedelta(minutes=30), # longer than the expected run ).token

Connect it to a LangChain agent

Any MCP host that sends a bearer header can use the endpoint. Here LangChain connects through langchain-mcp-adapters and runs a Claude model over the scoped tools, continuing from the mcp_server_url and token values above.

pip install "langchain-mcp-adapters>=0.3,<1" langchain-anthropic
import asyncio from langchain_anthropic import ChatAnthropic from langchain_core.messages import HumanMessage, ToolMessage from langchain_mcp_adapters.client import MultiServerMCPClient def message_text(content) -> str: if isinstance(content, str): return content return "".join( block.get("text", "") for block in content if isinstance(block, dict) ) async def run(mcp_url: str, session_token: str, prompt: str) -> str: client = MultiServerMCPClient( { "scalekit": { "transport": "streamable_http", "url": mcp_url, "headers": {"Authorization": f"Bearer {session_token}"}, } } ) tools = await client.get_tools() tool_map = {tool.name: tool for tool in tools} llm = ChatAnthropic(model="claude-sonnet-5", max_tokens=2048).bind_tools(tools) messages = [HumanMessage(prompt)] while True: response = await llm.ainvoke(messages) messages.append(response) if not response.tool_calls: return message_text(response.content) for tool_call in response.tool_calls: result = await tool_map[tool_call["name"]].ainvoke(tool_call["args"]) messages.append( ToolMessage(content=str(result), tool_call_id=tool_call["id"]) ) print( asyncio.run( run( mcp_server_url, token, "Find unanswered viewer questions in the latest comment threads on " "video VIDEO_ID and post a short summary to the #community channel " "in Slack.", ) ) )

Scalekit's LangChain example shows both the direct tool path and this MCP path side by side.

Why this shape fits multi-tenant YouTube agents

One server definition serves every creator. The endpoint is static; the identity is per-user, carried by a session token that expires on its own. No creator's token reaches another creator's run, and no YouTube credential enters the agent runtime or the model's context.

Least privilege is enforced at the tool level. The community manager cannot delete videos, run searches, or touch analytics, because those tools are not on its server. A separate analytics role can get youtube_analytics_query and the Reporting tools without comment write access. For the design reasoning, see what a Virtual MCP server is and when to use one.

Observability for downstream YouTube tool calls

YouTube failures are rarely loud. Exhaust the shared quota at 2 p.m. Pacific and every general-bucket call fails for every tenant until midnight, while the model may paraphrase the error into something that reads like success. You need a record per call.

What the tool call log records

AgentKit's tool call log records every call with timestamp, connection, tool name, user identifier, and latency. Each row opens to the connection ID, connected account ID, source, duration, and, for failures, the error code and full error message. The overview dashboard tracks total calls, success rate, and error counts per connector from a 1-hour to a 30-day window.

Errors are classified by where they happened. A call rejected before it left Scalekit, such as an expired token or invalid parameters, is separated from a call that reached YouTube and failed there, such as a quotaExceeded or commentsDisabled response. Those have different owners and different fixes.

Why the user identifier matters on YouTube

Because quota is shared across your project, one noisy tenant can exhaust it for everyone. The identifier on every log row tells you whose agent spent it, which tool it called, and when. That is the difference between "YouTube is failing" and "creator_184's agent retried youtube_comments_insert 140 times this morning."

Shared tokens make this unanswerable. Per-user connected accounts make it a filter. Read more in agent tool observability and on agent tool calling auth patterns.

Which one to build against

If your agent operates channels for many creators, answering comments, moderating, reading analytics, managing playlists, build on the MCP path through a Scalekit Virtual MCP server, or call the same tools with execute_tool when you own the runtime. If your agent publishes video, manages captions and thumbnails, or runs a fixed Reporting API ingest, integrate those endpoints directly, or through Scalekit's API proxy so they share the same connected accounts.

Many production YouTube agents will do both. The interactive assistant uses scoped tools; the publishing pipeline calls upload endpoints. What does not change is the credential problem underneath: per-user Google grants, a shared project quota, and no service account escape hatch. That is the layer that needs production-grade infrastructure.

Build your YouTube agent with Scalekit

Start with the YouTube connector docs and the YouTube connector page. For patterns you can adapt, the competitive intelligence briefing agent and Slack triage agent templates pair well with YouTube tools. Compare the sibling write-up on Vimeo MCP vs Vimeo API, and check pricing before you size quota and connected accounts.

Building a YouTube agent and stuck on OAuth verification, quota, or multi-tenant scoping? Talk to us for immediate help from the Scalekit team.

Browse the Scalekit YouTube connector

No items found.
Agent
Auth Quickstart
On this page
Share this article
Agent
Auth Quickstart

Acquire enterprise customers with
‍zero upfront cost.

Every feature unlocked. No hidden fees.