Acumatica MCP Server
The Acumatica MCP Server lets you query and manage an Acumatica ERP system through any MCP-compatible client (e.g., Claude Desktop), exposing the full contract-based REST API via 8 generic tools.
Discover & Explore
list_entities— Browse all ~119 available Acumatica entities (SalesOrder, Bill, Customer, StockItem, etc.)describe_entity— Inspect field names, key formats, available actions, and expandable sub-collections for any entityget_schema— Find user-defined (DAC extension) fields and view names not in the standard contract
Read Data
list_records— Fetch records with OData filtering ($filter), field selection ($select), pagination ($top/$skip), expansion ($expand), sorting, and custom/extension fields via thecustom=parameterget_record— Retrieve a single record by its entity-specific key
Write Data (opt-in)
upsert_record— Create or update any entity (requiresACUMATICA_ALLOW_WRITES=1)delete_record— Remove a record by key (requiresACUMATICA_ALLOW_DELETES=1)invoke_action— Trigger entity-specific actions likeReleaseBill,CancelSalesOrder, orConfirmShipment(requiresACUMATICA_ALLOW_WRITES=1)
Additional Features
Safe by default — All write and delete operations are blocked unless explicitly enabled, making it safe for production exploration
Clickable results — Every returned record includes a
browser_urllinking directly to that record in the Acumatica web UIActionable error handling — Errors return helpful hints instead of raw HTTP 500s
Pre-built skills — Execute packaged workflows for AP/AR health checks, three-way match reconciliation, recent record lookups, and document diagnostics
Customizable entity catalog — Regenerate the entity catalog to include custom entities or extension fields specific to your tenant
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Acumatica MCP ServerShow me the latest 5 sales orders."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Acumatica MCP Server
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⡖⠿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣞⡻⠉⢀⠀⠈⠳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡏⠀⡂⣸⣦⠀⠀⠘⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⢻⠉⠻⠐⣭⡀⠀⠙⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⢡⠤⠜⠂⠀⠀⠈⠘⠀⠀⠀⠱⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣠⠞⠁⠙⢦⣀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠣⡀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⢸⡀⠀⠀⠀⠉⠳⣄⠀⠀⣹⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣼⣶⣶⢒⣛⡻⢥⡤⣀⠀⢮⡗⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⢰⣶⣿⣿⣿⣾⣧⣤⣬⣤⣀⣙⣿⣤⣽⡆⠂⠂⡀⠀⠀⠀⠀⣀⠀⠠⠐⠂⠈⡋⣟⣿⣇⣠⡀⡼⣏⣉⡉⠱⣿⣿⣶⣶⠒⠒⠒⠒⠒⠒⠒⠒⠢⠤⢄⡀
⠀⠀⠀⠀⠉⠉⢛⣿⢿⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠀⠀⠀⠄⠀⠀⠀⠀⠂⠂⠀⠉⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣿⣷⣶⣶⣶⣶⣶⣶⣾⣿⠿⠛⠁
⠀⠀⠀⠀⠀⠀⠈⠛⢻⣿⣿⣿⣿⡏⢁⣀⣀⣠⣤⣤⡤⠀⢀⠀⠀⢀⡀⣀⣠⣤⣿⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⠿⢿⠟⠛⠋⠉⠉⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿⡿⠿⠛⠛⠉⠀⠀⠒⢾⠤⠤⠤⠀⠚⠛⠉⢩⠙⠛⠛⠟⠿⣿⡿⢿⡿⣿⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣀⣿⣿⠟⢻⠁⠀⠀⢀⣀⣀⣀⣀⠤⠀⠀⠀⠀⠀⢀⣤⡤⠼⣴⣤⣤⣤⣤⣿⡿⠿⠛⠛⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠠⢶⣶⣶⣿⣦⣤⣠⣿⣿⣶⣾⣿⣶⣿⣿⠿⠿⠛⠁⠀⠀⠀⠀⠤⠤⠶⠿⢿⣿⣿⣿⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠉⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⠿⠿⠿⠿⠙⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣿⠟⢿⣿⣿⣿⣿⡿⢻⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣸⡇⠀⣿⣿⣿⣿⠟⠀⢸⠋⠀⠀⠀⠀⠠⣤⣀⣄⣴⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢀⡟⠀⢠⣿⣿⡟⠁⠀⠀⡸⠁⠀⠠⠀⠀⠁⠀⢉⣿⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣾⠀⠀⣼⡟⠁⠀⠀⠀⢠⡇⢀⢄⡞⠀⠀⡳⣴⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠈⠙⠚⠋⠀⠀⠀⠀⢀⣾⠇⠡⠈⠀⠀⢀⣾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠿⡆⠀⠀⢀⣴⠏⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⣷⣶⣾⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀A Model Context Protocol (MCP) server for Acumatica ERP. It lets an MCP client (Claude Desktop, or any MCP-aware agent) query and act on any Acumatica tenant's contract-based REST API through just 8 generic tools.
Acumatica's contract API is uniform: every entity (SalesOrder, Bill, Customer,
StockItem, and so on) supports the same GET / PUT / DELETE verbs with OData
query parameters, plus POST /{Entity}/{Action} for entity-specific actions.
Instead of hand-coding hundreds of endpoints, this server exposes 8 tools that
cover the entire surface (all ~119 entities in a standard tenant), plus a small
catalog that teaches the model each entity's fields, key format, and actions.
Status: Beta. Battle-tested.
Table of Contents
Related MCP server: MCP4Acumatica
Features
Small and legible. One server file, ~700 lines, three dependencies. You can read the whole thing before trusting it with your ERP.
Complete coverage. 8 generic tools reach all ~119 entities of any tenant's contract API, no per-entity code.
Read-only by default. Writes and deletes stay disabled until you explicitly opt in, so it is safe to point at production while you explore.
Portable. Works against any Acumatica instance with just a service account.
Clickable results. Records come back with a
browser_urlthat links straight to the record in the Acumatica web UI.Self-correcting queries. Errors return actionable hints (wrong field name, missing mandatory filter, permission gap) instead of raw HTTP 500s.
Repeatable workflows. Ships example skills - packaged, tested procedures (AP/AR health, three-way match, and more) that turn the raw tools into reliable, one-command operations. See Skills.
Architecture
flowchart LR
U[You] -->|natural language| C[Claude / MCP client]
C -->|MCP tool calls| S[acumatica-mcp-server]
S -->|"cookie-auth REST + OData"| A[(Acumatica ERP)]
A -->|JSON records| S
S -->|"results + browser_url"| C
C -->|answer| UThe server is a thin, stateless translator: MCP tool calls in, Acumatica REST
calls out. All entity knowledge (fields, keys, actions) lives in a data catalog
(entity_catalog.json), so the tools stay generic.
The 8 tools
Tool | HTTP | What it does |
| (local) | List the entities available in the tenant, filterable by substring. |
| (local) | Call this first. Returns an entity's fields, key format, actions, and expandable sub-collections. |
|
| Query records with OData ( |
|
| Fetch a single record by its key. |
|
| Create or update a record. Requires |
|
| Delete a record. Requires |
|
| Run an action (Release, Cancel, Confirm). Requires |
|
| Discover user-defined (DAC extension) fields and view names. |
See docs/USAGE.md for the field-name, key-format, $filter,
and $custom rules that make queries reliable.
How a query flows
The golden rule: call describe_entity first. Most failures come from
guessing field names or key formats.
flowchart TD
Q[Need data or an action] --> LE[list_entities: find the entity]
LE --> DE[describe_entity: fields, key format, actions]
DE --> RW{Read or write?}
RW -->|read| RD[list_records / get_record]
RW -->|write| G{Gate enabled?}
G -->|"ALLOW_WRITES / ALLOW_DELETES set"| WR[upsert_record / delete_record / invoke_action]
G -->|not set| BL[403 blocked: read-only by default]Skills (repeatable workflows)
The 8 tools give a model the raw verbs. Skills turn those verbs into
repeatable, tested workflows: the exact queries, fallbacks, and output format for a
real task, written down once so the model runs it the same correct way every time.
The skills/ folder ships a starter set you can use as-is or adapt:
Skill | What it does |
Reliably find the latest / most-recent record of any entity (works around tenants that ignore | |
Accounts-payable health check: aging buckets, overdue bills, stale POs, uninvoiced receipts. | |
Accounts-receivable health check: open AR, aging, unapplied payments, customer concentration. | |
Reconcile Bill vs Purchase Receipt vs PO line by line and flag price / quantity variances. | |
Diagnose why a document is stuck or wrong (receive failures, wrong totals, holds) and propose the fix. |
Each skill is a single SKILL.md with frontmatter, in the format used by Claude
Code / Claude Desktop skills. Drop the folder wherever your client discovers skills
(for example your project's .claude/skills/) and invoke it by name. All five are
read-only reporting workflows; none of them writes to your tenant.
Requirements
An Acumatica instance with the contract-based REST API enabled (the default
Defaultendpoint, for example version24.200.001).A dedicated service / integration account with the appropriate role(s).
Python 3.10+.
Installation
Clone the repository and install its dependencies:
git clone https://github.com/yourlastnamesoundslikeatypeofpasta/acumatica-mcp-server.git
cd acumatica-mcp-server
python -m venv .venv
# Windows: .venv\Scripts\activate
# macOS/Linux: source .venv/bin/activate
pip install -r requirements.txtConfiguration
The server reads its connection settings from environment variables. There are two ways to supply them, and you only need one (you never enter credentials twice):
Option A: the MCP client
envblock (recommended). Put the values in your MCP client config (see Register with Claude Desktop). Nothing is written to disk and no.envfile is needed.Option B: a
.envfile. Copy.env.exampleto.envnext toserver.pyand fill it in. Your MCP client config then only needs thecommand/args, not the credentials.
ACUMATICA_BASE_URL=https://your-instance.acumatica.com
ACUMATICA_ENDPOINT_PATH=/entity/Default/24.200.001
ACUMATICA_USERNAME=service_account
ACUMATICA_PASSWORD=your-password
ACUMATICA_COMPANY=YourCompanyIf you set both, the env block (process environment) wins and the .env file only
fills in anything it did not set.
Register with Claude Desktop
Add this to your claude_desktop_config.json (full example in
docs/claude-desktop-config.example.json).
This is Option A: credentials live in the env block. If you use a .env file
instead (Option B), drop the ACUMATICA_* credential keys from env:
{
"mcpServers": {
"acumatica": {
"command": "python",
"args": ["C:/path/to/acumatica-mcp-server/src/acumatica_mcp/server.py"],
"env": {
"ACUMATICA_BASE_URL": "https://your-instance.acumatica.com",
"ACUMATICA_ENDPOINT_PATH": "/entity/Default/24.200.001",
"ACUMATICA_USERNAME": "service_account",
"ACUMATICA_PASSWORD": "your-password",
"ACUMATICA_COMPANY": "YourCompany"
}
}
}
}Restart Claude Desktop, then try: "List the open sales orders modified in the last 14 days" or "Describe the Bill entity."
Authentication
Cookie-based. The server logs in on the first request, holds the session cookie, transparently re-logs in on a 401, and logs out on exit.
sequenceDiagram
participant S as acumatica-mcp-server
participant A as Acumatica
S->>A: POST /entity/auth/login (first request)
A-->>S: session cookie
S->>A: GET / PUT / POST /{Entity}
A-->>S: 200 + data
Note over S,A: on 401, re-login once and retry
S->>A: POST /entity/auth/logout (on exit)Write safety (read-only by default)
The three mutating tools are disabled by default. Enable them deliberately via environment variables:
Variable | Enables |
|
|
|
|
When a mutating tool is called while disabled, it returns a 403-style envelope
with a hint telling you which variable to set. No request is sent to Acumatica.
Regenerating the entity catalog
The bundled entity_catalog.json covers standard Acumatica entities. If your
tenant has customizations (custom entities, extension fields), regenerate it from
your tenant's OpenAPI spec:
In Acumatica, open your endpoint under Web Service Endpoints and export its OpenAPI (Swagger) JSON, or
GET {BASE_URL}{ENDPOINT_PATH}/swagger.json.Rebuild:
python src/acumatica_mcp/rebuild_catalog.py path/to/your_openapi_spec.jsonRestart the server (the catalog is loaded once at startup).
Security notes
Read-only by default.
upsert_recordandinvoke_actionrequireACUMATICA_ALLOW_WRITES=1;delete_recordrequiresACUMATICA_ALLOW_DELETES=1. Enable them only when you mean to, ideally on a sandbox tenant.Use a dedicated service account scoped to only the entities/roles you need, never a real person's login. A read-only role in Acumatica is a good second layer of defense.
.envis git-ignored. Keep credentials out of version control; prefer passing them through your MCP client'senvblock.
Prior art and related projects
This is not the first Acumatica-to-MCP or Acumatica-to-AI project. If this one does not fit your needs, look at these:
grp-mcp: a far more capable MCP server with full CRUD, four client planes, and headless ERP setup.
MCP4Acumatica: a remote MCP server (Cloudflare Workers) with per-user OAuth and role-based, read-only access.
easy-acumatica: a mature Python REST SDK (not MCP) with dynamic model generation.
CData Acumatica MCP Server: a read-only MCP backed by the CData JDBC driver.
This server's angle is deliberate minimalism: a small, dependency-light, self-hostable stdio server you can read top to bottom in one sitting, that works against any tenant with nothing but a service account.
License
MIT (c) Christian Zagazeta
Disclaimer
Not affiliated with or endorsed by Acumatica, Inc. "Acumatica" is a trademark of its respective owner. Use at your own risk against your own tenants.
Available Tools
8 toolsdelete_recordA
Delete a record by ID or key fields. Requires ACUMATICA_ALLOW_DELETES=1.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| entity | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Without annotations, the description must convey behavior. It implies destructive action (delete) and states a requirement. It lacks details on idempotency, return behavior, or permanence of deletion. Output schema exists but is not referenced.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences, front-loaded with the primary action, no extraneous words. Efficiently communicates core function and a usage requirement.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple tool (2 params) and existence of an output schema, the description is adequate but lacks parameter-specific context. It provides a usage requirement but not enough to fully inform an agent without schema descriptions.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so description must compensate. It mentions 'ID or key fields' but does not explain how 'key fields' relate to the schema parameters (id, entity). The 'entity' parameter is not clarified at all.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action (delete) and resource (record), and distinguishes it from siblings which are all non-deletion operations (describe, get, list, upsert, invoke). The mention of 'by ID or key fields' specifies the scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description includes a prerequisite (ACUMATICA_ALLOW_DELETES=1), giving clear context for use. However, it does not explicitly state when not to use this tool or mention alternatives, though no sibling directly competes.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_entityA
Return the full metadata for an entity: fields, key format, actions, and sub-collections.
Always call this before list_records or get_record when you are unsure of:
which field names are valid (use these in select= and filter= expressions)
how to format the id= argument for get_record / delete_record
which sub-collections can be passed to expand=
Args: entity: Entity name, e.g. "SalesOrder", "Bill", "Customer".
Returns one of two shapes:
Normal entity (has a key): { "entity": "SalesOrder", "fields": ["OrderType", "OrderNbr", "CustomerID", ...], # valid $select / $filter names "key_fields": ["OrderType", "OrderNbr"], # fields that make up the URL key "key_format": "Slash-separated: /", # how to build the id= string "actions": ["CancelSalesOrder", ...], "expand": ["Details", "Shipments", ...] }
Query-only entity (inquiry/summary view - no addressable key): { "entity": "AccountSummaryInquiry", "query_only": true, "note": "This entity has no addressable key - use list_records with filter= only. ...", "fields": [...], "actions": [], "expand": [] } For query-only entities: do NOT call get_record - pass at least one filter= to list_records. Calling list_records with no filter on these entities returns HTTP 500 on this tenant.
Returns {error: "Unknown entity"} if the entity is not in the catalog.
Examples: describe_entity("SalesOrder") # -> key_format: "Slash-separated: /" # -> use get_record("SalesOrder", "QT/I004264")
describe_entity("Bill")
# -> key_format: "Slash-separated: <Type>/<ReferenceNbr>"
# -> use get_record("Bill", "Bill/012979")
describe_entity("AccountSummaryInquiry")
# -> query_only: true
# -> use list_records("AccountSummaryInquiry", filter="Period eq '202506'")
| Name | Required | Description | Default |
|---|---|---|---|
| entity | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, but the description fully discloses behavior: two return shapes for normal vs query-only entities, error response for unknown entities, and concrete examples. It also notes that query-only entities have no addressable key.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is moderately long but well-structured: a one-line summary, usage instructions, Args section, and two return shapes with examples. It is front-loaded with the main purpose. Some redundancy could be trimmed, but overall clear.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (different handling for normal vs query-only entities) and the presence of an output schema, the description provides complete contextual information: when to use, what to expect, and edge cases. No gaps identified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter 'entity' has 0% schema coverage, but the description adds value by specifying it as the entity name with examples (e.g., 'SalesOrder'). While sufficient for a simple parameter, the examples are helpful but not exhaustive.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool returns full metadata for an entity including fields, key format, actions, and sub-collections. It distinguishes itself from siblings like list_entities by specifying the exact information provided.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly advises calling this tool before list_records or get_record when uncertain about field names, id format, or expand parameters. It also differentiates between normal and query-only entities, warns against calling get_record on query-only entities, and mentions HTTP 500 risks without filters.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_recordA
Get a single record by its key.
Call describe_entity(entity) first to find the key_fields and key_format for this entity - the key format varies per entity and using the wrong format causes a 500 error.
Args: entity: Entity name. id: The record key - key field values joined with '/' in key order. Examples: SalesOrder -> "QT/I004264" (OrderType/OrderNbr) Bill -> "Bill/001234" (Type/ReferenceNbr) Customer -> "C000001" (CustomerID only) Invoice -> "INV/001234" (Type/ReferenceNbr) Use describe_entity() to find the exact key_fields for any entity. A GUID (the session 'id' field) also works if you have it. select / expand / custom: same as list_records.
Returns:
{status, ok, data: {record}} or {status, ok: false, error}
Record includes a browser_url field (for entities with a known screen ID).
Render the record identifier as a Markdown hyperlink using browser_url:
050297
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| custom | No | ||
| entity | Yes | ||
| expand | No | ||
| select | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description covers all critical behaviors: warning about incorrect key format causing errors, return structure (status, ok, data/error), browser_url field and its rendering. It also mentions that a GUID works as an alternative key. Fully transparent for the tool's usage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is detailed but each sentence adds value. It is structured with a brief summary, then Args section, then Returns. The examples are valuable but could be slightly condensed. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the existence of an output schema (not shown but known), the description explains the return format comprehensively. It includes error handling, browser_url usage, and prerequisite dependency on describe_entity. Complete for a single-record retrieval tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The id parameter is richly explained with examples for different entities and alternative GUID usage. The select/expand/custom are referenced as same as list_records, providing cross-reference. However, entity parameter is not elaborated beyond its name, though it is a known concept from describe_entity. Compensates with practical examples.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states 'Get a single record by its key' and contrasts with list_records by indicating single record retrieval. It clearly distinguishes from sibling tools like delete_record and upsert_record.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It instructs to call describe_entity first to find key_fields and key_format, preventing 500 errors. It also notes that select/expand/custom parameters work similarly to list_records, providing cross-tool consistency. Lacks explicit when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_schemaA
Return the entity's extension-field schema (GET /{Entity}/$adHocSchema).
Two reasons to call this:
Discover user-defined extension fields (UsrXxx fields, attribute fields like AttributeCOLOR) that are NOT in the standard contract and not listed by describe_entity(). These appear nested under a view name in the response.
Discover the available VIEW NAMES for this entity's graph. View names are the first part of the 'ViewName.FieldName' string needed by the custom= parameter. Standard Acumatica DAC fields (e.g. CreatedByID, LastModifiedByID) that are absent from the contract can ALSO be pulled via custom= using these view names, even though they don't appear explicitly in this schema response.
Common SalesOrder view names (confirmed working): Document - SOOrder header fields (CreatedByID, BranchID, etc.) CurrentDocument - additional header computed fields Transactions - line-level fields (on Details rows) Adjustments - payment application fields
Example workflow: 1. get_schema("SalesOrder") # identify view names 2. list_records("SalesOrder", # pull extension + standard DAC fields custom="Document.CreatedByID,Document.UsrYourCustomField")
| Name | Required | Description | Default |
|---|---|---|---|
| entity | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully carries the behavioral transparency burden. It explains the response structure (nested under view names), mentions that standard DAC fields absent from the contract can still be pulled via custom=, and provides common view names. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with bullet points and an example, and is front-loaded with the purpose. It is slightly verbose but every part adds value. Could be slightly more concise, but still effective.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the existence of an output schema, the description does not need to explain return values. It is complete for the tool's purpose, covering what it returns, why to use it, and how to use the results with other tools like list_records.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter 'entity' has no schema description coverage, but the description adds meaning by giving usage context, examples (e.g., 'SalesOrder'), and explaining that it is the entity name. It adds value beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states that the tool returns the entity's extension-field schema, and distinguishes it from siblings like describe_entity and list_records by explaining it discovers user-defined fields and view names not in the standard contract.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly lists two reasons to call the tool and provides an example workflow. It also implicitly tells when not to use it (e.g., for standard contract fields, use describe_entity) and mentions alternatives like describe_entity().
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
invoke_actionA
Invoke a named action on an entity (POST /{Entity}/{Action}). Requires ACUMATICA_ALLOW_WRITES=1.
Examples: invoke_action("SalesOrder", "CancelSalesOrder", entity_record={"OrderType": {"value": "SO"}, "OrderNbr": {"value": "SO012345"}}) invoke_action("Bill", "ReleaseBill", entity_record={"ReferenceNbr": {"value": "001234"}})
Args: entity: Entity name. action: Action name (call describe_entity(entity) to see available actions). entity_record: The record the action runs against, in Acumatica's wrapped format. parameters: Action-specific parameters, if any.
Returns 204 No Content for fire-and-forget actions; 202 for long-running.
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | ||
| entity | Yes | ||
| parameters | No | ||
| entity_record | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations were provided. The description adds context by noting the required environment variable (ACUMATICA_ALLOW_WRITES=1) and explaining HTTP return codes (204 for fire-and-forget, 202 for long-running). However, it does not detail potential side effects, error handling, or reversibility.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise yet thorough: one sentence for purpose, code examples, then structured argument descriptions. No wasted words, and information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema (not shown) and the complexity of 4 parameters (2 required, 2 optional objects), the description covers purpose, parameters, environment requirement, and return values. It could mention error cases or idempotency but is largely complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description carries full burden. It explains each parameter: entity (entity name), action (use describe_entity to list), entity_record (wrapped format with example), parameters (action-specific). This adds substantial meaning beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Invoke a named action on an entity' and provides concrete examples (CancelSalesOrder, ReleaseBill), making the purpose unambiguous and distinct from sibling tools like upsert_record or delete_record.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when to use this tool (invoking actions), mentions using describe_entity to find available actions, and includes examples. It does not explicitly compare to siblings or state when not to use, but the guidance is clear enough for most cases.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_entitiesA
List the Acumatica entities exposed by this tenant's OpenAPI spec.
Args: filter: Optional case-insensitive substring to narrow the list, e.g. "order" returns SalesOrder, PurchaseOrder, etc.
Returns: {count, entities: [{name, actions}]}
Tip: call describe_entity(name) to get the full field list, key format, and expandable sub-collections for any entity before querying it.
| Name | Required | Description | Default |
|---|---|---|---|
| filter | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It discloses the return format and filter behavior, but does not mention performance, pagination, or authentication requirements. Adequate for a simple read operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise with clear sections (Args, Returns, Tip). Every sentence adds value without redundancy, making it easy to parse quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple list tool with one parameter and an existing output schema, the description fully covers purpose, parameter semantics, return structure, and a usage hint. It is complete for its complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description adds significant meaning beyond the schema: it explains the filter is optional, case-insensitive, and provides an example ('order' returns SalesOrder, etc.). This is essential since the schema has 0% description coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'List' and resource 'Acumatica entities' and specifies the context 'exposed by this tenant's OpenAPI spec'. It easily distinguishes from siblings like list_records and describe_entity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description includes a tip to call describe_entity for details, guiding usage after listing. However, it does not explicitly mention when not to use this tool or contrast with get_schema, so it's slightly less than perfect.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_recordsA
Retrieve records from an Acumatica entity using OData query parameters.
IMPORTANT: Call describe_entity(entity) first to get the exact field names for this entity. Using a field name that doesn't exist causes a hard 500 error.
Args: entity: Entity name, e.g. "SalesOrder", "Bill", "Customer". filter: OData $filter expression, e.g. "Status eq 'Open'". Only use field names returned by describe_entity() - guessed names cause KeyNotFoundException (500). Date/time fields require datetimeoffset literal format: Date gt datetimeoffset'2026-05-01T00:00:00-04:00' Plain strings or datetime'' literals will fail. top: Max rows to return. Defaults to 50; use a smaller number when exploring. skip: Rows to skip (pagination). select: Comma-separated fields, e.g. "OrderNbr,CustomerID,OrderTotal". Only use field names returned by describe_entity() - invalid names -> 500. expand: Comma-separated sub-collections to inline, e.g. "Details,Shipments". Valid values are listed in describe_entity() under 'expand'. orderby: e.g. "Date desc". NOTE: $orderby is silently ignored by this tenant. To get the most recent records, use a date filter instead and sort client-side. Use a narrow window first - expand only if empty: Step 1: filter="Date gt datetimeoffset'T00:00:00-04:00'" Step 2: if empty, retry with today-30d, then today-90d Client-side: sort results by Date desc, then LastModifiedDateTime desc to find the single most-recent record. This resolves "last created" queries in 1-2 API calls instead of 5+. custom: Pull user-defined (DAC extension) fields not in the standard contract. Format: "ViewName.FieldName" - multiple fields comma-separated. Example: "Document.LastModifiedByID,Document.CreatedByID" To discover available view names and fields, call get_schema(entity). Common view name for header-level fields: "Document".
Returns:
{status, ok, data: [records]} or {status, ok: false, error}
Each record includes a browser_url field (for entities with a known screen ID)
linking directly to that record in the Acumatica web UI.
ALWAYS render the primary identifier (ReferenceNbr, OrderNbr, etc.) as a
Markdown hyperlink using browser_url so the user can click through to audit:
050297
| Name | Required | Description | Default |
|---|---|---|---|
| top | No | ||
| skip | No | ||
| custom | No | ||
| entity | Yes | ||
| expand | No | ||
| filter | No | ||
| select | No | ||
| orderby | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully discloses behavioral traits: using non-existent fields causes 500, date/time format requirement, orderby silently ignored, workaround for last-created queries, and the return of browser_url. This is comprehensive and goes beyond basic read-only expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is lengthy but well-structured with sections: overview, important callout, args, returns. Every sentence adds value, though it could be slightly more concise without losing critical detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (8 parameters, OData syntax, error-prone behaviors, and pagination), the description is thorough. It covers prerequisites, edge cases, return format (including error structure and browser_url), and even provides a step-by-step workaround for a common query pattern. Output schema exists but the description adds value beyond it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It extensively documents each parameter: filter format with examples, top default and exploration tip, skip for pagination, select/expand based on describe_entity, orderby caveat with workaround, and custom fields format. This adds significant meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Retrieve records from an Acumatica entity using OData query parameters.' with a specific verb ('retrieve') and resource ('records from an entity'). Among siblings like get_record, delete_record, etc., it is distinct as the list operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly instructs 'Call describe_entity(entity) first to get the exact field names' and explains why (avoid 500 errors). It provides context for proper usage but does not explicitly mention when not to use this tool or compare with alternatives like get_record.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upsert_recordA
Create or update a record (PUT /{Entity}). Requires ACUMATICA_ALLOW_WRITES=1.
Acumatica's contract-based API uses PUT for both create and update - the server decides based on whether key fields match an existing record.
Args:
entity: Entity name.
data: Body in Acumatica's {"FieldName": {"value": ...}} shape.
Example:
{"OrderType": {"value": "SO"},
"CustomerID": {"value": "ABARTENDE"},
"Details": [{"InventoryID": {"value": "AALEGO500"}, "Quantity": {"value": 5}}]}
| Name | Required | Description | Default |
|---|---|---|---|
| data | Yes | ||
| entity | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses the mutation behavior, API pattern, and required environment variable, but omits error handling or idempotency details.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Extremely concise and well-structured: two paragraphs plus a bulleted args list with an example. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the essential context (prerequisite, API shape, example), but could briefly mention error handling or response format (though output schema may cover response).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Despite 0% schema coverage, the description provides clear parameter explanations and a detailed example for the 'data' parameter, which is critical given its nested object structure.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Create or update a record' and explains the PUT behavior, distinguishing it from read tools like get_record and list_records.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Specifies the prerequisite ACUMATICA_ALLOW_WRITES=1 and explains the create-vs-update logic, but does not explicitly contrast with siblings like delete_record.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
8 tool updates
v0.1.0- First observed
delete_record - First observed
describe_entity - First observed
get_record - First observed
get_schema - First observed
invoke_action - First observed
list_entities - First observed
list_records - First observed
upsert_record
TDQS
Scored across 8 tools
Each tool targets a distinct operation: listing entities, describing metadata, retrieving/listing/upserting/deleting records, invoking actions, and discovering extension fields. Although describe_entity and get_schema both return metadata, their roles are clearly separated (standard contract/keys vs. view names/extension fields).
All tool names follow a consistent verb_noun snake_case pattern (list_records, get_record, delete_record, upsert_record, invoke_action, describe_entity, get_schema, list_entities). There are no mixed conventions or vague verbs.
Eight tools form a tight, well-scoped set for an entity-oriented ERP API. Each tool has a clear role, and the count is within the ideal range without redundancy.
The server covers the full record lifecycle (list/get/create-update/delete), named business actions, entity catalog discovery, key/field metadata, and extension-field schema discovery. This leaves no obvious dead ends for interacting with Acumatica records.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
BETA — Run SuiteQL, read/write NetSuite records, query SuiteAnalytics, and run saved bookmarks.
Read and edit GA4, Search Console and Google Tag Manager from any MCP client. 29 tools.
Access Avalara AvaTax API for tax calculation, transactions, nexus management, and compliance
Related MCP Servers
- AlicenseAqualityAmaintenanceProvides unified interface for Qlik Sense Enterprise APIs through Model Context Protocol, offering 21 tools for managing applications, data, users, and analytics operations.1041MIT
- AlicenseNot gradedqualityAmaintenanceEnables Claude to interact with Acumatica ERP through a remote MCP server with per-user OAuth, role-based access, and 44 tools for querying and managing ERP data.17Apache 2.0
- FlicenseAqualityDmaintenanceEnables read-only analytics queries on Acumatica ERP data, including sales orders, inventory, shipments, invoices, purchase orders, customers, and OData generic inquiries.16-
- AlicenseNot gradedqualityCmaintenanceEnables Claude to securely interact with Acumatica ERP 2025 R2 via per-user OAuth, role-based access, and sensitive field redaction, providing 48 tools for data lookup, utility, and schema discovery.Apache 2.0