@hopivia/mcp 0.0.0-stage → 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 +77 -2
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +35 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +24 -0
- package/dist/client.js +61 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +173 -0
- package/dist/server.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/package.json +43 -4
package/README.md
CHANGED
|
@@ -1,3 +1,78 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @hopivia/mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
MCP server for the [Hopivia API](https://hopivia.com/docs): the best price across every major DEX of a network, a Tron ↔ EVM USDT bridge and token safety checks — as tools for Claude, Cursor, Windsurf and any other [Model Context Protocol](https://modelcontextprotocol.io) client.
|
|
4
|
+
|
|
5
|
+
The server runs on your machine and talks to `https://hopivia.com/api/v1` over HTTPS. It never sees a private key and never sends anything on-chain: the write tools return the same **unsigned transactions** as the REST API, and the agent signs them with its own wallet.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Claude Code:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
claude mcp add hopivia -- npx -y @hopivia/mcp
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Claude Desktop, Cursor, Windsurf — add to the client's MCP config (`claude_desktop_config.json`, `.cursor/mcp.json`, …):
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"hopivia": {
|
|
21
|
+
"command": "npx",
|
|
22
|
+
"args": ["-y", "@hopivia/mcp"],
|
|
23
|
+
"env": { "HOPIVIA_API_KEY": "hk_…" }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`HOPIVIA_API_KEY` is optional: without it requests run at the anonymous rate limit (30/min). Free keys (120/min) are issued at <https://hopivia.com/agents> by signing a message with a wallet — no gas, no registration.
|
|
30
|
+
|
|
31
|
+
## Tools
|
|
32
|
+
|
|
33
|
+
| Tool | What it does |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `list_chains` | networks, venues and bridge directions |
|
|
36
|
+
| `list_tokens` | known tokens of a chain (any ERC-20 also works by address) |
|
|
37
|
+
| `get_quote` | best same-chain price: amountOut, venue, route, price impact, fee |
|
|
38
|
+
| `build_swap_transactions` | unsigned approvals + swap in `steps`; optional `simulate`, `checkSafety`, `maxPriceImpactPct` |
|
|
39
|
+
| `get_bridge_quote` | cross-chain quote (EVM ↔ EVM via LI.FI, Tron ↔ EVM USDT via Symbiosis) |
|
|
40
|
+
| `build_bridge_transactions` | unsigned cross-chain steps (EVM calldata or TronWeb parameters) |
|
|
41
|
+
| `get_bridge_status` | status of a transfer by its source tx hash |
|
|
42
|
+
| `check_token` | metadata + GoPlus safety check (honeypot, taxes, owner privileges) |
|
|
43
|
+
| `get_balances` | native + token balances of an address |
|
|
44
|
+
| `api_key_info` | tier, limit and usage of the configured key |
|
|
45
|
+
|
|
46
|
+
Resource `hopivia://docs` — the full API guide as Markdown (same as <https://hopivia.com/docs.md>).
|
|
47
|
+
|
|
48
|
+
Refusals of the API (HTTP 422: `simulation_reverted`, `price_impact_too_high`, `token_risk_high`, `insufficient_balance`) come back as tool errors with the API's `error` and `message`, so the agent can explain and fix the request.
|
|
49
|
+
|
|
50
|
+
## Environment
|
|
51
|
+
|
|
52
|
+
| Variable | Default | Meaning |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `HOPIVIA_API_KEY` | — | `X-API-Key` for higher limits |
|
|
55
|
+
| `HOPIVIA_API_URL` | `https://hopivia.com/api/v1` | API base (point it at a local API for development) |
|
|
56
|
+
| `HOPIVIA_SITE_URL` | `https://hopivia.com` | site base for docs links and the docs resource |
|
|
57
|
+
|
|
58
|
+
## Programmatic use
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { createServer } from '@hopivia/mcp';
|
|
62
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
63
|
+
|
|
64
|
+
const server = createServer({ apiKey: process.env.HOPIVIA_API_KEY });
|
|
65
|
+
await server.connect(new StdioServerTransport());
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Development
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm install # at the repository root (workspaces)
|
|
72
|
+
npm run build -w @hopivia/mcp
|
|
73
|
+
npm test -w @hopivia/mcp # unit tests with a fake API
|
|
74
|
+
npm run smoke:mcp # end to end over stdio against https://hopivia.com (BASE=… to override)
|
|
75
|
+
npx @modelcontextprotocol/inspector node packages/mcp/dist/cli.js
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Publish: `npm version patch -w @hopivia/mcp && npm publish --access public -w @hopivia/mcp` (needs an npm account that owns the `hopivia` scope).
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// `npx @hopivia/mcp` — stdio MCP server for Claude Desktop, Claude Code, Cursor and any other MCP client.
|
|
3
|
+
// Configuration (all optional): HOPIVIA_API_KEY, HOPIVIA_API_URL (default https://hopivia.com/api/v1),
|
|
4
|
+
// HOPIVIA_SITE_URL (default https://hopivia.com).
|
|
5
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
6
|
+
import { createServer } from './server.js';
|
|
7
|
+
import { VERSION } from './version.js';
|
|
8
|
+
const arg = process.argv[2];
|
|
9
|
+
if (arg === '--version' || arg === '-v') {
|
|
10
|
+
console.log(VERSION);
|
|
11
|
+
process.exit(0);
|
|
12
|
+
}
|
|
13
|
+
if (arg === '--help' || arg === '-h') {
|
|
14
|
+
console.log(`@hopivia/mcp ${VERSION} — MCP server for the Hopivia API (https://hopivia.com/docs)
|
|
15
|
+
|
|
16
|
+
Usage: hopivia-mcp start the stdio server (what MCP clients run)
|
|
17
|
+
hopivia-mcp --version
|
|
18
|
+
|
|
19
|
+
Environment:
|
|
20
|
+
HOPIVIA_API_KEY optional X-API-Key; free keys at https://hopivia.com/agents
|
|
21
|
+
HOPIVIA_API_URL API base, default https://hopivia.com/api/v1
|
|
22
|
+
HOPIVIA_SITE_URL site base for docs links, default https://hopivia.com
|
|
23
|
+
|
|
24
|
+
Claude Code: claude mcp add hopivia -- npx -y @hopivia/mcp
|
|
25
|
+
Claude Desktop / Cursor: {"mcpServers":{"hopivia":{"command":"npx","args":["-y","@hopivia/mcp"]}}}`);
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
const server = createServer({
|
|
29
|
+
apiKey: process.env.HOPIVIA_API_KEY,
|
|
30
|
+
baseUrl: process.env.HOPIVIA_API_URL,
|
|
31
|
+
siteUrl: process.env.HOPIVIA_SITE_URL,
|
|
32
|
+
userAgent: `hopivia-mcp/${VERSION}`,
|
|
33
|
+
});
|
|
34
|
+
await server.connect(new StdioServerTransport());
|
|
35
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,0GAA0G;AAC1G,uGAAuG;AACvG,kDAAkD;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC5B,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AACD,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,gBAAgB,OAAO;;;;;;;;;;;mGAW8D,CAAC,CAAC;IACnG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,YAAY,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe;IACnC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe;IACpC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB;IACrC,SAAS,EAAE,eAAe,OAAO,EAAE;CACpC,CAAC,CAAC;AACH,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type ClientOptions = {
|
|
2
|
+
baseUrl?: string;
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
fetchImpl?: typeof fetch;
|
|
5
|
+
userAgent?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare class ApiError extends Error {
|
|
8
|
+
status: number;
|
|
9
|
+
body: unknown;
|
|
10
|
+
constructor(status: number, body: unknown);
|
|
11
|
+
}
|
|
12
|
+
type Query = Record<string, string | number | boolean | undefined>;
|
|
13
|
+
export declare class HopiviaClient {
|
|
14
|
+
readonly baseUrl: string;
|
|
15
|
+
private readonly apiKey?;
|
|
16
|
+
private readonly fetchImpl;
|
|
17
|
+
private readonly userAgent;
|
|
18
|
+
constructor(opts?: ClientOptions);
|
|
19
|
+
get hasKey(): boolean;
|
|
20
|
+
get<T = unknown>(path: string, query?: Query): Promise<T>;
|
|
21
|
+
post<T = unknown>(path: string, body: Record<string, unknown>): Promise<T>;
|
|
22
|
+
private send;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Thin client for the Hopivia REST API (https://hopivia.com/docs). The MCP tools are a 1:1 map of
|
|
2
|
+
// its endpoints, so everything the server returns (including 4xx refusals with their reasons)
|
|
3
|
+
// is passed to the agent as-is.
|
|
4
|
+
export class ApiError extends Error {
|
|
5
|
+
status;
|
|
6
|
+
body;
|
|
7
|
+
constructor(status, body) {
|
|
8
|
+
super(`Hopivia API ${status}`);
|
|
9
|
+
this.status = status;
|
|
10
|
+
this.body = body;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class HopiviaClient {
|
|
14
|
+
baseUrl;
|
|
15
|
+
apiKey;
|
|
16
|
+
fetchImpl;
|
|
17
|
+
userAgent;
|
|
18
|
+
constructor(opts = {}) {
|
|
19
|
+
this.baseUrl = (opts.baseUrl ?? 'https://hopivia.com/api/v1').replace(/\/+$/, '');
|
|
20
|
+
this.apiKey = opts.apiKey;
|
|
21
|
+
this.fetchImpl = opts.fetchImpl ?? fetch;
|
|
22
|
+
this.userAgent = opts.userAgent ?? 'hopivia-mcp';
|
|
23
|
+
}
|
|
24
|
+
get hasKey() {
|
|
25
|
+
return Boolean(this.apiKey);
|
|
26
|
+
}
|
|
27
|
+
async get(path, query = {}) {
|
|
28
|
+
const url = new URL(this.baseUrl + path);
|
|
29
|
+
for (const [k, v] of Object.entries(query)) {
|
|
30
|
+
if (v !== undefined && v !== '')
|
|
31
|
+
url.searchParams.set(k, String(v));
|
|
32
|
+
}
|
|
33
|
+
return this.send(url, { method: 'GET' });
|
|
34
|
+
}
|
|
35
|
+
async post(path, body) {
|
|
36
|
+
const clean = Object.fromEntries(Object.entries(body).filter(([, v]) => v !== undefined && v !== ''));
|
|
37
|
+
return this.send(new URL(this.baseUrl + path), {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: { 'content-type': 'application/json' },
|
|
40
|
+
body: JSON.stringify(clean),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async send(url, init) {
|
|
44
|
+
const headers = new Headers(init.headers);
|
|
45
|
+
headers.set('accept', 'application/json');
|
|
46
|
+
headers.set('user-agent', this.userAgent);
|
|
47
|
+
if (this.apiKey)
|
|
48
|
+
headers.set('x-api-key', this.apiKey);
|
|
49
|
+
const res = await this.fetchImpl(url, { ...init, headers });
|
|
50
|
+
const text = await res.text();
|
|
51
|
+
let json = text;
|
|
52
|
+
try {
|
|
53
|
+
json = text ? JSON.parse(text) : null;
|
|
54
|
+
}
|
|
55
|
+
catch { /* non-JSON body: keep the text */ }
|
|
56
|
+
if (!res.ok)
|
|
57
|
+
throw new ApiError(res.status, json);
|
|
58
|
+
return json;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAsB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAsB,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// MCP server for the Hopivia API: one tool per endpoint. Everything is read-only from the
|
|
2
|
+
// server's point of view — the write tools return UNSIGNED transactions that the agent signs
|
|
3
|
+
// with its own wallet. The server never sees a private key and never sends anything on-chain.
|
|
4
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { ApiError, HopiviaClient } from './client.js';
|
|
7
|
+
import { VERSION } from './version.js';
|
|
8
|
+
const CHAIN = 'Chain id or key: 56|bsc, 1|ethereum, 42161|arbitrum, 8453|base, 137|polygon, 10|optimism, 43114|avalanche, 204|opbnb. Call list_chains for the live set.';
|
|
9
|
+
const TOKEN = '"native" for the chain coin (BNB, ETH, POL…), a symbol from list_tokens (USDT, USDC, …) or a 0x address.';
|
|
10
|
+
const AMOUNT = 'Amount in human units, e.g. "0.5". Alternative: amountWei in the smallest unit.';
|
|
11
|
+
const SLIPPAGE = 'Slippage tolerance in basis points, 50 = 0.5% (default 50).';
|
|
12
|
+
const SIGNING_RULES = [
|
|
13
|
+
'The result contains unsigned transactions in `steps` — sign and send them with your own wallet, strictly in order, waiting for each to confirm.',
|
|
14
|
+
'Never ask the user for a private key; never send keys anywhere.',
|
|
15
|
+
'Quote first, show the user the amount out, the fee and the price impact, and get a confirmation before building and sending transactions.',
|
|
16
|
+
].join(' ');
|
|
17
|
+
const text = (data) => ({ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] });
|
|
18
|
+
const failure = (err) => {
|
|
19
|
+
if (err instanceof ApiError) {
|
|
20
|
+
// 4xx refusals carry a machine-readable `error` and a human `message`: pass them through so the
|
|
21
|
+
// agent can explain (and fix the request) instead of guessing
|
|
22
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: err.status, ...(typeof err.body === 'object' && err.body ? err.body : { message: String(err.body) }) }, null, 2) }] };
|
|
23
|
+
}
|
|
24
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify({ error: 'request_failed', message: err instanceof Error ? err.message : String(err) }) }] };
|
|
25
|
+
};
|
|
26
|
+
export function createServer(opts = {}) {
|
|
27
|
+
const api = new HopiviaClient(opts);
|
|
28
|
+
const siteUrl = (opts.siteUrl ?? 'https://hopivia.com').replace(/\/+$/, '');
|
|
29
|
+
const server = new McpServer({ name: 'hopivia', version: VERSION }, {
|
|
30
|
+
instructions: [
|
|
31
|
+
'Hopivia gives you the best price across every major DEX of a network, a Tron ↔ EVM USDT bridge and token safety checks.',
|
|
32
|
+
'Read tools: list_chains, list_tokens, get_quote, get_bridge_quote, get_bridge_status, check_token, get_balances.',
|
|
33
|
+
'Write tools (build_swap_transactions, build_bridge_transactions) return UNSIGNED transactions — you sign and send them yourself, in order.',
|
|
34
|
+
SIGNING_RULES,
|
|
35
|
+
`Full guide: ${siteUrl}/docs.md (also available as the resource hopivia://docs).`,
|
|
36
|
+
].join('\n'),
|
|
37
|
+
});
|
|
38
|
+
const run = async (fn) => {
|
|
39
|
+
try {
|
|
40
|
+
return text(await fn());
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
return failure(err);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
server.registerTool('list_chains', {
|
|
47
|
+
title: 'Supported chains',
|
|
48
|
+
description: 'Networks Hopivia supports and what each offers (same-chain venues, bridge directions, native coin). Call this first when unsure which chain key to use.',
|
|
49
|
+
inputSchema: {},
|
|
50
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
51
|
+
}, async () => run(() => api.get('/chains')));
|
|
52
|
+
server.registerTool('list_tokens', {
|
|
53
|
+
title: 'Known tokens of a chain',
|
|
54
|
+
description: 'Known tokens (symbol, address, decimals) of one chain. Any other ERC-20 can still be used by its 0x address in the other tools.',
|
|
55
|
+
inputSchema: {
|
|
56
|
+
chain: z.string().describe(CHAIN),
|
|
57
|
+
q: z.string().optional().describe('Filter by symbol, name or address.'),
|
|
58
|
+
},
|
|
59
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
60
|
+
}, async ({ chain, q }) => run(() => api.get('/tokens', { chain, q })));
|
|
61
|
+
server.registerTool('get_quote', {
|
|
62
|
+
title: 'Best same-chain price',
|
|
63
|
+
description: 'Best price for a same-chain swap across all connected DEXes. Returns amountOut, the venue and route, price impact, Hopivia fee (feeBps) and gas estimate. No transaction is built.',
|
|
64
|
+
inputSchema: {
|
|
65
|
+
chain: z.string().describe(CHAIN),
|
|
66
|
+
tokenIn: z.string().describe(TOKEN),
|
|
67
|
+
tokenOut: z.string().describe(TOKEN),
|
|
68
|
+
amount: z.string().optional().describe(AMOUNT),
|
|
69
|
+
amountWei: z.string().optional().describe('Amount in the smallest unit (alternative to amount).'),
|
|
70
|
+
slippageBps: z.number().int().min(1).max(5000).optional().describe(SLIPPAGE),
|
|
71
|
+
},
|
|
72
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
73
|
+
}, async (a) => run(() => api.get('/quote', a)));
|
|
74
|
+
server.registerTool('build_swap_transactions', {
|
|
75
|
+
title: 'Build same-chain swap transactions (unsigned)',
|
|
76
|
+
description: `Unsigned transactions for the best same-chain swap: approvals / Permit2 allowance first, then the swap, in \`steps\`. ${SIGNING_RULES} Optional safety rails: simulate (dry-run, reverts are refused), checkSafety (GoPlus check of tokenOut, high risk refused with 422), maxPriceImpactPct.`,
|
|
77
|
+
inputSchema: {
|
|
78
|
+
chain: z.string().describe(CHAIN),
|
|
79
|
+
tokenIn: z.string().describe(TOKEN),
|
|
80
|
+
tokenOut: z.string().describe(TOKEN),
|
|
81
|
+
amount: z.string().optional().describe(AMOUNT),
|
|
82
|
+
amountWei: z.string().optional().describe('Amount in the smallest unit (alternative to amount).'),
|
|
83
|
+
from: z.string().describe('Sender 0x address — the wallet that will sign.'),
|
|
84
|
+
recipient: z.string().optional().describe('Recipient of tokenOut; defaults to from.'),
|
|
85
|
+
slippageBps: z.number().int().min(1).max(5000).optional().describe(SLIPPAGE),
|
|
86
|
+
simulate: z.boolean().optional().describe('Dry-run the swap with eth_estimateGas; a revert is refused with 422.'),
|
|
87
|
+
checkSafety: z.boolean().optional().describe('GoPlus check on tokenOut; risk "high" is refused with 422 unless allowRiskyToken.'),
|
|
88
|
+
allowRiskyToken: z.boolean().optional().describe('Build even if tokenOut is a honeypot / >50% sell tax / owner can mint or pause.'),
|
|
89
|
+
maxPriceImpactPct: z.number().min(0).max(100).optional().describe('Refuse with 422 price_impact_too_high above this percentage.'),
|
|
90
|
+
},
|
|
91
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
92
|
+
}, async (a) => run(() => api.post('/swap/tx', a)));
|
|
93
|
+
server.registerTool('get_bridge_quote', {
|
|
94
|
+
title: 'Cross-chain quote',
|
|
95
|
+
description: 'Quote for a cross-chain swap: EVM ↔ EVM via LI.FI, Tron ↔ EVM via Symbiosis (USDT only on the Tron side). Returns amountOut, fees in USD, estimated time and warnings (e.g. Tron Energy needs). Bridging small amounts loses a large share to fixed fees — the quote warns above 10%.',
|
|
96
|
+
inputSchema: {
|
|
97
|
+
fromChain: z.string().describe(`${CHAIN} Plus "tron" (USDT only).`),
|
|
98
|
+
toChain: z.string().describe(`${CHAIN} Plus "tron" (USDT only).`),
|
|
99
|
+
fromToken: z.string().describe(TOKEN),
|
|
100
|
+
toToken: z.string().describe(TOKEN),
|
|
101
|
+
amount: z.string().optional().describe(AMOUNT),
|
|
102
|
+
amountWei: z.string().optional().describe('Amount in the smallest unit (alternative to amount).'),
|
|
103
|
+
from: z.string().optional().describe('Sender on fromChain (0x… or T…). Required later for build_bridge_transactions.'),
|
|
104
|
+
to: z.string().optional().describe('Recipient on toChain. Required when the address formats differ (Tron ↔ EVM) — always confirm it with the user.'),
|
|
105
|
+
slippageBps: z.number().int().min(1).max(5000).optional().describe(SLIPPAGE),
|
|
106
|
+
},
|
|
107
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
108
|
+
}, async (a) => run(() => api.get('/bridge/quote', a)));
|
|
109
|
+
server.registerTool('build_bridge_transactions', {
|
|
110
|
+
title: 'Build cross-chain transactions (unsigned)',
|
|
111
|
+
description: `Unsigned transactions for a cross-chain swap in \`steps\` (EVM: approve + bridge call; Tron: tron-approve + tron-call with what TronWeb needs). ${SIGNING_RULES} For Tron ↔ EVM always pass \`to\` in the destination network's format and confirm it with the user.`,
|
|
112
|
+
inputSchema: {
|
|
113
|
+
fromChain: z.string().describe(`${CHAIN} Plus "tron" (USDT only).`),
|
|
114
|
+
toChain: z.string().describe(`${CHAIN} Plus "tron" (USDT only).`),
|
|
115
|
+
fromToken: z.string().describe(TOKEN),
|
|
116
|
+
toToken: z.string().describe(TOKEN),
|
|
117
|
+
amount: z.string().optional().describe(AMOUNT),
|
|
118
|
+
amountWei: z.string().optional().describe('Amount in the smallest unit (alternative to amount).'),
|
|
119
|
+
from: z.string().describe('Sender on fromChain (0x… or T…) — the wallet that will sign.'),
|
|
120
|
+
to: z.string().optional().describe('Recipient on toChain; required when the address formats differ (Tron ↔ EVM).'),
|
|
121
|
+
slippageBps: z.number().int().min(1).max(5000).optional().describe(SLIPPAGE),
|
|
122
|
+
},
|
|
123
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
124
|
+
}, async (a) => run(() => api.post('/bridge/tx', a)));
|
|
125
|
+
server.registerTool('get_bridge_status', {
|
|
126
|
+
title: 'Cross-chain transfer status',
|
|
127
|
+
description: 'Status of a cross-chain transfer by its source transaction hash: pending / done / failed, destination tx hash when known. Poll every ~30 s; Tron ↔ EVM usually takes 2–10 minutes.',
|
|
128
|
+
inputSchema: {
|
|
129
|
+
provider: z.enum(['lifi', 'symbiosis']).describe('Provider named in the bridge quote / tx response.'),
|
|
130
|
+
txHash: z.string().describe('Source-chain transaction hash of the bridge call.'),
|
|
131
|
+
fromChain: z.string().describe(`${CHAIN} Plus "tron".`),
|
|
132
|
+
toChain: z.string().describe(`${CHAIN} Plus "tron".`),
|
|
133
|
+
bridge: z.string().optional().describe('LI.FI tool name from build_bridge_transactions (LI.FI only).'),
|
|
134
|
+
},
|
|
135
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
136
|
+
}, async (a) => run(() => api.get('/bridge/status', a)));
|
|
137
|
+
server.registerTool('check_token', {
|
|
138
|
+
title: 'Token metadata + safety check',
|
|
139
|
+
description: 'Token metadata (symbol, decimals, name) and a GoPlus safety check: honeypot, buy/sell tax, owner privileges (mint, pause, blacklist), with an overall risk level. Run it before buying anything the user did not name explicitly.',
|
|
140
|
+
inputSchema: {
|
|
141
|
+
chain: z.string().describe(CHAIN),
|
|
142
|
+
address: z.string().describe('0x token address.'),
|
|
143
|
+
},
|
|
144
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
145
|
+
}, async (a) => run(() => api.get('/token/check', a)));
|
|
146
|
+
server.registerTool('get_balances', {
|
|
147
|
+
title: 'Balances of an address',
|
|
148
|
+
description: 'Native coin and known-token balances of an address on one chain (plus any extra token addresses you pass). Use it to check the user has enough tokenIn and gas before building transactions.',
|
|
149
|
+
inputSchema: {
|
|
150
|
+
chain: z.string().describe(CHAIN),
|
|
151
|
+
address: z.string().describe('0x address to inspect.'),
|
|
152
|
+
tokens: z.string().optional().describe('Comma-separated extra 0x token addresses to include.'),
|
|
153
|
+
},
|
|
154
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
155
|
+
}, async (a) => run(() => api.get('/balances', a)));
|
|
156
|
+
server.registerTool('api_key_info', {
|
|
157
|
+
title: 'Current API key',
|
|
158
|
+
description: `Tier, rate limit and usage of the configured API key (HOPIVIA_API_KEY). Without a key the API still works at the anonymous limit; free keys are issued at ${siteUrl}/agents by signing a message with a wallet.`,
|
|
159
|
+
inputSchema: {},
|
|
160
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
161
|
+
}, async () => (api.hasKey ? run(() => api.get('/keys/me')) : text({ configured: false, hint: `No HOPIVIA_API_KEY set — requests run at the anonymous rate limit. Get a free key at ${siteUrl}/agents.` })));
|
|
162
|
+
// The guide the tools are documented in, as a resource the client can attach to context
|
|
163
|
+
server.registerResource('docs', 'hopivia://docs', {
|
|
164
|
+
title: 'Hopivia API guide',
|
|
165
|
+
description: 'The full API guide as Markdown: quick start, every endpoint, errors and refusals, fees, rules for AI agents.',
|
|
166
|
+
mimeType: 'text/markdown',
|
|
167
|
+
}, async (uri) => {
|
|
168
|
+
const res = await (opts.fetchImpl ?? fetch)(`${siteUrl}/docs.md`, { headers: { accept: 'text/markdown' } });
|
|
169
|
+
return { contents: [{ uri: uri.href, mimeType: 'text/markdown', text: await res.text() }] };
|
|
170
|
+
});
|
|
171
|
+
return server;
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const VERSION = "0.1.0";
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hopivia/mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for the Hopivia API: best-price DEX quotes, unsigned swap and bridge transactions, token safety checks — as tools for Claude, Cursor and other MCP clients",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"homepage": "https://hopivia.com/docs#mcp-server",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/gyuikyh/dee-back.git",
|
|
11
|
+
"directory": "packages/mcp"
|
|
12
|
+
},
|
|
13
|
+
"keywords": ["mcp", "model-context-protocol", "dex", "defi", "swap", "bridge", "hopivia", "ai-agents"],
|
|
14
|
+
"bin": {
|
|
15
|
+
"hopivia-mcp": "./dist/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc -b && node -e \"require('fs').chmodSync('dist/cli.js', 0o755)\"",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"version": "node -e \"const v=require('./package.json').version;require('fs').writeFileSync('src/version.ts','// Kept in sync with package.json by `npm version` (see the \\\"version\\\" script there)\\nexport const VERSION = \\''+v+'\\';\\n')\" && git add src/version.ts",
|
|
36
|
+
"prepublishOnly": "npm run build && npm test"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.32.0",
|
|
40
|
+
"zod": "^3.25.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"vitest": "^3.0.0"
|
|
44
|
+
}
|
|
45
|
+
}
|