The Write Tools subsystem, introduced in v2.1, provides a controlled surface for mutating Help Scout state. It implements a two-tier permission model, a confirmation contract for customer-visible actions, and a "dry-run" capability to ensure safety and predictability in LLM-driven operations.
Write operations are not advertised as individual MCP tools. Instead, they are encapsulated within a single gateway tool: write_help_scout src/tools/gateway.ts32 This tool delegates execution to the WriteHandler class src/tools/writes.ts241 which manages a registry of 13 specific mutation operations.
Access to write operations is governed by two environment variables, creating a safety gradient:
| Tier | Permission Gate | Mutation Classes Included | Description |
|---|---|---|---|
| Tier 1 | HELPSCOUT_ENABLE_WRITES | nonDestructive, reversible | Internal changes (notes, tags, status) that do not alert customers. |
| Tier 2 | HELPSCOUT_ENABLE_CUSTOMER_VISIBLE_WRITES | externallyVisible | Actions that email customers (replies, publishing drafts). |
Sources: src/tools/writes.ts18-21 src/tools/gateway.ts208-223
To prevent accidental "hallucinated" emails, externallyVisible operations (Tier 2) require a Confirmation Contract. The request must include three specific metadata fields that match the operation's arguments:
confirm: trueconfirmOperation: Must match the name argument exactly.targetId: Must match the conversationId argument exactly.If these do not match, the WriteHandler rejects the request before any API call is made src/tools/gateway.ts158-170 src/tools/gateway.ts253-272
The following diagram illustrates the flow from a Natural Language request to a Help Scout API mutation.
Sources: src/tools/gateway.ts236-285 src/tools/writes.ts241-278
The WriteHandler defines 13 operations, each categorized by a MutationClass which determines its Tier and confirmation requirements src/tools/writes.ts1012-1028
These operations require HELPSCOUT_ENABLE_WRITES=true.
| Operation | Mutation Class | Target | Description |
|---|---|---|---|
createNote | nonDestructive | Conversation | Adds an internal note src/tools/writes.ts316 |
createDraftReply | nonDestructive | Conversation | Creates a draft (not sent to customer) src/tools/writes.ts348 |
updateConversationStatus | reversible | Conversation | Changes status (active, pending, closed) src/tools/writes.ts446 |
assignConversation | reversible | Conversation | Assigns to a specific user src/tools/writes.ts488 |
unassignConversation | reversible | Conversation | Removes assignment src/tools/writes.ts526 |
addConversationTags | reversible | Conversation | Appends tags (Read-Modify-Write) src/tools/writes.ts559 |
removeConversationTags | reversible | Conversation | Removes tags (Read-Modify-Write) src/tools/writes.ts607 |
updateConversationFields | reversible | Conversation | Updates custom fields src/tools/writes.ts655 |
snoozeConversation | reversible | Conversation | Sets a snooze timer src/tools/writes.ts708 |
unsnoozeConversation | reversible | Conversation | Removes snooze src/tools/writes.ts753 |
moveConversation | reversible | Conversation | Moves ticket to a different inbox src/tools/writes.ts787 |
These require HELPSCOUT_ENABLE_CUSTOMER_VISIBLE_WRITES=true and the Confirmation Contract.
| Operation | Mutation Class | Target | Description |
|---|---|---|---|
sendReply | externallyVisible | Conversation | Sends an email directly to the customer src/tools/writes.ts835 |
publishDraft | externallyVisible | Thread | Converts an existing draft into a sent reply src/tools/writes.ts919 |
Sources: src/tools/writes.ts1012-1028 tests/mcp-client-dogfood.ts135-150
Every write operation supports a dryRun: true argument src/tools/gateway.ts171-173 When active, the WriteHandler invokes the operation's plan() method to return a PlannedRequest object without calling the Help Scout API. This allows the LLM or user to verify the exact HTTP method, path, and body that would be sent src/tools/writes.ts28-42 src/tools/writes.ts262-269
Operations like addConversationTags and updateConversationFields implement RMW logic to prevent overwriting existing data.
GET request for the conversation src/tools/writes.ts579-583PUT or PATCH request is sent with the consolidated state src/tools/writes.ts592Upon a successful write, the WriteHandler automatically invalidates relevant cache entries (e.g., the conversation and its thread list) to ensure subsequent reads reflect the changes immediately src/tools/writes.ts275-276
The system uses a strict taxonomy to bridge the internal operation registry with the MCP tool surface.
Sources: src/tools/gateway.ts67-80 src/tools/writes.ts51-63 src/tools/writes.ts28-42
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.