Skip to main content
Glama
zeybekci-lab

Payables MCP

by zeybekci-lab
README.md
# Payables MCP

A small MCP server for accounts payable. I built it to work out what an AP agent should look
like if you give a model tools instead of a UI: what it should be allowed to do on its own, what
needs a person, and where the line between the two sits.

Everything runs against a mock ERP in `data.json`, so you can clone it and click through it in
a couple of minutes. There are no API keys.

## Running it

```bash
uv venv && uv sync
uv run mcp dev server.py      # opens the MCP inspector
uv run pytest                 # 5 tests
```

`AP_PROFILE=analyst` or `AP_PROFILE=processor` in front of the run command gives you a
smaller server. More on that below.

## What you get

### Tools

![tools](docs/tools.png)

Eleven tools. The first five read and write bills and vendors, the same shape as any ERP
connector. The interesting ones are in the middle: `check_duplicates`, `match_invoice` and
`recommend_approval` are where the AP judgment lives. They call plain functions in
`ap_logic.py` and hand back a dict with the reasons, so a person can see why a bill got held.

`request_payment_release` is the one to notice. It queues approved bills for a payment run and
that is all it does. There is no tool that releases the run or sends money. That part stays in
the ERP, done by a person, on purpose.

### Prompts

![prompts](docs/prompts.png)

One prompt for now, the weekly payment run. It tells the assistant which resource to read and
which tools to run in what order. It carries no data itself.

### Resources

![resources](docs/resources.png)

Things the assistant reads often and should not need a tool call for: all bills, one bill by
id, bills due in the next N days, and the tolerance policy.

## Profiles

Not every deployment should get every tool. `AP_PROFILE` decides what gets registered when the
server starts:

| profile | can |
|---|---|
| `analyst` | read bills and vendors, run the checks, see the audit log |
| `processor` | all of the above, plus create bills and record bank changes |
| `full` | all of the above, plus queue payment runs |

An analyst server does not refuse `create_bill`. It never lists it, so the model cannot try.

## The files

| file | |
|---|---|
| `server.py` | the tools, resources, prompt, and the profile setup at the bottom |
| `ap_logic.py` | matching, duplicate check, screening. No MCP in here, so it tests on its own |
| `erp.py` | the mock ERP. Swap this for a real backend and the server stays the same |
| `data.json` | 3 vendors, 3 purchase orders, 5 bills |
| `test_server.py` | the logic on its own, one bill through the whole flow, and a check on tool names |

The five bills are set up so each one shows something: B-1001 is clean, B-1002 is a duplicate of
it that came in through a different channel, B-1003 bills more than was received, B-1004 is from
a vendor that changed bank details by email last week and has a memo asking for a payment
change, and B-1005 has no purchase order.

TDQS

A3.5/5.0

Scored across 11 tools

Disambiguation4/5

Most tools have clearly distinct roles (create/get/search bills, match against PO, check duplicates, recommend approval, release payments). The only potential confusion is between check_duplicates and match_invoice, both bill-validation steps, but their descriptions ('earlier bills' vs 'PO and goods receipt') clearly separate them.

Naming Consistency5/5

All tools follow a consistent snake_case verb_noun pattern (get_bill, search_bills, create_bill, match_invoice, request_payment_release). No mixing of conventions or vague verbs; the pattern is predictable throughout.

Tool Count5/5

11 tools is well-scoped for a payables/AP workflow. Each tool maps to a distinct step (bill CRUD, validation, approval recommendation, payment release, audit) and earns its place without redundancy.

Completeness4/5

Core bill lifecycle (create, get, search, validate, recommend, release) and audit are covered, but there is no update_bill/void, no vendor search or create (only get_vendor by id), and no explicit approve action. These are workable gaps for a controlled approval workflow but leave some dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues