@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.
@@ -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.
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node