@humanagencyp/erp-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +29 -0
- package/.github/workflows/publish.yml +51 -0
- package/README.md +148 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +787 -0
- package/package.json +51 -0
- package/src/db.ts +248 -0
- package/src/index.ts +302 -0
- package/src/money.ts +43 -0
- package/src/tools/customers.ts +50 -0
- package/src/tools/items.ts +36 -0
- package/src/tools/orders.ts +123 -0
- package/src/tools/quotes.ts +227 -0
- package/test/erp.test.ts +518 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout
|
|
14
|
+
uses: actions/checkout@v6
|
|
15
|
+
|
|
16
|
+
- name: Setup Node
|
|
17
|
+
uses: actions/setup-node@v6
|
|
18
|
+
with:
|
|
19
|
+
node-version: '22'
|
|
20
|
+
cache: 'npm'
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: npm ci
|
|
24
|
+
|
|
25
|
+
- name: Build
|
|
26
|
+
run: npm run build
|
|
27
|
+
|
|
28
|
+
- name: Test
|
|
29
|
+
run: npm test
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
id-token: write # for npm provenance
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout
|
|
16
|
+
uses: actions/checkout@v6
|
|
17
|
+
|
|
18
|
+
- name: Setup Node
|
|
19
|
+
uses: actions/setup-node@v6
|
|
20
|
+
with:
|
|
21
|
+
node-version: '22'
|
|
22
|
+
registry-url: 'https://registry.npmjs.org'
|
|
23
|
+
cache: 'npm'
|
|
24
|
+
|
|
25
|
+
- name: Upgrade npm
|
|
26
|
+
# Trusted Publishing (OIDC) needs npm 11.5+ to use the OIDC token instead
|
|
27
|
+
# of a bearer token. Mirrors hap-core's publish workflow.
|
|
28
|
+
run: npm install -g npm@11
|
|
29
|
+
|
|
30
|
+
- name: Install dependencies
|
|
31
|
+
run: npm ci
|
|
32
|
+
|
|
33
|
+
- name: Verify tag matches package.json version
|
|
34
|
+
run: |
|
|
35
|
+
TAG_VERSION="${GITHUB_REF_NAME#v}"
|
|
36
|
+
PKG_VERSION=$(node -p "require('./package.json').version")
|
|
37
|
+
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
|
|
38
|
+
echo "Tag version ($TAG_VERSION) does not match package.json version ($PKG_VERSION)"
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
- name: Build
|
|
43
|
+
run: npm run build
|
|
44
|
+
|
|
45
|
+
- name: Test
|
|
46
|
+
run: npm test
|
|
47
|
+
|
|
48
|
+
- name: Publish to npm
|
|
49
|
+
# Trusted Publishing via OIDC — no NPM_TOKEN. Requires a Trusted Publisher
|
|
50
|
+
# configured for this package on npmjs.com (repo + this workflow file).
|
|
51
|
+
run: npm publish --access public --provenance
|
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# HAP ERP MCP Server
|
|
2
|
+
|
|
3
|
+
A generic ERP for AI agents, built as an [MCP](https://modelcontextprotocol.io) server and gated through the [Human Agency Protocol](https://humanagencyprotocol.org).
|
|
4
|
+
|
|
5
|
+
> **@humanagencyp/erp-mcp** — unpublished (version 0.1.0, not yet on npm)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What It Does
|
|
10
|
+
|
|
11
|
+
The quote-to-order flow — the common subset of Microsoft Dynamics 365 Business Central
|
|
12
|
+
(`salesQuotes` / `salesOrders` / `items` / `customers`), SAP Business One (`Quotations` /
|
|
13
|
+
`Orders` / `Items` / `BusinessPartners`), and Odoo (`sale.order` / `product.product` /
|
|
14
|
+
`res.partner`).
|
|
15
|
+
|
|
16
|
+
- **Items** — catalog: sku, name, unit, list price, stock
|
|
17
|
+
- **Customers** — name, currency, credit limit, open balance, payment terms
|
|
18
|
+
- **Quotes** — draft → sent → converted, with lines priced off the item catalog
|
|
19
|
+
- **Orders** — created by converting a sent quote; reserves stock
|
|
20
|
+
|
|
21
|
+
Every write is gated through the HAP `sales` profile (`hap-profiles/sales/0.1.profile.json`).
|
|
22
|
+
|
|
23
|
+
### Out of scope for 0.1
|
|
24
|
+
|
|
25
|
+
No invoices, delivery notes, payments, credit memos, or master-data changes
|
|
26
|
+
(no creating/editing items or customers). This connector only drives the
|
|
27
|
+
quote-to-order flow; billing and fulfillment stay in the source ERP.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
### Standalone
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install
|
|
37
|
+
npm run build
|
|
38
|
+
node dist/index.js
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Starts the MCP server with a SQLite database at `~/.hap/erp.db` (seeded with a
|
|
42
|
+
small demo dataset — 8 items, 5 customers — on first run).
|
|
43
|
+
|
|
44
|
+
For Postgres:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
DATABASE_URL=postgres://user:pass@host:5432/mydb node dist/index.js
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Tools
|
|
53
|
+
|
|
54
|
+
### Reads
|
|
55
|
+
|
|
56
|
+
| Tool | Description |
|
|
57
|
+
|------|-------------|
|
|
58
|
+
| `list_items` | Search items by sku/name |
|
|
59
|
+
| `get_item` | Get an item, including stock and list price |
|
|
60
|
+
| `find_customers` | Search customers by name/email |
|
|
61
|
+
| `get_customer` | Get a customer, including credit limit, open balance, available credit |
|
|
62
|
+
| `list_quotes` | List quotes, filter by status/customer |
|
|
63
|
+
| `get_quote` | Get a quote with its lines |
|
|
64
|
+
| `list_orders` | List orders, filter by customer |
|
|
65
|
+
| `get_order` | Get an order with its lines |
|
|
66
|
+
|
|
67
|
+
### Changes
|
|
68
|
+
|
|
69
|
+
| Tool | Description |
|
|
70
|
+
|------|-------------|
|
|
71
|
+
| `create_quote` | Create a draft quote (customer, lines, discount, value, currency) |
|
|
72
|
+
| `update_quote` | Update a draft quote (lines, discount, value, currency) — draft only |
|
|
73
|
+
| `send_quote` | Mark a draft quote sent (simulated — no email is actually sent) — draft → sent |
|
|
74
|
+
| `convert_quote_to_order` | Convert a sent quote into a confirmed order, reserving stock — sent → order |
|
|
75
|
+
|
|
76
|
+
Every change tool **requires** `value`, `discount_pct`, and `currency` in its call arguments.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Why the connector re-derives the total (this is the point)
|
|
81
|
+
|
|
82
|
+
The gateway's bounds engine enforces limits on the **declared** `value`,
|
|
83
|
+
`discount_pct`, and `currency` fields of a tool call — it has no visibility
|
|
84
|
+
into line items. That makes the declaration the security boundary: if this
|
|
85
|
+
connector executed whatever document the lines actually describe while the
|
|
86
|
+
gateway bound-checked a different, merely-asserted number, the bound would be
|
|
87
|
+
decorative.
|
|
88
|
+
|
|
89
|
+
So every change tool:
|
|
90
|
+
|
|
91
|
+
1. **Recomputes** the net total as `sum(qty × list_price) × (1 − discount_pct / 100)`,
|
|
92
|
+
rounded to cents, and refuses the call if the declared `value` differs by
|
|
93
|
+
more than 0.01.
|
|
94
|
+
2. Refuses if the declared `discount_pct` is outside `[0, 100]`, or — on
|
|
95
|
+
`send_quote` / `convert_quote_to_order` — differs from the discount already
|
|
96
|
+
recorded on the document (the discount is fixed once a quote is sent).
|
|
97
|
+
3. Refuses if the declared `currency` differs from the customer's currency
|
|
98
|
+
(on `create_quote`) or the document's stored currency (on
|
|
99
|
+
`update_quote` / `send_quote` / `convert_quote_to_order`).
|
|
100
|
+
4. On `convert_quote_to_order`: refuses if `open_balance + net_total` would
|
|
101
|
+
exceed the customer's `credit_limit`, and refuses if any line lacks
|
|
102
|
+
sufficient stock. Only after every line clears the stock check does it
|
|
103
|
+
reserve (decrement) stock — a shortfall on any line rejects the whole
|
|
104
|
+
conversion instead of partially reserving.
|
|
105
|
+
5. Enforces the document state machine: `update_quote` and `send_quote` only
|
|
106
|
+
act on `draft` quotes; `convert_quote_to_order` only acts on `sent` quotes
|
|
107
|
+
(which also blocks double-conversion — a converted quote is no longer
|
|
108
|
+
`sent`).
|
|
109
|
+
6. Refuses unknown `customer_id`/`item_id`, and non-positive or non-integer
|
|
110
|
+
`qty`.
|
|
111
|
+
|
|
112
|
+
Every refusal is returned as `isError: true` with a message naming the field,
|
|
113
|
+
the declared value, and the computed/expected value.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Database
|
|
118
|
+
|
|
119
|
+
**SQLite (default)** — zero config. Data stored at `~/.hap/erp.db` (or
|
|
120
|
+
`${HAP_DATA_DIR}/erp.db` when the gateway sets `HAP_DATA_DIR`). Auto-backup to
|
|
121
|
+
`erp.backup.db` daily.
|
|
122
|
+
|
|
123
|
+
**Postgres** — set `DATABASE_URL` to a connection string. For teams where
|
|
124
|
+
multiple gateways need shared access.
|
|
125
|
+
|
|
126
|
+
Schema is created automatically on first start, and a deterministic demo
|
|
127
|
+
dataset is seeded when the `items` table is empty.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## HAP Profile
|
|
132
|
+
|
|
133
|
+
This server is gated through the `sales` profile
|
|
134
|
+
(`github.com/humanagencyprotocol/hap-profiles/sales@0.1`):
|
|
135
|
+
|
|
136
|
+
- **Action types** — `quote`, `send`, `order`
|
|
137
|
+
- **Bounds** — `read_access`, `value_max`, `discount_max`, `order_value_daily_max`,
|
|
138
|
+
`quote_daily_max`, `send_daily_max`, `order_daily_max`
|
|
139
|
+
- **Execution fields** — `value`, `discount_pct`, `currency` (all `source: "declared"`,
|
|
140
|
+
verified by this connector against the lines before the gateway ever sees them)
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT
|
|
147
|
+
|
|
148
|
+
See [humanagencyprotocol.org](https://humanagencyprotocol.org) for the full protocol specification.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|