If you run a wholesale distribution company on Epicor Eclipse, you already know the system inside and out. You know where the inventory screens live, which reports your ops team runs every morning, and how to pull a customer's pricing contract from four menus deep. Your people know too — and they spend hours every day doing exactly that.
What you might not have considered is how much that knowledge costs you in aggregate. Every time a sales rep manually looks up stock across six branches, every time a buyer calls the warehouse to check an inbound PO, every time a manager needs a customer's order history before a call — that's a human using trained expertise to perform a lookup that a well-configured AI agent should be able to do in seconds.
We built mcp-server-eclipse to close that gap. Here's the full story.
// 01 The gap nobody talks about
Epicor Eclipse is the dominant ERP for plumbing, HVAC, and electrical wholesale distribution. More than 700 companies run it. More than 64,000 users log in every day. It handles everything from purchase orders and inventory management to customer pricing contracts, AR aging, and branch transfers.
But here's what nobody says out loud: Eclipse has zero AI agent tooling. Not one production-ready connector for any large language model. Not a single integration in the Anthropic or OpenAI ecosystems. A system that is central to billions of dollars in daily distribution activity cannot be queried by an AI agent.
The result is predictable. Distributors make thousands of decisions a day — where is this item in stock? what price does this customer get? which vendor PO is late? — and every one of those decisions starts with a human manually navigating a screen. Your most experienced people spend a significant portion of their day as human query engines for a database that could answer those questions automatically.
This is not a criticism of Eclipse. It's a market gap that nobody has prioritized. Until now.
// 02 What MCP is and why it matters for ERP
Model Context Protocol (MCP) is an open standard developed by Anthropic that defines how AI models like Claude connect to external data sources and tools. Think of it as a universal adapter layer between an LLM and any system that exposes data — whether that's a database, a REST API, a file system, or an ERP.
Before MCP, connecting Claude to your ERP meant building a custom integration: a bespoke API wrapper, a prompt engineering layer, a deployment pipeline. You'd do it once for one use case and then rebuild it from scratch for the next one.
MCP changes the model. You build one server that exposes your data as a set of named tools. Claude discovers those tools and calls them as needed during a conversation. The LLM figures out which tool to call, what parameters to pass, and how to synthesize the result — you just have to expose the data correctly.
For ERP specifically, this is significant. Instead of building "an AI that answers inventory questions," you build a connector that exposes inventory data. Claude handles the natural language understanding, the multi-step reasoning, and the answer synthesis. You get the benefit of a senior employee who knows where to look in your system — without hard-coding every possible question.
// 03 How the connector works
mcp-server-eclipse is a Python MCP server that wraps the Eclipse REST API. When Claude needs ERP data, it calls one of the registered tools. The server authenticates with your Eclipse instance, makes the API call, and returns the result.
Here is the core authentication flow:
async def authenticate(self) -> None:
"""Obtain a session token from the Eclipse REST API."""
response = await self.http_client.post(
f"{self.base_url}/auth/login",
json={
"username": self.username,
"password": self.password,
"companyId": self.company_id,
},
)
response.raise_for_status()
self.session_token = response.json()["token"]
self.token_expires_at = time.time() + response.json()["expiresIn"]
Authentication is handled automatically before every request. If the token has expired, the client re-authenticates transparently — the tool calling layer never has to think about session management.
Here is an example tool registration — the search_inventory tool:
@mcp.tool()
async def search_inventory(
product_id: str | None = None,
branch_id: str | None = None,
include_all_branches: bool = False,
) -> str:
"""
Search inventory levels in Eclipse. Can filter by product,
branch, or both. Set include_all_branches=True to see stock
across every location.
"""
client = get_eclipse_client()
data = await client.search_inventory(
product_id=product_id,
branch_id=branch_id,
include_all_branches=include_all_branches,
)
return json.dumps(data, indent=2)
The tool's docstring is load-bearing: Claude reads it to understand when and how to call the tool. Clear parameter descriptions mean Claude selects the right arguments without guessing. The full server registers seven tools at launch: inventory search, product lookup, sales order retrieval, customer info, purchase orders, pricing matrix, and branch inventory. AP/AR and receiving tools are in active development.
// 04 Demo walkthrough
The repo ships with a mock Eclipse API server that returns realistic sample data — products, customers, orders, pricing — so you can see exactly what Claude does without a live Eclipse instance.
Start the mock server:
git clone https://github.com/rshift-ai/eclipse-claude-connector.git
cd eclipse-claude-connector
pip install -e ".[mock]"
python mock_eclipse_api.py
# Mock API running at http://localhost:8080
Point the MCP server at it and open Claude Desktop. Now try:
"What's our current inventory of PVC fittings across all branches?"
Claude calls search_products with query="PVC fittings" to find matching SKUs, then calls get_branch_inventory with include_all_branches=True for each result, aggregates quantities by branch, and returns a structured summary: which branches have stock, units on hand vs available, and which locations are at zero. A query that would normally require a manager to run a report and export to Excel — done in four seconds.
"What's the contract price for customer C001 on SKU PIPE-CU-075?"
Claude calls get_pricing with both parameters and returns the customer's specific contract price alongside list price — so the sales rep immediately knows the margin they're working with.
These are not cherry-picked edge cases. They are the actual daily questions that distribution ops teams answer manually, dozens of times a day.
// 05 What we're building next
We are currently in conversations with a Pacific Northwest wholesale distributor for a production pilot. That engagement will drive the next round of endpoint coverage: accounts payable invoice lookup, AR aging, inter-branch transfer orders, and PO receiving and discrepancy tracking.
Claude Code integration for ops teams. Operations leads can use Claude Code from the terminal to run complex multi-step queries — compare inventory positions across branches, pull AR aging for a customer segment, or draft a reorder recommendation based on current stock and open POs.
Webhook support for real-time alerts. The current architecture is pull-based. We are designing a webhook layer that will let Eclipse events — a PO past due, a stock level below threshold, an order that hasn't shipped — proactively trigger Claude agents that investigate and summarize the situation before a human even knows to look.