Skip to content
461 linesCodeBlameRaw
1import type { Provider } from "./integrations";
2
3/**
4 * The connector catalog: every tool g1t connects to, or will, in one list.
5 * The workspace's Integrations page and your own Integrations settings are
6 * both drawn from it, so a new connector is added here, once.
7 *
8 * A connector is `available` when g1t can set it up today (its `href` is
9 * where), and `soon` while it is planned. `scopes` says who connects it:
10 *
11 * - `workspace`: an owner connects it once, for everyone in the workspace.
12 * - `personal`: each person connects their own account, and it follows them
13 * into every workspace they belong to (a calendar, a personal sign-in).
14 *
15 * A connector with both scopes can say something different for each, in
16 * `personal`: its own description, status, capabilities or setup page.
17 * `connectorView` resolves that into what one context shows.
18 *
19 * Paths in `href` are g1t's own pages. `:workspace` stands for the
20 * workspace's slug.
21 */
22
23export type ConnectorScope = "workspace" | "personal";
24export type ConnectorStatus = "available" | "soon";
25
26export type ConnectorCategory =
27 | "code"
28 | "issues"
29 | "chat"
30 | "calendar"
31 | "docs"
32 | "monitoring"
33 | "cloud"
34 | "ai"
35 | "data"
36 | "crm"
37 | "design"
38 | "security"
39 | "files";
40
41/** What a connector lets g1t do, as the small tags on its card. */
42export type ConnectorCapability =
43 | "Agents can read"
44 | "Agents can act"
45 | "Opens issues"
46 | "Writes back"
47 | "Imports repositories"
48 | "Signs you in"
49 | "Sends events"
50 | "Alerts into chat"
51 | "Sets your status"
52 | "Finds a time"
53 | "AI provider"
54 | "Deploys"
55 | "Syncs people";
56
57export type Connector = {
58 /** Stable and unique: used in links and requests. */
59 id: string;
60 name: string;
61 category: ConnectorCategory;
62 /** One plain line of what it does in g1t, for a workspace (or for you, when it is only personal). */
63 description: string;
64 scopes: ConnectorScope[];
65 status: ConnectorStatus;
66 /** Where an available connector is set up, for each scope it has. */
67 href?: Partial<Record<ConnectorScope, string>>;
68 capabilities?: ConnectorCapability[];
69 /** The integration provider behind it, whose connections show it as connected. */
70 provider?: Provider;
71 /** What differs when you connect it for yourself. */
72 personal?: { description?: string; status?: ConnectorStatus; capabilities?: ConnectorCapability[] };
73 /** More words search should find it by. */
74 keywords?: string[];
75 /**
76 * The remote MCP server behind it, when the tool publishes one, and how
77 * it signs in (`oauth`: the browser; `header`: a key an owner pastes;
78 * `none`). Its connector is soon: see `mcp()` below.
79 */
80 mcp?: {
81 url: string;
82 auth: "oauth" | "header" | "none";
83 /** For `header`: the header the key goes in (Authorization when unset). */
84 header?: string;
85 /** What to know before connecting: where the key comes from, or that signing in needs an app g1t doesn't have yet. */
86 caveat?: string;
87 };
88};
89
90/** A connector as one context (a workspace, or you) shows it. */
91export type ConnectorView = {
92 id: string;
93 name: string;
94 category: ConnectorCategory;
95 description: string;
96 status: ConnectorStatus;
97 href: string | null;
98 capabilities: ConnectorCapability[];
99 provider: Provider | null;
100 keywords: string[];
101 /** The other scope it can also be connected in. */
102 alsoIn: ConnectorScope | null;
103 /** The MCP server behind it, when there is one. */
104 mcp: Connector["mcp"] | null;
105};
106
107/** The categories, in the order the directory lists them. */
108export const CONNECTOR_CATEGORIES: { id: ConnectorCategory; title: string }[] = [
109 { id: "code", title: "Code & CI" },
110 { id: "issues", title: "Issues & projects" },
111 { id: "chat", title: "Chat & meetings" },
112 { id: "calendar", title: "Calendar & email" },
113 { id: "docs", title: "Docs & knowledge" },
114 { id: "monitoring", title: "Monitoring & incidents" },
115 { id: "cloud", title: "Cloud & deploy" },
116 { id: "ai", title: "AI models" },
117 { id: "data", title: "Data & analytics" },
118 { id: "crm", title: "CRM & support" },
119 { id: "design", title: "Design" },
120 { id: "security", title: "Security & identity" },
121 { id: "files", title: "Files & storage" },
122];
123
124const W: ConnectorScope[] = ["workspace"];
125const P: ConnectorScope[] = ["personal"];
126const BOTH: ConnectorScope[] = ["workspace", "personal"];
127
128/** An AI provider: its credentials are kept on the workspace's AI providers page. */
129function model(provider: Provider, name: string, description: string, keywords: string[] = []): Connector {
130 return {
131 id: provider.replace(/_/g, "-"),
132 name,
133 category: "ai",
134 description,
135 scopes: W,
136 status: "available",
137 href: { workspace: `/:workspace/-/integrations/models?add=${provider}#add` },
138 capabilities: ["AI provider"],
139 provider,
140 keywords: ["model", "llm", ...keywords],
141 };
142}
143
144/**
145 * A tool with a remote MCP server. Soon: Customize, where an owner
146 * connected one, was retired with g1t's hosted agents, so nothing in g1t
147 * connects to these servers today. The server is kept for when something
148 * does; until then each person's own harness connects to it directly.
149 */
150function mcp(
151 id: string,
152 name: string,
153 category: ConnectorCategory,
154 description: string,
155 server: NonNullable<Connector["mcp"]>,
156 capabilities: ConnectorCapability[] = ["Agents can read", "Agents can act"],
157 keywords: string[] = [],
158): Connector {
159 return { id, name, category, description, scopes: W, status: "soon", capabilities, keywords: ["mcp", ...keywords], mcp: server };
160}
161
162/** A planned connector. */
163function soon(
164 id: string,
165 name: string,
166 category: ConnectorCategory,
167 scopes: ConnectorScope[],
168 description: string,
169 capabilities: ConnectorCapability[] = [],
170 personal?: Connector["personal"],
171): Connector {
172 return { id, name, category, description, scopes, status: "soon", capabilities, ...(personal ? { personal } : {}) };
173}
174
175export const CONNECTORS: Connector[] = [
176 // Code & CI -------------------------------------------------------------
177 {
178 id: "github",
179 name: "GitHub",
180 category: "code",
181 description: "Import repositories, with their branches, tags and issues, through g1t's GitHub App.",
182 scopes: BOTH,
183 status: "available",
184 href: { workspace: "/new/github?workspace=:workspace", personal: "/settings/github" },
185 capabilities: ["Imports repositories"],
186 personal: {
187 description: "Sign in with your GitHub account, and reach the repositories you can see there to import them.",
188 capabilities: ["Signs you in", "Imports repositories"],
189 },
190 keywords: ["git", "import", "sign in"],
191 },
192 mcp("github-mcp", "GitHub (MCP)", "code", "Agents read and act on repositories, issues and pull requests on GitHub, through GitHub's MCP server.", { url: "https://api.githubcopilot.com/mcp/", auth: "header", header: "Authorization", caveat: "Paste a GitHub personal access token as Bearer <token>: GitHub's server takes one in place of a sign-in." }, ["Agents can read", "Agents can act"], ["issues", "pull requests"]),
193 {
194 id: "webhooks",
195 name: "Webhooks",
196 category: "code",
197 description: "Every repository's events, sent to your own addresses as they happen, signed.",
198 scopes: W,
199 status: "available",
200 href: { workspace: "/:workspace/-/webhooks" },
201 capabilities: ["Sends events"],
202 keywords: ["http", "events", "outgoing"],
203 },
204 soon("gitlab", "GitLab", "code", BOTH, "Import projects, with their branches, tags and issues.", ["Imports repositories"], {
205 description: "Sign in with GitLab, and reach your own projects to import them.",
206 capabilities: ["Signs you in", "Imports repositories"],
207 }),
208 soon("bitbucket", "Bitbucket", "code", BOTH, "Import repositories, with their branches and tags.", ["Imports repositories"], {
209 description: "Reach your own Bitbucket repositories to import them.",
210 capabilities: ["Imports repositories"],
211 }),
212 soon("circleci", "CircleCI", "code", W, "Pipeline results as checks on pull requests, which agents read when a build fails.", ["Agents can read"]),
213 soon("buildkite", "Buildkite", "code", W, "Build results as checks on pull requests, with the failing step for agents to fix.", ["Agents can read"]),
214 soon("docker-hub", "Docker Hub", "code", W, "Push images your workflows build, and pull private base images.", ["Deploys"]),
215
216 // Issues & projects -----------------------------------------------------
217 {
218 id: "linear",
219 name: "Linear",
220 category: "issues",
221 description: "Agents read ENG-42 when work mentions it; import issues, and they hear back when the work lands.",
222 scopes: BOTH,
223 status: "available",
224 href: { workspace: "/:workspace/-/integrations/trackers?add=linear#add" },
225 capabilities: ["Agents can read", "Writes back"],
226 provider: "linear",
227 personal: {
228 description: "Issues assigned to you in Linear, in your g1t inbox beside everything else.",
229 status: "soon",
230 capabilities: ["Agents can read"],
231 },
232 keywords: ["tracker", "tickets"],
233 },
234 mcp("linear-mcp", "Linear (MCP)", "issues", "Agents search, create and update issues, projects and cycles in Linear, through Linear's MCP server.", { url: "https://mcp.linear.app/mcp", auth: "oauth" }, ["Agents can read", "Agents can act"], ["tracker", "issues"]),
235 {
236 id: "jira",
237 name: "Jira",
238 category: "issues",
239 description: "Agents read TECH-1234 when work mentions it; import tickets, and they hear back when the work lands.",
240 scopes: W,
241 status: "available",
242 href: { workspace: "/:workspace/-/integrations/trackers?add=jira#add" },
243 capabilities: ["Agents can read", "Writes back"],
244 provider: "jira",
245 keywords: ["atlassian", "tracker", "tickets"],
246 },
247 mcp("asana", "Asana", "issues", "Agents read, create and update tasks and projects in Asana, through Asana's MCP server.", { url: "https://mcp.asana.com/v2/mcp", auth: "oauth", caveat: "Asana signs in only apps registered with it, and g1t isn't one yet: signing in here fails until it is." }, ["Agents can read", "Agents can act"], ["tasks", "projects"]),
248 soon("shortcut", "Shortcut", "issues", W, "Stories agents read when work mentions them, updated when the work lands.", ["Agents can read", "Writes back"]),
249 soon("clickup", "ClickUp", "issues", W, "Tasks agents can read and import, kept in step with their pull requests.", ["Agents can read", "Writes back"]),
250 soon("trello", "Trello", "issues", W, "Cards become issues, and move along their board as the work does.", ["Opens issues", "Writes back"]),
251
252 // Chat & meetings -------------------------------------------------------
253 soon("slack", "Slack", "chat", BOTH, "Alerts and agent updates in the channels your team already reads, and agents to talk to there.", ["Alerts into chat", "Agents can act"], {
254 description: "Your status in g1t follows the one you set in Slack, and the other way round.",
255 capabilities: ["Sets your status"],
256 }),
257 soon("microsoft-teams", "Microsoft Teams", "chat", BOTH, "Alerts and agent updates posted to Teams channels, with agents to talk to there.", ["Alerts into chat", "Agents can act"], {
258 description: "Your status in g1t follows your Teams presence.",
259 capabilities: ["Sets your status"],
260 }),
261 soon("discord", "Discord", "chat", W, "Releases, alerts and agent updates posted to a Discord server.", ["Alerts into chat"]),
262 soon("zoom", "Zoom", "chat", BOTH, "Meeting notes and recordings agents can read when work refers to them.", ["Agents can read"], {
263 description: "Sets your status to On a call while you are in a Zoom meeting.",
264 capabilities: ["Sets your status"],
265 }),
266 soon("google-meet", "Google Meet", "chat", P, "Sets your status to On a call while you are in a meeting, and starts a call from any channel.", ["Sets your status"]),
267
268 // Calendar & email ------------------------------------------------------
269 soon("google-calendar", "Google Calendar", "calendar", P, "Sets your status to In a meeting while you are in one; agents can find a time that suits everyone.", ["Sets your status", "Finds a time"]),
270 soon("outlook-calendar", "Outlook Calendar", "calendar", P, "Sets your status to In a meeting while you are in one; agents can find a time that suits everyone.", ["Sets your status", "Finds a time"]),
271 soon("gmail", "Gmail", "calendar", P, "Forward a thread to an agent, or turn an email into an issue, from your own inbox.", ["Opens issues", "Agents can read"]),
272 soon("outlook-mail", "Outlook Mail", "calendar", P, "Forward a thread to an agent, or turn an email into an issue, from your own inbox.", ["Opens issues", "Agents can read"]),
273
274 // Docs & knowledge ------------------------------------------------------
275 mcp("notion", "Notion", "docs", "Agents search, read and write Notion pages and databases, through Notion's MCP server.", { url: "https://mcp.notion.com/mcp", auth: "oauth" }, ["Agents can read", "Agents can act"], ["pages", "wiki", "databases"]),
276 mcp("atlassian", "Atlassian (Jira and Confluence)", "docs", "Agents search and update Jira issues and Confluence pages, through Atlassian's MCP server.", { url: "https://mcp.atlassian.com/v1/mcp", auth: "oauth" }, ["Agents can read", "Agents can act"], ["jira", "confluence", "tickets", "wiki"]),
277 soon("google-docs", "Google Docs", "docs", BOTH, "Agents read the specs and plans linked from issues and chat.", ["Agents can read"], {
278 description: "Docs you share in chat open for agents as well as people.",
279 capabilities: ["Agents can read"],
280 }),
281 mcp("zapier", "Zapier", "data", "Agents run the actions you expose from Zapier, across thousands of apps, through Zapier's MCP server.", { url: "https://mcp.zapier.com/api/mcp/mcp", auth: "header", header: "Authorization", caveat: "Paste the token from your Zapier MCP settings as Bearer <token>." }, ["Agents can act"], ["automation", "apps"]),
282 soon("coda", "Coda", "docs", W, "Agents read the docs and tables linked from issues and chat.", ["Agents can read"]),
283
284 // Monitoring & incidents ------------------------------------------------
285 {
286 id: "sentry",
287 name: "Sentry",
288 category: "monitoring",
289 description: "New errors open issues with the stack trace, and resolve in Sentry when the fix merges.",
290 scopes: W,
291 status: "available",
292 href: { workspace: "/:workspace/-/integrations/alerts?add=sentry#add" },
293 capabilities: ["Opens issues", "Agents can read", "Writes back"],
294 provider: "sentry",
295 keywords: ["errors", "alerts", "exceptions"],
296 },
297 {
298 id: "datadog",
299 name: "Datadog",
300 category: "monitoring",
301 description: "Monitors that trigger open issues, and recoveries are noted on them.",
302 scopes: W,
303 status: "available",
304 href: { workspace: "/:workspace/-/integrations/alerts?add=datadog#add" },
305 capabilities: ["Opens issues"],
306 provider: "datadog",
307 keywords: ["monitors", "alerts", "apm"],
308 },
309 {
310 id: "alerts-webhook",
311 name: "Alerts webhook",
312 category: "monitoring",
313 description: "Anything that can send signed JSON opens issues: your own scripts, or any monitoring tool.",
314 scopes: W,
315 status: "available",
316 href: { workspace: "/:workspace/-/integrations/alerts?add=webhook#add" },
317 capabilities: ["Opens issues"],
318 provider: "webhook",
319 keywords: ["incoming", "http", "alerts", "pagerduty", "grafana"],
320 },
321 mcp("sentry-mcp", "Sentry (MCP)", "monitoring", "Agents search issues, read stack traces and look up errors in Sentry, through Sentry's MCP server.", { url: "https://mcp.sentry.dev/mcp", auth: "oauth" }, ["Agents can read", "Agents can act"], ["errors", "issues"]),
322 soon("pagerduty", "PagerDuty", "monitoring", BOTH, "Incidents open issues an agent can start on, and resolve when the fix lands.", ["Opens issues", "Writes back"], {
323 description: "Sets your status to On call while you are on call.",
324 capabilities: ["Sets your status"],
325 }),
326 soon("opsgenie", "Opsgenie", "monitoring", W, "Alerts open issues, and close when the fix lands.", ["Opens issues", "Writes back"]),
327 soon("incident-io", "incident.io", "monitoring", W, "Incidents get a channel in g1t, with agents to dig through what changed.", ["Opens issues", "Alerts into chat"]),
328 soon("grafana", "Grafana", "monitoring", W, "Alert rules open issues, and agents read the dashboards they link to.", ["Opens issues", "Agents can read"]),
329 soon("new-relic", "New Relic", "monitoring", W, "Alerts open issues, with the traces agents need to find the cause.", ["Opens issues", "Agents can read"]),
330 soon("honeycomb", "Honeycomb", "monitoring", W, "Triggers open issues, and agents query traces while they work.", ["Opens issues", "Agents can read"]),
331 soon("better-stack", "Better Stack", "monitoring", W, "Uptime incidents and log alerts open issues.", ["Opens issues"]),
332
333 // Cloud & deploy --------------------------------------------------------
334 mcp("cloudflare", "Cloudflare", "cloud", "Agents read your Cloudflare account's Workers, storage and settings, and look things up in its docs, through Cloudflare's MCP servers.", { url: "https://bindings.mcp.cloudflare.com/mcp", auth: "oauth" }, ["Agents can read", "Agents can act"], ["workers", "r2", "d1", "dns"]),
335 mcp("cloudflare-docs", "Cloudflare docs", "docs", "Agents search Cloudflare's documentation while they work.", { url: "https://docs.mcp.cloudflare.com/mcp", auth: "none" }, ["Agents can read"], ["documentation"]),
336 soon("aws", "Amazon Web Services", "cloud", W, "Workflows and deployments reach AWS with short-lived credentials, no stored keys.", ["Deploys"]),
337 soon("google-cloud", "Google Cloud", "cloud", W, "Workflows and deployments reach Google Cloud with short-lived credentials.", ["Deploys"]),
338 soon("azure", "Microsoft Azure", "cloud", W, "Workflows and deployments reach Azure with short-lived credentials.", ["Deploys"]),
339 mcp("vercel", "Vercel", "cloud", "Agents read your Vercel projects, deployments and logs, through Vercel's MCP server.", { url: "https://mcp.vercel.com", auth: "oauth" }, ["Agents can read", "Agents can act"], ["deployments", "previews"]),
340 soon("netlify", "Netlify", "cloud", W, "Deploy previews as checks on pull requests.", ["Deploys", "Agents can read"]),
341 soon("fly-io", "Fly.io", "cloud", W, "Deploy apps from workflows, and roll back from the deployment's page.", ["Deploys"]),
342 soon("kubernetes", "Kubernetes", "cloud", W, "Roll out to your own clusters from workflows, with each rollout's status on g1t.", ["Deploys"]),
343
344 // AI models -------------------------------------------------------------
345 model("anthropic", "Anthropic", "Keep your team's Anthropic API key, sealed, for the workspace.", ["claude"]),
346 model("openai", "OpenAI", "Keep your team's OpenAI API key, sealed, for the workspace.", ["gpt"]),
347 model("gemini", "Google Gemini", "Keep your team's Google AI Studio key, sealed, for the workspace.", ["google"]),
348 model("xai", "xAI", "Keep your team's xAI API key, sealed, for the workspace.", ["grok"]),
349 model("mistral", "Mistral", "Keep your team's Mistral API key, sealed, for the workspace."),
350 model("deepseek", "DeepSeek", "Keep your team's DeepSeek API key, sealed, for the workspace."),
351 model("azure_openai", "Azure OpenAI", "Keep your Azure OpenAI resource, deployment and key for the workspace.", ["microsoft"]),
352 model("openrouter", "OpenRouter", "Keep your team's OpenRouter key, sealed, for the workspace."),
353 model("groq", "Groq", "Keep your team's Groq API key, sealed, for the workspace."),
354 model("together", "Together AI", "Keep your team's Together AI key, sealed, for the workspace."),
355 model("fireworks", "Fireworks AI", "Keep your team's Fireworks AI key, sealed, for the workspace."),
356 model("cerebras", "Cerebras", "Keep your team's Cerebras API key, sealed, for the workspace."),
357 model("anthropic_endpoint", "Anthropic-compatible endpoint", "Any server that speaks the Anthropic API, such as your own gateway or proxy.", ["self-hosted", "proxy"]),
358 model("openai_endpoint", "OpenAI-compatible endpoint", "Any server that speaks the OpenAI API, such as a model you host yourself.", ["self-hosted", "proxy", "ollama", "vllm"]),
359 {
360 id: "mcp",
361 name: "MCP clients",
362 category: "ai",
363 description: "Your own agent, connected to g1t's MCP server, works in g1t as you.",
364 scopes: P,
365 status: "available",
366 href: { personal: "/settings/applications" },
367 capabilities: ["Agents can act"],
368 keywords: ["model context protocol", "agent", "applications", "oauth"],
369 },
370 soon("amazon-bedrock", "Amazon Bedrock", "ai", W, "Models in your own AWS account, billed there.", ["AI provider"]),
371 soon("vertex-ai", "Google Vertex AI", "ai", W, "Models in your own Google Cloud project, billed there.", ["AI provider"]),
372 mcp("hugging-face", "Hugging Face", "ai", "Agents search models, datasets, papers and Spaces on the Hub, through Hugging Face's MCP server.", { url: "https://huggingface.co/mcp", auth: "oauth" }, ["Agents can read"], ["models", "datasets", "hub"]),
373 mcp("context7", "Context7", "docs", "Agents read current documentation for the libraries a codebase uses, through Context7's MCP server.", { url: "https://mcp.context7.com/mcp", auth: "none" }, ["Agents can read"], ["documentation", "libraries"]),
374 mcp("microsoft-learn", "Microsoft Learn", "docs", "Agents search Microsoft's documentation for Azure, .NET and Windows, through Microsoft Learn's MCP server.", { url: "https://learn.microsoft.com/api/mcp", auth: "none" }, ["Agents can read"], ["azure", "dotnet", "documentation"]),
375 mcp("deepwiki", "DeepWiki", "docs", "Agents read generated documentation for public repositories, through DeepWiki's MCP server.", { url: "https://mcp.deepwiki.com/mcp", auth: "none" }, ["Agents can read"], ["repositories", "documentation"]),
376
377 // Data & analytics ------------------------------------------------------
378 soon("postgresql", "PostgreSQL", "data", W, "Agents read your schema, and run read-only queries while they investigate.", ["Agents can read"]),
379 soon("snowflake", "Snowflake", "data", W, "Agents answer questions from your warehouse with read-only queries.", ["Agents can read"]),
380 soon("bigquery", "BigQuery", "data", W, "Agents answer questions from your datasets with read-only queries.", ["Agents can read"]),
381 mcp("posthog", "PostHog", "data", "Agents read product analytics, feature flags and errors in PostHog, through PostHog's MCP server.", { url: "https://mcp.posthog.com/mcp", auth: "oauth" }, ["Agents can read", "Agents can act"], ["analytics", "feature flags"]),
382 mcp("supabase", "Supabase", "data", "Agents read your Supabase projects, schemas and logs, and run queries, through Supabase's MCP server.", { url: "https://mcp.supabase.com/mcp", auth: "oauth" }, ["Agents can read", "Agents can act"], ["postgres", "database"]),
383 mcp("neon", "Neon", "data", "Agents read and manage Neon Postgres projects and branches, through Neon's MCP server.", { url: "https://mcp.neon.tech/mcp", auth: "oauth" }, ["Agents can read", "Agents can act"], ["postgres", "database"]),
384 soon("amplitude", "Amplitude", "data", W, "Agents read the charts that work refers to.", ["Agents can read"]),
385 soon("segment", "Segment", "data", W, "Agents read your tracking plan, and check new events against it.", ["Agents can read"]),
386
387 // CRM & support ---------------------------------------------------------
388 soon("zendesk", "Zendesk", "crm", W, "Turn a ticket into an issue, and tell the customer when the fix ships.", ["Opens issues", "Writes back"]),
389 mcp("intercom", "Intercom", "crm", "Agents search conversations, contacts and companies in Intercom, through Intercom's MCP server.", { url: "https://mcp.intercom.com/mcp", auth: "oauth" }, ["Agents can read", "Agents can act"], ["support", "conversations", "customers"]),
390 mcp("hubspot", "HubSpot", "crm", "Agents read contacts, companies and deals in HubSpot, through HubSpot's MCP server.", { url: "https://mcp.hubspot.com/anthropic", auth: "oauth", caveat: "HubSpot signs in only apps registered with it, and g1t isn't one yet: signing in here fails until it is." }, ["Agents can read", "Agents can act"], ["crm", "contacts", "deals"]),
391 soon("salesforce", "Salesforce", "crm", W, "Agents read the account and case behind a request.", ["Agents can read"]),
392 mcp("stripe", "Stripe", "crm", "Agents read customers, payments and subscriptions, and look things up in Stripe's docs, through Stripe's MCP server.", { url: "https://mcp.stripe.com", auth: "oauth" }, ["Agents can read", "Agents can act"], ["payments", "billing", "customers"]),
393 mcp("paypal", "PayPal", "crm", "Agents read and manage orders, invoices and subscriptions, through PayPal's MCP server.", { url: "https://mcp.paypal.com/mcp", auth: "oauth" }, ["Agents can read", "Agents can act"], ["payments", "invoices"]),
394
395 // Design ----------------------------------------------------------------
396 mcp("figma", "Figma", "design", "Agents read designs, components and variables from your Figma files, and build to them, through Figma's MCP server.", { url: "https://mcp.figma.com/mcp", auth: "oauth" }, ["Agents can read"], ["design", "frames", "components"]),
397 mcp("canva", "Canva", "design", "Agents search, create and export Canva designs, through Canva's MCP server.", { url: "https://mcp.canva.com/mcp", auth: "oauth" }, ["Agents can read", "Agents can act"], ["design", "slides"]),
398 soon("miro", "Miro", "design", W, "Agents read the boards linked from issues and chat.", ["Agents can read"]),
399 soon("storybook", "Storybook", "design", W, "Each pull request's stories as a check, with what changed.", ["Agents can read"]),
400
401 // Security & identity ---------------------------------------------------
402 soon("okta", "Okta", "security", W, "Single sign-on, and people added and removed with your directory.", ["Signs you in", "Syncs people"]),
403 soon("entra-id", "Microsoft Entra ID", "security", W, "Single sign-on, and people added and removed with your directory.", ["Signs you in", "Syncs people"]),
404 soon("google-workspace", "Google Workspace", "security", BOTH, "Single sign-on, and people added and removed with your directory.", ["Signs you in", "Syncs people"], {
405 description: "Sign in to g1t with your Google account.",
406 capabilities: ["Signs you in"],
407 }),
408 soon("1password", "1Password", "security", W, "Secrets from a vault, read by workflows and deployments when they run.", ["Deploys"]),
409 soon("snyk", "Snyk", "security", W, "Findings open issues, and an agent opens the fix.", ["Opens issues"]),
410
411 // Files & storage -------------------------------------------------------
412 soon("google-drive", "Google Drive", "files", BOTH, "Agents read the files linked from issues and chat.", ["Agents can read"], {
413 description: "Attach files from your Drive in chat, without downloading them first.",
414 capabilities: ["Agents can read"],
415 }),
416 soon("dropbox", "Dropbox", "files", BOTH, "Agents read the files linked from issues and chat.", ["Agents can read"], {
417 description: "Attach files from your Dropbox in chat.",
418 capabilities: ["Agents can read"],
419 }),
420 soon("onedrive", "OneDrive and SharePoint", "files", BOTH, "Agents read the files linked from issues and chat.", ["Agents can read"], {
421 description: "Attach files from your OneDrive in chat.",
422 capabilities: ["Agents can read"],
423 }),
424 soon("box", "Box", "files", W, "Agents read the files linked from issues and chat.", ["Agents can read"]),
425];
426
427/** The connector by its id. */
428export function connectorById(id: string): Connector | undefined {
429 return CONNECTORS.find((connector) => connector.id === id);
430}
431
432/** A connector as `scope` shows it, or null when it cannot be connected there. */
433export function connectorView(connector: Connector, scope: ConnectorScope): ConnectorView | null {
434 if (!connector.scopes.includes(scope)) return null;
435 const own = scope === "personal" ? connector.personal : undefined;
436 const status = own?.status ?? connector.status;
437 const other: ConnectorScope = scope === "workspace" ? "personal" : "workspace";
438 return {
439 id: connector.id,
440 name: connector.name,
441 category: connector.category,
442 description: own?.description ?? connector.description,
443 status,
444 href: status === "available" ? (connector.href?.[scope] ?? null) : null,
445 capabilities: own?.capabilities ?? connector.capabilities ?? [],
446 provider: connector.provider ?? null,
447 keywords: connector.keywords ?? [],
448 alsoIn: connector.scopes.includes(other) ? other : null,
449 mcp: connector.mcp ?? null,
450 };
451}
452
453/** Every connector `scope` can show, in catalog order. */
454export function connectorsFor(scope: ConnectorScope): ConnectorView[] {
455 return CONNECTORS.map((connector) => connectorView(connector, scope)).filter((view): view is ConnectorView => view != null);
456}
457
458/** A setup path with its `:workspace` filled in. */
459export function connectorPath(path: string, workspace: string): string {
460 return path.replace(/:workspace\b/g, encodeURIComponent(workspace));
461}