@lizzythelizard/whatsapp-mcp 0.1.3 → 0.1.5
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.
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +1 -0
- package/dist/auth.js.map +1 -1
- package/dist/index.js +32 -9
- package/dist/index.js.map +1 -1
- package/dist/store.d.ts +23 -9
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +16 -10
- package/dist/store.js.map +1 -1
- package/dist/sync.d.ts +6 -2
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +61 -2
- package/dist/sync.js.map +1 -1
- package/dist/tools.d.ts +4 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +69 -60
- package/dist/tools.js.map +1 -1
- package/package.json +59 -45
- package/.github/dependabot.yml +0 -20
- package/.github/workflows/auto-merge.yml +0 -19
- package/.github/workflows/ci.yml +0 -75
- package/.vscode/extensions.json +0 -7
- package/.vscode/settings.json +0 -12
- package/AGENTS.md +0 -42
- package/Dockerfile +0 -25
- package/dist/syncManager.d.ts +0 -29
- package/dist/syncManager.d.ts.map +0 -1
- package/dist/syncManager.js +0 -79
- package/dist/syncManager.js.map +0 -1
- package/eslint.config.mjs +0 -32
- package/src/auth.test.ts +0 -138
- package/src/auth.ts +0 -58
- package/src/index.ts +0 -45
- package/src/store.test.ts +0 -353
- package/src/store.ts +0 -182
- package/src/sync.test.ts +0 -304
- package/src/sync.ts +0 -170
- package/src/tools.test.ts +0 -254
- package/src/tools.ts +0 -132
- package/tsconfig.json +0 -19
- package/tsconfig.test.json +0 -7
- package/vitest.config.ts +0 -7
package/src/tools.test.ts
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, Mock } from 'vitest'
|
|
2
|
-
import { z } from 'zod'
|
|
3
|
-
import { registerWhatsAppTools } from './tools.js'
|
|
4
|
-
import type { WhatsAppStore } from './store.js'
|
|
5
|
-
import type { WhatsAppHandler } from './sync.js'
|
|
6
|
-
import type { CallToolResult, ReadResourceResult } from '@modelcontextprotocol/sdk/types'
|
|
7
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'
|
|
8
|
-
|
|
9
|
-
function createMockServer(): McpServer & { registerResource: Mock, registerTool: Mock } {
|
|
10
|
-
return {
|
|
11
|
-
registerResource: vi.fn(),
|
|
12
|
-
registerTool: vi.fn(),
|
|
13
|
-
} as McpServer & { registerResource: Mock, registerTool: Mock }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function createMockStore(): WhatsAppStore {
|
|
17
|
-
return {
|
|
18
|
-
bind: vi.fn(),
|
|
19
|
-
getChats: vi.fn().mockReturnValue([]),
|
|
20
|
-
getChat: vi.fn().mockReturnValue(undefined),
|
|
21
|
-
getContacts: vi.fn().mockReturnValue([]),
|
|
22
|
-
getContact: vi.fn().mockReturnValue(undefined),
|
|
23
|
-
getMessages: vi.fn().mockReturnValue([]),
|
|
24
|
-
getMessage: vi.fn().mockReturnValue(undefined),
|
|
25
|
-
reset: vi.fn(),
|
|
26
|
-
getAuth: vi.fn(),
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function createMockSync(): WhatsAppHandler {
|
|
31
|
-
return {
|
|
32
|
-
close: vi.fn(),
|
|
33
|
-
getStatus: vi.fn(),
|
|
34
|
-
sendMessage: vi.fn(),
|
|
35
|
-
setArchived: vi.fn(),
|
|
36
|
-
setRead: vi.fn(),
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
describe('registerWhatsAppTools', () => {
|
|
41
|
-
it('registers resources and tools on the server', () => {
|
|
42
|
-
const server = createMockServer()
|
|
43
|
-
const store = createMockStore()
|
|
44
|
-
const sync = createMockSync()
|
|
45
|
-
registerWhatsAppTools(server, store, sync)
|
|
46
|
-
expect(server.registerResource).toHaveBeenCalled()
|
|
47
|
-
expect(server.registerTool).toHaveBeenCalled()
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('registers 5 resources (chats, chat, contacts, contact, messages, message)', () => {
|
|
51
|
-
const server = createMockServer()
|
|
52
|
-
const store = createMockStore()
|
|
53
|
-
const sync = createMockSync()
|
|
54
|
-
registerWhatsAppTools(server, store, sync)
|
|
55
|
-
expect(server.registerResource).toHaveBeenCalledTimes(6)
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
it('registers 3 tools (send_message, set_chat_archived, set_chat_read)', () => {
|
|
59
|
-
const server = createMockServer()
|
|
60
|
-
const store = createMockStore()
|
|
61
|
-
const sync = createMockSync()
|
|
62
|
-
registerWhatsAppTools(server, store, sync)
|
|
63
|
-
expect(server.registerTool).toHaveBeenCalledTimes(3)
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
describe('send_message handler', () => {
|
|
68
|
-
it('calls sync.sendMessage with jid and message', async () => {
|
|
69
|
-
const server = createMockServer()
|
|
70
|
-
const store = createMockStore()
|
|
71
|
-
const sync = createMockSync()
|
|
72
|
-
vi.mocked(sync.sendMessage).mockResolvedValue({
|
|
73
|
-
key: { id: 'm1', remoteJid: 'user@s.whatsapp.net' },
|
|
74
|
-
message: { conversation: 'Hello!' },
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
registerWhatsAppTools(server, store, sync)
|
|
78
|
-
const sendMessageTool = server.registerTool.mock.calls.find((c: string[]) => c[0] === 'send_message')
|
|
79
|
-
const handler = sendMessageTool?.[2] as (input: { jid: string, message: string }) => Promise<CallToolResult>
|
|
80
|
-
|
|
81
|
-
const result: CallToolResult = await handler({ jid: 'user@s.whatsapp.net', message: 'Hello!' })
|
|
82
|
-
expect(sync.sendMessage).toHaveBeenCalledWith('user@s.whatsapp.net', 'Hello!')
|
|
83
|
-
expect(result.isError).toBe(false)
|
|
84
|
-
expect(result.content[0]).toEqual({ text: 'Message sent to user@s.whatsapp.net: "Hello!"', type: 'text' })
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
it('returns error result when sync.sendMessage fails', async () => {
|
|
88
|
-
const server = createMockServer()
|
|
89
|
-
const store = createMockStore()
|
|
90
|
-
const sync = createMockSync()
|
|
91
|
-
vi.mocked(sync.sendMessage).mockRejectedValue(new Error('connection lost'))
|
|
92
|
-
|
|
93
|
-
registerWhatsAppTools(server, store, sync)
|
|
94
|
-
const sendMessageTool = server.registerTool.mock.calls.find((c: string[]) => c[0] === 'send_message')
|
|
95
|
-
const handler = sendMessageTool?.[2] as (input: { jid: string, message: string }) => Promise<CallToolResult>
|
|
96
|
-
|
|
97
|
-
const result: CallToolResult = await handler({ jid: 'user@s.whatsapp.net', message: 'Hello!' })
|
|
98
|
-
expect(result.isError).toBe(true)
|
|
99
|
-
expect(result.content[0]).toEqual({ text: 'Error: connection lost', type: 'text' })
|
|
100
|
-
})
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
describe('set_chat_archived handler', () => {
|
|
104
|
-
it('calls sync.setArchived with jid and archived', async () => {
|
|
105
|
-
const server = createMockServer()
|
|
106
|
-
const store = createMockStore()
|
|
107
|
-
const sync = createMockSync()
|
|
108
|
-
vi.mocked(sync.setArchived).mockResolvedValue(undefined)
|
|
109
|
-
|
|
110
|
-
registerWhatsAppTools(server, store, sync)
|
|
111
|
-
const tool = server.registerTool.mock.calls.find((c: string[]) => c[0] === 'set_chat_archived')
|
|
112
|
-
const handler = tool?.[2] as (input: { jid: string, archived: boolean }) => Promise<CallToolResult>
|
|
113
|
-
|
|
114
|
-
const result: CallToolResult = await handler({ jid: 'user@s.whatsapp.net', archived: true })
|
|
115
|
-
expect(sync.setArchived).toHaveBeenCalledWith('user@s.whatsapp.net', true)
|
|
116
|
-
expect(result.isError).toBe(false)
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
it('returns error when sync.setArchived fails', async () => {
|
|
120
|
-
const server = createMockServer()
|
|
121
|
-
const store = createMockStore()
|
|
122
|
-
const sync = createMockSync()
|
|
123
|
-
vi.mocked(sync.setArchived).mockRejectedValue(new Error('no chat'))
|
|
124
|
-
|
|
125
|
-
registerWhatsAppTools(server, store, sync)
|
|
126
|
-
const tool = server.registerTool.mock.calls.find((c: string[]) => c[0] === 'set_chat_archived')
|
|
127
|
-
const handler = tool?.[2] as (input: { jid: string, archived: boolean }) => Promise<CallToolResult>
|
|
128
|
-
|
|
129
|
-
const result: CallToolResult = await handler({ jid: 'user@s.whatsapp.net', archived: false })
|
|
130
|
-
expect(result.isError).toBe(true)
|
|
131
|
-
expect(result.content[0]).toEqual({ text: 'Error: no chat', type: 'text' })
|
|
132
|
-
})
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
describe('set_chat_read handler', () => {
|
|
136
|
-
it('calls sync.setRead with jid and read', async () => {
|
|
137
|
-
const server = createMockServer()
|
|
138
|
-
const store = createMockStore()
|
|
139
|
-
const sync = createMockSync()
|
|
140
|
-
vi.mocked(sync.setRead).mockResolvedValue(undefined)
|
|
141
|
-
|
|
142
|
-
registerWhatsAppTools(server, store, sync)
|
|
143
|
-
const tool = server.registerTool.mock.calls.find((c: string[]) => c[0] === 'set_chat_read')
|
|
144
|
-
const handler = tool?.[2] as (input: { jid: string, read: boolean }) => Promise<CallToolResult>
|
|
145
|
-
|
|
146
|
-
const result: CallToolResult = await handler({ jid: 'user@s.whatsapp.net', read: true })
|
|
147
|
-
expect(sync.setRead).toHaveBeenCalledWith('user@s.whatsapp.net', true)
|
|
148
|
-
expect(result.isError).toBe(false)
|
|
149
|
-
})
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
describe('resource handlers', () => {
|
|
153
|
-
it('chats resource handler returns store.getChats() as content', async () => {
|
|
154
|
-
const server = createMockServer()
|
|
155
|
-
const store = createMockStore()
|
|
156
|
-
const sync = createMockSync()
|
|
157
|
-
vi.mocked(store.getChats).mockReturnValue([{ id: 'c1', name: 'Chat1' }])
|
|
158
|
-
|
|
159
|
-
registerWhatsAppTools(server, store, sync)
|
|
160
|
-
const call = server.registerResource.mock.calls.find((c: string[]) => c[0] === 'chats')
|
|
161
|
-
const handler = call?.[3] as () => Promise<ReadResourceResult>
|
|
162
|
-
|
|
163
|
-
const result: ReadResourceResult = await handler()
|
|
164
|
-
expect(result.contents).toHaveLength(1)
|
|
165
|
-
expect(result.contents[0].uri).toBe('chats://app/c1')
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
it('single chat resource handler returns store.getChat(chatId)', async () => {
|
|
169
|
-
const server = createMockServer()
|
|
170
|
-
const store = createMockStore()
|
|
171
|
-
const sync = createMockSync()
|
|
172
|
-
vi.mocked(store.getChat).mockReturnValue({ id: 'c1', name: 'Found' })
|
|
173
|
-
|
|
174
|
-
registerWhatsAppTools(server, store, sync)
|
|
175
|
-
const call = server.registerResource.mock.calls.find((c: string[]) => c[0] === 'chat')
|
|
176
|
-
const handler = call?.[3] as (input: undefined, params: { chatId: string }) => Promise<ReadResourceResult>
|
|
177
|
-
|
|
178
|
-
const result: ReadResourceResult = await handler(undefined, { chatId: 'c1' })
|
|
179
|
-
expect(result.contents).toHaveLength(1)
|
|
180
|
-
expect(result.contents[0].uri).toBe('chats://app/c1')
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
it('contacts resource handler returns store.getContacts()', async () => {
|
|
184
|
-
const server = createMockServer()
|
|
185
|
-
const store = createMockStore()
|
|
186
|
-
const sync = createMockSync()
|
|
187
|
-
vi.mocked(store.getContacts).mockReturnValue([{ id: 'c1', name: 'Contact1' }])
|
|
188
|
-
|
|
189
|
-
registerWhatsAppTools(server, store, sync)
|
|
190
|
-
const call = server.registerResource.mock.calls.find((c: string[]) => c[0] === 'contacts')
|
|
191
|
-
const handler = call?.[3] as () => Promise<ReadResourceResult>
|
|
192
|
-
|
|
193
|
-
const result: ReadResourceResult = await handler()
|
|
194
|
-
expect(result.contents).toHaveLength(1)
|
|
195
|
-
expect(result.contents[0].uri).toBe('contacts://app/c1')
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
it('single contact resource handler returns store.getContact(contactId)', async () => {
|
|
199
|
-
const server = createMockServer()
|
|
200
|
-
const store = createMockStore()
|
|
201
|
-
const sync = createMockSync()
|
|
202
|
-
vi.mocked(store.getContact).mockReturnValue({ id: 'c1', name: 'Found' })
|
|
203
|
-
|
|
204
|
-
registerWhatsAppTools(server, store, sync)
|
|
205
|
-
const call = server.registerResource.mock.calls.find((c: string[]) => c[0] === 'contact')
|
|
206
|
-
const handler = call?.[3] as (input: undefined, params: { contactId: string }) => Promise<ReadResourceResult>
|
|
207
|
-
|
|
208
|
-
const result: ReadResourceResult = await handler(undefined, { contactId: 'c1' })
|
|
209
|
-
expect(result.contents).toHaveLength(1)
|
|
210
|
-
expect(result.contents[0].uri).toBe('contacts://app/c1')
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
it('messages resource handler returns store.getMessages()', async () => {
|
|
214
|
-
const server = createMockServer()
|
|
215
|
-
const store = createMockStore()
|
|
216
|
-
const sync = createMockSync()
|
|
217
|
-
vi.mocked(store.getMessages).mockReturnValue([{ key: { id: 'm1' }, message: { conversation: 'hi' } }])
|
|
218
|
-
|
|
219
|
-
registerWhatsAppTools(server, store, sync)
|
|
220
|
-
const call = server.registerResource.mock.calls.find((c: string[]) => c[0] === 'messages')
|
|
221
|
-
const handler = call?.[3] as () => Promise<ReadResourceResult>
|
|
222
|
-
|
|
223
|
-
const result: ReadResourceResult = await handler()
|
|
224
|
-
expect(result.contents).toHaveLength(1)
|
|
225
|
-
expect(result.contents[0].uri).toBe('messages://app/m1')
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
it('single message resource handler returns store.getMessage(messageId)', async () => {
|
|
229
|
-
const server = createMockServer()
|
|
230
|
-
const store = createMockStore()
|
|
231
|
-
const sync = createMockSync()
|
|
232
|
-
vi.mocked(store.getMessage).mockReturnValue({ key: { id: 'm1' }, message: { conversation: 'found' } })
|
|
233
|
-
|
|
234
|
-
registerWhatsAppTools(server, store, sync)
|
|
235
|
-
const call = server.registerResource.mock.calls.find((c: string[]) => c[0] === 'message')
|
|
236
|
-
const handler = call?.[3] as (input: undefined, params: { messageId: string }) => Promise<ReadResourceResult>
|
|
237
|
-
|
|
238
|
-
const result: ReadResourceResult = await handler(undefined, { messageId: 'm1' })
|
|
239
|
-
expect(result.contents).toHaveLength(1)
|
|
240
|
-
expect(result.contents[0].uri).toBe('messages://app/m1')
|
|
241
|
-
})
|
|
242
|
-
|
|
243
|
-
it('resource returns empty array when no data exists', async () => {
|
|
244
|
-
const server = createMockServer()
|
|
245
|
-
const store = createMockStore()
|
|
246
|
-
|
|
247
|
-
registerWhatsAppTools(server, store, createMockSync())
|
|
248
|
-
const call = server.registerResource.mock.calls.find((c: string[]) => c[0] === 'chats')
|
|
249
|
-
const handler = call?.[3] as () => Promise<ReadResourceResult>
|
|
250
|
-
|
|
251
|
-
const result: ReadResourceResult = await handler()
|
|
252
|
-
expect(result.contents).toEqual([])
|
|
253
|
-
})
|
|
254
|
-
})
|
package/src/tools.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp'
|
|
2
|
-
import { ChatWithId, ContactWithId, MessageWithId, WhatsAppStore } from './store.js'
|
|
3
|
-
import { WhatsAppHandler } from './sync.js'
|
|
4
|
-
import { CallToolResult, ListResourcesResult, ReadResourceResult } from '@modelcontextprotocol/sdk/types'
|
|
5
|
-
import z from 'zod'
|
|
6
|
-
import { WAMessage } from '@whiskeysockets/baileys'
|
|
7
|
-
|
|
8
|
-
export function registerWhatsAppTools(server: McpServer, store: WhatsAppStore, sync: WhatsAppHandler) {
|
|
9
|
-
registerChatsResources(server, store)
|
|
10
|
-
registerContactsResources(server, store)
|
|
11
|
-
registerMessagesResources(server, store)
|
|
12
|
-
registerMessageTools(server, sync)
|
|
13
|
-
registerChatTools(server, sync)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function registerChatsResources(server: McpServer, store: WhatsAppStore) {
|
|
17
|
-
server.registerResource(
|
|
18
|
-
'chats',
|
|
19
|
-
'chats://app',
|
|
20
|
-
{ title: 'All WhatsApp Chats', description: 'List WhatsApp chats', mimeType: 'application/json' },
|
|
21
|
-
() => toReadResource(store.getChats().flatMap(chatToReadResource)))
|
|
22
|
-
server.registerResource(
|
|
23
|
-
'chat',
|
|
24
|
-
new ResourceTemplate('chats://app/{chatId}', { list: () => toListResource(store.getChats().flatMap(chatToListResource)) }),
|
|
25
|
-
{ title: 'A single WhatsApp Chat', description: 'Details of a single WhatsApp chat', mimeType: 'application/json' },
|
|
26
|
-
(_, { chatId }) => toReadResource(chatToReadResource(store.getChat(chatId as string))))
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const chatToReadResource = (chat: ChatWithId | undefined) => chat
|
|
30
|
-
? [{ uri: `chats://app/${chat.id}`, mimeType: 'application/json', text: JSON.stringify(chat) }]
|
|
31
|
-
: []
|
|
32
|
-
|
|
33
|
-
const chatToListResource = (chat: ChatWithId | undefined) => chat
|
|
34
|
-
? [{ uri: `chats://app/${chat.id}`, name: chat.name ?? chat.id }]
|
|
35
|
-
: []
|
|
36
|
-
|
|
37
|
-
function registerContactsResources(server: McpServer, store: WhatsAppStore) {
|
|
38
|
-
server.registerResource(
|
|
39
|
-
'contacts',
|
|
40
|
-
'contacts://app',
|
|
41
|
-
{ title: 'All WhatsApp Contacts', description: 'List WhatsApp contacts', mimeType: 'application/json' },
|
|
42
|
-
() => toReadResource(store.getContacts().flatMap(contactToReadResource)))
|
|
43
|
-
server.registerResource(
|
|
44
|
-
'contact',
|
|
45
|
-
new ResourceTemplate('contacts://app/{contactId}', { list: () => toListResource(store.getContacts().flatMap(contactToListResource)) }),
|
|
46
|
-
{ title: 'A single WhatsApp Contact', description: 'Details of a single WhatsApp contact', mimeType: 'application/json' },
|
|
47
|
-
(_, { contactId }) => toReadResource(contactToReadResource(store.getContact(contactId as string))))
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const contactToReadResource = (contact: ContactWithId | undefined) => contact
|
|
51
|
-
? [{ uri: `contacts://app/${contact.id}`, mimeType: 'application/json', text: JSON.stringify(contact) }]
|
|
52
|
-
: []
|
|
53
|
-
|
|
54
|
-
const contactToListResource = (contact: ContactWithId | undefined) => contact
|
|
55
|
-
? [{ uri: `contacts://app/${contact.id}`, name: contact.name ?? contact.id }]
|
|
56
|
-
: []
|
|
57
|
-
|
|
58
|
-
function registerMessagesResources(server: McpServer, store: WhatsAppStore) {
|
|
59
|
-
server.registerResource(
|
|
60
|
-
'messages',
|
|
61
|
-
'messages://app',
|
|
62
|
-
{ title: 'All WhatsApp Messages', description: 'List WhatsApp messages', mimeType: 'application/json' },
|
|
63
|
-
() => toReadResource(store.getMessages().flatMap(messageToReadResource)))
|
|
64
|
-
server.registerResource(
|
|
65
|
-
'message',
|
|
66
|
-
new ResourceTemplate('messages://app/{messageId}', { list: () => toListResource(store.getMessages().flatMap(messageToListResource)) }),
|
|
67
|
-
{ title: 'A single WhatsApp Message', description: 'Details of a single WhatsApp message', mimeType: 'application/json' },
|
|
68
|
-
(_, { messageId }) => toReadResource(messageToReadResource(store.getMessage(messageId as string))))
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const messageToReadResource = (message: MessageWithId | undefined) => message
|
|
72
|
-
? [{ uri: `messages://app/${message.key.id}`, mimeType: 'application/json', text: JSON.stringify(message) }]
|
|
73
|
-
: []
|
|
74
|
-
|
|
75
|
-
const messageToListResource = (message: MessageWithId | undefined) => message
|
|
76
|
-
? [{ uri: `messages://app/${message.key.id}`, name: message.key.id }]
|
|
77
|
-
: []
|
|
78
|
-
|
|
79
|
-
const toReadResource = (t: ReadResourceResult['contents']) => ({ contents: t })
|
|
80
|
-
const toListResource = (t: ListResourcesResult['resources']) => ({ resources: t })
|
|
81
|
-
|
|
82
|
-
function registerMessageTools(server: McpServer, sync: WhatsAppHandler) {
|
|
83
|
-
server.registerTool(
|
|
84
|
-
'send_message',
|
|
85
|
-
{ description: 'Send a WhatsApp-Message to a given JID.', inputSchema: SendMessageSchema },
|
|
86
|
-
args => sync.sendMessage(args.jid, args.message).then(messageToText).then(toCallResult).catch(toCallError),
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const messageToText = (message: WAMessage): string => {
|
|
91
|
-
return `Message sent to ${message.key.remoteJid ?? 'unknown'}: "${message.message?.conversation ?? 'unknown'}"`
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function registerChatTools(server: McpServer, sync: WhatsAppHandler) {
|
|
95
|
-
server.registerTool(
|
|
96
|
-
'set_chat_archived',
|
|
97
|
-
{ description: 'Set a WhatsApp chat as archived or unarchived.', inputSchema: ArchiveChatSchema },
|
|
98
|
-
args => sync.setArchived(args.jid, args.archived).then(() => `Chat ${args.jid} archived status set to ${args.archived.toString()}`).then(toCallResult).catch(toCallError),
|
|
99
|
-
)
|
|
100
|
-
server.registerTool(
|
|
101
|
-
'set_chat_read',
|
|
102
|
-
{ description: 'Set a WhatsApp chat as read or unread.', inputSchema: ReadChatSchema },
|
|
103
|
-
args => sync.setRead(args.jid, args.read).then(() => `Chat ${args.jid} read status set to ${args.read.toString()}`).then(toCallResult).catch(toCallError),
|
|
104
|
-
)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const JidSchema = z.union([
|
|
108
|
-
z.string().min(1, 'JID is required').endsWith('@s.whatsapp.net', 'JID not a valid WhatsApp JID)'),
|
|
109
|
-
z.string().min(1, 'JID is required').endsWith('@g.us', 'JID not a valid WhatsApp JID)'),
|
|
110
|
-
]).describe('The JID of the recipient or chat. For example 41791234567@s.whatsapp.net for an individual or 1234567890-1234567890@g.us for a group')
|
|
111
|
-
|
|
112
|
-
const SendMessageSchema = z.object({
|
|
113
|
-
jid: JidSchema,
|
|
114
|
-
message: z.string()
|
|
115
|
-
.min(1, 'Message body is required')
|
|
116
|
-
.describe('The body of the message to be sent. Can contain unicode characters like emojis.'),
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
const ArchiveChatSchema = z.object({
|
|
120
|
-
jid: JidSchema,
|
|
121
|
-
archived: z.boolean()
|
|
122
|
-
.describe('Whether the chat should be archived (true) or unarchived (false).'),
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
const ReadChatSchema = z.object({
|
|
126
|
-
jid: JidSchema,
|
|
127
|
-
read: z.boolean()
|
|
128
|
-
.describe('Whether the chat should be marked as read (true) or unread (false).'),
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
const toCallResult = (t: string): CallToolResult => ({ content: [{ type: 'text', text: t }], isError: false })
|
|
132
|
-
const toCallError = (error: Error): CallToolResult => ({ content: [{ type: 'text', text: `Error: ${error.message}` }], isError: true })
|
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"outDir": "dist",
|
|
7
|
-
"rootDir": "src",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"declaration": true,
|
|
13
|
-
"declarationMap": true,
|
|
14
|
-
"sourceMap": true,
|
|
15
|
-
"types": ["node"]
|
|
16
|
-
},
|
|
17
|
-
"include": ["src/**/*"],
|
|
18
|
-
"exclude": ["node_modules", "dist", "src/**/*.test.ts"]
|
|
19
|
-
}
|
package/tsconfig.test.json
DELETED