Acumatica MCP Server
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| ACUMATICA_COMPANY | Yes | The Acumatica company name. | |
| ACUMATICA_BASE_URL | Yes | The base URL of your Acumatica instance. | |
| ACUMATICA_PASSWORD | Yes | The service account password. | |
| ACUMATICA_USERNAME | Yes | The service account username. | |
| ACUMATICA_ALLOW_WRITES | No | Set to '1' to enable upsert_record and invoke_action tools. | 0 |
| ACUMATICA_ALLOW_DELETES | No | Set to '1' to enable delete_record tool. | 0 |
| ACUMATICA_ENDPOINT_PATH | Yes | The endpoint path to the contract-based REST API (e.g., /entity/Default/24.200.001). |
Capabilities
Features and capabilities supported by this server
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| 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. |
| 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:
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") |
| 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 |
| 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 |
| 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 |
| delete_recordA | Delete a record by ID or key fields. Requires ACUMATICA_ALLOW_DELETES=1. |
| 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. |
| get_schemaA | Return the entity's extension-field schema (GET /{Entity}/$adHocSchema). Two reasons to call this:
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") |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/yourlastnamesoundslikeatypeofpasta/acumatica-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server