Repository navigation
feat(integrations): Twenty CRM + Chatwoot, native HTTP MCP transport, Linear create fix - #406
Merged
Merged
Conversation
… Linear create fix - fix(linear): linear_write create sent both `team` and `teamId`; the hosted Linear MCP rejects unknown keys, so every create failed. Send only schema keys everywhere: comment uses issueId (never `id`, which edits a comment), comments read sends issueId only, mine asks list_issues for assignee "me". `team` is now documented as required and checked before the call. - feat(mcp): Streamable HTTP transport (`type: "http"`) with auth `headers`, session id + protocol version echo, re-initialize on a forgotten session, JSON or SSE replies (read until our response, so an open stream can't stall), per-call timeout, DELETE on close. Previously http entries were skipped as "not yet supported". - feat(twenty): twenty_read (search/list/record/pipeline) and twenty_write (create/update/note/task, no delete) over Twenty's execute_tool, sending the exact shapes it validates (select on reads, position on creates, composite name/emails/domainName, amounts in micros). - feat(chatwoot): chatwoot_read / chatwoot_write over Chatwoot's REST API (it has no MCP): conversations, transcript, contacts, inboxes/agents/labels; reply (customer-visible, guidance says only when asked), private note, status, assign, label (merged, add-only). Token never follows a redirect; customer text is marked as untrusted data. - config: chatwootUrl/chatwootToken/chatwootAccountId in ~/.tsforge/config.json; TSFORGE_NO_TWENTY, TSFORGE_TWENTY_RAW, TSFORGE_NO_CHATWOOT. - tests: strict fakes that reject unknown fields (the check that would have caught the Linear bug), Twenty calls validated against its real v2.41 input schemas + field names (fixture), a real local HTTP server for the transport, mutation-checked; opt-in live suite (TSFORGE_LIVE=1) against real instances. - docs: Twenty and Chatwoot pages; MCP http transport; Linear team; settings.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
tsforge | 21d1797 | Commit Preview URL Branch Preview URL |
Sep 29 2026, 11:58 AM |
GHSA-3wwx-pv8p-q78v: WebSocket permessage-deflate DoS in undici >=7.28.0 <7.29.1. Reaches the tree through the root override and miniflare's exact 7.29.0 pin; the override lifts both to 7.30.0. osv-scanner: no issues.
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
linear_write createsent bothteamandteamId. The hosted Linear MCP rejects unknown keys, so every create failed ("Unrecognized key: teamId"). Every Linear call now sends only schema keys:commentusesissueId(neverid, which edits a comment),commentssendsissueIdonly, andmineaskslist_issuesforassignee: "me"(before, it listed everyone's issues).teamis documented as required and checked up front.type: "http"+headers): Streamable HTTP, JSON or SSE replies (read only until our response, so an open stream can't stall), session id + protocol-version echo, re-initialize on a forgotten session, per-call timeout, DELETE on close. Until nowhttpentries were skipped as "not yet supported".twenty_read(search / list / record with attached notes and tasks / pipeline) andtwenty_write(create / update / note / task; no delete). Twenty's MCP is a catalog → learn_tools → execute_tool meta-surface over ~300 tools. The verbs callexecute_toolwith the exact shapes Twenty validates (selecton reads,positionon creates, composite name/emails/domainName, amounts in micros).chatwoot_read(conversations, transcript, contacts, inboxes/agents/labels) andchatwoot_write(reply, private note, status, assign, label). A reply is customer-visible, so the guidance says send only when asked and otherwise leave a private-note draft. Labels merge (Chatwoot's endpoint replaces the set). The token never follows a redirect, and customer text is marked as untrusted data.chatwootUrl/chatwootToken/chatwootAccountIdin~/.tsforge/config.json;TSFORGE_NO_TWENTY,TSFORGE_TWENTY_RAW,TSFORGE_NO_CHATWOOT.team; settings/flags.How it's tested
mainwith the exact production error.tests/fixtures/twenty-schemas.json: metadata only, no CRM data). Wrong field, missingselect/position, bad enum, or an unknownselectname all fail as they would live.Bun.serveMCP server (JSON, SSE, SSE-never-closes, auth, sessions, 404 re-init, timeout, isError, close).TSFORGE_LIVE=1, opt-in, skipped in CI) against real self-hosted instances. Twenty reads and a full create → update → note → task → read-back → destroy cycle pass. Chatwoot reads pass. The live runs caught two bugs the fakes couldn't: Twenty'sgroup_byshape (dimensions/value), and soft-deleted records keeping unique domains (the duplicate error is now explained in plain words).bun run ci:local: 6311 pass, 0 fail. Docs build is clean.Not in this PR
notion-ops/sentry-opsguess payload keys the same way the Linear bug did (e.g.{ id, pageId, page_id }). Worth the same strict-schema treatment in a follow-up.