Announcing CIMD support for MCP Client registration
Learn more

Floot MCP vs Floot API for AI Agents

Vishal Dhawani
Founding Architect @ Scalekit

TL;DR

  • Floot's hosted remote Model Context Protocol (MCP) server is the only programmatic way to build and publish on Floot. Its docs describe no public platform REST API.
  • Floot MCP uses OAuth 2.1 with PKCE (S256 only) and dynamic client registration. No API keys, and one consent covers the whole Floot account.
  • Tool calls are metered as build actions, 100 to 5,000 a day by plan, counted against the authorizing Floot account. A shared login pools every tenant.
  • The only REST-style surface in a Floot build is your app's backend: right for runtime data and webhooks, no help for building or publishing.
  • Scalekit's flootmcp connector stores and refreshes each user's Floot token, scopes its 45 tools per agent with Virtual MCP, and ties every call to a user.

Why Floot MCP vs Floot API is not the usual choice

Your agent needs to build software on Floot: create a project, write pages and endpoints, provision a database, run the tests, and publish. You go looking for the Floot API and find a hosted MCP server instead, plus the backend endpoints of whatever app Floot ends up hosting. So the Floot MCP vs Floot API decision is not the usual tradeoff between two views of one platform. The surfaces do different jobs, authenticate different principals, and fail differently in production. Here's how to decide what your Floot agent builds against.

What Floot MCP and Floot API actually are

Two objects, and only one of them can change a Floot project.

Floot MCP is the platform's control plane

Floot builds and hosts full-stack TypeScript and React apps, and it expects your assistant to drive it through a hosted remote MCP server that Floot runs itself. The server speaks Streamable HTTP, answers in plain JSON with no SSE stream, and holds no session state: every request carries its own bearer token. Floot registers the same tool set for every client, and Scalekit's catalog lists 45 tools. One client caveat: standard ChatGPT only exposes the search and fetch tools. Floot documents the server on its own connector page and in its "Connect any MCP client" guide.

Floot API means your app's backend, not the platform

Floot's documentation describes no public REST API for managing projects. Its API pages cover the other direction: how the apps you build call third-party APIs and receive webhooks. What does exist is each app's backend. Endpoints live in files such as endpoints/route_POST.ts, Floot's tool descriptions call them the project's /_api/* routes, and a published app serves them on its own domain. Authentication on those endpoints is whatever your app's code enforces. The closest official reference is Floot's "Connecting external services" guide.

How Scalekit catalogs Floot

Scalekit mirrors that shape. Floot appears as one vendor MCP connector, flootmcp, using OAuth 2.1 with dynamic client registration and routing calls to Floot's own server. Scalekit prefixes each of the 45 tools with flootmcp_. There is no separate Floot API connector, because there is no platform API to wrap. Schemas and setup steps are in the Floot MCP connector docs, and the Floot MCP connector page has starter prompts for projects, files, preview, and publishing.

What your agent can actually do

The capability split follows from that asymmetry. MCP can do almost anything to a project; your app's endpoints can only do what you wrote into them.

The capability comparison

Tool names are Floot's own; through Scalekit, each carries the flootmcp_ prefix.

Capability
Floot MCP
Floot app endpoints (/_api/*)
Create a project
Yes: create_project
No
Read and edit code
Yes: read_files, apply_patch
No
Provision a database or sign-in
Yes: provision_resource
No
Query or migrate the app database
Yes: query_database, execute_sql
Only via endpoints you write
Read backend logs
Yes: get_logs, production via run_code_in_vm
No
Typecheck and run tests
Yes: typecheck, run_tests
No
Publish or take the app offline
Yes: publish_app, unpublish_app
No
Finish a custom domain
Starts it; DNS finishes in the browser
No
Export the code zip
No: browser only
No
Receive third-party webhooks
No
Yes, once published
Serve the app's own users
No
Yes

What stays in the browser

Floot draws a deliberate line around money and handoff. No tool can buy anything, change a plan, or add a payment method. Exporting the code zip, finishing custom-domain DNS, the first native mobile build before a store account is connected, and adding collaborators all happen in Floot's web app. Any agent workflow that ends in one of those steps needs a human handoff you design, not a tool call you retry.

Tools that assume a human at the editor

Several Floot tools only work while the user has the project open in Floot's editor. run_code_in_browser fails fast without a connected browser, navigate_preview needs an open Floot window, and get_current_context reports what the user is looking at right now. Call publish_app without a domain and the user gets a publish form in the editor instead. The catalog also carries card_upload_asset, which Floot marks as an internal bridge not meant for agents, and get_guide, an alias of get_guides. A headless agent should never see the editor-bound tools, and it should always pass the subdomain label as domain when it publishes.

The tool surface is heavy before any work starts

Floot's tool descriptions are long because they carry Floot's conventions: patch formats, path schemes, concurrency guards, destructive-action warnings. Scalekit's catalog entry for the 45 tools runs to roughly 9,700 words of descriptions and parameter docs, on the order of 16,000 tokens at four characters per token. Loading all of it on every run is a cost problem and an accuracy problem. The fix is not better prompting. It is surface reduction.

The auth path each one puts you on

The two surfaces authenticate different principals. MCP authenticates your end user to Floot; your app's endpoints authenticate whoever calls your app.

Floot MCP: OAuth 2.1, PKCE, one grant per account

Floot's MCP server is its own OAuth authorization server. It runs the OAuth 2.1 Authorization Code flow with PKCE (RFC 7636), accepts only the S256 challenge method, and supports dynamic client registration (RFC 7591), so there is no client ID or secret to create. Consent happens on Floot's site, and the client then sends the access token as a standard bearer header. There is no API key or personal token alternative; Floot tells clients to leave those fields empty. The grant is account-wide: a connected client can read and edit any project in that Floot account.

Floot app endpoints: whatever your code enforces

Floot's provisioned auth is built for your app's human users: email-and-password sessions, plus Google and Microsoft sign-in that Floot brokers. Floot's docs describe no machine credential for an external agent calling your endpoints, so that check is code you write in the endpoint. The secret it verifies is yours to issue, rotate, and revoke. Storing it through request_external_resource as a GENERIC credential keeps the value out of the model's view; the model only ever sees the environment variable name. Static secrets are simpler for headless callers. They also never expire unless you make them.

Metering follows the authorizing account

Floot meters connector work in build actions: one per tool call, reads included, with failed and cancelled calls free. Free accounts get 100 a day, Pro ($25 a month) gets 1,000, and Power ($100 a month) gets 5,000. Six housekeeping tools are exempt, including list_projects, get_job_status, and unpublish_app. The count lands on the account whose Floot login authorized the connector, not on the project owner. Every redundant read_file where one read_files call would do spends the user's allowance, which gives tool selection accuracy a direct price on Floot.

Recommended Reading: Rate Limiting in Virtual MCP Servers: Per-User, Per-Tool, and Per-Tenant Controls

What you own in production

Floot runs the server, the build machine, and the hosting. Everything between your agent and a correct, attributable call is still yours.

On the MCP path

You own the per-user OAuth tokens: storage, refresh, and reauthorization when a user revokes access. You also own how the agent handles Floot's asynchronous model. Long-running calls return a jobId to poll with get_job_status, write tools accept an expected_version guard against concurrent edits, and a production build past 15 minutes of wall clock returns a definite failure. When a user hits a build-action limit, the refusal names the limit and the reset time. Your agent has to stop and surface it, not retry.

Guardrails move into your code

Floot's safety model assumes an interactive MCP client. execute_sql allows destructive statements and relies on the client to show the user the SQL and ask for approval, and unpublish_app tells the model to confirm with the user first. A headless agent calling those tools through execute_tool has no approval dialog. The human-in-the-loop gate becomes code you write, or the tool never enters that agent's surface.

Schema drift is Floot's release cadence

The contract you depend on is Floot's tool list, and it moves when Floot ships. Floot says tools it adds later are metered unless it exempts them, and its docs describe no way to pin a tool-set version. Name the tools each agent may call instead of trusting whatever the server lists today.

On the app endpoint path

Here you own everything: endpoint design, the credential check, input validation, and the retry behavior of whichever agent calls in. Floot's backend is serverless on AWS Lambda, so nothing survives between requests outside the database or storage. Published apps are also protected from runaway traffic: when traffic spikes far past an app's baseline, Floot caps its backend concurrency and lifts the cap no sooner than 30 minutes later. An agent polling your endpoints in a tight loop can look exactly like the runaway poller that throttle is built to catch.

When to use MCP, when to use the app API

The split is cleaner than for most tools, because the two surfaces barely overlap.

Use Floot MCP when

  • Your agent builds or changes the app: scaffolding a project, editing code, provisioning a database or sign-in, running migrations, and publishing
  • Your agent debugs a project: reading logs with get_logs, running typecheck and run_tests, and batching file reads with read_files
  • The agent is interactive, in Claude, Cursor, or a similar client where the user watches the preview and approves destructive SQL
  • Floot is one tool among several, such as a release agent that publishes on Floot and reports to Slack

Use your Floot app's endpoints when

  • The agent works with the app's data at runtime: reading orders, creating bookings, or updating records through endpoints you designed
  • An external system pushes events into the app, such as a Stripe or form-provider webhook
  • The caller is a pipeline or another company's agent that should never hold a Floot account
  • You need a contract you version yourself, because the endpoint schema is code you control

The credential problem that exists on both paths

Neither surface gives you somewhere to keep credentials for many users, and Floot's account model makes the shortcut unusually costly.

The shared-login failure mode

The tempting design for a multi-tenant Floot agent is one Floot account behind the whole product. Three things break at once. The grant is account-wide, so the agent acting for tenant A can read and edit tenant B's projects. Build actions pool, so 40 tenants share one 1,000-call daily allowance on Pro. And Floot's records can only ever name that one account, so they cannot tell your tenants apart. Shared credentials are a single-user solution. They do not survive a second user.

The N-credential problem

Per-user accounts fix isolation and turn it into bookkeeping. Every end user completes Floot's OAuth consent once, and you now hold N tokens to encrypt at rest, refresh before expiry, and discard the moment a user revokes access. Floot keeps a raw audit row per tool call, with the tool name, a capped argument summary, and the result, for three days. Anything longer, attributed to your own users, is yours to keep. The app endpoint path has the same shape: N callers, N secrets, N revocations.

Recommended Reading: How to Handle Token Refresh for AI Agents

Where Scalekit fits

Scalekit's Floot MCP connector handles the OAuth flow, token storage, and refresh for every user, so your credential infrastructure doesn't change with the path you pick. Each user signs in to Floot once, and credentials never touch the agent runtime or the model's context. If other agents call your Floot app's endpoints, bring your own connector puts that API under the same connected-account model. What the user can't do, the agent can't do.

How to connect a Floot agent through Scalekit

The examples use Python and LangChain: a deterministic call, a scoped agent, and a multi-tool Virtual MCP server. The snippets share the actions client from the first one.

Before you start

Create a Floot MCP connection in the Scalekit dashboard under AgentKit, then Connections. Floot supports dynamic client registration, so Scalekit registers itself as the OAuth client and there is no Floot app to create. Copy your environment URL, client ID, and client secret from Developers, then API Credentials. The connection_name in every call must match the connection name in the dashboard exactly; a mismatch is the most common integration error.

pip install scalekit-sdk-python python-dotenv langchain-anthropic "langchain-mcp-adapters>=0.3,<1" SCALEKIT_ENVIRONMENT_URL=<your-environment-url> SCALEKIT_CLIENT_ID=<your-client-id> SCALEKIT_CLIENT_SECRET=<your-client-secret> ANTHROPIC_API_KEY=<your-anthropic-api-key>

Authorize a user and make a deterministic call

The first run sends the user through Floot's consent screen once. After that, execute_tool runs a named Floot tool with no model in the loop, the pattern for pipelines that must behave the same way every time.

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 # Must match the connection name under AgentKit > Connections exactly CONNECTION_NAME = "flootmcp" USER_ID = "user_123" # your app's stable ID for this end user def ensure_floot_connected(user_id: str) -> None: response = actions.get_or_create_connected_account( connection_name=CONNECTION_NAME, identifier=user_id ) if response.connected_account.status == "ACTIVE": return link = actions.get_authorization_link( connection_name=CONNECTION_NAME, identifier=user_id ) print("Authorize Floot:", link.link) input("Press Enter after authorizing...") response = actions.get_or_create_connected_account( connection_name=CONNECTION_NAME, identifier=user_id ) if response.connected_account.status != "ACTIVE": raise RuntimeError(f"Floot is {response.connected_account.status}, not ACTIVE") ensure_floot_connected(USER_ID) # Deterministic call: your code names the tool; no model chooses it. # list_projects is one of Floot's unmetered tools. result = actions.execute_tool( tool_name="flootmcp_list_projects", tool_input={"limit": 10}, connection_name=CONNECTION_NAME, identifier=USER_ID, ) print(result.execution_id, result.data)

Give a LangChain agent a scoped Floot toolset

Before the loop starts, retrieve the tools this user's connected account is authorized to call, filtered to what this agent role needs. The agent never sees the 45-tool catalog. It sees seven read-and-verify tools, none of which writes, publishes, or needs an open editor.

from langchain_anthropic import ChatAnthropic from langchain_core.messages import HumanMessage, SystemMessage, ToolMessage # Read-and-verify surface: no writes, no publish, no editor-bound tools REVIEW_TOOLS = [ "flootmcp_list_projects", "flootmcp_list_files", "flootmcp_read_files", "flootmcp_search_code", "flootmcp_typecheck", "flootmcp_run_tests", "flootmcp_get_logs", ] tools = actions.langchain.get_tools( identifier=USER_ID, connection_names=[CONNECTION_NAME], tool_names=REVIEW_TOOLS, page_size=100, ) tool_map = {tool.name: tool for tool in tools} llm = ChatAnthropic(model="claude-opus-5-5").bind_tools(tools) messages = [ SystemMessage("You review Floot projects. Batch file reads with flootmcp_read_files."), HumanMessage("Typecheck my Launchpad project and explain any errors."), ] while True: response = llm.invoke(messages) messages.append(response) if not response.tool_calls: print(response.text) break for call in response.tool_calls: output = tool_map[call["name"]].invoke(call["args"]) messages.append(ToolMessage(content=str(output), tool_call_id=call["id"]))

Floot recommends Opus-class models for long, multi-tool builds, which is why the example uses Claude Opus. Scalekit's LangChain example covers the adapter's other filters.

Define a Virtual MCP server for a Floot release agent

A release agent needs Floot and Slack, but only a few tools from each. A Virtual MCP server declares exactly that surface once per agent role and returns a static mcp_server_url. Setup runs once, not once per user. The mapping includes flootmcp_get_guides because the flootmcp_publish_app description asks the model to read the publishing guide before its first call.

from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping config_response = actions.mcp.create_config( name="floot-release-agent", description="Tests, typechecks, and republishes Floot apps; reports to Slack", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name="flootmcp", tools=[ "flootmcp_list_projects", "flootmcp_get_guides", "flootmcp_read_files", "flootmcp_typecheck", "flootmcp_run_tests", "flootmcp_get_publish_status", "flootmcp_publish_app", "flootmcp_get_job_status", ], ), McpConfigConnectionToolMapping( connection_name="slack", # must match your Slack connection name tools=["slack_send_message"], ), ], ) # Static for this agent role: save as SCALEKIT_MCP_CONFIG_ID and SCALEKIT_MCP_SERVER_URL print(config_response.config.id, config_response.config.mcp_server_url)

Mint a per-user session token at runtime

Before each run, confirm the user's connections are active, mint a short-lived session token for that user, and pass the URL and token to the agent as bearer auth. Setup once per agent role. Mint a token before each run. The endpoint is static; the identity is not.

import asyncio import os from datetime import timedelta from langchain_anthropic import ChatAnthropic from langchain_core.messages import HumanMessage, ToolMessage from langchain_mcp_adapters.client import MultiServerMCPClient CONFIG_ID = os.environ["SCALEKIT_MCP_CONFIG_ID"] MCP_SERVER_URL = os.environ["SCALEKIT_MCP_SERVER_URL"] def mint_session_token(user_id: str) -> str: state = actions.mcp.list_mcp_connected_accounts( config_id=CONFIG_ID, identifier=user_id, include_auth_link=True ) pending = { account.connection_name: account.authentication_link for account in state.connected_accounts if account.connected_account_status != "ACTIVE" } if pending: raise RuntimeError(f"User must authorize first: {pending}") return actions.mcp.create_session_token( mcp_config_id=CONFIG_ID, identifier=user_id, expiry=timedelta(minutes=30), ).token async def run_release_agent(user_id: str, request: str) -> str: client = MultiServerMCPClient( { "scalekit": { "transport": "streamable_http", "url": MCP_SERVER_URL, "headers": {"Authorization": f"Bearer {mint_session_token(user_id)}"}, } } ) tools = await client.get_tools() tool_map = {tool.name: tool for tool in tools} llm = ChatAnthropic(model="claude-opus-5-5").bind_tools(tools) messages = [HumanMessage(request)] while True: response = await llm.ainvoke(messages) messages.append(response) if not response.tool_calls: return response.text for call in response.tool_calls: output = await tool_map[call["name"]].ainvoke(call["args"]) messages.append(ToolMessage(content=str(output), tool_call_id=call["id"])) print(asyncio.run(run_release_agent( "user_123", "Typecheck and test Launchpad. If both pass, republish it to its current " "subdomain and post the live URL to #releases in Slack.", )))

Session tokens default to about an hour, and create_session_token is also the remint call; there is no refresh endpoint. Tools left out of the mapping, such as flootmcp_unpublish_app and flootmcp_execute_sql, do not exist for this agent. Slack tool names are in the Slack connector docs, and the configuration guide covers updates and deletion.

Trace every Floot call back to a user

Floot's three-day audit rows know nothing about your tenants. Scalekit sits in the call path: execute_tool returns an execution_id, provider-side failures raise ScalekitToolException with the provider's error code and message, and the dashboard keeps tool call logs alongside auth logs you can filter by user and organization. Write the execution_id next to your tenant ID and you have an audit record that outlives Floot's window.

import logging from scalekit.common.exceptions import ScalekitToolException audit_log = logging.getLogger("floot.audit") def run_floot_tool(tenant_id: str, user_id: str, tool_name: str, tool_input: dict): try: result = actions.execute_tool( tool_name=tool_name, tool_input=tool_input, connection_name=CONNECTION_NAME, identifier=user_id, ) except ScalekitToolException as err: audit_log.error( "floot tool failed tenant=%s user=%s tool=%s execution_id=%s code=%s message=%s", tenant_id, user_id, tool_name, err.execution_id, err.tool_error_code, err.tool_error_message, ) raise audit_log.info( "floot tool ok tenant=%s user=%s tool=%s execution_id=%s", tenant_id, user_id, tool_name, result.execution_id, ) return result.data

Auth logs can also stream to a SIEM or data warehouse. Agent webhooks emit connected account events, so a scheduled Floot agent can pause when a user disconnects instead of failing mid-build. The agent audit trail guide covers which events to keep.

Which one to build against

The decision is less MCP versus API than control plane versus data plane.

For agents that build and ship Floot apps

If your agent creates, edits, debugs, or publishes Floot apps, it builds against Floot MCP, because nothing else can. Scope each agent role to the tools it needs, keep editor-bound tools out of headless runs, and gate destructive SQL and unpublishing in your own code.

For agents that use what the app does

If your agent reads or writes the app's data after launch, or an external system pushes events into it, call the app's endpoints and own that contract. Most production Floot products end up running both: an MCP-driven builder and an endpoint-driven integration. Either way, the per-user credential problem is the same, and that is the part that needs production-grade infrastructure.

Get help building your Floot agent

Start with the Floot MCP connector docs and the Floot MCP connector page, or browse all connectors to pair Floot with Slack, GitHub, or Linear. The DevOps assistant agent and incident response agent templates show the multi-connector pattern, and pricing covers plan limits. Building a Floot agent right now? Talk to us for hands-on help.

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.