Skip to main content
Glama
Sheikh-Muhammad-Mujtaba

ERPNext MCP Server

README.md
# ERPNext MCP Server

A comprehensive **Model Context Protocol (MCP) server** for ERPNext that provides **generic, doctype-agnostic access** to any ERPNext document type with **robust permission controls**, **audit logging**, and **enterprise-grade security**.

## Architecture Overview

```mermaid
graph TB
    A[Claude/LLM Client] --> B[MCP Protocol]
    B --> C[ERPNext MCP Server]
    C --> D[Permission Manager]
    C --> E[ERPNext Client]
    E --> H[ERPNext API]
    D --> I[Audit Logger]

    subgraph "Permission System"
        D --> J[Doctype Permissions]
        D --> K[Field-Level Control]
        D --> L[Operation Validation]
        D --> M[Condition Checking]
    end

    subgraph "ERPNext Integration"
        E --> N[Generic CRUD]
        E --> O[Search & Filter]
        E --> P[Schema Discovery]
    end
```

### Core Components

- **Generic Client** — Works with any ERPNext doctype (Customer, Item, Sales Invoice, GL Entry, Client Script, etc.)
- **Permission System** — Multi-layer access control with field-level restrictions
- **Audit System** — Comprehensive logging of all operations
- **Performance** — Built-in caching and rate limiting
- **Discovery** — Dynamic tool generation based on configured doctypes

---

## Quick Start

### 1. Clone & Install

```bash
git clone https://github.com/Sheikh-Muhammad-Mujtaba/ErpNext-MCP.git
cd ErpNext-MCP/

# Create virtual environment
uv sync
source .venv/bin/activate        # Windows: .venv\Scripts\activate

# Install dependencies
uv pip install -r requirements.txt
```

### 2. Configure Environment

Create a `.env` file in the project root:

```bash
ERPNEXT_URL=https://your-erpnext-instance.com

# api key or username/password
ERPNEXT_API_KEY=your_api_key
ERPNEXT_API_SECRET=your_api_secret

ERPNEXT_USERNAME=username
ERPNEXT_PASSWORD=pass
```

### 3. Configure Permissions

Edit `config/config.json`:

```json
{
  "erpnext": {
    "timeout": 30
  },
  "permissions": {
    "doctypes": {
      "Customer": {
        "read": true,
        "create": true,
        "update": true,
        "delete": false,
        "allowed_fields": ["customer_name", "email_id", "mobile_no"],
        "conditions": {
          "create": {"customer_type": ["Company", "Individual"]}
        }
      }
    },
    "default": {
      "read": true,
      "create": true,
      "update": false,
      "delete": false
    }
  },
  "audit": {
    "enabled": true,
    "log_file": "logs/audit.log",
    "log_level": "INFO"
  },
  "rate_limiting": {
    "enabled": true,
    "requests_per_minute": 60,
    "requests_per_hour": 1000
  },
  "cache": {
    "enabled": true,
    "ttl": 300,
    "max_size": 1000
  }
}
```

### 4. Run the Server

```bash
python -m src.server
```

---

## Connect to Claude Code

### User-scoped (available across all projects)

```bash
claude mcp add erpnext -s user -- bash -c "cd '/path/to/ERP_Next-MCP' && .venv/bin/python -m src.server"
```

### Project-scoped (current directory only)

```bash
claude mcp add erpnext -- bash -c "cd '/path/to/ERP_Next-MCP' && .venv/bin/python -m src.server"
```

### Verify connection

```bash
claude mcp list
```

### Claude Desktop Integration

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "erpnext": {
      "command": "bash",
      "args": ["-c", "cd '/path/to/ERP_Next-MCP' && .venv/bin/python -m src.server"],
      "env": {
        "MCP_LOG_LEVEL": "INFO"
      }
    }
  }
}
```

---

## Available MCP Tools

### System Tools

| Tool | Description |
|------|-------------|
| `test_connection` | Test ERPNext server connectivity |
| `get_system_info` | Get ERPNext system information |
| `list_doctypes` | List all configured doctypes and permissions |
| `get_doctype_permissions` | Get detailed permissions for a specific doctype |
| `get_doctype_schema` | Get schema/metadata for any doctype |

### Generic Document Tools

| Tool | Description |
|------|-------------|
| `get_generic_document` | Get any document by doctype and name |
| `list_generic_documents` | List documents for any doctype with filters |
| `create_generic_document` | Create a document for any doctype |
| `update_generic_document` | Update a document for any doctype |

### Customer-Specific Tools

| Tool | Description |
|------|-------------|
| `list_customer_documents` | List customers with optional filters |
| `get_customer_document` | Get a specific customer by name |
| `search_customer_documents` | Search customers by text |
| `create_customer_document` | Create a new customer |
| `update_customer_document` | Update an existing customer |

> For each doctype configured in `config.json`, the server auto-generates:
> `list_`, `get_`, `search_`, `create_`, `update_`, and `delete_` tools.

---

## Known Limitations

- **`list_generic_documents` only returns `name` fields** — field filtering in the `fields` parameter is not applied by the list endpoint; use `get_generic_document` to retrieve full document details.
- The list endpoint is capped at **100 results** per call.
- Aggregated queries (SUM, COUNT, GROUP BY) are not supported — use ERPNext's built-in reports for financial summaries.

---

## Permission Model

### Multi-Layer Security

#### 1. Operation-Level
```json
{
  "Customer": {
    "read": true,
    "create": true,
    "update": true,
    "delete": false
  }
}
```

#### 2. Field-Level Access Control
```json
{
  "Customer": {
    "allowed_fields": ["customer_name", "email_id", "mobile_no"],
    "restricted_fields": ["creation", "modified", "owner", "credit_limit"]
  }
}
```

#### 3. Conditional Validation
```json
{
  "Customer": {
    "conditions": {
      "create": {
        "customer_type": ["Company", "Individual"]
      },
      "update": {
        "status": {"not_in": ["Disabled", "Blocked"]}
      }
    }
  }
}
```

#### 4. Audit Logging
```json
{
  "audit": {
    "enabled": true,
    "log_file": "logs/audit.log",
    "log_level": "INFO"
  }
}
```

### Example Configurations

#### Read-only analyst
```json
{
  "permissions": {
    "doctypes": {
      "Customer": {
        "read": true, "create": false, "update": false, "delete": false,
        "allowed_fields": ["name", "customer_name", "territory", "customer_group"]
      },
      "Sales Invoice": {
        "read": true, "create": false, "update": false, "delete": false,
        "allowed_fields": ["name", "customer", "grand_total", "status", "posting_date"]
      }
    }
  }
}
```

#### Sales user
```json
{
  "permissions": {
    "doctypes": {
      "Customer": {
        "read": true, "create": true, "update": true, "delete": false,
        "allowed_fields": ["customer_name", "customer_type", "email_id", "mobile_no", "territory"],
        "conditions": {
          "create": {"customer_type": ["Company", "Individual"]},
          "update": {"status": {"not_in": ["Disabled"]}}
        }
      }
    }
  }
}
```

---

## Example Prompts

### Fetch a document
```
Get the Client Script document named "Sales Invoice"
```

### List documents
```
List all Client Script documents
```

### Financial queries
```
Get GL Entry ACC-GLE-2025-113787
```

### Search
```
Search customer documents for "National"
```

### Cross-doctype analysis
```
Get the Sales Invoice ACC-SINV-2025-06622 and show me the items and COGS
```

---

## Security

### Authentication
- Uses ERPNext API Key/Secret — no passwords stored
- Credentials loaded from `.env` file (never commit this file)
- Supports ERPNext user-level role permissions

### Generate API Keys in ERPNext
1. Go to **Settings > Integrations > API Access**
2. Click **Generate Keys**
3. Assign the API user appropriate roles (e.g., "Accounts User", "Sales Manager")
4. Copy the key and secret into your `.env` file

### Network
- HTTPS-only connections to ERPNext
- Configurable request timeouts
- Rate limiting: 60 req/min, 1000 req/hour (configurable)

### Audit Trail

All operations are logged with timestamp, operation type, doctype, and result:

```
2025-08-29 11:18:35 - INFO - Operation: READ | DocType: Sales Invoice | Result: ALLOWED | Document: ACC-SINV-2025-06622
2025-08-29 11:18:35 - WARNING - Operation: DELETE | DocType: Customer | Result: DENIED | Reason: Delete not permitted
```

---

## Testing

```bash
python test.py
```

---

## Project Structure

```
ERP_Next-MCP/
├── src/
│   ├── server.py          # MCP server entry point
│   ├── erpnext_client.py  # ERPNext API client
│   └── permissions.py     # Permission manager
├── config/
│   ├── config.json        # Main configuration
│   ├── multi_doctype_config.json
│   └── restricted_config.json
├── logs/
│   └── audit.log
├── .env                   # API credentials (not committed)
├── .env.example           # Example env file
├── requirements.txt
└── test.py
```