Files
2026-07-13 13:39:12 +08:00

149 lines
4.9 KiB
TypeScript

/**
* MCP Gamification Tools — leaderboard, badges, levels, sharing.
*
* @module mcp-server/tools/gamificationTools
*/
import { z } from "zod";
export const gamificationTools = [
{
name: "gamification_leaderboard",
description: "Get leaderboard rankings for a scope (global, weekly, monthly, tokens_shared).",
scopes: ["read:gamification"],
inputSchema: z.object({
scope: z.enum(["global", "weekly", "monthly", "tokens_shared"]).default("global"),
limit: z.number().min(1).max(100).default(50),
}),
handler: async (args: { scope: string; limit: number }) => {
const { getTopN } = await import("../../../src/lib/gamification/leaderboard");
const entries = await getTopN(args.scope as any, args.limit);
return { entries };
},
},
{
name: "gamification_rank",
description: "Get rank for an API key in a leaderboard scope.",
scopes: ["read:gamification"],
inputSchema: z.object({
apiKeyId: z.string(),
scope: z.enum(["global", "weekly", "monthly", "tokens_shared"]).default("global"),
}),
handler: async (args: { apiKeyId: string; scope: string }) => {
const { getRank } = await import("../../../src/lib/gamification/leaderboard");
const rank = await getRank(args.apiKeyId, args.scope as any);
return { rank };
},
},
{
name: "gamification_profile",
description: "Get XP, level, and badges for an API key.",
scopes: ["read:gamification"],
inputSchema: z.object({
apiKeyId: z.string(),
}),
handler: async (args: { apiKeyId: string }) => {
const { getXp, getBadges } = await import("../../../src/lib/db/gamification");
const { calculateLevel, getLevelTitle, getLevelTier } =
await import("../../../src/lib/gamification/xp");
const { getStreak } = await import("../../../src/lib/gamification/streaks");
const xp = getXp(args.apiKeyId);
const badges = getBadges(args.apiKeyId);
const streak = await getStreak(args.apiKeyId);
const level = xp ? calculateLevel(xp.totalXp) : 1;
return {
totalXp: xp?.totalXp || 0,
level,
title: getLevelTitle(level),
tier: getLevelTier(level),
streak: streak.currentStreak,
longestStreak: streak.longestStreak,
badges: badges.map((b) => ({ id: b.badgeId, unlockedAt: b.unlockedAt })),
};
},
},
{
name: "gamification_badges",
description: "List all badge definitions or earned badges for an API key.",
scopes: ["read:gamification"],
inputSchema: z.object({
apiKeyId: z.string().optional(),
category: z.string().optional(),
}),
handler: async (args: { apiKeyId?: string; category?: string }) => {
const { getBadgeDefinitions, getBadges } = await import("../../../src/lib/db/gamification");
if (args.apiKeyId) {
const badges = getBadges(args.apiKeyId);
return { earned: badges };
}
const definitions = getBadgeDefinitions(args.category);
return { definitions };
},
},
{
name: "gamification_transfer",
description: "Transfer tokens between API keys.",
scopes: ["write:gamification"],
inputSchema: z.object({
fromApiKeyId: z.string(),
toApiKeyId: z.string(),
amount: z.number().positive(),
reason: z.string().optional(),
}),
handler: async (args: {
fromApiKeyId: string;
toApiKeyId: string;
amount: number;
reason?: string;
}) => {
const { transferTokens } = await import("../../../src/lib/gamification/sharing");
const result = await transferTokens(
args.fromApiKeyId,
args.toApiKeyId,
args.amount,
args.reason
);
return result;
},
},
{
name: "gamification_invite",
description: "Create an invite token for server connection.",
scopes: ["write:gamification"],
inputSchema: z.object({
apiKeyId: z.string(),
serverUrl: z.string().optional(),
maxUses: z.number().positive().default(1),
}),
handler: async (args: { apiKeyId: string; serverUrl?: string; maxUses: number }) => {
const { createInvite } = await import("../../../src/lib/gamification/invites");
const result = await createInvite(args.apiKeyId, args.serverUrl, args.maxUses);
return result;
},
},
{
name: "gamification_servers",
description: "List connected community servers.",
scopes: ["read:gamification"],
inputSchema: z.object({}),
handler: async () => {
const { listServers } = await import("../../../src/lib/gamification/servers");
return { servers: await listServers() };
},
},
{
name: "gamification_anomalies",
description: "Get flagged anomalous XP activity (admin only).",
scopes: ["read:gamification"],
inputSchema: z.object({}),
handler: async () => {
const { getAnomalies } = await import("../../../src/lib/gamification/antiCheat");
return { anomalies: await getAnomalies() };
},
},
];