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