groovehq-mcp 0.2.0 → 0.4.0

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/README.md CHANGED
@@ -15,8 +15,9 @@ Both repos use Groove's REST API for conversations. This one runs on GraphQL onl
15
15
  - `listConversations`: search and filter by keyword, state, agent, team, contact, channel, or tag
16
16
  - `getConversation`: get one ticket
17
17
  - `createConversation`: start a new ticket by sending an email
18
- - `updateConversation`: change the state, assign someone, or add tags
18
+ - `updateConversation`: change the state, assign or unassign someone, or add or remove tags
19
19
  - `closeConversation`: the most satisfying one
20
+ - `mergeConversations`: merge one ticket into another. This can't be undone
20
21
 
21
22
  **Messages**
22
23
 
@@ -60,6 +61,18 @@ Using a different MCP client? Have it run `npx -y groovehq-mcp` and set `GROOVE_
60
61
 
61
62
  > **Heads up:** the package is `groovehq-mcp`, with the `hq`. `groove-mcp` doesn't work.
62
63
 
64
+ ## Use as a library
65
+
66
+ You can run the same tools over your own transport, for example in a Cloudflare Worker. `createGrooveServer` returns a new MCP `Server` and connects nothing itself:
67
+
68
+ ```ts
69
+ import { createGrooveServer } from 'groovehq-mcp/server';
70
+
71
+ const server = createGrooveServer({ token: 'your_token_here', readOnly: true });
72
+ ```
73
+
74
+ `allowSend`, `allowMerge`, and `apiUrl` are optional too. Sending stays off unless you set `allowSend: true`, merging stays on unless you set `allowMerge: false`, and `readOnly` always wins.
75
+
63
76
  ## Handle with care
64
77
 
65
78
  This server can send real email to real customers. A few things keep that honest:
@@ -67,6 +80,7 @@ This server can send real email to real customers. A few things keep that honest
67
80
  - **Sending is off by default.** `sendMessage` and `createConversation` only appear when you set `GROOVE_ALLOW_SEND=1`.
68
81
  - **Read-only mode.** Set `GROOVE_READ_ONLY=1` to leave out every tool that writes, including drafts.
69
82
  - **Recipients are always explicit.** `createConversation` and `sendMessage` require a `to` address, and nothing is sent to a default.
83
+ - **Merging is permanent.** Only the target ticket stays, with its own contact, subject, and assignee. Replies and notes move over, tags are combined, and an open ticket reopens the target. `mergeConversations` is marked as destructive, and it refuses tickets with different contacts or your own drafts on the merged ticket unless told otherwise. Set `GROOVE_ALLOW_MERGE=0` to turn merging off.
70
84
  - **Failed updates tell you what happened.** Groove has no all-or-nothing update, so `updateConversation` can succeed halfway. When it does, the error says which steps already went through.
71
85
 
72
86
  Sending a draft from Groove may close the ticket, depending on your Groove settings.
@@ -78,7 +92,8 @@ Your MCP client will usually ask before a tool runs. For sending mail, it's a go
78
92
  - **Some of this API is undocumented.** Sending mail and adding notes are in the official docs. The read queries (`conversations` and `events`) aren't, but Groove's own web app uses them.
79
93
  - **Not tested with everything.** Our account only has email tickets and no knowledge base articles, so chat, widget, knowledge base search haven't been tried with real data.
80
94
  - **Drafts are personal.** They belong to the agent who owns the API token, and they only work on existing tickets.
81
- - **Some things aren't in here yet.** You can't send attachments, use cc and bcc when sending directly, remove tags, unassign a ticket, or set a contact's company.
95
+ - **Merged messages don't get sorted.** Groove adds them to the end of the ticket with their original dates, while `listMessages` always sorts by date.
96
+ - **Some things aren't in here yet.** You can't send attachments, use cc and bcc when sending directly, or set a contact's company.
82
97
 
83
98
  ## Development
84
99
 
@@ -114,6 +129,18 @@ To test drafts, add `--drafts` and set `GROOVE_TEST_TICKET` to a ticket you own.
114
129
  GROOVE_API_TOKEN=your_token_here GROOVE_TEST_TICKET=12345 npm run test:live -- --drafts
115
130
  ```
116
131
 
132
+ To test changes to a ticket, add `--update`. It finds a ticket whose subject starts with `[TEST]`, changes its tags and assignee, and puts them back. If you don't have one yet, run `--write` once:
133
+
134
+ ```bash
135
+ GROOVE_API_TOKEN=your_token_here npm run test:live -- --update
136
+ ```
137
+
138
+ To test merging, add `--merge`. It asks first, then sends 3 real mails to `GROOVE_TEST_TO` and a plus address of it, and merges those tickets into one that it closes again:
139
+
140
+ ```bash
141
+ GROOVE_API_TOKEN=your_token_here GROOVE_TEST_TO=you@example.com GROOVE_TEST_CHANNEL=ch_123 npm run test:live -- --merge
142
+ ```
143
+
117
144
  ## License
118
145
 
119
146
  MIT. Original work by [Christian Genco](https://github.com/christiangenco). Thanks for the head start!
@@ -1 +1 @@
1
- {"version":3,"file":"groove-client.d.ts","sourceRoot":"","sources":["../src/groove-client.ts"],"names":[],"mappings":"AAIA,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAgB;gBAElB,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,MAA8C;IAa9E,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IAiB5D,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBtD,MAAM,CAAC,CAAC,GAAG,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IAaxE,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC;CAkB7C"}
1
+ {"version":3,"file":"groove-client.d.ts","sourceRoot":"","sources":["../src/groove-client.ts"],"names":[],"mappings":"AAIA,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAgB;gBAElB,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,MAA8C;IAa9E,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IAqB5D,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBtD,MAAM,CAAC,CAAC,GAAG,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IAaxE,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC;CAkB7C"}
@@ -20,6 +20,10 @@ export class GrooveClient {
20
20
  catch (error) {
21
21
  if (error.response?.errors) {
22
22
  const graphqlError = error.response.errors[0];
23
+ if (graphqlError.extensions?.code === 'RESOURCE_MERGED') {
24
+ const target = String(graphqlError.extensions.new_conversation_id).replace(/^cnv_/, '#');
25
+ throw new Error(`Ticket was merged into ${target}`);
26
+ }
23
27
  // Groove reports an ID that never existed as deleted too
24
28
  if (graphqlError.message.includes('object of type Conversation is deleted')) {
25
29
  throw new Error('Ticket not found or deleted');
@@ -36,6 +40,8 @@ export class GrooveClient {
36
40
  return ticket;
37
41
  const response = await this.request(queries.getConversationId, { number: Number(number) });
38
42
  if (!response.conversation) {
43
+ // Groove finds no merged ticket by number, but its ID says where it went
44
+ await this.request(queries.getTicketNode, { id: `cnv_${number}` });
39
45
  throw new Error(`Ticket not found: ${ticket}`);
40
46
  }
41
47
  return response.conversation.id;
@@ -1 +1 @@
1
- {"version":3,"file":"groove-client.js","sourceRoot":"","sources":["../src/groove-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"groove-client.js","sourceRoot":"","sources":["../src/groove-client.ts"],"names":[],"mappings":"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"}