@zackbart/connecta 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. package/CHANGELOG.md +961 -5
  2. package/README.md +62 -39
  3. package/bin/connecta.mjs +110 -139
  4. package/bin/meta-tool-names.d.mts +2 -0
  5. package/bin/meta-tool-names.mjs +9 -0
  6. package/bin/version.mjs +3 -0
  7. package/dist/access-tokens.js +53 -63
  8. package/dist/activity-request.js +8 -0
  9. package/dist/activity.d.ts +76 -42
  10. package/dist/activity.js +110 -42
  11. package/dist/auth/clerk-sdk/client.d.ts +65 -0
  12. package/dist/auth/clerk-sdk/client.js +5 -0
  13. package/dist/auth/clerk-sdk/generated.js +1845 -0
  14. package/dist/auth/clerk-transport.js +19 -0
  15. package/dist/auth/clerk.d.ts +17 -7
  16. package/dist/auth/clerk.js +189 -107
  17. package/dist/auth/cloudflare-access.js +25 -26
  18. package/dist/auth/downstream-client-metadata.d.ts +29 -0
  19. package/dist/auth/downstream-client-metadata.js +133 -0
  20. package/dist/auth/downstream-oauth.js +1632 -1509
  21. package/dist/auth/downstream-revocation.js +106 -0
  22. package/dist/auth/oauth-token-response.js +231 -0
  23. package/dist/auth/oauth-v2-migration.js +116 -0
  24. package/dist/auth/static-oauth.js +526 -0
  25. package/dist/auth-elicitation.js +283 -0
  26. package/dist/branding.d.ts +8 -16
  27. package/dist/branding.js +26 -59
  28. package/dist/byte-read-response.js +39 -0
  29. package/dist/call-admission.js +12 -16
  30. package/dist/catalog-cache.js +739 -0
  31. package/dist/catalog-drift.d.ts +50 -15
  32. package/dist/catalog-drift.js +365 -128
  33. package/dist/catalog-fingerprint.js +2 -4
  34. package/dist/catalog-freshness.js +13 -0
  35. package/dist/catalog-limits.js +2 -2
  36. package/dist/catalog-service.js +368 -224
  37. package/dist/catalog.js +43 -84
  38. package/dist/concurrency.js +3 -4
  39. package/dist/config-defaults.d.ts +39 -0
  40. package/dist/config-defaults.js +46 -0
  41. package/dist/config-schema.d.ts +181 -0
  42. package/dist/config-schema.js +435 -0
  43. package/dist/config-value-sources.js +102 -0
  44. package/dist/config.d.ts +631 -0
  45. package/dist/config.js +503 -0
  46. package/dist/connector-access.d.ts +1 -0
  47. package/dist/connector-access.js +13 -15
  48. package/dist/connector-caller.d.ts +8 -0
  49. package/dist/connector-caller.js +15 -6
  50. package/dist/connector-scope.js +1 -1
  51. package/dist/connectors/api-connector.d.ts +220 -0
  52. package/dist/connectors/api-connector.js +214 -0
  53. package/dist/connectors/api.d.ts +8 -71
  54. package/dist/connectors/api.js +13 -99
  55. package/dist/connectors/guarded-fetch.d.ts +144 -0
  56. package/dist/connectors/guarded-fetch.js +108 -25
  57. package/dist/connectors/negotiation-cache.js +46 -0
  58. package/dist/connectors/option-shapes.js +27 -0
  59. package/dist/connectors/remote-mcp.d.ts +30 -4
  60. package/dist/connectors/remote-mcp.js +1780 -351
  61. package/dist/connectors/resource-uri.js +335 -0
  62. package/dist/credential-contract.d.ts +10 -0
  63. package/dist/credential-rules.js +1 -3
  64. package/dist/credential-url.js +108 -0
  65. package/dist/credentials.d.ts +6 -1
  66. package/dist/credentials.js +27 -18
  67. package/dist/d1.d.ts +130 -0
  68. package/dist/d1.js +290 -0
  69. package/dist/describe-config.d.ts +165 -0
  70. package/dist/describe-config.js +315 -0
  71. package/dist/described.js +106 -0
  72. package/dist/downstream-input-context.js +119 -0
  73. package/dist/downstream-input.js +323 -0
  74. package/dist/errors.d.ts +97 -20
  75. package/dist/errors.js +158 -80
  76. package/dist/execute.js +453 -305
  77. package/dist/executor-admission.d.ts +1 -0
  78. package/dist/executor-admission.js +11 -15
  79. package/dist/executor-contract.d.ts +20 -0
  80. package/dist/executor-contract.js +48 -0
  81. package/dist/executor-result.js +24 -9
  82. package/dist/executors/quickjs-child.js +3 -4
  83. package/dist/executors/quickjs-runtime.js +147 -59
  84. package/dist/executors/quickjs.js +29 -35
  85. package/dist/favicon.js +1 -2
  86. package/dist/fix-prompt.js +1 -3
  87. package/dist/guest-runtime.js +188 -0
  88. package/dist/guest-types.d.ts +176 -0
  89. package/dist/guest-types.js +1 -0
  90. package/dist/html-security.js +24 -0
  91. package/dist/identity.js +1 -3
  92. package/dist/inbound-credential.js +52 -0
  93. package/dist/index.d.ts +25 -257
  94. package/dist/index.js +65 -478
  95. package/dist/invocation-auth.js +69 -0
  96. package/dist/invocation.js +230 -73
  97. package/dist/json-schema.d.ts +1 -1
  98. package/dist/mcp-client-context.js +35 -0
  99. package/dist/mcp-result.js +11 -7
  100. package/dist/meta-output.js +76 -0
  101. package/dist/meta-tool-names.d.ts +2 -0
  102. package/dist/meta-tool-names.js +3 -0
  103. package/dist/meta-tools.js +285 -209
  104. package/dist/module-contracts.d.ts +8 -23
  105. package/dist/node.d.ts +0 -2
  106. package/dist/node.js +2 -2
  107. package/dist/oauth-callback-outcome.js +1 -3
  108. package/dist/oauth-handoff.js +117 -0
  109. package/dist/oauth-partition.js +17 -0
  110. package/dist/oauth-sealing.js +20 -0
  111. package/dist/operator-record.d.ts +137 -0
  112. package/dist/operator-record.js +420 -0
  113. package/dist/operator-ui/assets.js +31 -0
  114. package/dist/operator-ui/contract.d.ts +72 -0
  115. package/dist/operator-ui/contract.js +1 -0
  116. package/dist/operator-ui/fix-prompts.d.ts +18 -0
  117. package/dist/operator-ui/generated.js +5 -4
  118. package/dist/operator-ui/model.d.ts +12 -87
  119. package/dist/operator-ui/model.js +2 -9
  120. package/dist/operator-ui/setup-commands.js +1 -3
  121. package/dist/operator-ui/view.d.ts +323 -0
  122. package/dist/operator-ui/view.js +62 -189
  123. package/dist/page-styles.js +2 -3
  124. package/dist/program-source.js +14 -2
  125. package/dist/{exempt-writes.js → program-writes.js} +55 -18
  126. package/dist/provider.d.ts +142 -0
  127. package/dist/provider.js +187 -0
  128. package/dist/providers/_shared/google/result-size.js +57 -0
  129. package/dist/providers/_shared/google/service-account.d.ts +58 -0
  130. package/dist/providers/_shared/google/service-account.js +500 -0
  131. package/dist/providers/_shared/google/workspace.d.ts +276 -0
  132. package/dist/providers/_shared/google/workspace.js +518 -0
  133. package/dist/providers/basecamp/index.d.ts +43 -0
  134. package/dist/providers/basecamp/index.js +997 -0
  135. package/dist/providers/basecamp/skill.generated.js +9 -0
  136. package/dist/providers/breeze/index.d.ts +34 -0
  137. package/dist/providers/breeze/index.js +1446 -0
  138. package/dist/providers/breeze/skill.generated.js +9 -0
  139. package/dist/providers/ccb/index.d.ts +103 -0
  140. package/dist/providers/ccb/index.js +1725 -0
  141. package/dist/providers/ccb/skill.generated.js +9 -0
  142. package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
  143. package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
  144. package/dist/providers/cloudflare/skill.generated.js +10 -0
  145. package/dist/providers/docs/index.d.ts +54 -0
  146. package/dist/providers/docs/index.js +1237 -0
  147. package/dist/providers/docs/skill.generated.js +9 -0
  148. package/dist/providers/drive/index.d.ts +53 -0
  149. package/dist/providers/drive/index.js +1523 -0
  150. package/dist/providers/drive/skill.generated.js +9 -0
  151. package/dist/providers/forms/index.d.ts +54 -0
  152. package/dist/providers/forms/index.js +1217 -0
  153. package/dist/providers/forms/skill.generated.js +11 -0
  154. package/dist/providers/github/auth.d.ts +32 -0
  155. package/dist/providers/github/auth.js +361 -0
  156. package/dist/providers/github/hosted.js +218 -0
  157. package/dist/providers/github/index.d.ts +13 -0
  158. package/dist/providers/github/index.js +140 -0
  159. package/dist/providers/github/key.js +100 -0
  160. package/dist/providers/github/rest.js +321 -0
  161. package/dist/providers/github/scope.d.ts +29 -0
  162. package/dist/providers/github/scope.js +124 -0
  163. package/dist/providers/github/skill.generated.js +8 -0
  164. package/dist/providers/gmail/index.d.ts +51 -0
  165. package/dist/providers/gmail/index.js +1436 -0
  166. package/dist/providers/gmail/skill.generated.js +9 -0
  167. package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
  168. package/dist/providers/linear/index.js +352 -0
  169. package/dist/providers/linear/skill.generated.js +8 -0
  170. package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
  171. package/dist/providers/mixpanel/index.js +416 -0
  172. package/dist/providers/mixpanel/skill.generated.js +9 -0
  173. package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
  174. package/dist/providers/{notion.js → notion/index.js} +226 -239
  175. package/dist/providers/notion/skill.generated.js +10 -0
  176. package/dist/providers/overflow/index.d.ts +60 -0
  177. package/dist/providers/overflow/index.js +1535 -0
  178. package/dist/providers/overflow/skill.generated.js +8 -0
  179. package/dist/providers/planning-center/index.d.ts +59 -0
  180. package/dist/providers/planning-center/index.js +2199 -0
  181. package/dist/providers/planning-center/skill.generated.js +10 -0
  182. package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
  183. package/dist/providers/revenuecat/index.js +557 -0
  184. package/dist/providers/revenuecat/skill.generated.js +11 -0
  185. package/dist/providers/sheets/index.d.ts +54 -0
  186. package/dist/providers/sheets/index.js +1237 -0
  187. package/dist/providers/sheets/skill.generated.js +10 -0
  188. package/dist/providers/slides/index.d.ts +53 -0
  189. package/dist/providers/slides/index.js +2645 -0
  190. package/dist/providers/slides/skill.generated.js +9 -0
  191. package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
  192. package/dist/providers/stripe/index.js +266 -0
  193. package/dist/providers/stripe/skill.generated.js +11 -0
  194. package/dist/providers/tithely/index.d.ts +49 -0
  195. package/dist/providers/tithely/index.js +1003 -0
  196. package/dist/providers/tithely/skill.generated.js +8 -0
  197. package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
  198. package/dist/providers/vercel/index.js +1038 -0
  199. package/dist/providers/vercel/mcp-ownership.js +212 -0
  200. package/dist/providers/vercel/skill.generated.js +11 -0
  201. package/dist/registry.d.ts +108 -171
  202. package/dist/registry.js +513 -925
  203. package/dist/request-state.js +21 -0
  204. package/dist/resource-read.js +100 -0
  205. package/dist/result-shapes.js +17 -49
  206. package/dist/retired-toolkits.js +1 -1
  207. package/dist/routes/access-tokens.js +3 -6
  208. package/dist/routes/activity-context.js +21 -0
  209. package/dist/routes/activity-disclosure.js +40 -0
  210. package/dist/routes/activity.js +59 -21
  211. package/dist/routes/actor-labels.js +3 -50
  212. package/dist/routes/connect.js +221 -0
  213. package/dist/routes/credentials.js +15 -27
  214. package/dist/routes/mcp.js +356 -130
  215. package/dist/routes/oauth-client-metadata.js +15 -0
  216. package/dist/routes/oauth-management.js +45 -107
  217. package/dist/routes/oauth.js +136 -57
  218. package/dist/routes/operator.js +3 -3
  219. package/dist/routes/shared.d.ts +25 -64
  220. package/dist/routes/shared.js +160 -80
  221. package/dist/routes/skills.js +30 -0
  222. package/dist/routes/ui-config.js +225 -0
  223. package/dist/routes/ui-data.js +40 -35
  224. package/dist/routes/ui.js +66 -56
  225. package/dist/runtime/admission.js +4 -2
  226. package/dist/runtime/call-admission.js +3 -1
  227. package/dist/runtime/connector-scope.js +1 -4
  228. package/dist/runtime/run.js +10 -39
  229. package/dist/runtime/services.js +12 -117
  230. package/dist/runtime/shared-read.js +1 -3
  231. package/dist/runtime/storage.js +8 -1
  232. package/dist/sent-secrets.d.ts +52 -0
  233. package/dist/sent-secrets.js +474 -0
  234. package/dist/server.js +28 -71
  235. package/dist/skills.js +406 -174
  236. package/dist/sqlite.d.ts +48 -0
  237. package/dist/sqlite.js +166 -0
  238. package/dist/storage/keys.js +428 -0
  239. package/dist/storage/memory.js +7 -0
  240. package/dist/storage/sql.d.ts +66 -0
  241. package/dist/storage/sql.js +534 -0
  242. package/dist/timeout.js +4 -2
  243. package/dist/tool-name.js +17 -0
  244. package/dist/tool-safety.d.ts +9 -35
  245. package/dist/tool-safety.js +20 -40
  246. package/dist/types.d.ts +320 -54
  247. package/dist/types.js +0 -1
  248. package/dist/ui.d.ts +7 -19
  249. package/dist/ui.js +76 -90
  250. package/dist/url-safety.js +3 -6
  251. package/dist/usage-guide.js +137 -0
  252. package/dist/validate.d.ts +7 -0
  253. package/dist/validate.js +309 -47
  254. package/dist/version.d.ts +1 -7
  255. package/dist/version.js +3 -7
  256. package/dist/worker.d.ts +11 -0
  257. package/dist/worker.js +434 -0
  258. package/documentation/architecture.md +665 -230
  259. package/documentation/auth.md +962 -458
  260. package/documentation/code-mode.md +501 -312
  261. package/documentation/meta-tools.md +449 -200
  262. package/documentation/operator-tests.md +93 -0
  263. package/documentation/provider-migration-0.29.md +60 -0
  264. package/examples/worker/AGENTS.md +34 -12
  265. package/examples/worker/README.md +286 -255
  266. package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
  267. package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
  268. package/examples/worker/src/connecta.config.ts +151 -0
  269. package/examples/worker/src/index.ts +14 -197
  270. package/examples/worker/wrangler.jsonc +15 -35
  271. package/package.json +125 -35
  272. package/templates/node/.dockerignore +1 -2
  273. package/templates/node/.env.example +20 -21
  274. package/templates/node/AGENTS.md +21 -17
  275. package/templates/node/Dockerfile +3 -5
  276. package/templates/node/README.md +133 -58
  277. package/templates/node/docker-compose.yml +11 -12
  278. package/templates/node/package.json +4 -2
  279. package/templates/node/src/connecta.config.ts +119 -0
  280. package/templates/node/src/index.ts +9 -154
  281. package/templates/node/src/provision-token.ts +17 -0
  282. package/AGENTS.md +0 -170
  283. package/dist/artifacts/connector.d.ts +0 -58
  284. package/dist/artifacts/connector.js +0 -730
  285. package/dist/artifacts/document.js +0 -86
  286. package/dist/artifacts/guide.js +0 -140
  287. package/dist/artifacts/html-scan.js +0 -329
  288. package/dist/artifacts/json.js +0 -78
  289. package/dist/artifacts/kv-store.d.ts +0 -20
  290. package/dist/artifacts/kv-store.js +0 -140
  291. package/dist/artifacts/markdown.js +0 -478
  292. package/dist/artifacts/module.d.ts +0 -37
  293. package/dist/artifacts/module.js +0 -66
  294. package/dist/artifacts/operations.d.ts +0 -197
  295. package/dist/artifacts/operations.js +0 -1002
  296. package/dist/artifacts/refresh.d.ts +0 -55
  297. package/dist/artifacts/refresh.js +0 -236
  298. package/dist/artifacts/routes.js +0 -206
  299. package/dist/artifacts/types.d.ts +0 -214
  300. package/dist/artifacts/types.js +0 -22
  301. package/dist/artifacts/validate.d.ts +0 -62
  302. package/dist/artifacts/validate.js +0 -651
  303. package/dist/artifacts.d.ts +0 -6
  304. package/dist/artifacts.js +0 -9
  305. package/dist/auth/bearer.d.ts +0 -11
  306. package/dist/auth/bearer.js +0 -50
  307. package/dist/providers/linear.js +0 -217
  308. package/dist/providers/mixpanel.js +0 -247
  309. package/dist/providers/revenuecat.js +0 -317
  310. package/dist/providers/stripe.js +0 -253
  311. package/dist/providers/vercel.js +0 -1253
  312. package/dist/storage/file.d.ts +0 -15
  313. package/dist/storage/file.js +0 -455
  314. package/ethos.md +0 -93
  315. package/examples/worker/src/cloudflare-kv.ts +0 -43
  316. package/examples/worker/src/d1-activity-row.ts +0 -155
  317. package/examples/worker/src/d1-activity.ts +0 -147
  318. package/examples/worker/src/d1-storage.ts +0 -138
  319. package/examples/worker/src/r2-artifact-blobs.ts +0 -29
  320. package/templates/node/src/file-activity.ts +0 -182
@@ -0,0 +1,997 @@
1
+ import { skill } from "./skill.generated.js";
2
+ import { remoteMcp } from "../../connectors/remote-mcp.js";
3
+ import { reviewedCatalog } from "../../catalog-drift.js";
4
+ import { keys, optionsOf } from "../../config-schema.js";
5
+ import { PROVIDER_COMMON } from "../../connectors/option-shapes.js";
6
+ import { defineProvider } from "../../provider.js";
7
+ /**
8
+ * Basecamp's one hosted MCP endpoint, streamable HTTP.
9
+ *
10
+ * Live but undocumented: as of 2026-10-05 37signals has announced no MCP
11
+ * server, and basecamp.com/agents (where the endpoint's own 401 body points)
12
+ * describes the CLI and SDKs without naming it. What the server does publish is
13
+ * its OAuth discovery — protected-resource metadata naming
14
+ * `https://app.basecamp.com` as the authorization server — and that is what
15
+ * this provider is written against, beside a captured live `tools/list`.
16
+ */
17
+ export const BASECAMP_MCP_ENDPOINT = "https://mcp.basecamp.com/mcp";
18
+ /**
19
+ * Requested only when Basecamp stops advertising scopes of its own.
20
+ *
21
+ * The MCP client picks the scope from the `WWW-Authenticate` challenge first
22
+ * (`mcp full` today), then the protected resource's `scopes_supported`, and
23
+ * only then this value — appending `offline_access` itself whenever the
24
+ * authorization server lists it. So for Basecamp as it serves today, this is a
25
+ * fallback that matches what the challenge already asks for, not a lever.
26
+ */
27
+ const FALLBACK_SCOPE = "full mcp offline_access";
28
+ /**
29
+ * Retains the 227-tool live tools/list review captured on 2026-10-05,
30
+ * including the server's explicit read annotations. Basecamp publishes no
31
+ * inventory; credential-free checks can only verify OAuth discovery.
32
+ * Reviewed in #705's provider audit against https://mcp.basecamp.com/.well-known/oauth-protected-resource/mcp.
33
+ * Retains the release-reviewed inventory, including names absent from today's
34
+ * public reference. Live annotations were not reverified without credentials.
35
+ * No schema digest is asserted without a captured schema to review.
36
+ */
37
+ const BASECAMP_CLASSIFICATION = {
38
+ tools: {
39
+ "get_basecamp_guide": {
40
+ "verdict": "read",
41
+ "reason": "Reads Basecamp reference guidance; it does not change account state.",
42
+ },
43
+ "get_me": { "verdict": "read", "reason": "Reads the signed-in identity and connected account label." },
44
+ "get_account": {
45
+ "verdict": "read",
46
+ "reason": "Retrieves Basecamp account information without changing vendor state.",
47
+ },
48
+ "get_my_profile": {
49
+ "verdict": "read",
50
+ "reason": "Retrieves Basecamp my profile information without changing vendor state.",
51
+ },
52
+ "get_my_preferences": {
53
+ "verdict": "read",
54
+ "reason": "Retrieves Basecamp my preferences information without changing vendor state.",
55
+ },
56
+ "get_by_url": {
57
+ "verdict": "read",
58
+ "reason": "Resolves a Basecamp URL and reads its record; it does not change the target.",
59
+ },
60
+ "search": { "verdict": "read", "reason": "Searches Basecamp records without modifying them." },
61
+ "search_mentions": {
62
+ "verdict": "read",
63
+ "reason": "Retrieves Basecamp mentions information without changing vendor state.",
64
+ },
65
+ "get_person": {
66
+ "verdict": "read",
67
+ "reason": "Retrieves Basecamp person information without changing vendor state.",
68
+ },
69
+ "list_people": {
70
+ "verdict": "read",
71
+ "reason": "Retrieves Basecamp people information without changing vendor state.",
72
+ },
73
+ "list_pingable_people": {
74
+ "verdict": "read",
75
+ "reason": "Retrieves Basecamp pingable people information without changing vendor state.",
76
+ },
77
+ "list_assignable_people": {
78
+ "verdict": "read",
79
+ "reason": "Retrieves Basecamp assignable people information without changing vendor state.",
80
+ },
81
+ "list_project_people": {
82
+ "verdict": "read",
83
+ "reason": "Retrieves Basecamp project people information without changing vendor state.",
84
+ },
85
+ "get_out_of_office": {
86
+ "verdict": "read",
87
+ "reason": "Retrieves Basecamp out of office information without changing vendor state.",
88
+ },
89
+ "list_projects": {
90
+ "verdict": "read",
91
+ "reason": "Retrieves Basecamp projects information without changing vendor state.",
92
+ },
93
+ "get_project": {
94
+ "verdict": "read",
95
+ "reason": "Retrieves Basecamp project information without changing vendor state.",
96
+ },
97
+ "get_project_tools": {
98
+ "verdict": "read",
99
+ "reason": "Retrieves Basecamp project tools information without changing vendor state.",
100
+ },
101
+ "get_dock_tool": {
102
+ "verdict": "read",
103
+ "reason": "Retrieves Basecamp dock tool information without changing vendor state.",
104
+ },
105
+ "get_project_construction": {
106
+ "verdict": "read",
107
+ "reason": "Retrieves Basecamp project construction information without changing vendor state.",
108
+ },
109
+ "list_templates": {
110
+ "verdict": "read",
111
+ "reason": "Retrieves Basecamp templates information without changing vendor state.",
112
+ },
113
+ "get_template": {
114
+ "verdict": "read",
115
+ "reason": "Retrieves Basecamp template information without changing vendor state.",
116
+ },
117
+ "list_folders": {
118
+ "verdict": "read",
119
+ "reason": "Retrieves Basecamp folders information without changing vendor state.",
120
+ },
121
+ "get_folder": {
122
+ "verdict": "read",
123
+ "reason": "Retrieves Basecamp folder information without changing vendor state.",
124
+ },
125
+ "get_my_assignments": {
126
+ "verdict": "read",
127
+ "reason": "Retrieves Basecamp my assignments information without changing vendor state.",
128
+ },
129
+ "get_my_completed_assignments": {
130
+ "verdict": "read",
131
+ "reason": "Retrieves Basecamp my completed assignments information without changing vendor state.",
132
+ },
133
+ "get_my_due_assignments": {
134
+ "verdict": "read",
135
+ "reason": "Retrieves Basecamp my due assignments information without changing vendor state.",
136
+ },
137
+ "get_my_day": {
138
+ "verdict": "read",
139
+ "reason": "Retrieves Basecamp my day information without changing vendor state.",
140
+ },
141
+ "get_catchup": {
142
+ "verdict": "read",
143
+ "reason": "Retrieves Basecamp catchup information without changing vendor state.",
144
+ },
145
+ "get_my_notifications": {
146
+ "verdict": "read",
147
+ "reason": "Retrieves Basecamp my notifications information without changing vendor state.",
148
+ },
149
+ "get_bubble_ups": {
150
+ "verdict": "read",
151
+ "reason": "Retrieves Basecamp bubble ups information without changing vendor state.",
152
+ },
153
+ "get_my_note": {
154
+ "verdict": "read",
155
+ "reason": "Retrieves Basecamp my note information without changing vendor state.",
156
+ },
157
+ "list_my_bookmarks": {
158
+ "verdict": "read",
159
+ "reason": "Retrieves Basecamp my bookmarks information without changing vendor state.",
160
+ },
161
+ "list_my_drafts": {
162
+ "verdict": "read",
163
+ "reason": "Retrieves Basecamp my drafts information without changing vendor state.",
164
+ },
165
+ "get_bookmark": {
166
+ "verdict": "read",
167
+ "reason": "Retrieves Basecamp bookmark information without changing vendor state.",
168
+ },
169
+ "get_question_reminders": {
170
+ "verdict": "read",
171
+ "reason": "Retrieves Basecamp question reminders information without changing vendor state.",
172
+ },
173
+ "show_my_work": {
174
+ "verdict": "read",
175
+ "reason": "Retrieves Basecamp my work information without changing vendor state.",
176
+ },
177
+ "get_progress_report": {
178
+ "verdict": "read",
179
+ "reason": "Retrieves Basecamp progress report information without changing vendor state.",
180
+ },
181
+ "get_project_timeline": {
182
+ "verdict": "read",
183
+ "reason": "Retrieves Basecamp project timeline information without changing vendor state.",
184
+ },
185
+ "get_person_progress": {
186
+ "verdict": "read",
187
+ "reason": "Retrieves Basecamp person progress information without changing vendor state.",
188
+ },
189
+ "list_feed_events": {
190
+ "verdict": "read",
191
+ "reason": "Retrieves Basecamp feed events information without changing vendor state.",
192
+ },
193
+ "get_event_inbox": {
194
+ "verdict": "read",
195
+ "reason": "Retrieves Basecamp event inbox information without changing vendor state.",
196
+ },
197
+ "list_everything_feed": {
198
+ "verdict": "read",
199
+ "reason": "Retrieves Basecamp everything feed information without changing vendor state.",
200
+ },
201
+ "list_everything_todos": {
202
+ "verdict": "read",
203
+ "reason": "Retrieves Basecamp everything todos information without changing vendor state.",
204
+ },
205
+ "list_everything_cards": {
206
+ "verdict": "read",
207
+ "reason": "Retrieves Basecamp everything cards information without changing vendor state.",
208
+ },
209
+ "summarize_recording": {
210
+ "verdict": "read",
211
+ "reason": "Retrieves Basecamp recording information without changing vendor state.",
212
+ },
213
+ "create_stream_ticket": {
214
+ "verdict": "read",
215
+ "reason": "Retained exception from the 2026-10-05 live review: the server marks this short-lived, single-connection feed ticket read-only. It creates no Basecamp record and unlocks only the same observational feed as list_feed_events. The ticket is an ephemeral credential; the guide tells agents not to call it because Connecta cannot hold the WebSocket connection.",
216
+ },
217
+ "get_todoset": {
218
+ "verdict": "read",
219
+ "reason": "Retrieves Basecamp todoset information without changing vendor state.",
220
+ },
221
+ "list_todolists": {
222
+ "verdict": "read",
223
+ "reason": "Retrieves Basecamp todolists information without changing vendor state.",
224
+ },
225
+ "get_todolist": {
226
+ "verdict": "read",
227
+ "reason": "Retrieves Basecamp todolist information without changing vendor state.",
228
+ },
229
+ "list_todolist_groups": {
230
+ "verdict": "read",
231
+ "reason": "Retrieves Basecamp todolist groups information without changing vendor state.",
232
+ },
233
+ "get_todolist_group": {
234
+ "verdict": "read",
235
+ "reason": "Retrieves Basecamp todolist group information without changing vendor state.",
236
+ },
237
+ "list_todos": {
238
+ "verdict": "read",
239
+ "reason": "Retrieves Basecamp todos information without changing vendor state.",
240
+ },
241
+ "get_todo": { "verdict": "read", "reason": "Retrieves Basecamp todo information without changing vendor state." },
242
+ "get_assigned_todos": {
243
+ "verdict": "read",
244
+ "reason": "Retrieves Basecamp assigned todos information without changing vendor state.",
245
+ },
246
+ "get_overdue_todos": {
247
+ "verdict": "read",
248
+ "reason": "Retrieves Basecamp overdue todos information without changing vendor state.",
249
+ },
250
+ "get_hill_chart": {
251
+ "verdict": "read",
252
+ "reason": "Retrieves Basecamp hill chart information without changing vendor state.",
253
+ },
254
+ "get_message_board": {
255
+ "verdict": "read",
256
+ "reason": "Retrieves Basecamp message board information without changing vendor state.",
257
+ },
258
+ "list_messages": {
259
+ "verdict": "read",
260
+ "reason": "Retrieves Basecamp messages information without changing vendor state.",
261
+ },
262
+ "get_message": {
263
+ "verdict": "read",
264
+ "reason": "Retrieves Basecamp message information without changing vendor state.",
265
+ },
266
+ "list_message_types": {
267
+ "verdict": "read",
268
+ "reason": "Retrieves Basecamp message types information without changing vendor state.",
269
+ },
270
+ "get_message_type": {
271
+ "verdict": "read",
272
+ "reason": "Retrieves Basecamp message type information without changing vendor state.",
273
+ },
274
+ "list_comments": {
275
+ "verdict": "read",
276
+ "reason": "Retrieves Basecamp comments information without changing vendor state.",
277
+ },
278
+ "get_comment": {
279
+ "verdict": "read",
280
+ "reason": "Retrieves Basecamp comment information without changing vendor state.",
281
+ },
282
+ "list_recording_boosts": {
283
+ "verdict": "read",
284
+ "reason": "Retrieves Basecamp recording boosts information without changing vendor state.",
285
+ },
286
+ "list_event_boosts": {
287
+ "verdict": "read",
288
+ "reason": "Retrieves Basecamp event boosts information without changing vendor state.",
289
+ },
290
+ "get_boost": { "verdict": "read", "reason": "Retrieves Basecamp boost information without changing vendor state." },
291
+ "get_card_table": {
292
+ "verdict": "read",
293
+ "reason": "Retrieves Basecamp card table information without changing vendor state.",
294
+ },
295
+ "get_card_column": {
296
+ "verdict": "read",
297
+ "reason": "Retrieves Basecamp card column information without changing vendor state.",
298
+ },
299
+ "list_cards": {
300
+ "verdict": "read",
301
+ "reason": "Retrieves Basecamp cards information without changing vendor state.",
302
+ },
303
+ "get_card": { "verdict": "read", "reason": "Retrieves Basecamp card information without changing vendor state." },
304
+ "get_card_step": {
305
+ "verdict": "read",
306
+ "reason": "Retrieves Basecamp card step information without changing vendor state.",
307
+ },
308
+ "get_campfire": {
309
+ "verdict": "read",
310
+ "reason": "Retrieves Basecamp campfire information without changing vendor state.",
311
+ },
312
+ "list_campfire_lines": {
313
+ "verdict": "read",
314
+ "reason": "Retrieves Basecamp campfire lines information without changing vendor state.",
315
+ },
316
+ "get_campfire_line": {
317
+ "verdict": "read",
318
+ "reason": "Retrieves Basecamp campfire line information without changing vendor state.",
319
+ },
320
+ "list_campfire_uploads": {
321
+ "verdict": "read",
322
+ "reason": "Retrieves Basecamp campfire uploads information without changing vendor state.",
323
+ },
324
+ "get_schedule": {
325
+ "verdict": "read",
326
+ "reason": "Retrieves Basecamp schedule information without changing vendor state.",
327
+ },
328
+ "list_schedule_entries": {
329
+ "verdict": "read",
330
+ "reason": "Retrieves Basecamp schedule entries information without changing vendor state.",
331
+ },
332
+ "get_schedule_entry": {
333
+ "verdict": "read",
334
+ "reason": "Retrieves Basecamp schedule entry information without changing vendor state.",
335
+ },
336
+ "get_schedule_entry_occurrence": {
337
+ "verdict": "read",
338
+ "reason": "Retrieves Basecamp schedule entry occurrence information without changing vendor state.",
339
+ },
340
+ "get_upcoming_schedule": {
341
+ "verdict": "read",
342
+ "reason": "Retrieves Basecamp upcoming schedule information without changing vendor state.",
343
+ },
344
+ "get_calendar": {
345
+ "verdict": "read",
346
+ "reason": "Retrieves Basecamp calendar information without changing vendor state.",
347
+ },
348
+ "list_lineup_markers": {
349
+ "verdict": "read",
350
+ "reason": "Retrieves Basecamp lineup markers information without changing vendor state.",
351
+ },
352
+ "get_vault": { "verdict": "read", "reason": "Retrieves Basecamp vault information without changing vendor state." },
353
+ "list_vaults": {
354
+ "verdict": "read",
355
+ "reason": "Retrieves Basecamp vaults information without changing vendor state.",
356
+ },
357
+ "list_documents": {
358
+ "verdict": "read",
359
+ "reason": "Retrieves Basecamp documents information without changing vendor state.",
360
+ },
361
+ "get_document": {
362
+ "verdict": "read",
363
+ "reason": "Retrieves Basecamp document information without changing vendor state.",
364
+ },
365
+ "list_uploads": {
366
+ "verdict": "read",
367
+ "reason": "Retrieves Basecamp uploads information without changing vendor state.",
368
+ },
369
+ "get_upload": {
370
+ "verdict": "read",
371
+ "reason": "Retrieves Basecamp upload information without changing vendor state.",
372
+ },
373
+ "list_upload_versions": {
374
+ "verdict": "read",
375
+ "reason": "Retrieves Basecamp upload versions information without changing vendor state.",
376
+ },
377
+ "get_cloud_file": {
378
+ "verdict": "read",
379
+ "reason": "Retrieves Basecamp cloud file information without changing vendor state.",
380
+ },
381
+ "get_google_document": {
382
+ "verdict": "read",
383
+ "reason": "Retrieves Basecamp google document information without changing vendor state.",
384
+ },
385
+ "get_questionnaire": {
386
+ "verdict": "read",
387
+ "reason": "Retrieves Basecamp questionnaire information without changing vendor state.",
388
+ },
389
+ "list_questions": {
390
+ "verdict": "read",
391
+ "reason": "Retrieves Basecamp questions information without changing vendor state.",
392
+ },
393
+ "get_question": {
394
+ "verdict": "read",
395
+ "reason": "Retrieves Basecamp question information without changing vendor state.",
396
+ },
397
+ "list_question_answerers": {
398
+ "verdict": "read",
399
+ "reason": "Retrieves Basecamp question answerers information without changing vendor state.",
400
+ },
401
+ "list_answers": {
402
+ "verdict": "read",
403
+ "reason": "Retrieves Basecamp answers information without changing vendor state.",
404
+ },
405
+ "get_answer": {
406
+ "verdict": "read",
407
+ "reason": "Retrieves Basecamp answer information without changing vendor state.",
408
+ },
409
+ "get_answers_by_person": {
410
+ "verdict": "read",
411
+ "reason": "Retrieves Basecamp answers by person information without changing vendor state.",
412
+ },
413
+ "get_timesheet_report": {
414
+ "verdict": "read",
415
+ "reason": "Retrieves Basecamp timesheet report information without changing vendor state.",
416
+ },
417
+ "get_project_timesheet": {
418
+ "verdict": "read",
419
+ "reason": "Retrieves Basecamp project timesheet information without changing vendor state.",
420
+ },
421
+ "get_recording_timesheet": {
422
+ "verdict": "read",
423
+ "reason": "Retrieves Basecamp recording timesheet information without changing vendor state.",
424
+ },
425
+ "get_timesheet_entry": {
426
+ "verdict": "read",
427
+ "reason": "Retrieves Basecamp timesheet entry information without changing vendor state.",
428
+ },
429
+ "list_gauges": {
430
+ "verdict": "read",
431
+ "reason": "Retrieves Basecamp gauges information without changing vendor state.",
432
+ },
433
+ "list_gauge_needles": {
434
+ "verdict": "read",
435
+ "reason": "Retrieves Basecamp gauge needles information without changing vendor state.",
436
+ },
437
+ "get_gauge_needle": {
438
+ "verdict": "read",
439
+ "reason": "Retrieves Basecamp gauge needle information without changing vendor state.",
440
+ },
441
+ "update_account_name": {
442
+ "verdict": "destructive",
443
+ "reason": "update account name changes existing Basecamp state or removes it.",
444
+ },
445
+ "remove_account_logo": {
446
+ "verdict": "destructive",
447
+ "reason": "remove account logo changes existing Basecamp state or removes it.",
448
+ },
449
+ "update_my_profile": {
450
+ "verdict": "destructive",
451
+ "reason": "update my profile changes existing Basecamp state or removes it.",
452
+ },
453
+ "update_my_preferences": {
454
+ "verdict": "destructive",
455
+ "reason": "update my preferences changes existing Basecamp state or removes it.",
456
+ },
457
+ "update_my_note": {
458
+ "verdict": "destructive",
459
+ "reason": "update my note changes existing Basecamp state or removes it.",
460
+ },
461
+ "enable_out_of_office": {
462
+ "verdict": "destructive",
463
+ "reason": "enable out of office changes existing Basecamp state or removes it.",
464
+ },
465
+ "disable_out_of_office": {
466
+ "verdict": "destructive",
467
+ "reason": "disable out of office changes existing Basecamp state or removes it.",
468
+ },
469
+ "create_project": {
470
+ "verdict": "write",
471
+ "reason": "create project creates or appends Basecamp state; it has side effects.",
472
+ },
473
+ "create_project_from_template": {
474
+ "verdict": "write",
475
+ "reason": "create project from template creates or appends Basecamp state; it has side effects.",
476
+ },
477
+ "update_project": {
478
+ "verdict": "destructive",
479
+ "reason": "update project changes existing Basecamp state or removes it.",
480
+ },
481
+ "update_project_access": {
482
+ "verdict": "destructive",
483
+ "reason": "update project access changes existing Basecamp state or removes it.",
484
+ },
485
+ "trash_project": {
486
+ "verdict": "destructive",
487
+ "reason": "trash project changes existing Basecamp state or removes it.",
488
+ },
489
+ "create_template": {
490
+ "verdict": "write",
491
+ "reason": "create template creates or appends Basecamp state; it has side effects.",
492
+ },
493
+ "update_template": {
494
+ "verdict": "destructive",
495
+ "reason": "update template changes existing Basecamp state or removes it.",
496
+ },
497
+ "delete_template": {
498
+ "verdict": "destructive",
499
+ "reason": "delete template changes existing Basecamp state or removes it.",
500
+ },
501
+ "enable_dock_tool": {
502
+ "verdict": "destructive",
503
+ "reason": "enable dock tool changes existing Basecamp state or removes it.",
504
+ },
505
+ "disable_dock_tool": {
506
+ "verdict": "destructive",
507
+ "reason": "disable dock tool changes existing Basecamp state or removes it.",
508
+ },
509
+ "update_dock_tool": {
510
+ "verdict": "destructive",
511
+ "reason": "update dock tool changes existing Basecamp state or removes it.",
512
+ },
513
+ "reposition_dock_tool": {
514
+ "verdict": "destructive",
515
+ "reason": "reposition dock tool changes existing Basecamp state or removes it.",
516
+ },
517
+ "trash_dock_tool": {
518
+ "verdict": "destructive",
519
+ "reason": "trash dock tool changes existing Basecamp state or removes it.",
520
+ },
521
+ "create_folder": {
522
+ "verdict": "destructive",
523
+ "reason": "create folder changes existing Basecamp state or removes it.",
524
+ },
525
+ "update_folder": {
526
+ "verdict": "destructive",
527
+ "reason": "update folder changes existing Basecamp state or removes it.",
528
+ },
529
+ "delete_folder": {
530
+ "verdict": "destructive",
531
+ "reason": "delete folder changes existing Basecamp state or removes it.",
532
+ },
533
+ "prioritize_assignment": {
534
+ "verdict": "write",
535
+ "reason": "prioritize assignment creates or appends Basecamp state; it has side effects.",
536
+ },
537
+ "deprioritize_assignment": {
538
+ "verdict": "destructive",
539
+ "reason": "deprioritize assignment changes existing Basecamp state or removes it.",
540
+ },
541
+ "reorder_up_next": {
542
+ "verdict": "destructive",
543
+ "reason": "reorder up next changes existing Basecamp state or removes it.",
544
+ },
545
+ "mark_as_read": {
546
+ "verdict": "destructive",
547
+ "reason": "mark as read changes existing Basecamp state or removes it.",
548
+ },
549
+ "create_bookmark": {
550
+ "verdict": "write",
551
+ "reason": "create bookmark creates or appends Basecamp state; it has side effects.",
552
+ },
553
+ "delete_bookmark": {
554
+ "verdict": "destructive",
555
+ "reason": "delete bookmark changes existing Basecamp state or removes it.",
556
+ },
557
+ "create_todolist": {
558
+ "verdict": "write",
559
+ "reason": "create todolist creates or appends Basecamp state; it has side effects.",
560
+ },
561
+ "update_todolist": {
562
+ "verdict": "destructive",
563
+ "reason": "update todolist changes existing Basecamp state or removes it.",
564
+ },
565
+ "reposition_todolist": {
566
+ "verdict": "destructive",
567
+ "reason": "reposition todolist changes existing Basecamp state or removes it.",
568
+ },
569
+ "trash_todolist": {
570
+ "verdict": "destructive",
571
+ "reason": "trash todolist changes existing Basecamp state or removes it.",
572
+ },
573
+ "create_todolist_group": {
574
+ "verdict": "write",
575
+ "reason": "create todolist group creates or appends Basecamp state; it has side effects.",
576
+ },
577
+ "update_todolist_group": {
578
+ "verdict": "destructive",
579
+ "reason": "update todolist group changes existing Basecamp state or removes it.",
580
+ },
581
+ "reposition_todolist_group": {
582
+ "verdict": "destructive",
583
+ "reason": "reposition todolist group changes existing Basecamp state or removes it.",
584
+ },
585
+ "trash_todolist_group": {
586
+ "verdict": "destructive",
587
+ "reason": "trash todolist group changes existing Basecamp state or removes it.",
588
+ },
589
+ "create_todo": {
590
+ "verdict": "write",
591
+ "reason": "create todo creates or appends Basecamp state; it has side effects.",
592
+ },
593
+ "create_todoset_todo": {
594
+ "verdict": "write",
595
+ "reason": "create todoset todo creates or appends Basecamp state; it has side effects.",
596
+ },
597
+ "update_todo": { "verdict": "destructive", "reason": "update todo changes existing Basecamp state or removes it." },
598
+ "complete_todo": {
599
+ "verdict": "destructive",
600
+ "reason": "complete todo changes existing Basecamp state or removes it.",
601
+ },
602
+ "uncomplete_todo": {
603
+ "verdict": "destructive",
604
+ "reason": "uncomplete todo changes existing Basecamp state or removes it.",
605
+ },
606
+ "reposition_todo": {
607
+ "verdict": "destructive",
608
+ "reason": "reposition todo changes existing Basecamp state or removes it.",
609
+ },
610
+ "trash_todo": { "verdict": "destructive", "reason": "trash todo changes existing Basecamp state or removes it." },
611
+ "update_hill_chart_settings": {
612
+ "verdict": "destructive",
613
+ "reason": "update hill chart settings changes existing Basecamp state or removes it.",
614
+ },
615
+ "create_message": {
616
+ "verdict": "write",
617
+ "reason": "create message creates or appends Basecamp state; it has side effects.",
618
+ },
619
+ "update_message": {
620
+ "verdict": "destructive",
621
+ "reason": "update message changes existing Basecamp state or removes it.",
622
+ },
623
+ "pin_message": { "verdict": "destructive", "reason": "pin message changes existing Basecamp state or removes it." },
624
+ "unpin_message": {
625
+ "verdict": "destructive",
626
+ "reason": "unpin message changes existing Basecamp state or removes it.",
627
+ },
628
+ "archive_message": {
629
+ "verdict": "destructive",
630
+ "reason": "archive message changes existing Basecamp state or removes it.",
631
+ },
632
+ "unarchive_message": {
633
+ "verdict": "destructive",
634
+ "reason": "unarchive message changes existing Basecamp state or removes it.",
635
+ },
636
+ "trash_message": {
637
+ "verdict": "destructive",
638
+ "reason": "trash message changes existing Basecamp state or removes it.",
639
+ },
640
+ "create_message_type": {
641
+ "verdict": "write",
642
+ "reason": "create message type creates or appends Basecamp state; it has side effects.",
643
+ },
644
+ "update_message_type": {
645
+ "verdict": "destructive",
646
+ "reason": "update message type changes existing Basecamp state or removes it.",
647
+ },
648
+ "delete_message_type": {
649
+ "verdict": "destructive",
650
+ "reason": "delete message type changes existing Basecamp state or removes it.",
651
+ },
652
+ "create_comment": {
653
+ "verdict": "write",
654
+ "reason": "create comment creates or appends Basecamp state; it has side effects.",
655
+ },
656
+ "update_comment": {
657
+ "verdict": "destructive",
658
+ "reason": "update comment changes existing Basecamp state or removes it.",
659
+ },
660
+ "trash_comment": {
661
+ "verdict": "destructive",
662
+ "reason": "trash comment changes existing Basecamp state or removes it.",
663
+ },
664
+ "create_recording_boost": {
665
+ "verdict": "write",
666
+ "reason": "create recording boost creates or appends Basecamp state; it has side effects.",
667
+ },
668
+ "create_event_boost": {
669
+ "verdict": "write",
670
+ "reason": "create event boost creates or appends Basecamp state; it has side effects.",
671
+ },
672
+ "delete_boost": {
673
+ "verdict": "destructive",
674
+ "reason": "delete boost changes existing Basecamp state or removes it.",
675
+ },
676
+ "create_card_column": {
677
+ "verdict": "write",
678
+ "reason": "create card column creates or appends Basecamp state; it has side effects.",
679
+ },
680
+ "update_card_column": {
681
+ "verdict": "destructive",
682
+ "reason": "update card column changes existing Basecamp state or removes it.",
683
+ },
684
+ "move_card_column": {
685
+ "verdict": "destructive",
686
+ "reason": "move card column changes existing Basecamp state or removes it.",
687
+ },
688
+ "set_card_column_color": {
689
+ "verdict": "destructive",
690
+ "reason": "set card column color changes existing Basecamp state or removes it.",
691
+ },
692
+ "enable_card_column_on_hold": {
693
+ "verdict": "destructive",
694
+ "reason": "enable card column on hold changes existing Basecamp state or removes it.",
695
+ },
696
+ "disable_card_column_on_hold": {
697
+ "verdict": "destructive",
698
+ "reason": "disable card column on hold changes existing Basecamp state or removes it.",
699
+ },
700
+ "watch_column": {
701
+ "verdict": "write",
702
+ "reason": "watch column creates or appends Basecamp state; it has side effects.",
703
+ },
704
+ "subscribe_to_card_column": {
705
+ "verdict": "write",
706
+ "reason": "subscribe to card column creates or appends Basecamp state; it has side effects.",
707
+ },
708
+ "unwatch_column": {
709
+ "verdict": "destructive",
710
+ "reason": "unwatch column changes existing Basecamp state or removes it.",
711
+ },
712
+ "unsubscribe_from_card_column": {
713
+ "verdict": "destructive",
714
+ "reason": "unsubscribe from card column changes existing Basecamp state or removes it.",
715
+ },
716
+ "create_wormhole": {
717
+ "verdict": "write",
718
+ "reason": "create wormhole creates or appends Basecamp state; it has side effects.",
719
+ },
720
+ "update_wormhole": {
721
+ "verdict": "destructive",
722
+ "reason": "update wormhole changes existing Basecamp state or removes it.",
723
+ },
724
+ "delete_wormhole": {
725
+ "verdict": "destructive",
726
+ "reason": "delete wormhole changes existing Basecamp state or removes it.",
727
+ },
728
+ "create_card": {
729
+ "verdict": "write",
730
+ "reason": "create card creates or appends Basecamp state; it has side effects.",
731
+ },
732
+ "update_card": { "verdict": "destructive", "reason": "update card changes existing Basecamp state or removes it." },
733
+ "move_card": { "verdict": "destructive", "reason": "move card changes existing Basecamp state or removes it." },
734
+ "trash_card": { "verdict": "destructive", "reason": "trash card changes existing Basecamp state or removes it." },
735
+ "create_card_step": {
736
+ "verdict": "write",
737
+ "reason": "create card step creates or appends Basecamp state; it has side effects.",
738
+ },
739
+ "update_card_step": {
740
+ "verdict": "destructive",
741
+ "reason": "update card step changes existing Basecamp state or removes it.",
742
+ },
743
+ "complete_card_step": {
744
+ "verdict": "destructive",
745
+ "reason": "complete card step changes existing Basecamp state or removes it.",
746
+ },
747
+ "uncomplete_card_step": {
748
+ "verdict": "destructive",
749
+ "reason": "uncomplete card step changes existing Basecamp state or removes it.",
750
+ },
751
+ "reposition_card_step": {
752
+ "verdict": "destructive",
753
+ "reason": "reposition card step changes existing Basecamp state or removes it.",
754
+ },
755
+ "delete_card_step": {
756
+ "verdict": "destructive",
757
+ "reason": "delete card step changes existing Basecamp state or removes it.",
758
+ },
759
+ "create_campfire_line": {
760
+ "verdict": "write",
761
+ "reason": "create campfire line creates or appends Basecamp state; it has side effects.",
762
+ },
763
+ "create_campfire_upload": {
764
+ "verdict": "write",
765
+ "reason": "create campfire upload creates or appends Basecamp state; it has side effects.",
766
+ },
767
+ "delete_campfire_line": {
768
+ "verdict": "destructive",
769
+ "reason": "delete campfire line changes existing Basecamp state or removes it.",
770
+ },
771
+ "create_schedule_entry": {
772
+ "verdict": "write",
773
+ "reason": "create schedule entry creates or appends Basecamp state; it has side effects.",
774
+ },
775
+ "update_schedule_entry": {
776
+ "verdict": "destructive",
777
+ "reason": "update schedule entry changes existing Basecamp state or removes it.",
778
+ },
779
+ "trash_schedule_entry": {
780
+ "verdict": "destructive",
781
+ "reason": "trash schedule entry changes existing Basecamp state or removes it.",
782
+ },
783
+ "update_schedule_settings": {
784
+ "verdict": "destructive",
785
+ "reason": "update schedule settings changes existing Basecamp state or removes it.",
786
+ },
787
+ "update_calendar": {
788
+ "verdict": "destructive",
789
+ "reason": "update calendar changes existing Basecamp state or removes it.",
790
+ },
791
+ "create_lineup_marker": {
792
+ "verdict": "write",
793
+ "reason": "create lineup marker creates or appends Basecamp state; it has side effects.",
794
+ },
795
+ "update_lineup_marker": {
796
+ "verdict": "destructive",
797
+ "reason": "update lineup marker changes existing Basecamp state or removes it.",
798
+ },
799
+ "delete_lineup_marker": {
800
+ "verdict": "destructive",
801
+ "reason": "delete lineup marker changes existing Basecamp state or removes it.",
802
+ },
803
+ "create_vault": {
804
+ "verdict": "write",
805
+ "reason": "create vault creates or appends Basecamp state; it has side effects.",
806
+ },
807
+ "update_vault": {
808
+ "verdict": "destructive",
809
+ "reason": "update vault changes existing Basecamp state or removes it.",
810
+ },
811
+ "create_document": {
812
+ "verdict": "write",
813
+ "reason": "create document creates or appends Basecamp state; it has side effects.",
814
+ },
815
+ "update_document": {
816
+ "verdict": "destructive",
817
+ "reason": "update document changes existing Basecamp state or removes it.",
818
+ },
819
+ "trash_document": {
820
+ "verdict": "destructive",
821
+ "reason": "trash document changes existing Basecamp state or removes it.",
822
+ },
823
+ "create_attachment": {
824
+ "verdict": "write",
825
+ "reason": "create attachment creates or appends Basecamp state; it has side effects.",
826
+ },
827
+ "create_upload": {
828
+ "verdict": "write",
829
+ "reason": "create upload creates or appends Basecamp state; it has side effects.",
830
+ },
831
+ "update_upload": {
832
+ "verdict": "destructive",
833
+ "reason": "update upload changes existing Basecamp state or removes it.",
834
+ },
835
+ "trash_upload": {
836
+ "verdict": "destructive",
837
+ "reason": "trash upload changes existing Basecamp state or removes it.",
838
+ },
839
+ "create_cloud_file": {
840
+ "verdict": "write",
841
+ "reason": "create cloud file creates or appends Basecamp state; it has side effects.",
842
+ },
843
+ "update_cloud_file": {
844
+ "verdict": "destructive",
845
+ "reason": "update cloud file changes existing Basecamp state or removes it.",
846
+ },
847
+ "create_google_document": {
848
+ "verdict": "write",
849
+ "reason": "create google document creates or appends Basecamp state; it has side effects.",
850
+ },
851
+ "update_google_document": {
852
+ "verdict": "destructive",
853
+ "reason": "update google document changes existing Basecamp state or removes it.",
854
+ },
855
+ "create_question": {
856
+ "verdict": "write",
857
+ "reason": "create question creates or appends Basecamp state; it has side effects.",
858
+ },
859
+ "update_question": {
860
+ "verdict": "destructive",
861
+ "reason": "update question changes existing Basecamp state or removes it.",
862
+ },
863
+ "pause_question": {
864
+ "verdict": "destructive",
865
+ "reason": "pause question changes existing Basecamp state or removes it.",
866
+ },
867
+ "resume_question": {
868
+ "verdict": "destructive",
869
+ "reason": "resume question changes existing Basecamp state or removes it.",
870
+ },
871
+ "update_question_notification_settings": {
872
+ "verdict": "destructive",
873
+ "reason": "update question notification settings changes existing Basecamp state or removes it.",
874
+ },
875
+ "create_answer": {
876
+ "verdict": "write",
877
+ "reason": "create answer creates or appends Basecamp state; it has side effects.",
878
+ },
879
+ "update_answer": {
880
+ "verdict": "destructive",
881
+ "reason": "update answer changes existing Basecamp state or removes it.",
882
+ },
883
+ "create_timesheet_entry": {
884
+ "verdict": "write",
885
+ "reason": "create timesheet entry creates or appends Basecamp state; it has side effects.",
886
+ },
887
+ "update_timesheet_entry": {
888
+ "verdict": "destructive",
889
+ "reason": "update timesheet entry changes existing Basecamp state or removes it.",
890
+ },
891
+ "destroy_timesheet_entry": {
892
+ "verdict": "destructive",
893
+ "reason": "destroy timesheet entry changes existing Basecamp state or removes it.",
894
+ },
895
+ "toggle_gauge": {
896
+ "verdict": "destructive",
897
+ "reason": "toggle gauge changes existing Basecamp state or removes it.",
898
+ },
899
+ "create_gauge_needle": {
900
+ "verdict": "write",
901
+ "reason": "create gauge needle creates or appends Basecamp state; it has side effects.",
902
+ },
903
+ "update_gauge_needle": {
904
+ "verdict": "destructive",
905
+ "reason": "update gauge needle changes existing Basecamp state or removes it.",
906
+ },
907
+ "destroy_gauge_needle": {
908
+ "verdict": "destructive",
909
+ "reason": "destroy gauge needle changes existing Basecamp state or removes it.",
910
+ },
911
+ },
912
+ };
913
+ /** The catalog's summary bound; a longer declared value throws (`src/registry.ts`). */
914
+ const SUMMARY_BUDGET = 120;
915
+ /**
916
+ * Fit a purpose-bearing summary inside the catalog's bound. Basecamp's routing
917
+ * fact is the account a grant reached, which only the operator's purpose can
918
+ * name, so the summary carries the purpose and clipping is this function's
919
+ * job rather than the operator's.
920
+ */
921
+ function boundedSummary(prefix, purpose) {
922
+ const full = `${prefix}${purpose}`;
923
+ if (full.length <= SUMMARY_BUDGET)
924
+ return full;
925
+ return `${full.slice(0, SUMMARY_BUDGET - 1).trimEnd()}…`;
926
+ }
927
+ function usageGuide(purpose, authScope, instructions) {
928
+ const accountInstructions = instructions?.trim();
929
+ // Leads the guide because discovery summarizes a connector by its first
930
+ // content line, and which account a call lands in is the one thing that
931
+ // decides routing between two Basecamp connections (P3).
932
+ const grant = authScope === "personal"
933
+ ? "Each person authorizes this connector separately and picks the account on Basecamp's consent screen, so two people can reach different accounts through it."
934
+ : "One shared authorization, made on Basecamp's consent screen, decides that account for everyone who uses this connector.";
935
+ return `# Basecamp usage
936
+
937
+ One account per authorization: ${purpose}${skill.fragments.guide_0}${grant}${skill.fragments.guide_1}${accountInstructions ? `\n## ${skill.instructionsHeading}\n\n${accountInstructions}\n` : ""}`;
938
+ }
939
+ /** The closed options basecamp() accepts; see `assertKnownOptions`. */
940
+ const BASECAMP_OPTIONS = optionsOf()({ ...PROVIDER_COMMON, ...keys("clientMetadataUrl") });
941
+ /** A maintained Basecamp hosted-MCP connection. */
942
+ export const basecamp = defineProvider({
943
+ name: "basecamp",
944
+ title: "Basecamp",
945
+ kind: "mcp",
946
+ readme: "Basecamp",
947
+ bundle: {
948
+ "baselineGzip": 131228,
949
+ "maxGzip": 191228,
950
+ "note": "./providers/basecamp starts at 131,228 B gzip, measured where it was introduced: a remoteMcp() wrapper like ./providers/revenuecat, so the same shape and the same baseline + 60,000 B policy.",
951
+ },
952
+ skill,
953
+ options: BASECAMP_OPTIONS,
954
+ classify: BASECAMP_CLASSIFICATION,
955
+ create: basecampConnector,
956
+ });
957
+ function basecampConnector(id, options, provider) {
958
+ const purpose = options.purpose.trim();
959
+ const clientMetadataUrl = options.clientMetadataUrl;
960
+ const authScope = options.authScope ?? "shared";
961
+ const connector = remoteMcp(id, {
962
+ url: BASECAMP_MCP_ENDPOINT,
963
+ ...provider.connectorOptions,
964
+ title: options.title ?? "Basecamp",
965
+ description: `Basecamp projects, to-dos, messages, cards, schedules, and files (one account per authorization) — ${purpose}`,
966
+ // OAuth only (P9's headless alternative knowingly missed). Basecamp issues
967
+ // personal access tokens at app.basecamp.com/my/access_tokens, but nothing
968
+ // public says this endpoint accepts one, and a PAT carries no refresh
969
+ // token; shipping a slot for a framing nobody has verified is the
970
+ // borrowed-convention mistake P9 names. The access mode P4 asks for is
971
+ // missing for the same kind of reason: Basecamp advertises a `read` scope
972
+ // beside `full`, but the MCP client requests the scope the server's own
973
+ // challenge names (`mcp full`) ahead of anything configured here, and what
974
+ // `read` permits on this server is unverified — a read-only option would
975
+ // be a label, not a guarantee. The classification fails closed either way.
976
+ auth: {
977
+ type: "oauth",
978
+ ...(clientMetadataUrl !== undefined ? { clientMetadataUrl } : {}),
979
+ scope: FALLBACK_SCOPE,
980
+ },
981
+ requireHttps: true,
982
+ classify: provider.classify,
983
+ usageGuide: {
984
+ content: usageGuide(purpose, authScope, options.instructions),
985
+ // Explicit rather than derived, and purpose-bearing: the derived summary
986
+ // would cut the account sentence mid-clause, and two Basecamp
987
+ // connections differ only by the account each grant reached (P3).
988
+ summary: boundedSummary("One account per grant; get_me names it: ", purpose),
989
+ // Not `required`. Basecamp's own schemas and `get_basecamp_guide` cover
990
+ // each call; this guide carries account routing and the id chain, worth
991
+ // reading before a run rather than before every call.
992
+ },
993
+ });
994
+ return connector;
995
+ }
996
+ /** @deprecated Read `basecamp.definition.classify` instead. Kept for existing imports. */
997
+ export const BASECAMP_VETTED_CATALOG = reviewedCatalog(basecamp.definition.classify, 'defineProvider("basecamp")');