CHANGELOG.md
Language Markdown11.8 KB251 lines
# ChangelogNewest first. Tool contracts (names, parameters and docstrings) are listedwhere they changed; everything else is internal.## UnreleasedInternal cleanup; no tool, parameter, docstring, reply or configurationchanges (the 30-tool contract is now pinned by `tests/tool_api.json`).- The version history moved out of the `server.py` docstring into this file.- Shared helpers replace repeated code: record-id validation, the writeguards (a decorator on each write tool), local timestamp display, stagelookup and name joining; one user cache instead of two; the contact andcompany create/update tools share one implementation.- Imports that sat inside functions are at the top of the module.- Added `pyproject.toml` (ruff and pytest settings), unit tests with a fakedBitrix client and `httpx.MockTransport`, and a CI workflow.## 1.15.1 (2026-07-20)A Bitrix pipeline rename no longer revokes deal writes. `BITRIX_WRITE_FUNNELS`now defaults to categoryIds (`24,26,36`) instead of names: categoryIds arestable across renames, and entries may still be names. `_allowed_funnel_cats()`resolves each entry independently: an entry that cannot resolve is skippedwith a warning instead of disabling all deal writes, and it only errors ifnone resolve. (Funnel 24, then "Partner Outreach", had been renamed to"Partner Tier Upgrade", which broke every deal write.)## 1.15.0 (2026-07-20)Packaging: the `.mcpb` now uses the MCPB uv runtime (`server.type` "uv",manifest 0.4) instead of bundling per-platform native wheels for one pinnedPython. Dependencies live in `mcpb/pyproject.toml` and are resolved on theuser's machine by uv, which also provisions a compatible Python. The bundle isPython-version-agnostic (>=3.10, no cp312 ABI lock) and no longer depends onthe user's system `python` being present or on PATH, which fixes the Windows"Server disconnected" failure (Store stub, wrong-version python, ABI mismatch).One universal bundle for macOS, Windows and Linux; `build.sh` no longer fetcheswheels. Server logic is unchanged.## 1.14.2 (2026-07-09)The write-funnel default now includes "Partner Outreach" (categoryId 24)alongside Quarterly Check-In Flow and Winback, so deal writes are permitted inthat funnel out of the box, matching the deployed `BITRIX_WRITE_FUNNELS` andthe `.mcpb` manifest. No effect where the variable is set explicitly.## 1.14.1 (2026-06-30)Packaging. `BITRIX_DATA_DIR` lets logs and schema snapshots be written to astable, writable location (default next to the server; the `.mcpb` points itat `~/.bitrix24-mcp`) so a packaged install survives updates. Ships as asingle universal desktop extension carrying both the macOS and Windows nativebinaries: the org connector stores one versioned bundle per connector, so one`.mcpb` must serve every platform.## 1.14.0 (2026-06-30)Deploy hardening and expansion, verified against the live REST docs via theb24-dev-mcp documentation server.- Security: tool-call logging redacts customer names as well as email andphone by default (`BITRIX_LOG_ARGS=redact|full|off`), and `calls.jsonl` issize-capped and rotated. Untrusted CRM free text (record fields, timelinebodies, website-chat messages) is wrapped in explicit "untrusted data"fences before it reaches the model. Record IDs are validated as numeric attool entry.- Efficiency: one shared `httpx.AsyncClient` (connection pooling) instead ofone per call. New `bitrix_batch()` wraps `rest.batch` (up to 50 commands)and powers `pipeline_summary` (N stage counts in one call), `search_crm` andbulk user-name resolution. Duplicate field formatters merged.- New reads: `get_chat_transcript` (`imopenlines.crm.chat.get` then`im.dialog.messages.get`) surfaces website-chat conversations bound to alead, deal, contact or company, and `get_timeline` gains a Website chatssection. `get_call_recording` exposes the telephony recording URL and file;`transcribe_call` (opt-in, local mlx-whisper) sits behind`BITRIX_TRANSCRIBE`. `get_record` and `get_products` gain an Order summaryblock (order id, invoice, money totals, partner tier).- New writes (gated by `BITRIX_WRITES`): `set_lead_fields` and`set_deal_fields` set custom fields by display label; `create_contact`,`update_contact`, `create_company` and `update_company` are gatedadditionally by `BITRIX_WRITE_PARTIES` and dup-checked via`crm.duplicate.findbycomm` before create.- Bitrix CoPilot output and transcripts are not REST-readable, and a call's`TRANSCRIPT_ID` has no getter, so CoPilot-style value comes from the modelsummarizing the data these tools expose, not from reading CoPilot itself.## 1.13.1 (2026-06-12)`list_records` with a scoped pipeline no longer builds a cross-funnel stagefilter (it shows the whole funnel unless a stage is given); item extractiontolerates list- or dict-shaped results.## 1.13 (2026-06-12)Deal writes, locked to `BITRIX_WRITE_FUNNELS` (default "Quarterly Check-InFlow,Winback,Partner Outreach"). Every write verifies the deal's categoryId isin that set and refuses otherwise; `create_deal` only creates into thosefunnels. The tools map to the New-Deal form: `set_deal_stage`,`set_deal_title`, `link_deal_contact`, `link_deal_company`,`add_deal_comment`, `assign_deal`, `create_deal`. Contact and company linksresolve an existing record by email, phone or name (no new records arecreated). Gated by `BITRIX_WRITES`.## 1.12 (2026-06-12)`pipeline_summary` and `list_records` accept a `pipeline` (deal funnel name orcategoryId), which scopes deals to that funnel's category and its`DEAL_STAGE_<cat>` stages, so a named customer-success funnel (for exampleQuarterly Check-In Flow) gets correct per-stage counts and record lists. Thefunnel is resolved by fuzzy name match via `crm.category.list` (cached).## 1.11 (2026-06-12)`list_pipelines` (read-only) enumerates deal funnels via `crm.category.list`(each with its stages from `crm.status.list`) and smart processes via`crm.type.list`: the discovery step before scoping `pipeline_summary` or`list_records` to a named non-default pipeline.## 1.10 (2026-06-05)`get_call_history` (read-only) wraps `voximplant.statistic.get` to surface,per call: localized start time, direction, number, duration, the bound CRMentity (type and id; calls bind to whatever record, often a contact), whethera recording URL is present, and Bitrix's own transcript id and pending flag.Requires the telephony scope on the webhook. This is the probe that decidesthe call-transcription architecture (Bitrix transcript or local mlx-whisper)and the read foundation the transcription work reuses.## 1.9 (2026-06-05)First writes. Two lead-only write tools: `add_lead_comment`(`crm.timeline.comment.add`) and `rename_lead` (`crm.item.update` title). Bothhardcode the lead entity; neither can touch deals, contacts or companies.Writes are gated by `BITRIX_WRITES` (default on; set "off" to disable).`rename_lead` refuses to overwrite a title that looks human-authored unless`overwrite_named=True`; all write text is sanitized (control charactersstripped, length capped). Every write is logged to `calls.jsonl` with beforeand after. `get_timeline` gains `full_text` to return untruncated activitybodies for the summarize-to-comment workflow. Call transcription is left outon purpose: CoPilot transcripts are not REST-reachable, and raw audio needs thetelephony scope plus transcription, a separate project.## 1.8.3 (2026-06-05)Packaging: `tzdata` added to requirements (Windows has no system timezonedatabase and zoneinfo needs one there), and a missing timezone database nolonger stops the server from starting. No tool changes.## 1.8.2 (2026-06-05)Security hardening: transport-level httpx exceptions are caught, retried andre-raised as `BitrixError` with the webhook URL redacted (previously theycould propagate raw); pagination and product-row numeric parsing toleratemalformed API values.## 1.8.1 (2026-06-05)Stage history field names vary by entity (leads report `STATUS_ID`, deals`STAGE_ID`); both are now read.## 1.8 (2026-06-05)Reads expansion. `get_products` (`crm.item.productrow.list`) answers "what didthey order"; `get_stage_history` (`crm.stagehistory.list`) shows stagemovement with time in stage; `get_timeline` includes staff notes(`crm.timeline.comment.list`) with author names; user IDs in `get_record` and`list_records` resolve to names (cached); boolean field filters work via aclient-side scan (Bitrix ignores them server-side; the scan is capped at 200records and labeled as such).## 1.7 (2026-06-05)Timezone-correct dates. `list_records` accepts `created_on`, `created_from`,`created_to` and `tz`; day windows are computed in the local zone(`BITRIX_LOCAL_TZ`, default America/Chicago) and passed to Bitrix asoffset-aware ISO 8601 bounds on `createdTime`. Date-filtered queries paginatepast the 50-row cap. Timestamps in `get_record` are displayed in local timewith the raw offset string preserved; list and timeline lines show local time.zoneinfo throughout, no fixed offsets, DST-safe.## 1.6.3 (2026-06-05)Security and ship pass: logs live inside the repo folder (they had beenwritten one level up, a leftover of an old `src/` layout); emails and phonenumbers are masked in `calls.jsonl` entries; the `search_crm` limit is cappedat 50; dependency versions are bounded.## 1.6.2 (2026-06-04)Boolean `UF_*` filters are refused with an explanation: live testing showed`crm.item.list` silently ignores them and returns the unfiltered set.Enum, string and date filters verified working.## 1.6.1 (2026-06-04)`crm.item.list` filters on `UF_*` fields require `useOriginalUfNames=Y`, nowsent by `list_records`. Bitrix HTTP 4xx error bodies are parsed into`BitrixError` messages instead of surfacing raw httpx exceptions, whichembedded the webhook URL, token included, in the error text shown to theclient.## 1.6 (2026-06-04)`find_field` (search field definitions by label or ID fragment across allentity types); `list_records` accepts `field`/`value` to filter on any fieldby its display label, with enum option labels and yes/no booleans translatedautomatically; the field schema is snapshotted to `./schema/` (one dated JSONfile per entity per day) so form-builder drift is diffable over time.## 1.5 (2026-06-04)`get_fields`: the full field schema per entity type via `crm.item.fields`(cached). `get_record` labels custom `UF_*` fields with their configureddisplay names and translates enumeration value IDs into their display labels.## 1.4 (2026-06-04)Assignee support. `pipeline_summary` accepts `assigned_to` ('me', a name, ora numeric user ID, resolved via `user.current`, `user.search` or `user.get`);the new `list_records` tool lists records filtered by assignee and/or stage.User lookups are cached per process.## 1.3 (2026-06-04)`pipeline_summary`: per-stage counts for leads and deals with human-readablestage names via `crm.status.list` (cached per process). Counts come from the`crm.item.list` response envelope's `total`, so they are exact regardless ofpage size.## 1.2 (2026-06-04)Leads (entityTypeId 1) added to all three CRM tools. `search_crm` 'all' coverslead, contact, company and deal; `findbycomm` covers leads. Section headersproperly pluralized.## 1.1 (2026-06-04)CRM reads migrated from the legacy `crm.{entity}.list/get` family (developmenthalted by Bitrix) to the universal `crm.item.*` API. Email and phone lookupuses `crm.duplicate.findbycomm`. Verified against https://apidocs.bitrix24.com(crm-item-list, crm-item-get, crm-duplicate-find-by-comm). Tool contractsunchanged.## 1.0The core read tools: `search_crm`, `get_record`, `get_timeline` and`list_tasks`, over an incoming webhook (`BITRIX_WEBHOOK_URL`) and stdio. Toolnames are semantic rather than Bitrix-specific so the interface survives afuture CRM migration: the implementation behind them is what gets swapped, notthe contracts. Every call is logged to `logs/calls.jsonl` for migrationevaluation.