Announcing CIMD support for MCP Client registration
Learn more

Render MCP vs Render API for AI Agents

Saif Ali Shaik
Founding Developer Advocate

TL;DR

  • Render's official MCP server has 26 tools, and 3 of them only return a Dashboard link. Rollback, scaling, suspension, and deletion exist only in the REST API.
  • Render documents MCP OAuth only for Claude Code, Claude Desktop, Codex, and Cursor. A custom agent backend uses a Render API key on either path.
  • Render API keys have no documented scopes and reach every workspace their owner belongs to, so least privilege lives at the tool layer.
  • Both paths share per-user rate limits: 30 writes and 30 log requests a minute.
  • Scalekit's Render connector vaults each user's key and scopes its 205 tools per agent through list_scoped_tools or a Virtual MCP server.

Why the Render choice isn't obvious

Your agent needs to operate Render. It reads a failing deploy's logs, checks memory on the API service, and rolls back the release that broke checkout. Render ships an official MCP server and a REST API that covers almost everything in the Dashboard. They are not interchangeable. The MCP server is built for a developer prompting from an AI coding tool; the API is built for software acting on its own. Here's where the two diverge for a production agent, and how to pick.

What Render MCP and Render API actually are

Both paths end at the same place: the Render REST API, called as a specific Render user.

Render MCP server

Render maintains the official MCP server, hosts it, and publishes the implementation as open source. It went GA on August 21, 2025. Render recommends the hosted server over running it locally, because the hosted version updates automatically. It supports Streamable HTTP and stdio.

Authentication has two modes. OAuth for Claude Code, Codex, and Cursor shipped on July 22, 2026, and Render's docs also cover OAuth through the Claude Desktop connector. Those flows run through Render's official plugins and connectors; the Codex setup passes a fixed codex OAuth client ID. Other applications and non-interactive environments such as CI/CD send a Render API key as a Bearer token. Resource tools accept an explicit workspaceId.

Render REST API

The REST API lives under /v1 and is described by an OpenAPI 3.0 spec. Render says it supports almost all of the functionality in the Dashboard: every service type, Postgres and Key Value, deploys, rollbacks, scaling, environment groups, Blueprints, projects, custom domains, disks, webhooks, workflows, logs, metrics, and audit logs.

Every request requires an API key in the Authorization: Bearer header. Keys are created from Account Settings and shown once. Render documents no other authentication method for the REST API.

Comparing them where it matters for agents

Four dimensions change your architecture: capability coverage, the auth path, what you own in production, and which workloads fit each path.

What your agent can actually do

The MCP server's 26 tools cover discovery, creation, deploys, logs, metrics, and datastores. Three of them, update_web_service, update_static_site, and update_cron_job, return a Dashboard link instead of changing anything. Scalekit's Render connector wraps the REST API as 205 tools.

Capability
Render MCP
Render API
List and inspect services, deploys, events
Yes
Yes
Create services and datastores
Web services, static sites, cron jobs, Postgres, Key Value
All service types, including private services and background workers
Trigger a deploy
Yes, with optional cache clear
Yes, plus a specific commit, image, or deploy-only mode
Cancel or roll back a deploy
No
Yes
Scale, autoscale, suspend, resume, restart
No
Yes
Update service settings
No, returns a Dashboard link
Yes
Environment variables
One tool that takes the complete list
Per-key upsert, full replace, env groups, secret files
Logs and metrics
Yes
Yes, plus log streams and metrics streams
Run SQL against Postgres
Yes, read-only
No, connection info only
Custom domains, disks, snapshots, webhooks
No
Yes
Delete any resource
No
Yes
Workspace members and audit logs
No
Yes

Where the MCP ceiling sits

The MCP server stops right before the actions an incident responder reaches for. An agent working through MCP can find the failing deploy, read the error logs, and spot an out-of-memory event in the service's event history. It cannot roll back, restart, or scale. Its only levers on an existing service are a fresh deploy and an environment variable update. Render's own docs state the boundary: other modifications and deletions go through the Dashboard or the REST API.

The one thing only MCP does

query_render_postgres runs read-only SQL against a Render Postgres database, and the REST API has no equivalent. There is a catch for production data. The tool connects over the database's external URL, so the database's IP allowlist applies, and the hosted server has no IP addresses you can allowlist yet. For an IP-restricted database, Render's guidance is to run the MCP server locally.

The auth path each one puts you on

For a custom agent, both paths converge on one credential. Render documents MCP OAuth only for its four supported AI tools. An agent you host, whether a LangChain service, a Claude SDK worker, or a scheduled job, connects to the hosted MCP server with a Render API key in the Authorization header. That is the same key it would send to the REST API. The token type doesn't change between paths. Only the tool surface does.

Recommended reading: OAuth vs API keys for AI agents

One key, every workspace

That credential is broad. Render's API docs describe no scopes and no read-only mode for keys, and a key provides access to every workspace its owner belongs to. Render still enforces the user's role: in a protected environment, only admins can perform destructive actions. What the user can't do, the agent can't do. The inverse holds too. Everything the user can do, across every workspace they belong to, the agent can do.

Per-user credentials in multi-tenant agents

Both paths require per-user credential isolation in a multi-tenant B2B agent. Each user connects their own Render API key, so you hold one long-lived key per user. Neither path stores, rotates, or revokes it for you. The workspace breadth adds a second obligation: a consultant who belongs to three client workspaces hands your agent all three. Every call must pin the right owner_id or workspaceId, sourced from your tenant record, never inferred by the model.

What you own on the MCP path

Render owns hosting, tool schemas, and server updates. You own the key for each user and explicit workspace selection on every call. The older session-level workspace selection is deprecated and scheduled for removal, which is also a live example of the maintenance trajectory: the hosted server changes on Render's schedule, and tool contracts move with it. An agent pinned to today's tool signatures needs a regression check when the server ships.

What you own on the API path

You own everything above the HTTP call: request construction, cursor pagination, 429 handling, and an LLM-ready schema for every endpoint you expose. Render recommends exponential backoff with random jitter for 429s. The API itself maintains backward compatibility, but Render notes that endpoint names and tags in the OpenAPI spec can change. That matters if you generate tool definitions from the spec. Writing the schema is the hard part, not the API call.

Rate limits are shared across both paths

Render rate limits the REST API per user: 400 GET requests a minute, 30 other writes a minute, 30 log requests a minute, and 20 service creations an hour. Deploys, suspends, and resumes are capped at 10 a minute per service. The hosted MCP server calls the Render API with the credential you give it, so an MCP session and a REST pipeline for the same user drain one budget. Log search is the tight constraint: a triage agent paging through logs hits the 30-per-minute ceiling long before the GET limit.

Recommended reading: Rate limiting for Virtual MCP servers

When Render MCP wins

Pick the MCP server when the agent is an assistant for the person holding the account:

  • A developer debugs their own services from Claude Code, Cursor, Codex, or Claude Desktop and signs in with OAuth in the browser.
  • The work is read-heavy triage: logs, metrics, deploy history, and service events in a workspace the user already works in.
  • You need ad hoc read-only SQL against a Render Postgres database that isn't IP-restricted.
  • You're prototyping a Render assistant and the 26-tool surface covers the workflow.

When the Render API wins

Pick the REST API when the agent acts on its own or for many customers:

  • The agent must remediate, not just diagnose: roll back, restart, scale, suspend, or cancel a deploy.
  • It runs headless: a webhook-driven incident responder, a nightly preview-environment cleanup, a CI step.
  • You're building a multi-tenant product where each customer's engineers connect their own Render accounts.
  • The workflow touches custom domains, disks and snapshots, environment groups, Blueprints, or audit logs.
  • You need a versioned contract rather than a server that updates on Render's schedule.

The credential problem that exists on both paths

Neither path turns a Render key into production-grade credential infrastructure.

What Render gives you

Render gives every request an identity. The key acts as the user, and Render enforces that user's workspace role on every call, including admin-only destructive actions in protected environments. That is the correct security primitive for an agent acting on behalf of a person. It is not a credential lifecycle.

What you still have to build

Take a B2B platform-engineering agent serving 60 engineers across 12 customer companies. That is 60 Render API keys, each long-lived, each able to reach every workspace its owner belongs to. You store them encrypted and isolated per tenant, keep them out of logs and LLM context, pin each call to the right workspace, and delete them when an engineer leaves or a customer churns. The MCP path removes none of this; for a custom agent, it uses the same key.

Scalekit's Render connector handles key collection, vaulted storage, and per-user tool execution, and serves the same connected account through direct tool calls or a Virtual MCP server. The MCP vs API decision doesn't change your credential infrastructure.

Why build Render agents on Scalekit

Four properties matter for a Render agent in production: where keys live, which tools the model sees, how multi-tool agents stay scoped, and what you can audit afterward.

Per-user keys, collected and vaulted

Each user connects their Render API key once through a Scalekit-hosted page. For API-key connectors, that page shows a credential form instead of an OAuth consent screen. Scalekit encrypts the key with AES-256 at rest, isolates it per tenant, supports your own GCP or AWS KMS, and sends it with every call. Your agent passes an identifier. Credentials never touch the agent runtime or the LLM context.

205 tools, scoped to the job

Tool bloat is an accuracy problem and a cost problem. At roughly 200 tokens per tool, loading all 205 Render tools costs about 41,000 tokens before the agent does any work. list_scoped_tools returns only the tools the current user's connected account is authorized to call, narrowed further by tool name. A triage agent needs eight read-only tools. It should never see render_service_delete or render_postgres_connection_info_get, which returns the database password. Because the Render key can't be scoped, the tool surface is where least privilege lives. The fix is not better prompting. It is surface reduction.

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

A Virtual MCP server declares exactly which connections and tools an agent role can see: for example, eight read-only Render tools, two GitHub tools, and one Slack tool for an incident agent. Render's MCP docs describe no way to restrict its toolset per client; a Virtual MCP server exposes only the allowlist. You create the server once per agent role and mint a short-lived session token for each user before each run. One server definition serves all users. The endpoint is static; the identity is per-user. There is no MCP server to deploy, host, or maintain.

Recommended reading: What is a Virtual MCP server? and When to use a Virtual MCP server

Observability on every downstream call

Scalekit tracks every tool call with its outcome: success, failure, and why. Each call is captured as a structured event you can stream to Datadog, Splunk, or any SIEM. Every execute_tool response carries an execution_id, and each connected account records last_used_at. Auth logs cover token and session events across users and agents, filterable by user, organization, and status. When a customer asks which agent touched their API service at 02:14, the answer comes from a log, not a reconstruction.

Recommended reading: Audit trails for agent auth in B2B SaaS

How to connect a Render agent with Scalekit in Python

The walkthrough builds a Render incident-triage agent in Python: the Claude SDK for the direct tool-calling path, and LangChain for the MCP path. The Node.js SDK supports connected accounts and executeTool, but as of version 2.17.0 it doesn't mint Virtual MCP session tokens, so Python keeps both paths in one language.

Prerequisites

Create the Render connection once per environment in AgentKit > Connections > Create Connection; the Render connector docs walk through the dashboard steps. The connection name in your code must match the dashboard exactly. This is the single most common integration error. The examples use render. Copy SCALEKIT_ENVIRONMENT_URL, SCALEKIT_CLIENT_ID, and SCALEKIT_CLIENT_SECRET from Developers > API Credentials, and set ANTHROPIC_API_KEY and RENDER_WORKSPACE_ID.

pip install scalekit-sdk-python anthropic python-dotenv pip install langchain-anthropic "langchain-mcp-adapters>=0.3,<1" # MCP path only

Step 1: Connect each user's Render account

get_or_create_connected_account creates the per-user record. If it isn't ACTIVE, get_authorization_link returns a hosted page where the user enters their Render API key. The identifier must be your server-side user ID, never a value the browser supplies.

import os from dotenv import load_dotenv from scalekit import ScalekitClient load_dotenv() scalekit_client = ScalekitClient( env_url=os.environ["SCALEKIT_ENVIRONMENT_URL"], client_id=os.environ["SCALEKIT_CLIENT_ID"], client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], ) actions = scalekit_client.actions RENDER_CONNECTION = "render" # must match the connection name in AgentKit > Connections exactly USER_ID = "user_123" # your server-side user ID, never a value taken from the browser WORKSPACE_ID = os.environ["RENDER_WORKSPACE_ID"] # tea-..., from your tenant record def ensure_render_connected(identifier: str) -> None: account = actions.get_or_create_connected_account( connection_name=RENDER_CONNECTION, identifier=identifier, ).connected_account if account.status != "ACTIVE": link = actions.get_authorization_link( connection_name=RENDER_CONNECTION, identifier=identifier, ).link # The hosted page collects the user's Render API key; Scalekit vaults it print(f"Connect your Render account: {link}") input("Press Enter once the key is saved...") account = actions.get_or_create_connected_account( connection_name=RENDER_CONNECTION, identifier=identifier, ).connected_account if account.status != "ACTIVE": raise RuntimeError(f"Render connection is {account.status}, not ACTIVE") ensure_render_connected(USER_ID)

Step 2: Retrieve the tools this user can call

The agent doesn't load a flat catalog of 205 tools. list_scoped_tools returns the tools this user's connected account is authorized to call, and the tool_names filter narrows that to a read-only triage surface. No deploy, rollback, scale, delete, or credential tool reaches the model.

from google.protobuf.json_format import MessageToDict TRIAGE_TOOLS = [ "render_services_list", "render_service_get", "render_deploys_list", "render_deploy_get", "render_service_events_list", "render_logs_list", "render_metrics_cpu_get", "render_metrics_memory_get", ] scoped_response, _ = actions.tools.list_scoped_tools( identifier=USER_ID, filter={"connection_names": [RENDER_CONNECTION], "tool_names": TRIAGE_TOOLS}, page_size=100, ) claude_tools = [] for scoped_tool in scoped_response.tools: definition = MessageToDict(scoped_tool.tool).get("definition", {}) claude_tools.append({ "name": definition["name"], "description": definition.get("description", ""), "input_schema": definition.get("input_schema", {"type": "object"}), })

Step 3: Run the Claude agent loop with execute_tool

Each tool_use block becomes an execute_tool call against the user's connected account. Scalekit injects the vaulted Render key and returns structured output. Errors, including Render 429s, go back to the model as is_error tool results instead of crashing the loop.

import json import anthropic client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY SYSTEM_PROMPT = ( "You are a read-only Render incident triage agent. " f"Work only in Render workspace {WORKSPACE_ID}. " "Diagnose the problem and report findings; you cannot change anything." ) messages = [{ "role": "user", "content": "The api service started returning 500s after the last deploy. Find out why.", }] while True: response = client.messages.create( model="claude-sonnet-5", max_tokens=2048, system=SYSTEM_PROMPT, tools=claude_tools, messages=messages, ) messages.append({"role": "assistant", "content": response.content}) if response.stop_reason != "tool_use": print("".join(block.text for block in response.content if block.type == "text")) break tool_results = [] for block in response.content: if block.type != "tool_use": continue try: result = actions.execute_tool( tool_name=block.name, tool_input=block.input, identifier=USER_ID, connection_name=RENDER_CONNECTION, ) content, is_error = json.dumps(result.data, default=str), False except Exception as exc: # return Render errors, including 429s, to the model content, is_error = f"Tool call failed: {exc}", True tool_results.append({ "type": "tool_result", "tool_use_id": block.id, "content": content, "is_error": is_error, }) messages.append({"role": "user", "content": tool_results})

Step 4: Define a Virtual MCP server for the agent role

For MCP clients and multi-tool agents, define the server once per agent role, not once per user. This one pairs the Render triage tools with two GitHub tools and one Slack tool. Every connection_name must already exist in AgentKit > Connections and match the dashboard exactly.

from datetime import timedelta from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping # Run once per agent role. Persist config_id and mcp_server_url. vmcp = actions.mcp.create_config( name="render-incident-agent", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name=RENDER_CONNECTION, tools=TRIAGE_TOOLS, ), McpConfigConnectionToolMapping( connection_name="github-connect", # match your GitHub connection name tools=["github_commits_compare", "github_commit_pull_requests_list"], ), McpConfigConnectionToolMapping( connection_name="slack", # match your Slack connection name tools=["slack_send_message"], ), ], ) config_id = vmcp.config.id mcp_server_url = vmcp.config.mcp_server_url def mint_session_token(identifier: str) -> str: """Check every connection is ACTIVE for this user, then mint a fresh token.""" accounts = actions.mcp.list_mcp_connected_accounts( config_id=config_id, identifier=identifier, include_auth_link=True, ) pending = { account.connection_name: account.authentication_link for account in accounts.connected_accounts if account.connected_account_status != "ACTIVE" } if pending: raise RuntimeError(f"User must connect these accounts first: {pending}") return actions.mcp.create_session_token( mcp_config_id=config_id, identifier=identifier, expiry=timedelta(minutes=30), ).token

Step 5: Connect a LangChain agent to the Virtual MCP server

LangChain reaches the Virtual MCP server through langchain-mcp-adapters over Streamable HTTP, with the session token as a Bearer header. The loop below is the full tool-calling cycle; the model only sees the eleven allowlisted tools.

import asyncio from langchain_anthropic import ChatAnthropic from langchain_core.messages import HumanMessage, ToolMessage from langchain_mcp_adapters.client import MultiServerMCPClient async def run_incident_agent(identifier: str, prompt: str) -> None: token = mint_session_token(identifier) # never reuse a token across runs mcp_client = MultiServerMCPClient({ "scalekit": { "transport": "streamable_http", "url": mcp_server_url, "headers": {"Authorization": f"Bearer {token}"}, } }) tools = await mcp_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: print(response.text) break for call in response.tool_calls: result = await tool_map[call["name"]].ainvoke(call["args"]) messages.append(ToolMessage(content=str(result), tool_call_id=call["id"])) asyncio.run(run_incident_agent( USER_ID, f"In Render workspace {WORKSPACE_ID}, find why the api service is failing, " "compare the last two deployed commits, and post a summary to #incidents.", ))

Start from a template

The same pattern powers Scalekit's incident response agent, DevOps assistant agent, engineering standup agent, and auto release notes agent templates. Framework-specific versions live in the LangChain and Anthropic examples, and the full Virtual MCP lifecycle is in Set up and connect a Virtual MCP server.

Recommended reading: Vercel MCP vs Vercel API, GitHub MCP vs GitHub API, and PagerDuty MCP vs PagerDuty API

Which one to build against

If your agent is a developer's assistant inside Claude Code or Cursor, diagnosing that developer's own services, Render's hosted MCP server with OAuth is the fastest path, and its read-only SQL is a real advantage. If your agent remediates, runs headless, or serves many customers, build on the REST API: rollback, scaling, and suspension exist nowhere else. Either way, a custom agent holds a per-user Render API key that reaches every workspace its owner belongs to. That credential, and the tool surface you let it drive, is what needs production-grade infrastructure.

Build your Render agent with Scalekit

Shipping a Render agent for many users and want a second set of eyes on the credential model or the tool scoping? Talk to us and a Scalekit engineer will help you get it to production.

Start with the Scalekit Render connector docs, browse all Scalekit connectors and the full connector catalog in the docs, or compare plans on the pricing page.

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.