149 lines
4.9 KiB
TypeScript
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() };
|
|
},
|
|
},
|
|
];
|