@dimcool/mcp 0.1.0 → 0.1.2
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 +49 -7
- package/dist/index.js +164 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ Add to your MCP config (`claude_desktop_config.json` or `.cursor/mcp.json`):
|
|
|
21
21
|
"command": "npx",
|
|
22
22
|
"args": ["@dimcool/mcp"],
|
|
23
23
|
"env": {
|
|
24
|
-
"
|
|
24
|
+
"DIM_WALLET_STORE_PATH": "/absolute/path/to/mcp-wallet.json",
|
|
25
25
|
"DIM_API_URL": "https://api.dim.cool"
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -29,20 +29,62 @@ Add to your MCP config (`claude_desktop_config.json` or `.cursor/mcp.json`):
|
|
|
29
29
|
}
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
### Bootstrap a wallet locally (recommended)
|
|
33
|
+
|
|
34
|
+
Create a local non-custodial wallet file (private key never leaves your machine):
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx @dimcool/mcp init-wallet
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This prints:
|
|
41
|
+
|
|
42
|
+
- your public Solana address
|
|
43
|
+
- the local wallet store path
|
|
44
|
+
- the env snippet to add to your MCP config
|
|
45
|
+
|
|
46
|
+
### Bring your own key (advanced)
|
|
47
|
+
|
|
48
|
+
If you already have a wallet:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
DIM_WALLET_PRIVATE_KEY=<base58-key> npx @dimcool/mcp
|
|
52
|
+
```
|
|
53
|
+
|
|
32
54
|
### Environment Variables
|
|
33
55
|
|
|
34
|
-
| Variable | Required | Description
|
|
35
|
-
| ------------------------ | -------- |
|
|
36
|
-
| `DIM_WALLET_PRIVATE_KEY` |
|
|
37
|
-
| `
|
|
38
|
-
| `
|
|
56
|
+
| Variable | Required | Description |
|
|
57
|
+
| ------------------------ | -------- | ------------------------------------------------------------------- |
|
|
58
|
+
| `DIM_WALLET_PRIVATE_KEY` | No\* | Base58-encoded Solana private key |
|
|
59
|
+
| `DIM_WALLET_STORE_PATH` | No | Local path to wallet store file (default: `~/.dim/mcp-wallet.json`) |
|
|
60
|
+
| `DIM_WALLET_AUTO_CREATE` | No | If `true`, auto-creates/stores a wallet when key/store is missing |
|
|
61
|
+
| `DIM_API_URL` | No | API base URL (default: `https://api.dim.cool`) |
|
|
62
|
+
| `DIM_REFERRAL_CODE` | No | Referral code to use on first signup |
|
|
63
|
+
|
|
64
|
+
\*Required if you do not use wallet store or auto-create.
|
|
39
65
|
|
|
40
66
|
### Wallet Auth Configuration
|
|
41
67
|
|
|
42
|
-
- `@dimcool/mcp`
|
|
68
|
+
- `@dimcool/mcp` supports three wallet startup modes:
|
|
69
|
+
1. direct key (`DIM_WALLET_PRIVATE_KEY`)
|
|
70
|
+
2. local wallet store (`DIM_WALLET_STORE_PATH`)
|
|
71
|
+
3. auto-create (`DIM_WALLET_AUTO_CREATE=true`)
|
|
43
72
|
- Call `dim_login` before any wallet, games, chat, social, referrals, support, or market tools.
|
|
73
|
+
- Call `dim_get_balance` after login and before paid actions.
|
|
44
74
|
- To generate/export a Base58 key programmatically, use [@dimcool/wallet](https://docs.dim.cool/guides/wallet-package).
|
|
45
75
|
|
|
76
|
+
### Funding your wallet
|
|
77
|
+
|
|
78
|
+
- Send **USDC on Solana** to the wallet public address shown during bootstrap/import.
|
|
79
|
+
- Most paid actions (transfers, game bets, market buys) require USDC balance.
|
|
80
|
+
- If balance is low, agents should ask users to fund first, then retry.
|
|
81
|
+
- You can still start referral growth without pre-funding: onboarding referred users who play can earn rewards.
|
|
82
|
+
|
|
83
|
+
### Skill templates for agent platforms
|
|
84
|
+
|
|
85
|
+
- OpenClaw starter skill: `skills/openclaw-dim/SKILL.md`
|
|
86
|
+
- Hermes starter skill: `skills/hermes-dim/SKILL.md`
|
|
87
|
+
|
|
46
88
|
## Available Tools
|
|
47
89
|
|
|
48
90
|
### Authentication
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,19 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
// src/index.ts
|
|
10
|
+
import {
|
|
11
|
+
chmod,
|
|
12
|
+
mkdir,
|
|
13
|
+
readFile,
|
|
14
|
+
rename,
|
|
15
|
+
stat,
|
|
16
|
+
writeFile
|
|
17
|
+
} from "fs/promises";
|
|
18
|
+
import os from "os";
|
|
19
|
+
import path from "path";
|
|
10
20
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
21
|
+
import { Keypair as Keypair3 } from "@solana/web3.js";
|
|
22
|
+
import bs582 from "bs58";
|
|
11
23
|
|
|
12
24
|
// src/server.ts
|
|
13
25
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -6489,14 +6501,14 @@ var require_url_state_machine = __commonJS({
|
|
|
6489
6501
|
return url2.replace(/\u0009|\u000A|\u000D/g, "");
|
|
6490
6502
|
}
|
|
6491
6503
|
function shortenPath(url2) {
|
|
6492
|
-
const
|
|
6493
|
-
if (
|
|
6504
|
+
const path2 = url2.path;
|
|
6505
|
+
if (path2.length === 0) {
|
|
6494
6506
|
return;
|
|
6495
6507
|
}
|
|
6496
|
-
if (url2.scheme === "file" &&
|
|
6508
|
+
if (url2.scheme === "file" && path2.length === 1 && isNormalizedWindowsDriveLetter(path2[0])) {
|
|
6497
6509
|
return;
|
|
6498
6510
|
}
|
|
6499
|
-
|
|
6511
|
+
path2.pop();
|
|
6500
6512
|
}
|
|
6501
6513
|
function includesCredentials(url2) {
|
|
6502
6514
|
return url2.username !== "" || url2.password !== "";
|
|
@@ -7543,15 +7555,15 @@ var require_node_gyp_build = __commonJS({
|
|
|
7543
7555
|
"../../node_modules/node-gyp-build/node-gyp-build.js"(exports, module) {
|
|
7544
7556
|
"use strict";
|
|
7545
7557
|
var fs = __require2("fs");
|
|
7546
|
-
var
|
|
7547
|
-
var
|
|
7558
|
+
var path2 = __require2("path");
|
|
7559
|
+
var os2 = __require2("os");
|
|
7548
7560
|
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require2;
|
|
7549
7561
|
var vars = process.config && process.config.variables || {};
|
|
7550
7562
|
var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
|
|
7551
7563
|
var abi = process.versions.modules;
|
|
7552
7564
|
var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
|
|
7553
|
-
var arch = process.env.npm_config_arch ||
|
|
7554
|
-
var platform = process.env.npm_config_platform ||
|
|
7565
|
+
var arch = process.env.npm_config_arch || os2.arch();
|
|
7566
|
+
var platform = process.env.npm_config_platform || os2.platform();
|
|
7555
7567
|
var libc = process.env.LIBC || (isAlpine(platform) ? "musl" : "glibc");
|
|
7556
7568
|
var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
|
|
7557
7569
|
var uv = (process.versions.uv || "").split(".")[0];
|
|
@@ -7560,21 +7572,21 @@ var require_node_gyp_build = __commonJS({
|
|
|
7560
7572
|
return runtimeRequire(load.resolve(dir));
|
|
7561
7573
|
}
|
|
7562
7574
|
load.resolve = load.path = function(dir) {
|
|
7563
|
-
dir =
|
|
7575
|
+
dir = path2.resolve(dir || ".");
|
|
7564
7576
|
try {
|
|
7565
|
-
var name = runtimeRequire(
|
|
7577
|
+
var name = runtimeRequire(path2.join(dir, "package.json")).name.toUpperCase().replace(/-/g, "_");
|
|
7566
7578
|
if (process.env[name + "_PREBUILD"]) dir = process.env[name + "_PREBUILD"];
|
|
7567
7579
|
} catch (err) {
|
|
7568
7580
|
}
|
|
7569
7581
|
if (!prebuildsOnly) {
|
|
7570
|
-
var release = getFirst(
|
|
7582
|
+
var release = getFirst(path2.join(dir, "build/Release"), matchBuild);
|
|
7571
7583
|
if (release) return release;
|
|
7572
|
-
var debug = getFirst(
|
|
7584
|
+
var debug = getFirst(path2.join(dir, "build/Debug"), matchBuild);
|
|
7573
7585
|
if (debug) return debug;
|
|
7574
7586
|
}
|
|
7575
7587
|
var prebuild = resolve(dir);
|
|
7576
7588
|
if (prebuild) return prebuild;
|
|
7577
|
-
var nearby = resolve(
|
|
7589
|
+
var nearby = resolve(path2.dirname(process.execPath));
|
|
7578
7590
|
if (nearby) return nearby;
|
|
7579
7591
|
var target = [
|
|
7580
7592
|
"platform=" + platform,
|
|
@@ -7591,14 +7603,14 @@ var require_node_gyp_build = __commonJS({
|
|
|
7591
7603
|
].filter(Boolean).join(" ");
|
|
7592
7604
|
throw new Error("No native build was found for " + target + "\n loaded from: " + dir + "\n");
|
|
7593
7605
|
function resolve(dir2) {
|
|
7594
|
-
var tuples = readdirSync(
|
|
7606
|
+
var tuples = readdirSync(path2.join(dir2, "prebuilds")).map(parseTuple);
|
|
7595
7607
|
var tuple2 = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0];
|
|
7596
7608
|
if (!tuple2) return;
|
|
7597
|
-
var prebuilds =
|
|
7609
|
+
var prebuilds = path2.join(dir2, "prebuilds", tuple2.name);
|
|
7598
7610
|
var parsed = readdirSync(prebuilds).map(parseTags);
|
|
7599
7611
|
var candidates = parsed.filter(matchTags(runtime, abi));
|
|
7600
7612
|
var winner = candidates.sort(compareTags(runtime))[0];
|
|
7601
|
-
if (winner) return
|
|
7613
|
+
if (winner) return path2.join(prebuilds, winner.file);
|
|
7602
7614
|
}
|
|
7603
7615
|
};
|
|
7604
7616
|
function readdirSync(dir) {
|
|
@@ -7610,7 +7622,7 @@ var require_node_gyp_build = __commonJS({
|
|
|
7610
7622
|
}
|
|
7611
7623
|
function getFirst(dir, filter) {
|
|
7612
7624
|
var files = readdirSync(dir).filter(filter);
|
|
7613
|
-
return files[0] &&
|
|
7625
|
+
return files[0] && path2.join(dir, files[0]);
|
|
7614
7626
|
}
|
|
7615
7627
|
function matchBuild(name) {
|
|
7616
7628
|
return /\.node$/.test(name);
|
|
@@ -15332,8 +15344,8 @@ var StructError = class extends TypeError {
|
|
|
15332
15344
|
constructor(failure, failures) {
|
|
15333
15345
|
let cached;
|
|
15334
15346
|
const { message, explanation, ...rest } = failure;
|
|
15335
|
-
const { path } = failure;
|
|
15336
|
-
const msg =
|
|
15347
|
+
const { path: path2 } = failure;
|
|
15348
|
+
const msg = path2.length === 0 ? message : `At path: ${path2.join(".")} -- ${message}`;
|
|
15337
15349
|
super(explanation ?? msg);
|
|
15338
15350
|
if (explanation != null)
|
|
15339
15351
|
this.cause = msg;
|
|
@@ -15371,15 +15383,15 @@ function toFailure(result, context, struct2, value) {
|
|
|
15371
15383
|
} else if (typeof result === "string") {
|
|
15372
15384
|
result = { message: result };
|
|
15373
15385
|
}
|
|
15374
|
-
const { path, branch } = context;
|
|
15386
|
+
const { path: path2, branch } = context;
|
|
15375
15387
|
const { type: type2 } = struct2;
|
|
15376
15388
|
const { refinement, message = `Expected a value of type \`${type2}\`${refinement ? ` with refinement \`${refinement}\`` : ""}, but received: \`${print(value)}\`` } = result;
|
|
15377
15389
|
return {
|
|
15378
15390
|
value,
|
|
15379
15391
|
type: type2,
|
|
15380
15392
|
refinement,
|
|
15381
|
-
key:
|
|
15382
|
-
path,
|
|
15393
|
+
key: path2[path2.length - 1],
|
|
15394
|
+
path: path2,
|
|
15383
15395
|
branch,
|
|
15384
15396
|
...result,
|
|
15385
15397
|
message
|
|
@@ -15397,8 +15409,8 @@ function* toFailures(result, context, struct2, value) {
|
|
|
15397
15409
|
}
|
|
15398
15410
|
}
|
|
15399
15411
|
function* run(value, struct2, options = {}) {
|
|
15400
|
-
const { path = [], branch = [value], coerce: coerce2 = false, mask: mask2 = false } = options;
|
|
15401
|
-
const ctx = { path, branch, mask: mask2 };
|
|
15412
|
+
const { path: path2 = [], branch = [value], coerce: coerce2 = false, mask: mask2 = false } = options;
|
|
15413
|
+
const ctx = { path: path2, branch, mask: mask2 };
|
|
15402
15414
|
if (coerce2) {
|
|
15403
15415
|
value = struct2.coercer(value, ctx);
|
|
15404
15416
|
}
|
|
@@ -15410,7 +15422,7 @@ function* run(value, struct2, options = {}) {
|
|
|
15410
15422
|
}
|
|
15411
15423
|
for (let [k, v, s] of struct2.entries(value, ctx)) {
|
|
15412
15424
|
const ts = run(v, s, {
|
|
15413
|
-
path: k === void 0 ?
|
|
15425
|
+
path: k === void 0 ? path2 : [...path2, k],
|
|
15414
15426
|
branch: k === void 0 ? branch : [...branch, v],
|
|
15415
15427
|
coerce: coerce2,
|
|
15416
15428
|
mask: mask2,
|
|
@@ -26838,10 +26850,135 @@ function createDimMcpServer(config) {
|
|
|
26838
26850
|
}
|
|
26839
26851
|
|
|
26840
26852
|
// src/index.ts
|
|
26841
|
-
var
|
|
26853
|
+
var DEFAULT_WALLET_STORE_PATH = path.join(
|
|
26854
|
+
os.homedir(),
|
|
26855
|
+
".dim",
|
|
26856
|
+
"mcp-wallet.json"
|
|
26857
|
+
);
|
|
26858
|
+
function parseBooleanFlag(value) {
|
|
26859
|
+
if (!value) return false;
|
|
26860
|
+
return ["1", "true", "yes", "on"].includes(value.trim().toLowerCase());
|
|
26861
|
+
}
|
|
26862
|
+
function resolveWalletStorePath(cliArgs2) {
|
|
26863
|
+
const storeFlagIndex = cliArgs2.indexOf("--store");
|
|
26864
|
+
if (storeFlagIndex !== -1) {
|
|
26865
|
+
const value = cliArgs2[storeFlagIndex + 1];
|
|
26866
|
+
if (!value || value.startsWith("--")) {
|
|
26867
|
+
throw new Error(
|
|
26868
|
+
"Missing value for --store. Example: npx @dimcool/mcp init-wallet --store ~/.dim/mcp-wallet.json"
|
|
26869
|
+
);
|
|
26870
|
+
}
|
|
26871
|
+
if (value.startsWith("~/")) {
|
|
26872
|
+
return path.join(os.homedir(), value.slice(2));
|
|
26873
|
+
}
|
|
26874
|
+
return path.resolve(value);
|
|
26875
|
+
}
|
|
26876
|
+
const envPath = process.env.DIM_WALLET_STORE_PATH?.trim();
|
|
26877
|
+
if (envPath) {
|
|
26878
|
+
if (envPath.startsWith("~/")) {
|
|
26879
|
+
return path.join(os.homedir(), envPath.slice(2));
|
|
26880
|
+
}
|
|
26881
|
+
return path.resolve(envPath);
|
|
26882
|
+
}
|
|
26883
|
+
return DEFAULT_WALLET_STORE_PATH;
|
|
26884
|
+
}
|
|
26885
|
+
async function writeWalletStoreFile(storePath, record2) {
|
|
26886
|
+
await mkdir(path.dirname(storePath), { recursive: true });
|
|
26887
|
+
const tmpPath = `${storePath}.tmp`;
|
|
26888
|
+
await writeFile(tmpPath, `${JSON.stringify(record2, null, 2)}
|
|
26889
|
+
`, {
|
|
26890
|
+
encoding: "utf8",
|
|
26891
|
+
mode: 384
|
|
26892
|
+
});
|
|
26893
|
+
await chmod(tmpPath, 384);
|
|
26894
|
+
await rename(tmpPath, storePath);
|
|
26895
|
+
}
|
|
26896
|
+
async function readWalletStoreFile(storePath) {
|
|
26897
|
+
try {
|
|
26898
|
+
const raw = await readFile(storePath, "utf8");
|
|
26899
|
+
const parsed = JSON.parse(raw);
|
|
26900
|
+
if (parsed.walletPrivateKey && parsed.walletAddress) {
|
|
26901
|
+
return {
|
|
26902
|
+
version: 1,
|
|
26903
|
+
walletAddress: parsed.walletAddress,
|
|
26904
|
+
walletPrivateKey: parsed.walletPrivateKey,
|
|
26905
|
+
createdAt: parsed.createdAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
26906
|
+
};
|
|
26907
|
+
}
|
|
26908
|
+
return null;
|
|
26909
|
+
} catch {
|
|
26910
|
+
return null;
|
|
26911
|
+
}
|
|
26912
|
+
}
|
|
26913
|
+
async function createWalletRecord() {
|
|
26914
|
+
const keypair = Keypair3.generate();
|
|
26915
|
+
return {
|
|
26916
|
+
version: 1,
|
|
26917
|
+
walletAddress: keypair.publicKey.toBase58(),
|
|
26918
|
+
walletPrivateKey: bs582.encode(keypair.secretKey),
|
|
26919
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
26920
|
+
};
|
|
26921
|
+
}
|
|
26922
|
+
async function walletStoreExists(storePath) {
|
|
26923
|
+
try {
|
|
26924
|
+
await stat(storePath);
|
|
26925
|
+
return true;
|
|
26926
|
+
} catch {
|
|
26927
|
+
return false;
|
|
26928
|
+
}
|
|
26929
|
+
}
|
|
26930
|
+
async function handleInitWallet(cliArgs2) {
|
|
26931
|
+
const force = cliArgs2.includes("--force");
|
|
26932
|
+
const storePath = resolveWalletStorePath(cliArgs2);
|
|
26933
|
+
const exists = await walletStoreExists(storePath);
|
|
26934
|
+
if (exists && !force) {
|
|
26935
|
+
console.error(
|
|
26936
|
+
`Wallet store already exists at ${storePath}.
|
|
26937
|
+
Use --force to overwrite, or remove the file first.`
|
|
26938
|
+
);
|
|
26939
|
+
process.exit(1);
|
|
26940
|
+
}
|
|
26941
|
+
const record2 = await createWalletRecord();
|
|
26942
|
+
await writeWalletStoreFile(storePath, record2);
|
|
26943
|
+
console.log("DIM wallet created and stored locally.");
|
|
26944
|
+
console.log(`Public address: ${record2.walletAddress}`);
|
|
26945
|
+
console.log(`Store path: ${storePath}`);
|
|
26946
|
+
console.log("");
|
|
26947
|
+
console.log("Add this to your MCP env config:");
|
|
26948
|
+
console.log(` DIM_WALLET_STORE_PATH="${storePath}"`);
|
|
26949
|
+
console.log(' DIM_API_URL="https://api.dim.cool"');
|
|
26950
|
+
console.log("");
|
|
26951
|
+
console.log(
|
|
26952
|
+
"Next step: fund this wallet with USDC on Solana, then call dim_login and dim_get_balance."
|
|
26953
|
+
);
|
|
26954
|
+
}
|
|
26955
|
+
async function resolveWalletPrivateKey(cliArgs2) {
|
|
26956
|
+
const direct = process.env.DIM_WALLET_PRIVATE_KEY?.trim();
|
|
26957
|
+
if (direct) return direct;
|
|
26958
|
+
const storePath = resolveWalletStorePath(cliArgs2);
|
|
26959
|
+
const record2 = await readWalletStoreFile(storePath);
|
|
26960
|
+
if (record2?.walletPrivateKey) return record2.walletPrivateKey;
|
|
26961
|
+
if (parseBooleanFlag(process.env.DIM_WALLET_AUTO_CREATE)) {
|
|
26962
|
+
const newRecord = await createWalletRecord();
|
|
26963
|
+
await writeWalletStoreFile(storePath, newRecord);
|
|
26964
|
+
console.error(
|
|
26965
|
+
`DIM wallet auto-created. Public address: ${newRecord.walletAddress}
|
|
26966
|
+
Stored at: ${storePath}
|
|
26967
|
+
Fund this wallet with USDC on Solana before paid actions.`
|
|
26968
|
+
);
|
|
26969
|
+
return newRecord.walletPrivateKey;
|
|
26970
|
+
}
|
|
26971
|
+
return null;
|
|
26972
|
+
}
|
|
26973
|
+
var cliArgs = process.argv.slice(2);
|
|
26974
|
+
if (cliArgs[0] === "init-wallet") {
|
|
26975
|
+
await handleInitWallet(cliArgs.slice(1));
|
|
26976
|
+
process.exit(0);
|
|
26977
|
+
}
|
|
26978
|
+
var walletPrivateKey = await resolveWalletPrivateKey(cliArgs);
|
|
26842
26979
|
if (!walletPrivateKey) {
|
|
26843
26980
|
console.error(
|
|
26844
|
-
"Error:
|
|
26981
|
+
"Error: DIM wallet key is not configured.\nProvide DIM_WALLET_PRIVATE_KEY, or initialize a local wallet store.\n\nExamples:\n DIM_WALLET_PRIVATE_KEY=your-base58-key npx @dimcool/mcp\n npx @dimcool/mcp init-wallet\n DIM_WALLET_AUTO_CREATE=true npx @dimcool/mcp"
|
|
26845
26982
|
);
|
|
26846
26983
|
process.exit(1);
|
|
26847
26984
|
}
|