telegram-wallet-p2p-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 +92 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +316 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Telegram Wallet P2P MCP Server
|
|
2
|
+
|
|
3
|
+
> ⚠️ **Unofficial** — This project is not affiliated with, endorsed by, or related to Telegram or Wallet.
|
|
4
|
+
|
|
5
|
+
An [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server providing read-only tools for Telegram Wallet P2P market data analytics.
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
| Tool | Description |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `get_p2p_ads` | Fetch active P2P ads filtered by crypto/fiat/side |
|
|
12
|
+
| `get_market_summary` | Aggregated analytics: price stats, payment methods, merchant distribution |
|
|
13
|
+
| `get_best_price` | Find the best available buy/sell price |
|
|
14
|
+
|
|
15
|
+
All tools return structured JSON suitable for AI consumption.
|
|
16
|
+
|
|
17
|
+
## Setup
|
|
18
|
+
|
|
19
|
+
### Prerequisites
|
|
20
|
+
|
|
21
|
+
- Node.js 18+
|
|
22
|
+
- A Wallet P2P API key ([how to get one](https://help.wallet.tg/article/934-p2p-api))
|
|
23
|
+
|
|
24
|
+
### Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install -g telegram-wallet-p2p-mcp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or build from source:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
cd packages/mcp
|
|
34
|
+
npm install
|
|
35
|
+
npm run build
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Configuration
|
|
39
|
+
|
|
40
|
+
Set your API key as an environment variable:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
export WALLET_P2P_API_KEY=your-api-key
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Usage with Claude Desktop
|
|
47
|
+
|
|
48
|
+
Add to your Claude Desktop configuration (`claude_desktop_config.json`):
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"telegram-wallet-p2p": {
|
|
54
|
+
"command": "npx",
|
|
55
|
+
"args": ["telegram-wallet-p2p-mcp"],
|
|
56
|
+
"env": {
|
|
57
|
+
"WALLET_P2P_API_KEY": "your-api-key"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Usage with VS Code
|
|
65
|
+
|
|
66
|
+
Add to your VS Code settings (`.vscode/mcp.json`):
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"servers": {
|
|
71
|
+
"telegram-wallet-p2p": {
|
|
72
|
+
"command": "npx",
|
|
73
|
+
"args": ["telegram-wallet-p2p-mcp"],
|
|
74
|
+
"env": {
|
|
75
|
+
"WALLET_P2P_API_KEY": "your-api-key"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Example Prompts
|
|
83
|
+
|
|
84
|
+
Once connected, you can ask your AI assistant:
|
|
85
|
+
|
|
86
|
+
- *"What's the current best price for selling USDT in RUB?"*
|
|
87
|
+
- *"Show me a market summary for BTC/USD buy ads"*
|
|
88
|
+
- *"List all USDT/RUB sell ads that accept Tinkoff"*
|
|
89
|
+
|
|
90
|
+
## License
|
|
91
|
+
|
|
92
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Telegram Wallet P2P MCP Server (Unofficial)
|
|
4
|
+
*
|
|
5
|
+
* An MCP server providing read-only tools for Telegram Wallet P2P market data.
|
|
6
|
+
* This is an UNOFFICIAL project — not affiliated with Telegram or Wallet.
|
|
7
|
+
*
|
|
8
|
+
* Tools:
|
|
9
|
+
* - get_p2p_ads: Fetch filtered P2P ads from the market
|
|
10
|
+
* - get_market_summary: Get aggregated market analytics
|
|
11
|
+
* - get_best_price: Find the best buy/sell price
|
|
12
|
+
*
|
|
13
|
+
* Configuration:
|
|
14
|
+
* - WALLET_P2P_API_KEY: Required environment variable for API authentication
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Telegram Wallet P2P MCP Server (Unofficial)
|
|
4
|
+
*
|
|
5
|
+
* An MCP server providing read-only tools for Telegram Wallet P2P market data.
|
|
6
|
+
* This is an UNOFFICIAL project — not affiliated with Telegram or Wallet.
|
|
7
|
+
*
|
|
8
|
+
* Tools:
|
|
9
|
+
* - get_p2p_ads: Fetch filtered P2P ads from the market
|
|
10
|
+
* - get_market_summary: Get aggregated market analytics
|
|
11
|
+
* - get_best_price: Find the best buy/sell price
|
|
12
|
+
*
|
|
13
|
+
* Configuration:
|
|
14
|
+
* - WALLET_P2P_API_KEY: Required environment variable for API authentication
|
|
15
|
+
*/
|
|
16
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
17
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
const BASE_URL = "https://p2p.walletbot.me";
|
|
20
|
+
const ONLINE_ITEMS_PATH = "/p2p/integration-api/v1/item/online";
|
|
21
|
+
// --- API Client ---
|
|
22
|
+
async function fetchAds(apiKey, params) {
|
|
23
|
+
const url = `${BASE_URL}${ONLINE_ITEMS_PATH}`;
|
|
24
|
+
const response = await fetch(url, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: {
|
|
27
|
+
"X-API-Key": apiKey,
|
|
28
|
+
"Content-Type": "application/json",
|
|
29
|
+
Accept: "application/json",
|
|
30
|
+
},
|
|
31
|
+
body: JSON.stringify({
|
|
32
|
+
cryptoCurrency: params.cryptoCurrency,
|
|
33
|
+
fiatCurrency: params.fiatCurrency,
|
|
34
|
+
side: params.side,
|
|
35
|
+
page: params.page ?? 1,
|
|
36
|
+
pageSize: params.pageSize ?? 50,
|
|
37
|
+
}),
|
|
38
|
+
});
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
let errorMsg = `API error: ${response.status}`;
|
|
41
|
+
try {
|
|
42
|
+
const errorBody = (await response.json());
|
|
43
|
+
errorMsg = `API error ${response.status}: [${errorBody.errorCode}] ${errorBody.errorMessage}`;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// ignore parse errors
|
|
47
|
+
}
|
|
48
|
+
throw new Error(errorMsg);
|
|
49
|
+
}
|
|
50
|
+
const data = (await response.json());
|
|
51
|
+
return data.data;
|
|
52
|
+
}
|
|
53
|
+
// --- Analytics helpers ---
|
|
54
|
+
function calcPriceSpread(items) {
|
|
55
|
+
if (items.length === 0)
|
|
56
|
+
return null;
|
|
57
|
+
const prices = items.map((i) => parseFloat(i.price)).sort((a, b) => a - b);
|
|
58
|
+
const min = prices[0];
|
|
59
|
+
const max = prices[prices.length - 1];
|
|
60
|
+
const avg = prices.reduce((s, p) => s + p, 0) / prices.length;
|
|
61
|
+
const mid = Math.floor(prices.length / 2);
|
|
62
|
+
const median = prices.length % 2 !== 0
|
|
63
|
+
? prices[mid]
|
|
64
|
+
: (prices[mid - 1] + prices[mid]) / 2;
|
|
65
|
+
return {
|
|
66
|
+
min: min.toFixed(4),
|
|
67
|
+
max: max.toFixed(4),
|
|
68
|
+
avg: avg.toFixed(4),
|
|
69
|
+
median: median.toFixed(4),
|
|
70
|
+
spread: (max - min).toFixed(4),
|
|
71
|
+
count: prices.length,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// --- Server setup ---
|
|
75
|
+
function getApiKey() {
|
|
76
|
+
const key = process.env.WALLET_P2P_API_KEY;
|
|
77
|
+
if (!key) {
|
|
78
|
+
console.error("Error: WALLET_P2P_API_KEY environment variable is required.");
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
return key;
|
|
82
|
+
}
|
|
83
|
+
const apiKey = getApiKey();
|
|
84
|
+
const server = new McpServer({
|
|
85
|
+
name: "telegram-wallet-p2p",
|
|
86
|
+
version: "0.1.0",
|
|
87
|
+
});
|
|
88
|
+
// --- Tool: get_p2p_ads ---
|
|
89
|
+
server.tool("get_p2p_ads", "Fetch active P2P market ads filtered by cryptocurrency, fiat currency, and trade side. Returns detailed ad data including price, quantity, payment methods, and trader info. This is an UNOFFICIAL tool — not affiliated with Telegram or Wallet.", {
|
|
90
|
+
cryptoCurrency: z
|
|
91
|
+
.string()
|
|
92
|
+
.describe('Cryptocurrency code, e.g. "USDT", "BTC", "TON"'),
|
|
93
|
+
fiatCurrency: z
|
|
94
|
+
.string()
|
|
95
|
+
.describe('Fiat currency code, e.g. "RUB", "USD", "EUR"'),
|
|
96
|
+
side: z.enum(["BUY", "SELL"]).describe("Trade side from the ad maker perspective"),
|
|
97
|
+
page: z.number().int().min(1).optional().describe("Page number (default: 1)"),
|
|
98
|
+
pageSize: z
|
|
99
|
+
.number()
|
|
100
|
+
.int()
|
|
101
|
+
.min(1)
|
|
102
|
+
.max(50)
|
|
103
|
+
.optional()
|
|
104
|
+
.describe("Items per page (default: 50, max: 50)"),
|
|
105
|
+
}, async ({ cryptoCurrency, fiatCurrency, side, page, pageSize }) => {
|
|
106
|
+
try {
|
|
107
|
+
const items = await fetchAds(apiKey, {
|
|
108
|
+
cryptoCurrency,
|
|
109
|
+
fiatCurrency,
|
|
110
|
+
side,
|
|
111
|
+
page,
|
|
112
|
+
pageSize,
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: "text",
|
|
118
|
+
text: JSON.stringify({
|
|
119
|
+
totalResults: items.length,
|
|
120
|
+
cryptoCurrency,
|
|
121
|
+
fiatCurrency,
|
|
122
|
+
side,
|
|
123
|
+
ads: items.map((item) => ({
|
|
124
|
+
id: item.id,
|
|
125
|
+
nickname: item.nickname,
|
|
126
|
+
price: item.price,
|
|
127
|
+
availableQuantity: item.lastQuantity,
|
|
128
|
+
minAmount: item.minAmount,
|
|
129
|
+
maxAmount: item.maxAmount,
|
|
130
|
+
payments: item.payments,
|
|
131
|
+
completedOrders: item.orderNum,
|
|
132
|
+
completionRate: item.executeRate,
|
|
133
|
+
isOnline: item.isOnline,
|
|
134
|
+
merchantLevel: item.merchantLevel,
|
|
135
|
+
paymentPeriod: item.paymentPeriod,
|
|
136
|
+
autoAccept: item.isAutoAccept,
|
|
137
|
+
})),
|
|
138
|
+
}, null, 2),
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
return {
|
|
145
|
+
content: [
|
|
146
|
+
{
|
|
147
|
+
type: "text",
|
|
148
|
+
text: `Error fetching ads: ${error instanceof Error ? error.message : String(error)}`,
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
isError: true,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
// --- Tool: get_market_summary ---
|
|
156
|
+
server.tool("get_market_summary", "Get aggregated market analytics for a cryptocurrency/fiat pair including price statistics, payment method distribution, merchant levels, and trader metrics. This is an UNOFFICIAL tool.", {
|
|
157
|
+
cryptoCurrency: z
|
|
158
|
+
.string()
|
|
159
|
+
.describe('Cryptocurrency code, e.g. "USDT"'),
|
|
160
|
+
fiatCurrency: z
|
|
161
|
+
.string()
|
|
162
|
+
.describe('Fiat currency code, e.g. "RUB"'),
|
|
163
|
+
side: z.enum(["BUY", "SELL"]).describe("Trade side to analyze"),
|
|
164
|
+
}, async ({ cryptoCurrency, fiatCurrency, side }) => {
|
|
165
|
+
try {
|
|
166
|
+
const items = await fetchAds(apiKey, {
|
|
167
|
+
cryptoCurrency,
|
|
168
|
+
fiatCurrency,
|
|
169
|
+
side,
|
|
170
|
+
pageSize: 50,
|
|
171
|
+
});
|
|
172
|
+
const priceStats = calcPriceSpread(items);
|
|
173
|
+
const paymentMethods = {};
|
|
174
|
+
for (const item of items) {
|
|
175
|
+
for (const method of item.payments) {
|
|
176
|
+
paymentMethods[method] = (paymentMethods[method] ?? 0) + 1;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const merchantDist = {};
|
|
180
|
+
for (const item of items) {
|
|
181
|
+
merchantDist[item.merchantLevel] =
|
|
182
|
+
(merchantDist[item.merchantLevel] ?? 0) + 1;
|
|
183
|
+
}
|
|
184
|
+
const avgRate = items.length > 0
|
|
185
|
+
? items.reduce((s, i) => s + parseFloat(i.executeRate), 0) /
|
|
186
|
+
items.length
|
|
187
|
+
: 0;
|
|
188
|
+
const summary = {
|
|
189
|
+
cryptoCurrency,
|
|
190
|
+
fiatCurrency,
|
|
191
|
+
side,
|
|
192
|
+
totalAds: items.length,
|
|
193
|
+
priceStats,
|
|
194
|
+
onlineTraders: items.filter((i) => i.isOnline).length,
|
|
195
|
+
autoAcceptAds: items.filter((i) => i.isAutoAccept).length,
|
|
196
|
+
paymentMethods,
|
|
197
|
+
merchantDistribution: merchantDist,
|
|
198
|
+
avgCompletionRate: avgRate.toFixed(4),
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
content: [
|
|
202
|
+
{
|
|
203
|
+
type: "text",
|
|
204
|
+
text: JSON.stringify(summary, null, 2),
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
return {
|
|
211
|
+
content: [
|
|
212
|
+
{
|
|
213
|
+
type: "text",
|
|
214
|
+
text: `Error generating summary: ${error instanceof Error ? error.message : String(error)}`,
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
isError: true,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
// --- Tool: get_best_price ---
|
|
222
|
+
server.tool("get_best_price", "Find the best available price for buying or selling crypto on the P2P market. Returns the top ad with the most favorable price. This is an UNOFFICIAL tool.", {
|
|
223
|
+
cryptoCurrency: z
|
|
224
|
+
.string()
|
|
225
|
+
.describe('Cryptocurrency code, e.g. "USDT"'),
|
|
226
|
+
fiatCurrency: z
|
|
227
|
+
.string()
|
|
228
|
+
.describe('Fiat currency code, e.g. "RUB"'),
|
|
229
|
+
side: z
|
|
230
|
+
.enum(["BUY", "SELL"])
|
|
231
|
+
.describe("Trade side: BUY = find cheapest to buy, SELL = find highest to sell"),
|
|
232
|
+
}, async ({ cryptoCurrency, fiatCurrency, side }) => {
|
|
233
|
+
try {
|
|
234
|
+
const items = await fetchAds(apiKey, {
|
|
235
|
+
cryptoCurrency,
|
|
236
|
+
fiatCurrency,
|
|
237
|
+
side,
|
|
238
|
+
pageSize: 50,
|
|
239
|
+
});
|
|
240
|
+
if (items.length === 0) {
|
|
241
|
+
return {
|
|
242
|
+
content: [
|
|
243
|
+
{
|
|
244
|
+
type: "text",
|
|
245
|
+
text: JSON.stringify({
|
|
246
|
+
message: "No ads found for the specified criteria.",
|
|
247
|
+
cryptoCurrency,
|
|
248
|
+
fiatCurrency,
|
|
249
|
+
side,
|
|
250
|
+
}),
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
const best = items.reduce((best, item) => {
|
|
256
|
+
const bestVal = parseFloat(best.price);
|
|
257
|
+
const itemVal = parseFloat(item.price);
|
|
258
|
+
if (side === "BUY") {
|
|
259
|
+
return itemVal < bestVal ? item : best;
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
return itemVal > bestVal ? item : best;
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
return {
|
|
266
|
+
content: [
|
|
267
|
+
{
|
|
268
|
+
type: "text",
|
|
269
|
+
text: JSON.stringify({
|
|
270
|
+
cryptoCurrency,
|
|
271
|
+
fiatCurrency,
|
|
272
|
+
side,
|
|
273
|
+
bestPrice: best.price,
|
|
274
|
+
trader: {
|
|
275
|
+
nickname: best.nickname,
|
|
276
|
+
merchantLevel: best.merchantLevel,
|
|
277
|
+
completedOrders: best.orderNum,
|
|
278
|
+
completionRate: best.executeRate,
|
|
279
|
+
isOnline: best.isOnline,
|
|
280
|
+
},
|
|
281
|
+
availableQuantity: best.lastQuantity,
|
|
282
|
+
amountRange: {
|
|
283
|
+
min: best.minAmount,
|
|
284
|
+
max: best.maxAmount,
|
|
285
|
+
},
|
|
286
|
+
payments: best.payments,
|
|
287
|
+
autoAccept: best.isAutoAccept,
|
|
288
|
+
paymentPeriod: best.paymentPeriod,
|
|
289
|
+
totalAdsScanned: items.length,
|
|
290
|
+
}, null, 2),
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
return {
|
|
297
|
+
content: [
|
|
298
|
+
{
|
|
299
|
+
type: "text",
|
|
300
|
+
text: `Error finding best price: ${error instanceof Error ? error.message : String(error)}`,
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
isError: true,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
// --- Start server ---
|
|
308
|
+
async function main() {
|
|
309
|
+
const transport = new StdioServerTransport();
|
|
310
|
+
await server.connect(transport);
|
|
311
|
+
console.error("Telegram Wallet P2P MCP Server running on stdio");
|
|
312
|
+
}
|
|
313
|
+
main().catch((error) => {
|
|
314
|
+
console.error("Fatal error:", error);
|
|
315
|
+
process.exit(1);
|
|
316
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "telegram-wallet-p2p-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Unofficial MCP server for Telegram Wallet P2P market data analytics",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"telegram-wallet-p2p-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "npx -p typescript tsc",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"telegram",
|
|
21
|
+
"wallet",
|
|
22
|
+
"p2p",
|
|
23
|
+
"mcp",
|
|
24
|
+
"model-context-protocol",
|
|
25
|
+
"crypto",
|
|
26
|
+
"analytics"
|
|
27
|
+
],
|
|
28
|
+
"author": "Furkan Köykıran",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/furkankoykiran/telegram-wallet-p2p-sdk",
|
|
33
|
+
"directory": "packages/mcp"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18.0.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.27.0",
|
|
40
|
+
"zod": "^3.25.76"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^20.19.33",
|
|
44
|
+
"typescript": "^5.4.0"
|
|
45
|
+
}
|
|
46
|
+
}
|