feat(api): bridge the Slack agent to the user's Linear and GitHub plugins

Merged
AV
2mo ago
+972-101

Links

Summary

  • A linked user's connected plugins reach the Slack agent through the credential proxy, the way superset mcp call-tool does. Linear and GitHub today; the token is decrypted per call inside the API and never handed to the model.
  • A curated subset per plugin (11 Linear, 12 GitHub: reads plus filing issues, commenting and opening PRs; no deletes, merges or bulk writes), enforced at discovery and at execution like the Superset allowlist.
  • Filed Linear issues and opened GitHub PRs show in the Changes footer with links. A reply that names a plugin the user hasn't connected gets a Connect button.

Why / Context

"Talk to Linear" was one of the three original asks. Only per-user plugin_connections give the agent tools, and both plugins already declare hosted MCP servers behind the proxy, so this is a bridge rather than new tool code.

How It Works

  • toolConnections(userId) in packages/trpc/src/router/plugins/connections.ts resolves each active connection to its install and bundled source and keeps plugins that expose tools; the integrations barrel re-exports it with listTools, callTool and templateScope.
  • dispatch.listTools/callTool take an optional AbortSignal, threaded through every upstream fetch including the session handshake, so plugin calls are bounded by the remaining run budget like MCP calls.
  • plugin-tools.ts beside the agent loop lists tools per connection with an in-process one-hour cache keyed by plugin, manifest version and auth method. A failed listing, or a failure resolving connections at all, logs and leaves the run with Superset tools only.
  • The agent registers linear_* / github_* tools from the curated subset, routes calls by prefix, and refuses anything outside the subset at execution. The system prompt gets one line per plugin: connected, connected but unavailable this run, or (only when the message names it) not connected.
  • The handler posts a "Connect " button linking to /plugins on web, a new deep-link passthrough to the desktop plugins page.

Manual QA Checklist

Needs a linked user with a Linear or GitHub plugin connection.

  • "file this as a Linear issue" creates the issue and the Changes footer links it
  • "what's open in Linear for me" answers from linear_list_issues
  • Ask for a Linear issue delete: refused
  • A user without GitHub asks about GitHub: reply says it isn't connected, Connect button appears, button opens the desktop plugins page
  • Disconnect the plugin, ask again: no linear_* tools offered

Testing

  • bun test src/app/api/integrations/slack in apps/api: 72 pass (10 new plugin tests, 2 new handler tests)
  • bun test in packages/trpc: 290 pass (worker's run)
  • bunx tsc --noEmit for apps/api, apps/web, packages/trpc: clean
  • bunx biome check on changed paths: clean
  • Not exercised against live Linear or GitHub: the reviewing account has no plugin connections, both remote MCP endpoints answer 401 unauthenticated. Linear tool names and the issue result shape were verified against the official Linear MCP; GitHub names come from the github-mcp-server README and its create responses from the Go source ({id, url} only, so the PR number is parsed from the URL).

Known Limitations

  • mentionsPlugin is a substring match on the display name, so a reply containing a github.com link for a user without GitHub draws the Connect button.
  • When a user holds several connections for one plugin, the newest wins.
  • save_issue and issue_write also edit a single issue when given an id; they are each server's only create path, so they stay in and the action record fires only on a create.

Rollout / Rollback

  • No flag: tools appear only for users who have connected a plugin, which today is nobody on the Slack surface. Rollback is a revert.

https://claude.ai/code/session_01YDDSQYG6WSZn4jXWTR3Pid


Summary by cubic

Bridges the Slack agent from Superset-only tools to a connected user's Linear and GitHub plugins through the credential proxy, so credentials stay server-side. Connected users can search, read, and create supported issues, comments, and pull requests; unavailable plugins surface a Connect button instead of failing the run.

Integration behavior

  • Exposes 11 Linear and 12 GitHub tools, with allowlists enforced during discovery and execution; destructive and bulk operations remain excluded.
  • Bounds plugin calls to the run deadline and caches tool listings for one hour by plugin installation, manifest version, and auth method; discovery gets its own 15-second cap so a hung plugin doesn't stall the run.
  • Records created issues and opened pull requests in the Changes footer, while treating edits as updates rather than creations.
  • Distinguishes connected, temporarily unavailable, and named-but-unconnected plugins in the agent context.

Slack delivery

  • Connect prompts use the reply client and link /plugins to the desktop plugins route, including when the agent has exhausted its run budget.
  • Connection or tool-listing failures leave the run on Superset tools; a failed listing is reported as unavailable rather than unconnected.
  • No feature flag or migration is required; rollback is a revert.

Summary by CodeRabbit

  • New Features

    • Slack Agent can use connected Linear and GitHub integrations for supported actions.
    • Added clearer progress updates while working with integrations.
    • Slack replies now include issue and pull request results with links.
    • When an unavailable integration is referenced, Slack displays a Connect button linking to the Plugins page.
    • Added a direct Plugins page entry point for integration setup.
  • Bug Fixes

    • Improved formatting and escaping for Slack action messages.
    • Added safer handling for integration connection, tool-loading, and execution failures.