@zackbart/connecta 0.15.1 → 0.16.1

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 (335) hide show
  1. package/AGENTS.md +40 -20
  2. package/CHANGELOG.md +653 -0
  3. package/README.md +25 -5
  4. package/bin/connecta.mjs +44 -3
  5. package/dist/access-tokens.d.ts +0 -1
  6. package/dist/access-tokens.js +0 -1
  7. package/dist/activity.d.ts +50 -2
  8. package/dist/activity.js +34 -1
  9. package/dist/apps-shell.d.ts +0 -1
  10. package/dist/apps-shell.js +0 -1
  11. package/dist/auth/bearer.d.ts +0 -1
  12. package/dist/auth/bearer.js +0 -1
  13. package/dist/auth/clerk.d.ts +0 -1
  14. package/dist/auth/clerk.js +45 -9
  15. package/dist/auth/downstream-oauth.d.ts +0 -1
  16. package/dist/auth/downstream-oauth.js +0 -1
  17. package/dist/call-admission.d.ts +0 -1
  18. package/dist/call-admission.js +0 -1
  19. package/dist/catalog-drift.d.ts +99 -0
  20. package/dist/catalog-drift.js +251 -0
  21. package/dist/catalog-fingerprint.d.ts +0 -1
  22. package/dist/catalog-fingerprint.js +0 -1
  23. package/dist/catalog-limits.d.ts +0 -1
  24. package/dist/catalog-limits.js +0 -1
  25. package/dist/catalog-service.d.ts +0 -1
  26. package/dist/catalog-service.js +41 -5
  27. package/dist/catalog.d.ts +11 -1
  28. package/dist/catalog.js +20 -1
  29. package/dist/concurrency.d.ts +0 -1
  30. package/dist/concurrency.js +0 -1
  31. package/dist/connector-scope.d.ts +0 -1
  32. package/dist/connector-scope.js +0 -1
  33. package/dist/connectors/api.d.ts +29 -21
  34. package/dist/connectors/api.js +45 -19
  35. package/dist/connectors/guarded-fetch.d.ts +106 -0
  36. package/dist/connectors/guarded-fetch.js +289 -0
  37. package/dist/connectors/remote-mcp.d.ts +0 -1
  38. package/dist/connectors/remote-mcp.js +0 -1
  39. package/dist/credentials.d.ts +0 -1
  40. package/dist/credentials.js +0 -1
  41. package/dist/errors.d.ts +30 -3
  42. package/dist/errors.js +1 -1
  43. package/dist/execute.d.ts +0 -1
  44. package/dist/execute.js +0 -1
  45. package/dist/executor-admission.d.ts +11 -1
  46. package/dist/executor-admission.js +28 -1
  47. package/dist/executor-result.d.ts +0 -1
  48. package/dist/executor-result.js +0 -1
  49. package/dist/executors/quickjs-child.d.ts +0 -1
  50. package/dist/executors/quickjs-child.js +0 -1
  51. package/dist/executors/quickjs-protocol.d.ts +0 -1
  52. package/dist/executors/quickjs-protocol.js +0 -1
  53. package/dist/executors/quickjs-runtime.d.ts +0 -1
  54. package/dist/executors/quickjs-runtime.js +0 -1
  55. package/dist/executors/quickjs.d.ts +0 -1
  56. package/dist/executors/quickjs.js +2 -1
  57. package/dist/favicon.d.ts +0 -1
  58. package/dist/favicon.js +0 -1
  59. package/dist/index.d.ts +2 -3
  60. package/dist/index.js +24 -7
  61. package/dist/invocation.d.ts +0 -1
  62. package/dist/invocation.js +0 -1
  63. package/dist/json-schema.d.ts +0 -1
  64. package/dist/json-schema.js +0 -1
  65. package/dist/mcp-result.d.ts +0 -1
  66. package/dist/mcp-result.js +0 -1
  67. package/dist/meta-tools.d.ts +0 -1
  68. package/dist/meta-tools.js +0 -1
  69. package/dist/node.d.ts +0 -1
  70. package/dist/node.js +0 -1
  71. package/dist/operator-ui/generated.d.ts +2 -3
  72. package/dist/operator-ui/generated.js +3 -4
  73. package/dist/operator-ui/model.d.ts +10 -1
  74. package/dist/operator-ui/model.js +0 -1
  75. package/dist/operator-ui/view.d.ts +167 -0
  76. package/dist/operator-ui/view.js +270 -0
  77. package/dist/providers/cloudflare.d.ts +0 -1
  78. package/dist/providers/cloudflare.js +261 -299
  79. package/dist/providers/linear.d.ts +26 -5
  80. package/dist/providers/linear.js +32 -61
  81. package/dist/providers/mixpanel.d.ts +35 -4
  82. package/dist/providers/mixpanel.js +53 -79
  83. package/dist/providers/notion.d.ts +0 -1
  84. package/dist/providers/notion.js +87 -42
  85. package/dist/providers/stripe.d.ts +13 -1
  86. package/dist/providers/stripe.js +31 -60
  87. package/dist/registry.d.ts +34 -2
  88. package/dist/registry.js +85 -5
  89. package/dist/retired-toolkits.d.ts +0 -1
  90. package/dist/retired-toolkits.js +0 -1
  91. package/dist/routes/access-tokens.d.ts +0 -1
  92. package/dist/routes/access-tokens.js +0 -1
  93. package/dist/routes/activity.d.ts +0 -1
  94. package/dist/routes/activity.js +0 -1
  95. package/dist/routes/credentials.d.ts +0 -1
  96. package/dist/routes/credentials.js +0 -1
  97. package/dist/routes/mcp.d.ts +0 -1
  98. package/dist/routes/mcp.js +0 -1
  99. package/dist/routes/oauth.d.ts +0 -1
  100. package/dist/routes/oauth.js +0 -1
  101. package/dist/routes/shared.d.ts +2 -1
  102. package/dist/routes/shared.js +0 -1
  103. package/dist/routes/ui.d.ts +0 -1
  104. package/dist/routes/ui.js +0 -1
  105. package/dist/server.d.ts +0 -1
  106. package/dist/server.js +11 -1
  107. package/dist/skills.d.ts +0 -1
  108. package/dist/skills.js +0 -1
  109. package/dist/storage/file.d.ts +0 -1
  110. package/dist/storage/file.js +0 -1
  111. package/dist/storage/memory.d.ts +0 -1
  112. package/dist/storage/memory.js +0 -1
  113. package/dist/timeout.d.ts +0 -1
  114. package/dist/timeout.js +0 -1
  115. package/dist/tool-safety.d.ts +0 -1
  116. package/dist/tool-safety.js +0 -1
  117. package/dist/types.d.ts +45 -1
  118. package/dist/types.js +0 -1
  119. package/dist/ui.d.ts +0 -1
  120. package/dist/ui.js +13 -137
  121. package/dist/validate.d.ts +13 -15
  122. package/dist/validate.js +24 -11
  123. package/dist/version.d.ts +1 -2
  124. package/dist/version.js +1 -2
  125. package/documentation/architecture.md +186 -5
  126. package/documentation/auth.md +11 -0
  127. package/documentation/call-admission.md +142 -6
  128. package/documentation/cloudflare.md +92 -10
  129. package/documentation/code-first-exploration.md +2 -2
  130. package/documentation/code-mode.md +14 -14
  131. package/documentation/connector-guides.md +172 -5
  132. package/documentation/connectors.md +89 -0
  133. package/documentation/linear.md +20 -2
  134. package/documentation/mcp-ui-design.md +2 -2
  135. package/documentation/meta-tools.md +7 -1
  136. package/documentation/mixpanel.md +42 -9
  137. package/documentation/notion.md +23 -2
  138. package/documentation/operations.md +325 -5
  139. package/documentation/operator-ui.md +120 -5
  140. package/documentation/provider-audit.md +160 -0
  141. package/documentation/provider-conventions.md +667 -0
  142. package/documentation/request-admission.md +167 -5
  143. package/documentation/rich-output-design.md +1 -2
  144. package/documentation/stripe.md +15 -0
  145. package/documentation/upgrading.md +454 -0
  146. package/ethos.md +14 -9
  147. package/examples/worker/README.md +102 -12
  148. package/examples/worker/src/index.ts +46 -1
  149. package/examples/worker/wrangler.jsonc +14 -1
  150. package/package.json +10 -6
  151. package/templates/node/.dockerignore +10 -0
  152. package/templates/node/.env.example +40 -3
  153. package/templates/node/AGENTS.md +16 -1
  154. package/templates/node/Dockerfile +49 -0
  155. package/templates/node/README.md +117 -2
  156. package/templates/node/docker-compose.yml +39 -0
  157. package/templates/node/package.json +1 -1
  158. package/templates/node/src/file-activity.ts +182 -0
  159. package/templates/node/src/index.ts +80 -4
  160. package/assets/connecta-clay-hero.png +0 -0
  161. package/dist/access-tokens.d.ts.map +0 -1
  162. package/dist/access-tokens.js.map +0 -1
  163. package/dist/activity.d.ts.map +0 -1
  164. package/dist/activity.js.map +0 -1
  165. package/dist/apps-shell.d.ts.map +0 -1
  166. package/dist/apps-shell.js.map +0 -1
  167. package/dist/auth/bearer.d.ts.map +0 -1
  168. package/dist/auth/bearer.js.map +0 -1
  169. package/dist/auth/clerk.d.ts.map +0 -1
  170. package/dist/auth/clerk.js.map +0 -1
  171. package/dist/auth/downstream-oauth.d.ts.map +0 -1
  172. package/dist/auth/downstream-oauth.js.map +0 -1
  173. package/dist/call-admission.d.ts.map +0 -1
  174. package/dist/call-admission.js.map +0 -1
  175. package/dist/catalog-fingerprint.d.ts.map +0 -1
  176. package/dist/catalog-fingerprint.js.map +0 -1
  177. package/dist/catalog-limits.d.ts.map +0 -1
  178. package/dist/catalog-limits.js.map +0 -1
  179. package/dist/catalog-service.d.ts.map +0 -1
  180. package/dist/catalog-service.js.map +0 -1
  181. package/dist/catalog.d.ts.map +0 -1
  182. package/dist/catalog.js.map +0 -1
  183. package/dist/concurrency.d.ts.map +0 -1
  184. package/dist/concurrency.js.map +0 -1
  185. package/dist/connector-scope.d.ts.map +0 -1
  186. package/dist/connector-scope.js.map +0 -1
  187. package/dist/connectors/api.d.ts.map +0 -1
  188. package/dist/connectors/api.js.map +0 -1
  189. package/dist/connectors/remote-mcp.d.ts.map +0 -1
  190. package/dist/connectors/remote-mcp.js.map +0 -1
  191. package/dist/credentials.d.ts.map +0 -1
  192. package/dist/credentials.js.map +0 -1
  193. package/dist/errors.d.ts.map +0 -1
  194. package/dist/errors.js.map +0 -1
  195. package/dist/execute.d.ts.map +0 -1
  196. package/dist/execute.js.map +0 -1
  197. package/dist/executor-admission.d.ts.map +0 -1
  198. package/dist/executor-admission.js.map +0 -1
  199. package/dist/executor-result.d.ts.map +0 -1
  200. package/dist/executor-result.js.map +0 -1
  201. package/dist/executors/quickjs-child.d.ts.map +0 -1
  202. package/dist/executors/quickjs-child.js.map +0 -1
  203. package/dist/executors/quickjs-protocol.d.ts.map +0 -1
  204. package/dist/executors/quickjs-protocol.js.map +0 -1
  205. package/dist/executors/quickjs-runtime.d.ts.map +0 -1
  206. package/dist/executors/quickjs-runtime.js.map +0 -1
  207. package/dist/executors/quickjs.d.ts.map +0 -1
  208. package/dist/executors/quickjs.js.map +0 -1
  209. package/dist/favicon.d.ts.map +0 -1
  210. package/dist/favicon.js.map +0 -1
  211. package/dist/index.d.ts.map +0 -1
  212. package/dist/index.js.map +0 -1
  213. package/dist/invocation.d.ts.map +0 -1
  214. package/dist/invocation.js.map +0 -1
  215. package/dist/json-schema.d.ts.map +0 -1
  216. package/dist/json-schema.js.map +0 -1
  217. package/dist/mcp-result.d.ts.map +0 -1
  218. package/dist/mcp-result.js.map +0 -1
  219. package/dist/meta-tools.d.ts.map +0 -1
  220. package/dist/meta-tools.js.map +0 -1
  221. package/dist/node.d.ts.map +0 -1
  222. package/dist/node.js.map +0 -1
  223. package/dist/operator-ui/generated.d.ts.map +0 -1
  224. package/dist/operator-ui/generated.js.map +0 -1
  225. package/dist/operator-ui/model.d.ts.map +0 -1
  226. package/dist/operator-ui/model.js.map +0 -1
  227. package/dist/providers/cloudflare.d.ts.map +0 -1
  228. package/dist/providers/cloudflare.js.map +0 -1
  229. package/dist/providers/linear.d.ts.map +0 -1
  230. package/dist/providers/linear.js.map +0 -1
  231. package/dist/providers/mixpanel.d.ts.map +0 -1
  232. package/dist/providers/mixpanel.js.map +0 -1
  233. package/dist/providers/notion.d.ts.map +0 -1
  234. package/dist/providers/notion.js.map +0 -1
  235. package/dist/providers/stripe.d.ts.map +0 -1
  236. package/dist/providers/stripe.js.map +0 -1
  237. package/dist/registry.d.ts.map +0 -1
  238. package/dist/registry.js.map +0 -1
  239. package/dist/retired-toolkits.d.ts.map +0 -1
  240. package/dist/retired-toolkits.js.map +0 -1
  241. package/dist/routes/access-tokens.d.ts.map +0 -1
  242. package/dist/routes/access-tokens.js.map +0 -1
  243. package/dist/routes/activity.d.ts.map +0 -1
  244. package/dist/routes/activity.js.map +0 -1
  245. package/dist/routes/credentials.d.ts.map +0 -1
  246. package/dist/routes/credentials.js.map +0 -1
  247. package/dist/routes/mcp.d.ts.map +0 -1
  248. package/dist/routes/mcp.js.map +0 -1
  249. package/dist/routes/oauth.d.ts.map +0 -1
  250. package/dist/routes/oauth.js.map +0 -1
  251. package/dist/routes/shared.d.ts.map +0 -1
  252. package/dist/routes/shared.js.map +0 -1
  253. package/dist/routes/ui.d.ts.map +0 -1
  254. package/dist/routes/ui.js.map +0 -1
  255. package/dist/server.d.ts.map +0 -1
  256. package/dist/server.js.map +0 -1
  257. package/dist/skills.d.ts.map +0 -1
  258. package/dist/skills.js.map +0 -1
  259. package/dist/storage/file.d.ts.map +0 -1
  260. package/dist/storage/file.js.map +0 -1
  261. package/dist/storage/memory.d.ts.map +0 -1
  262. package/dist/storage/memory.js.map +0 -1
  263. package/dist/timeout.d.ts.map +0 -1
  264. package/dist/timeout.js.map +0 -1
  265. package/dist/tool-safety.d.ts.map +0 -1
  266. package/dist/tool-safety.js.map +0 -1
  267. package/dist/types.d.ts.map +0 -1
  268. package/dist/types.js.map +0 -1
  269. package/dist/ui.d.ts.map +0 -1
  270. package/dist/ui.js.map +0 -1
  271. package/dist/validate.d.ts.map +0 -1
  272. package/dist/validate.js.map +0 -1
  273. package/dist/version.d.ts.map +0 -1
  274. package/dist/version.js.map +0 -1
  275. package/examples/node/README.md +0 -52
  276. package/examples/node/src/index.ts +0 -71
  277. package/src/access-tokens.ts +0 -289
  278. package/src/activity.ts +0 -234
  279. package/src/apps-shell.ts +0 -370
  280. package/src/auth/bearer.ts +0 -61
  281. package/src/auth/clerk.ts +0 -553
  282. package/src/auth/downstream-oauth.ts +0 -575
  283. package/src/call-admission.ts +0 -521
  284. package/src/catalog-fingerprint.ts +0 -52
  285. package/src/catalog-limits.ts +0 -11
  286. package/src/catalog-service.ts +0 -1153
  287. package/src/catalog.ts +0 -790
  288. package/src/concurrency.ts +0 -39
  289. package/src/connector-scope.ts +0 -66
  290. package/src/connectors/api.ts +0 -159
  291. package/src/connectors/remote-mcp.ts +0 -1090
  292. package/src/credentials.ts +0 -428
  293. package/src/errors.ts +0 -364
  294. package/src/execute.ts +0 -1406
  295. package/src/executor-admission.ts +0 -328
  296. package/src/executor-result.ts +0 -107
  297. package/src/executors/quickjs-child.ts +0 -172
  298. package/src/executors/quickjs-protocol.ts +0 -99
  299. package/src/executors/quickjs-runtime.ts +0 -470
  300. package/src/executors/quickjs.ts +0 -776
  301. package/src/favicon.ts +0 -53
  302. package/src/index.ts +0 -666
  303. package/src/invocation.ts +0 -655
  304. package/src/json-schema.ts +0 -11
  305. package/src/mcp-result.ts +0 -43
  306. package/src/meta-tools.ts +0 -1607
  307. package/src/node.ts +0 -206
  308. package/src/operator-ui/browser.css +0 -423
  309. package/src/operator-ui/browser.ts +0 -1281
  310. package/src/operator-ui/generated.ts +0 -4
  311. package/src/operator-ui/model.ts +0 -111
  312. package/src/providers/cloudflare.ts +0 -3999
  313. package/src/providers/linear.ts +0 -302
  314. package/src/providers/mixpanel.ts +0 -229
  315. package/src/providers/notion.ts +0 -1879
  316. package/src/providers/stripe.ts +0 -307
  317. package/src/registry.ts +0 -1085
  318. package/src/retired-toolkits.ts +0 -14
  319. package/src/routes/access-tokens.ts +0 -115
  320. package/src/routes/activity.ts +0 -215
  321. package/src/routes/credentials.ts +0 -254
  322. package/src/routes/mcp.ts +0 -429
  323. package/src/routes/oauth.ts +0 -322
  324. package/src/routes/shared.ts +0 -247
  325. package/src/routes/ui.ts +0 -152
  326. package/src/server.ts +0 -195
  327. package/src/skills.ts +0 -271
  328. package/src/storage/file.ts +0 -123
  329. package/src/storage/memory.ts +0 -44
  330. package/src/timeout.ts +0 -84
  331. package/src/tool-safety.ts +0 -15
  332. package/src/types.ts +0 -523
  333. package/src/ui.ts +0 -744
  334. package/src/validate.ts +0 -387
  335. package/src/version.ts +0 -7
@@ -1,302 +0,0 @@
1
- import {
2
- remoteMcp,
3
- type RemoteMcpAuth,
4
- } from "../connectors/remote-mcp.js";
5
- import type {
6
- Connector,
7
- ConnectorCallAdmissionPolicy,
8
- ToolDef,
9
- } from "../types.js";
10
-
11
- /** Which of Linear's two hosted MCP endpoints this connection is bound to. */
12
- export type LinearAccess = "read-write" | "read-only";
13
-
14
- /**
15
- * Linear publishes two hosted endpoints. `read-only` is not a client-side
16
- * filter: it advertises the `read` scope alone, so the token minted for it
17
- * cannot reach Linear's write APIs at all. The deprecated `/sse` transport is
18
- * deliberately absent — it now answers 404.
19
- */
20
- export const LINEAR_MCP_ENDPOINTS: Readonly<Record<LinearAccess, string>> = {
21
- "read-write": "https://mcp.linear.app/mcp",
22
- "read-only": "https://mcp.linear.app/mcp/readonly",
23
- };
24
-
25
- export interface LinearOptions {
26
- /**
27
- * Human-readable display name; defaults to "Linear", or
28
- * "Linear (read-only)" when `access` is `"read-only"`.
29
- */
30
- title?: string;
31
- /** Which workspace this is and what decisions it answers. */
32
- purpose: string;
33
- /**
34
- * Endpoint selection. Defaults to `"read-write"`. `"read-only"` binds the
35
- * connection to Linear's read-only endpoint, whose token is scope-limited
36
- * downstream — a stronger guarantee than any annotation Connecta applies.
37
- */
38
- access?: LinearAccess;
39
- /** OAuth by default; static headers support a Linear personal API key. */
40
- auth?: RemoteMcpAuth;
41
- /** Workspace-specific conventions appended to the maintained provider guide. */
42
- instructions?: string;
43
- /** Connector-specific inline result limit; omit to inherit the deployment. */
44
- maxResultBytes?: number;
45
- /**
46
- * Optional per-runtime call-admission policy. Deliberately not defaulted:
47
- * Linear documents no MCP-specific limit, and the underlying API limit is
48
- * per user per hour, varies by credential type, and is raised dynamically
49
- * for workspace-level OAuth apps. A hardcoded per-runtime ceiling would
50
- * either throttle a healthy deployment or fail to protect a busy one, so
51
- * the number stays with the operator who knows the workspace.
52
- */
53
- callAdmission?: ConnectorCallAdmissionPolicy;
54
- }
55
-
56
- /**
57
- * Tools whose contract is observational rather than mutating.
58
- *
59
- * Linear's hosted catalog is not a fixed set — it varies by workspace plan and
60
- * enabled features (customer requests, releases, and code review are gated),
61
- * so this list is a superset of what any one workspace lists. A name here that
62
- * the workspace never returns costs nothing; a real read missing from it merely
63
- * fails closed. Only a write mistakenly listed here would be a safety bug,
64
- * which is why ambiguous helpers stay out.
65
- */
66
- const READ_ONLY_TOOLS = new Set([
67
- // Issues
68
- "list_issues",
69
- "get_issue",
70
- "list_issue_statuses",
71
- "get_issue_status",
72
- "list_issue_labels",
73
- // Projects
74
- "list_projects",
75
- "get_project",
76
- "list_project_labels",
77
- // Milestones
78
- "list_milestones",
79
- "get_milestone",
80
- // Initiatives
81
- "list_initiatives",
82
- "get_initiative",
83
- "list_initiative_labels",
84
- // Cycles
85
- "list_cycles",
86
- // Comments
87
- "list_comments",
88
- // Documents
89
- "list_documents",
90
- "get_document",
91
- // Teams and users
92
- "list_teams",
93
- "get_team",
94
- "list_users",
95
- "get_user",
96
- // Status updates
97
- "get_status_updates",
98
- // Releases
99
- "list_release_pipelines",
100
- "list_releases",
101
- "get_release",
102
- "list_release_notes",
103
- "get_release_note",
104
- // Code review
105
- "list_diffs",
106
- "get_diff",
107
- "get_diff_threads",
108
- // Attachments
109
- "get_attachment",
110
- // Agent skills
111
- "list_agent_skills",
112
- "get_agent_skill",
113
- // Documentation search
114
- "search_documentation",
115
- // Customer requests (plan-gated)
116
- "list_customers",
117
- // Markdown helper. It reads images out of content it is handed and touches
118
- // no workspace state; the hosted server ships it annotated `readOnlyHint:
119
- // true, idempotentHint: true`, and a fill-in classification agrees rather
120
- // than argues.
121
- "extract_images",
122
- ]);
123
-
124
- /**
125
- * The maintained write catalog. `"destructive"` tools modify or remove state
126
- * that already exists; `"additive"` ones only bring something new into being.
127
- * Both leave the read-only path — the distinction only decides whether the
128
- * connection asserts `destructiveHint`, which shapes the host's approval copy.
129
- *
130
- * Linear's `save_*` tools are upserts: passing an existing record's id updates
131
- * it in place. An upsert can therefore overwrite, so every `save_*` is
132
- * destructive even though some calls only create. The `create_*_label` tools
133
- * are the genuine creates.
134
- */
135
- const WRITE_TOOLS: ReadonlyMap<string, "additive" | "destructive"> = new Map([
136
- // Issues
137
- ["save_issue", "destructive"],
138
- ["create_issue_label", "additive"],
139
- // Projects
140
- ["save_project", "destructive"],
141
- // Milestones
142
- ["save_milestone", "destructive"],
143
- // Initiatives
144
- ["save_initiative", "destructive"],
145
- ["create_initiative_label", "additive"],
146
- // Comments
147
- ["save_comment", "destructive"],
148
- ["delete_comment", "destructive"],
149
- // Documents
150
- ["save_document", "destructive"],
151
- // Status updates
152
- ["save_status_update", "destructive"],
153
- ["delete_status_update", "destructive"],
154
- // Releases
155
- ["save_release", "destructive"],
156
- ["save_release_note", "destructive"],
157
- // Code review
158
- ["save_diff_comment", "destructive"],
159
- ["resolve_diff_thread", "destructive"],
160
- ["delete_diff_comment", "destructive"],
161
- ["submit_diff_review", "destructive"],
162
- ["merge_diff", "destructive"],
163
- // Attachments
164
- ["prepare_attachment_upload", "additive"],
165
- ["create_attachment_from_upload", "additive"],
166
- ["create_attachment", "additive"],
167
- ["delete_attachment", "destructive"],
168
- // Customer requests (plan-gated)
169
- ["save_customer", "destructive"],
170
- ["delete_customer", "destructive"],
171
- ["save_customer_need", "destructive"],
172
- ["delete_customer_need", "destructive"],
173
- ]);
174
-
175
- /**
176
- * Fill in downstream silence; keep reviewed destructive tools fail-closed.
177
- *
178
- * Silence is what a vetted classification is for, and an explicit downstream
179
- * annotation otherwise wins in both directions. `destructiveHint: true` or
180
- * `readOnlyHint: false` on an allowlisted read name is the downstream telling
181
- * us this release's allowlist is stale; `readOnlyHint: true` on a name no
182
- * release has classified says the same thing from the other side. The single
183
- * place a vetted verdict still overrides the downstream is a name this release
184
- * reviewed and filed destructive: there connecta knows what the tool does, and
185
- * a claim to the contrary is a downstream bug rather than news
186
- * ([#310](https://github.com/zackbart/connecta/issues/310),
187
- * [#315](https://github.com/zackbart/connecta/issues/315)).
188
- */
189
- function vettedSafety(definition: ToolDef): ToolDef {
190
- const downstream = definition.annotations ?? {};
191
- if (READ_ONLY_TOOLS.has(definition.name)) {
192
- if (
193
- downstream.destructiveHint === true ||
194
- downstream.readOnlyHint === false
195
- ) {
196
- return definition;
197
- }
198
- return {
199
- ...definition,
200
- annotations: {
201
- ...downstream,
202
- readOnlyHint: true,
203
- destructiveHint: downstream.destructiveHint ?? false,
204
- },
205
- };
206
- }
207
- if (WRITE_TOOLS.get(definition.name) === "destructive") {
208
- return {
209
- ...definition,
210
- annotations: {
211
- ...downstream,
212
- readOnlyHint: false,
213
- destructiveHint: true,
214
- },
215
- };
216
- }
217
- // Maintained additive creates and tools this release has never seen land
218
- // here alike. Fill-in only: a silent tool is not read-only, so drift still
219
- // fails closed onto `call_destructive_tool`, and neither population gets a
220
- // `destructiveHint` it has not earned. A tool that arrives explicitly
221
- // read-only keeps that annotation — on a name no release has reviewed, the
222
- // downstream's own word is the only evidence there is, and rewriting it
223
- // would be an overrule rather than a fill-in.
224
- return {
225
- ...definition,
226
- annotations: {
227
- ...downstream,
228
- readOnlyHint: downstream.readOnlyHint ?? false,
229
- },
230
- };
231
- }
232
-
233
- function usageGuide(
234
- purpose: string,
235
- access: LinearAccess,
236
- instructions: string | undefined,
237
- ): string {
238
- const accountInstructions = instructions?.trim();
239
- // Leads the guide because discovery summarizes a connector by its first
240
- // content line: whether this connection can write at all is the one thing an
241
- // agent must know before it opens the guide, and `search_tools` shows the
242
- // summary without the description.
243
- const accessNote =
244
- access === "read-only"
245
- ? "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."
246
- : "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.";
247
- return `# Linear usage
248
-
249
- ${accessNote}
250
-
251
- Workspace purpose: ${purpose}
252
-
253
- - 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.
254
- - 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.
255
- - \`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.
256
- - Labels are the exception to that naming: \`create_issue_label\` and \`create_initiative_label\` only ever create.
257
- - 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.
258
- - 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.
259
- - 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.
260
- - 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.
261
- - 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.
262
- ${
263
- accountInstructions
264
- ? `\n## Workspace instructions\n\n${accountInstructions}\n`
265
- : ""
266
- }`;
267
- }
268
-
269
- /** A maintained Linear hosted-MCP connection. */
270
- export function linear(id: string, options: LinearOptions): Connector {
271
- const purpose = options.purpose.trim();
272
- if (!purpose) {
273
- throw new Error("linear() requires a non-empty workspace purpose.");
274
- }
275
- const access = options.access ?? "read-write";
276
- const connector = remoteMcp(id, {
277
- url: LINEAR_MCP_ENDPOINTS[access],
278
- // The title is what browse-time discovery renders; a read-only connection
279
- // says so there rather than only in a description the caller may not see.
280
- title:
281
- options.title ?? (access === "read-only" ? "Linear (read-only)" : "Linear"),
282
- description:
283
- access === "read-only"
284
- ? `Linear issue tracking and project planning (read-only) — ${purpose}`
285
- : `Linear issue tracking and project planning — ${purpose}`,
286
- auth: options.auth ?? { type: "oauth" },
287
- requireHttps: true,
288
- usageGuide: usageGuide(purpose, access, options.instructions),
289
- ...(options.callAdmission !== undefined
290
- ? { callAdmission: options.callAdmission }
291
- : {}),
292
- ...(options.maxResultBytes !== undefined
293
- ? { maxResultBytes: options.maxResultBytes }
294
- : {}),
295
- });
296
- return {
297
- ...connector,
298
- async listTools(ctx) {
299
- return (await connector.listTools(ctx)).map(vettedSafety);
300
- },
301
- };
302
- }
@@ -1,229 +0,0 @@
1
- import {
2
- remoteMcp,
3
- type RemoteMcpAuth,
4
- } from "../connectors/remote-mcp.js";
5
- import type {
6
- Connector,
7
- ConnectorCallAdmissionPolicy,
8
- ToolDef,
9
- } from "../types.js";
10
-
11
- export type MixpanelRegion = "us" | "eu" | "in";
12
-
13
- export const MIXPANEL_MCP_ENDPOINTS: Readonly<
14
- Record<MixpanelRegion, string>
15
- > = {
16
- us: "https://mcp.mixpanel.com/mcp",
17
- eu: "https://mcp-eu.mixpanel.com/mcp",
18
- in: "https://mcp-in.mixpanel.com/mcp",
19
- };
20
-
21
- export interface MixpanelOptions {
22
- /** Human-readable display name; defaults to "Mixpanel". */
23
- title?: string;
24
- /** Who should use this account and for what decisions. */
25
- purpose: string;
26
- /** Mixpanel data residency region. Defaults to "us". */
27
- region?: MixpanelRegion;
28
- /** OAuth by default; static headers support Mixpanel service accounts. */
29
- auth?: RemoteMcpAuth;
30
- /** Account-specific conventions appended to the maintained provider guide. */
31
- instructions?: string;
32
- /** Connector-specific inline result limit; omit to inherit the deployment. */
33
- maxResultBytes?: number;
34
- }
35
-
36
- // Budget-only: a rejection computes its own retry-after from the window, and
37
- // declaring `retryAfterMs` here would be a queue setting without a queue —
38
- // which the admission controller refuses at construction.
39
- const MIXPANEL_ADMISSION: ConnectorCallAdmissionPolicy = {
40
- rules: [
41
- {
42
- budget: {
43
- kind: "rolling-window",
44
- maxCalls: 600,
45
- windowMs: 3_600_000,
46
- },
47
- },
48
- ],
49
- };
50
-
51
- /** Tools whose official contract is observational rather than mutating. */
52
- const READ_ONLY_TOOLS = new Set([
53
- "Run-Query",
54
- "Get-Query-Schema",
55
- "Get-Report",
56
- "Display-Query",
57
- "List-Dashboards",
58
- "Get-Dashboard",
59
- "Get-Business-Context",
60
- "Get-Projects",
61
- "List-Organizations",
62
- "Get-Events",
63
- "List-Properties",
64
- "Get-Property-Values",
65
- "Search-Entities",
66
- "Get-Issues",
67
- "Get-Lexicon-URL",
68
- "Find-Duplicate-Groups",
69
- "Get-Custom-Property",
70
- "Get-Cohort",
71
- "List-Cohorts",
72
- "Describe-Cohort-Schema",
73
- "Get-Lookup-Table",
74
- "Get-Metric",
75
- "List-Metrics",
76
- "Get-User-Replays-Data",
77
- "List-Experiments",
78
- "Get-Experiment",
79
- "Get-Experiment-Setup-Guidance",
80
- "Get-Experiment-Results-Interpretation-Guidance",
81
- "Explain-Experiment-Health-Check",
82
- "Run-Experiment-Pre-Launch-Checks",
83
- "Search-Prior-Experiments",
84
- "List-Feature-Flags",
85
- "Get-Feature-Flag",
86
- "Get-Feature-Flag-Setup-Guidance",
87
- "Get-Feature-Flag-Lifecycle-Guidance",
88
- ]);
89
-
90
- /**
91
- * The maintained write catalog. `"destructive"` tools modify or remove state
92
- * that already exists; `"additive"` ones only bring something new into being.
93
- * Both leave the read-only path — the distinction only decides whether the
94
- * connection asserts `destructiveHint`, which shapes the host's approval copy.
95
- */
96
- const WRITE_TOOLS: ReadonlyMap<string, "additive" | "destructive"> = new Map([
97
- ["Create-Dashboard", "additive"],
98
- ["Update-Dashboard", "destructive"],
99
- ["Duplicate-Dashboard", "additive"],
100
- ["Delete-Dashboard", "destructive"],
101
- ["Edit-Event", "destructive"],
102
- ["Edit-Property", "destructive"],
103
- ["Bulk-Edit-Events", "destructive"],
104
- ["Bulk-Edit-Properties", "destructive"],
105
- ["Create-Tag", "additive"],
106
- ["Rename-Tag", "destructive"],
107
- ["Delete-Tag", "destructive"],
108
- ["Dismiss-Issues", "destructive"],
109
- ["Update-Business-Context", "destructive"],
110
- ["Dismiss-Duplicate-Group", "destructive"],
111
- ["Merge-Group", "destructive"],
112
- ["Create-Custom-Property", "additive"],
113
- ["Update-Custom-Property", "destructive"],
114
- ["Create-Cohort", "additive"],
115
- ["Update-Cohort", "destructive"],
116
- ["Delete-Cohort", "destructive"],
117
- ["Create-Lookup-Table", "additive"],
118
- ["Update-Lookup-Table", "destructive"],
119
- ["Create-Metric", "additive"],
120
- ["Update-Metric", "destructive"],
121
- ["Create-Experiment", "additive"],
122
- ["Update-Experiment", "destructive"],
123
- ["Create-Feature-Flag", "additive"],
124
- ["Update-Feature-Flag", "destructive"],
125
- ]);
126
-
127
- /**
128
- * Fill in downstream silence; keep reviewed destructive tools fail-closed.
129
- *
130
- * Silence is what a vetted classification is for, and an explicit downstream
131
- * annotation otherwise wins in both directions. `destructiveHint: true` or
132
- * `readOnlyHint: false` on an allowlisted read name is the downstream telling
133
- * us this release's allowlist is stale; `readOnlyHint: true` on a name no
134
- * release has classified says the same thing from the other side. The single
135
- * place a vetted verdict still overrides the downstream is a name this release
136
- * reviewed and filed destructive: there connecta knows what the tool does, and
137
- * a claim to the contrary is a downstream bug rather than news
138
- * ([#310](https://github.com/zackbart/connecta/issues/310),
139
- * [#315](https://github.com/zackbart/connecta/issues/315)).
140
- */
141
- function vettedSafety(definition: ToolDef): ToolDef {
142
- const downstream = definition.annotations ?? {};
143
- if (READ_ONLY_TOOLS.has(definition.name)) {
144
- if (
145
- downstream.destructiveHint === true ||
146
- downstream.readOnlyHint === false
147
- ) {
148
- return definition;
149
- }
150
- return {
151
- ...definition,
152
- annotations: {
153
- ...downstream,
154
- readOnlyHint: true,
155
- destructiveHint: downstream.destructiveHint ?? false,
156
- },
157
- };
158
- }
159
- if (WRITE_TOOLS.get(definition.name) === "destructive") {
160
- return {
161
- ...definition,
162
- annotations: {
163
- ...downstream,
164
- readOnlyHint: false,
165
- destructiveHint: true,
166
- },
167
- };
168
- }
169
- // Maintained additive creates and tools this release has never seen land
170
- // here alike. Fill-in only: a silent tool is not read-only, so drift still
171
- // fails closed onto `call_destructive_tool`, and neither population gets a
172
- // `destructiveHint` it has not earned. A tool that arrives explicitly
173
- // read-only keeps that annotation — on a name no release has reviewed, the
174
- // downstream's own word is the only evidence there is, and rewriting it
175
- // would be an overrule rather than a fill-in.
176
- return {
177
- ...definition,
178
- annotations: {
179
- ...downstream,
180
- readOnlyHint: downstream.readOnlyHint ?? false,
181
- },
182
- };
183
- }
184
-
185
- function usageGuide(purpose: string, instructions: string | undefined): string {
186
- const accountInstructions = instructions?.trim();
187
- return `# Mixpanel usage
188
-
189
- Account purpose: ${purpose}
190
-
191
- - Start with \`Get-Projects\`, then use \`Get-Business-Context\` for the selected project before interpreting its events or metrics.
192
- - Discover names with \`Get-Events\`, \`List-Properties\`, and \`Get-Property-Values\`; do not guess event or property spelling.
193
- - For a new analysis, fetch \`Get-Query-Schema\` before \`Run-Query\`. Reduce query results inside \`execute_code\` before returning them.
194
- - Use \`Get-Report\` when the request names an existing saved report. Use \`Run-Query\` for a new question.
195
- - Mixpanel limits MCP traffic to 600 requests per user per hour. Reuse discovery results within a run and avoid speculative fan-out.
196
- - 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.
197
- ${
198
- accountInstructions
199
- ? `\n## Account instructions\n\n${accountInstructions}\n`
200
- : ""
201
- }`;
202
- }
203
-
204
- /** A maintained Mixpanel hosted-MCP connection. */
205
- export function mixpanel(id: string, options: MixpanelOptions): Connector {
206
- const purpose = options.purpose.trim();
207
- if (!purpose) {
208
- throw new Error("mixpanel() requires a non-empty account purpose.");
209
- }
210
- const region = options.region ?? "us";
211
- const connector = remoteMcp(id, {
212
- url: MIXPANEL_MCP_ENDPOINTS[region],
213
- title: options.title ?? "Mixpanel",
214
- description: `Mixpanel product analytics — ${purpose}`,
215
- auth: options.auth ?? { type: "oauth" },
216
- requireHttps: true,
217
- callAdmission: MIXPANEL_ADMISSION,
218
- usageGuide: usageGuide(purpose, options.instructions),
219
- ...(options.maxResultBytes !== undefined
220
- ? { maxResultBytes: options.maxResultBytes }
221
- : {}),
222
- });
223
- return {
224
- ...connector,
225
- async listTools(ctx) {
226
- return (await connector.listTools(ctx)).map(vettedSafety);
227
- },
228
- };
229
- }