@zackbart/connecta 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. package/CHANGELOG.md +961 -5
  2. package/README.md +62 -39
  3. package/bin/connecta.mjs +110 -139
  4. package/bin/meta-tool-names.d.mts +2 -0
  5. package/bin/meta-tool-names.mjs +9 -0
  6. package/bin/version.mjs +3 -0
  7. package/dist/access-tokens.js +53 -63
  8. package/dist/activity-request.js +8 -0
  9. package/dist/activity.d.ts +76 -42
  10. package/dist/activity.js +110 -42
  11. package/dist/auth/clerk-sdk/client.d.ts +65 -0
  12. package/dist/auth/clerk-sdk/client.js +5 -0
  13. package/dist/auth/clerk-sdk/generated.js +1845 -0
  14. package/dist/auth/clerk-transport.js +19 -0
  15. package/dist/auth/clerk.d.ts +17 -7
  16. package/dist/auth/clerk.js +189 -107
  17. package/dist/auth/cloudflare-access.js +25 -26
  18. package/dist/auth/downstream-client-metadata.d.ts +29 -0
  19. package/dist/auth/downstream-client-metadata.js +133 -0
  20. package/dist/auth/downstream-oauth.js +1632 -1509
  21. package/dist/auth/downstream-revocation.js +106 -0
  22. package/dist/auth/oauth-token-response.js +231 -0
  23. package/dist/auth/oauth-v2-migration.js +116 -0
  24. package/dist/auth/static-oauth.js +526 -0
  25. package/dist/auth-elicitation.js +283 -0
  26. package/dist/branding.d.ts +8 -16
  27. package/dist/branding.js +26 -59
  28. package/dist/byte-read-response.js +39 -0
  29. package/dist/call-admission.js +12 -16
  30. package/dist/catalog-cache.js +739 -0
  31. package/dist/catalog-drift.d.ts +50 -15
  32. package/dist/catalog-drift.js +365 -128
  33. package/dist/catalog-fingerprint.js +2 -4
  34. package/dist/catalog-freshness.js +13 -0
  35. package/dist/catalog-limits.js +2 -2
  36. package/dist/catalog-service.js +368 -224
  37. package/dist/catalog.js +43 -84
  38. package/dist/concurrency.js +3 -4
  39. package/dist/config-defaults.d.ts +39 -0
  40. package/dist/config-defaults.js +46 -0
  41. package/dist/config-schema.d.ts +181 -0
  42. package/dist/config-schema.js +435 -0
  43. package/dist/config-value-sources.js +102 -0
  44. package/dist/config.d.ts +631 -0
  45. package/dist/config.js +503 -0
  46. package/dist/connector-access.d.ts +1 -0
  47. package/dist/connector-access.js +13 -15
  48. package/dist/connector-caller.d.ts +8 -0
  49. package/dist/connector-caller.js +15 -6
  50. package/dist/connector-scope.js +1 -1
  51. package/dist/connectors/api-connector.d.ts +220 -0
  52. package/dist/connectors/api-connector.js +214 -0
  53. package/dist/connectors/api.d.ts +8 -71
  54. package/dist/connectors/api.js +13 -99
  55. package/dist/connectors/guarded-fetch.d.ts +144 -0
  56. package/dist/connectors/guarded-fetch.js +108 -25
  57. package/dist/connectors/negotiation-cache.js +46 -0
  58. package/dist/connectors/option-shapes.js +27 -0
  59. package/dist/connectors/remote-mcp.d.ts +30 -4
  60. package/dist/connectors/remote-mcp.js +1780 -351
  61. package/dist/connectors/resource-uri.js +335 -0
  62. package/dist/credential-contract.d.ts +10 -0
  63. package/dist/credential-rules.js +1 -3
  64. package/dist/credential-url.js +108 -0
  65. package/dist/credentials.d.ts +6 -1
  66. package/dist/credentials.js +27 -18
  67. package/dist/d1.d.ts +130 -0
  68. package/dist/d1.js +290 -0
  69. package/dist/describe-config.d.ts +165 -0
  70. package/dist/describe-config.js +315 -0
  71. package/dist/described.js +106 -0
  72. package/dist/downstream-input-context.js +119 -0
  73. package/dist/downstream-input.js +323 -0
  74. package/dist/errors.d.ts +97 -20
  75. package/dist/errors.js +158 -80
  76. package/dist/execute.js +453 -305
  77. package/dist/executor-admission.d.ts +1 -0
  78. package/dist/executor-admission.js +11 -15
  79. package/dist/executor-contract.d.ts +20 -0
  80. package/dist/executor-contract.js +48 -0
  81. package/dist/executor-result.js +24 -9
  82. package/dist/executors/quickjs-child.js +3 -4
  83. package/dist/executors/quickjs-runtime.js +147 -59
  84. package/dist/executors/quickjs.js +29 -35
  85. package/dist/favicon.js +1 -2
  86. package/dist/fix-prompt.js +1 -3
  87. package/dist/guest-runtime.js +188 -0
  88. package/dist/guest-types.d.ts +176 -0
  89. package/dist/guest-types.js +1 -0
  90. package/dist/html-security.js +24 -0
  91. package/dist/identity.js +1 -3
  92. package/dist/inbound-credential.js +52 -0
  93. package/dist/index.d.ts +25 -257
  94. package/dist/index.js +65 -478
  95. package/dist/invocation-auth.js +69 -0
  96. package/dist/invocation.js +230 -73
  97. package/dist/json-schema.d.ts +1 -1
  98. package/dist/mcp-client-context.js +35 -0
  99. package/dist/mcp-result.js +11 -7
  100. package/dist/meta-output.js +76 -0
  101. package/dist/meta-tool-names.d.ts +2 -0
  102. package/dist/meta-tool-names.js +3 -0
  103. package/dist/meta-tools.js +285 -209
  104. package/dist/module-contracts.d.ts +8 -23
  105. package/dist/node.d.ts +0 -2
  106. package/dist/node.js +2 -2
  107. package/dist/oauth-callback-outcome.js +1 -3
  108. package/dist/oauth-handoff.js +117 -0
  109. package/dist/oauth-partition.js +17 -0
  110. package/dist/oauth-sealing.js +20 -0
  111. package/dist/operator-record.d.ts +137 -0
  112. package/dist/operator-record.js +420 -0
  113. package/dist/operator-ui/assets.js +31 -0
  114. package/dist/operator-ui/contract.d.ts +72 -0
  115. package/dist/operator-ui/contract.js +1 -0
  116. package/dist/operator-ui/fix-prompts.d.ts +18 -0
  117. package/dist/operator-ui/generated.js +5 -4
  118. package/dist/operator-ui/model.d.ts +12 -87
  119. package/dist/operator-ui/model.js +2 -9
  120. package/dist/operator-ui/setup-commands.js +1 -3
  121. package/dist/operator-ui/view.d.ts +323 -0
  122. package/dist/operator-ui/view.js +62 -189
  123. package/dist/page-styles.js +2 -3
  124. package/dist/program-source.js +14 -2
  125. package/dist/{exempt-writes.js → program-writes.js} +55 -18
  126. package/dist/provider.d.ts +142 -0
  127. package/dist/provider.js +187 -0
  128. package/dist/providers/_shared/google/result-size.js +57 -0
  129. package/dist/providers/_shared/google/service-account.d.ts +58 -0
  130. package/dist/providers/_shared/google/service-account.js +500 -0
  131. package/dist/providers/_shared/google/workspace.d.ts +276 -0
  132. package/dist/providers/_shared/google/workspace.js +518 -0
  133. package/dist/providers/basecamp/index.d.ts +43 -0
  134. package/dist/providers/basecamp/index.js +997 -0
  135. package/dist/providers/basecamp/skill.generated.js +9 -0
  136. package/dist/providers/breeze/index.d.ts +34 -0
  137. package/dist/providers/breeze/index.js +1446 -0
  138. package/dist/providers/breeze/skill.generated.js +9 -0
  139. package/dist/providers/ccb/index.d.ts +103 -0
  140. package/dist/providers/ccb/index.js +1725 -0
  141. package/dist/providers/ccb/skill.generated.js +9 -0
  142. package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
  143. package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
  144. package/dist/providers/cloudflare/skill.generated.js +10 -0
  145. package/dist/providers/docs/index.d.ts +54 -0
  146. package/dist/providers/docs/index.js +1237 -0
  147. package/dist/providers/docs/skill.generated.js +9 -0
  148. package/dist/providers/drive/index.d.ts +53 -0
  149. package/dist/providers/drive/index.js +1523 -0
  150. package/dist/providers/drive/skill.generated.js +9 -0
  151. package/dist/providers/forms/index.d.ts +54 -0
  152. package/dist/providers/forms/index.js +1217 -0
  153. package/dist/providers/forms/skill.generated.js +11 -0
  154. package/dist/providers/github/auth.d.ts +32 -0
  155. package/dist/providers/github/auth.js +361 -0
  156. package/dist/providers/github/hosted.js +218 -0
  157. package/dist/providers/github/index.d.ts +13 -0
  158. package/dist/providers/github/index.js +140 -0
  159. package/dist/providers/github/key.js +100 -0
  160. package/dist/providers/github/rest.js +321 -0
  161. package/dist/providers/github/scope.d.ts +29 -0
  162. package/dist/providers/github/scope.js +124 -0
  163. package/dist/providers/github/skill.generated.js +8 -0
  164. package/dist/providers/gmail/index.d.ts +51 -0
  165. package/dist/providers/gmail/index.js +1436 -0
  166. package/dist/providers/gmail/skill.generated.js +9 -0
  167. package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
  168. package/dist/providers/linear/index.js +352 -0
  169. package/dist/providers/linear/skill.generated.js +8 -0
  170. package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
  171. package/dist/providers/mixpanel/index.js +416 -0
  172. package/dist/providers/mixpanel/skill.generated.js +9 -0
  173. package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
  174. package/dist/providers/{notion.js → notion/index.js} +226 -239
  175. package/dist/providers/notion/skill.generated.js +10 -0
  176. package/dist/providers/overflow/index.d.ts +60 -0
  177. package/dist/providers/overflow/index.js +1535 -0
  178. package/dist/providers/overflow/skill.generated.js +8 -0
  179. package/dist/providers/planning-center/index.d.ts +59 -0
  180. package/dist/providers/planning-center/index.js +2199 -0
  181. package/dist/providers/planning-center/skill.generated.js +10 -0
  182. package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
  183. package/dist/providers/revenuecat/index.js +557 -0
  184. package/dist/providers/revenuecat/skill.generated.js +11 -0
  185. package/dist/providers/sheets/index.d.ts +54 -0
  186. package/dist/providers/sheets/index.js +1237 -0
  187. package/dist/providers/sheets/skill.generated.js +10 -0
  188. package/dist/providers/slides/index.d.ts +53 -0
  189. package/dist/providers/slides/index.js +2645 -0
  190. package/dist/providers/slides/skill.generated.js +9 -0
  191. package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
  192. package/dist/providers/stripe/index.js +266 -0
  193. package/dist/providers/stripe/skill.generated.js +11 -0
  194. package/dist/providers/tithely/index.d.ts +49 -0
  195. package/dist/providers/tithely/index.js +1003 -0
  196. package/dist/providers/tithely/skill.generated.js +8 -0
  197. package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
  198. package/dist/providers/vercel/index.js +1038 -0
  199. package/dist/providers/vercel/mcp-ownership.js +212 -0
  200. package/dist/providers/vercel/skill.generated.js +11 -0
  201. package/dist/registry.d.ts +108 -171
  202. package/dist/registry.js +513 -925
  203. package/dist/request-state.js +21 -0
  204. package/dist/resource-read.js +100 -0
  205. package/dist/result-shapes.js +17 -49
  206. package/dist/retired-toolkits.js +1 -1
  207. package/dist/routes/access-tokens.js +3 -6
  208. package/dist/routes/activity-context.js +21 -0
  209. package/dist/routes/activity-disclosure.js +40 -0
  210. package/dist/routes/activity.js +59 -21
  211. package/dist/routes/actor-labels.js +3 -50
  212. package/dist/routes/connect.js +221 -0
  213. package/dist/routes/credentials.js +15 -27
  214. package/dist/routes/mcp.js +356 -130
  215. package/dist/routes/oauth-client-metadata.js +15 -0
  216. package/dist/routes/oauth-management.js +45 -107
  217. package/dist/routes/oauth.js +136 -57
  218. package/dist/routes/operator.js +3 -3
  219. package/dist/routes/shared.d.ts +25 -64
  220. package/dist/routes/shared.js +160 -80
  221. package/dist/routes/skills.js +30 -0
  222. package/dist/routes/ui-config.js +225 -0
  223. package/dist/routes/ui-data.js +40 -35
  224. package/dist/routes/ui.js +66 -56
  225. package/dist/runtime/admission.js +4 -2
  226. package/dist/runtime/call-admission.js +3 -1
  227. package/dist/runtime/connector-scope.js +1 -4
  228. package/dist/runtime/run.js +10 -39
  229. package/dist/runtime/services.js +12 -117
  230. package/dist/runtime/shared-read.js +1 -3
  231. package/dist/runtime/storage.js +8 -1
  232. package/dist/sent-secrets.d.ts +52 -0
  233. package/dist/sent-secrets.js +474 -0
  234. package/dist/server.js +28 -71
  235. package/dist/skills.js +406 -174
  236. package/dist/sqlite.d.ts +48 -0
  237. package/dist/sqlite.js +166 -0
  238. package/dist/storage/keys.js +428 -0
  239. package/dist/storage/memory.js +7 -0
  240. package/dist/storage/sql.d.ts +66 -0
  241. package/dist/storage/sql.js +534 -0
  242. package/dist/timeout.js +4 -2
  243. package/dist/tool-name.js +17 -0
  244. package/dist/tool-safety.d.ts +9 -35
  245. package/dist/tool-safety.js +20 -40
  246. package/dist/types.d.ts +320 -54
  247. package/dist/types.js +0 -1
  248. package/dist/ui.d.ts +7 -19
  249. package/dist/ui.js +76 -90
  250. package/dist/url-safety.js +3 -6
  251. package/dist/usage-guide.js +137 -0
  252. package/dist/validate.d.ts +7 -0
  253. package/dist/validate.js +309 -47
  254. package/dist/version.d.ts +1 -7
  255. package/dist/version.js +3 -7
  256. package/dist/worker.d.ts +11 -0
  257. package/dist/worker.js +434 -0
  258. package/documentation/architecture.md +665 -230
  259. package/documentation/auth.md +962 -458
  260. package/documentation/code-mode.md +501 -312
  261. package/documentation/meta-tools.md +449 -200
  262. package/documentation/operator-tests.md +93 -0
  263. package/documentation/provider-migration-0.29.md +60 -0
  264. package/examples/worker/AGENTS.md +34 -12
  265. package/examples/worker/README.md +286 -255
  266. package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
  267. package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
  268. package/examples/worker/src/connecta.config.ts +151 -0
  269. package/examples/worker/src/index.ts +14 -197
  270. package/examples/worker/wrangler.jsonc +15 -35
  271. package/package.json +125 -35
  272. package/templates/node/.dockerignore +1 -2
  273. package/templates/node/.env.example +20 -21
  274. package/templates/node/AGENTS.md +21 -17
  275. package/templates/node/Dockerfile +3 -5
  276. package/templates/node/README.md +133 -58
  277. package/templates/node/docker-compose.yml +11 -12
  278. package/templates/node/package.json +4 -2
  279. package/templates/node/src/connecta.config.ts +119 -0
  280. package/templates/node/src/index.ts +9 -154
  281. package/templates/node/src/provision-token.ts +17 -0
  282. package/AGENTS.md +0 -170
  283. package/dist/artifacts/connector.d.ts +0 -58
  284. package/dist/artifacts/connector.js +0 -730
  285. package/dist/artifacts/document.js +0 -86
  286. package/dist/artifacts/guide.js +0 -140
  287. package/dist/artifacts/html-scan.js +0 -329
  288. package/dist/artifacts/json.js +0 -78
  289. package/dist/artifacts/kv-store.d.ts +0 -20
  290. package/dist/artifacts/kv-store.js +0 -140
  291. package/dist/artifacts/markdown.js +0 -478
  292. package/dist/artifacts/module.d.ts +0 -37
  293. package/dist/artifacts/module.js +0 -66
  294. package/dist/artifacts/operations.d.ts +0 -197
  295. package/dist/artifacts/operations.js +0 -1002
  296. package/dist/artifacts/refresh.d.ts +0 -55
  297. package/dist/artifacts/refresh.js +0 -236
  298. package/dist/artifacts/routes.js +0 -206
  299. package/dist/artifacts/types.d.ts +0 -214
  300. package/dist/artifacts/types.js +0 -22
  301. package/dist/artifacts/validate.d.ts +0 -62
  302. package/dist/artifacts/validate.js +0 -651
  303. package/dist/artifacts.d.ts +0 -6
  304. package/dist/artifacts.js +0 -9
  305. package/dist/auth/bearer.d.ts +0 -11
  306. package/dist/auth/bearer.js +0 -50
  307. package/dist/providers/linear.js +0 -217
  308. package/dist/providers/mixpanel.js +0 -247
  309. package/dist/providers/revenuecat.js +0 -317
  310. package/dist/providers/stripe.js +0 -253
  311. package/dist/providers/vercel.js +0 -1253
  312. package/dist/storage/file.d.ts +0 -15
  313. package/dist/storage/file.js +0 -455
  314. package/ethos.md +0 -93
  315. package/examples/worker/src/cloudflare-kv.ts +0 -43
  316. package/examples/worker/src/d1-activity-row.ts +0 -155
  317. package/examples/worker/src/d1-activity.ts +0 -147
  318. package/examples/worker/src/d1-storage.ts +0 -138
  319. package/examples/worker/src/r2-artifact-blobs.ts +0 -29
  320. package/templates/node/src/file-activity.ts +0 -182
@@ -1,50 +0,0 @@
1
- import { assertNoRetiredToolkitOptions } from "../retired-toolkits.js";
2
- const encoder = new TextEncoder();
3
- /** Constant-time byte comparison. Differing lengths still iterate to reduce leak. */
4
- function timingSafeEqual(a, b) {
5
- if (a.length !== b.length) {
6
- let r = 1;
7
- const n = Math.max(a.length, b.length);
8
- for (let i = 0; i < n; i++)
9
- r |= (a[i] ?? 0) ^ (b[i] ?? 0);
10
- return false;
11
- }
12
- let r = 0;
13
- for (let i = 0; i < a.length; i++)
14
- r |= (a[i] ?? 0) ^ (b[i] ?? 0);
15
- return r === 0;
16
- }
17
- /**
18
- * Static bearer-token inbound auth. Constant-time compares the Bearer token
19
- * against `secret`. Checked before interactive providers in the server; a
20
- * mismatch falls through so another configured provider can admit the request.
21
- */
22
- export function bearerToken(secret, options = {}) {
23
- assertNoRetiredToolkitOptions("bearerToken", options);
24
- const secretBytes = encoder.encode(secret);
25
- return {
26
- kind: "bearer",
27
- authorize(request) {
28
- const header = request.headers.get("authorization") ?? "";
29
- const match = /^Bearer\s+(.+)$/i.exec(header);
30
- if (match && timingSafeEqual(encoder.encode(match[1]), secretBytes)) {
31
- return {
32
- ok: true,
33
- ...(options.subjectId ? { subjectId: options.subjectId } : {}),
34
- };
35
- }
36
- return {
37
- ok: false,
38
- response: new Response(JSON.stringify({ error: "unauthorized" }), {
39
- status: 401,
40
- headers: {
41
- "Content-Type": "application/json",
42
- // A configured secret has no OAuth metadata or issuer to
43
- // advertise; interactive adapters own resource discovery.
44
- "WWW-Authenticate": "Bearer",
45
- },
46
- }),
47
- };
48
- },
49
- };
50
- }
@@ -1,217 +0,0 @@
1
- import { remoteMcp, withCredentialDefaults, } from "../connectors/remote-mcp.js";
2
- import { vettedCatalog, withVettedCatalog } from "../catalog-drift.js";
3
- import { defined } from "../connectors/api.js";
4
- /**
5
- * Linear publishes two hosted endpoints. `read-only` is not a client-side
6
- * filter: it advertises the `read` scope alone, so the token minted for it
7
- * cannot reach Linear's write APIs at all. The deprecated `/sse` transport is
8
- * deliberately absent — it now answers 404.
9
- */
10
- export const LINEAR_MCP_ENDPOINTS = {
11
- "read-write": "https://mcp.linear.app/mcp",
12
- "read-only": "https://mcp.linear.app/mcp/readonly",
13
- };
14
- /**
15
- * Reviewed reads, listed by name (P5). The list is a superset: Linear's hosted
16
- * `tools/list` varies by plan and enabled features, so a name this workspace
17
- * never returns costs nothing while an unlisted new one fails closed.
18
- */
19
- const READ_ONLY_TOOLS = new Set([
20
- // Issues
21
- "list_issues",
22
- "get_issue",
23
- "list_issue_statuses",
24
- "get_issue_status",
25
- "list_issue_labels",
26
- // Projects
27
- "list_projects",
28
- "get_project",
29
- "list_project_labels",
30
- // Milestones
31
- "list_milestones",
32
- "get_milestone",
33
- // Initiatives
34
- "list_initiatives",
35
- "get_initiative",
36
- "list_initiative_labels",
37
- // Cycles
38
- "list_cycles",
39
- // Comments
40
- "list_comments",
41
- // Documents
42
- "list_documents",
43
- "get_document",
44
- // Teams and users
45
- "list_teams",
46
- "get_team",
47
- "list_users",
48
- "get_user",
49
- "get_workspace",
50
- // Templates
51
- "list_templates",
52
- "get_template",
53
- // Status updates
54
- "get_status_updates",
55
- // Releases
56
- "list_release_pipelines",
57
- "list_releases",
58
- "get_release",
59
- "list_release_notes",
60
- "get_release_note",
61
- // Code review
62
- "list_diffs",
63
- "get_diff",
64
- "get_diff_threads",
65
- // Attachments
66
- "get_attachment",
67
- // Agent skills
68
- "list_agent_skills",
69
- "get_agent_skill",
70
- // Documentation search
71
- "search_documentation",
72
- // Customer requests (plan-gated)
73
- "list_customers",
74
- // Markdown helper. It reads images out of content it is handed and touches
75
- // no workspace state; the hosted server ships it annotated `readOnlyHint:
76
- // true, idempotentHint: true`, and a fill-in classification agrees rather
77
- // than argues.
78
- "extract_images",
79
- ]);
80
- /**
81
- * Reviewed writes with their destructive verdict. Every `save_*` is destructive
82
- * because Linear's `save_*` tools are upserts: omitting a record id creates,
83
- * supplying one overwrites in place, and the schema cannot tell them apart. The
84
- * genuine creates — the `create_*_label` and attachment tools — stay additive,
85
- * since `readOnlyHint: false` already routes them through the approval path.
86
- */
87
- const WRITE_TOOLS = new Map([
88
- // Issues
89
- ["save_issue", "destructive"],
90
- ["create_issue_label", "additive"],
91
- // Projects
92
- ["save_project", "destructive"],
93
- // Milestones
94
- ["save_milestone", "destructive"],
95
- // Initiatives
96
- ["save_initiative", "destructive"],
97
- ["create_initiative_label", "additive"],
98
- // Comments
99
- ["save_comment", "destructive"],
100
- ["delete_comment", "destructive"],
101
- // Documents
102
- ["save_document", "destructive"],
103
- // Status updates
104
- ["save_status_update", "destructive"],
105
- ["delete_status_update", "destructive"],
106
- // Releases
107
- ["save_release", "destructive"],
108
- ["save_release_note", "destructive"],
109
- // Code review
110
- ["save_diff_comment", "destructive"],
111
- ["resolve_diff_thread", "destructive"],
112
- ["delete_diff_comment", "destructive"],
113
- ["submit_diff_review", "destructive"],
114
- ["merge_diff", "destructive"],
115
- // Attachments
116
- ["prepare_attachment_upload", "additive"],
117
- ["create_attachment_from_upload", "additive"],
118
- ["create_attachment", "additive"],
119
- ["delete_attachment", "destructive"],
120
- // Explicit issue access. Both halves change an existing issue's audience.
121
- ["share_issue", "destructive"],
122
- ["unshare_issue", "destructive"],
123
- // Customer requests (plan-gated)
124
- ["save_customer", "destructive"],
125
- ["delete_customer", "destructive"],
126
- ["save_customer_need", "destructive"],
127
- ["delete_customer_need", "destructive"],
128
- ]);
129
- /**
130
- * One release-reviewed manifest, used both to classify a live tool and as the
131
- * baseline the drift check compares against, so the annotation a caller gets
132
- * and the verdict a check reads can never disagree. Drift must surface as an
133
- * unclassified tool on the approval path (P5), never a quiet re-guess.
134
- */
135
- export const LINEAR_VETTED_CATALOG = vettedCatalog({
136
- reads: READ_ONLY_TOOLS,
137
- writes: WRITE_TOOLS,
138
- });
139
- function usageGuide(purpose, access, instructions) {
140
- const accountInstructions = instructions?.trim();
141
- // Leads the guide because discovery summarizes a connector by its first
142
- // content line: whether this connection can write at all is the one thing an
143
- // agent must know before it opens the guide, and `search_tools` shows the
144
- // summary without the description.
145
- const accessNote = access === "read-only"
146
- ? "Read-only connection: bound to Linear's read-only endpoint, whose token is scope-limited downstream, so every write fails at Linear regardless of arguments. Route writes to a connector configured for read-write access."
147
- : "Read-write connection: treat every `save_`, `create_`, `delete_`, `resolve_`, `submit_`, and `merge_` operation as a write. Connecta routes the maintained write catalog through `call_destructive_tool`; newly added tools also fail closed until a release classifies them.";
148
- return `# Linear usage
149
-
150
- ${accessNote}
151
-
152
- Workspace purpose: ${purpose}
153
-
154
- - Resolve identity before acting. \`list_teams\`, \`list_users\`, \`list_projects\`, \`list_issue_statuses\`, and \`list_issue_labels\` return the ids that create and update arguments expect; do not guess a team, status, label, or assignee id.
155
- - Issues carry a human identifier like \`ENG-123\` — team key, dash, number — alongside a UUID. Use the identifier the request gave you and resolve it with \`get_issue\` or \`list_issues\` when a tool wants an id; never fabricate an identifier or renumber one.
156
- - \`save_*\` tools are upserts: omit the record id to create, supply it to update in place. Read the record first when you mean to update, and send only the fields you intend to change — an upsert overwrites what you restate.
157
- - Labels are the exception to that naming: \`create_issue_label\` and \`create_initiative_label\` only ever create.
158
- - Projects, milestones, and initiatives nest: initiatives contain projects, projects contain milestones and issues, and cycles are per-team time boxes. Scope a search by team or project rather than listing the workspace and filtering afterwards.
159
- - List tools paginate with a cursor. Thread the returned cursor for the next page instead of raising the page size, and reduce pages inside \`execute_code\` before returning them.
160
- - This workspace's catalog is not the whole product. Customer requests, releases, and code review are plan- and feature-gated, so search the catalog for what this connector actually exposes rather than assuming a tool exists.
161
- - Linear meters the underlying API per user per hour, shared with everything else that credential does. Reuse discovery results within a run and avoid speculative fan-out.
162
- - An \`auth_required\` failure means this connector's Linear authorization is missing or expired: run \`authorize_connector\` for this connector id, then retry the same call unchanged.
163
- ${accountInstructions
164
- ? `\n## Workspace instructions\n\n${accountInstructions}\n`
165
- : ""}`;
166
- }
167
- /** A maintained Linear hosted-MCP connection. */
168
- export function linear(id, options) {
169
- const purpose = options.purpose.trim();
170
- if (!purpose) {
171
- throw new Error("linear() requires a non-empty workspace purpose.");
172
- }
173
- const access = options.access;
174
- if (access !== "read-write" && access !== "read-only") {
175
- throw new Error(`linear("${id}") requires access "read-write" or "read-only".`);
176
- }
177
- const connector = remoteMcp(id, {
178
- url: LINEAR_MCP_ENDPOINTS[access],
179
- ...(options.authScope ? { authScope: options.authScope } : {}),
180
- // The title is what browse-time discovery renders; a read-only connection
181
- // says so there rather than only in a description the caller may not see.
182
- title: options.title ?? (access === "read-only" ? "Linear (read-only)" : "Linear"),
183
- description: access === "read-only"
184
- ? `Linear issue tracking and project planning (read-only) — ${purpose}`
185
- : `Linear issue tracking and project planning — ${purpose}`,
186
- // Linear's MCP endpoint takes an API key the same way it takes an OAuth
187
- // token — `Authorization: Bearer <yourtoken>` — so only the slot copy is
188
- // provider-specific and the bearer framing default stands. The bare-header
189
- // convention belongs to Linear's GraphQL API, not to this endpoint.
190
- auth: withCredentialDefaults(options.auth ?? { type: "oauth" }, {
191
- credential: {
192
- label: "Personal API key",
193
- description: "A Linear personal API key. It carries the issuing user's full workspace access and is stored encrypted; the read-only endpoint still limits what it can reach.",
194
- placeholder: "lin_api_…",
195
- },
196
- }),
197
- requireHttps: true,
198
- usageGuide: {
199
- content: usageGuide(purpose, access, options.instructions),
200
- // Explicit rather than derived. The derived summary would truncate the
201
- // access note mid-sentence at 120 characters, and the one thing a
202
- // browsing agent must not get wrong is whether this connection can write
203
- // at all ([#342](https://github.com/zackbart/connecta/issues/342)).
204
- summary: access === "read-only"
205
- ? "Read-only: every write fails at Linear. Id resolution, upsert semantics, and cursor paging."
206
- : "Read-write. Id resolution, `save_*` upsert semantics, plan-gated areas, and cursor paging.",
207
- // Not `required`. Linear's own schemas describe each call correctly; the
208
- // guide adds cross-tool sequence advice that is worth reading before a
209
- // write, not worth loading before every read.
210
- },
211
- ...defined({
212
- callAdmission: options.callAdmission,
213
- maxResultBytes: options.maxResultBytes,
214
- }),
215
- });
216
- return withVettedCatalog(connector, LINEAR_VETTED_CATALOG);
217
- }
@@ -1,247 +0,0 @@
1
- import { remoteMcp, withCredentialDefaults, } from "../connectors/remote-mcp.js";
2
- import { vettedCatalog, withVettedCatalog } from "../catalog-drift.js";
3
- import { defined } from "../connectors/api.js";
4
- export const MIXPANEL_MCP_ENDPOINTS = {
5
- us: "https://mcp.mixpanel.com/mcp",
6
- eu: "https://mcp-eu.mixpanel.com/mcp",
7
- in: "https://mcp-in.mixpanel.com/mcp",
8
- };
9
- /** Tools whose official contract is observational rather than mutating. */
10
- const READ_ONLY_TOOLS = new Set([
11
- "Run-Query",
12
- "Get-Query-Schema",
13
- "Get-Report",
14
- "Display-Query",
15
- "List-Dashboards",
16
- "Get-Dashboard",
17
- "Get-Business-Context",
18
- "Get-Projects",
19
- "List-Organizations",
20
- "Get-Events",
21
- "List-Properties",
22
- "Get-Property-Values",
23
- "Search-Entities",
24
- "Get-Issues",
25
- "Get-Lexicon-URL",
26
- "Find-Duplicate-Groups",
27
- "Get-Custom-Property",
28
- "Get-Cohort",
29
- "List-Cohorts",
30
- "Describe-Cohort-Schema",
31
- "Get-Lookup-Table",
32
- "Get-Metric",
33
- "List-Metrics",
34
- "Get-User-Replays-Data",
35
- "List-Experiments",
36
- "Get-Experiment",
37
- "Get-Experiment-Setup-Guidance",
38
- "Get-Experiment-Results-Interpretation-Guidance",
39
- "Explain-Experiment-Health-Check",
40
- "Run-Experiment-Pre-Launch-Checks",
41
- "Search-Prior-Experiments",
42
- "List-Feature-Flags",
43
- "Get-Feature-Flag",
44
- "Get-Feature-Flag-Setup-Guidance",
45
- "Get-Feature-Flag-Lifecycle-Guidance",
46
- ]);
47
- /**
48
- * Reviewed writes, each with its destructive verdict (P5). Additive writes stay
49
- * `additive` because `readOnlyHint: false` already routes them through the
50
- * approval path, and claiming destruction only inflates the copy a host shows a
51
- * human. Anything unlisted is not read-only, so a new name fails closed.
52
- */
53
- const WRITE_TOOLS = new Map([
54
- ["Create-Dashboard", "additive"],
55
- ["Update-Dashboard", "destructive"],
56
- ["Duplicate-Dashboard", "additive"],
57
- ["Delete-Dashboard", "destructive"],
58
- ["Edit-Event", "destructive"],
59
- ["Edit-Property", "destructive"],
60
- ["Bulk-Edit-Events", "destructive"],
61
- ["Bulk-Edit-Properties", "destructive"],
62
- ["Create-Tag", "additive"],
63
- ["Rename-Tag", "destructive"],
64
- ["Delete-Tag", "destructive"],
65
- ["Dismiss-Issues", "destructive"],
66
- ["Update-Business-Context", "destructive"],
67
- ["Dismiss-Duplicate-Group", "destructive"],
68
- ["Merge-Group", "destructive"],
69
- ["Create-Custom-Property", "additive"],
70
- ["Update-Custom-Property", "destructive"],
71
- ["Create-Cohort", "additive"],
72
- ["Update-Cohort", "destructive"],
73
- ["Delete-Cohort", "destructive"],
74
- ["Create-Lookup-Table", "additive"],
75
- ["Update-Lookup-Table", "destructive"],
76
- ["Create-Metric", "additive"],
77
- ["Update-Metric", "destructive"],
78
- ["Create-Experiment", "additive"],
79
- ["Update-Experiment", "destructive"],
80
- ["Create-Feature-Flag", "additive"],
81
- ["Update-Feature-Flag", "destructive"],
82
- // Applies generated names and descriptions to existing Lexicon events.
83
- ["Fill-Event-Metadata", "destructive"],
84
- ]);
85
- /** Live US hosted-MCP schemas reviewed read-only on 2026-08-30 (#395, #512). */
86
- const MIXPANEL_SCHEMA_DIGESTS = {
87
- "Bulk-Edit-Events": "sha256:94512138df153de95436371f5a313e32b97faffebda3be6c0c69d09d1ff2b340",
88
- "Bulk-Edit-Properties": "sha256:93481eb896ded45b623c678612e2156439efbaad5b4d660da1f2b087e7409ee3",
89
- "Create-Cohort": "sha256:ea687f4bc607f8bfb5b1949e060239d6f7d629d3ec80fb0b72eae6cc6156ed03",
90
- "Create-Custom-Property": "sha256:d22818b812f3fd0e785a5bbbee26cf099eaa911d5b6f383f94cf458a2ed26294",
91
- "Create-Dashboard": "sha256:bd3b6e5134d27dafb04ccdf04d19e54dd23e6e2dc16989e418006e484268037b",
92
- "Create-Experiment": "sha256:1cfc2edeb2ac2d329a531d2095671a0653ab5b94b9e233b34268ff29a48c5ac5",
93
- "Create-Feature-Flag": "sha256:3460d11d726727349cac62db5c19915ab589b7f1d8387042f0a3783356b252c4",
94
- "Create-Lookup-Table": "sha256:c2fefa33a4f19fc65f394fecdc7126cab0ae874f7c97018cf003d8462a049e4c",
95
- "Create-Metric": "sha256:315766d0c197d87bb44aedd16732f6e69fbfc93661d1fcfc177cadc1751f26ce",
96
- "Create-Tag": "sha256:f99b6faad422aa6142d20d0aa4bdec1074e96a8ec45e35573e86d84b01df1d3b",
97
- "Delete-Cohort": "sha256:e18c500459edd9c2b6a614a3f6c97b668786be9abf72929a0a50086bdadb1dae",
98
- "Delete-Dashboard": "sha256:3a04594218b491743240e6970f677ed8ed132237d933efe30e97bdc41eb1ab6f",
99
- "Delete-Tag": "sha256:5f6cc58ada5d2796f124e15883fe05061d03f9129414f4c8e10a0ec463f17807",
100
- "Describe-Cohort-Schema": "sha256:775dbb8bb71ad3fa39ba35ca3a2683dfd88120f7af84a968531609c5a12de537",
101
- "Dismiss-Duplicate-Group": "sha256:4e39c6f9bb83ed54020097f6cf34507a5288de2c1ce333456c84682bb5986bc4",
102
- "Dismiss-Issues": "sha256:9c1f4901eca53f58d16feee126868d23c6ed1f5fad72344f86ea9965385b8644",
103
- "Display-Query": "sha256:d0776167b8a20898c1ff580ca9517da8dea6b827c64e10b9fa01ae1a3c2db95f",
104
- "Duplicate-Dashboard": "sha256:9738db7495d29034df966423df3c9d4b16ac3a8254c8473bf1e85a467fe9cf4e",
105
- "Edit-Event": "sha256:28c47da0b56f57da0f11eb11435441a39ecd5175600f854442744c66a379ef93",
106
- "Edit-Property": "sha256:11975587d2a566edc468db7cb24df70167d12068f30c1fe52c84f543cf4e2399",
107
- "Explain-Experiment-Health-Check": "sha256:a50b1263247012dc78521bf6c1dd18584a7b08d46221a444b1ca49c81d3286e5",
108
- "Fill-Event-Metadata": "sha256:53accc988f216bdd5d7a259d731f6df82549e4e6146b191f1815a0d1a72a1abe",
109
- "Find-Duplicate-Groups": "sha256:8f944cef9a147eab3c51bfcf1b873cef1409e5a6c21565d34e7ed20d23dcebb7",
110
- "Get-Business-Context": "sha256:309f5ba864c90132061096b4f0ebc1e78544a6486bac3a45bd661d16bcab2b6c",
111
- "Get-Cohort": "sha256:e18c500459edd9c2b6a614a3f6c97b668786be9abf72929a0a50086bdadb1dae",
112
- "Get-Custom-Property": "sha256:d1cbce906cee66d422846c8ef1a745bbeac2c058ecad6b1ee8dcdd2120fa86be",
113
- "Get-Dashboard": "sha256:56659fa3277723b75e24f3b4ca142ac9cd62120fb97e6c9252c221d00cdf8509",
114
- "Get-Events": "sha256:d206fe30ab47d64bf6090bffdb4d119a80cfc2a35963bbe7fd52d56060090ded",
115
- "Get-Experiment": "sha256:ab685aa985aa2ec36d9cbeb1b3c1ef298b020e552e8fdce12e75abbeb4706f2b",
116
- "Get-Experiment-Results-Interpretation-Guidance": "sha256:e517d9759f66f4a7ad15b0b67ffaabfb605e80949afcf41d007dfafd8f3e9574",
117
- "Get-Experiment-Setup-Guidance": "sha256:e517d9759f66f4a7ad15b0b67ffaabfb605e80949afcf41d007dfafd8f3e9574",
118
- "Get-Feature-Flag": "sha256:129de58b379ffba272bdbcee2b5759262e586dd415edc2067a69e9844d4d0877",
119
- "Get-Feature-Flag-Lifecycle-Guidance": "sha256:e517d9759f66f4a7ad15b0b67ffaabfb605e80949afcf41d007dfafd8f3e9574",
120
- "Get-Feature-Flag-Setup-Guidance": "sha256:e517d9759f66f4a7ad15b0b67ffaabfb605e80949afcf41d007dfafd8f3e9574",
121
- "Get-Issues": "sha256:cf172ef18f37504a758c825c7bd4bc23fd98c3421655754dccd8e5ee2d700a10",
122
- "Get-Lexicon-URL": "sha256:c6456d5c4a38ba069a2caa6cdac651be9d86d47bc6efb3316a893c7336d0e2bc",
123
- "Get-Lookup-Table": "sha256:061602b283461f083bbd74348c264f802cb21c4fe6d961241c7090895a8334ac",
124
- "Get-Metric": "sha256:eef10dd9ca25a63a63775565cbc4f2261b289dec526aa33df0f318eefbc96c46",
125
- "Get-Projects": "sha256:d23d07a777441f04b128f08a2c30a6e8a1573d203f8a1ad7788bc1fd57a9cbbf",
126
- "Get-Property-Values": "sha256:0cd487c9b92a187b21f456de3c785bb631aa30cba702785c9ff158608883a6bb",
127
- "Get-Query-Schema": "sha256:8fea929d2ad4f8fed6c47116ff0eaa6f964b3ddd4685e482b68a8dac0231af73",
128
- "Get-Report": "sha256:a99ba2af1ab57c1d5a606dbd7701968aa430ab23f5969f356a4c41f345dba041",
129
- "Get-User-Replays-Data": "sha256:5df287735478a67489075b0c7c9d8c07097abe67408d06743c7fb9be43c6e024",
130
- "List-Cohorts": "sha256:fd04778d60a027cfd777b40f36fbb037ba070661e149b2fce35a14865cada2db",
131
- "List-Dashboards": "sha256:994c1c9fc87a4f1f00a677b856a44bad028252d283bd8e647ae157683fc89ea2",
132
- "List-Experiments": "sha256:26a3f3e0b4e52135d74335dd769103303071fc48c15b1df40efd2dfa5a353848",
133
- "List-Feature-Flags": "sha256:75fc1ff14f3d3faedb8e00c6563d151de397d584429764fd0c332f6a84f6993c",
134
- "List-Metrics": "sha256:341710bebabb82112e80eb521d9d5cdb3bca024699b3aa795874d3549a315042",
135
- "List-Organizations": "sha256:e4c23f123dde073e00038d92ebd53f45157c83a4d3a2ff686ab1b66c859f4a11",
136
- "List-Properties": "sha256:52b38861df076119dfefe0128cf9819868336bf60e090f63c80da734877a69fe",
137
- "Merge-Group": "sha256:a3b215a5be70305c2f02439513bee76ae3947da14e2a9e5b6ff0afb9ad3d4dcd",
138
- "Rename-Tag": "sha256:a7e20e79ecd6ca7edca104fa1030e059ffae8962bf084d4a384c012ac9bbf087",
139
- "Run-Experiment-Pre-Launch-Checks": "sha256:f6b5d85f75450b76fda9c7ef441f190fd45fcaeaff4cc3c30a6d1bee76e4c706",
140
- "Run-Query": "sha256:0eb7d52343f6137275a02c2d7bb02dafdbfd25bd6f9067395eb689492d835466",
141
- "Search-Entities": "sha256:86cfa1d3bf7f17a70ad07264d7b1d16c83480e40996e8d847911fe8bde13e35e",
142
- "Search-Prior-Experiments": "sha256:847d1dcefaf6dc5e7ea967476f464a4d678a06b5e7d437dfb11ad4af2e56620f",
143
- "Update-Business-Context": "sha256:0d21290053b6d532386c3c83d60cd78013a7109492c02ba2e7822716f2cde027",
144
- "Update-Cohort": "sha256:ebe0d5afcc00e23eef55f079cd1816c851c2c647dff9565b7045f1f1615663f2",
145
- "Update-Custom-Property": "sha256:781aaaab41c1ab5958062dc393d02b1df2ef2a09a28d3c4f21ae3177f4f53c86",
146
- "Update-Dashboard": "sha256:2cc179ba75eda476ba7488f01503d947f023a4460aa98c4806ef0ab10c3b3ce8",
147
- "Update-Experiment": "sha256:3ea3902555c146f45127fc563b36ffb7ff04b7594765dac9ae98cc09dc432808",
148
- "Update-Feature-Flag": "sha256:9b34b19164168938d08a75d268c9becf8d189c85a1789a45061ae304041faf7c",
149
- "Update-Lookup-Table": "sha256:ef28f1ec9c9484a7a53b5e2b6659e70f79a8e71e55bda17025aa4ab3c23b6a63",
150
- "Update-Metric": "sha256:739bb6abdab19282afd4a6644a96183daabe9098a5322c44a77b840608a5ee9d",
151
- };
152
- /**
153
- * One release-reviewed manifest, used both to classify a live tool and as the
154
- * baseline the drift check compares against, so the annotation a caller gets
155
- * and the verdict a check reads can never disagree. Drift must surface as an
156
- * unclassified tool on the approval path (P5), never a quiet re-guess.
157
- */
158
- export const MIXPANEL_VETTED_CATALOG = vettedCatalog({
159
- reads: READ_ONLY_TOOLS,
160
- writes: WRITE_TOOLS,
161
- schemaDigests: MIXPANEL_SCHEMA_DIGESTS,
162
- });
163
- const REGION_COPY = {
164
- us: "US",
165
- eu: "EU",
166
- in: "India",
167
- };
168
- function usageGuide(purpose, region, instructions) {
169
- const accountInstructions = instructions?.trim();
170
- // Leads the guide because discovery summarizes a connector by its first
171
- // content line. A project lives in exactly one residency, so a question
172
- // pointed at the wrong region does not return fewer rows — it returns
173
- // nothing, and reads as the project having no data.
174
- const regionNote = `${REGION_COPY[region]}-residency connection: bound to Mixpanel's ${region} endpoint. A project created in another residency is not reachable from here at all, so an empty result may mean wrong connector rather than no data.`;
175
- return `# Mixpanel usage
176
-
177
- ${regionNote}
178
-
179
- Account purpose: ${purpose}
180
-
181
- - Start with \`Get-Projects\`, then use \`Get-Business-Context\` for the selected project before interpreting its events or metrics.
182
- - Resolve ids before acting; never guess one. \`Get-Projects\` yields the project id every other call is scoped by, and \`List-Dashboards\`, \`List-Cohorts\`, \`List-Metrics\`, \`List-Experiments\`, and \`List-Feature-Flags\` yield the ids their \`Get-\`, \`Update-\`, and \`Delete-\` counterparts expect.
183
- - Discover names with \`Get-Events\`, \`List-Properties\`, and \`Get-Property-Values\`; do not guess event or property spelling.
184
- - \`Get-Business-Context\` requires either \`project_id\` or \`organization_id\`. Its schema marks both optional, but the hosted tool rejects a call with neither.
185
- - \`Get-Property-Values\` requires \`properties\` or the deprecated \`property\` alias. Event property values also require \`event\`; prefer \`properties\` and never send both property forms with conflicting values.
186
- - \`List-Properties\` accepts \`names\` or \`query\`, never both. Use exact \`names\` for known properties and \`query\` for substring discovery.
187
- - One analysis is one \`execute_code\` program: fetch \`Get-Query-Schema\` once, run every \`Run-Query\` of the analysis in that program, and return the reduced table. The schema is tens of kilobytes and the same for every report type, so re-fetching it per query buys nothing. Never return raw \`Run-Query\` output.
188
- - Insights, funnels, and retention answer aggregate questions. A per-user ordered event timeline, or a sequence question such as "event A with no later event B", is not answerable with \`Run-Query\` in a reasonable number of calls, and this hosted catalog has no per-\`distinct_id\` event timeline — \`Get-User-Replays-Data\` covers one user's replays with their events only where session replay is enabled and present. If the deployment exposes a Mixpanel export or activity-feed connector, use that; if it does not, tell the user the question is out of reach here rather than approximating it with hourly buckets and hundreds of empty rows.
189
- - \`false\` on a boolean property may be an absent property: Mixpanel renders a missing value as \`false\` in boolean breakdowns, and server-imported events often lack client-side properties entirely. Confirm the property is present with \`List-Properties\` or \`Get-Property-Values\` before treating \`false\` as a signal, and say when a conclusion rests on that ambiguity.
190
- - Breakdown responses nest \`$overall\` and per-segment series objects. Flatten to one row per complete breakdown combination inside \`execute_code\` before returning, and drop \`$overall\` unless the question asks for the total.
191
- - Use \`Get-Report\` when the request names an existing saved report. Use \`Run-Query\` for a new question.
192
- - This account's tool list is not a fixed set. Mixpanel gates parts of its MCP catalog by plan and beta enrollment — experiments, feature flags, session replay, and issue triage are the usual absentees — so search this connector for what it actually exposes rather than assuming a documented tool is here.
193
- - Mixpanel meters MCP traffic per user per hour, shared with everything else that credential does. Reuse discovery results within a run and avoid speculative fan-out.
194
- - An \`auth_required\` failure means this connector's Mixpanel authorization is missing or expired: run \`authorize_connector\` for this connector id, then retry the same call unchanged. A rejected argument or a plan restriction comes back in Mixpanel's own words instead — read it rather than re-authorizing.
195
- - Treat every create, update, edit, merge, dismiss, duplicate, or delete operation as a write. Connecta routes the maintained write catalog through \`call_destructive_tool\`; newly added tools also fail closed until classified.
196
- ${accountInstructions
197
- ? `\n## Account instructions\n\n${accountInstructions}\n`
198
- : ""}`;
199
- }
200
- /** A maintained Mixpanel hosted-MCP connection. */
201
- export function mixpanel(id, options) {
202
- const purpose = options.purpose.trim();
203
- if (!purpose) {
204
- throw new Error("mixpanel() requires a non-empty account purpose.");
205
- }
206
- const region = options.region ?? "us";
207
- if (!(region in MIXPANEL_MCP_ENDPOINTS)) {
208
- throw new Error(`mixpanel("${id}") region must be "us", "eu", or "in".`);
209
- }
210
- const connector = remoteMcp(id, {
211
- url: MIXPANEL_MCP_ENDPOINTS[region],
212
- ...(options.authScope ? { authScope: options.authScope } : {}),
213
- // The region rides the title because browse-time discovery renders the
214
- // title and the guide summary and nothing else, and residency is the fact
215
- // an agent must not get wrong between two Mixpanel connections.
216
- title: options.title ?? `Mixpanel (${region})`,
217
- description: `Mixpanel product analytics (${REGION_COPY[region]} residency) — ${purpose}`,
218
- // Mixpanel's beta service-account scheme is deliberately not ordinary HTTP
219
- // Basic: the endpoint wants `Bearer Basic <base64(user:secret)>`. The
220
- // operator therefore pastes the pair, not an encoded blob, and Connecta
221
- // does the framing — the same shaping the maintainer drift check applies.
222
- auth: withCredentialDefaults(options.auth ?? { type: "oauth" }, {
223
- credential: {
224
- label: "Service account",
225
- description: "A Mixpanel service account as `username:secret`. Connecta encodes and frames it the way the hosted endpoint requires; it is stored encrypted and never displayed.",
226
- placeholder: "username:secret",
227
- },
228
- scheme: "Bearer Basic",
229
- }),
230
- requireHttps: true,
231
- usageGuide: {
232
- content: usageGuide(purpose, region, options.instructions),
233
- // Explicit rather than derived: the derived summary would truncate the
234
- // residency note mid-sentence at 120 characters
235
- // ([#342](https://github.com/zackbart/connecta/issues/342)).
236
- summary: `${REGION_COPY[region]} residency. Project scoping, id resolution, query-schema-first analysis, plan-gated catalog.`,
237
- // Not `required`. Mixpanel's own schemas describe each call; the guide
238
- // carries the project-then-context sequence, which is worth reading
239
- // before an analysis rather than before every call.
240
- },
241
- ...defined({
242
- callAdmission: options.callAdmission,
243
- maxResultBytes: options.maxResultBytes,
244
- }),
245
- });
246
- return withVettedCatalog(connector, MIXPANEL_VETTED_CATALOG);
247
- }