Skip to main content
Glama

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:

  1. A GET /api/v1/users/me seeds an XSRF-TOKEN cookie.

  2. POST /api/v1/login sends username/password form-encoded, echoing that token in the X-XSRF-TOKEN header.

  3. The response sets a SESSION cookie 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.

Related MCP server: hamravesh-mcp

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_widget copies a widget that Appsmith itself created, so the defaults are always correct and there is nothing to maintain. Every descendant gets a fresh widgetId and 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 returns renamedInsideCopy for the caller to fix.

  • appsmith_generate_crud_page calls 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_application and non-GET appsmith_api_request calls refuse to run unless APPSMITH_MCP_ALLOW_DESTRUCTIVE=true.

  • appsmith_execute_query runs 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_page returns a widget outline by default; pass full=true for the raw layout. appsmith_export_application takes an outputPath to 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/home documents workspaceId as optional, but this instance rejects the call without it. appsmith_list_applications fans out across every workspace when no id is given.

  • POST /pages rejects an empty layouts array, and layouts: [{}] silently creates a page whose DSL is null — blank and unusable in the editor. The root CANVAS_WIDGET canvas must be sent explicitly; see src/defaults.js.

Maintenance

Routes were taken from the Appsmith backend controllers, not guessed:

  • controllers/ce/ApplicationControllerCE.java

  • controllers/ce/PageControllerCE.java

  • controllers/ce/ActionControllerCE.java

  • controllers/ce/DatasourceControllerCE.java

  • controllers/ce/WorkspaceControllerCE.java

  • constants/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.

Available Tools

30 tools
appsmith_api_requestRaw Appsmith API callA

Calls any Appsmith REST endpoint directly, for things the typed tools do not cover. GET is always allowed; other methods require APPSMITH_MCP_ALLOW_DESTRUCTIVE=true.

Inputs: path (required), method (required), body, query.

appsmith_clone_applicationClone an applicationA

Clones an application within its workspace. Useful as a backup before risky edits.

Inputs: applicationId (required).

appsmith_clone_widgetClone a widgetA

Copies an existing widget (and everything inside it) into the same page under a new name, then applies any property overrides. This is how to add a widget: Appsmith's widget defaults live in its frontend, not its API, so copying a real widget of the wanted type is what produces a valid one. The copy lands below its siblings. Bindings inside the copy are carried over as-is, so any that named the source widget still point at the original — the response lists what was renamed so they can be fixed.

Inputs: pageId (required), newWidgetName (required), sourceWidgetName (required), properties.

appsmith_create_applicationCreate an applicationB

Creates an application inside a workspace.

Inputs: name (required), workspaceId (required).

appsmith_create_js_objectCreate a JS objectA

Creates a JS object from its source. The exported functions are parsed out of the body — Appsmith stores each one separately, and the source alone would produce an object with no callable functions.

Inputs: body (required), name (required), pageId (required), applicationId (required).

appsmith_create_pageCreate a pageB

Creates a page in an application, with the same empty root canvas the editor creates.

Inputs: name (required), applicationId (required).

appsmith_create_queryCreate a queryB

Creates a query on a page against an existing datasource. The plugin and workspace are taken from the datasource.

Inputs: body (required), name (required), pageId (required), datasourceId (required).

appsmith_create_workspaceCreate a workspaceC

Creates a new Appsmith workspace.

Inputs: name (required).

appsmith_delete_applicationDelete an applicationA

Permanently deletes an application. Disabled unless APPSMITH_MCP_ALLOW_DESTRUCTIVE=true is set in the server env.

Inputs: applicationId (required).

appsmith_delete_js_objectDelete a JS objectA

Deletes a JS object and all its functions. Check for references first — nothing rewrites bindings that point at it. Disabled unless APPSMITH_MCP_ALLOW_DESTRUCTIVE=true is set in the server env.

Inputs: collectionId (required).

appsmith_delete_queryDelete a queryA

Deletes a query or API action. Disabled unless APPSMITH_MCP_ALLOW_DESTRUCTIVE=true is set in the server env.

Inputs: actionId (required).

appsmith_execute_queryRun a queryB

Executes an existing query/API by its action id and returns the result. This runs against the real datasource — a write query will write.

Inputs: actionId (required), viewMode.

appsmith_export_applicationExport an applicationA

Exports an application as JSON. Writes to outputPath when given (recommended — exports are large); otherwise returns the JSON inline, truncated.

Inputs: applicationId (required), outputPath.

appsmith_generate_crud_pageGenerate a CRUD page from a tableA

Runs Appsmith's own page generator: builds a page with a table, a form and the wired-up queries from one datasource table. This is the supported way to create a complete, detailed screen — the layout comes from Appsmith rather than being assembled by hand.

Inputs: tableName (required), datasourceId (required), applicationId (required), columns, +1 more.

appsmith_get_datasource_structureGet datasource schemaB

Returns the introspected schema (tables, columns, keys) of a datasource.

Inputs: datasourceId (required), refresh.

appsmith_get_pageGet a pageA

Returns a page. By default returns a widget outline (name, type, id) which is compact; set full=true for the raw layout DSL, which can be very large.

Inputs: pageId (required), full.

appsmith_get_widgetGet a widget's propertiesA

Returns one widget's properties from a page, without dumping the whole layout. Use this to see current values before editing.

Inputs: pageId (required), widgetName (required).

appsmith_list_applicationsList applicationsA

Lists Appsmith applications, optionally filtered to one workspace. Returns app ids needed by the other tools.

Inputs: workspaceId.

appsmith_list_datasourcesList datasourcesC

Lists datasources in a workspace, with the plugin each one uses.

Inputs: workspaceId (required).

appsmith_list_js_objectsList JS objectsB

Lists the JS objects (action collections) of an application and their function names.

Inputs: applicationId (required), includeBody.

appsmith_list_pagesList pages of an applicationC

Lists the pages of an application, with page ids and which page is the default.

Inputs: applicationId (required).

appsmith_list_pluginsList pluginsA

Lists available Appsmith plugins (Postgres, REST API, MongoDB, ...) and their ids.

Inputs: workspaceId.

appsmith_list_queriesList queries / APIsB

Lists the non-JS actions (database queries and API calls) of an application, including their datasource and current body.

Inputs: applicationId (required), includeBody.

appsmith_list_workspacesList workspacesA

Lists the workspaces the authenticated user can access, with their ids.

Inputs: no named parameters.

appsmith_publish_applicationPublish an applicationA

Deploys the current edit-mode state of an application, making it live for viewers.

Inputs: applicationId (required).

appsmith_search_entitiesSearch entitiesB

Searches applications and workspaces by keyword.

Inputs: keyword (required), entities.

appsmith_update_js_objectUpdate a JS objectA

Replaces a JS object's source. Functions are parsed from the new body and diffed against the current ones, so added, changed and removed functions are all applied — a plain body write would leave deleted functions behind.

Inputs: body (required), collectionId (required), applicationId (required).

appsmith_update_queryUpdate a query / APIA

Edits an existing query or API action. Only the fields you pass are changed — the server merges the rest, so the datasource and untouched settings are preserved. Does not rename: renaming needs a refactor that rewrites bindings across the app.

Inputs: actionId (required), body, path, headers, +2 more.

appsmith_update_widgetUpdate widget propertiesA

Sets properties on a widget, e.g. {"isDisabled": "{{ appsmith.store.modo === "edicion" }}"}. Binding registration is handled automatically: a value containing {{ }} is added to the widget's dynamicBindingPathList, and a literal value is removed from it. Property names may be dot paths for nested config. Other widgets on the page are left untouched.

Inputs: pageId (required), properties (required), widgetName (required).

appsmith_whoamiCurrent Appsmith userA

Returns the authenticated Appsmith user and instance info. Use this first to confirm the MCP server can reach and log into the instance.

Inputs: no named parameters.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.4/5.0

    Scored across 30 tools

    Disambiguation4/5

    Most tools target clearly distinct resources and actions (workspaces, applications, pages, queries, JS objects, widgets, datasources). A few overlaps exist: appsmith_list_applications vs appsmith_search_entities both find apps, and get_widget/update_widget/clone_widget vs get_page are adjacent, but descriptions clarify each tool's distinct purpose well.

    Naming Consistency4/5

    Tools largely follow the appsmith_verb_noun pattern consistently (list_, create_, update_, delete_, get_, clone_, execute_, export_). Minor deviations like appsmith_whoami (noun-style) and appsmith_api_request (generic verb) break the pattern slightly, but the overall convention is coherent and predictable.

    Tool Count3/5

    At 30 tools, this is on the heavy side for an MCP server, exceeding the typical 3-15 well-scoped range. However, Appsmith is a broad platform covering workspaces, apps, pages, queries, JS objects, widgets, and datasources, so each tool reasonably earns its place across the resource categories.

    Completeness4/5

    The surface covers CRUD across most resource types: workspaces (create/list), applications (create/list/clone/delete/export/publish), pages (create/get/list), queries (create/update/delete/execute), JS objects (create/update/delete), widgets (get/update/clone). Minor gaps include no delete_page or delete_datasource, and the generic appsmith_api_request fallback covers edge cases.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      MCP server for interacting with QUADS infrastructure systems via API, enabling resource management and automation through LLM applications.
      MIT
    • A
      license
      C
      quality
      B
      maintenance
      MCP server to manage Hamravesh (Darkube) apps via the console's internal API, supporting read and write operations like listing apps, viewing logs, restarting, scaling, and updating environment variables.
      30
      2
      MIT
    • F
      license
      A
      quality
      B
      maintenance
      MCP server for the Gripp API, enabling CRUD operations on Gripp entities with built-in confirmation safety for mutations.
      9
      11 npm
      1
      -