@setluca/mcp 0.2.1 → 0.3.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 (69) hide show
  1. package/CHANGELOG.md +331 -0
  2. package/LICENSE +21 -0
  3. package/README.md +19 -288
  4. package/dist/annotations.js +33 -18
  5. package/dist/client-address.js +64 -0
  6. package/dist/completions.js +24 -27
  7. package/dist/config.js +89 -38
  8. package/dist/errors.js +94 -13
  9. package/dist/fields.js +68 -0
  10. package/dist/fixed-window.js +46 -0
  11. package/dist/generated/openapi-inputs.js +216 -5820
  12. package/dist/generated/openapi-outputs.js +19014 -14001
  13. package/dist/generated/route-catalog.js +80 -0
  14. package/dist/http.js +107 -44
  15. package/dist/index.js +4 -1
  16. package/dist/oauth-challenge.js +74 -0
  17. package/dist/oauth-resolver.js +58 -61
  18. package/dist/observability.js +30 -15
  19. package/dist/openapi-schema.js +175 -0
  20. package/dist/operations/catalog.js +17 -0
  21. package/dist/operations/groups/analytics.js +20 -10
  22. package/dist/operations/groups/bookings.js +43 -15
  23. package/dist/operations/groups/broadcasts.js +29 -58
  24. package/dist/operations/groups/cadences.js +3 -1
  25. package/dist/operations/groups/callEvents.js +19 -72
  26. package/dist/operations/groups/campaigns.js +28 -32
  27. package/dist/operations/groups/channels.js +23 -0
  28. package/dist/operations/groups/conversations.js +14 -25
  29. package/dist/operations/groups/insights.js +4 -0
  30. package/dist/operations/groups/integrations.js +15 -17
  31. package/dist/operations/groups/knowledge.js +5 -1
  32. package/dist/operations/groups/leads.js +22 -23
  33. package/dist/operations/groups/learning.js +13 -1
  34. package/dist/operations/groups/memory.js +4 -6
  35. package/dist/operations/groups/reports.js +1 -1
  36. package/dist/operations/groups/reviewQueue.js +17 -14
  37. package/dist/operations/groups/safety.js +1 -1
  38. package/dist/operations/groups/voice.js +0 -1
  39. package/dist/operations/groups/webhooks.js +15 -3
  40. package/dist/operations/manifest.js +7 -6
  41. package/dist/operations/registry.js +102 -108
  42. package/dist/operations.js +4 -3
  43. package/dist/optional-field.js +15 -3
  44. package/dist/page-contract.js +74 -0
  45. package/dist/pagination.js +147 -67
  46. package/dist/prompts.js +122 -97
  47. package/dist/rate-limit.js +40 -0
  48. package/dist/remote.js +145 -65
  49. package/dist/resilience.js +107 -52
  50. package/dist/resolvers.js +125 -0
  51. package/dist/scopes.js +70 -17
  52. package/dist/serialization.js +32 -22
  53. package/dist/server.js +148 -132
  54. package/dist/standard-schema.js +215 -0
  55. package/dist/task-tools/analytics.js +145 -86
  56. package/dist/task-tools/bookings.js +168 -81
  57. package/dist/task-tools/cadences.js +30 -45
  58. package/dist/task-tools/calls.js +131 -124
  59. package/dist/task-tools/inbox.js +37 -47
  60. package/dist/task-tools/leads.js +49 -77
  61. package/dist/task-tools/runtime.js +75 -15
  62. package/dist/token-verification.js +47 -0
  63. package/dist/tool-cache.js +3 -2
  64. package/dist/tool.js +151 -96
  65. package/dist/version.js +1 -1
  66. package/package.json +37 -16
  67. package/dist/openapi-zod.js +0 -335
  68. package/dist/page-shape.js +0 -62
  69. package/dist/tsconfig.tsbuildinfo +0 -1
package/CHANGELOG.md CHANGED
@@ -10,6 +10,337 @@ input schema, or changing what a tool does to a workspace.
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [0.3.1] - 2026-10-06
14
+
15
+ ### Fixed
16
+
17
+ - Restore authenticated remote MCP discovery and tool calls on Cloudflare.
18
+ Token checks and tool requests now use a direct service binding to Luca's API,
19
+ avoiding the public API's WAF challenge. Both paths use Cloudflare's supported
20
+ manual redirect mode and still reject redirected responses without forwarding
21
+ credentials.
22
+
23
+ ### Changed
24
+
25
+ - The remote tool catalog includes explicit safety annotations for directory
26
+ review. The protocol suite checks the published `tools/list` shape.
27
+
28
+ ## [0.3.0] - 2026-10-05
29
+
30
+ This is the first Luca MCP release from its own repository. The package and
31
+ hosted connection now share a release path, with checks against the Luca API
32
+ currently in production. The README starts with what people can do in Luca;
33
+ setup and development details live in the guides.
34
+
35
+ ### Breaking
36
+
37
+ - **Tool names are snake_case throughout.** Operation tools used the camelCase
38
+ of their operation id, so the list mixed `luca_analytics_speedImpact` with
39
+ `luca_book_call`. Every name now matches the task tools' casing. 73 tools
40
+ are renamed; the other 130 keep their names. A client or saved prompt that
41
+ calls an old name gets an unknown-tool error. 203 tools ship: 188 operations
42
+ and 15 task tools.
43
+
44
+ <details>
45
+ <summary>Every renamed tool</summary>
46
+
47
+ | Old name | New name |
48
+ | ------------------------------------------------- | -------------------------------------------------- |
49
+ | `luca_leads_fieldDefinitions_list` | `luca_leads_field_definitions_list` |
50
+ | `luca_leads_fieldDefinitions_upsert` | `luca_leads_field_definitions_upsert` |
51
+ | `luca_leads_importPreview` | `luca_leads_import_preview` |
52
+ | `luca_leads_importApply` | `luca_leads_import_apply` |
53
+ | `luca_reviewQueue_list` | `luca_review_queue_list` |
54
+ | `luca_reviewQueue_explain` | `luca_review_queue_explain` |
55
+ | `luca_reviewQueue_approve` | `luca_review_queue_approve` |
56
+ | `luca_reviewQueue_reject` | `luca_review_queue_reject` |
57
+ | `luca_reviewQueue_restore` | `luca_review_queue_restore` |
58
+ | `luca_reviewQueue_media_retry` | `luca_review_queue_media_retry` |
59
+ | `luca_reviewQueue_sla` | `luca_review_queue_sla` |
60
+ | `luca_reviewQueue_objectionVariant` | `luca_review_queue_objection_variant` |
61
+ | `luca_bookings_managedAvailability` | `luca_bookings_managed_availability` |
62
+ | `luca_bookings_outcomeReasons_list` | `luca_bookings_outcome_reasons_list` |
63
+ | `luca_bookings_needsOutcome` | `luca_bookings_needs_outcome` |
64
+ | `luca_bookings_lifecycleAttention` | `luca_bookings_lifecycle_attention` |
65
+ | `luca_bookings_lifecycleResolution` | `luca_bookings_lifecycle_resolution` |
66
+ | `luca_bookings_providerSync_retry` | `luca_bookings_provider_sync_retry` |
67
+ | `luca_bookings_guestLinks_create` | `luca_bookings_guest_links_create` |
68
+ | `luca_bookings_guestLinks_revoke` | `luca_bookings_guest_links_revoke` |
69
+ | `luca_bookings_outcomeReasons_create` | `luca_bookings_outcome_reasons_create` |
70
+ | `luca_bookings_outcomeReasons_update` | `luca_bookings_outcome_reasons_update` |
71
+ | `luca_callEvents_needingFeedback` | `luca_call_events_needing_feedback` |
72
+ | `luca_callEvents_get` | `luca_call_events_get` |
73
+ | `luca_callEvents_byBooking` | `luca_call_events_by_booking` |
74
+ | `luca_callEvents_byLead` | `luca_call_events_by_lead` |
75
+ | `luca_callEvents_feedback` | `luca_call_events_feedback` |
76
+ | `luca_callEvents_summary_generate` | `luca_call_events_summary_generate` |
77
+ | `luca_callEvents_summary_replace` | `luca_call_events_summary_replace` |
78
+ | `luca_callEvents_pushToCrm` | `luca_call_events_push_to_crm` |
79
+ | `luca_callEvents_undoOutcome` | `luca_call_events_undo_outcome` |
80
+ | `luca_callEvents_backfill` | `luca_call_events_backfill` |
81
+ | `luca_campaigns_providerCapabilities` | `luca_campaigns_provider_capabilities` |
82
+ | `luca_campaigns_commentEvents_list` | `luca_campaigns_comment_events_list` |
83
+ | `luca_campaigns_commentSimulationSuite_run` | `luca_campaigns_comment_simulation_suite_run` |
84
+ | `luca_campaigns_setStatus` | `luca_campaigns_set_status` |
85
+ | `luca_webhooks_testDelivery` | `luca_webhooks_test_delivery` |
86
+ | `luca_webhooks_signatureGuide` | `luca_webhooks_signature_guide` |
87
+ | `luca_webhooks_events_bulkReplay` | `luca_webhooks_events_bulk_replay` |
88
+ | `luca_integrations_crm_oauthUrl` | `luca_integrations_crm_oauth_url` |
89
+ | `luca_integrations_crm_connections_webhooksSetup` | `luca_integrations_crm_connections_webhooks_setup` |
90
+ | `luca_integrations_crm_syncRuns_list` | `luca_integrations_crm_sync_runs_list` |
91
+ | `luca_integrations_crm_syncRuns_create` | `luca_integrations_crm_sync_runs_create` |
92
+ | `luca_coach_nicheProfile` | `luca_coach_niche_profile` |
93
+ | `luca_coach_objectionPlaybook` | `luca_coach_objection_playbook` |
94
+ | `luca_coach_postCallSettings` | `luca_coach_post_call_settings` |
95
+ | `luca_coach_postCallCrmMapping` | `luca_coach_post_call_crm_mapping` |
96
+ | `luca_coach_postCallDealSync` | `luca_coach_post_call_deal_sync` |
97
+ | `luca_coach_auditLog` | `luca_coach_audit_log` |
98
+ | `luca_insights_unreadCount` | `luca_insights_unread_count` |
99
+ | `luca_insights_markRead` | `luca_insights_mark_read` |
100
+ | `luca_insights_markActioned` | `luca_insights_mark_actioned` |
101
+ | `luca_learning_frameworkPerformance` | `luca_learning_framework_performance` |
102
+ | `luca_learning_abTests_list` | `luca_learning_ab_tests_list` |
103
+ | `luca_learning_abTests_get` | `luca_learning_ab_tests_get` |
104
+ | `luca_knowledge_approveSuggestion` | `luca_knowledge_approve_suggestion` |
105
+ | `luca_knowledge_rejectSuggestion` | `luca_knowledge_reject_suggestion` |
106
+ | `luca_memory_setArchived` | `luca_memory_set_archived` |
107
+ | `luca_cadences_rescueStart` | `luca_cadences_rescue_start` |
108
+ | `luca_analytics_speedImpact` | `luca_analytics_speed_impact` |
109
+ | `luca_analytics_callIntelligence` | `luca_analytics_call_intelligence` |
110
+ | `luca_analytics_callIntelligenceCalls` | `luca_analytics_call_intelligence_calls` |
111
+ | `luca_analytics_ghostedLeads` | `luca_analytics_ghosted_leads` |
112
+ | `luca_analytics_trustScore` | `luca_analytics_trust_score` |
113
+ | `luca_analytics_leadScore` | `luca_analytics_lead_score` |
114
+ | `luca_analytics_lossReasons` | `luca_analytics_loss_reasons` |
115
+ | `luca_analytics_contentAttribution` | `luca_analytics_content_attribution` |
116
+ | `luca_analytics_contentPerformance` | `luca_analytics_content_performance` |
117
+ | `luca_analytics_topicPerformance` | `luca_analytics_topic_performance` |
118
+ | `luca_analytics_benchmarkConsent` | `luca_analytics_benchmark_consent` |
119
+ | `luca_analytics_learningInsights` | `luca_analytics_learning_insights` |
120
+ | `luca_analytics_crmSyncHealth` | `luca_analytics_crm_sync_health` |
121
+ | `luca_analytics_objectionDrilldown` | `luca_analytics_objection_drilldown` |
122
+
123
+ </details>
124
+
125
+ - **A tool call with an argument the tool does not define fails.** It used to
126
+ drop the field and run, so a typo such as `limt` silently fell back to the
127
+ default. The error names the field, and no request is sent.
128
+ - **Seven further tools need `confirm: true`:**
129
+ `luca_bookings_lifecycle_resolution`, `luca_bookings_provider_sync_retry`,
130
+ `luca_call_events_summary_replace`, `luca_call_events_push_to_crm`,
131
+ `luca_webhooks_test_delivery`,
132
+ `luca_integrations_crm_connections_webhooks_setup`, and
133
+ `luca_integrations_crm_sync_runs_create`. Each writes to a connected
134
+ calendar or CRM, or posts to an outside URL. 27 operations are now gated,
135
+ which covers every write that can reach past the workspace.
136
+ - **`luca_find_leads` takes `channel` as one of `telegram`, `instagram`,
137
+ `messenger`, or `whatsapp`,** the values `GET /api/leads` accepts. Any other
138
+ value fails before a request is sent.
139
+ - **The analytics task tools return what they could read.**
140
+ `luca_analytics_rollup`, `luca_analytics_magic_monday`, and
141
+ `luca_analytics_deep_dive` used to fail when any one read failed. Each
142
+ section is now optional, and a `failedSections` list names the section and
143
+ the error for every read that failed. The call fails only when every read
144
+ does, or when a read is refused with a 401 or a scope 403.
145
+ - **Six more tools need `confirm: true`:** `luca_leads_import_apply`,
146
+ `luca_leads_consents_grant`, `luca_bookings_cancel`,
147
+ `luca_webhooks_subscriptions_create`, `luca_webhooks_subscriptions_update`,
148
+ and `luca_campaigns_set_status` when it sets `published` (resuming sends). A
149
+ client that called these without it now gets a tool error asking for it.
150
+ - **Two tools are gone.** `luca_integrations_crm_oauthCallback` and
151
+ `luca_integrations_crm_webhooks_record` were provider callbacks that an agent
152
+ had no reason to call.
153
+ - **`openWorldHint` is now `false` for most tools.** It is `true` only for the
154
+ 25 operations, and the task tools built on them, that can reach past the
155
+ workspace: messaging a lead, posting to an outside URL, or writing to a
156
+ connected calendar or CRM.
157
+ - **The remote resolver API changed.** `apiKeyResolver(settings)` and
158
+ `oauthResolver(settings)` take the API base URL, auth header, and timeout as
159
+ one settings object, and a `TokenResolver` returns `Option<LucaConfig>`.
160
+ `ResolvedIdentity` and `chainResolvers` are gone. Pick a resolver by the
161
+ token's shape with the new `looksLikeDeveloperKey`.
162
+ - **`LucaConfig.apiKey` is a `Redacted<string>`.** A custom `TokenResolver`
163
+ wraps the key with `Redacted.make` from `effect/Redacted`, so a logged or
164
+ inspected config prints `<redacted>` instead of the key.
165
+ - **Booking and moving a call need `confirm: true`:** `luca_book_call`,
166
+ `luca_reschedule_call`, `luca_bookings_create`, and `luca_bookings_update`
167
+ now match `luca_bookings_cancel`. A booking moves the lead to booked and
168
+ notifies the coach's webhook subscribers; a move updates the connected
169
+ calendar and the lead's reminder. All four now report `destructiveHint: true`.
170
+ To migrate, show the coach the slot, then pass `confirm: true` once they
171
+ approve it. A call without it returns a tool error and sends nothing.
172
+ - **`luca_close_call_loop` needs `confirm: true` when `attendance` is
173
+ `no_show`.** That report can start recovery that messages the lead. Other
174
+ attendance values run without it.
175
+ - **`provider` on `luca_book_call` and `luca_reschedule_call` is one of
176
+ `manual`, `cal_com`, `calendly`, `google_calendar`, `iclosed`, or
177
+ `gohighlevel`.** Any other value fails before a request is sent. It used to
178
+ be skipped by the availability check without a word.
179
+ - **The hosted server checks developer keys.** A `luca_` key is checked with
180
+ one `GET /api/capabilities` before a server is built, so a made-up key gets
181
+ 401 instead of a tool list. `apiKeyResolver(settings, fetchImpl?, checks?)`
182
+ now resolves asynchronously and can fail with
183
+ `TokenVerificationUnavailable`.
184
+ - **An empty `idempotencyKey` fails before a request is sent** on every task
185
+ tool that takes one. It used to reach the API as a blank header.
186
+ - **`RemoteRateLimiters` has a required `perTokenAddress` limiter,** charged
187
+ per client address on requests that carry a token.
188
+ - **`luca_call_events_feedback` asks for confirmation on a `no_show` report.**
189
+ A no-show can start recovery messaging, so that outcome now needs
190
+ `confirm: true`. Other outcomes need no confirmation, and the tool stays on
191
+ the `luca:draft` scope. `luca_close_call_loop` keeps its own no-show gate.
192
+
193
+ ### Added
194
+
195
+ - Every tool declares the lowest OAuth scope that can call it in
196
+ `_meta.securitySchemes`. On the hosted server, a call that fails because the
197
+ token was revoked or its scopes fall short returns
198
+ `_meta["mcp/www_authenticate"]`, so a client such as ChatGPT can ask the coach
199
+ to reconnect. See [docs/remote.md](./docs/remote.md#per-tool-scopes-and-re-authorization).
200
+ - Two prompts, `luca-plan-campaign` and `luca-plan-broadcast`, which take a
201
+ campaign or broadcast through a dry run or preview before anything goes live.
202
+ - Server instructions, returned on `initialize`, naming the starting tools, the
203
+ confirm rule, and how to treat lead-authored text.
204
+ - Cancelling a tool call now aborts the request it has in flight.
205
+ - `luca_book_call` takes an optional `bookingTypeId` and sends it with the
206
+ booking. The API requires one for a `google_calendar` booking, so that
207
+ provider could not be booked through the tool before.
208
+ - Two tools: `luca_learning_ab_tests_list` and `luca_learning_ab_tests_get`
209
+ read the coach's A/B tests and per-variant results. Creating, running, and
210
+ adopting a test stay in the Luca app.
211
+ - Four channel tools under the new `channels:read` API-key scope, granted from
212
+ `luca:read` up: `luca_channels_list` and `luca_channels_get` read the coach's
213
+ connected accounts with their status and health, `luca_channels_catalog`
214
+ says which channels can be connected yet, and `luca_channels_features` says
215
+ what each provider supports. Connecting, pausing, and repairing an account
216
+ stay in the Luca app.
217
+ - The 15 task tools declare an `outputSchema`, so a client can read their
218
+ `structuredContent` without guessing its shape.
219
+ - `createRemoteResponder` in `@setluca/mcp/remote` returns the remote handler as
220
+ an Effect, for a host that runs its own Effect program around each request.
221
+ `createRemoteHandler` still returns a plain fetch handler.
222
+ - `createLocalRateLimits` in `@setluca/mcp/remote` builds the in-memory
223
+ limiters, and `createRemoteHandler` and `createRemoteResponder` take them as
224
+ an optional `rateLimits`, so a host can keep one set across requests.
225
+
226
+ ### Changed
227
+
228
+ - A tool call stops after 45 seconds in total, retries and waits included, and
229
+ each attempt still stops after 30. A write that times out says its outcome is
230
+ unknown and names the idempotency key that makes a second send safe. The
231
+ timeout error carries the last 429 or 5xx the call saw.
232
+ - A 429, 502, 503, or 504 retries even when its body is HTML or plain text, and
233
+ honors `Retry-After`. It used to fail as a decode error.
234
+ - A paged list that stops early keeps the pages it fetched and leads with a
235
+ `warning` that says the list is incomplete and how to fetch the rest. It
236
+ stops when a page fails or can't be read, when the server repeats a cursor
237
+ or sends an empty page with one, or after 120 seconds in total. A later page
238
+ refused with 401, or 403 for a missing scope, fails the whole call instead,
239
+ so the client gets the challenge that sends it back through sign-in.
240
+ - Lead-authored text is marked untrusted per operation instead of only on
241
+ reads, so a write that returns lead text is framed too. 51 operations are
242
+ framed, among them every booking route that returns the invitee's
243
+ cancellation reason (`luca_bookings_list`, `luca_bookings_get`,
244
+ `luca_bookings_create`, `luca_bookings_update`, `luca_bookings_cancel`,
245
+ `luca_bookings_lifecycle_attention`, and
246
+ `luca_bookings_lifecycle_resolution`), `luca_bookings_needs_outcome`,
247
+ `luca_analytics_ghosted_leads`, and the five lead writes that echo the lead
248
+ record back: `luca_leads_create`, `luca_leads_update`,
249
+ `luca_leads_import_preview`, `luca_leads_import_apply`, and
250
+ `luca_leads_identities_attach`. Those five now list `full_content` as their
251
+ data sensitivity. `luca_book_call`, `luca_reschedule_call`, and
252
+ `luca_analytics_deep_dive` are framed as well.
253
+ - A task tool that returns partial results fails the whole call when the API
254
+ answers 401, or 403 with `scope_required` or `needs_scope`, so the agent
255
+ sees a credentials problem instead of a missing section. This covers the
256
+ three analytics task tools, `luca_close_call_loop`, the explanations of
257
+ `luca_triage_inbox`, and the guest links of `luca_reschedule_call`. Other failures still come back as a section error.
258
+ - `luca_book_call` and `luca_reschedule_call` skip the availability check when
259
+ the call carries an `idempotencyKey`, so a retry of a booking that went
260
+ through reaches the API's replay instead of reporting the slot taken.
261
+ `luca_book_call` sends `provider` with the booking; `luca_reschedule_call`
262
+ uses it only for the availability check and keeps the booking's provider.
263
+ - `luca_book_call` with a `bookingTypeId` checks the slot against that booking
264
+ type's own schedule instead of the calendar provider's free time. An
265
+ availability check refused with 401, or 403 for a missing scope, fails the
266
+ call instead of booking unchecked.
267
+ - `luca_close_call_loop` says what filing starts: no-show recovery, a call
268
+ summary that can sync to the CRM, and a CRM deal-stage update.
269
+ - The workflow prompts point at the task tools, such as
270
+ `luca_morning_report` and `luca_draft_reply`, instead of the raw operations.
271
+ - Completion suggestions match the typed prefix in any case.
272
+ - `luca-rescue-silent-leads` applies its `days` window to the conversation
273
+ list step, not only to the heading.
274
+ - `luca_analytics_deep_dive` no longer requires `question`.
275
+ - `luca_close_call_loop` reports a failed call-event lookup as
276
+ `feedbackError`. It used to read as "no call event for this booking".
277
+ - A failed resource read answers with a JSON-RPC error: resource-not-found for
278
+ a missing record, an invalid request carrying the same
279
+ `mcp/www_authenticate` challenge a tool error carries for a refused token or
280
+ missing scope, and an internal error for anything else.
281
+ - An API response that is not JSON is reported by its length. The error no
282
+ longer quotes the body, text no Luca schema shaped.
283
+ - Calls to the Luca API refuse to follow redirects, so a key or token is never
284
+ sent to a host the config did not name.
285
+ - The hosted server:
286
+ - checks an OAuth token within 5 seconds and answers 503 if it cannot;
287
+ - treats only a 401 from the token check as a refused token, so a misrouted
288
+ or overloaded API no longer sends every client back through sign-in;
289
+ - limits each bearer token to 60 requests a minute, so coaches who
290
+ share an address no longer share a budget, and also limits requests with
291
+ a token to 600 a minute per address, so made-up tokens run out too;
292
+ - limits requests without a token to 600 a minute per address;
293
+ - refuses a token over 4,096 characters, or an OAuth token that is not
294
+ three base64url segments, with 401 `invalid_token` and no API call;
295
+ - leaves `scope` out of an `invalid_token` challenge, so a client that
296
+ reconnects asks for the scope it had rather than a lower one;
297
+ - answers 429 with "Too many requests";
298
+ - reads the client address from `CF-Connecting-IP` only and ignores
299
+ `X-Forwarded-For`, which any client can set;
300
+ - answers 500 to every request when a production deploy is missing any of
301
+ its three rate-limit bindings, or when `MCP_PUBLIC_ORIGIN` is not an
302
+ http(s) origin with no path;
303
+ - serves its discovery documents to any origin, CORS preflight included.
304
+ - The package no longer depends on Zod directly.
305
+ - Tool input schemas now advertise closed objects
306
+ (`additionalProperties: false`) and keep each field's format, title, and
307
+ description.
308
+ - The docs describe Luca as a DM sales platform.
309
+ - The hosted Worker reads `LUCA_AUTH_HEADER` and `LUCA_REQUEST_TIMEOUT_MS` with
310
+ the stdio parser. `bearer` now works there, and an unknown value answers 500
311
+ instead of sending keys in a header the API ignores.
312
+ - The `WWW-Authenticate` challenge on a tool error now carries
313
+ `realm="luca-mcp"`, like the transport's 401.
314
+ - A tool call missing a path parameter fails as a tool input error before any
315
+ request is sent.
316
+ - Prompts no longer use em dashes, and every workflow prompt ends with the same
317
+ safety rules.
318
+ - A task tool's read-only, confirm, and untrusted-content flags now come from
319
+ the operations it composes, so a task tool cannot claim to be safer than the
320
+ routes it calls.
321
+ - Cancelling a resource read aborts the request it has in flight.
322
+ - A write that needs an idempotency key and gets none now mints a fresh key
323
+ each time the call runs, rather than once per built request.
324
+ - A cancelled tool call is logged with `outcome: "interrupted"`.
325
+ - Each tool's `x-luca-redacted-fields` list now comes from the API's
326
+ `sensitive()` markers at generation time instead of a hand-written list, and
327
+ `redaction:check` is gone. The lists did not change.
328
+ - **`luca_reschedule_call` checks the booking's own schedule.** It reads the
329
+ booking first and checks the new time against the slots of its booking type,
330
+ or the provider calendar when the booking has no booking type or cannot be
331
+ read.
332
+ - **More routes frame lead-written text as untrusted.** CRM rows, broadcast
333
+ recipients, campaign enrollments, and integration sync records now carry the
334
+ untrusted-content marker and `full_content` data sensitivity.
335
+ - **`luca_rescue_silent_leads` rejects empty lead ids.**
336
+
337
+ ### Fixed
338
+
339
+ - The hosted server logs `mcp.token_verification_unavailable`, with the error
340
+ message and no token, when the token verifier cannot answer and the request
341
+ gets a 503.
342
+ - Resource registration shares one read path for fixed and templated URIs.
343
+
13
344
  ## [0.2.1] - 2026-08-22
14
345
 
15
346
  ### Added
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Luca
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.