@dritan/mcp 0.5.0 → 0.6.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 +4 -0
- package/dist/index.js +104 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,6 +39,8 @@ npm run build && npm start
|
|
|
39
39
|
## Tools
|
|
40
40
|
|
|
41
41
|
- `system_check_prereqs`
|
|
42
|
+
- `auth_status`
|
|
43
|
+
- `auth_set_api_key`
|
|
42
44
|
- `wallet_create_local`
|
|
43
45
|
- `wallet_get_address`
|
|
44
46
|
- `wallet_get_balance`
|
|
@@ -79,9 +81,11 @@ npm run build && npm start
|
|
|
79
81
|
- Wallets default to `~/.config/dritan-mcp/wallets`.
|
|
80
82
|
- Private keys never leave local files; only public address/signature are returned.
|
|
81
83
|
- `swap_sign_and_broadcast` signs locally, then broadcasts via Dritan.
|
|
84
|
+
- `auth_set_api_key` activates a key for the running MCP process without restart.
|
|
82
85
|
- Agent onboarding without `DRITAN_API_KEY` should present two options:
|
|
83
86
|
- Option 1: paid x402 flow (`x402_get_pricing` -> `x402_create_api_key_quote` -> user funds agent wallet -> `wallet_transfer_sol` -> `x402_create_api_key`).
|
|
84
87
|
- Option 2: user gets a free key at `https://dritan.dev`.
|
|
88
|
+
- `x402_create_api_key` auto-activates returned keys for the current MCP session.
|
|
85
89
|
- `token_get_ohlcv_chart` returns a shareable chart URL plus a ready-to-send markdown image snippet.
|
|
86
90
|
- `token_get_ohlcv_chart` supports `chartType: "line-volume" | "candlestick"` (default is `line-volume`).
|
|
87
91
|
- Ticker workflow for chart requests: `token_search` -> extract mint -> `token_get_ohlcv` or `token_get_ohlcv_chart`.
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,41 @@ import { Connection, Keypair, PublicKey, SystemProgram, Transaction, VersionedTr
|
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
const DEFAULT_WALLET_DIR = join(homedir(), ".config", "dritan-mcp", "wallets");
|
|
13
13
|
const LAMPORTS_PER_SOL = 1_000_000_000;
|
|
14
|
+
function normalizeApiKey(value) {
|
|
15
|
+
const trimmed = value?.trim();
|
|
16
|
+
return trimmed ? trimmed : null;
|
|
17
|
+
}
|
|
18
|
+
function apiKeyPreview(apiKey) {
|
|
19
|
+
if (!apiKey)
|
|
20
|
+
return null;
|
|
21
|
+
if (apiKey.length <= 12)
|
|
22
|
+
return `${apiKey.slice(0, 4)}...`;
|
|
23
|
+
return `${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`;
|
|
24
|
+
}
|
|
25
|
+
let runtimeApiKey = normalizeApiKey(process.env.DRITAN_API_KEY);
|
|
26
|
+
let runtimeApiKeySource = runtimeApiKey ? "env" : "none";
|
|
27
|
+
function setRuntimeApiKey(apiKey, source) {
|
|
28
|
+
const normalized = normalizeApiKey(apiKey);
|
|
29
|
+
if (!normalized) {
|
|
30
|
+
throw new Error("apiKey is required");
|
|
31
|
+
}
|
|
32
|
+
runtimeApiKey = normalized;
|
|
33
|
+
runtimeApiKeySource = source;
|
|
34
|
+
process.env.DRITAN_API_KEY = normalized;
|
|
35
|
+
return normalized;
|
|
36
|
+
}
|
|
37
|
+
function getActiveApiKey() {
|
|
38
|
+
if (runtimeApiKey)
|
|
39
|
+
return runtimeApiKey;
|
|
40
|
+
const fromEnv = normalizeApiKey(process.env.DRITAN_API_KEY);
|
|
41
|
+
if (fromEnv) {
|
|
42
|
+
runtimeApiKey = fromEnv;
|
|
43
|
+
runtimeApiKeySource = "env";
|
|
44
|
+
return fromEnv;
|
|
45
|
+
}
|
|
46
|
+
runtimeApiKeySource = "none";
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
14
49
|
const STREAM_DEXES = [
|
|
15
50
|
"pumpamm",
|
|
16
51
|
"pumpfun",
|
|
@@ -35,7 +70,7 @@ const server = new Server({
|
|
|
35
70
|
"This server supports two API-key onboarding options when DRITAN_API_KEY is missing:",
|
|
36
71
|
"1) x402 pay-per-use key flow: create wallet, receive SOL, create quote, forward payment, claim key.",
|
|
37
72
|
"2) Free key flow: user creates a free API key at https://dritan.dev.",
|
|
38
|
-
"After key is obtained, set
|
|
73
|
+
"After key is obtained, set it with auth_set_api_key (no restart needed), or restart with DRITAN_API_KEY configured.",
|
|
39
74
|
"Suggested setup command:",
|
|
40
75
|
" claude mcp add dritan-mcp -e DRITAN_API_KEY=<your-key> -- npx @dritan/mcp@latest",
|
|
41
76
|
].join("\n"),
|
|
@@ -48,10 +83,11 @@ function missingApiKeyError() {
|
|
|
48
83
|
"Missing DRITAN_API_KEY in environment.",
|
|
49
84
|
"Option 1 (paid): use x402 tools (x402_get_pricing, x402_create_api_key_quote, x402_create_api_key) and wallet tools.",
|
|
50
85
|
"Option 2 (free): create a free key at https://dritan.dev and set DRITAN_API_KEY.",
|
|
86
|
+
"You can activate a key immediately with auth_set_api_key without restarting MCP.",
|
|
51
87
|
].join(" "));
|
|
52
88
|
}
|
|
53
89
|
function getDritanClient() {
|
|
54
|
-
const apiKey =
|
|
90
|
+
const apiKey = getActiveApiKey();
|
|
55
91
|
if (!apiKey) {
|
|
56
92
|
throw missingApiKeyError();
|
|
57
93
|
}
|
|
@@ -65,7 +101,7 @@ function getDritanClient() {
|
|
|
65
101
|
function getX402Client() {
|
|
66
102
|
return new DritanClient({
|
|
67
103
|
// x402 endpoints are public; SDK constructor still needs a string.
|
|
68
|
-
apiKey:
|
|
104
|
+
apiKey: getActiveApiKey() ?? "x402_public_endpoints",
|
|
69
105
|
baseUrl: process.env.DRITAN_BASE_URL,
|
|
70
106
|
controlBaseUrl: getControlBaseUrl(),
|
|
71
107
|
wsBaseUrl: process.env.DRITAN_WS_BASE_URL,
|
|
@@ -79,10 +115,10 @@ function getThsClient() {
|
|
|
79
115
|
async function searchTokens(client, query, options) {
|
|
80
116
|
const sdkSearch = client.searchTokens;
|
|
81
117
|
if (typeof sdkSearch === "function") {
|
|
82
|
-
return await sdkSearch(query, options);
|
|
118
|
+
return await sdkSearch.call(client, query, options);
|
|
83
119
|
}
|
|
84
120
|
// Backward-compatible fallback for environments where dritan-sdk hasn't been upgraded yet.
|
|
85
|
-
const apiKey =
|
|
121
|
+
const apiKey = getActiveApiKey();
|
|
86
122
|
if (!apiKey) {
|
|
87
123
|
throw missingApiKeyError();
|
|
88
124
|
}
|
|
@@ -412,6 +448,9 @@ const walletCreateSchema = z.object({
|
|
|
412
448
|
name: z.string().min(1).default("agent-wallet"),
|
|
413
449
|
walletDir: z.string().min(1).optional(),
|
|
414
450
|
});
|
|
451
|
+
const authSetApiKeySchema = z.object({
|
|
452
|
+
apiKey: z.string().min(8),
|
|
453
|
+
});
|
|
415
454
|
const walletPathSchema = z.object({
|
|
416
455
|
walletPath: z.string().min(1),
|
|
417
456
|
});
|
|
@@ -531,6 +570,25 @@ const tools = [
|
|
|
531
570
|
properties: {},
|
|
532
571
|
},
|
|
533
572
|
},
|
|
573
|
+
{
|
|
574
|
+
name: "auth_status",
|
|
575
|
+
description: "Show current API key status for this MCP session (active source, preview, and onboarding options).",
|
|
576
|
+
inputSchema: {
|
|
577
|
+
type: "object",
|
|
578
|
+
properties: {},
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
name: "auth_set_api_key",
|
|
583
|
+
description: "Set the active Dritan API key for this running MCP process without restart (runtime session scope).",
|
|
584
|
+
inputSchema: {
|
|
585
|
+
type: "object",
|
|
586
|
+
required: ["apiKey"],
|
|
587
|
+
properties: {
|
|
588
|
+
apiKey: { type: "string" },
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
},
|
|
534
592
|
{
|
|
535
593
|
name: "wallet_create_local",
|
|
536
594
|
description: "Create a local Solana wallet using solana-keygen and return path + public address.",
|
|
@@ -976,7 +1034,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
976
1034
|
switch (request.params.name) {
|
|
977
1035
|
case "system_check_prereqs": {
|
|
978
1036
|
const solanaCli = checkSolanaCli();
|
|
979
|
-
const
|
|
1037
|
+
const activeApiKey = getActiveApiKey();
|
|
1038
|
+
const apiKeySet = !!activeApiKey;
|
|
980
1039
|
return ok({
|
|
981
1040
|
ready: solanaCli.ok && apiKeySet,
|
|
982
1041
|
readyForX402Onboarding: solanaCli.ok,
|
|
@@ -985,6 +1044,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
985
1044
|
{
|
|
986
1045
|
ok: apiKeySet,
|
|
987
1046
|
name: "DRITAN_API_KEY",
|
|
1047
|
+
source: runtimeApiKeySource,
|
|
1048
|
+
preview: apiKeyPreview(activeApiKey),
|
|
988
1049
|
hint: apiKeySet
|
|
989
1050
|
? "API key is configured."
|
|
990
1051
|
: "Missing DRITAN_API_KEY. You can either use x402 onboarding tools or get a free key at https://dritan.dev.",
|
|
@@ -997,6 +1058,29 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
997
1058
|
: "Environment ready.",
|
|
998
1059
|
});
|
|
999
1060
|
}
|
|
1061
|
+
case "auth_status": {
|
|
1062
|
+
const activeApiKey = getActiveApiKey();
|
|
1063
|
+
return ok({
|
|
1064
|
+
apiKeyConfigured: !!activeApiKey,
|
|
1065
|
+
source: runtimeApiKeySource,
|
|
1066
|
+
preview: apiKeyPreview(activeApiKey),
|
|
1067
|
+
controlBaseUrl: getControlBaseUrl(),
|
|
1068
|
+
onboardingOptions: [
|
|
1069
|
+
"Option 1 (paid x402): create wallet -> receive user SOL -> x402 quote -> transfer -> claim key.",
|
|
1070
|
+
"Option 2 (free): create key at https://dritan.dev and set it with auth_set_api_key.",
|
|
1071
|
+
],
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
case "auth_set_api_key": {
|
|
1075
|
+
const input = authSetApiKeySchema.parse(args);
|
|
1076
|
+
const activated = setRuntimeApiKey(input.apiKey, "runtime");
|
|
1077
|
+
return ok({
|
|
1078
|
+
ok: true,
|
|
1079
|
+
message: "API key activated for this MCP session without restart.",
|
|
1080
|
+
source: runtimeApiKeySource,
|
|
1081
|
+
preview: apiKeyPreview(activated),
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1000
1084
|
case "dritan_health": {
|
|
1001
1085
|
return ok(await checkDritanHealth());
|
|
1002
1086
|
}
|
|
@@ -1090,7 +1174,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1090
1174
|
"If user picked paid flow, ensure agent has a local wallet (wallet_create_local + wallet_get_address).",
|
|
1091
1175
|
"User funds the agent wallet.",
|
|
1092
1176
|
"Transfer quoted SOL amount to receiver wallet using wallet_transfer_sol.",
|
|
1093
|
-
"Claim key with x402_create_api_key using returned tx signature.",
|
|
1177
|
+
"Claim key with x402_create_api_key using returned tx signature (MCP auto-activates returned apiKey).",
|
|
1094
1178
|
],
|
|
1095
1179
|
});
|
|
1096
1180
|
}
|
|
@@ -1098,7 +1182,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1098
1182
|
const input = x402CreateApiKeySchema.parse(args);
|
|
1099
1183
|
const client = getX402Client();
|
|
1100
1184
|
const created = await x402CreateApiKey(client, input);
|
|
1101
|
-
|
|
1185
|
+
const payload = typeof created === "object" && created !== null
|
|
1186
|
+
? { ...created }
|
|
1187
|
+
: { value: created };
|
|
1188
|
+
if (typeof payload.apiKey === "string") {
|
|
1189
|
+
const activated = setRuntimeApiKey(payload.apiKey, "x402");
|
|
1190
|
+
payload.mcpAuth = {
|
|
1191
|
+
activated: true,
|
|
1192
|
+
source: runtimeApiKeySource,
|
|
1193
|
+
preview: apiKeyPreview(activated),
|
|
1194
|
+
message: "x402-created API key is active for this MCP session (no restart needed).",
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
return ok(payload);
|
|
1102
1198
|
}
|
|
1103
1199
|
case "market_get_snapshot": {
|
|
1104
1200
|
const input = marketSnapshotSchema.parse(args);
|