@tongateway/mcp 0.1.0 → 0.2.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 +43 -0
- package/dist/index.js +113 -7
- package/package.json +14 -5
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @tongateway/mcp
|
|
2
|
+
|
|
3
|
+
MCP server for [Agent Gateway](https://github.com/pewpewgogo/ton-agent-gateway) — lets AI agents request TON blockchain transfers via Model Context Protocol.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @tongateway/mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configure
|
|
12
|
+
|
|
13
|
+
Add to your MCP client config (Claude Code, Cursor, etc.):
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"mcpServers": {
|
|
18
|
+
"tongateway": {
|
|
19
|
+
"command": "tongateway-mcp",
|
|
20
|
+
"env": {
|
|
21
|
+
"AGENT_GATEWAY_TOKEN": "YOUR_TOKEN_HERE",
|
|
22
|
+
"AGENT_GATEWAY_API_URL": "https://api.tongateway.ai"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Get your token at [tongateway.ai/app.html](https://tongateway.ai/app.html).
|
|
30
|
+
|
|
31
|
+
## Tools
|
|
32
|
+
|
|
33
|
+
| Tool | Description |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `request_transfer` | Request a TON transfer (to, amountNano, payloadBoc?) |
|
|
36
|
+
| `get_request_status` | Check status of a request by ID |
|
|
37
|
+
| `list_pending_requests` | List all pending requests |
|
|
38
|
+
|
|
39
|
+
## Links
|
|
40
|
+
|
|
41
|
+
- [Agent Gateway](https://github.com/pewpewgogo/ton-agent-gateway) — main repo with all links
|
|
42
|
+
- [Dashboard](https://tongateway.ai) — connect wallet & manage tokens
|
|
43
|
+
- [API Docs](https://api.tongateway.ai/docs) — Swagger UI
|
package/dist/index.js
CHANGED
|
@@ -3,17 +3,18 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
const API_URL = process.env.AGENT_GATEWAY_API_URL ?? 'https://api.tongateway.ai';
|
|
6
|
-
|
|
7
|
-
if (!TOKEN) {
|
|
8
|
-
console.error('AGENT_GATEWAY_TOKEN environment variable is required');
|
|
9
|
-
process.exit(1);
|
|
10
|
-
}
|
|
6
|
+
let TOKEN = process.env.AGENT_GATEWAY_TOKEN || '';
|
|
11
7
|
async function apiCall(path, options = {}) {
|
|
8
|
+
const headers = {
|
|
9
|
+
'Content-Type': 'application/json',
|
|
10
|
+
};
|
|
11
|
+
if (TOKEN) {
|
|
12
|
+
headers['Authorization'] = `Bearer ${TOKEN}`;
|
|
13
|
+
}
|
|
12
14
|
const res = await fetch(`${API_URL}${path}`, {
|
|
13
15
|
...options,
|
|
14
16
|
headers: {
|
|
15
|
-
|
|
16
|
-
Authorization: `Bearer ${TOKEN}`,
|
|
17
|
+
...headers,
|
|
17
18
|
...options.headers,
|
|
18
19
|
},
|
|
19
20
|
});
|
|
@@ -27,11 +28,104 @@ const server = new McpServer({
|
|
|
27
28
|
name: 'agent-gateway',
|
|
28
29
|
version: '0.1.0',
|
|
29
30
|
});
|
|
31
|
+
server.tool('request_auth', 'Request wallet authentication. Generates a one-time link for the user to connect their TON wallet. After the user connects, use get_auth_token to retrieve the token. Use this when no token is configured.', {
|
|
32
|
+
label: z.string().optional().describe('Label for this agent session (e.g. "claude-agent")'),
|
|
33
|
+
}, async ({ label }) => {
|
|
34
|
+
try {
|
|
35
|
+
const result = await fetch(`${API_URL}/v1/auth/request`, {
|
|
36
|
+
method: 'POST',
|
|
37
|
+
headers: { 'Content-Type': 'application/json' },
|
|
38
|
+
body: JSON.stringify({ label: label || 'agent' }),
|
|
39
|
+
});
|
|
40
|
+
const data = await result.json();
|
|
41
|
+
if (!result.ok)
|
|
42
|
+
throw new Error(data.error ?? 'Failed');
|
|
43
|
+
return {
|
|
44
|
+
content: [
|
|
45
|
+
{
|
|
46
|
+
type: 'text',
|
|
47
|
+
text: [
|
|
48
|
+
`Authentication requested.`,
|
|
49
|
+
``,
|
|
50
|
+
`Ask the user to open this link:`,
|
|
51
|
+
data.authUrl,
|
|
52
|
+
``,
|
|
53
|
+
`Auth ID: ${data.authId}`,
|
|
54
|
+
`Expires: ${new Date(data.expiresAt).toISOString()}`,
|
|
55
|
+
``,
|
|
56
|
+
`After the user connects their wallet, call get_auth_token with this authId to get the token.`,
|
|
57
|
+
].join('\n'),
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
return {
|
|
64
|
+
content: [{ type: 'text', text: `Error: ${e.message}` }],
|
|
65
|
+
isError: true,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
server.tool('get_auth_token', 'Check if the user has completed wallet authentication and retrieve the token. Call this after request_auth once the user has opened the link and connected their wallet.', {
|
|
70
|
+
authId: z.string().describe('The authId returned by request_auth'),
|
|
71
|
+
}, async ({ authId }) => {
|
|
72
|
+
try {
|
|
73
|
+
const result = await fetch(`${API_URL}/v1/auth/check/${authId}`, {
|
|
74
|
+
headers: { 'Content-Type': 'application/json' },
|
|
75
|
+
});
|
|
76
|
+
const data = await result.json();
|
|
77
|
+
if (!result.ok)
|
|
78
|
+
throw new Error(data.error ?? 'Failed');
|
|
79
|
+
if (data.status === 'pending') {
|
|
80
|
+
return {
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: 'text',
|
|
84
|
+
text: [
|
|
85
|
+
`Authentication still pending.`,
|
|
86
|
+
`The user has not connected their wallet yet.`,
|
|
87
|
+
``,
|
|
88
|
+
`Wait a moment and try again.`,
|
|
89
|
+
].join('\n'),
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Store the token for future API calls
|
|
95
|
+
TOKEN = data.token;
|
|
96
|
+
return {
|
|
97
|
+
content: [
|
|
98
|
+
{
|
|
99
|
+
type: 'text',
|
|
100
|
+
text: [
|
|
101
|
+
`Authentication complete!`,
|
|
102
|
+
`Token received and configured.`,
|
|
103
|
+
`Wallet: ${data.address}`,
|
|
104
|
+
``,
|
|
105
|
+
`You can now use request_transfer, get_request_status, and list_pending_requests.`,
|
|
106
|
+
].join('\n'),
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
return {
|
|
113
|
+
content: [{ type: 'text', text: `Error: ${e.message}` }],
|
|
114
|
+
isError: true,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
});
|
|
30
118
|
server.tool('request_transfer', 'Request a TON transfer from the wallet owner. The request will be queued and the owner must approve it via TON Connect.', {
|
|
31
119
|
to: z.string().describe('Destination TON address'),
|
|
32
120
|
amountNano: z.string().describe('Amount in nanoTON (1 TON = 1000000000)'),
|
|
33
121
|
payloadBoc: z.string().optional().describe('Optional BOC-encoded payload for the transaction'),
|
|
34
122
|
}, async ({ to, amountNano, payloadBoc }) => {
|
|
123
|
+
if (!TOKEN) {
|
|
124
|
+
return {
|
|
125
|
+
content: [{ type: 'text', text: 'No token configured. Use request_auth first to authenticate.' }],
|
|
126
|
+
isError: true,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
35
129
|
try {
|
|
36
130
|
const body = { to, amountNano };
|
|
37
131
|
if (payloadBoc)
|
|
@@ -68,6 +162,12 @@ server.tool('request_transfer', 'Request a TON transfer from the wallet owner. T
|
|
|
68
162
|
server.tool('get_request_status', 'Check the status of a previously submitted transfer request.', {
|
|
69
163
|
id: z.string().describe('The request ID returned by request_transfer'),
|
|
70
164
|
}, async ({ id }) => {
|
|
165
|
+
if (!TOKEN) {
|
|
166
|
+
return {
|
|
167
|
+
content: [{ type: 'text', text: 'No token configured. Use request_auth first to authenticate.' }],
|
|
168
|
+
isError: true,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
71
171
|
try {
|
|
72
172
|
const result = await apiCall(`/v1/safe/tx/${id}`);
|
|
73
173
|
return {
|
|
@@ -97,6 +197,12 @@ server.tool('get_request_status', 'Check the status of a previously submitted tr
|
|
|
97
197
|
}
|
|
98
198
|
});
|
|
99
199
|
server.tool('list_pending_requests', 'List all pending transfer requests waiting for wallet owner approval.', {}, async () => {
|
|
200
|
+
if (!TOKEN) {
|
|
201
|
+
return {
|
|
202
|
+
content: [{ type: 'text', text: 'No token configured. Use request_auth first to authenticate.' }],
|
|
203
|
+
isError: true,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
100
206
|
try {
|
|
101
207
|
const data = await apiCall('/v1/safe/tx/pending');
|
|
102
208
|
const requests = data.requests;
|
package/package.json
CHANGED
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tongateway/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "MCP server for Agent Gateway — lets AI agents request TON blockchain transfers",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "https://github.com/tongateway/
|
|
8
|
+
"url": "https://github.com/tongateway/mcp"
|
|
9
9
|
},
|
|
10
|
-
"keywords": [
|
|
10
|
+
"keywords": [
|
|
11
|
+
"mcp",
|
|
12
|
+
"ton",
|
|
13
|
+
"blockchain",
|
|
14
|
+
"agent",
|
|
15
|
+
"ai",
|
|
16
|
+
"wallet"
|
|
17
|
+
],
|
|
11
18
|
"type": "module",
|
|
12
19
|
"bin": {
|
|
13
20
|
"agent-gateway-mcp": "./dist/index.js"
|
|
14
21
|
},
|
|
15
|
-
"files": [
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
16
25
|
"scripts": {
|
|
17
26
|
"build": "tsc",
|
|
18
|
-
"dev": "tsx src/index.ts"
|
|
27
|
+
"dev": "tsx src/index.ts"
|
|
19
28
|
},
|
|
20
29
|
"dependencies": {
|
|
21
30
|
"@modelcontextprotocol/sdk": "^1.12.1",
|