@aynicobros/mcp
v0.1.1
Published
MCP server for building an ayni cobros integration: creates test charges and drives them through the bank simulator, so an assistant can exercise the code it just wrote.
Maintainers
Readme
@aynicobros/mcp
An MCP server for building an ayni cobros integration. It creates test charges and drives them through the bank simulator, so an assistant can exercise the code it just wrote instead of only describing it.
https://aynicobros.com/llms.txt tells a model how the integration works. This
lets it run one.
Test mode only, and that is the whole safety model
An MCP server is a process that holds an API key and hands a language model tools
that use it. That inverts the rule @aynicobros/node is built around — the
secret key never leaves your server — because here it sits on a laptop beside a
model reading text other people wrote. A merchant pasting a customer's message
into an assistant is pasting untrusted instructions next to a charge-creating
tool.
So:
- The server refuses to start with an
ayn_live_key. Not a per-call check that someone can forget or reorder — the process does not come up. create_test_chargehardcodesmode: 'test'. It is not in the tool schema, so no argument can change it.- The API refuses
simulate-paymentagainst a live charge unconditionally, which is a second guard that does not depend on the first.
The blast radius of the worst case is a row in a database.
Live charge creation is deliberately absent. It needs per-call human confirmation, which is a protocol concern rather than a bigger version of this.
Setup
Get a test key from your ayni dashboard, then:
{
"mcpServers": {
"aynicobros": {
"command": "npx",
"args": ["-y", "@aynicobros/mcp"],
"env": { "AYNI_TEST_KEY": "ayn_test_..." }
}
}
}AYNI_API_ORIGIN overrides the API host while developing locally. It is read
from the environment and never from a tool argument — an origin a model can
choose is an origin a model can be talked into choosing.
Tools
| Tool | What it does |
| --------------------- | -------------------------------------------------------------------------------------- |
| create_test_charge | Creates a mode: test charge; returns checkoutUrl and publicToken |
| simulate_payment | Settles it through the bank simulator |
| simulate_expiry | Expires it, so the unhappy path is reachable too |
| get_charge | Reads one charge and its payments |
| list_charges | Lists charges, newest first |
| get_checkout_status | Reads a charge by its public token, the way the payer's browser does — no key involved |
The loop it makes possible
create_test_charge → open the checkoutUrl and look at it
→ simulate_payment
→ get_checkout_status, and watch PENDING become PAIDThen the same again with simulate_expiry, which is the branch most
integrations never test until a real charge expires on a real customer.
Amounts and dates, once more
amount is a decimal string in major units: "250.00" is 250 Bs, not 250
centavos. dueInDays is resolved against the Bolivian calendar by
datePlusDays() — a server on UTC is a day ahead of Bolivia for four hours out
of every day.
