Render Useful MCP

by lusrodri

Not rated
GitHub

About

Full Render.com control for AI agents: deploys, scaling, databases, logs, disks. All 207 API endpoints, generated from Render's OpenAPI spec.

Details

Author
lusrodri
Categories
Developer Tools

Setup

Install Render Useful MCP in your MCP client (Claude Desktop, Cursor, Windsurf, and others).

Repository: https://github.com/lusrodri/render-useful-mcp

Follow the installation instructions in the repository README, then restart your MCP client.

A Model Context Protocol server forRenderthat exposesevery endpoint of the official Render Public API, plus a handful of higher-level tools for the workflows the raw API makes tedious.

Written in TypeScript. Every API tool is generated from Render's own OpenAPI document, so coverage is complete by construction and stays that way.

212 tools: all 207 operations of the Render Public API (spec version 1.0.0), plus 5 workflow tools for the sequences the raw API makes tedious.

πŸ“–Documentation siteΒ·tool catalogueΒ·llms.txt

Most API wrappers stop at a curated subset of endpoints, which drifts out of date and leaves you stuck the moment you need something the author skipped.

- Complete, by construction.Every operation in Render's own OpenAPI document becomes a tool. Everything the API allows your key to do is reachable out of the box β€” no opt-in required.
- Usable by a model.Names resolve to ids fuzzily, your workspace id is filled in automatically, deploys can be waited on in one call, and failures come back with a hint instead of a bare status code.
- Narrowable when you want it.Every toolset is on by default;RENDER_MCP_TOOLSETSandRENDER_MCP_READ_ONLYexist to restrict the surface deliberately, not to gate it.
- Honest about risk.MCP destructive/read-only/idempotent annotations are derived from real HTTP semantics, so clients can make sensible auto-approval decisions β€” including thePUTs that replace a whole collection, where everything the caller omits is deleted. Secrets are redacted from logs.

Both buttons prefill the config with a placeholder API key β€” replace it after install.

Claude Codeβ€” install it globally, so it is there in every project:

claude mcp add render --scope user -e RENDER_API_KEY=rnd_your_key -- npx -y render-useful-mcp

--scope useris the part that matters. Claude Code defaults tolocalscope, which registers the server for the current directory only β€” so it works where you installed it and is missing everywhere else, which is the usual reason a freshly added server seems to disappear. The three scopes are:

Confirm withclaude mcp list, and re-run the command with--scope userifrenderis not listed from an unrelated directory.

Claude Code, as a plugin β€” this wires up the server and its docs in one step, and plugins are installed globally by nature:

/plugin marketplace add LuSrodri/render-useful-mcp /plugin install render-useful-mcp@lusrodri-render

ExportRENDER_API_KEYin the shell that launches Claude Code; the plugin reads it from the environment rather than storing it. Seeplugin/README.md.

Claude for macOS and Windows, as a desktop extension β€” download the.mcpbbundle from thelatest releaseand open it. Claude installs it and asks for the API key in a form, so nothing is configured by hand. The bundle ships its own dependencies; it does not need npm or a global Node install.

Desktop installs default to theservices,logsandenv-groupstoolsets rather than the whole catalogue, because every tool definition costs context in every conversation. Set theToolsetsfield toall, or to any comma-separated list, to change that.

Requires Node.js β‰₯ 20.11 for every install route except the desktop extension.

Or run it without installing, which is what most MCP client configs do:

It is also listed in theMCP Registryasio.github.LuSrodri/render-useful-mcp, so clients that browse the registry can find and configure it without being pointed at the npm package by hand.

Get an API key fromRender Dashboard β†’ Account Settings β†’ API Keys.

claude mcp add render --scope user -e RENDER_API_KEY=rnd_your_key -- npx -y render-useful-mcp

AddRENDER_WORKSPACE_IDthe same way if you know it:

claude mcp add render --scope user \ -e RENDER_API_KEY=rnd_your_key \ -e RENDER_WORKSPACE_ID=tea_your_workspace_id \ -- npx -y render-useful-mcp

Claude Desktop / any client usingmcpServersβ€” add to the config file:

{ "mcpServers": { "render": { "command": "npx", "args": ["-y", "render-useful-mcp"], "env": { "RENDER_API_KEY": "rnd_your_key_here", "RENDER_WORKSPACE_ID": "tea_your_workspace_id" } } } }

RENDER_WORKSPACE_IDis optional but recommended: many Render endpoints require anownerIdthat the model has no way to guess, and setting it removes a lookup from nearly every session. Find it with therender_list_ownerstool, or read it from your dashboard URL.

// A client that struggles with the full catalogue, or a session scoped to one job. "env": { "RENDER_MCP_TOOLSETS": "services,logs,metrics" } // An agent that should be able to look but not touch. "env": { "RENDER_MCP_READ_ONLY": "true" }

If you do narrow it, the model can still callrender_toolsetsto see everything that exists and which groups are switched off, so it can tell you exactly what to change. Widening the surface means editingRENDER_MCP_TOOLSETSand restarting the server: protocol revision2026-07-28requires the result oftools/listnot to vary per connection or as a side effect of another call, so the enabled set is fixed at startup.

These are always available, in any toolset configuration. They exist because the equivalent raw sequence is several calls the model usually gets wrong on the first try.

One per Render endpoint, namedrender_<operation_id>β€”render_list_services,render_create_deploy,render_update_postgres, and so on. Each carries the summary, description, parameter docs, enums and constraints straight from Render's spec. The full list is on thetool catalogue page.

A generated tool is only as good as what the spec says about it, and Render's spec describes shapes rather than usage. Three things close that gap:

oneOfbranches keep their names, and say which one applies.Dereferencing a$refnormally throws away the schema's name, which leavesserviceDetailsonrender_create_serviceas five structurally similar anonymous objects with nothing to say which one goes with whichtype. Each branch now carries its name from Render's spec as atitle, socron_job→cronJobDetailsPOSTandruntime: docker→dockerDetailsare decisions a model can actually make.

Naming the branches makes the choice readable but not checkable, and Render's spec carries nodiscriminator: underoneOf's exactly-one rule, a branch that requires nothing β€”staticSiteDetailsPOSTβ€” accepts every payload, which leaves the other four unreachable.src/tools/schema-unions.tsrewrites those unions intoif/thenrules keyed on the property that selects them, so the mapping is part of the schema rather than advice in a description, and a wrong-branch field is rejected by name instead of asmust match exactly one schema in oneOf. A build invariant fails the generator if anyoneOfbranch is left unreachable, andtest/payloads.test.tschecks the property against real payloads for all 207 tools.

Fields no caller can fill are removed.Render's spec reuses response schemas inside request bodies in a couple of places, which drags in values the server generates: a cron job's Docker branch asks for a wholeregistryCredentialobject requiring the credential'sidand the timestamp of its last change, where a web service takes a plainregistryCredentialId. A field that can only be filled with invented values is worse than no field, sosrc/tools/schema-repairs.tsdrops it and the usage note points atimage.registryCredentialId, which is where Render actually takes the reference. The generator throws if an entry stops matching, so a fix upstream shows up as a build failure.

A few tools carry hand-written usage notes.src/tools/operation-hints.tsappends aUsage:paragraph to the operations models demonstrably get wrong β€”create-servicegets complete worked examples,update-env-vars-for-servicewarns that it replaces the whole set,post-jobsays it isnothow you create a cron job. Examples are data, not prose: every one is validated against its own tool schema by the test suite and rendered into the description from the same object, so a published example is one the server provably accepts. The generator throws if a hint names an operation Render has withdrawn, so the file cannot rot silently.

The server sendsinstructions.src/instructions.tsis delivered once atinitialize: id prefixes, resolve-the-name-first, which workflow tool replaces which raw sequence, and theoneOfconvention. Cross-tool advice belongs there rather than duplicated into every tool description that needs it.

Creating a cron job that runs a Docker image

The case that motivated all three. A cron job is a service, so:

// render_create_service { "type": "cron_job", "name": "nightly-report", "ownerId": "tea-…", "repo": "https://github.com/acme/reports", "branch": "main", "serviceDetails": { // the cronJobDetailsPOST branch "runtime": "docker", "schedule": "0 3   ", // five-field cron, UTC, required for cron jobs "plan": "starter", "region": "oregon", "envSpecificDetails": { // the dockerDetails branch, because runtime is docker "dockerfilePath": "./Dockerfile", "dockerContext": ".", "dockerCommand": "python report.py", }, }, }

For a prebuilt image instead of a build, droprepo/branch, setimageto{"ownerId": "tea-…", "imagePath": "docker.io/acme/reports:latest"}, use"runtime": "image", and giveenvSpecificDetailsonly thedockerCommand. Change the schedule later withrender_update_service; trigger an off-schedule run withrender_run_cron_job.render_create_jobis a different thing β€” a one-off command on an existing service.

Generated, not hand-written.scripts/generate-operations.tsreadsspec/render-openapi.jsonand emits the tool catalogue. It is strict: an unmapped tag, a name collision, a cyclic$ref, a path parameter missing from its template, or a body property that would shadow a query parameter all fail the build rather than producing a subtly wrong tool. Updating to a new Render API version is: drop in the new spec, runnpm run generate, review the diff.

Schemas reach the client intact.Render's spec uses the full range of JSON Schema. Tool schemas are fully dereferenced and passed through, and Ajv validates arguments against them β€” so enums, patterns, formats andoneOfare all actually enforced. This is why the server uses the SDK's low-levelServerrather thanMcpServer, which accepts only Zod schemas. The one deliberate rewrite is the undiscriminated unions described above: left as the spec writes them, they cannot be satisfied at all.

Bodies are flattened.Request-body properties become top-level tool arguments, which keeps call sites shallow and improves tool-call accuracy. The generator proves at build time that body properties never collide with path or query parameters. The six array- andoneOf-valued bodies keep their structure under a singlebodyargument.

Errors are made actionable.A failure returns the HTTP status, Render's own message and a hint aimed at the actual cause β€” a 404 suggests confirming the id with a list call, a 401 points at the API key page. A tool that is registered but hidden says which toolset to enable rather than "unknown tool".

Retries are conservative.Rate limits and transient 5xx are retried with decorrelated-jitter backoff, honouringRetry-After. Non-idempotent methods are never replayed on a server error: a retriedPOST /deployswould deploy twice.

Secrets stay out of logs.Logging is structured JSON on stderr β€” stdout is the transport β€” with connection strings, API keys and tokens redacted.

npm install npm run generate # rebuild the tool catalogue from the OpenAPI spec npm run docs # re-render every doc that quotes the catalogue npm run build npm test npm run check # generate + docs + lint + typecheck + test

Tool counts, the toolset table, the workflow-tool list, the wholedocs site,llms.txtandllms-full.txtare all rendered fromsrc/generated/operations.jsonbyscripts/generate-docs.ts. Regions between<!-- generated:key -->markers in this file andplugin/README.mdare rewritten in place; the site's files are written whole.

npm run docs:checkre-renders everything and fails if it differs from what is committed. CI runs it on every pull request, the Pages workflow runs it before deploying, and the spec sync runsnpm run docsso an API change and the prose describing it arrive in one reviewable pull request. Numbers in the docs cannot silently drift from the catalogue β€” which they had, before this existed.

The test suite covers catalogue invariants (all 207 operations, no dangling$ref, path params required, annotations match HTTP semantics), request mapping, retry and pagination behaviour, the composite tools, and a full in-memory MCP client/server round trip.

npm run build:mcpb # -> build/render-useful-mcp-<version>.mcpb

This stagesdist/plus the production dependency tree intobuild/mcpb/and packs it. The bundle is self-contained by design β€” Claude runs it with no install step β€” so the dependencies are copied out of this repository'snode_modulesrather than reinstalled, which is what guarantees the artefact contains the tree the test suite actually ran on.

manifest.jsonat the repository root is the extension's manifest;npm versionkeeps its version in step with the package. To inspect a built bundle:

npx mcpb info build/render-useful-mcp-<version>.mcpb npx mcpb unpack build/render-useful-mcp-<version>.mcpb /tmp/check

This is automated..github/workflows/spec-sync.ymlruns daily, fetches Render's current API description, regenerates the catalogueand the documentation, and opens a pull request when the set of tools actually changes β€” with a summary of which tools were added, removed or changed shape, and a warning when the change is breaking. Nothing merges automatically.

Every run writes to its job summary, including the runs that find nothing, so "did it check today?" is answerable from the Actions tab rather than inferred from the absence of a pull request.

Two details of the schedule are deliberate, and both come from the job appearing dead while it was in fact working:

- 47 5 , not0 6 1.GitHub queues scheduled workflows best-effort and drops them under load; the top of the hour is the most contended slot there is. The one observed scheduled run started nearly four hours late. Daily, at an unremarkable minute, makes a dropped run cost a day rather than a fortnight β€” and a run that finds no catalogue change exits early, so the cost of daily is a few seconds of CI.
- .github/spec-sync-heartbeat.json.GitHub disables scheduled workflows in repositories that go 60 days without activity, and a disabled workflow cannot re-enable itself. The workflow commits a timestamp to that file whenever the recorded one is more than 20 days old β€” roughly 18 commits a year, which keeps the clock well clear of the limit and leaves a visible record in the git log that the routine is alive.

To do it by hand, or to check right now:

npm run sync-spec # fetch the current spec into spec/render-openapi.json npm run generate # rebuild the catalogue from it git diff src/generated/operations.json npm test

Render does not serve its OpenAPI document from a stable URL β€” the documented.jsonand.yamlendpoints 404 β€” soscripts/fetch-spec.tsextracts it from the docs HTML. That is fragile by nature, so it validates what it extracts (title, server, minimum operation count) and fails loudly rather than overwriting a good spec with a truncated one. If Render changes their docs platform, the sync workflow goes red instead of quietly reporting "no changes" forever.

The generator refuses to emit a catalogue it cannot fully understand β€” an unmapped tag, a name collision, a cyclic$ref, a path parameter missing from its template, or a body property that would shadow a query parameter all fail the build. CI additionally asserts that the committed catalogue matches what the spec produces, so a spec update without a regenerate cannot merge.

A release publishes to two places: the package to npm, and metadata describing it to theMCP Registry. Both authenticate with the workflow's GitHub OIDC token β€” npm viaTrusted Publishing, the registry viamcp-publisher login github-oidcβ€” so no npm token or registry secret is stored anywhere. The npm publish carries a provenance attestation.

npm version patch # or minor / major git push --follow-tags

Pushing avtag runs.github/workflows/publish.yml, which verifies the tag matchespackage.jsonand that the generated catalogueand documentationare current, works out which of the two targets still need this version, then lints, type-checks, tests, builds and publishes. It also builds the.mcpbbundle and attaches it to the GitHub Release, which is the only place the desktop extension is distributed from.

The documentation check is repeated here rather than left to CI becauseREADME.mdships inside the npm tarball and a tag can be cut from any commit. npm versions are immutable, so a package whose README contradicts the catalogue beside it cannot be taken back.

The order is fixed: npm first, then the registry. The registry proves you own the package by fetching the published tarball and looking formcpNamein itspackage.json, so it cannot accept a version npm has not served yet.

If a release fails for a reason outside the code, re-run it from the Actions tab viaRun workflow, selecting the tag underUse workflow from*. Each target is checked independently, so a retry after a half-finished release skips whatever already succeeded instead of failing on npm's immutable versions. The workflow rejects dispatches from a branch, so a published version always corresponds to a tag.

server.jsonis the registry's copy of this server's metadata. Two of its fields are load bearing and both are asserted bytest/server-json.test.ts:

- namemust beio.github.LuSrodri/.... The registry derives the namespace you may publish to from the OIDC token'srepository_ownerclaim and compares it case sensitively, so the lowercased spelling is rejected with a 403.
- mcpNameinpackage.jsonmust equal that same name. It is the ownership proof described above; without it the registry refuses the package.

The version fields trackpackage.jsonβ€”npm versionkeeps them in step via theversionlifecycle script, somcp-publisher publishalso works from a clean local checkout. CI stamps them from the tag again before publishing, so the tag is what decides what ships.

No telemetry, no analytics, no backend. The server runs on your machine and contacts exactly one host β€” Render's API. Your key is read from the environment, sent only to Render, never written to disk, and redacted from log output. Full detail, including how to verify each claim yourself:PRIVACY.md.

Not affiliated with Render.spec/render-openapi.jsonis Render's published API description, vendored so builds are reproducible.

This is a web browser that enables your coding agent, such as Claude Code, to visit websites on your behalf and assist you in identifying bugs or creating UI test cases.

Create crafted UI components inspired by the best 21st.dev design engineers.

Bring agent evaluations, observability, and synthetic test set generation directly into your IDE for free with Galileo's new MCP server

An MCP server to help AI assistants to answer questions and generate AccelByte Extend SDK code more effectively .

MCP server for AI Diagram Maker β€” generate beautiful software engineering diagrams directly inside Cursor, Claude Desktop, Claude Code, or any MCP-compatible AI agent

ALAPI MCP Tools,Call hundreds of API interfaces via MCP

No reviews yet β€” be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.