MCP on a self-hosted install
Enable the MCP server of a self-hosted Nodaro so Claude, Cursor, ChatGPT and other MCP clients can use your install over OAuth, on an MCP hostname or a path.
The Nodaro MCP server lets AI clients such as Claude, Cursor, Cline, Continue, Goose and ChatGPT use the tools of your self-hosted install on a user's behalf. It is off by default. To enable it, you give MCP its own hostname, route that hostname to the API, and set two variables. Users then sign in to your install with OAuth from their client.
How MCP is served
- The API serves MCP at the path
/mcp, on port9000inside thenodarocontainer. - The web server on port
3000refuses MCP requests. A request to/mcpon the app's main address answers405with the errorwrong_mcp_hostand the address of the real endpoint. - So MCP needs its own hostname, such as
mcp.nodaro.example.com, whose traffic reaches the API directly. On the Business and Cloud editions, you can serve it by path on your own hosts instead. - Sign-in stays on your main domain. The OAuth discovery document
/.well-known/oauth-authorization-serverand the consent screen are served onPUBLIC_URL.
Enable MCP
Route an MCP hostname to the API
Create a DNS record for mcp.<your-domain> that resolves to your server. Do not proxy it through a CDN: proxies break the long-lived Server-Sent Events connections that MCP uses.
The compose file does not publish the API port. Publish it on the loopback interface, under the nodaro service:
nodaro:
ports:
- "3000:3000"
- "127.0.0.1:9000:9000"Then give your reverse proxy a second site for the MCP host that forwards to 127.0.0.1:9000 instead of 127.0.0.1:3000. Keep response buffering off, as in the nginx example.
Add the MCP hostname as a custom domain of the backend service:
railway domain add mcp.your-domain.com --service backendOr, in the Railway dashboard: Project › backend service › Settings › Domains › Add custom domain. Then add the CNAME record at your DNS provider.
Set the variables
MCP_ENABLED=true # required; the default is off
MCP_PUBLIC_URL=https://mcp.your-domain.com # the hostname from step 1On the compose stack, add both under environment: of the nodaro service: the compose file does not pass them from .env. Then run docker compose -f docker-compose.community.yml up -d.
MCP_PUBLIC_URL is the identity that the discovery endpoints advertise for the protected resource (RFC 9728), and the base of the upload links that tools return. Without it, your install advertises the Nodaro Cloud MCP host. If you serve MCP on your main domain instead of a subdomain, set it to the same value as PUBLIC_URL. Requests to /mcp must then still reach the API port directly.
Check the discovery endpoints
curl https://mcp.your-domain.com/.well-known/oauth-protected-resource
curl https://your-domain.com/.well-known/oauth-authorization-serverBoth must return JSON with status 200.
Add the connector in your client
The MCP endpoint is https://mcp.your-domain.com/mcp. In Claude, open Settings › Connectors › Add custom connector and enter that URL. For other clients, see Connect a client and use your own MCP URL instead of Nodaro Cloud's.
MCP by path (no dedicated MCP host)
Business and Cloud editions only. It is a surface profile key, which Community ignores. A deployment with no hostname to spare for mcp.<your-domain>, or whose network allows only its own listed hosts, can serve the same MCP endpoint under a path:
NODARO_SURFACE_PROFILE={"mcp":{"byPath":true}}- Where it answers. At
https://<host>/v1/mcpon each host the deployment declares as its own:PUBLIC_URLand everyCORS_ORIGINentry.mcp.pathsets another path:/v1/mcpor a lower-case path under it, with no trailing slash and at most 64 characters. Any other path falls back to/v1/mcp, with a warning. - What it needs.
MCP_ENABLED=true, andPUBLIC_URLset to the deployment's own address. WithoutPUBLIC_URL, the server logs a warning and keeps MCP on/mcp. - No proxy change. The bundled proxy already forwards
/v1/*and/.well-known/oauth-*to the API.MCP_PUBLIC_URLis not needed either. - Every address follows the host. The
401challenge, the OAuth discovery documents, the consent screen and the links the tools hand out all name the declared host the client connected through. People sign in on the site they are on. A request on a host the deployment did not declare gets the addresses ofPUBLIC_URL. - One sign-in works on every host. A client signed in through one of the deployment's hosts may use the same token on another.
- The path replaces
/mcp. While the mode is on,/mcpand its/.well-known/…/mcpdocuments are not served. A client set up with an earlier/mcpaddress reconnects at the path.
List only origins this deployment serves in CORS_ORIGIN: each one counts as one of its own hosts while the mode is on. With the mode off, the default, every MCP answer is unchanged.
To check it:
curl https://your-domain.com/.well-known/oauth-protected-resource/v1/mcpThe resource must be https://your-domain.com/v1/mcp. Users then add https://your-domain.com/v1/mcp as the connector URL.
Which clients can register
MCP clients sign in with OAuth. Supported clients register themselves with your install through dynamic client registration (RFC 7591). Two variables control it, and their defaults suit most installs:
| Variable | Default | What it does |
|---|---|---|
MCP_DYNAMIC_REGISTRATION | allowlist | allowlist accepts only the client names in MCP_DCR_ALLOWLIST. open accepts any client. off disables dynamic registration. |
MCP_DCR_ALLOWLIST | 14 known clients | The client names accepted in allowlist mode, comma-separated. |
The default allowlist is: Claude, Claude Code, Cursor, Cline, Continue, Goose, ChatGPT, OpenAI, Lovable, Gemini, Gemini CLI, Codex, MCP Inspector and mcp-inspector. To add your own client, set the full list:
MCP_DCR_ALLOWLIST=Claude,Cursor,Cline,Continue,Goose,YourCustomClientallowlist is the recommended mode.
What the clients can do
The MCP server covers the generation tools for image, video, audio, characters, locations and objects, and tools for the gallery, workflows, apps, saved components and models. Each user acts as their own account on your install. See the MCP tools reference and MCP troubleshooting.
Frequently asked questions
Is MCP on by default on a self-hosted Nodaro?
No. Set MCP_ENABLED=true and MCP_PUBLIC_URL, route an MCP hostname to the API, and restart. On the compose stack, add both variables under the nodaro service's environment block, because the compose file does not pass them from .env.
Why does my MCP client get 405 wrong_mcp_host?
The client uses the app's main address, where the web server refuses MCP requests. Point the client at the MCP host instead, https://your-mcp-host/mcp, which must reach the API on port 9000 directly.
Which MCP clients can register with my install?
By default, 14 known clients, including Claude, Claude Code, Cursor, Cline, Continue, Goose, ChatGPT and Codex. Add names to MCP_DCR_ALLOWLIST, or set MCP_DYNAMIC_REGISTRATION=open to accept any client.
Can I serve MCP without a dedicated MCP hostname?
On the Business and Cloud editions, yes. Set mcp.byPath to true in the surface profile, and MCP answers at https://your-host/v1/mcp on the deployment's own hosts. No proxy change and no MCP_PUBLIC_URL are needed.
Can I put a CDN in front of the MCP host?
Not one that proxies traffic. MCP keeps long-lived Server-Sent Events connections open, and a proxying CDN breaks them. Point DNS straight at your server.
Related
Nodaro MCP
Connect a client
MCP tools reference
Reverse proxy and HTTPS
Configuration
Last updated on
Connect to Nodaro Cloud
Connect a self-hosted Nodaro to a Nodaro Cloud account to run standard models without your own keys and to use the Nodaro-exclusive nodes, billed in credits.
Single sign-on
Let a trusted identity provider sign users in to your self-hosted Nodaro. Configure EXTERNAL_SSO_PROVIDERS, choose the account-linking rules and allow SSO only.