@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
@@ -18,11 +18,20 @@ export interface LinearOptions {
18
18
  /** Which workspace this is and what decisions it answers. */
19
19
  purpose: string;
20
20
  /**
21
- * Endpoint selection. Defaults to `"read-write"`. `"read-only"` binds the
22
- * connection to Linear's read-only endpoint, whose token is scope-limited
23
- * downstream a stronger guarantee than any annotation Connecta applies.
21
+ * Endpoint selection. Required, and deliberately undefaulted.
22
+ *
23
+ * `"read-only"` binds the connection to Linear's read-only endpoint, whose
24
+ * token is scope-limited downstream — a stronger guarantee than any
25
+ * annotation Connecta applies. `"read-write"` reaches the full API.
26
+ *
27
+ * Neither is a safe default. Defaulting to `"read-write"` hands a deployment
28
+ * write access it never asked for, and defaulting to `"read-only"` turns a
29
+ * deployment that does write into one whose every write fails at Linear —
30
+ * at runtime, where no agent can repair it. So the operator declares it, and
31
+ * a deployment that forgot fails here instead
32
+ * ([#342](https://github.com/zackbart/connecta/issues/342)).
24
33
  */
25
- access?: LinearAccess;
34
+ access: LinearAccess;
26
35
  /** OAuth by default; static headers support a Linear personal API key. */
27
36
  auth?: RemoteMcpAuth;
28
37
  /** Workspace-specific conventions appended to the maintained provider guide. */
@@ -39,6 +48,18 @@ export interface LinearOptions {
39
48
  */
40
49
  callAdmission?: ConnectorCallAdmissionPolicy;
41
50
  }
51
+ /**
52
+ * The manifest this release reviewed: both lists in one place, which is what
53
+ * makes the classification the connector applies and the drift check that runs
54
+ * beside it the same fact (P13). No schema digests yet — no release has read
55
+ * Linear's live schemas and written them down, and an invented digest would
56
+ * report a change that never happened. `npm run drift:check -- --record` reads
57
+ * them from a live workspace and prints the block to paste in
58
+ * ([#351](https://github.com/zackbart/connecta/issues/351)).
59
+ *
60
+ * Exported because the maintainer-run check compares against this manifest and
61
+ * *names* what moved, which the runtime check deliberately cannot.
62
+ */
63
+ export declare const LINEAR_VETTED_CATALOG: import("../catalog-drift.js").VettedCatalog;
42
64
  /** A maintained Linear hosted-MCP connection. */
43
65
  export declare function linear(id: string, options: LinearOptions): Connector;
44
- //# sourceMappingURL=linear.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import { remoteMcp, } from "../connectors/remote-mcp.js";
2
+ import { vettedCatalog, withVettedCatalog } from "../catalog-drift.js";
2
3
  /**
3
4
  * Linear publishes two hosted endpoints. `read-only` is not a client-side
4
5
  * filter: it advertises the `read` scope alone, so the token minted for it
@@ -127,60 +128,21 @@ const WRITE_TOOLS = new Map([
127
128
  ["delete_customer_need", "destructive"],
128
129
  ]);
129
130
  /**
130
- * Fill in downstream silence; keep reviewed destructive tools fail-closed.
131
+ * The manifest this release reviewed: both lists in one place, which is what
132
+ * makes the classification the connector applies and the drift check that runs
133
+ * beside it the same fact (P13). No schema digests yet — no release has read
134
+ * Linear's live schemas and written them down, and an invented digest would
135
+ * report a change that never happened. `npm run drift:check -- --record` reads
136
+ * them from a live workspace and prints the block to paste in
137
+ * ([#351](https://github.com/zackbart/connecta/issues/351)).
131
138
  *
132
- * Silence is what a vetted classification is for, and an explicit downstream
133
- * annotation otherwise wins in both directions. `destructiveHint: true` or
134
- * `readOnlyHint: false` on an allowlisted read name is the downstream telling
135
- * us this release's allowlist is stale; `readOnlyHint: true` on a name no
136
- * release has classified says the same thing from the other side. The single
137
- * place a vetted verdict still overrides the downstream is a name this release
138
- * reviewed and filed destructive: there connecta knows what the tool does, and
139
- * a claim to the contrary is a downstream bug rather than news
140
- * ([#310](https://github.com/zackbart/connecta/issues/310),
141
- * [#315](https://github.com/zackbart/connecta/issues/315)).
139
+ * Exported because the maintainer-run check compares against this manifest and
140
+ * *names* what moved, which the runtime check deliberately cannot.
142
141
  */
143
- function vettedSafety(definition) {
144
- const downstream = definition.annotations ?? {};
145
- if (READ_ONLY_TOOLS.has(definition.name)) {
146
- if (downstream.destructiveHint === true ||
147
- downstream.readOnlyHint === false) {
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
- }
142
+ export const LINEAR_VETTED_CATALOG = vettedCatalog({
143
+ reads: READ_ONLY_TOOLS,
144
+ writes: WRITE_TOOLS,
145
+ });
184
146
  function usageGuide(purpose, access, instructions) {
185
147
  const accountInstructions = instructions?.trim();
186
148
  // Leads the guide because discovery summarizes a connector by its first
@@ -215,7 +177,10 @@ export function linear(id, options) {
215
177
  if (!purpose) {
216
178
  throw new Error("linear() requires a non-empty workspace purpose.");
217
179
  }
218
- const access = options.access ?? "read-write";
180
+ const access = options.access;
181
+ if (access !== "read-write" && access !== "read-only") {
182
+ throw new Error(`linear("${id}") requires access "read-write" or "read-only".`);
183
+ }
219
184
  const connector = remoteMcp(id, {
220
185
  url: LINEAR_MCP_ENDPOINTS[access],
221
186
  // The title is what browse-time discovery renders; a read-only connection
@@ -226,7 +191,19 @@ export function linear(id, options) {
226
191
  : `Linear issue tracking and project planning — ${purpose}`,
227
192
  auth: options.auth ?? { type: "oauth" },
228
193
  requireHttps: true,
229
- usageGuide: usageGuide(purpose, access, options.instructions),
194
+ usageGuide: {
195
+ content: usageGuide(purpose, access, options.instructions),
196
+ // Explicit rather than derived. The derived summary would truncate the
197
+ // access note mid-sentence at 120 characters, and the one thing a
198
+ // browsing agent must not get wrong is whether this connection can write
199
+ // at all ([#342](https://github.com/zackbart/connecta/issues/342)).
200
+ summary: access === "read-only"
201
+ ? "Read-only: every write fails at Linear. Id resolution, upsert semantics, and cursor paging."
202
+ : "Read-write. Id resolution, `save_*` upsert semantics, plan-gated areas, and cursor paging.",
203
+ // Not `required`. Linear's own schemas describe each call correctly; the
204
+ // guide adds cross-tool sequence advice that is worth reading before a
205
+ // write, not worth loading before every read.
206
+ },
230
207
  ...(options.callAdmission !== undefined
231
208
  ? { callAdmission: options.callAdmission }
232
209
  : {}),
@@ -234,11 +211,5 @@ export function linear(id, options) {
234
211
  ? { maxResultBytes: options.maxResultBytes }
235
212
  : {}),
236
213
  });
237
- return {
238
- ...connector,
239
- async listTools(ctx) {
240
- return (await connector.listTools(ctx)).map(vettedSafety);
241
- },
242
- };
214
+ return withVettedCatalog(connector, LINEAR_VETTED_CATALOG);
243
215
  }
244
- //# sourceMappingURL=linear.js.map
@@ -1,13 +1,22 @@
1
1
  import { type RemoteMcpAuth } from "../connectors/remote-mcp.js";
2
- import type { Connector } from "../types.js";
2
+ import type { Connector, ConnectorCallAdmissionPolicy } from "../types.js";
3
3
  export type MixpanelRegion = "us" | "eu" | "in";
4
4
  export declare const MIXPANEL_MCP_ENDPOINTS: Readonly<Record<MixpanelRegion, string>>;
5
5
  export interface MixpanelOptions {
6
- /** Human-readable display name; defaults to "Mixpanel". */
6
+ /**
7
+ * Human-readable display name; defaults to "Mixpanel (<region>)". The region
8
+ * rides the title because a project lives in exactly one residency and
9
+ * discovery shows the title before anything else.
10
+ */
7
11
  title?: string;
8
12
  /** Who should use this account and for what decisions. */
9
13
  purpose: string;
10
- /** Mixpanel data residency region. Defaults to "us". */
14
+ /**
15
+ * Mixpanel data residency region. Defaults to `"us"`, which is where a
16
+ * project lives unless it was explicitly created in the EU or India
17
+ * residency — the other two are opt-in, so `"us"` is the honest default
18
+ * rather than a convenient one.
19
+ */
11
20
  region?: MixpanelRegion;
12
21
  /** OAuth by default; static headers support Mixpanel service accounts. */
13
22
  auth?: RemoteMcpAuth;
@@ -15,7 +24,29 @@ export interface MixpanelOptions {
15
24
  instructions?: string;
16
25
  /** Connector-specific inline result limit; omit to inherit the deployment. */
17
26
  maxResultBytes?: number;
27
+ /**
28
+ * Optional per-runtime call-admission policy. Deliberately not defaulted:
29
+ * Mixpanel meters its MCP server per user per hour, and a per-runtime
30
+ * counter cannot approximate a per-user quota — one runtime serving several
31
+ * users under-counts, and several runtimes sharing one user over-counts.
32
+ * A hardcoded ceiling would therefore either throttle a healthy deployment
33
+ * or fail to protect a busy one, so the number stays with the operator who
34
+ * knows the account.
35
+ */
36
+ callAdmission?: ConnectorCallAdmissionPolicy;
18
37
  }
38
+ /**
39
+ * The manifest this release reviewed: both lists in one place, which is what
40
+ * makes the classification the connector applies and the drift check that runs
41
+ * beside it the same fact (P13). No schema digests yet — no release has read
42
+ * Mixpanel's live schemas and written them down, and an invented digest would
43
+ * report a change that never happened. `npm run drift:check -- --record` reads
44
+ * them from a live project and prints the block to paste in
45
+ * ([#351](https://github.com/zackbart/connecta/issues/351)).
46
+ *
47
+ * Exported because the maintainer-run check compares against this manifest and
48
+ * *names* what moved, which the runtime check deliberately cannot.
49
+ */
50
+ export declare const MIXPANEL_VETTED_CATALOG: import("../catalog-drift.js").VettedCatalog;
19
51
  /** A maintained Mixpanel hosted-MCP connection. */
20
52
  export declare function mixpanel(id: string, options: MixpanelOptions): Connector;
21
- //# sourceMappingURL=mixpanel.d.ts.map
@@ -1,23 +1,10 @@
1
1
  import { remoteMcp, } from "../connectors/remote-mcp.js";
2
+ import { vettedCatalog, withVettedCatalog } from "../catalog-drift.js";
2
3
  export const MIXPANEL_MCP_ENDPOINTS = {
3
4
  us: "https://mcp.mixpanel.com/mcp",
4
5
  eu: "https://mcp-eu.mixpanel.com/mcp",
5
6
  in: "https://mcp-in.mixpanel.com/mcp",
6
7
  };
7
- // Budget-only: a rejection computes its own retry-after from the window, and
8
- // declaring `retryAfterMs` here would be a queue setting without a queue —
9
- // which the admission controller refuses at construction.
10
- const MIXPANEL_ADMISSION = {
11
- rules: [
12
- {
13
- budget: {
14
- kind: "rolling-window",
15
- maxCalls: 600,
16
- windowMs: 3_600_000,
17
- },
18
- },
19
- ],
20
- };
21
8
  /** Tools whose official contract is observational rather than mutating. */
22
9
  const READ_ONLY_TOOLS = new Set([
23
10
  "Run-Query",
@@ -93,71 +80,47 @@ const WRITE_TOOLS = new Map([
93
80
  ["Update-Feature-Flag", "destructive"],
94
81
  ]);
95
82
  /**
96
- * Fill in downstream silence; keep reviewed destructive tools fail-closed.
83
+ * The manifest this release reviewed: both lists in one place, which is what
84
+ * makes the classification the connector applies and the drift check that runs
85
+ * beside it the same fact (P13). No schema digests yet — no release has read
86
+ * Mixpanel's live schemas and written them down, and an invented digest would
87
+ * report a change that never happened. `npm run drift:check -- --record` reads
88
+ * them from a live project and prints the block to paste in
89
+ * ([#351](https://github.com/zackbart/connecta/issues/351)).
97
90
  *
98
- * Silence is what a vetted classification is for, and an explicit downstream
99
- * annotation otherwise wins in both directions. `destructiveHint: true` or
100
- * `readOnlyHint: false` on an allowlisted read name is the downstream telling
101
- * us this release's allowlist is stale; `readOnlyHint: true` on a name no
102
- * release has classified says the same thing from the other side. The single
103
- * place a vetted verdict still overrides the downstream is a name this release
104
- * reviewed and filed destructive: there connecta knows what the tool does, and
105
- * a claim to the contrary is a downstream bug rather than news
106
- * ([#310](https://github.com/zackbart/connecta/issues/310),
107
- * [#315](https://github.com/zackbart/connecta/issues/315)).
91
+ * Exported because the maintainer-run check compares against this manifest and
92
+ * *names* what moved, which the runtime check deliberately cannot.
108
93
  */
109
- function vettedSafety(definition) {
110
- const downstream = definition.annotations ?? {};
111
- if (READ_ONLY_TOOLS.has(definition.name)) {
112
- if (downstream.destructiveHint === true ||
113
- downstream.readOnlyHint === false) {
114
- return definition;
115
- }
116
- return {
117
- ...definition,
118
- annotations: {
119
- ...downstream,
120
- readOnlyHint: true,
121
- destructiveHint: downstream.destructiveHint ?? false,
122
- },
123
- };
124
- }
125
- if (WRITE_TOOLS.get(definition.name) === "destructive") {
126
- return {
127
- ...definition,
128
- annotations: {
129
- ...downstream,
130
- readOnlyHint: false,
131
- destructiveHint: true,
132
- },
133
- };
134
- }
135
- // Maintained additive creates and tools this release has never seen land
136
- // here alike. Fill-in only: a silent tool is not read-only, so drift still
137
- // fails closed onto `call_destructive_tool`, and neither population gets a
138
- // `destructiveHint` it has not earned. A tool that arrives explicitly
139
- // read-only keeps that annotation — on a name no release has reviewed, the
140
- // downstream's own word is the only evidence there is, and rewriting it
141
- // would be an overrule rather than a fill-in.
142
- return {
143
- ...definition,
144
- annotations: {
145
- ...downstream,
146
- readOnlyHint: downstream.readOnlyHint ?? false,
147
- },
148
- };
149
- }
150
- function usageGuide(purpose, instructions) {
94
+ export const MIXPANEL_VETTED_CATALOG = vettedCatalog({
95
+ reads: READ_ONLY_TOOLS,
96
+ writes: WRITE_TOOLS,
97
+ });
98
+ const REGION_COPY = {
99
+ us: "US",
100
+ eu: "EU",
101
+ in: "India",
102
+ };
103
+ function usageGuide(purpose, region, instructions) {
151
104
  const accountInstructions = instructions?.trim();
105
+ // Leads the guide because discovery summarizes a connector by its first
106
+ // content line. A project lives in exactly one residency, so a question
107
+ // pointed at the wrong region does not return fewer rows — it returns
108
+ // nothing, and reads as the project having no data.
109
+ 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.`;
152
110
  return `# Mixpanel usage
153
111
 
112
+ ${regionNote}
113
+
154
114
  Account purpose: ${purpose}
155
115
 
156
116
  - Start with \`Get-Projects\`, then use \`Get-Business-Context\` for the selected project before interpreting its events or metrics.
117
+ - 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.
157
118
  - Discover names with \`Get-Events\`, \`List-Properties\`, and \`Get-Property-Values\`; do not guess event or property spelling.
158
119
  - For a new analysis, fetch \`Get-Query-Schema\` before \`Run-Query\`. Reduce query results inside \`execute_code\` before returning them.
159
120
  - Use \`Get-Report\` when the request names an existing saved report. Use \`Run-Query\` for a new question.
160
- - Mixpanel limits MCP traffic to 600 requests per user per hour. Reuse discovery results within a run and avoid speculative fan-out.
121
+ - 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.
122
+ - 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.
123
+ - 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.
161
124
  - 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.
162
125
  ${accountInstructions
163
126
  ? `\n## Account instructions\n\n${accountInstructions}\n`
@@ -170,23 +133,34 @@ export function mixpanel(id, options) {
170
133
  throw new Error("mixpanel() requires a non-empty account purpose.");
171
134
  }
172
135
  const region = options.region ?? "us";
136
+ if (!(region in MIXPANEL_MCP_ENDPOINTS)) {
137
+ throw new Error(`mixpanel("${id}") region must be "us", "eu", or "in".`);
138
+ }
173
139
  const connector = remoteMcp(id, {
174
140
  url: MIXPANEL_MCP_ENDPOINTS[region],
175
- title: options.title ?? "Mixpanel",
176
- description: `Mixpanel product analytics ${purpose}`,
141
+ // The region rides the title because browse-time discovery renders the
142
+ // title and the guide summary and nothing else, and residency is the fact
143
+ // an agent must not get wrong between two Mixpanel connections.
144
+ title: options.title ?? `Mixpanel (${region})`,
145
+ description: `Mixpanel product analytics (${REGION_COPY[region]} residency) — ${purpose}`,
177
146
  auth: options.auth ?? { type: "oauth" },
178
147
  requireHttps: true,
179
- callAdmission: MIXPANEL_ADMISSION,
180
- usageGuide: usageGuide(purpose, options.instructions),
148
+ usageGuide: {
149
+ content: usageGuide(purpose, region, options.instructions),
150
+ // Explicit rather than derived: the derived summary would truncate the
151
+ // residency note mid-sentence at 120 characters
152
+ // ([#342](https://github.com/zackbart/connecta/issues/342)).
153
+ summary: `${REGION_COPY[region]} residency. Project scoping, id resolution, query-schema-first analysis, plan-gated catalog.`,
154
+ // Not `required`. Mixpanel's own schemas describe each call; the guide
155
+ // carries the project-then-context sequence, which is worth reading
156
+ // before an analysis rather than before every call.
157
+ },
158
+ ...(options.callAdmission !== undefined
159
+ ? { callAdmission: options.callAdmission }
160
+ : {}),
181
161
  ...(options.maxResultBytes !== undefined
182
162
  ? { maxResultBytes: options.maxResultBytes }
183
163
  : {}),
184
164
  });
185
- return {
186
- ...connector,
187
- async listTools(ctx) {
188
- return (await connector.listTools(ctx)).map(vettedSafety);
189
- },
190
- };
165
+ return withVettedCatalog(connector, MIXPANEL_VETTED_CATALOG);
191
166
  }
192
- //# sourceMappingURL=mixpanel.js.map
@@ -36,4 +36,3 @@ export interface NotionOptions {
36
36
  }
37
37
  /** A maintained Notion connection over the public REST API. */
38
38
  export declare function notion(id: string, options: NotionOptions): Connector;
39
- //# sourceMappingURL=notion.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import { api } from "../connectors/api.js";
2
+ import { guardedFetch } from "../connectors/guarded-fetch.js";
2
3
  import { ConnectorCallError } from "../errors.js";
3
4
  /** Notion's REST origin. Every tool below speaks to exactly this host. */
4
5
  export const NOTION_API_BASE_URL = "https://api.notion.com";
@@ -34,6 +35,15 @@ const MAX_CHILDREN_PER_REQUEST = 100;
34
35
  * hits this ceiling it stops and says so in `truncated`.
35
36
  */
36
37
  const MAX_CONTENT_REQUESTS = 20;
38
+ /**
39
+ * The largest response this connection will read.
40
+ *
41
+ * Notion's own limits put a legitimate answer nowhere near this: `page_size`
42
+ * tops out at 100, and every payload here is JSON. Four mebibytes is a ceiling
43
+ * on absurdity — a proxy that decided to answer with something enormous — not
44
+ * a budget any real read has to think about.
45
+ */
46
+ const NOTION_MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
37
47
  /**
38
48
  * Approximates Notion's documented limit: "an average of three requests per
39
49
  * second, with some bursts beyond the average allowed" — expressed as a
@@ -132,42 +142,50 @@ function notionFailure(status, body, retryAfterHeader) {
132
142
  retryable: false,
133
143
  });
134
144
  }
145
+ /**
146
+ * The one transport every Notion tool goes through.
147
+ *
148
+ * URL confinement, `ctx.signal`, redirect refusal, bounded reads, and the
149
+ * "could not reach the provider" normalization live in the shared helper. The
150
+ * two things that cannot be shared stay here: the integration token becomes
151
+ * the headers Notion accepts, and `notionFailure` decides what a status means
152
+ * — which is the whole reason a generic HTTP client is the wrong shape, given
153
+ * that Notion's 403 and 404 both mean something no status table would guess.
154
+ */
155
+ const send = guardedFetch({
156
+ provider: "Notion",
157
+ baseUrl: NOTION_API_BASE_URL,
158
+ headers: { "Notion-Version": NOTION_API_VERSION },
159
+ maxResponseBytes: NOTION_MAX_RESPONSE_BYTES,
160
+ authenticate: async (ctx) => {
161
+ const token = (await ctx.credential?.get())?.trim();
162
+ if (!token) {
163
+ throw new ConnectorCallError("auth_required", "No Notion integration token is configured for this connector — an operator must add one on /credentials before any Notion call can run.");
164
+ }
165
+ return { Authorization: `Bearer ${token}` };
166
+ },
167
+ });
135
168
  async function notionRequest(ctx, request) {
136
- const token = (await ctx.credential?.get())?.trim();
137
- if (!token) {
138
- throw new ConnectorCallError("auth_required", "No Notion integration token is configured for this connector — an operator must add one on /credentials before any Notion call can run.");
139
- }
140
- const url = new URL(request.path, NOTION_API_BASE_URL);
141
- for (const [key, value] of Object.entries(request.query ?? {})) {
142
- if (value !== undefined)
143
- url.searchParams.set(key, String(value));
144
- }
145
- const headers = {
146
- Authorization: `Bearer ${token}`,
147
- "Notion-Version": NOTION_API_VERSION,
148
- };
149
- if (request.body !== undefined)
150
- headers["Content-Type"] = "application/json";
151
- const response = await fetch(url, {
152
- method: request.method,
153
- headers,
154
- ...(request.body !== undefined
155
- ? { body: JSON.stringify(request.body) }
156
- : {}),
157
- ...(ctx.signal ? { signal: ctx.signal } : {}),
169
+ return await send(request, ctx, async (response) => {
170
+ let payload;
171
+ try {
172
+ // Notion answers a delete with an empty body and a gateway answers with
173
+ // HTML; neither is a payload, and neither is worth a different failure.
174
+ payload = (await response.json());
175
+ }
176
+ catch (cause) {
177
+ // A transport failure is not a parse failure. The connector's byte
178
+ // ceiling fires from inside this read, and swallowing it would report an
179
+ // oversized response as an empty success on a 2xx.
180
+ if (cause instanceof ConnectorCallError)
181
+ throw cause;
182
+ payload = undefined;
183
+ }
184
+ if (!response.ok) {
185
+ throw notionFailure(response.status, payload, response.headers.get("Retry-After"));
186
+ }
187
+ return payload ?? {};
158
188
  });
159
- const text = await response.text();
160
- let payload;
161
- try {
162
- payload = text ? JSON.parse(text) : undefined;
163
- }
164
- catch {
165
- payload = undefined;
166
- }
167
- if (!response.ok) {
168
- throw notionFailure(response.status, payload, response.headers.get("Retry-After"));
169
- }
170
- return payload ?? {};
171
189
  }
172
190
  // ---------------------------------------------------------------------------
173
191
  // Projections
@@ -513,9 +531,15 @@ function projectSchemaProperty(property) {
513
531
  // ---------------------------------------------------------------------------
514
532
  // Shared schema fragments
515
533
  // ---------------------------------------------------------------------------
534
+ // The compact renderer inlines every property description, so these three
535
+ // shared strings are paid for once per tool that uses them. `query_data_source`
536
+ // carries all three plus a filter grammar and rendered past the 1,024-byte
537
+ // compact budget until they were cut to the fact each one actually adds
538
+ // ([#342](https://github.com/zackbart/connecta/issues/342)); the long versions
539
+ // live in the usage guide, which is fetched once rather than per tool.
516
540
  const RAW_PROPERTY = {
517
541
  type: "boolean",
518
- description: "Return Notion's unprojected response instead of the lean projection. Payloads are large — use only when a field the projection drops is genuinely needed.",
542
+ description: "Return Notion's much larger unprojected response instead of the lean projection.",
519
543
  };
520
544
  const PAGE_SIZE_PROPERTY = {
521
545
  type: "integer",
@@ -525,12 +549,12 @@ const PAGE_SIZE_PROPERTY = {
525
549
  };
526
550
  const START_CURSOR_PROPERTY = {
527
551
  type: "string",
528
- description: "Opaque cursor from a previous response's next_cursor. Pass it back verbatim; never parse or construct one.",
552
+ description: "Opaque next_cursor from the previous response. Pass it back verbatim.",
529
553
  };
530
554
  const PROPERTY_SELECT = {
531
555
  type: "array",
532
556
  items: { type: "string" },
533
- description: "Return only these property names. Omit for all properties. Narrowing here is the cheapest way to keep results small.",
557
+ description: "Return only these property names. Omit for all. The cheapest way to shrink a result.",
534
558
  };
535
559
  function listOutputSchema(itemSchema) {
536
560
  return {
@@ -674,10 +698,11 @@ function buildTools(defaultPageSize) {
674
698
  // ---------------------------------------------------------------- reads
675
699
  {
676
700
  name: "search",
677
- description: "Find pages and data sources by title across everything shared with this integration. Matches titles only, never page content — use query_data_source to filter rows inside a database. Returns identity fields only; call get_page for a match's properties.",
701
+ description: "Find pages and data sources by title across everything shared with this integration. Never searches page content — use query_data_source for rows inside a database. Returns identity fields only.",
678
702
  annotations: { readOnlyHint: true },
679
703
  inputSchema: {
680
704
  type: "object",
705
+ required: [],
681
706
  properties: {
682
707
  query: {
683
708
  type: "string",
@@ -1064,6 +1089,7 @@ function buildTools(defaultPageSize) {
1064
1089
  direction: {
1065
1090
  type: "string",
1066
1091
  enum: ["ascending", "descending"],
1092
+ description: "Direction for this sort.",
1067
1093
  },
1068
1094
  },
1069
1095
  additionalProperties: false,
@@ -1104,6 +1130,7 @@ function buildTools(defaultPageSize) {
1104
1130
  annotations: { readOnlyHint: true },
1105
1131
  inputSchema: {
1106
1132
  type: "object",
1133
+ required: [],
1107
1134
  properties: {
1108
1135
  page_size: PAGE_SIZE_PROPERTY,
1109
1136
  start_cursor: START_CURSOR_PROPERTY,
@@ -1127,7 +1154,12 @@ function buildTools(defaultPageSize) {
1127
1154
  name: "get_self",
1128
1155
  description: "Identify the integration this connector authenticates as, and the workspace it is installed in. The cheapest way to confirm the token works before a longer sequence.",
1129
1156
  annotations: { readOnlyHint: true },
1130
- inputSchema: { type: "object", additionalProperties: false },
1157
+ inputSchema: {
1158
+ type: "object",
1159
+ required: [],
1160
+ properties: {},
1161
+ additionalProperties: false,
1162
+ },
1131
1163
  outputSchema: {
1132
1164
  type: "object",
1133
1165
  properties: {
@@ -1189,15 +1221,22 @@ function buildTools(defaultPageSize) {
1189
1221
  description: "Create a page, either as a child of another page or as a row in a data source. Notion has no idempotency key: a retried create makes a second page, so confirm with search before repeating one.",
1190
1222
  annotations: { readOnlyHint: false },
1191
1223
  inputSchema: {
1224
+ // Empty rather than absent: a parent is required, but *which* parent is
1225
+ // an exclusive choice a plain-object `required` list cannot express,
1226
+ // and the top-level `anyOf` that could would cost the tool its
1227
+ // `inputKeys` in discovery. The choice is stated in both parent
1228
+ // descriptions and enforced locally as `invalid_args` before any round
1229
+ // trip ([#342](https://github.com/zackbart/connecta/issues/342)).
1230
+ required: [],
1192
1231
  type: "object",
1193
1232
  properties: {
1194
1233
  parent_page_id: {
1195
1234
  type: "string",
1196
- description: "Create as a child page of this page.",
1235
+ description: "Create as a child page of this page. Exactly one parent id, this or parent_data_source_id.",
1197
1236
  },
1198
1237
  parent_data_source_id: {
1199
1238
  type: "string",
1200
- description: "Create as a row in this data source. Not a database id.",
1239
+ description: "Create as a row in this data source, not a database id. Exactly one parent id, this or parent_page_id.",
1201
1240
  },
1202
1241
  title: { type: "string", description: "Plain-text title." },
1203
1242
  title_property: {
@@ -1561,6 +1600,13 @@ it. A block type this projection does not model keeps its payload under
1561
1600
  - **429** carries a retry window. Notion allows roughly three requests per
1562
1601
  second per integration, so wait it out rather than retrying immediately.
1563
1602
 
1603
+ ## No escape hatch
1604
+
1605
+ This connection has no guarded raw-REST tool, deliberately. Notion's public
1606
+ API is small and slow-moving enough for the named surface to cover it, so
1607
+ there is no \`notion_api_*\` to reach for — an operation absent from the tool
1608
+ list is absent from this connection, not hidden behind a generic call.
1609
+
1564
1610
  ## Writes and pagination
1565
1611
 
1566
1612
  - Notion has **no idempotency key**. A retried \`create_page\` or
@@ -1622,4 +1668,3 @@ export function notion(id, options) {
1622
1668
  : {}),
1623
1669
  });
1624
1670
  }
1625
- //# sourceMappingURL=notion.js.map
@@ -32,6 +32,18 @@ export interface StripeOptions {
32
32
  /** Connector-specific inline result limit; omit to inherit the deployment. */
33
33
  maxResultBytes?: number;
34
34
  }
35
+ /**
36
+ * The manifest this release reviewed: both lists in one place, which is what
37
+ * makes the classification the connector applies and the drift check that runs
38
+ * beside it the same fact (P13). No schema digests yet — no release has read
39
+ * Stripe's live schemas and written them down, and an invented digest would
40
+ * report a change that never happened. `npm run drift:check -- --record` reads
41
+ * them from a live account and prints the block to paste in
42
+ * ([#351](https://github.com/zackbart/connecta/issues/351)).
43
+ *
44
+ * Exported because the maintainer-run check compares against this manifest and
45
+ * *names* what moved, which the runtime check deliberately cannot.
46
+ */
47
+ export declare const STRIPE_VETTED_CATALOG: import("../catalog-drift.js").VettedCatalog;
35
48
  /** A maintained Stripe hosted-MCP connection. */
36
49
  export declare function stripe(id: string, options: StripeOptions): Connector;
37
- //# sourceMappingURL=stripe.d.ts.map