@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
@@ -111,6 +111,11 @@ export const connecta = createConnecta({
111
111
  All three are ordinary `Connector` instances by the time the registry sees
112
112
  them. Nothing in the list is privileged by how it was authored.
113
113
 
114
+ What a maintained connection owes an agent is written down rather than
115
+ inherited from whoever wrote it last:
116
+ [provider conventions](./provider-conventions.md), one set for hand-written
117
+ HTTP surfaces and one for hosted-MCP proxies.
118
+
114
119
  Maintained provider guides:
115
120
 
116
121
  - [Cloudflare](./cloudflare.md)
@@ -119,6 +124,90 @@ Maintained provider guides:
119
124
  - [Notion](./notion.md)
120
125
  - [Stripe](./stripe.md)
121
126
 
127
+ ## The `api()` construction contract
128
+
129
+ `api()` is the path every custom integration takes, and whatever it accepts is
130
+ what an agent eventually reads. Three things are refused at construction rather
131
+ than discovered in production
132
+ ([#340](https://github.com/zackbart/connecta/issues/340)):
133
+
134
+ - **A tool with no description.** Discovery has nothing else to route on, and a
135
+ guess costs a call.
136
+ - **A tool with no explicit boolean `annotations.readOnlyHint`.** `true`
137
+ declares a read and admits the tool to `call_tool` and `execute_code`;
138
+ `false` declares work that crosses `call_destructive_tool`, where the host
139
+ can ask a human. Connecta never infers the classification from a tool name,
140
+ description, schema, HTTP method, or the other annotations — an unclassified
141
+ tool is a bug in the deployment, not a puzzle to solve.
142
+ - **An `inputSchema` the validator cannot compile.** Declaring one is optional;
143
+ declaring one that cannot be enforced is not. A schema that only reveals
144
+ itself on first use — an unresolvable `$ref`, say — fails that call as
145
+ non-retryable `invalid_args` rather than forwarding raw arguments to the
146
+ handler. `validateArgs: false` still opts out of enforcement for deployments
147
+ that want loose coercion; it does not opt out of the schema being real.
148
+
149
+ None of this reaches a proxied catalog: hosted-MCP tools arrive as their
150
+ downstream wrote them, and an unannotated or contradictory one stays
151
+ fail-closed onto `call_destructive_tool`. The contract binds the surfaces we
152
+ write, not the catalogs we relay.
153
+
154
+ ## The guarded fetch transport
155
+
156
+ Every hand-written HTTP surface re-derives the same safety machinery, and two
157
+ of them had already derived it slightly differently. `src/connectors/guarded-fetch.ts`
158
+ is that machinery extracted once ([#341](https://github.com/zackbart/connecta/issues/341)):
159
+ one `guardedFetch({ provider, baseUrl, headers, maxResponseBytes, authenticate })`
160
+ factory returning the transport a connector sends every request through.
161
+
162
+ What it owns is mechanical and provider-independent:
163
+
164
+ - **Confinement.** A request path is provider-relative, carries no query or
165
+ fragment, and is re-checked against the base origin and path prefix *after*
166
+ `new URL` normalization — because normalization is how a path escapes a
167
+ prefix, not something to trust before it.
168
+ - **Construction.** Query parameters are encoded rather than concatenated, a
169
+ JSON body is serialized with the `Content-Type` to match, and a pre-framed
170
+ body gets none, so `fetch` still picks the multipart boundary.
171
+ - **Credential forwarding.** `authenticate` is called once per request and its
172
+ headers are applied last; a request header wearing one of their names is
173
+ refused rather than allowed to shadow it. A 3xx is refused outright — a
174
+ redirect is an instruction to re-send the credential to whatever origin the
175
+ `Location` names, and a confinement a redirect can undo was never one.
176
+ - **Bounded reads.** `maxResponseBytes` is required, not defaulted: what counts
177
+ as an absurd response is a fact about the API, not about HTTP. A declared
178
+ `Content-Length` past the ceiling fails before a byte is read, and a
179
+ streaming body is abandoned at the ceiling rather than buffered past it.
180
+ - **Normalization.** An unreachable provider becomes a retryable `unavailable`
181
+ instead of whatever `TypeError` the runtime threw, and `ctx.signal` rides
182
+ every request.
183
+
184
+ What it deliberately does not own is meaning. It never reads a status code and
185
+ never invents an authentication scheme: the provider's `authenticate` callback
186
+ supplies the headers, and the provider's mapper turns one `GuardedResponse`
187
+ into a result or a typed failure. That split is not fastidiousness. Notion's
188
+ 403 means a capability the integration was never granted — re-authorizing
189
+ cannot fix it — while Cloudflare's means a token scope, and the two want
190
+ opposite next moves. A helper that guessed would be wrong for one of them.
191
+
192
+ Cloudflare and Notion both run on it. Their existing suites carried over
193
+ unchanged, which proves the migration kept the behavior those suites cover —
194
+ not that nothing changed. Three things did, and the changelog names them: a
195
+ 3xx is refused where both providers used to follow it, both now fail past
196
+ their byte ceiling, and `cloudflare()`'s `baseUrl` is validated at
197
+ construction. Each suite gained one test for the ceiling, because the one
198
+ guard the helper was written to add is the one a provider's own mapper can
199
+ most easily disarm: a bare `catch` around `response.json()` swallows the
200
+ transport's refusal along with a parse error, and turns a response nobody was
201
+ allowed to read into an empty success. A mapper re-throws
202
+ `ConnectorCallError` and swallows only what it recognizes.
203
+
204
+ It is **not exported this release**: the two migrations proved the shape
205
+ preserves behavior for connectors that already had this machinery, not that it
206
+ is the right shape for an author starting from nothing, and an unexported
207
+ symbol costs nothing to reshape while a published one is a promise.
208
+ The provider audit ([#342](https://github.com/zackbart/connecta/issues/342))
209
+ supplies the third caller that would settle it.
210
+
122
211
  ## MCP version skew
123
212
 
124
213
  Connecta deliberately sits between protocol generations
@@ -11,6 +11,7 @@ import { linear } from "@zackbart/connecta/providers/linear";
11
11
  const tracker = linear("product_tracker", {
12
12
  title: "Product issue tracking",
13
13
  purpose: "Issue and project planning for the platform team",
14
+ access: "read-write",
14
15
  instructions: "File bugs into the Platform team unless the request names another.",
15
16
  });
16
17
  ```
@@ -23,13 +24,21 @@ cannot change the connector's safety classification.
23
24
 
24
25
  ## Access modes
25
26
 
26
- Linear publishes two hosted endpoints, and `access` selects between them:
27
+ Linear publishes two hosted endpoints, and `access` selects between them. It is
28
+ **required**, with no default:
27
29
 
28
30
  | `access` | Endpoint | OAuth scopes |
29
31
  | --- | --- | --- |
30
- | `"read-write"` (default) | `https://mcp.linear.app/mcp` | `read`, `write` |
32
+ | `"read-write"` | `https://mcp.linear.app/mcp` | `read`, `write` |
31
33
  | `"read-only"` | `https://mcp.linear.app/mcp/readonly` | `read` |
32
34
 
35
+ There is no safe default to pick. Defaulting to `"read-write"` hands a
36
+ deployment write access it never asked for; defaulting to `"read-only"` turns a
37
+ deployment that does write into one whose every write fails at Linear — at
38
+ runtime, where no agent can repair it. So the operator declares which one this
39
+ is, and a deployment that forgot fails at construction with a message naming
40
+ both options.
41
+
33
42
  Read-only is not a client-side filter. The endpoint advertises the `read` scope
34
43
  alone, so the token minted for it cannot reach Linear's write APIs — a stronger
35
44
  guarantee than any annotation Connecta applies. A deployment that only reports
@@ -63,6 +72,7 @@ also accepts a bearer token or a personal API key passed directly in the
63
72
  ```ts
64
73
  linear("automation_tracker", {
65
74
  purpose: "Headless release reporting",
75
+ access: "read-only",
66
76
  auth: {
67
77
  type: "headers",
68
78
  headers: { Authorization: env.LINEAR_API_KEY },
@@ -130,6 +140,7 @@ one. An operator who knows their workspace can supply one explicitly:
130
140
  ```ts
131
141
  linear("product_tracker", {
132
142
  purpose: "Issue and project planning for the platform team",
143
+ access: "read-write",
133
144
  callAdmission: {
134
145
  rules: [
135
146
  { budget: { kind: "rolling-window", maxCalls: 1_000, windowMs: 3_600_000 } },
@@ -141,3 +152,10 @@ linear("product_tracker", {
141
152
  A budget-only rule needs no queue. If you add `maxConcurrency` you are asking
142
153
  for a queue, and the admission controller then requires the rest of the queue
143
154
  settings at construction.
155
+
156
+ ## Conventions
157
+
158
+ This connection is audited against
159
+ [the provider conventions](./provider-conventions.md). Its verdict per
160
+ convention, including every recorded exception, is the Linear section of
161
+ [the provider audit](./provider-audit.md).
@@ -375,8 +375,8 @@ buy a guarantee the protocol already gives away.
375
375
  source carries the `srcdoc` and sandbox attributes and contains no
376
376
  message-forwarding path from the inner frame to the host.
377
377
  - `U1`–`U11` fold into `code-mode.md`, the `execute_code` description documents
378
- `connecta.ui`, and the test-map row lands in
379
- [`operations.md`](./operations.md) with that guide.
378
+ `connecta.ui`, and the suite takes its row in the
379
+ [test map](./operations.md#the-test-map).
380
380
  - `npm run check` passes.
381
381
 
382
382
  The implementation issue (#277) carries these as acceptance criteria.
@@ -229,7 +229,13 @@ results explain that no single tool covered every term and recommend splitting
229
229
  distinct intents. A true negative says that no matching capability is
230
230
  configured and recommends refining, connector-scoping, or browsing; when a
231
231
  connector catalog was unavailable, the response includes
232
- `unavailableConnectorCount` instead of making that stronger claim. A search
232
+ `unavailableConnectorCount` instead of making that stronger claim. A no-match
233
+ query whose terms name a configured connector's `id` or `title` never makes it
234
+ either: connector identity is not in the lexical index — indexing it would move
235
+ ranking for every query that already matches tools — so instead the guidance on
236
+ an unscoped miss names up to three such connectors by ID and sends the caller
237
+ to a scoped browse. Identity affects that one sentence and nothing else: no
238
+ ranking, no result, and no new field. A search
233
239
  explicitly scoped to that unavailable connector also receives `catalogError` —
234
240
  the bounded classified failure (`code`, `message`, `retryable`, and any
235
241
  `retryAfterMs`) so the caller can tell a transient outage from one a deployment
@@ -2,9 +2,9 @@
2
2
 
3
3
  Import `mixpanel()` independently from
4
4
  `@zackbart/connecta/providers/mixpanel`. It wraps Mixpanel's hosted MCP server
5
- with regional endpoint selection, OAuth by default, a provider-rate admission
6
- budget, a task-oriented usage guide, and a vetted safety classification. It
7
- adds no provider dependency and is not reachable from Connecta's root entry.
5
+ with regional endpoint selection, OAuth by default, a task-oriented usage
6
+ guide, and a vetted safety classification. It adds no provider dependency and
7
+ is not reachable from Connecta's root entry.
8
8
 
9
9
  ```ts
10
10
  import { mixpanel } from "@zackbart/connecta/providers/mixpanel";
@@ -25,6 +25,12 @@ connector's safety classification.
25
25
 
26
26
  `region` accepts `"us"` (the default), `"eu"`, or `"in"` and selects the
27
27
  corresponding [official hosted endpoint](https://docs.mixpanel.com/docs/mcp#mcp-server-urls).
28
+ A project lives in exactly one residency, so the region also decides what this
29
+ connection can see at all: a question pointed at the wrong one comes back empty
30
+ rather than wrong, which reads as the project having no data. That makes it a
31
+ routing fact, so it rides the default `title` (`Mixpanel (us)`, `Mixpanel
32
+ (eu)`, `Mixpanel (in)`) and opens the usage guide — `search_tools` renders a
33
+ connector's title and guide summary and never its description.
28
34
  OAuth is the recommended default and keeps each connector instance's flow and
29
35
  tokens in its connector-scoped storage. Mixpanel service accounts are also
30
36
  supported with an explicit header override:
@@ -68,9 +74,36 @@ approval copy the host shows a human.
68
74
  Experiments and Feature Flags — 15 of the 63 classified tools — are Mixpanel
69
75
  beta surfaces. Expect their names and schemas to move faster than the rest.
70
76
 
71
- The connection also declares a per-runtime call-admission budget matching
72
- Mixpanel's documented 600 requests per hour — a best-effort approximation of
73
- the per-user limit, not an enforcement of it. Each runtime keeps its own
74
- counter, so N Worker isolates or Node processes serving one deployment can each
75
- admit up to 600. Discovery traffic is outside connector call admission and
76
- still needs restrained use.
77
+ ## Rate limits
78
+
79
+ Mixpanel meters its MCP server **per user per hour**, shared with everything
80
+ else that credential does. Connecta's counter is per runtime, not per user, and
81
+ the two cannot be reconciled in either direction: one runtime serving several
82
+ users under-counts, and several Worker isolates or Node processes sharing one
83
+ credential each admit a full budget. A hardcoded ceiling would therefore either
84
+ throttle a healthy deployment or fail to protect a busy one, so this connection
85
+ declares **no call-admission budget by default**. An operator who knows the
86
+ account can supply one explicitly:
87
+
88
+ ```ts
89
+ mixpanel("product_analytics", {
90
+ purpose: "Product and growth decisions for the production app",
91
+ callAdmission: {
92
+ rules: [
93
+ { budget: { kind: "rolling-window", maxCalls: 300, windowMs: 3_600_000 } },
94
+ ],
95
+ },
96
+ });
97
+ ```
98
+
99
+ A budget-only rule needs no queue. If you add `maxConcurrency` you are asking
100
+ for a queue, and the admission controller then requires the rest of the queue
101
+ settings at construction. Discovery traffic is outside connector call admission
102
+ either way and still needs restrained use.
103
+
104
+ ## Conventions
105
+
106
+ This connection is audited against
107
+ [the provider conventions](./provider-conventions.md). Its verdict per
108
+ convention, including every recorded exception, is the Mixpanel section of
109
+ [the provider audit](./provider-audit.md).
@@ -166,7 +166,7 @@ should do next, and two of Notion's are easy to mistranslate.
166
166
  | 400 (`validation_error`, `invalid_json`, `invalid_request`, `missing_version`, …) | `invalid_args` | every documented 400 is a malformed request |
167
167
  | 401 `unauthorized` | `auth_required` | the token is missing or invalid |
168
168
  | 403 `restricted_resource` | `connector_call_failed`, non-retryable | **not** `auth_required` |
169
- | 404 `object_not_found` | `connector_call_failed`, non-retryable | overloaded; see below |
169
+ | 404 `object_not_found` | `connector_call_failed`, non-retryable | overloaded — deliberately **not** `not_found`; see below |
170
170
  | 409 `conflict_error` | `unavailable`, retryable | Notion says to retry |
171
171
  | 429 `rate_limited` | `rate_limited` + `retryAfterMs` | `Retry-After` seconds → ms |
172
172
  | 529 `service_overload` | `unavailable` + `retryAfterMs` | back off like a 429 |
@@ -184,7 +184,12 @@ whose message says an operator must change it in Notion.
184
184
  object that does not exist and for one that exists but has not been shared with
185
185
  the integration, and it will not say which. The message says both, because
186
186
  treating it as deletion is exactly how an agent concludes a page is gone when
187
- it was simply never shared.
187
+ it was simply never shared. This is why the row above does not use `not_found`,
188
+ which exists precisely to say "it is not there": the qualifier on that code
189
+ ([H11](./provider-conventions.md#h11--errors-are-mapped-to-what-the-caller-does-next))
190
+ is that the provider must tell absence apart from a permission gap, and Notion
191
+ does not. A program that skipped this id as missing would be right about half
192
+ the time, which is the half that matters.
188
193
 
189
194
  ## Rate limiting
190
195
 
@@ -231,3 +236,19 @@ block updates or deletes, no page moves. Those are all real Notion endpoints
231
236
  and all deliberately absent: this is a deliberate tool surface, not a mirror of
232
237
  the API. Anything missing is reachable through a custom `api()` connector
233
238
  beside this one, which remains a first-class path.
239
+
240
+ There is also **no guarded raw-REST escape hatch** — no `notion_api_get`, no
241
+ `notion_api_mutate`. The convention that permits one
242
+ ([H14](./provider-conventions.md#h14--a-named-tool-must-beat-the-escape-hatch-and-the-escape-hatch-splits-by-safety))
243
+ also permits a small provider to have none, provided it says so, and Notion's
244
+ public API is finite and slow-moving enough that a named surface can cover it.
245
+ The usage guide says it too, because an agent that assumes a hatch exists
246
+ spends a search proving it does not: absent from the tool list means absent
247
+ from this connection, not hidden behind a generic call.
248
+
249
+ ## Conventions
250
+
251
+ This connection is audited against
252
+ [the provider conventions](./provider-conventions.md). Its verdict per
253
+ convention, including every recorded exception, is the Notion section of
254
+ [the provider audit](./provider-audit.md).