PyerP MCP Server
An MCP (Model Context Protocol) server that exposes a PyerP ERP system to LLM agents. The server translates MCP tool calls into HTTP requests against the PyerP REST API, giving any MCP-compatible client (Claude Desktop, OpenCode, Cursor, etc.) the ability to search, read, create and update ERP records through natural language.
Architecture
┌──────────────┐ MCP (stdio/SSE/HTTP) ┌────────────────┐
│ LLM Client │ ◄──────────────────────────────► │ PyerP MCP │
│ (Claude, │ │ Server │
│ Cursor…) │ │ (server.py) │
└──────────────┘ └───────┬────────┘
│ httpx
▼
┌────────────────┐
│ PyerP REST │
│ API (Flask) │
└────────────────┘
The server itself is stateless. It authenticates to PyerP via api_key query parameter, exactly as the native web client does.
Requirements
- Python 3.10+
- A running PyerP instance with API access
- A valid PyerP API key
Installation
# Clone the repository
git clone <repo-url> PyerP-MCP
cd PyerP-MCP
# Install dependencies (pick one)
pip install -e . # pip
# or
uv pip install -e . # uv
Configuration
Copy the example environment file and fill in your values:
cp .env.example .env
| Variable | Default | Description |
|---|---|---|
PYERP_BASE_URL | http://localhost:5000 | Base URL of your PyerP instance (no trailing slash) |
PYERP_API_KEY | (empty) | API key for authentication. Required. |
PYERP_DEFAULT_MODULE | admin | Default module used when module is omitted in tool calls |
PYERP_REQUEST_TIMEOUT | 30 | HTTP request timeout in seconds |
Running the Server
stdio (default, for Claude Desktop / OpenCode / Cursor)
python server.py
SSE transport
python server.py --sse
Streamable HTTP transport
python server.py --streamable-http
With uv (no install needed)
uv run --with "mcp[cli]" --with httpx --with python-dotenv server.py
Client Configuration Examples
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"pyerp": {
"command": "python",
"args": ["/absolute/path/to/PyerP-MCP/server.py"],
"env": {
"PYERP_BASE_URL": "http://localhost:5000",
"PYERP_API_KEY": "your_api_key_here"
}
}
}
}
OpenCode
Add to your OpenCode MCP configuration:
{
"mcpServers": {
"pyerp": {
"command": "python",
"args": ["/absolute/path/to/PyerP-MCP/server.py"],
"env": {
"PYERP_BASE_URL": "http://localhost:5000",
"PYERP_API_KEY": "your_api_key_here"
}
}
}
}
Available Tools
Search
| Tool | Description |
|---|---|
search | Search records with AND logic. Multiple param/value pairs must all match. |
search_or | Search records with OR logic. Any param/value pair can match. |
Both tools accept: search_param, search_value, module, model, search_order_by, search_order, solve_references, page, page_size.
Search parameter behavior:
- Multiple params with matching values (e.g.
"name,email"+"John,john@test.com") applies AND/OR between each pair. - One param with multiple values (e.g.
"status"+"active,pending") matches any value for that column (OR/IN). - Use
"null"as a value to match NULL fields. - The
g_prefix on column names is added automatically; you do not need to include it.
Retrieve
| Tool | Description |
|---|---|
get_record | Get a single record by entity_id or entity_uuid. |
get_record_with_references | Same as above but with foreign key references resolved to human-readable values. |
get_all_records | Paginated list of all records (newest first). Max 1000 per page. |
get_all_records_with_references | Paginated list with FK references resolved. Max 10 per page. |
get_detail | Full detail view: inline fields with labels, reference dropdowns, and related sub-lists. |
Create & Update
| Tool | Description |
|---|---|
create_record | Create a new record. Pass field values as a data dictionary. |
update_record | Update an existing record by entity_uuid. Only include changed fields. |
Metadata
| Tool | Description |
|---|---|
check_api_status | Health check on a PyerP API module. |
Available Resources
The server exposes two static MCP resources that LLM clients can read for context:
| URI | Description |
|---|---|
pyerp://info/field-conventions | Column prefix conventions (g_, ref_, enc_, etc.) and system column documentation. |
pyerp://info/api-guide | Quick reference with current configuration, available modules/models, and workflow examples. |
PyerP Concepts
Modules
A PyerP instance is organized into modules. Each module exposes its own API under /api_{module}/. The main module is admin, which manages most data models.
| Module | Description |
|---|---|
admin | Users, roles, permissions, clients, products, providers, warehouse, inventory, etc. |
contacts | Contact management |
media | File/media management |
templates | Template management |
messenger | Email & SMS messaging |
communications | Communications management |
reports | Reporting |
Additional modules may be dynamically loaded depending on the PyerP instance configuration.
Models (Tables)
Within the admin module, common models include:
users, roles, permissions, clients, products, providers, warehouse, inventory, inventory_movements, remissions, price_rate, patients, diagnoses, health_providers, media
Field Naming Conventions
| Prefix | Meaning | Example |
|---|---|---|
g_ | General/regular field | g_name, g_email, g_status |
ref_ | Foreign key reference | ref_roles (references roles table) |
uref_ | Unique foreign key (1-to-1) | uref_profile |
enc_ | Encrypted field | enc_password |
bol_ | Boolean | bol_active |
int_ | Integer | int_quantity |
dec_ | Decimal | dec_price |
json_ | JSON data | json_metadata |
dt_ | Date/time | dt_scheduled |
System columns (entity_id, entity_uuid, created_at, updated_at, deleted, deleted_at) are auto-managed. Do not include them in create/update calls.
Soft Delete
PyerP uses soft deletes. All records have a deleted column (0 = active, 1 = deleted). All queries automatically filter WHERE deleted = 0.
Usage Examples
"Show me the first 20 users"
→ get_all_records(module="admin", model="users", page_size=20)
"Search for a client named ACME"
→ search(search_param="name", search_value="ACME", module="admin", model="clients")
"Find products that are active or pending"
→ search_or(search_param="status", search_value="active,pending", module="admin", model="products")
"Show me the full details of user with entity_id 5"
→ get_detail(entity_id=5, module="admin", model="users")
"Create a new provider"
→ create_record(data={"g_name": "New Provider", "g_email": "info@provider.com"}, module="admin", model="providers")
"Update client 789456123 phone number"
→ update_record(entity_uuid="789456123", data={"g_phone": "5559876543"}, module="admin", model="clients")
Project Structure
PyerP-MCP/
├── server.py # MCP server (tools, resources, helpers)
├── pyproject.toml # Project metadata and dependencies
├── .env.example # Configuration template
├── README.md # This file
└── agents.md # LLM agent prompt guide
License
See the PyerP main repository for license information.