Skip to content
463 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: g1t
77 * connects to it (docs.g1t.sh/guides/customize/, "Connectors"), signs in
78 * the way it asks (`oauth`: the browser; `header`: a key an owner
79 * pastes; `none`), lists its tools, and gives them to agents.
80 */
81 mcp?: {
82 url: string;
83 auth: "oauth" | "header" | "none";
84 /** For `header`: the header the key goes in (Authorization when unset). */
85 header?: string;
86 /** What to know before connecting: where the key comes from, or that signing in needs an app g1t doesn't have yet. */
87 caveat?: string;
88 };
89};
90
91/** A connector as one context (a workspace, or you) shows it. */
92export type ConnectorView = {
93 id: string;
94 name: string;
95 category: ConnectorCategory;
96 description: string;
97 status: ConnectorStatus;
98 href: string | null;
99 capabilities: ConnectorCapability[];
100 provider: Provider | null;
101 keywords: string[];
102 /** The other scope it can also be connected in. */
103 alsoIn: ConnectorScope | null;
104 /** The MCP server behind it, when there is one. */
105 mcp: Connector["mcp"] | null;
106};
107
108/** The categories, in the order the directory lists them. */
109export const CONNECTOR_CATEGORIES: { id: ConnectorCategory; title: string }[] = [
110 { id: "code", title: "Code & CI" },
111 { id: "issues", title: "Issues & projects" },
112 { id: "chat", title: "Chat & meetings" },
113 { id: "calendar", title: "Calendar & email" },
114 { id: "docs", title: "Docs & knowledge" },
115 { id: "monitoring", title: "Monitoring & incidents" },
116 { id: "cloud", title: "Cloud & deploy" },
117 { id: "ai", title: "AI models" },
118 { id: "data", title: "Data & analytics" },
119 { id: "crm", title: "CRM & support" },
120 { id: "design", title: "Design" },
121 { id: "security", title: "Security & identity" },
122 { id: "files", title: "Files & storage" },
123];
124
125const W: ConnectorScope[] = ["workspace"];
126const P: ConnectorScope[] = ["personal"];
127const BOTH: ConnectorScope[] = ["workspace", "personal"];
128
129/** An AI provider: its credentials are kept on the workspace's AI providers page. */
130function model(provider: Provider, name: string, description: string, keywords: string[] = []): Connector {
131 return {
132 id: provider.replace(/_/g, "-"),
133 name,
134 category: "ai",
135 description,
136 scopes: W,
137 status: "available",
138 href: { workspace: `/:workspace/-/integrations/models?add=${provider}#add` },
139 capabilities: ["AI provider"],
140 provider,
141 keywords: ["model", "llm", ...keywords],
142 };
143}
144
145/** Where an MCP-backed connector is connected: Customize's Connectors page, with the directory entry chosen. */
146export const MCP_CONNECT_PATH = "/:workspace/-/customize/connectors/new?directory=";
147
148/**
149 * A tool with a remote MCP server: available now, connected from Customize
150 * (an owner signs in or pastes a key), its tools then given to agents.
151 */
152function mcp(
153 id: string,
154 name: string,
155 category: ConnectorCategory,
156 description: string,
157 server: NonNullable<Connector["mcp"]>,
158 capabilities: ConnectorCapability[] = ["Agents can read", "Agents can act"],
159 keywords: string[] = [],
160): Connector {
161 return { id, name, category, description, scopes: W, status: "available", href: { workspace: `${MCP_CONNECT_PATH}${id}` }, capabilities, keywords: ["mcp", ...keywords], mcp: server };
162}
163
164/** A planned connector. */
165function soon(
166 id: string,
167 name: string,
168 category: ConnectorCategory,
169 scopes: ConnectorScope[],
170 description: string,
171 capabilities: ConnectorCapability[] = [],
172 personal?: Connector["personal"],
173): Connector {
174 return { id, name, category, description, scopes, status: "soon", capabilities, ...(personal ? { personal } : {}) };
175}
176
177export const CONNECTORS: Connector[] = [
178 // Code & CI -------------------------------------------------------------
179 {
180 id: "github",
181 name: "GitHub",
182 category: "code",
183 description: "Import repositories, with their branches, tags and issues, through g1t's GitHub App.",
184 scopes: BOTH,
185 status: "available",
186 href: { workspace: "/new/github?workspace=:workspace", personal: "/settings/github" },
187 capabilities: ["Imports repositories"],
188 personal: {
189 description: "Sign in with your GitHub account, and reach the repositories you can see there to import them.",
190 capabilities: ["Signs you in", "Imports repositories"],
191 },
192 keywords: ["git", "import", "sign in"],
193 },
194 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"]),
195 {
196 id: "webhooks",
197 name: "Webhooks",
198 category: "code",
199 description: "Every repository's events, sent to your own addresses as they happen, signed.",
200 scopes: W,
201 status: "available",
202 href: { workspace: "/:workspace/-/webhooks" },
203 capabilities: ["Sends events"],
204 keywords: ["http", "events", "outgoing"],
205 },
206 soon("gitlab", "GitLab", "code", BOTH, "Import projects, with their branches, tags and issues.", ["Imports repositories"], {
207 description: "Sign in with GitLab, and reach your own projects to import them.",
208 capabilities: ["Signs you in", "Imports repositories"],
209 }),
210 soon("bitbucket", "Bitbucket", "code", BOTH, "Import repositories, with their branches and tags.", ["Imports repositories"], {
211 description: "Reach your own Bitbucket repositories to import them.",
212 capabilities: ["Imports repositories"],
213 }),
214 soon("circleci", "CircleCI", "code", W, "Pipeline results as checks on pull requests, which agents read when a build fails.", ["Agents can read"]),
215 soon("buildkite", "Buildkite", "code", W, "Build results as checks on pull requests, with the failing step for agents to fix.", ["Agents can read"]),
216 soon("docker-hub", "Docker Hub", "code", W, "Push images your workflows build, and pull private base images.", ["Deploys"]),
217
218 // Issues & projects -----------------------------------------------------
219 {
220 id: "linear",
221 name: "Linear",
222 category: "issues",
223 description: "Agents read ENG-42 when work mentions it; import issues, and they hear back when the work lands.",
224 scopes: BOTH,
225 status: "available",
226 href: { workspace: "/:workspace/-/integrations/trackers?add=linear#add" },
227 capabilities: ["Agents can read", "Writes back"],
228 provider: "linear",
229 personal: {
230 description: "Issues assigned to you in Linear, in your g1t inbox beside everything else.",
231 status: "soon",
232 capabilities: ["Agents can read"],
233 },
234 keywords: ["tracker", "tickets"],
235 },
236 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"]),
237 {
238 id: "jira",
239 name: "Jira",
240 category: "issues",
241 description: "Agents read TECH-1234 when work mentions it; import tickets, and they hear back when the work lands.",
242 scopes: W,
243 status: "available",
244 href: { workspace: "/:workspace/-/integrations/trackers?add=jira#add" },
245 capabilities: ["Agents can read", "Writes back"],
246 provider: "jira",
247 keywords: ["atlassian", "tracker", "tickets"],
248 },
249 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"]),
250 soon("shortcut", "Shortcut", "issues", W, "Stories agents read when work mentions them, updated when the work lands.", ["Agents can read", "Writes back"]),
251 soon("clickup", "ClickUp", "issues", W, "Tasks agents can read and import, kept in step with their pull requests.", ["Agents can read", "Writes back"]),
252 soon("trello", "Trello", "issues", W, "Cards become issues, and move along their board as the work does.", ["Opens issues", "Writes back"]),
253
254 // Chat & meetings -------------------------------------------------------
255 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"], {
256 description: "Your status in g1t follows the one you set in Slack, and the other way round.",
257 capabilities: ["Sets your status"],
258 }),
259 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"], {
260 description: "Your status in g1t follows your Teams presence.",
261 capabilities: ["Sets your status"],
262 }),
263 soon("discord", "Discord", "chat", W, "Releases, alerts and agent updates posted to a Discord server.", ["Alerts into chat"]),
264 soon("zoom", "Zoom", "chat", BOTH, "Meeting notes and recordings agents can read when work refers to them.", ["Agents can read"], {
265 description: "Sets your status to On a call while you are in a Zoom meeting.",
266 capabilities: ["Sets your status"],
267 }),
268 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"]),
269
270 // Calendar & email ------------------------------------------------------
271 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"]),
272 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"]),
273 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"]),
274 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"]),
275
276 // Docs & knowledge ------------------------------------------------------
277 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"]),
278 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"]),
279 soon("google-docs", "Google Docs", "docs", BOTH, "Agents read the specs and plans linked from issues and chat.", ["Agents can read"], {
280 description: "Docs you share in chat open for agents as well as people.",
281 capabilities: ["Agents can read"],
282 }),
283 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"]),
284 soon("coda", "Coda", "docs", W, "Agents read the docs and tables linked from issues and chat.", ["Agents can read"]),
285
286 // Monitoring & incidents ------------------------------------------------
287 {
288 id: "sentry",
289 name: "Sentry",
290 category: "monitoring",
291 description: "New errors open issues with the stack trace, and resolve in Sentry when the fix merges.",
292 scopes: W,
293 status: "available",
294 href: { workspace: "/:workspace/-/integrations/alerts?add=sentry#add" },
295 capabilities: ["Opens issues", "Agents can read", "Writes back"],
296 provider: "sentry",
297 keywords: ["errors", "alerts", "exceptions"],
298 },
299 {
300 id: "datadog",
301 name: "Datadog",
302 category: "monitoring",
303 description: "Monitors that trigger open issues, and recoveries are noted on them.",
304 scopes: W,
305 status: "available",
306 href: { workspace: "/:workspace/-/integrations/alerts?add=datadog#add" },
307 capabilities: ["Opens issues"],
308 provider: "datadog",
309 keywords: ["monitors", "alerts", "apm"],
310 },
311 {
312 id: "alerts-webhook",
313 name: "Alerts webhook",
314 category: "monitoring",
315 description: "Anything that can send signed JSON opens issues: your own scripts, or any monitoring tool.",
316 scopes: W,
317 status: "available",
318 href: { workspace: "/:workspace/-/integrations/alerts?add=webhook#add" },
319 capabilities: ["Opens issues"],
320 provider: "webhook",
321 keywords: ["incoming", "http", "alerts", "pagerduty", "grafana"],
322 },
323 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"]),
324 soon("pagerduty", "PagerDuty", "monitoring", BOTH, "Incidents open issues an agent can start on, and resolve when the fix lands.", ["Opens issues", "Writes back"], {
325 description: "Sets your status to On call while you are on call.",
326 capabilities: ["Sets your status"],
327 }),
328 soon("opsgenie", "Opsgenie", "monitoring", W, "Alerts open issues, and close when the fix lands.", ["Opens issues", "Writes back"]),
329 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"]),
330 soon("grafana", "Grafana", "monitoring", W, "Alert rules open issues, and agents read the dashboards they link to.", ["Opens issues", "Agents can read"]),
331 soon("new-relic", "New Relic", "monitoring", W, "Alerts open issues, with the traces agents need to find the cause.", ["Opens issues", "Agents can read"]),
332 soon("honeycomb", "Honeycomb", "monitoring", W, "Triggers open issues, and agents query traces while they work.", ["Opens issues", "Agents can read"]),
333 soon("better-stack", "Better Stack", "monitoring", W, "Uptime incidents and log alerts open issues.", ["Opens issues"]),
334
335 // Cloud & deploy --------------------------------------------------------
336 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"]),
337 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"]),
338 soon("aws", "Amazon Web Services", "cloud", W, "Workflows and deployments reach AWS with short-lived credentials, no stored keys.", ["Deploys"]),
339 soon("google-cloud", "Google Cloud", "cloud", W, "Workflows and deployments reach Google Cloud with short-lived credentials.", ["Deploys"]),
340 soon("azure", "Microsoft Azure", "cloud", W, "Workflows and deployments reach Azure with short-lived credentials.", ["Deploys"]),
341 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"]),
342 soon("netlify", "Netlify", "cloud", W, "Deploy previews as checks on pull requests.", ["Deploys", "Agents can read"]),
343 soon("fly-io", "Fly.io", "cloud", W, "Deploy apps from workflows, and roll back from the deployment's page.", ["Deploys"]),
344 soon("kubernetes", "Kubernetes", "cloud", W, "Roll out to your own clusters from workflows, with each rollout's status on g1t.", ["Deploys"]),
345
346 // AI models -------------------------------------------------------------
347 model("anthropic", "Anthropic", "Keep your team's Anthropic API key, sealed, for the workspace.", ["claude"]),
348 model("openai", "OpenAI", "Keep your team's OpenAI API key, sealed, for the workspace.", ["gpt"]),
349 model("gemini", "Google Gemini", "Keep your team's Google AI Studio key, sealed, for the workspace.", ["google"]),
350 model("xai", "xAI", "Keep your team's xAI API key, sealed, for the workspace.", ["grok"]),
351 model("mistral", "Mistral", "Keep your team's Mistral API key, sealed, for the workspace."),
352 model("deepseek", "DeepSeek", "Keep your team's DeepSeek API key, sealed, for the workspace."),
353 model("azure_openai", "Azure OpenAI", "Keep your Azure OpenAI resource, deployment and key for the workspace.", ["microsoft"]),
354 model("openrouter", "OpenRouter", "Keep your team's OpenRouter key, sealed, for the workspace."),
355 model("groq", "Groq", "Keep your team's Groq API key, sealed, for the workspace."),
356 model("together", "Together AI", "Keep your team's Together AI key, sealed, for the workspace."),
357 model("fireworks", "Fireworks AI", "Keep your team's Fireworks AI key, sealed, for the workspace."),
358 model("cerebras", "Cerebras", "Keep your team's Cerebras API key, sealed, for the workspace."),
359 model("anthropic_endpoint", "Anthropic-compatible endpoint", "Any server that speaks the Anthropic API, such as your own gateway or proxy.", ["self-hosted", "proxy"]),
360 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"]),
361 {
362 id: "mcp",
363 name: "MCP clients",
364 category: "ai",
365 description: "Your own agent, connected to g1t's MCP server, works in g1t as you.",
366 scopes: P,
367 status: "available",
368 href: { personal: "/settings/applications" },
369 capabilities: ["Agents can act"],
370 keywords: ["model context protocol", "agent", "applications", "oauth"],
371 },
372 soon("amazon-bedrock", "Amazon Bedrock", "ai", W, "Models in your own AWS account, billed there.", ["AI provider"]),
373 soon("vertex-ai", "Google Vertex AI", "ai", W, "Models in your own Google Cloud project, billed there.", ["AI provider"]),
374 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"]),
375 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"]),
376 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"]),
377 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"]),
378
379 // Data & analytics ------------------------------------------------------
380 soon("postgresql", "PostgreSQL", "data", W, "Agents read your schema, and run read-only queries while they investigate.", ["Agents can read"]),
381 soon("snowflake", "Snowflake", "data", W, "Agents answer questions from your warehouse with read-only queries.", ["Agents can read"]),
382 soon("bigquery", "BigQuery", "data", W, "Agents answer questions from your datasets with read-only queries.", ["Agents can read"]),
383 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"]),
384 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"]),
385 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"]),
386 soon("amplitude", "Amplitude", "data", W, "Agents read the charts that work refers to.", ["Agents can read"]),
387 soon("segment", "Segment", "data", W, "Agents read your tracking plan, and check new events against it.", ["Agents can read"]),
388
389 // CRM & support ---------------------------------------------------------
390 soon("zendesk", "Zendesk", "crm", W, "Turn a ticket into an issue, and tell the customer when the fix ships.", ["Opens issues", "Writes back"]),
391 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"]),
392 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"]),
393 soon("salesforce", "Salesforce", "crm", W, "Agents read the account and case behind a request.", ["Agents can read"]),
394 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"]),
395 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"]),
396
397 // Design ----------------------------------------------------------------
398 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"]),
399 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"]),
400 soon("miro", "Miro", "design", W, "Agents read the boards linked from issues and chat.", ["Agents can read"]),
401 soon("storybook", "Storybook", "design", W, "Each pull request's stories as a check, with what changed.", ["Agents can read"]),
402
403 // Security & identity ---------------------------------------------------
404 soon("okta", "Okta", "security", W, "Single sign-on, and people added and removed with your directory.", ["Signs you in", "Syncs people"]),
405 soon("entra-id", "Microsoft Entra ID", "security", W, "Single sign-on, and people added and removed with your directory.", ["Signs you in", "Syncs people"]),
406 soon("google-workspace", "Google Workspace", "security", BOTH, "Single sign-on, and people added and removed with your directory.", ["Signs you in", "Syncs people"], {
407 description: "Sign in to g1t with your Google account.",
408 capabilities: ["Signs you in"],
409 }),
410 soon("1password", "1Password", "security", W, "Secrets from a vault, read by workflows and deployments when they run.", ["Deploys"]),
411 soon("snyk", "Snyk", "security", W, "Findings open issues, and an agent opens the fix.", ["Opens issues"]),
412
413 // Files & storage -------------------------------------------------------
414 soon("google-drive", "Google Drive", "files", BOTH, "Agents read the files linked from issues and chat.", ["Agents can read"], {
415 description: "Attach files from your Drive in chat, without downloading them first.",
416 capabilities: ["Agents can read"],
417 }),
418 soon("dropbox", "Dropbox", "files", BOTH, "Agents read the files linked from issues and chat.", ["Agents can read"], {
419 description: "Attach files from your Dropbox in chat.",
420 capabilities: ["Agents can read"],
421 }),
422 soon("onedrive", "OneDrive and SharePoint", "files", BOTH, "Agents read the files linked from issues and chat.", ["Agents can read"], {
423 description: "Attach files from your OneDrive in chat.",
424 capabilities: ["Agents can read"],
425 }),
426 soon("box", "Box", "files", W, "Agents read the files linked from issues and chat.", ["Agents can read"]),
427];
428
429/** The connector by its id. */
430export function connectorById(id: string): Connector | undefined {
431 return CONNECTORS.find((connector) => connector.id === id);
432}
433
434/** A connector as `scope` shows it, or null when it cannot be connected there. */
435export function connectorView(connector: Connector, scope: ConnectorScope): ConnectorView | null {
436 if (!connector.scopes.includes(scope)) return null;
437 const own = scope === "personal" ? connector.personal : undefined;
438 const status = own?.status ?? connector.status;
439 const other: ConnectorScope = scope === "workspace" ? "personal" : "workspace";
440 return {
441 id: connector.id,
442 name: connector.name,
443 category: connector.category,
444 description: own?.description ?? connector.description,
445 status,
446 href: status === "available" ? (connector.href?.[scope] ?? null) : null,
447 capabilities: own?.capabilities ?? connector.capabilities ?? [],
448 provider: connector.provider ?? null,
449 keywords: connector.keywords ?? [],
450 alsoIn: connector.scopes.includes(other) ? other : null,
451 mcp: connector.mcp ?? null,
452 };
453}
454
455/** Every connector `scope` can show, in catalog order. */
456export function connectorsFor(scope: ConnectorScope): ConnectorView[] {
457 return CONNECTORS.map((connector) => connectorView(connector, scope)).filter((view): view is ConnectorView => view != null);
458}
459
460/** A setup path with its `:workspace` filled in. */
461export function connectorPath(path: string, workspace: string): string {
462 return path.replace(/:workspace\b/g, encodeURIComponent(workspace));
463}