Skip to main content
Glama
vvbv

PyerP MCP Server

by vvbv
README.md
# PyerP MCP Server

An [MCP](https://modelcontextprotocol.io/) (Model Context Protocol) server that exposes a [PyerP](https://github.com/your-org/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

```bash
# 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:

```bash
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)

```bash
python server.py
```

### SSE transport

```bash
python server.py --sse
```

### Streamable HTTP transport

```bash
python server.py --streamable-http
```

### With uv (no install needed)

```bash
uv run --with "mcp[cli]" --with httpx --with python-dotenv server.py
```

## Client Configuration Examples

### Claude Desktop

Add to `claude_desktop_config.json`:

```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:

```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"
      }
    }
  }
}
```

## 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.