@dritan/mcp 0.6.1 → 0.8.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 +5 -2
- package/dist/index.js +80 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -72,22 +72,25 @@ npm run build && npm start
|
|
|
72
72
|
- `ths_get_score`
|
|
73
73
|
- `ths_get_score_tokens_get`
|
|
74
74
|
- `ths_get_score_tokens_post`
|
|
75
|
+
- `ths_get_top_wallets`
|
|
75
76
|
- `swap_build`
|
|
76
77
|
- `swap_sign_and_broadcast`
|
|
77
78
|
- `swap_build_sign_and_broadcast`
|
|
78
79
|
|
|
79
80
|
## Notes
|
|
80
81
|
|
|
81
|
-
- Wallets default to
|
|
82
|
+
- Wallets default to the current working directory (`process.cwd()`).
|
|
82
83
|
- Private keys never leave local files; only public address/signature are returned.
|
|
83
84
|
- `swap_sign_and_broadcast` signs locally, then broadcasts via Dritan.
|
|
84
85
|
- `auth_set_api_key` activates a key for the running MCP process without restart.
|
|
86
|
+
- `auth_set_api_key` and successful `x402_create_api_key` responses include a capability summary so agents can immediately guide users to next actions.
|
|
85
87
|
- Agent onboarding without `DRITAN_API_KEY` should present two options:
|
|
86
|
-
- Option 1: paid x402 flow (`
|
|
88
|
+
- Option 1: paid x402 flow (`wallet_create_local` in current directory -> share wallet + backup file path -> user chooses SOL amount and funds agent wallet -> if no key exists use `x402_create_api_key_quote` -> `wallet_transfer_sol` -> `x402_create_api_key`).
|
|
87
89
|
- Option 2: user gets a free key at `https://dritan.dev`.
|
|
88
90
|
- `x402_create_api_key` auto-activates returned keys for the current MCP session.
|
|
89
91
|
- `token_get_ohlcv_chart` returns a shareable chart URL plus a ready-to-send markdown image snippet.
|
|
90
92
|
- `token_get_ohlcv_chart` supports `chartType: "line-volume" | "candlestick"` (default is `candlestick`).
|
|
93
|
+
- `ths_get_top_wallets` returns a paginated leaderboard of THS-ranked wallets (`page`, `limit`) for smart-wallet discovery workflows.
|
|
91
94
|
- Ticker workflow for chart requests: `token_search` -> extract mint -> `token_get_ohlcv` or `token_get_ohlcv_chart`.
|
|
92
95
|
- If users ask for `$WIF` style symbols, always resolve mint with `token_search` first.
|
|
93
96
|
- If Solana CLI is missing, run `system_check_prereqs` and follow returned install steps.
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { mkdirSync, readFileSync, existsSync } from "node:fs";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
3
|
import { dirname, join, resolve } from "node:path";
|
|
5
4
|
import { spawnSync } from "node:child_process";
|
|
6
5
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -9,7 +8,7 @@ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextpro
|
|
|
9
8
|
import { DritanClient, MeteoraThsClient, } from "dritan-sdk";
|
|
10
9
|
import { Connection, Keypair, PublicKey, SystemProgram, Transaction, VersionedTransaction, clusterApiUrl, } from "@solana/web3.js";
|
|
11
10
|
import { z } from "zod";
|
|
12
|
-
const DEFAULT_WALLET_DIR =
|
|
11
|
+
const DEFAULT_WALLET_DIR = process.cwd();
|
|
13
12
|
const LAMPORTS_PER_SOL = 1_000_000_000;
|
|
14
13
|
function normalizeApiKey(value) {
|
|
15
14
|
const trimmed = value?.trim();
|
|
@@ -68,7 +67,10 @@ const server = new Server({
|
|
|
68
67
|
},
|
|
69
68
|
instructions: [
|
|
70
69
|
"This server supports two API-key onboarding options when DRITAN_API_KEY is missing:",
|
|
71
|
-
"1) x402 pay-per-use key flow:
|
|
70
|
+
"1) x402 pay-per-use key flow:",
|
|
71
|
+
" a) Create a local agent wallet with wallet_create_local (saved in current working directory by default).",
|
|
72
|
+
" b) Ask user how much SOL they want to allocate and provide both wallet address and backup file path.",
|
|
73
|
+
" c) If no active key exists, create quote -> pay from agent wallet -> claim key.",
|
|
72
74
|
"2) Free key flow: user creates a free API key at https://dritan.dev.",
|
|
73
75
|
"After key is obtained, set it with auth_set_api_key (no restart needed), or restart with DRITAN_API_KEY configured.",
|
|
74
76
|
"Suggested setup command:",
|
|
@@ -82,10 +84,24 @@ function missingApiKeyError() {
|
|
|
82
84
|
return new Error([
|
|
83
85
|
"Missing DRITAN_API_KEY in environment.",
|
|
84
86
|
"Option 1 (paid): use x402 tools (x402_get_pricing, x402_create_api_key_quote, x402_create_api_key) and wallet tools.",
|
|
87
|
+
"Paid flow order: create wallet in current directory -> tell user funding amount + backup file path -> if no key exists then create/claim x402 key.",
|
|
85
88
|
"Option 2 (free): create a free key at https://dritan.dev and set DRITAN_API_KEY.",
|
|
86
89
|
"You can activate a key immediately with auth_set_api_key without restarting MCP.",
|
|
87
90
|
].join(" "));
|
|
88
91
|
}
|
|
92
|
+
const postAuthCapabilities = [
|
|
93
|
+
"Token intelligence: token search, price, metadata, risk, first buyers, deployer stats.",
|
|
94
|
+
"Charts: OHLCV data and shareable line-volume/candlestick chart URLs.",
|
|
95
|
+
"Wallet analytics: summary, holdings, trade history, performance, and portfolio charts.",
|
|
96
|
+
"Trader discovery: Meteora THS wallet score lookups plus top-wallet leaderboard.",
|
|
97
|
+
"Execution: build/sign/broadcast swaps and monitor wallet/DEX streams.",
|
|
98
|
+
];
|
|
99
|
+
function buildPostAuthGuidance() {
|
|
100
|
+
return {
|
|
101
|
+
capabilities: postAuthCapabilities,
|
|
102
|
+
suggestedNextPrompt: "Tell me your goal and I can proceed: token research, smart-wallet discovery, chart generation, or swap execution.",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
89
105
|
function getDritanClient() {
|
|
90
106
|
const apiKey = getActiveApiKey();
|
|
91
107
|
if (!apiKey) {
|
|
@@ -112,6 +128,24 @@ function getThsClient() {
|
|
|
112
128
|
baseUrl: process.env.METEORA_THS_BASE_URL,
|
|
113
129
|
});
|
|
114
130
|
}
|
|
131
|
+
async function getThsTopWallets(ths, options = {}) {
|
|
132
|
+
const sdkMethod = ths.getTopWalletsByScore;
|
|
133
|
+
if (typeof sdkMethod === "function") {
|
|
134
|
+
return await sdkMethod.call(ths, options);
|
|
135
|
+
}
|
|
136
|
+
const baseUrl = ths.baseUrl ?? "https://ths.dritan.dev";
|
|
137
|
+
const url = new URL("/ths/top-wallets", baseUrl);
|
|
138
|
+
if (options.page !== undefined)
|
|
139
|
+
url.searchParams.set("page", String(options.page));
|
|
140
|
+
if (options.limit !== undefined)
|
|
141
|
+
url.searchParams.set("limit", String(options.limit));
|
|
142
|
+
const res = await fetch(url.toString(), { method: "GET" });
|
|
143
|
+
if (!res.ok) {
|
|
144
|
+
const text = await res.text().catch(() => "");
|
|
145
|
+
throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);
|
|
146
|
+
}
|
|
147
|
+
return (await res.json());
|
|
148
|
+
}
|
|
115
149
|
async function searchTokens(client, query, options) {
|
|
116
150
|
const sdkSearch = client.searchTokens;
|
|
117
151
|
if (typeof sdkSearch === "function") {
|
|
@@ -440,7 +474,12 @@ function createLocalWalletFile(walletPath) {
|
|
|
440
474
|
throw new Error(`solana-keygen failed (${cmd.status}): ${cmd.stderr || cmd.stdout}`);
|
|
441
475
|
}
|
|
442
476
|
const keypair = loadKeypairFromPath(walletPath);
|
|
443
|
-
return {
|
|
477
|
+
return {
|
|
478
|
+
walletPath,
|
|
479
|
+
backupFilePath: walletPath,
|
|
480
|
+
walletDir: dir,
|
|
481
|
+
address: keypair.publicKey.toBase58(),
|
|
482
|
+
};
|
|
444
483
|
}
|
|
445
484
|
function loadKeypairFromPath(walletPath) {
|
|
446
485
|
const bytes = JSON.parse(readFileSync(walletPath, "utf8"));
|
|
@@ -558,6 +597,10 @@ const thsScoreSchema = z.object({
|
|
|
558
597
|
const thsScoreTokensSchema = thsScoreSchema.extend({
|
|
559
598
|
tokenMints: z.array(z.string().min(1)).min(1).max(200),
|
|
560
599
|
});
|
|
600
|
+
const thsTopWalletsSchema = z.object({
|
|
601
|
+
page: z.number().int().min(1).optional(),
|
|
602
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
603
|
+
});
|
|
561
604
|
const swapBuildSchema = z.object({
|
|
562
605
|
walletPath: z.string().min(1).optional(),
|
|
563
606
|
userPublicKey: z.string().min(1).optional(),
|
|
@@ -988,6 +1031,17 @@ const tools = [
|
|
|
988
1031
|
},
|
|
989
1032
|
},
|
|
990
1033
|
},
|
|
1034
|
+
{
|
|
1035
|
+
name: "ths_get_top_wallets",
|
|
1036
|
+
description: "Fetch paginated top wallets ranked by THS score.",
|
|
1037
|
+
inputSchema: {
|
|
1038
|
+
type: "object",
|
|
1039
|
+
properties: {
|
|
1040
|
+
page: { type: "number" },
|
|
1041
|
+
limit: { type: "number" },
|
|
1042
|
+
},
|
|
1043
|
+
},
|
|
1044
|
+
},
|
|
991
1045
|
{
|
|
992
1046
|
name: "swap_build",
|
|
993
1047
|
description: "Build an unsigned swap transaction with Dritan.",
|
|
@@ -1061,11 +1115,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1061
1115
|
preview: apiKeyPreview(activeApiKey),
|
|
1062
1116
|
hint: apiKeySet
|
|
1063
1117
|
? "API key is configured."
|
|
1064
|
-
: "Missing DRITAN_API_KEY.
|
|
1118
|
+
: "Missing DRITAN_API_KEY. Use x402 flow (wallet in current directory, user funds it, then claim key) or get a free key at https://dritan.dev.",
|
|
1065
1119
|
},
|
|
1066
1120
|
],
|
|
1067
1121
|
nextAction: !apiKeySet
|
|
1068
|
-
? "Choose one: (1) x402 paid onboarding flow
|
|
1122
|
+
? "Choose one: (1) x402 paid onboarding flow: wallet_create_local -> share wallet + backup file path -> user funds -> x402 quote/claim, or (2) get a free key at https://dritan.dev and set DRITAN_API_KEY."
|
|
1069
1123
|
: !solanaCli.ok
|
|
1070
1124
|
? "Install Solana CLI using installHint, then retry wallet_create_local."
|
|
1071
1125
|
: "Environment ready.",
|
|
@@ -1079,9 +1133,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1079
1133
|
preview: apiKeyPreview(activeApiKey),
|
|
1080
1134
|
controlBaseUrl: getControlBaseUrl(),
|
|
1081
1135
|
onboardingOptions: [
|
|
1082
|
-
"Option 1 (paid x402): create wallet ->
|
|
1136
|
+
"Option 1 (paid x402): create wallet in current directory -> share wallet address and backup file path -> user funds wallet -> if no key exists, quote/transfer/claim key.",
|
|
1083
1137
|
"Option 2 (free): create key at https://dritan.dev and set it with auth_set_api_key.",
|
|
1084
1138
|
],
|
|
1139
|
+
...(activeApiKey ? buildPostAuthGuidance() : {}),
|
|
1085
1140
|
});
|
|
1086
1141
|
}
|
|
1087
1142
|
case "auth_set_api_key": {
|
|
@@ -1092,6 +1147,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1092
1147
|
message: "API key activated for this MCP session without restart.",
|
|
1093
1148
|
source: runtimeApiKeySource,
|
|
1094
1149
|
preview: apiKeyPreview(activated),
|
|
1150
|
+
...buildPostAuthGuidance(),
|
|
1095
1151
|
});
|
|
1096
1152
|
}
|
|
1097
1153
|
case "dritan_health": {
|
|
@@ -1101,7 +1157,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1101
1157
|
const input = walletCreateSchema.parse(args);
|
|
1102
1158
|
const walletPath = toWalletPath(input.name, input.walletDir);
|
|
1103
1159
|
const created = createLocalWalletFile(walletPath);
|
|
1104
|
-
return ok(
|
|
1160
|
+
return ok({
|
|
1161
|
+
...created,
|
|
1162
|
+
fundingInstruction: "Ask the user how much SOL they want to allocate to this wallet, and tell them this backup file path.",
|
|
1163
|
+
});
|
|
1105
1164
|
}
|
|
1106
1165
|
case "wallet_get_address": {
|
|
1107
1166
|
const input = walletPathSchema.parse(args);
|
|
@@ -1172,7 +1231,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1172
1231
|
return ok({
|
|
1173
1232
|
...(pricing ?? {}),
|
|
1174
1233
|
onboardingOptions: [
|
|
1175
|
-
"Option 1 (paid x402): create wallet ->
|
|
1234
|
+
"Option 1 (paid x402): create wallet in current directory -> share wallet + backup path -> user funds wallet -> if no key exists, quote/payment/claim.",
|
|
1176
1235
|
"Option 2 (free): user gets API key at https://dritan.dev and provides it as DRITAN_API_KEY.",
|
|
1177
1236
|
],
|
|
1178
1237
|
});
|
|
@@ -1180,12 +1239,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1180
1239
|
case "x402_create_api_key_quote": {
|
|
1181
1240
|
const input = x402QuoteSchema.parse(args);
|
|
1182
1241
|
const client = getX402Client();
|
|
1242
|
+
const activeApiKey = getActiveApiKey();
|
|
1183
1243
|
const quote = await x402CreateQuote(client, input);
|
|
1184
1244
|
return ok({
|
|
1185
1245
|
...(quote ?? {}),
|
|
1246
|
+
apiKeyAlreadyConfigured: !!activeApiKey,
|
|
1247
|
+
keyPreview: apiKeyPreview(activeApiKey),
|
|
1186
1248
|
nextSteps: [
|
|
1187
|
-
"
|
|
1188
|
-
"
|
|
1249
|
+
"Ensure agent has a local wallet in current directory (wallet_create_local + wallet_get_address) and tell user the backup file path.",
|
|
1250
|
+
"Ask user how much SOL they want to allocate; user funds the agent wallet.",
|
|
1251
|
+
"Only proceed if no API key is active; otherwise skip paid key creation.",
|
|
1189
1252
|
"Transfer quoted SOL amount to receiver wallet using wallet_transfer_sol.",
|
|
1190
1253
|
"Claim key with x402_create_api_key using returned tx signature (MCP auto-activates returned apiKey).",
|
|
1191
1254
|
],
|
|
@@ -1206,6 +1269,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1206
1269
|
preview: apiKeyPreview(activated),
|
|
1207
1270
|
message: "x402-created API key is active for this MCP session (no restart needed).",
|
|
1208
1271
|
};
|
|
1272
|
+
Object.assign(payload, buildPostAuthGuidance());
|
|
1209
1273
|
}
|
|
1210
1274
|
return ok(payload);
|
|
1211
1275
|
}
|
|
@@ -1433,6 +1497,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1433
1497
|
breakdown: input.breakdown,
|
|
1434
1498
|
}));
|
|
1435
1499
|
}
|
|
1500
|
+
case "ths_get_top_wallets": {
|
|
1501
|
+
const input = thsTopWalletsSchema.parse(args);
|
|
1502
|
+
const ths = getThsClient();
|
|
1503
|
+
return ok(await getThsTopWallets(ths, input));
|
|
1504
|
+
}
|
|
1436
1505
|
case "swap_build": {
|
|
1437
1506
|
const input = swapBuildSchema.parse(args);
|
|
1438
1507
|
const client = getDritanClient();
|