File size: 3,248 Bytes
57a889c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
import { z } from 'zod';
import { isDemoUser } from '../../services/authService';
import {
  getNotifications, getUnreadCount,
  markRead as markNotificationRead, markUnread as markNotificationUnread,
  markAllRead,
} from '../../services/inAppNotifications';
import {
  TOOL_ANNOTATIONS_READONLY, TOOL_ANNOTATIONS_WRITE,
  TOOL_ANNOTATIONS_DELETE, TOOL_ANNOTATIONS_NON_IDEMPOTENT,
  demoDenied, ok,
} from './_shared';
import { canRead, canWrite } from '../scopes';

export function registerNotificationTools(server: McpServer, userId: number, scopes: string[] | null): void {
  const R = canRead(scopes, 'notifications');
  const W = canWrite(scopes, 'notifications');

  // --- NOTIFICATIONS ---

  if (R) server.registerTool(
    'list_notifications',
    {
      description: 'List in-app notifications for the current user.',
      inputSchema: {
        limit: z.number().int().positive().optional().default(20),
        offset: z.number().int().min(0).optional().default(0),
        unread_only: z.boolean().optional().default(false),
      },
      annotations: TOOL_ANNOTATIONS_READONLY,
    },
    async ({ limit, offset, unread_only }) => {
      const result = getNotifications(userId, { limit: limit ?? 20, offset: offset ?? 0, unreadOnly: unread_only ?? false });
      return ok(result);
    }
  );

  if (R) server.registerTool(
    'get_unread_notification_count',
    {
      description: 'Get the number of unread in-app notifications.',
      inputSchema: {},
      annotations: TOOL_ANNOTATIONS_READONLY,
    },
    async () => {
      const count = getUnreadCount(userId);
      return ok({ count });
    }
  );

  if (W) server.registerTool(
    'mark_notification_read',
    {
      description: 'Mark a single notification as read.',
      inputSchema: {
        notificationId: z.number().int().positive(),
      },
      annotations: TOOL_ANNOTATIONS_WRITE,
    },
    async ({ notificationId }) => {
      if (isDemoUser(userId)) return demoDenied();
      const success = markNotificationRead(notificationId, userId);
      if (!success) return { content: [{ type: 'text' as const, text: 'Notification not found.' }], isError: true };
      return ok({ success: true });
    }
  );

  if (W) server.registerTool(
    'mark_notification_unread',
    {
      description: 'Mark a single notification as unread.',
      inputSchema: {
        notificationId: z.number().int().positive(),
      },
      annotations: TOOL_ANNOTATIONS_WRITE,
    },
    async ({ notificationId }) => {
      if (isDemoUser(userId)) return demoDenied();
      const success = markNotificationUnread(notificationId, userId);
      if (!success) return { content: [{ type: 'text' as const, text: 'Notification not found.' }], isError: true };
      return ok({ success: true });
    }
  );

  if (W) server.registerTool(
    'mark_all_notifications_read',
    {
      description: "Mark all of the current user's notifications as read.",
      inputSchema: {},
      annotations: TOOL_ANNOTATIONS_WRITE,
    },
    async () => {
      if (isDemoUser(userId)) return demoDenied();
      const count = markAllRead(userId);
      return ok({ success: true, count });
    }
  );
}