Skip to main content
Glama
audit-tools.ts8.76 kB
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import { AuditLogEvent } from 'discord.js'; import { getDiscordClient } from '../utils/discord-client.js'; import { withErrorHandling } from '../utils/error-handler.js'; export function registerAuditTools(server: McpServer): void { // Get audit logs server.tool( 'get_audit_logs', 'Get audit logs from a server', { guildId: z.string().describe('The ID of the server (guild)'), limit: z.number().optional().describe('Number of entries to fetch (1-100, default 50)'), userId: z.string().optional().describe('Filter by user who performed action'), actionType: z.string().optional().describe('Filter by action type (e.g., MEMBER_BAN_ADD, CHANNEL_CREATE)'), before: z.string().optional().describe('Get entries before this audit log entry ID'), }, async ({ guildId, limit = 50, userId, actionType, before }) => { const result = await withErrorHandling(async () => { const client = await getDiscordClient(); const guild = await client.guilds.fetch(guildId); const fetchOptions: { limit: number; user?: string; type?: AuditLogEvent; before?: string } = { limit: Math.min(Math.max(1, limit), 100), }; if (userId) fetchOptions.user = userId; if (before) fetchOptions.before = before; if (actionType) { const eventType = AuditLogEvent[actionType as keyof typeof AuditLogEvent]; if (eventType !== undefined) fetchOptions.type = eventType; } const auditLogs = await guild.fetchAuditLogs(fetchOptions); return auditLogs.entries.map((entry) => ({ id: entry.id, action: AuditLogEvent[entry.action], actionType: entry.actionType, targetType: entry.targetType, targetId: entry.targetId, executorId: entry.executorId, executor: entry.executor ? { id: entry.executor.id, username: entry.executor.username, } : null, reason: entry.reason, createdAt: entry.createdAt.toISOString(), changes: entry.changes.map((change) => ({ key: change.key, old: change.old, new: change.new, })), extra: entry.extra, })); }); if (!result.success) { return { content: [{ type: 'text', text: result.error }], isError: true }; } return { content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }] }; } ); // List audit log action types server.tool( 'list_audit_log_types', 'List all available audit log action types', {}, async () => { const actionTypes = Object.entries(AuditLogEvent) .filter(([key]) => isNaN(Number(key))) .map(([name, value]) => ({ name, value })); const categorized = { guild: actionTypes.filter(t => t.name.startsWith('Guild')), channel: actionTypes.filter(t => t.name.startsWith('Channel') || t.name.startsWith('Thread')), member: actionTypes.filter(t => t.name.startsWith('Member')), role: actionTypes.filter(t => t.name.startsWith('Role')), invite: actionTypes.filter(t => t.name.startsWith('Invite')), webhook: actionTypes.filter(t => t.name.startsWith('Webhook')), emoji: actionTypes.filter(t => t.name.startsWith('Emoji')), message: actionTypes.filter(t => t.name.startsWith('Message')), integration: actionTypes.filter(t => t.name.startsWith('Integration')), stageInstance: actionTypes.filter(t => t.name.startsWith('StageInstance')), sticker: actionTypes.filter(t => t.name.startsWith('Sticker')), scheduledEvent: actionTypes.filter(t => t.name.startsWith('GuildScheduledEvent')), autoMod: actionTypes.filter(t => t.name.startsWith('AutoMod')), }; return { content: [{ type: 'text', text: JSON.stringify({ actionTypes, categorized }, null, 2) }], }; } ); // List auto-moderation rules server.tool( 'list_automod_rules', 'List all auto-moderation rules in a server', { guildId: z.string().describe('The ID of the server (guild)'), }, async ({ guildId }) => { const result = await withErrorHandling(async () => { const client = await getDiscordClient(); const guild = await client.guilds.fetch(guildId); const rules = await guild.autoModerationRules.fetch(); return rules.map((rule) => ({ id: rule.id, name: rule.name, enabled: rule.enabled, eventType: rule.eventType, triggerType: rule.triggerType, triggerMetadata: rule.triggerMetadata, actions: rule.actions.map((action) => ({ type: action.type, metadata: action.metadata, })), exemptRoles: rule.exemptRoles.map((r) => ({ id: r.id, name: r.name })), exemptChannels: rule.exemptChannels.map((c) => ({ id: c.id, name: c.name })), creatorId: rule.creatorId, })); }); if (!result.success) { return { content: [{ type: 'text', text: result.error }], isError: true }; } return { content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }] }; } ); // Get auto-moderation rule server.tool( 'get_automod_rule', 'Get details of a specific auto-moderation rule', { guildId: z.string().describe('The ID of the server (guild)'), ruleId: z.string().describe('The ID of the rule'), }, async ({ guildId, ruleId }) => { const result = await withErrorHandling(async () => { const client = await getDiscordClient(); const guild = await client.guilds.fetch(guildId); const rule = await guild.autoModerationRules.fetch(ruleId); return { id: rule.id, name: rule.name, enabled: rule.enabled, eventType: rule.eventType, triggerType: rule.triggerType, triggerMetadata: rule.triggerMetadata, actions: rule.actions, exemptRoles: rule.exemptRoles.map((r) => ({ id: r.id, name: r.name })), exemptChannels: rule.exemptChannels.map((c) => ({ id: c.id, name: c.name })), creatorId: rule.creatorId, }; }); if (!result.success) { return { content: [{ type: 'text', text: result.error }], isError: true }; } return { content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }] }; } ); // Delete auto-moderation rule server.tool( 'delete_automod_rule', 'Delete an auto-moderation rule', { guildId: z.string().describe('The ID of the server (guild)'), ruleId: z.string().describe('The ID of the rule to delete'), reason: z.string().optional().describe('Reason for deletion'), }, async ({ guildId, ruleId, reason }) => { const result = await withErrorHandling(async () => { const client = await getDiscordClient(); const guild = await client.guilds.fetch(guildId); const rule = await guild.autoModerationRules.fetch(ruleId); const ruleName = rule.name; await rule.delete(reason); return { ruleId, ruleName, message: 'Auto-moderation rule deleted successfully' }; }); if (!result.success) { return { content: [{ type: 'text', text: result.error }], isError: true }; } return { content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }] }; } ); // Toggle auto-moderation rule server.tool( 'toggle_automod_rule', 'Enable or disable an auto-moderation rule', { guildId: z.string().describe('The ID of the server (guild)'), ruleId: z.string().describe('The ID of the rule'), enabled: z.boolean().describe('Enable or disable the rule'), reason: z.string().optional().describe('Reason for change'), }, async ({ guildId, ruleId, enabled, reason }) => { const result = await withErrorHandling(async () => { const client = await getDiscordClient(); const guild = await client.guilds.fetch(guildId); const rule = await guild.autoModerationRules.fetch(ruleId); await rule.edit({ enabled, reason }); return { ruleId, ruleName: rule.name, enabled, message: `Auto-moderation rule ${enabled ? 'enabled' : 'disabled'} successfully`, }; }); if (!result.success) { return { content: [{ type: 'text', text: result.error }], isError: true }; } return { content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }] }; } ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/scarecr0w12/discord-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server