Give your app an MCP server

An app you build on Cloudrizz can itself be an MCP server. Add one file and ChatGPT, Claude, or any MCP client can connect to your app and call tools you define — signed in as your app's own end-users. Cloudrizz generates the entire OAuth authorization server and MCP transport for you.

Two different MCP servers

Don't confuse this with the Cloudrizz MCP server you connect to in order to build apps:

  • The Cloudrizz MCP server (mcp.cloudrizz.com) is how you build and deploy apps from your assistant.
  • Your app's MCP server (this page) runs on your app's own domain and lets your users' assistants call the tools your app exposes.
This capability is in beta. The file contract below is stable; the connection UX continues to improve as ChatGPT and Claude evolve their connector flows.

Enable it: ship api/mcp/tools.js

There's no setting to flip. When your app contains a file at api/mcp/tools.js whose default export is an array of tools, Cloudrizz injects the MCP runtime at deploy time. Apps without that file pay nothing.

Each tool is a plain object:

// api/mcp/tools.js
export default [
  {
    name: "list_notes",
    description: "List the signed-in user's notes.",
    // JSON Schema describing the arguments (optional).
    inputSchema: { type: "object", properties: {} },
    async handler(args, { user, env }) {
      const { results } = await env.DB
        .prepare("SELECT id, body FROM notes WHERE user_id = ?")
        .bind(user.id)
        .all();
      return results;
    },
  },
  {
    name: "add_note",
    description: "Create a note for the signed-in user.",
    inputSchema: {
      type: "object",
      properties: { body: { type: "string" } },
      required: ["body"],
    },
    async handler({ body }, { user, env }) {
      await env.DB
        .prepare("INSERT INTO notes (user_id, body) VALUES (?, ?)")
        .bind(user.id, body)
        .run();
      return "Note saved.";
    },
  },
];

The tool object

  • name — unique tool name the assistant calls.
  • description — what the tool does (the model reads this to decide when to use it).
  • inputSchema — JSON Schema for the arguments. Optional; defaults to an empty object.
  • scope — optional. If set, the tool is only callable when the access token was granted that scope.
  • handler(args, ctx) — your code. Receives the parsed args and a context object.

The handler context gives you everything you need to act as the user:

  • ctx.user — the authenticated end-user (id, email, name, emailVerified, twoFactorEnabled, createdAt). Scope queries to user.id.
  • ctx.env — your app bindings (env.DB, env.STORAGE, env.AUTH, etc.).
  • ctx.request — the incoming request.
  • ctx.scopes — the scopes granted to this token.

Return a string or any JSON-serializable value and Cloudrizz wraps it as MCP text content. Return an object with a content array to control the MCP result yourself. Throwing inside a handler is reported to the model as a tool error, so it can react.

What Cloudrizz serves for you

Once api/mcp/tools.js is present, your deployed app answers these routes on its own domain — you write none of this:

  • /mcp — the MCP endpoint (Streamable HTTP). This is the URL your users add to ChatGPT or Claude.
  • /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource — discovery metadata.
  • /oauth/register — Dynamic Client Registration (RFC 7591).
  • /oauth/authorize — sign-in + consent screen, backed by env.AUTH (your app's own users, including email OTP if 2FA is on).
  • /oauth/token — OAuth 2.1 token endpoint with PKCE and refresh rotation.

Auth state lives in your app's database under the reserved _cr_oauth_* tables (created on first use). Access and refresh tokens are stored hashed, never in plaintext. Tools require a valid token — an unauthenticated request to /mcp returns a 401 that triggers the client's OAuth flow automatically.

How your users connect

Give users your app's MCP URL — your domain plus /mcp:

https://your-app.example.com/mcp

They add it as a custom connector / remote MCP server exactly like they would the Cloudrizz one (see Connect ChatGPT & Claude). The first connection opens your app's sign-in screen; after they authorize, their assistant can call your tools as them.

Build it from chat

In practice you don't hand-write any of this. Ask your assistant something like “add an MCP server to my app exposing tools to list and create notes” — it creates api/mcp/tools.js with edit_file, then save_version and deploy_app. See Build & deploy an app.