@dimcool/mcp 0.1.26 → 0.1.27

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.
Files changed (2) hide show
  1. package/dist/index.js +287 -53
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11984,19 +11984,18 @@ var Lobbies = class {
11984
11984
  return this.http.delete(`/lobbies/admin/${lobbyId}`);
11985
11985
  }
11986
11986
  /**
11987
- * Play again: Create a new lobby, start deposits, and prepare deposit transaction
11988
- * Returns the lobby and unsigned transaction that needs to be signed
11987
+ * Play again: Create a new lobby and prepare deposit in one flow.
11988
+ * Returns the lobby and unsigned transaction that needs to be signed.
11989
11989
  * @param gameType - The game type to play again
11990
11990
  * @param betAmount - The bet amount (same as previous game)
11991
11991
  * @param escrow - The escrow service instance (from sdk.escrow)
11992
11992
  */
11993
11993
  async playAgain(gameType, betAmount, escrow) {
11994
11994
  const lobby = await this.createLobby(gameType, betAmount);
11995
- await escrow.startDeposits(lobby.id);
11996
- const prepareResponse = await escrow.prepareDepositTransaction(lobby.id);
11995
+ const { transaction } = await escrow.prepareAndStartDeposit(lobby.id);
11997
11996
  return {
11998
11997
  lobby,
11999
- unsignedTransaction: prepareResponse.transaction
11998
+ unsignedTransaction: transaction
12000
11999
  };
12001
12000
  }
12002
12001
  };
@@ -12860,6 +12859,17 @@ var Escrow = class {
12860
12859
  `/escrow/lobby/${lobbyId}/deposit/prepare`
12861
12860
  );
12862
12861
  }
12862
+ /**
12863
+ * Combined prepare-and-start: validates lobby, transitions waiting→preparing,
12864
+ * initializes depositStatus, and prepares the unsigned transaction in one call.
12865
+ * Eliminates one HTTP round-trip vs startDeposits() + prepareDepositTransaction().
12866
+ */
12867
+ async prepareAndStartDeposit(lobbyId) {
12868
+ return this.http.post(
12869
+ `/escrow/lobby/${lobbyId}/deposit/prepare-and-start`,
12870
+ {}
12871
+ );
12872
+ }
12863
12873
  /**
12864
12874
  * Submit a signed deposit transaction
12865
12875
  * The transaction will be submitted to the Solana network and confirmed
@@ -12890,7 +12900,7 @@ var Escrow = class {
12890
12900
  );
12891
12901
  }
12892
12902
  /**
12893
- * One-call lobby deposit: start deposits, prepare, sign, submit, and poll until
12903
+ * One-call lobby deposit: prepare-and-start, sign, submit, and poll until
12894
12904
  * the current user's deposit is confirmed. Requires sdk.wallet.setSigner() to be set.
12895
12905
  * Returns when all required deposits are confirmed and the lobby can proceed to queue.
12896
12906
  *
@@ -12902,8 +12912,7 @@ var Escrow = class {
12902
12912
  "No signer configured. Use sdk.wallet.setSigner(...) first."
12903
12913
  );
12904
12914
  }
12905
- await this.startDeposits(lobbyId);
12906
- const { transaction } = await this.prepareDepositTransaction(lobbyId);
12915
+ const { transaction } = await this.prepareAndStartDeposit(lobbyId);
12907
12916
  const unsignedTx = Transaction5.from(base64ToBytes(transaction));
12908
12917
  let signature;
12909
12918
  if (this.wallet.isSignAndSendMode()) {
@@ -12925,7 +12934,7 @@ var Escrow = class {
12925
12934
  if (status.allConfirmed && status.canProceedToQueue) {
12926
12935
  return {
12927
12936
  signature,
12928
- status: "pending",
12937
+ status: "confirmed",
12929
12938
  canProceedToQueue: true
12930
12939
  };
12931
12940
  }
@@ -12937,6 +12946,39 @@ var Escrow = class {
12937
12946
  canProceedToQueue: false
12938
12947
  };
12939
12948
  }
12949
+ /**
12950
+ * Zero-polling deposit variant using server-side awaitConfirmation.
12951
+ * 2 HTTP calls total, 0 client-side polling. Ideal for agents.
12952
+ *
12953
+ * Automatically uses signAndSendTransaction or signTransaction based on signer capability.
12954
+ */
12955
+ async depositForLobbySync(lobbyId) {
12956
+ if (!this.wallet.hasSigner()) {
12957
+ throw new Error(
12958
+ "No signer configured. Use sdk.wallet.setSigner(...) first."
12959
+ );
12960
+ }
12961
+ const { transaction } = await this.prepareAndStartDeposit(lobbyId);
12962
+ const unsignedTx = Transaction5.from(base64ToBytes(transaction));
12963
+ let signature;
12964
+ if (this.wallet.isSignAndSendMode()) {
12965
+ signature = await this.wallet.signAndSendTransaction(unsignedTx);
12966
+ await this.http.post(
12967
+ `/escrow/lobby/${lobbyId}/deposit/confirm-signature?awaitConfirmation=true`,
12968
+ { signature }
12969
+ );
12970
+ } else {
12971
+ const signedTx = await this.wallet.signTransaction(unsignedTx);
12972
+ const signedBase64 = bytesToBase64(
12973
+ signedTx.serialize({ requireAllSignatures: false })
12974
+ );
12975
+ const result = await this.http.post(`/escrow/lobby/${lobbyId}/deposit/submit?awaitConfirmation=true`, {
12976
+ signedTransaction: signedBase64
12977
+ });
12978
+ signature = result.signature;
12979
+ }
12980
+ return { signature, status: "confirmed", canProceedToQueue: true };
12981
+ }
12940
12982
  async claimLobbyDepositRefund(lobbyId, depositSignature) {
12941
12983
  return this.http.post(
12942
12984
  `/escrow/lobby/${lobbyId}/deposit/${depositSignature}/claim-refund`,
@@ -12949,33 +12991,6 @@ var Escrow = class {
12949
12991
  {}
12950
12992
  );
12951
12993
  }
12952
- /**
12953
- * Submit a signed deposit transaction and wait until the lobby is queued/active.
12954
- *
12955
- * Note: the backend may auto-transition the lobby to the queue once deposits are confirmed.
12956
- * In that case, calling /join-queue from the client would be redundant and can fail with
12957
- * "Current status: queued".
12958
- * @param lobbyId - The lobby ID
12959
- * @param signedTransaction - The signed transaction (base64 encoded)
12960
- * @param lobbies - The lobbies service instance (from sdk.lobbies) to read lobby status
12961
- */
12962
- async submitDepositAndJoinQueue(lobbyId, signedTransaction, lobbies) {
12963
- await this.submitDeposit(lobbyId, signedTransaction);
12964
- const MAX_WAIT_TIME = 3e4;
12965
- const POLL_INTERVAL = 1e3;
12966
- const startTime = Date.now();
12967
- while (Date.now() - startTime < MAX_WAIT_TIME) {
12968
- const status = await this.getDepositStatus(lobbyId);
12969
- if (status.allConfirmed && status.canProceedToQueue) {
12970
- const lobby = await lobbies.getLobby(lobbyId);
12971
- if (lobby.status === "queued" || lobby.status === "active") {
12972
- return lobby;
12973
- }
12974
- }
12975
- await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
12976
- }
12977
- throw new Error("Deposit confirmation timeout");
12978
- }
12979
12994
  };
12980
12995
  var Daily = class {
12981
12996
  constructor(http, logger2 = logger) {
@@ -13602,8 +13617,14 @@ var _StandaloneWsTransport = class _StandaloneWsTransport2 extends BaseWsTranspo
13602
13617
  connecting: false,
13603
13618
  error: null
13604
13619
  });
13620
+ const wasReconnect = this.reconnectAttempts > 0;
13605
13621
  this.reconnectAttempts = 0;
13606
13622
  this.onReconnect();
13623
+ if (wasReconnect) {
13624
+ this.dispatchEvent("connection:reconnected", {
13625
+ timestamp: Date.now()
13626
+ });
13627
+ }
13607
13628
  });
13608
13629
  socket.on("disconnect", (reason) => {
13609
13630
  this.updateConnectionState({ connected: false, connecting: false });
@@ -13745,7 +13766,8 @@ function createLobbyStore(transport2) {
13745
13766
  const store = createSdkStore({
13746
13767
  lobbiesById: {},
13747
13768
  matchedEvent: null,
13748
- typingByLobbyId: {}
13769
+ typingByLobbyId: {},
13770
+ depositStatusByLobbyId: {}
13749
13771
  });
13750
13772
  const setBaseState = (lobbies) => {
13751
13773
  const lobbiesById = {};
@@ -13825,6 +13847,15 @@ function createLobbyStore(transport2) {
13825
13847
  };
13826
13848
  });
13827
13849
  break;
13850
+ case "lobby:deposit:updated":
13851
+ store.updateState((state) => ({
13852
+ ...state,
13853
+ depositStatusByLobbyId: {
13854
+ ...state.depositStatusByLobbyId,
13855
+ [event.payload.lobbyId]: event.payload
13856
+ }
13857
+ }));
13858
+ break;
13828
13859
  case "lobby:typing:start":
13829
13860
  case "lobby:typing:stop":
13830
13861
  store.updateState((state) => {
@@ -13853,12 +13884,22 @@ function createLobbyStore(transport2) {
13853
13884
  }
13854
13885
  }
13855
13886
  );
13887
+ const subscribeDepositUpdate = (lobbyId, callback) => store.subscribeSelector(
13888
+ (state) => state.depositStatusByLobbyId[lobbyId],
13889
+ () => {
13890
+ const data = store.getState().depositStatusByLobbyId[lobbyId];
13891
+ if (data) {
13892
+ callback(data);
13893
+ }
13894
+ }
13895
+ );
13856
13896
  return {
13857
13897
  store,
13858
13898
  setBaseState,
13859
13899
  applyWsEvent,
13860
13900
  joinLobby,
13861
- subscribeMatched
13901
+ subscribeMatched,
13902
+ subscribeDepositUpdate
13862
13903
  };
13863
13904
  }
13864
13905
  function createGameStore(transport2) {
@@ -14140,7 +14181,6 @@ function createGameActionsStore(transport2) {
14140
14181
  ...current,
14141
14182
  roundState: {
14142
14183
  ...current.roundState,
14143
- phase: "completed",
14144
14184
  timeRemaining: 0,
14145
14185
  actions: timedOutUser ? {
14146
14186
  ...current.roundState.actions,
@@ -14652,6 +14692,7 @@ var WS_EVENT_NAMES = [
14652
14692
  "lobby:queue:joined",
14653
14693
  "lobby:queue:cancelled",
14654
14694
  "lobby:matched",
14695
+ "lobby:deposit:updated",
14655
14696
  "lobby:typing:start",
14656
14697
  "lobby:typing:stop",
14657
14698
  "game:updated",
@@ -14728,6 +14769,11 @@ function decodeWsEvent(eventName, payload) {
14728
14769
  event: "lobby:matched",
14729
14770
  payload
14730
14771
  };
14772
+ case "lobby:deposit:updated":
14773
+ return {
14774
+ event: "lobby:deposit:updated",
14775
+ payload
14776
+ };
14731
14777
  case "lobby:typing:start":
14732
14778
  case "lobby:typing:stop":
14733
14779
  return {
@@ -15184,6 +15230,17 @@ var SAFETY_RULES = [
15184
15230
  ];
15185
15231
 
15186
15232
  // ../dim-agent-core/src/tools/auth.ts
15233
+ var WALLET_LINKAGE_NOTE = "DIM is noncustodial. Your DIM wallet is the Solana address shown here; it was configured with a base58 private key at setup. Signing is done locally where this instance runs, using that private key and DIM's wallet package.";
15234
+ async function getSpectateUrl(client) {
15235
+ if (!client.currentUserId) return null;
15236
+ try {
15237
+ const user = await client.sdk.users.getUserById(client.currentUserId);
15238
+ const u = user;
15239
+ return u?.username ? `https://dim.cool/spectate/${u.username}` : null;
15240
+ } catch {
15241
+ return null;
15242
+ }
15243
+ }
15187
15244
  async function login(client) {
15188
15245
  try {
15189
15246
  const result = await client.authenticate();
@@ -15213,6 +15270,7 @@ async function login(client) {
15213
15270
  userId: result.userId,
15214
15271
  username: result.username ?? null,
15215
15272
  walletAddress: client.walletAddress,
15273
+ walletNote: WALLET_LINKAGE_NOTE,
15216
15274
  safetyRules: SAFETY_RULES,
15217
15275
  nextSteps
15218
15276
  };
@@ -15246,7 +15304,11 @@ async function getProfile(client) {
15246
15304
  };
15247
15305
  }
15248
15306
  const user = await client.sdk.users.getUserById(client.currentUserId);
15249
- return { data: user };
15307
+ const profile = {
15308
+ ...typeof user === "object" && user !== null ? user : {},
15309
+ walletAddress: client.walletAddress
15310
+ };
15311
+ return { data: profile };
15250
15312
  } catch (error) {
15251
15313
  return {
15252
15314
  error: `Failed to get profile: ${error instanceof Error ? error.message : String(error)}`,
@@ -15447,12 +15509,31 @@ async function listDmThreads(client) {
15447
15509
  }
15448
15510
 
15449
15511
  // ../dim-agent-core/src/tools/wallet.ts
15512
+ async function getWalletAddress(client) {
15513
+ try {
15514
+ return {
15515
+ data: {
15516
+ walletAddress: client.walletAddress,
15517
+ walletNote: WALLET_LINKAGE_NOTE
15518
+ }
15519
+ };
15520
+ } catch (error) {
15521
+ return {
15522
+ error: `Failed to get wallet address: ${error instanceof Error ? error.message : String(error)}`,
15523
+ isError: true
15524
+ };
15525
+ }
15526
+ }
15450
15527
  async function getBalance(client) {
15451
15528
  try {
15452
15529
  const balance = await client.sdk.wallet.getBalances();
15453
15530
  const usdcDollars = balance.usdc / 1e6;
15454
15531
  return {
15455
- data: { ...balance, usdcFormatted: `$${usdcDollars.toFixed(2)}` }
15532
+ data: {
15533
+ ...balance,
15534
+ usdcFormatted: `$${usdcDollars.toFixed(2)}`,
15535
+ walletAddress: client.walletAddress
15536
+ }
15456
15537
  };
15457
15538
  } catch (error) {
15458
15539
  return {
@@ -15519,7 +15600,10 @@ async function getWalletActivity(client, args) {
15519
15600
  limit: args.limit || 20
15520
15601
  });
15521
15602
  const claimable = activity.items.filter((i) => i.claimable === true);
15522
- const data = { ...activity };
15603
+ const data = {
15604
+ ...activity,
15605
+ walletAddress: client.walletAddress
15606
+ };
15523
15607
  if (claimable.length > 0) {
15524
15608
  data.hint = `You have ${claimable.length} claimable item(s). Call dim_claim_funds with the activityId to claim each one.`;
15525
15609
  data.claimableItems = claimable.map((i) => ({
@@ -15728,9 +15812,8 @@ function buildGameOverHint(state) {
15728
15812
  const winnerId = state.winnerId;
15729
15813
  const wonAmount = state.wonAmount;
15730
15814
  const isDraw = state.draw === true || winnerId == null;
15731
- if (isDraw) return "Game over \u2014 it was a draw.";
15732
- const amountStr = wonAmount != null ? ` Won $${(wonAmount / 1e6).toFixed(2)}.` : "";
15733
- return `Game over. Winner: ${winnerId}.${amountStr}`;
15815
+ const result = isDraw ? "Game over \u2014 it was a draw." : `Game over. Winner: ${winnerId}.${wonAmount != null ? ` Won $${(wonAmount / 1e6).toFixed(2)}.` : ""}`;
15816
+ return `${result} You can request a rematch with dim_request_rematch, or check dim_check_notifications for new activity.`;
15734
15817
  }
15735
15818
  async function fetchNewGameChat(client, gameId) {
15736
15819
  try {
@@ -15838,13 +15921,13 @@ async function createLobby(client, args) {
15838
15921
  }
15839
15922
  async function depositForLobby(client, args) {
15840
15923
  try {
15841
- const result = await client.sdk.escrow.depositForLobby(args.lobbyId);
15924
+ const result = await client.sdk.escrow.depositForLobbySync(args.lobbyId);
15842
15925
  return {
15843
15926
  data: {
15844
15927
  signature: result.signature,
15845
15928
  status: result.status,
15846
15929
  canProceedToQueue: result.canProceedToQueue,
15847
- hint: result.canProceedToQueue ? "Deposit confirmed. Call dim_join_queue when ready (and when all players have deposited if 2-player)." : "Deposit submitted. Poll dim_get_deposit_status or try dim_join_queue once all players have deposited."
15930
+ hint: "Deposit confirmed. The server auto-joins the queue when all players have deposited."
15848
15931
  }
15849
15932
  };
15850
15933
  } catch (error) {
@@ -15875,13 +15958,15 @@ async function joinQueue(client, args) {
15875
15958
  await client.ensureConnected();
15876
15959
  const lobby = await client.sdk.lobbies.joinQueue(args.lobbyId);
15877
15960
  const matched = lobby.status === "active" && lobby.gameId;
15961
+ const spectateUrl = matched ? await getSpectateUrl(client) : null;
15878
15962
  return {
15879
15963
  data: {
15880
15964
  lobbyId: lobby.id,
15881
15965
  status: lobby.status,
15882
15966
  gameId: lobby.gameId || null,
15883
15967
  matched: !!matched,
15884
- hint: matched ? `Game started! Call dim_game_loop with gameId "${lobby.gameId}" to play.` : "Waiting for an opponent. Poll dim_get_lobby to check for a match."
15968
+ ...spectateUrl && { spectateUrl },
15969
+ hint: matched ? `Game started! Call dim_game_loop with gameId "${lobby.gameId}" to play.${spectateUrl ? ` Tell the user they can spectate at ${spectateUrl}` : ""}` : "Waiting for an opponent. Poll dim_get_lobby to check for a match."
15885
15970
  }
15886
15971
  };
15887
15972
  } catch (error) {
@@ -16063,6 +16148,38 @@ async function inviteToLobby(client, args) {
16063
16148
  };
16064
16149
  }
16065
16150
  }
16151
+ async function requestRematch(client, args) {
16152
+ try {
16153
+ const result = await client.sdk.games.requestRematch(args.gameId);
16154
+ return {
16155
+ data: {
16156
+ ...result,
16157
+ hint: result.bothReady ? `Both players want a rematch! A lobby is being created.${result.newLobbyId ? ` Lobby ID: ${result.newLobbyId}.` : ""} Check dim_check_notifications or call dim_game_loop with the new gameId once the game starts.` : "Rematch requested. Waiting for opponent to accept. Call dim_check_notifications to see if they respond."
16158
+ }
16159
+ };
16160
+ } catch (error) {
16161
+ return {
16162
+ error: `Failed to request rematch: ${error instanceof Error ? error.message : String(error)}`,
16163
+ isError: true
16164
+ };
16165
+ }
16166
+ }
16167
+ async function acceptRematch(client, args) {
16168
+ try {
16169
+ const result = await client.sdk.games.requestRematch(args.gameId);
16170
+ return {
16171
+ data: {
16172
+ ...result,
16173
+ hint: result.bothReady ? `Rematch accepted! A lobby has been created.${result.newLobbyId ? ` Lobby ID: ${result.newLobbyId}.` : ""} Proceed with deposit and game flow.` : "Your rematch acceptance was recorded. Waiting for the other player."
16174
+ }
16175
+ };
16176
+ } catch (error) {
16177
+ return {
16178
+ error: `Failed to accept rematch: ${error instanceof Error ? error.message : String(error)}`,
16179
+ isError: true
16180
+ };
16181
+ }
16182
+ }
16066
16183
  function raceTimeout(promise, ms) {
16067
16184
  return new Promise((resolve) => {
16068
16185
  const timer = setTimeout(resolve, ms);
@@ -16109,10 +16226,12 @@ async function challengeUser(client, args) {
16109
16226
  async function acceptChallenge(client, args) {
16110
16227
  try {
16111
16228
  const result = await client.sdk.challenges.accept(args.challengeId);
16229
+ const spectateUrl = result.gameId ? await getSpectateUrl(client) : null;
16112
16230
  return {
16113
16231
  data: {
16114
16232
  ...result,
16115
- hint: result.gameId ? `Game started! Call dim_game_loop with gameId "${result.gameId}".` : `Lobby created: ${result.lobbyId}. Use dim_join_queue to start matchmaking.`
16233
+ ...spectateUrl && { spectateUrl },
16234
+ hint: result.gameId ? `Game started! Call dim_game_loop with gameId "${result.gameId}".${spectateUrl ? ` Tell the user they can spectate at ${spectateUrl}` : ""}` : `Lobby created: ${result.lobbyId}. Use dim_join_queue to start matchmaking.`
16116
16235
  }
16117
16236
  };
16118
16237
  } catch (error) {
@@ -16648,6 +16767,69 @@ async function getAgentConfig(client) {
16648
16767
  }
16649
16768
  }
16650
16769
 
16770
+ // ../dim-agent-core/src/tools/users.ts
16771
+ function formatMinor(m) {
16772
+ if (m == null) return "\u2014";
16773
+ const n = typeof m === "bigint" ? Number(m) : m;
16774
+ return `$${(n / 1e6).toFixed(2)}`;
16775
+ }
16776
+ async function getGameHistory(client, args) {
16777
+ try {
16778
+ if (!client.currentUserId) {
16779
+ return {
16780
+ error: "Not authenticated. Call dim_login first.",
16781
+ isError: true
16782
+ };
16783
+ }
16784
+ const raw = await client.sdk.users.getGameHistory(client.currentUserId);
16785
+ const limit = Math.min(args.limit ?? 50, 100);
16786
+ const items = raw.slice(0, limit).map((item) => ({
16787
+ ...item,
16788
+ betFormatted: formatMinor(item.betAmount),
16789
+ winningsFormatted: formatMinor(item.winnings)
16790
+ }));
16791
+ return {
16792
+ data: {
16793
+ items,
16794
+ totalReturned: items.length,
16795
+ hint: items.length >= limit ? `Showing most recent ${limit} games. Use limit param to request more (max 100).` : void 0
16796
+ }
16797
+ };
16798
+ } catch (error) {
16799
+ return {
16800
+ error: `Failed to get game history: ${error instanceof Error ? error.message : String(error)}`,
16801
+ isError: true
16802
+ };
16803
+ }
16804
+ }
16805
+ async function getMyStats(client) {
16806
+ try {
16807
+ if (!client.currentUserId) {
16808
+ return {
16809
+ error: "Not authenticated. Call dim_login first.",
16810
+ isError: true
16811
+ };
16812
+ }
16813
+ const stats = await client.sdk.users.getUserStats(
16814
+ client.currentUserId
16815
+ );
16816
+ return {
16817
+ data: {
16818
+ ...stats,
16819
+ totalEarnedFormatted: formatMinor(stats.totalEarned),
16820
+ referralEarnedFormatted: formatMinor(stats.referralEarned),
16821
+ totalLostFormatted: formatMinor(stats.totalLost),
16822
+ totalFeesPaidFormatted: formatMinor(stats.totalFeesPaid)
16823
+ }
16824
+ };
16825
+ } catch (error) {
16826
+ return {
16827
+ error: `Failed to get stats: ${error instanceof Error ? error.message : String(error)}`,
16828
+ isError: true
16829
+ };
16830
+ }
16831
+ }
16832
+
16651
16833
  // ../dim-agent-core/src/tools/index.ts
16652
16834
  var TOOL_DEFINITIONS = [
16653
16835
  // ── Auth ─────────────────────────────────────────────────────────────
@@ -16659,7 +16841,7 @@ var TOOL_DEFINITIONS = [
16659
16841
  },
16660
16842
  {
16661
16843
  name: "dim_get_profile",
16662
- description: "Get the current authenticated user profile including username, avatar, bio, and chess ELO rating.",
16844
+ description: "Get the current authenticated user profile including username, avatar, bio, chess ELO rating, and your DIM wallet address (walletAddress).",
16663
16845
  params: {},
16664
16846
  execute: (c) => getProfile(c)
16665
16847
  },
@@ -16819,9 +17001,15 @@ var TOOL_DEFINITIONS = [
16819
17001
  execute: (c) => listDmThreads(c)
16820
17002
  },
16821
17003
  // ── Wallet ───────────────────────────────────────────────────────────
17004
+ {
17005
+ name: "dim_get_wallet_address",
17006
+ description: "Get the Solana wallet address DIM uses for this account. Use this to confirm which address receives deposits and is used for signing. Returns walletAddress and a short wallet linkage note.",
17007
+ params: {},
17008
+ execute: (c) => getWalletAddress(c)
17009
+ },
16822
17010
  {
16823
17011
  name: "dim_get_balance",
16824
- description: "Get the wallet balance for the authenticated user. Returns SOL and USDC (usdcFormatted is always present, e.g. $0.00 or $1.50).",
17012
+ description: "Get the wallet balance for the authenticated user. Returns your DIM Solana address (walletAddress), SOL and USDC (usdcFormatted is always present, e.g. $0.00 or $1.50).",
16825
17013
  params: {},
16826
17014
  execute: (c) => getBalance(c)
16827
17015
  },
@@ -16863,7 +17051,7 @@ var TOOL_DEFINITIONS = [
16863
17051
  },
16864
17052
  {
16865
17053
  name: "dim_get_wallet_activity",
16866
- description: "Get recent wallet transaction activity (deposits, payouts, transfers, refunds). Highlights any claimable items.",
17054
+ description: "Get recent wallet transaction activity (deposits, payouts, transfers, refunds) and your DIM wallet address. Highlights any claimable items.",
16867
17055
  params: {
16868
17056
  limit: {
16869
17057
  type: "number",
@@ -16903,6 +17091,23 @@ var TOOL_DEFINITIONS = [
16903
17091
  params: {},
16904
17092
  execute: (c) => getGameMetrics(c)
16905
17093
  },
17094
+ {
17095
+ name: "dim_get_game_history",
17096
+ description: "Get your game history: past games with result, bet, winnings, opponent, and playedAt. Use for daily progress reports.",
17097
+ params: {
17098
+ limit: {
17099
+ type: "number",
17100
+ description: "Max games to return (default 50, max 100)"
17101
+ }
17102
+ },
17103
+ execute: (c, a) => getGameHistory(c, a)
17104
+ },
17105
+ {
17106
+ name: "dim_get_my_stats",
17107
+ description: "Get your aggregated DIM stats: games played, wins, losses, total earned, referral earned, total lost, fees paid, chess ELO, points.",
17108
+ params: {},
17109
+ execute: (c) => getMyStats(c)
17110
+ },
16906
17111
  {
16907
17112
  name: "dim_create_lobby",
16908
17113
  description: "Create a new game lobby. Bet amount is in USDC dollars (e.g., 1.00 for $1.00). A 1% fee (min 1 cent) is charged per player.",
@@ -17032,6 +17237,30 @@ var TOOL_DEFINITIONS = [
17032
17237
  },
17033
17238
  execute: (c, a) => gameLoop(c, a)
17034
17239
  },
17240
+ {
17241
+ name: "dim_request_rematch",
17242
+ description: "Request a rematch after a completed game. If both players request, a lobby is created automatically server-side.",
17243
+ params: {
17244
+ gameId: {
17245
+ type: "string",
17246
+ description: "The completed game ID to request a rematch for",
17247
+ required: true
17248
+ }
17249
+ },
17250
+ execute: (c, a) => requestRematch(c, a)
17251
+ },
17252
+ {
17253
+ name: "dim_accept_rematch",
17254
+ description: "Accept a rematch request from your opponent. When both players accept, the rematch lobby is created automatically.",
17255
+ params: {
17256
+ gameId: {
17257
+ type: "string",
17258
+ description: "The completed game ID to accept the rematch for",
17259
+ required: true
17260
+ }
17261
+ },
17262
+ execute: (c, a) => acceptRematch(c, a)
17263
+ },
17035
17264
  {
17036
17265
  name: "dim_get_lobby_link",
17037
17266
  description: "Get a shareable join link for a lobby. Share this URL via DM \u2014 the user can join with one click. Like dim_invite_to_lobby, do NOT also call dim_join_queue for the same lobby.",
@@ -17632,7 +17861,7 @@ function createDimMcpServer(config) {
17632
17861
  const server2 = new McpServer({
17633
17862
  name: "dim",
17634
17863
  version: "1.0.0",
17635
- description: "DIM Gaming Platform \u2014 Play games, chat, send USDC, challenge users, and earn referral income. Start by calling dim_login. After login: set a username with dim_set_username, check balance with dim_get_balance, list games with dim_list_games, or apply a referral code with dim_apply_referral_code for a 10% fee discount."
17864
+ description: "DIM Gaming Platform \u2014 Play games, chat, send USDC, challenge users, and earn referral income. DIM is noncustodial; your Solana address is returned by dim_get_profile and dim_get_balance. Start by calling dim_login. After login: set a username with dim_set_username, check balance with dim_get_balance, list games with dim_list_games, or apply a referral code with dim_apply_referral_code for a 10% fee discount."
17636
17865
  });
17637
17866
  const client = new DimAgentClient(config);
17638
17867
  for (const tool of TOOL_DEFINITIONS) {
@@ -17675,7 +17904,12 @@ function createDimMcpServer(config) {
17675
17904
  type: "text",
17676
17905
  text: JSON.stringify(
17677
17906
  {
17907
+ wallet_linkage: WALLET_LINKAGE_NOTE,
17908
+ wallet_address: "Your DIM Solana address is returned by dim_get_profile, dim_get_balance, dim_get_wallet_activity, and dim_get_wallet_address. Use it to confirm which address is tied to DIM.",
17909
+ wallet_activity: "For deposits, transfers, payouts, and claimable items use dim_get_wallet_activity.",
17678
17910
  hint: "Game flow: For paid lobbies, dim_create_lobby \u2192 dim_deposit_for_lobby \u2192 dim_join_queue. For free lobbies, dim_create_lobby \u2192 dim_join_queue. Then dim_game_loop (blocks until your turn) \u2192 dim_submit_action \u2192 dim_game_loop \u2192 repeat. Use dim_leave_lobby to exit a lobby.",
17911
+ spectate_on_game_start: "When a game starts (dim_join_queue or dim_accept_challenge returns matched/gameId), tell the user they can spectate at the spectateUrl in the tool response, or at https://dim.cool/spectate/[your DIM username].",
17912
+ daily_summary: "At least once per day, report to the operator your DIM progress: call dim_get_game_history (and optionally dim_get_my_stats and dim_get_referral_summary), then summarize games played and referral earnings.",
17679
17913
  move_formats: {
17680
17914
  "rock-paper-scissors": 'action: "play", payload: { action: "rock"|"paper"|"scissors" }',
17681
17915
  chess: 'action: "move", payload: { from: "e2", to: "e4" }',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dimcool/mcp",
3
- "version": "0.1.26",
3
+ "version": "0.1.27",
4
4
  "description": "MCP server for DIM — lets AI agents play games, chat, send USDC, and earn referral income on the DIM platform",
5
5
  "type": "module",
6
6
  "bin": {