payflowagent-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/README.md +107 -0
- package/dist/index.js +100 -0
- package/dist/x402.js +78 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# PayFlowAgent MCP-Server
|
|
2
|
+
|
|
3
|
+
Bindet den PayFlowAgent-Dienst (Token-Intelligence fuer nad.fun auf Monad) als
|
|
4
|
+
**MCP-Server** in KI-Agenten ein — Cursor, Claude Desktop oder eigene Agenten.
|
|
5
|
+
|
|
6
|
+
Warum: Je niedriger die Integrationshuerde, desto eher kommt der naechste bezahlte
|
|
7
|
+
Call. Ein Agent fuegt einmal diesen Server hinzu und kann danach Token bewerten —
|
|
8
|
+
die bezahlten Tools begleichen den Preis automatisch in USDC via **x402**.
|
|
9
|
+
|
|
10
|
+
## Tools
|
|
11
|
+
|
|
12
|
+
| Tool | Preis | Beschreibung |
|
|
13
|
+
|-----------------|--------------|--------------|
|
|
14
|
+
| `score_token` | kostenlos | 0–100 Score, `riskLevel`, `action` (rate-limitiert). |
|
|
15
|
+
| `decide_token` | bezahlt (x402) | Voller Report: Faktoren, Graduation, Momentum. |
|
|
16
|
+
| `token_summary` | bezahlt (x402) | Graduation-Fortschritt + Momentum (guenstiger Einstieg). |
|
|
17
|
+
| `screen_tokens` | bezahlt (x402) | Gerankte Liste vorgescorter neuer Token. |
|
|
18
|
+
|
|
19
|
+
## Konfiguration (Env)
|
|
20
|
+
|
|
21
|
+
| Variable | Default | Zweck |
|
|
22
|
+
|--------------------------|-------------------------------|-------|
|
|
23
|
+
| `PAYFLOWAGENT_API_BASE` | `https://payflowagent.net` | Basis-URL des Dienstes. |
|
|
24
|
+
| `X402_BUYER_PRIVATE_KEY` | — | Private Key einer **dedizierten** Zahler-Wallet (Base, USDC). Ohne Key laufen nur kostenlose Tools. |
|
|
25
|
+
| `X402_BUYER_RPC` | `https://mainnet.base.org` | Zahlungs-RPC (optional). |
|
|
26
|
+
|
|
27
|
+
> Sicherheit: Nutze eine separate Wallet nur fuer diese Zahlungen, niemals die
|
|
28
|
+
> Empfangs-Wallet oder eine Wallet mit grossem Guthaben. Der Key wird ausschliesslich
|
|
29
|
+
> aus der Env gelesen.
|
|
30
|
+
|
|
31
|
+
## Einbinden in Cursor
|
|
32
|
+
|
|
33
|
+
`~/.cursor/mcp.json` (oder Projekt-`.cursor/mcp.json`):
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"payflowagent": {
|
|
39
|
+
"command": "npx",
|
|
40
|
+
"args": ["-y", "payflowagent-mcp"],
|
|
41
|
+
"env": {
|
|
42
|
+
"X402_BUYER_PRIVATE_KEY": "0x..."
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Einbinden in Claude Desktop
|
|
50
|
+
|
|
51
|
+
`claude_desktop_config.json`:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"mcpServers": {
|
|
56
|
+
"payflowagent": {
|
|
57
|
+
"command": "npx",
|
|
58
|
+
"args": ["-y", "payflowagent-mcp"],
|
|
59
|
+
"env": { "X402_BUYER_PRIVATE_KEY": "0x..." }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
> Ohne installiertes Paket lädt `npx -y payflowagent-mcp` es automatisch von npm.
|
|
66
|
+
> Für lokale Entwicklung statt der npm-Version: `["-y", "tsx", "<absoluter Pfad>/apps/mcp/src/index.ts"]`.
|
|
67
|
+
|
|
68
|
+
## Lokal starten / testen
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pnpm --filter payflowagent-mcp start # stdio-Server (aus dem Quellcode)
|
|
72
|
+
pnpm --filter payflowagent-mcp typecheck
|
|
73
|
+
pnpm --filter payflowagent-mcp build # dist/ erzeugen (wie beim Publish)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Veröffentlichen (npm)
|
|
77
|
+
|
|
78
|
+
Einmalig vorbereiten und publishen (benötigt deinen npm-Account):
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm login # einmalig
|
|
82
|
+
cd apps/mcp
|
|
83
|
+
npm publish --access public # baut via prepack automatisch dist/
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Nach dem Publish funktioniert überall: `npx -y payflowagent-mcp`.
|
|
87
|
+
|
|
88
|
+
### Offizielle MCP-Registry (optional)
|
|
89
|
+
|
|
90
|
+
`server.json` liegt bei. Mit dem offiziellen Publisher:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Publisher installieren: siehe https://github.com/modelcontextprotocol/registry
|
|
94
|
+
mcp-publisher login # Namespace net.payflowagent/* via DNS-TXT verifizieren
|
|
95
|
+
mcp-publisher publish # nutzt apps/mcp/server.json
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Viele Verzeichnisse (Glama, mcp.so, PulseMCP) indexieren npm zusätzlich automatisch
|
|
99
|
+
anhand der `mcp*`-Keywords.
|
|
100
|
+
|
|
101
|
+
Der Server kommuniziert ueber **stdio** (stdout ist dem MCP-Protokoll vorbehalten;
|
|
102
|
+
Statusmeldungen gehen nach stderr).
|
|
103
|
+
|
|
104
|
+
## Hinweis
|
|
105
|
+
|
|
106
|
+
Ohne `X402_BUYER_PRIVATE_KEY` liefern die bezahlten Tools eine klare Meldung, wie
|
|
107
|
+
man Zahlungen aktiviert — `score_token` funktioniert immer kostenlos zum Ausprobieren.
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PayFlowAgent MCP-Server (stdio).
|
|
4
|
+
*
|
|
5
|
+
* Zweck (Leitfrage "dient es den Zahlungseingaengen?"):
|
|
6
|
+
* Verteilt den Dienst genau dort, wo zahlende KI-Agenten leben (Cursor, Claude
|
|
7
|
+
* Desktop, eigene Agenten). Ein Agent bindet diesen MCP-Server ein und kann
|
|
8
|
+
* ohne Integrationsaufwand Token-Scores abrufen - die bezahlten Tools loesen
|
|
9
|
+
* per x402 automatisch eine USDC-Zahlung an die Empfangs-Wallet aus.
|
|
10
|
+
*
|
|
11
|
+
* Tools:
|
|
12
|
+
* - score_token (kostenlos): 0-100 Score, riskLevel, action fuer einen Token.
|
|
13
|
+
* - decide_token (bezahlt): voller Report inkl. Faktoren/Graduation/Momentum.
|
|
14
|
+
* - token_summary (bezahlt): Graduation + Momentum (guenstiger Einstieg).
|
|
15
|
+
* - screen_tokens (bezahlt): gerankte Liste vorgescorter neuer Token.
|
|
16
|
+
*
|
|
17
|
+
* Konfiguration (Env):
|
|
18
|
+
* PAYFLOWAGENT_API_BASE Basis-URL des Dienstes (Default https://payflowagent.net)
|
|
19
|
+
* X402_BUYER_PRIVATE_KEY Private Key einer dedizierten Zahler-Wallet (Base, USDC).
|
|
20
|
+
* Ohne Key funktionieren nur die kostenlosen Tools.
|
|
21
|
+
* X402_BUYER_RPC Optionaler Zahlungs-RPC (Default https://mainnet.base.org)
|
|
22
|
+
*/
|
|
23
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
24
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
25
|
+
import { z } from "zod";
|
|
26
|
+
import { createPayer, payFetch } from "./x402.js";
|
|
27
|
+
const API_BASE = (process.env.PAYFLOWAGENT_API_BASE ?? "https://payflowagent.net").replace(/\/+$/, "");
|
|
28
|
+
const payer = createPayer(process.env.X402_BUYER_PRIVATE_KEY, process.env.X402_BUYER_RPC);
|
|
29
|
+
const TOKEN = z
|
|
30
|
+
.string()
|
|
31
|
+
.regex(/^0x[0-9a-fA-F]{40}$/, "nad.fun Token-Adresse auf Monad (0x..., 42 Hex-Zeichen)");
|
|
32
|
+
const ok = (data, meta) => ({
|
|
33
|
+
content: [{ type: "text", text: JSON.stringify(meta ? { ...meta, data } : data, null, 2) }],
|
|
34
|
+
});
|
|
35
|
+
const err = (text) => ({ content: [{ type: "text", text }], isError: true });
|
|
36
|
+
/** Wandelt ein PayResult in ein MCP-Tool-Ergebnis (mit hilfreichen Fehlern). */
|
|
37
|
+
function present(label, r) {
|
|
38
|
+
if (r.ok) {
|
|
39
|
+
return ok(r.data, r.paid ? { paid: true, tx: r.tx ?? null, price: "USDC via x402" } : undefined);
|
|
40
|
+
}
|
|
41
|
+
if (r.status === 402 && r.error === "payment_required_no_key") {
|
|
42
|
+
return err(`${label} ist kostenpflichtig (x402, USDC). Es ist keine Zahler-Wallet konfiguriert.\n` +
|
|
43
|
+
`Setze die Umgebungsvariable X402_BUYER_PRIVATE_KEY (dedizierte Wallet mit USDC auf Base) ` +
|
|
44
|
+
`und starte den MCP-Server neu. Fuer einen kostenlosen Test nutze stattdessen das Tool "score_token".`);
|
|
45
|
+
}
|
|
46
|
+
if (r.status === 429) {
|
|
47
|
+
return err(`${label}: Rate-Limit erreicht (kostenloser Endpunkt). Bitte spaeter erneut versuchen.`);
|
|
48
|
+
}
|
|
49
|
+
if (r.error?.startsWith("payment_failed")) {
|
|
50
|
+
return err(`${label}: Zahlung fehlgeschlagen. Haeufige Ursache: zu wenig USDC/ETH (Gas) in der Zahler-Wallet. Detail: ${r.error}`);
|
|
51
|
+
}
|
|
52
|
+
const detail = typeof r.data === "object" ? JSON.stringify(r.data) : String(r.data ?? "");
|
|
53
|
+
return err(`${label}: HTTP ${r.status}. ${detail}`);
|
|
54
|
+
}
|
|
55
|
+
const server = new McpServer({ name: "payflowagent", version: "0.1.0" });
|
|
56
|
+
server.registerTool("score_token", {
|
|
57
|
+
title: "Token-Score (kostenlos)",
|
|
58
|
+
description: "Kostenloser, rate-limitierter Score (0-100) inkl. riskLevel und action fuer einen nad.fun-Token auf Monad. " +
|
|
59
|
+
"Ideal zum Pruefen vor einem bezahlten Aufruf.",
|
|
60
|
+
inputSchema: { token: TOKEN },
|
|
61
|
+
}, async ({ token }) => present("score_token", await payFetch(`${API_BASE}/v1/lite?token=${token}`, null)));
|
|
62
|
+
server.registerTool("decide_token", {
|
|
63
|
+
title: "Voller Report (bezahlt, x402)",
|
|
64
|
+
description: "Bezahlt (USDC via x402). Entscheidungsfertiger Report fuer einen nad.fun-Token: Score, riskLevel, action, " +
|
|
65
|
+
"erklaerende Faktoren, Graduation-Fortschritt und 5-Minuten-Momentum.",
|
|
66
|
+
inputSchema: { token: TOKEN },
|
|
67
|
+
}, async ({ token }) => present("decide_token", await payFetch(`${API_BASE}/v1/decide?token=${token}`, payer)));
|
|
68
|
+
server.registerTool("token_summary", {
|
|
69
|
+
title: "Graduation + Momentum (bezahlt, x402)",
|
|
70
|
+
description: "Bezahlt (USDC via x402). Guenstiger Einstieg: Graduation-Fortschritt (Bonding-Curve %) + Momentum-" +
|
|
71
|
+
"Zusammenfassung fuer einen nad.fun-Token.",
|
|
72
|
+
inputSchema: { token: TOKEN },
|
|
73
|
+
}, async ({ token }) => present("token_summary", await payFetch(`${API_BASE}/v1/token/${token}/summary`, payer)));
|
|
74
|
+
server.registerTool("screen_tokens", {
|
|
75
|
+
title: "Screening: gerankte Token-Liste (bezahlt, x402)",
|
|
76
|
+
description: "Bezahlt (USDC via x402). Gerankte Liste vorgescorter, frischer nad.fun-Token (score, riskLevel, action, " +
|
|
77
|
+
"Graduation, Holder). Ideal fuer Screener/Trading-Agenten, die regelmaessig nach Chancen suchen.",
|
|
78
|
+
inputSchema: {
|
|
79
|
+
limit: z.number().int().min(1).max(25).optional().describe("Max. Anzahl Token (1-25, Default 10)"),
|
|
80
|
+
minScore: z.number().int().min(0).max(100).optional().describe("Nur Token mit Score >= minScore (0-100)"),
|
|
81
|
+
},
|
|
82
|
+
}, async ({ limit, minScore }) => {
|
|
83
|
+
const qs = new URLSearchParams();
|
|
84
|
+
if (limit != null)
|
|
85
|
+
qs.set("limit", String(limit));
|
|
86
|
+
if (minScore != null)
|
|
87
|
+
qs.set("minScore", String(minScore));
|
|
88
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
89
|
+
return present("screen_tokens", await payFetch(`${API_BASE}/v1/screen${suffix}`, payer));
|
|
90
|
+
});
|
|
91
|
+
async function main() {
|
|
92
|
+
const transport = new StdioServerTransport();
|
|
93
|
+
await server.connect(transport);
|
|
94
|
+
// Hinweis auf stderr (stdout ist dem MCP-Protokoll vorbehalten).
|
|
95
|
+
console.error(`[payflowagent-mcp] verbunden. API=${API_BASE} · Zahlungen=${payer ? `aktiv (${payer.address})` : "deaktiviert (kein X402_BUYER_PRIVATE_KEY)"}`);
|
|
96
|
+
}
|
|
97
|
+
main().catch((e) => {
|
|
98
|
+
console.error(`[payflowagent-mcp] Start fehlgeschlagen: ${e?.message ?? String(e)}`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
});
|
package/dist/x402.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402-Zahlungs-Helper fuer den MCP-Server.
|
|
3
|
+
*
|
|
4
|
+
* Zweck (Leitfrage "dient es den Zahlungseingaengen?"):
|
|
5
|
+
* Macht aus einem normalen fetch einen bezahlenden fetch. Bezahlte Routen
|
|
6
|
+
* (HTTP 402) werden - falls ein Buyer-Key gesetzt ist - automatisch in USDC
|
|
7
|
+
* beglichen und erneut aufgerufen. Damit kann jeder KI-Agent, der diesen
|
|
8
|
+
* MCP-Server einbindet, ohne Zusatzcode bezahlte Calls ausloesen.
|
|
9
|
+
*
|
|
10
|
+
* Sicherheit: Der Private Key kommt NUR aus der Env (X402_BUYER_PRIVATE_KEY),
|
|
11
|
+
* niemals aus Argumenten/Logs. Es muss eine dedizierte Zahler-Wallet sein.
|
|
12
|
+
*/
|
|
13
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
14
|
+
import { x402Client, x402HTTPClient } from "@x402/core/client";
|
|
15
|
+
import { registerExactEvmScheme } from "@x402/evm/exact/client";
|
|
16
|
+
/** Default-Zahlungs-RPC (Base Mainnet). Per X402_BUYER_RPC ueberschreibbar. */
|
|
17
|
+
const DEFAULT_RPC = "https://mainnet.base.org";
|
|
18
|
+
/**
|
|
19
|
+
* Baut einen Payer aus dem Buyer-Key. Gibt null zurueck, wenn kein gueltiger
|
|
20
|
+
* Key vorhanden ist (dann funktionieren nur die kostenlosen Tools).
|
|
21
|
+
*/
|
|
22
|
+
export function createPayer(privateKey, rpcUrl) {
|
|
23
|
+
const key = privateKey?.trim();
|
|
24
|
+
if (!key || !/^0x[0-9a-fA-F]{64}$/.test(key))
|
|
25
|
+
return null;
|
|
26
|
+
const account = privateKeyToAccount(key);
|
|
27
|
+
const core = new x402Client();
|
|
28
|
+
registerExactEvmScheme(core, { signer: account, schemeOptions: { rpcUrl: rpcUrl?.trim() || DEFAULT_RPC } });
|
|
29
|
+
return { address: account.address, http: new x402HTTPClient(core) };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Fuehrt einen GET aus. Bei 402 wird - sofern ein Payer vorhanden ist -
|
|
33
|
+
* automatisch bezahlt und erneut aufgerufen.
|
|
34
|
+
*/
|
|
35
|
+
export async function payFetch(url, payer) {
|
|
36
|
+
const r1 = await fetch(url, { headers: { accept: "application/json" } });
|
|
37
|
+
// Kein Bezahlfall (200, 400, 429, ...) -> direkt zurueck.
|
|
38
|
+
if (r1.status !== 402) {
|
|
39
|
+
const data = await r1.json().catch(() => undefined);
|
|
40
|
+
return { ok: r1.ok, status: r1.status, data, paid: false };
|
|
41
|
+
}
|
|
42
|
+
const body1 = await r1.json().catch(() => undefined);
|
|
43
|
+
if (!payer) {
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
status: 402,
|
|
47
|
+
data: body1,
|
|
48
|
+
paid: false,
|
|
49
|
+
error: "payment_required_no_key",
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// 402 -> Zahlung signieren und erneut aufrufen.
|
|
53
|
+
try {
|
|
54
|
+
const required = payer.http.getPaymentRequiredResponse((n) => r1.headers.get(n), body1);
|
|
55
|
+
const payload = await payer.http.createPaymentPayload(required);
|
|
56
|
+
const payHeaders = payer.http.encodePaymentSignatureHeader(payload);
|
|
57
|
+
const r2 = await fetch(url, { headers: { accept: "application/json", ...payHeaders } });
|
|
58
|
+
const data = await r2.json().catch(() => undefined);
|
|
59
|
+
let tx;
|
|
60
|
+
try {
|
|
61
|
+
const settle = payer.http.getPaymentSettleResponse((n) => r2.headers.get(n));
|
|
62
|
+
tx = settle?.transaction;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
/* Settlement-Header optional */
|
|
66
|
+
}
|
|
67
|
+
return { ok: r2.ok, status: r2.status, data, paid: r2.ok, tx };
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
return {
|
|
71
|
+
ok: false,
|
|
72
|
+
status: 402,
|
|
73
|
+
data: body1,
|
|
74
|
+
paid: false,
|
|
75
|
+
error: `payment_failed: ${e?.message ?? String(e)}`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "payflowagent-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for PayFlowAgent — free & pay-per-call (x402/USDC) risk & momentum scores for nad.fun tokens on Monad.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"modelcontextprotocol",
|
|
8
|
+
"mcp-server",
|
|
9
|
+
"x402",
|
|
10
|
+
"monad",
|
|
11
|
+
"nad.fun",
|
|
12
|
+
"crypto",
|
|
13
|
+
"token",
|
|
14
|
+
"agent",
|
|
15
|
+
"ai"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://payflowagent.net",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://payflowagent.net"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "PayFlowAgent",
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "dist/index.js",
|
|
25
|
+
"bin": {
|
|
26
|
+
"payflowagent-mcp": "dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"mcpName": "net.payflowagent/mcp",
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"README.md"
|
|
32
|
+
],
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18.0.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"start": "tsx src/index.ts",
|
|
38
|
+
"dev": "tsx watch src/index.ts",
|
|
39
|
+
"build": "tsc -p tsconfig.build.json",
|
|
40
|
+
"prepack": "npm run build",
|
|
41
|
+
"typecheck": "tsc --noEmit",
|
|
42
|
+
"test": "echo \"no tests yet\""
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
46
|
+
"@x402/core": "^2.17.0",
|
|
47
|
+
"@x402/evm": "^2.17.0",
|
|
48
|
+
"viem": "^2.21.0",
|
|
49
|
+
"zod": "^3.23.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"tsx": "^4.19.0",
|
|
53
|
+
"typescript": "^5.6.0"
|
|
54
|
+
}
|
|
55
|
+
}
|