mcp-epicor
# Epicor MCP
Production [FastMCP](https://gofastmcp.com) server for **Epicor Kinetic**. **Read-only.** There are no write tools and the HTTP client rejects any method other than `GET`.
Auth follows the same split used by Azure MCP and Atlassian Rovo:
1. **Inbound** — the MCP client authenticates to this server (HTTP only).
2. **Outbound** — this server authenticates to Kinetic (`X-API-Key` plus Basic or Bearer).
HTTP is fail-closed without `MCP_JWKS_URI` or `MCP_JWT_SECRET`.
Author: **Clinton Follette**.
## Tools
| Tool | Access | Notes |
|---|---|---|
| `get_sales_order` | read | Header, `OrderDtls`, and `OrderRels`. Short-ship = `OurReqQty` vs shipped qty. |
| `get_customer` | read | By `CustNum` or `CustID`. |
| `get_part` | read | By `PartNum`. |
| `get_shipments` | read | `CustShipSvc/ShipDtls` pack lines. Never writes a pack. |
`$select` is always applied. The Kinetic Company id is configuration, not a tool argument.
## Install (local STDIO)
```json
{
"mcpServers": {
"epicor": {
"command": "mcp-epicor",
"env": {
"EPICOR_BASE_URL": "https://your-server/kinetic",
"EPICOR_COMPANY": "YOURCO",
"EPICOR_API_KEY": "<key>",
"EPICOR_USERNAME": "<user>",
"EPICOR_PASSWORD": "<password>"
}
}
}
}
```
```bash
pip install .
mcp-epicor
```
## Remote HTTP
```bash
export MCP_TRANSPORT=http
export MCP_HOST=127.0.0.1
export MCP_PORT=8002
export MCP_JWKS_URI=https://login.example.com/.well-known/jwks.json
export MCP_JWT_ISSUER=https://login.example.com
export MCP_JWT_AUDIENCE=mcp-epicor
mcp-epicor
```
Endpoint: `http://127.0.0.1:8002/mcp`. Health: `GET /health`.
## Outbound Kinetic configuration
| Variable | Required | Purpose |
|---|---|---|
| `EPICOR_BASE_URL` | yes | Kinetic origin |
| `EPICOR_COMPANY` | yes | Path segment in `/api/v2/odata/{Company}/...` |
| `EPICOR_API_KEY` | typical | `X-API-Key` |
| `EPICOR_USERNAME` / `EPICOR_PASSWORD` | or bearer | Basic auth |
| `EPICOR_BEARER_TOKEN` | optional | Alternative to Basic |
## Security
- No POST/PATCH/DELETE helpers exist on the client.
- HTTP without inbound JWT configuration refuses to boot.
- Vendor 401s do not echo credentials.
See [SECURITY.md](SECURITY.md).
## License
MIT. Copyright (c) 2026 Clinton Follette.
TDQS
Scored across 4 tools
Each tool targets a distinct entity (sales order, customer, part, shipments), and descriptions clarify their purposes. get_shipments could be confused with get_sales_order since it retrieves order-related data, but the description explicitly distinguishes it as shipment pack lines.
All tools follow a consistent get_ + noun snake_case pattern, making them predictable and easy to distinguish.
Four tools is borderline thin for an ERP integration like Epicor Kinetic. While each tool is well-scoped, the set covers only a small fraction of typical ERP operations, suggesting under-scoping.
The surface is read-only with no create, update, delete, or list operations for any entity. This creates significant gaps for an agent that needs to perform common ERP tasks beyond fetching individual records.