appsmith-mcp
MCP server for interacting with a self-hosted Appsmith instance via its REST API, enabling read/update/create of pages, queries, JS objects, widgets, datasources, and applications with lazy session management and destructive-operation gating.
README
appsmith-mcp
MCP server for a self-hosted Appsmith instance, over Appsmith's own REST API — the same API the editor uses.
Built because no reliable Appsmith MCP server exists: there is nothing published on
npm or PyPI, nothing in the appsmithorg GitHub org, and the listings that surface
in search results are auto-generated stubs with no implementation behind them.
How it authenticates
Appsmith uses Spring Security form login behind CSRF protection:
- A
GET /api/v1/users/meseeds anXSRF-TOKENcookie. POST /api/v1/loginsendsusername/passwordform-encoded, echoing that token in theX-XSRF-TOKENheader.- The response sets a
SESSIONcookie used for every later call.
The client logs in lazily on first use and re-logs in once automatically on a 401,
so an expired session heals itself instead of failing a tool call.
Setup
npm install
cp .env.example .env # then put your Appsmith password in .env
npm run check # read-only checks against the live instance
npm run check -- --scratch # also covers writes, via a throwaway app it deletes
npm run check prints a PASS/FAIL row per endpoint — run it whenever an Appsmith
upgrade might have moved routes. --scratch creates an mcp-smoke-* application,
exercises create-page / publish / delete against it, and removes it again.
Registration
Registered at user scope, so it is available in every project rather than one:
claude mcp add appsmith --scope user -- \
node --env-file-if-exists=<abs-path>/.env <abs-path>/src/index.js
That writes to ~/.claude.json. Paths must be absolute — a user-scope server is
launched from whatever directory the session happens to be in.
Credentials are read from .env via Node's --env-file-if-exists, so no secret
lives in the MCP config. Because .env pins one instance, retarget it by changing
APPSMITH_URL.
To scope it back to a single project, claude mcp remove appsmith --scope user and
put the same command in that project's .mcp.json.
Tools
Read
| Tool | Endpoint |
|---|---|
appsmith_whoami |
GET /api/v1/users/me |
appsmith_list_workspaces |
GET /api/v1/workspaces/home |
appsmith_list_applications |
GET /api/v1/applications/home |
appsmith_list_pages |
GET /api/v1/pages/application/{id} |
appsmith_get_page |
GET /api/v1/pages/{id} |
appsmith_list_queries |
GET /api/v1/actions |
appsmith_list_js_objects |
GET /api/v1/collections/actions |
appsmith_list_datasources |
GET /api/v1/datasources |
appsmith_get_datasource_structure |
GET /api/v1/datasources/{id}/structure |
appsmith_list_plugins |
GET /api/v1/plugins |
appsmith_search_entities |
GET /api/v1/search-entities |
appsmith_export_application |
GET /api/v1/applications/export/{id} |
Edit — changing an existing app's logic
| Tool | Endpoint |
|---|---|
appsmith_update_query |
PUT /api/v1/actions/{id} |
appsmith_create_query |
POST /api/v1/actions |
appsmith_update_js_object |
PATCH /api/v1/collections/actions/{id} + PUT .../body |
appsmith_create_js_object |
POST /api/v1/collections/actions |
appsmith_delete_query |
DELETE /api/v1/actions/{id} — gated |
appsmith_delete_js_object |
DELETE /api/v1/collections/actions/{id} — gated |
appsmith_get_widget |
GET /api/v1/pages/{id} (one widget) |
appsmith_update_widget |
PUT /api/v1/layouts/{layoutId}/pages/{pageId} |
appsmith_clone_widget |
PUT /api/v1/layouts/{layoutId}/pages/{pageId} |
appsmith_generate_crud_page |
POST /api/v1/pages/crud-page |
Write — structure and lifecycle
| Tool | Endpoint |
|---|---|
appsmith_create_workspace |
POST /api/v1/workspaces |
appsmith_create_application |
POST /api/v1/applications |
appsmith_create_page |
POST /api/v1/pages |
appsmith_execute_query |
POST /api/v1/actions/execute |
appsmith_publish_application |
POST /api/v1/applications/publish/{id} |
appsmith_clone_application |
POST /api/v1/applications/clone/{id} |
appsmith_delete_application |
DELETE /api/v1/applications/{id} — gated |
appsmith_api_request |
any route; non-GET gated |
Editing is deliberately typed rather than left to appsmith_api_request: the raw tool
is gated behind ALLOW_DESTRUCTIVE and cannot be safely auto-approved, since it can
reach any endpoint. The typed tools each do one thing, so they can be allow-listed
individually.
appsmith_update_query sends only the fields you pass — the server merges the rest,
so the datasource and untouched settings survive. It deliberately does not rename:
renaming needs a refactor pass that rewrites bindings across the app, and a plain
PUT would leave every reference broken.
Adding widgets
There is deliberately no "create widget from scratch" tool. Appsmith's widget defaults
live in its frontend, not its API — /api/v1/widgets, /widget-config and
/configs all 404 — and a real widget carries 24–65 properties depending on type. A
hand-written defaults catalogue would replicate frontend logic, drift on every Appsmith
upgrade, and fail silently when it did. The two supported routes instead:
appsmith_clone_widgetcopies a widget that Appsmith itself created, so the defaults are always correct and there is nothing to maintain. Every descendant gets a freshwidgetIdand a free name (Canvas1→Canvas2,interno→interno1); names only need to be unique per page. The copy is placed below its siblings so it cannot land on another widget. Bindings inside the copy are not rewritten — one that referenced the source by name still points at the original, so the response returnsrenamedInsideCopyfor the caller to fix.appsmith_generate_crud_pagecalls Appsmith's own generator for a whole screen.
Bindings
appsmith_update_widget maintains dynamicBindingPathList for you. Appsmith only
evaluates {{ }} on properties listed there and the server does not infer it: a
binding written without registration is stored verbatim and rendered as a literal
string — which, for a boolean like isDisabled, is always truthy. Setting a binding
adds the path; setting a literal removes it. A widget's other properties are preserved,
since the whole layout is read, patched and written back.
Safety
appsmith_delete_applicationand non-GETappsmith_api_requestcalls refuse to run unlessAPPSMITH_MCP_ALLOW_DESTRUCTIVE=true.appsmith_execute_queryruns against the real datasource — a write query writes. It is not gated, since running queries is the point, so check what a query does before running it.- Large payloads (page DSLs, exports) are truncated at
APPSMITH_MCP_MAX_CHARS.appsmith_get_pagereturns a widget outline by default; passfull=truefor the raw layout.appsmith_export_applicationtakes anoutputPathto write to disk instead of returning inline.
Instance quirks found while building this
Two behaviours differ from what the CE controllers suggest, both handled in the code:
GET /applications/homedocumentsworkspaceIdas optional, but this instance rejects the call without it.appsmith_list_applicationsfans out across every workspace when no id is given.POST /pagesrejects an emptylayoutsarray, andlayouts: [{}]silently creates a page whose DSL isnull— blank and unusable in the editor. The rootCANVAS_WIDGETcanvas must be sent explicitly; seesrc/defaults.js.
Maintenance
Routes were taken from the Appsmith backend controllers, not guessed:
controllers/ce/ApplicationControllerCE.javacontrollers/ce/PageControllerCE.javacontrollers/ce/ActionControllerCE.javacontrollers/ce/DatasourceControllerCE.javacontrollers/ce/WorkspaceControllerCE.javaconstants/ce/UrlCE.java
Appsmith's API is not a documented public contract, so a major upgrade can move a
route. npm run check is the fast way to find out.
License
MIT — see LICENSE.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
E2B
Using MCP to run code via e2b.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.