@venlyfinance/settlement-mcp 0.1.0 → 0.1.1
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/README.md +12 -10
- package/dist/client/http-client.d.ts +2 -2
- package/dist/client/http-client.js +2 -2
- package/dist/constants.d.ts +4 -4
- package/dist/constants.js +4 -4
- package/dist/tools/write-tools.js +19 -9
- package/dist/types.d.ts +13 -10
- package/dist/types.js +3 -3
- package/package.json +1 -1
- package/skills/{payment-link-lifecycle.md → payment-session-lifecycle.md} +8 -7
package/README.md
CHANGED
|
@@ -9,16 +9,18 @@ x402, the machine-to-machine agent-payments rail.
|
|
|
9
9
|
The differentiator: the MCP is the human-gated operator surface; x402 is the
|
|
10
10
|
machine-to-machine rail. Read-only by default, write tools fail closed.
|
|
11
11
|
|
|
12
|
-
Status: v0.1.
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
Status: v0.1.1 (realigned to the live published OpenAPI specs: staging base URL
|
|
13
|
+
and auth host corrected, `create_payment_link` became `create_payment_session`
|
|
14
|
+
to match the live API). Read tools work against staging out of the box once
|
|
15
|
+
credentials are set; write tools are shipped disarmed and fail closed (see the
|
|
16
|
+
safety model). The x402 tool is a stub that states a position, it moves no funds.
|
|
15
17
|
|
|
16
18
|
## What it is
|
|
17
19
|
|
|
18
20
|
- Built on the official MCP TypeScript SDK (`@modelcontextprotocol/sdk`), Node
|
|
19
21
|
>= 18, stdio transport.
|
|
20
22
|
- A thin layer over the Venly Finance API (`finance.yaml`, servers
|
|
21
|
-
`https://api.venlyfinance.com/
|
|
23
|
+
`https://api.venlyfinance.com/v1`) and the Fundflow API (`fundflow.yaml`,
|
|
22
24
|
servers `https://api-fundflow.venly.io`). Endpoint truth is the published API
|
|
23
25
|
reference at [docs.venlyfinance.com](https://docs.venlyfinance.com/api-reference).
|
|
24
26
|
- Transport is injected through the `VenlyClient` interface (`src/types.ts`).
|
|
@@ -57,7 +59,7 @@ matched vIBAN, the matched transactions, and the total amount.
|
|
|
57
59
|
### 2. Write tools (present, DISARMED by default)
|
|
58
60
|
|
|
59
61
|
`stage_transfer`, `approve_ramp_request`, `reject_ramp_request`,
|
|
60
|
-
`
|
|
62
|
+
`create_payment_session`.
|
|
61
63
|
|
|
62
64
|
Each is dry-run by default and returns the exact request it would send. See the
|
|
63
65
|
safety model below.
|
|
@@ -134,7 +136,7 @@ MCP client config example:
|
|
|
134
136
|
"command": "node",
|
|
135
137
|
"args": ["/absolute/path/to/settlement-mcp/dist/index.js"],
|
|
136
138
|
"env": {
|
|
137
|
-
"VENLY_FINANCE_BASE_URL": "https://api-staging.venlyfinance.com/
|
|
139
|
+
"VENLY_FINANCE_BASE_URL": "https://api-staging.venlyfinance.com/v1",
|
|
138
140
|
"VENLY_FUNDFLOW_BASE_URL": "https://api-fundflow-staging.venly.io"
|
|
139
141
|
}
|
|
140
142
|
}
|
|
@@ -149,9 +151,9 @@ Override via env:
|
|
|
149
151
|
|
|
150
152
|
| Env var | Default (staging) |
|
|
151
153
|
|---|---|
|
|
152
|
-
| `VENLY_FINANCE_BASE_URL` | `https://api-staging.venlyfinance.com/
|
|
154
|
+
| `VENLY_FINANCE_BASE_URL` | `https://api-staging.venlyfinance.com/v1` |
|
|
153
155
|
| `VENLY_FUNDFLOW_BASE_URL` | `https://api-fundflow-staging.venly.io` |
|
|
154
|
-
| `VENLY_TOKEN_URL` | `https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token` |
|
|
156
|
+
| `VENLY_TOKEN_URL` | `https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token` (staging; use `login.venly.io` for production) |
|
|
155
157
|
| `VENLY_CLIENT_ID` | unset (read-only until set) |
|
|
156
158
|
| `VENLY_CLIENT_SECRET` | unset |
|
|
157
159
|
| `VENLY_MCP_LIVE` | unset (writes disarmed) |
|
|
@@ -186,7 +188,7 @@ MCP-consumable workflow docs under `skills/`:
|
|
|
186
188
|
- `reconcile-by-reference-code.md`
|
|
187
189
|
- `four-eyes-approval.md`
|
|
188
190
|
- `stage-and-confirm-transfer.md`
|
|
189
|
-
- `payment-
|
|
191
|
+
- `payment-session-lifecycle.md`
|
|
190
192
|
- `x402-quote-walkthrough.md`
|
|
191
193
|
|
|
192
194
|
## Layout
|
|
@@ -213,7 +215,7 @@ settlement-mcp/
|
|
|
213
215
|
reconcile-by-reference-code.md
|
|
214
216
|
four-eyes-approval.md
|
|
215
217
|
stage-and-confirm-transfer.md
|
|
216
|
-
payment-
|
|
218
|
+
payment-session-lifecycle.md
|
|
217
219
|
x402-quote-walkthrough.md
|
|
218
220
|
four-eyes-approval.md
|
|
219
221
|
stage-and-confirm-transfer.md
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* when a write method is invoked, and write methods are invoked only after
|
|
16
16
|
* the gate in safety.ts is armed. Read-only by default is enforced upstream.
|
|
17
17
|
*/
|
|
18
|
-
import type { Account, CreateFiatTransferInput,
|
|
18
|
+
import type { Account, CreateFiatTransferInput, CreatePayInSessionRequest, ListRampRequestsParams, OptimisticLockingBody, Party, PaymentSession, RampRequestDto, RampRequestListItem, Transfer, VenlyClient, VirtualBankAccount } from "../types.js";
|
|
19
19
|
export interface HttpVenlyClientConfig {
|
|
20
20
|
financeBaseUrl?: string;
|
|
21
21
|
fundflowBaseUrl?: string;
|
|
@@ -54,5 +54,5 @@ export declare class HttpVenlyClient implements VenlyClient {
|
|
|
54
54
|
createFiatTransfer(senderAccountId: string, body: CreateFiatTransferInput): Promise<Transfer>;
|
|
55
55
|
approveRampRequest(id: string, body: OptimisticLockingBody): Promise<RampRequestDto>;
|
|
56
56
|
rejectRampRequest(id: string, body: OptimisticLockingBody): Promise<RampRequestDto>;
|
|
57
|
-
|
|
57
|
+
createPayInSession(accountId: string, body: CreatePayInSessionRequest): Promise<PaymentSession>;
|
|
58
58
|
}
|
|
@@ -157,7 +157,7 @@ export class HttpVenlyClient {
|
|
|
157
157
|
body,
|
|
158
158
|
});
|
|
159
159
|
}
|
|
160
|
-
|
|
161
|
-
return this.request(this.financeBaseUrl, "POST", `/accounts/${accountId}/fiat-to-crypto/payment-
|
|
160
|
+
createPayInSession(accountId, body) {
|
|
161
|
+
return this.request(this.financeBaseUrl, "POST", `/accounts/${accountId}/fiat-to-crypto/payment-sessions`, { body });
|
|
162
162
|
}
|
|
163
163
|
}
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/** Shared constants. Defaults point at STAGING so an accidental run never
|
|
2
2
|
* touches production. Override via env for a real sandbox test. */
|
|
3
3
|
export declare const SERVER_NAME = "venly-settlement-mcp-server";
|
|
4
|
-
export declare const SERVER_VERSION = "0.1.
|
|
4
|
+
export declare const SERVER_VERSION = "0.1.1";
|
|
5
5
|
/** The env flag that must equal "1" for any write tool to execute live. */
|
|
6
6
|
export declare const LIVE_FLAG = "VENLY_MCP_LIVE";
|
|
7
7
|
/** Default base URLs (STAGING). Production values live in the vendored specs:
|
|
8
|
-
* finance https://api.venlyfinance.com/
|
|
9
|
-
export declare const DEFAULT_FINANCE_BASE_URL = "https://api-staging.venlyfinance.com/
|
|
8
|
+
* finance https://api.venlyfinance.com/v1, fundflow https://api-fundflow.venly.io */
|
|
9
|
+
export declare const DEFAULT_FINANCE_BASE_URL = "https://api-staging.venlyfinance.com/v1";
|
|
10
10
|
export declare const DEFAULT_FUNDFLOW_BASE_URL = "https://api-fundflow-staging.venly.io";
|
|
11
|
-
export declare const DEFAULT_TOKEN_URL = "https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token";
|
|
11
|
+
export declare const DEFAULT_TOKEN_URL = "https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token";
|
|
12
12
|
/** Cap on serialized tool output length to keep responses readable. */
|
|
13
13
|
export declare const CHARACTER_LIMIT = 30000;
|
package/dist/constants.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/** Shared constants. Defaults point at STAGING so an accidental run never
|
|
2
2
|
* touches production. Override via env for a real sandbox test. */
|
|
3
3
|
export const SERVER_NAME = "venly-settlement-mcp-server";
|
|
4
|
-
export const SERVER_VERSION = "0.1.
|
|
4
|
+
export const SERVER_VERSION = "0.1.1";
|
|
5
5
|
/** The env flag that must equal "1" for any write tool to execute live. */
|
|
6
6
|
export const LIVE_FLAG = "VENLY_MCP_LIVE";
|
|
7
7
|
/** Default base URLs (STAGING). Production values live in the vendored specs:
|
|
8
|
-
* finance https://api.venlyfinance.com/
|
|
9
|
-
export const DEFAULT_FINANCE_BASE_URL = "https://api-staging.venlyfinance.com/
|
|
8
|
+
* finance https://api.venlyfinance.com/v1, fundflow https://api-fundflow.venly.io */
|
|
9
|
+
export const DEFAULT_FINANCE_BASE_URL = "https://api-staging.venlyfinance.com/v1";
|
|
10
10
|
export const DEFAULT_FUNDFLOW_BASE_URL = "https://api-fundflow-staging.venly.io";
|
|
11
|
-
export const DEFAULT_TOKEN_URL = "https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token";
|
|
11
|
+
export const DEFAULT_TOKEN_URL = "https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token";
|
|
12
12
|
/** Cap on serialized tool output length to keep responses readable. */
|
|
13
13
|
export const CHARACTER_LIMIT = 30_000;
|
|
@@ -124,17 +124,24 @@ export function registerWriteTools(server, client, env) {
|
|
|
124
124
|
return errorResult(e.message);
|
|
125
125
|
}
|
|
126
126
|
});
|
|
127
|
-
server.registerTool("
|
|
128
|
-
title: "Create a fiat-to-crypto payment
|
|
129
|
-
description: "Create a pay-in
|
|
130
|
-
"
|
|
127
|
+
server.registerTool("create_payment_session", {
|
|
128
|
+
title: "Create a fiat-to-crypto payment session (dry-run by default)",
|
|
129
|
+
description: "Create a hosted pay-in session (finance POST " +
|
|
130
|
+
"/accounts/{accountId}/fiat-to-crypto/payment-sessions); redirect the " +
|
|
131
|
+
"payer to the returned paymentUrl. DISARMED by default.",
|
|
131
132
|
inputSchema: {
|
|
132
133
|
accountId: z.string(),
|
|
133
134
|
inAmount: z.string().describe("Decimal string, e.g. \"250.00\""),
|
|
134
135
|
inCurrency: z.string().describe("e.g. EUR"),
|
|
135
|
-
outCryptocurrency: z.string().
|
|
136
|
-
|
|
136
|
+
outCryptocurrency: z.string().describe("e.g. USDC"),
|
|
137
|
+
callbackUrl: z.string().describe("Webhook URL notified on completion"),
|
|
138
|
+
successRedirectUrl: z.string().optional(),
|
|
139
|
+
failureRedirectUrl: z.string().optional(),
|
|
137
140
|
externalRef: z.string().optional(),
|
|
141
|
+
idempotencyKey: z
|
|
142
|
+
.string()
|
|
143
|
+
.optional()
|
|
144
|
+
.describe("UUID; generated when omitted"),
|
|
138
145
|
confirm: confirmField,
|
|
139
146
|
},
|
|
140
147
|
annotations: WRITE_ANNOTATIONS,
|
|
@@ -144,14 +151,17 @@ export function registerWriteTools(server, client, env) {
|
|
|
144
151
|
inAmount: rest.inAmount,
|
|
145
152
|
inCurrency: rest.inCurrency,
|
|
146
153
|
outCryptocurrency: rest.outCryptocurrency,
|
|
147
|
-
|
|
154
|
+
callbackUrl: rest.callbackUrl,
|
|
155
|
+
successRedirectUrl: rest.successRedirectUrl,
|
|
156
|
+
failureRedirectUrl: rest.failureRedirectUrl,
|
|
148
157
|
externalRef: rest.externalRef,
|
|
158
|
+
idempotencyKey: rest.idempotencyKey ?? crypto.randomUUID(),
|
|
149
159
|
};
|
|
150
160
|
if (!gate.armed) {
|
|
151
|
-
return jsonResult(buildDryRun("
|
|
161
|
+
return jsonResult(buildDryRun("create_payment_session", "POST", "finance", `/accounts/${accountId}/fiat-to-crypto/payment-sessions`, body, gate));
|
|
152
162
|
}
|
|
153
163
|
try {
|
|
154
|
-
const result = await client.
|
|
164
|
+
const result = await client.createPayInSession(accountId, body);
|
|
155
165
|
return jsonResult({ mode: "live", result });
|
|
156
166
|
}
|
|
157
167
|
catch (e) {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Domain types + the injectable VenlyClient interface.
|
|
3
3
|
*
|
|
4
|
-
* These shapes are a minimal projection of the
|
|
5
|
-
*
|
|
6
|
-
* https://api.venlyfinance.com/
|
|
4
|
+
* These shapes are a minimal projection of the published OpenAPI specs
|
|
5
|
+
* vendored in this repository under `specs/` – finance.yaml (servers:
|
|
6
|
+
* https://api.venlyfinance.com/v1) and fundflow.yaml (servers:
|
|
7
7
|
* https://api-fundflow.venly.io). Only the fields the tools actually read or
|
|
8
8
|
* echo are modeled. Fields are intentionally loose (optional) because this is a
|
|
9
9
|
* thin wrapper, not a full SDK.
|
|
@@ -94,8 +94,8 @@ export interface Party {
|
|
|
94
94
|
status?: string;
|
|
95
95
|
[key: string]: unknown;
|
|
96
96
|
}
|
|
97
|
-
/** A payment
|
|
98
|
-
export interface
|
|
97
|
+
/** A fiat-to-crypto payment session (finance PaymentSession). */
|
|
98
|
+
export interface PaymentSession {
|
|
99
99
|
id: string;
|
|
100
100
|
accountId?: string;
|
|
101
101
|
paymentUrl?: string;
|
|
@@ -141,12 +141,15 @@ export interface CreateFiatTransferInput {
|
|
|
141
141
|
export interface OptimisticLockingBody {
|
|
142
142
|
version: number;
|
|
143
143
|
}
|
|
144
|
-
/** Body for the payment
|
|
145
|
-
export interface
|
|
144
|
+
/** Body for the payment session POST (finance CreatePayInSessionRequest). */
|
|
145
|
+
export interface CreatePayInSessionRequest {
|
|
146
146
|
inAmount: string;
|
|
147
147
|
inCurrency: string;
|
|
148
|
-
outCryptocurrency
|
|
149
|
-
|
|
148
|
+
outCryptocurrency: string;
|
|
149
|
+
callbackUrl: string;
|
|
150
|
+
idempotencyKey: string;
|
|
151
|
+
successRedirectUrl?: string;
|
|
152
|
+
failureRedirectUrl?: string;
|
|
150
153
|
externalRef?: string;
|
|
151
154
|
metadata?: Record<string, string>;
|
|
152
155
|
}
|
|
@@ -173,5 +176,5 @@ export interface VenlyClient {
|
|
|
173
176
|
createFiatTransfer(senderAccountId: string, body: CreateFiatTransferInput): Promise<Transfer>;
|
|
174
177
|
approveRampRequest(id: string, body: OptimisticLockingBody): Promise<RampRequestDto>;
|
|
175
178
|
rejectRampRequest(id: string, body: OptimisticLockingBody): Promise<RampRequestDto>;
|
|
176
|
-
|
|
179
|
+
createPayInSession(accountId: string, body: CreatePayInSessionRequest): Promise<PaymentSession>;
|
|
177
180
|
}
|
package/dist/types.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Domain types + the injectable VenlyClient interface.
|
|
3
3
|
*
|
|
4
|
-
* These shapes are a minimal projection of the
|
|
5
|
-
*
|
|
6
|
-
* https://api.venlyfinance.com/
|
|
4
|
+
* These shapes are a minimal projection of the published OpenAPI specs
|
|
5
|
+
* vendored in this repository under `specs/` – finance.yaml (servers:
|
|
6
|
+
* https://api.venlyfinance.com/v1) and fundflow.yaml (servers:
|
|
7
7
|
* https://api-fundflow.venly.io). Only the fields the tools actually read or
|
|
8
8
|
* echo are modeled. Fields are intentionally loose (optional) because this is a
|
|
9
9
|
* thin wrapper, not a full SDK.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@venlyfinance/settlement-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Venly Settlement MCP server. Human-gated operator surface over the Venly Finance and Fundflow APIs, plus an x402 machine-to-machine quote stub. Read-only by default, write tools fail closed.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Skill: Create and track a payment
|
|
1
|
+
# Skill: Create and track a fiat-to-crypto payment session
|
|
2
2
|
|
|
3
|
-
Stand up a
|
|
3
|
+
Stand up a hosted pay-in session for an account, hand the URL to a payer,
|
|
4
4
|
and follow the payment through to settlement.
|
|
5
5
|
|
|
6
6
|
## When to use
|
|
@@ -13,7 +13,7 @@ collections, top-ups.
|
|
|
13
13
|
|
|
14
14
|
- `get_account` (read)
|
|
15
15
|
- `list_virtual_bank_accounts` (read)
|
|
16
|
-
- `
|
|
16
|
+
- `create_payment_session` (write, disarmed by default)
|
|
17
17
|
- `get_transfer` (read)
|
|
18
18
|
|
|
19
19
|
## Steps
|
|
@@ -21,10 +21,11 @@ collections, top-ups.
|
|
|
21
21
|
1. `get_account` for the collecting account. Confirm `status: "ACTIVE"` - an
|
|
22
22
|
unverified or suspended account cannot collect.
|
|
23
23
|
2. Optional context: `list_virtual_bank_accounts` shows the account's existing
|
|
24
|
-
collection surfaces (IBAN + referenceCode); a payment
|
|
24
|
+
collection surfaces (IBAN + referenceCode); a payment session is the hosted
|
|
25
25
|
alternative for payers who won't do a bank transfer.
|
|
26
|
-
3. `
|
|
27
|
-
|
|
26
|
+
3. `create_payment_session` with the `accountId`, a `callbackUrl` your system
|
|
27
|
+
will receive the completion webhook on, and an `externalRef` you can
|
|
28
|
+
reconcile on later. An `idempotencyKey` is generated when you don't pass one.
|
|
28
29
|
- By default the tool returns a dry-run object with the exact POST it would
|
|
29
30
|
send. Review it.
|
|
30
31
|
- Live execution needs all three: `confirm: true`, `VENLY_MCP_LIVE=1`, and
|
|
@@ -36,7 +37,7 @@ collections, top-ups.
|
|
|
36
37
|
|
|
37
38
|
## Notes
|
|
38
39
|
|
|
39
|
-
- Payment
|
|
40
|
+
- Payment sessions expire (`expiresAt`); a session that was never paid ends at
|
|
40
41
|
`EXPIRED`, not `FAILED`.
|
|
41
42
|
- Statuses walk `CREATED → PENDING_PAYMENT → PAYMENT_RECEIVED → CONVERTING →
|
|
42
43
|
MINTING → COMPLETED`, with `FAILED`, `CANCELLED`, `REFUNDING`, `REFUNDED` as
|