# Changelog

All notable changes to the NeuBird MCP Server will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [5.0.0] - 2026-10-18

### Changed

- With a `neubird login` (no `NEUBIRD_EMAIL`/`NEUBIRD_PASSWORD`), the login decides the instance. `switch_instance` uses the login, from any profile (`neubird login <url> --profile <name>`), whose URL matches the instance asked for. When there is none it fails without switching and names the `neubird login` command to run; it no longer sends the current token to the other instance, where it could only be rejected. At startup, an instance saved by an earlier `switch_instance` is used only when some login covers it, with that login's token; otherwise the server uses the login's own instance and logs that it ignored the saved one. Email/password setups are unchanged.
- A 401 from NeuBird now suggests `neubird login <instance>` for that instance, alongside checking `NEUBIRD_EMAIL`/`NEUBIRD_PASSWORD`. `get_guidance`'s authentication advice says the same.
- **Breaking: the nine tools that create, change or delete a tenant's configuration (`create_connection`, `add_connection_to_project`, `remove_connection_from_project`, `create_project`, `update_project`, `delete_project`, `create_skill`, `update_skill_status`, `delete_skill`) are off by default.** They are not listed, and a direct call returns an error naming the tool as unavailable without calling NeuBird. Set `NEUBIRD_ENABLE_CONFIG_TOOLS=true` to turn them on. A tool is only listed and run once it is classified, so a tool added later stays off until it is. `get_guidance` points to the web console instead of to tools that are off.
- A hosted (HTTP) server no longer lists `switch_instance` or `get_incident_report`, which cannot succeed there; a direct call returns an unavailable error.

### Added

- Every tool carries a `title` and MCP annotations with explicit `readOnlyHint`, `destructiveHint`, `idempotentHint` and `openWorldHint`. Clients that run read-only tools without asking, and ask before destructive ones, now tell the two apart; the Claude and OpenAI connector directories require these on every tool.
- `get_rca` shows as an interactive NeuBird RCA card in clients that render MCP Apps (Claude web, desktop and mobile, among others): the root cause first, confidence and time metrics, the timeline and sources, and buttons that open the investigation in NeuBird, check the RCA (`get_rca_verification`), ask a follow-up, and load the rest of a long report. The card is the `ui://neubird/rca/v<version>` resource (the vendored @neubirdai/mcp-views version, so a host that caches resources by URI loads a new card after an upgrade) (`resources/list`, `resources/read`), built in neubird-ui-core and vendored in `views/`; `get_rca`'s tool definition names it in `_meta.ui.resourceUri`. A client that declares the `io.modelcontextprotocol/ui` extension also gets `structuredContent` (the same object as the text) on `get_rca`; every other client, Claude Code among them, gets the text alone, as before. `get_rca` also adds `ui_link`, the session's console link, for every client. The card loads nothing from the network and holds no credentials: it reads the tool result, and its buttons call this server's tools through the client.
- `get_rca` returns `ui_link`, the investigation in the NeuBird console.
- `rate_investigation` records a thumbs-up or thumbs-down on an investigation, with the areas it concerns and a note: the rating the NeuBird UI and the Slack and Teams apps record. The RCA card's Rate button uses it.

### Fixed

- `get_session_link` builds its link only from id-like `session_uuid` and `project_uuid` values, as every other link does, and returns an error for anything else instead of putting it in the URL.
- `list_projects`, `get_project_details` and `list_connection_resources` return `created_at` and `updated_at` in ISO 8601 UTC (`2026-10-13T23:11:18.404Z`) instead of the backend's day-first `13/10/26 23:11:18.404431`, which read as a US date for days up to 12. A value in any other form is passed through as before. Every tool's times are now ISO 8601.
- `NEUBIRD_LOG_LEVEL` and `NEUBIRD_LOG_ENABLED` now work. The server read only `HAWKEYE_LOG_LEVEL` and `HAWKEYE_LOG_ENABLED`, which still work, but the `NEUBIRD_*` names win when both are set.
- Docs: the instruction pages are replaced by a skills guide (`guides/using-skills.md`), and `examples/testing-instructions.md` is removed. Every page now describes skills, with the real skill types and a testing flow that works: create the skill in a test project, rerun a past session, compare RCAs. The tool reference documents all 57 tools: it adds the 15 that had no section and drops `create_aws_connection` and `create_datadog_connection`, which never existed (use `create_connection`). Every parameter list now matches the tool's schema. The supported connections list matches `create_connection`, and troubleshooting covers `neubird login` and the saved instance. The installation page explains `NEUBIRD_ENABLE_CONFIG_TOOLS`, the guides that create connections, projects or skills say those tools are off by default, the tool reference marks them and adds `rate_investigation`, and troubleshooting covers the "is not available on this server" error.

## [4.2.1] - 2026-10-13

### Fixed

- `get_connection_info`, `list_connections` and `list_project_connections` return their times in ISO 8601 UTC (`2026-10-06T00:01:47.000Z`), as the other tools do, instead of the backend's Unix-seconds strings (`"1791244907"`). This covers `updated_at` and, on `get_connection_info`, `sync_updated_time` and `last_full_sync_time`. A time the backend has not set is still left out.
- Docs: the tool reference no longer lists a `wait_for_completion` parameter on `rerun_session`, `continue_investigation` and `wait_for_connection_sync`, nor `max_wait_seconds` on `rerun_session`; none of them exists. `wait_for_connection_sync` lists `poll_interval_seconds` and `rerun_session` lists `project_uuid`.

## [4.2.0] - 2026-10-12

### Added

- Two read-only tools for a project's service map, the map of services and the calls between them that NeuBird's scanner builds from connected sources (AWS, Azure, Kubernetes, Datadog, Dynatrace, Tempo). Neither runs a model. `find_services` lists or searches one tier of the map (`search` on the name, `category`, `tier_number`, paged with `start`/`limit` and `next_start`) and returns each service's `id` (NeuBird's own, `smn_...`), `name`, `native_id`, `category`, `node_type`, up to 10 `tags` and `tier`, with the map's `tiers` on the first page. A search returns only the project's own services: the backend searches names across projects, so a match that is not marked as this project's (another project's service, or one that names no project) is left out and counted in `other_projects_skipped`. A project with no map returns an empty list and a `note` saying so. `get_service_dependencies` reads one service's direct neighbours by that id: `depends_on` (the services its edges lead to) and `depended_on_by` (the services whose edges lead to it), each with the kind of edge as `relation` (for a `contains` edge the lists mean "contains" and "is contained in" rather than dependency), the full counts, and at most 100 neighbours a side (`..._truncated` when cut). It is one hop: call it again with a neighbour's id to walk further. An id the map does not hold returns `SERVICE_NOT_FOUND`. A node's raw source record, its alert statistics and other projects' ids are never returned, and every result stays under 45,000 characters.
- `list_tasks` (read-only) lists a project's saved tasks: each with its `uuid`, `title`, `category`, `agent` (the id of the agent the task is configured with; absent when it has none), `prompt` (up to 500 characters) and, when it has one, its `schedule`. NeuBird's own internal tasks are left out. Tasks are created, scheduled and run in the NeuBird UI: this server lists no agents and starts no agent or task.
- `list_sessions` takes an optional `task_uuid`: the runs of one saved task (from `list_tasks`). Rows carry `task_uuid` when the backend returns it; pass a run's `session_uuid` to `get_rca` to read its result, or to `get_investigation_status` while it runs. A task's runs are task sessions, so `task_uuid` combined with `only_uninvestigated: true`, or with a `session_type` other than `SESSION_TYPE_TASK` or `SESSION_TYPE_ACTION`, matches nothing: the request is sent as asked and the result's `task_filter_note` says why it is empty.
- Four read-only tools for the incidents and alerts NeuBird holds. `list_incidents` and `list_alerts` list a project's incidents (groups of related alerts) and alerts, filtered by `status`, `risk`, `search`, `date_from`/`date_to` (and, for alerts, `incident_id`, `external_id`, `alert_types`, `priority`), paged with `start`/`limit` and `next_start`. By default they ask for open rows, the same query the NeuBird web UI makes, and leave out ignored and noise ones: pass `status` to choose statuses, or `include_closed: true` for every status (it has no effect when `status` is given, and the result's `note` says so); `include_ignored` and `include_noise` add those rows. Rows carry status `INCIDENT_STATUS_OPEN` or `INCIDENT_STATUS_RESOLVED`; `INCIDENT_STATUS_INVESTIGATED` and `INCIDENT_STATUS_UNINVESTIGATED` are accepted but match nothing on current deployments, so a row's `investigated` field says whether it was investigated (an empty result for either status says so in its `note`). `list_alerts` finds alerts not yet investigated as the rows whose `investigated` is false, and with `external_id` turns a monitoring system's id into NeuBird's alert. `get_incident` reads one incident with a page of its alerts, whatever their status, paged by the backend; `get_alert` reads one alert, with its enriched data on `include_details`. Ids are NeuBird's own; a row's `session_uuid`, when present, is the investigation to pass to `get_rca` or `get_investigation_status`, and `investigated` says whether one exists. Every result stays under 45,000 characters (long text is cut with `<field>_truncated: true`), an alert's raw payload is never returned, and an unknown id is reported as not found with the list tool to use (an id containing `/`, which the backend's single-row routes cannot take, is reported as such, with `search` on the list tool as the way to find it).
- `get_incident_summary` reads a project's incident and investigation metrics for a time window (`date_from`/`date_to`; the last 24 hours when neither is given): open alerts and incidents, investigations run, incidents prevented and investigated, noise reduction, average triage time, MTTR reduction, cost savings and agent confidence, each with its `delta` from the previous period. `include_history` adds each metric's time buckets. The numbers come from two backend reads, each one attempt of at most 8 seconds: when one fails the other's metrics are returned with `unavailable` naming what is missing and a `note` giving the reason; when both fail the tool returns an error.
- Three tools for an investigation that is still running. `steer_investigation` sends it a note (`message`, at most 4,096 characters and 4,096 UTF-8 bytes) to redirect it or hand it a fact; it starts nothing and costs no model call of its own. The result is `status: "queued"`, not a delivery: the investigation reads the note at its next step, which can take minutes, and a note still waiting when the investigation finishes is dropped without notice. `ask_investigation` asks it a `question` about itself, answered by the backend from the investigation's transcript without changing its course; a question costs one model call on the backend and only one can be in flight per investigation. It listens on the investigation's live stream, for at most `wait_seconds` in all (0 to 45, default 30), and returns `status: "answered"` with the `answer` (cut at 20,000 characters), `status: "failed"` with `backend_error` when the backend could not answer, or `status: "pending"`. A pending answer cannot be fetched while the investigation runs, and is lost if the investigation finishes before it is ready. A question repeated word for word within the same investigation can get the earlier answer back; rephrase it to be sure. `get_investigation_notes` (read-only) lists a prompt cycle's delivered notes and answered questions in order, each with `kind`, `text`, `answer` and `round` (`answer_missing: true` on a question whose answering failed). Notes are recorded when the investigation finishes, so the list is empty while it runs: it confirms a delivery, or shows a late answer, only afterwards. Both write tools send their text exactly once and never re-send it. When nothing is running they say so and point to `continue_investigation`; when the investigation engine refused the text they say nothing was queued; when the backend's answer leaves it unknown whether the text was queued (the backend could not reach the investigation engine, a timeout, a dropped connection), the error says so, and that sending again may deliver a note twice or cost a second model call.
- Three read-only tools for what stands behind a finished analysis, each keyed by `session_uuid` and an optional `prompt_cycle_id` (the session's latest prompt cycle when omitted). `get_rca_verification` reads the independent review of the analysis: `status` is `none`, `reviewed` (with `verdict` `PASS`, `FAIL` or `INCONCLUSIVE`, a `tldr` and the `reasoning`, cut at 20,000 characters), `running` (with `stale: true` and a `note` once it has been marked running for more than 20 minutes, longer than a review is allowed to take), `failed` or `unreadable`. `get_rca_explanation` reads the step-by-step explanation: a `summary`, an `outcome` and the `steps` (tool, command, reason, conclusion, kind, basis, and `from_prompt_cycle_id` when a step rests on evidence from an earlier prompt cycle), 30 at a time with `start`/`limit` and `next_start`. `get_remediation` reads the remediation record: the session whose final answer is the runbook (`remediation_session_uuid`, read with `get_rca`; that session may not appear in `list_sessions`) and the steps marked done. A session id is returned whole or left out, never cut. None of them starts a review, an explanation or a remediation run; those are started from the NeuBird UI.
- `create_manual_investigation` and `continue_investigation` take an optional `attachments`: 1 to 5 pieces of text (logs, stack traces, configs) for the investigation to read, each `{ name?, text }` with `text` of 1 to 200,000 characters and at most 500,000 characters in all. Over a limit is a validation error and nothing is sent. The text is passed in the call; there is no file path input, since the server can run remotely, where a path would name a file on the server. Each attachment goes with the prompt as plain text (a `name` becomes its first line, `File: <name>`), in the same single prompt request as before. The result adds `attachments_sent` and, when any were sent, `attachments_note`: NeuBird does not acknowledge attachments, and text over about 12,000 bytes may be set aside for the investigation to read on demand instead of inline, depending on the deployment. Without `attachments` the request is what it was.

### Changed

- **`investigate_alert` no longer starts a paid investigation for an id it cannot find.** It now looks the alert up first, by NeuBird's alert id (from `list_alerts`) and then by the monitoring system's id, in one attempt each of at most 8 seconds. When the alert already has an investigation, nothing is started and the result is `status: "already_investigated"` with that `session_uuid` (pass the new `force_new: true` to start another). When several alerts share the monitoring-system id, nothing is started and the result lists up to 5 `candidates` (`error: "AMBIGUOUS_ALERT"`). When no alert has the id (`ALERT_NOT_FOUND`) or the lookup fails (`ALERT_LOOKUP_FAILED`), nothing is started unless the new `allow_unlinked: true` is passed, which starts an investigation whose prompt only mentions the id, as before, and returns `linked: false`. A started investigation returns `alert` (`id`, `external_id`, `title`) and `linked: true`.
  - `investigate_alert` starts nothing for an alert that is marked investigated but carries no investigation of its own (one investigated with its incident, for example). The result is `status: "already_investigated"`; when the alert belongs to an incident, that incident is read once (at most 8 seconds) and its investigation is returned as `session_uuid`, and otherwise the message says the investigation could not be located and points to `list_sessions`. `force_new: true` still starts another, and the `already_investigated` message now says that is the way forward when the existing investigation failed or no longer exists.
  - `investigate_alert` reports `ALERT_LOOKUP_FAILED`, not `ALERT_NOT_FOUND`, when the backend answers the lookup with alerts that do not carry the id asked for (a backend that cannot look an alert up by id). `ALERT_NOT_FOUND` is kept for an empty answer.
  - `investigate_alert` puts the alert's title into the prompt as one line of at most 300 characters: line breaks and runs of whitespace become single spaces, so a title from the monitoring system cannot add lines of its own to the prompt.
- `list_sessions` with `only_uninvestigated`: the hint and the tool description point to `list_alerts` (the rows whose `investigated` is false) for the alert ids, instead of telling the caller to fetch an id from the monitoring tool. What the filter sends is unchanged. `get_guidance` describes the same flow.
- `get_incident_report` (still an error: the backend removed the report) now points to `get_incident_summary` first, then to `list_sessions` and `get_session_report`.
- `get_guidance`: the `instructions` topic is now `skills`, and its answers name the skill tools. Next-step hints from `create_project`, `add_connection_to_project` and `wait_for_project_ready` point to `create_skill`.

### Removed

- The five project-instruction tools: `list_project_instructions`, `create_project_instruction`, `update_project_instruction_status`, `delete_project_instruction` and `validate_instruction`. Skills replaced instructions in the product, and these tools were deprecated aliases of the skill tools. Use `list_skills`, `create_skill`, `update_skill_status`, `delete_skill` and `validate_skill`; the skill tools take `SKILL_TYPE_*` types and an `enabled` flag where the old ones took `INSTRUCTION_TYPE_*` and `INSTRUCTION_STATUS_*`. The server now has 57 tools.

### Fixed

- `get_rca` returns a session's final answer when the session has no sectioned analysis. The run of a saved task (a cost report, a health check), and any session whose summary holds a `Title` section at most, came back as its title alone, while the report it wrote sat in the session's final answer. `get_rca` now reads that from the session overview (one more read, made only for these sessions) and returns it after the title, with `source: "final_answer"`, the `prompt_cycle_id` that wrote it (the latest one with a final answer) and a `note`; a sectioned analysis is returned as before, with `source: "summary"`. When there is no final answer either, or the overview cannot be read, the title is returned with a `note` saying there is no analysis text to show, not an error. The overview's rounds, tool calls and PDF are never returned.
- `get_rca` serves a long text whole, in pages: a text that does not fit in one result used to be cut with no way to read the rest. `rca_truncated`, `rca_total_chars` and the new `next_offset` say there is more; pass `next_offset` as the new optional `offset` to read on (`max_chars`, 1000-40000, sets a smaller window). A cut `rca` no longer ends with an ellipsis, so the pages join into the exact text.
- `investigate_alert` says investigations typically take 2-5 minutes, as `create_manual_investigation` does, instead of 30-90 seconds, which live runs exceeded.
- `investigate_alert` links the investigation to its alert: the prompt request carries the alert's NeuBird id (`alert_ids`), so the session is the alert's investigation instead of a manual session whose prompt merely mentioned the id. A monitoring-system id is resolved to NeuBird's alert first, and the prompt names the alert's title and ids.

## [4.1.0] - 2026-10-10

### Added

- `get_skill` reads one skill in full, in pages, including attached reference files. `list_skills` shortens long skills to stay under the client's tool-result limit; `get_skill` takes `offset`, `max_chars`, an optional `file_path` or `file_index` (for files with very long paths) and `files_offset` (to page the reference-file listing), and returns `next_offset` until the whole text is read. Every result stays under 50,000 characters.
- On macOS, the credential-file fallback reads the Falcon CLI (>= 1.0.94) login from the Keychain (service `ai.neubird.falcon-cli`) when the file's `access_token` is empty. The Keychain account follows the file that was read: a `NEUBIRD_PROFILE` with no `neubird-<profile>.json` falls back to `neubird.json`, as before, and reads the `default` login, so the URL and the token always come from the same login. Set `NEUBIRD_NO_KEYRING=1` to disable the read.

### Changed

- `list_skills` notes about shortened skills now point at `get_skill` instead of the web UI.
- `get_chain_of_thought`, `get_investigation_queries`, `get_investigation_sources`, `inspect_session` and `get_investigation_status` (with `include_full_details`, live or not) keep every result under 45,000 characters, whatever the session holds; one live session's overview came to 383 KB, which Claude Code replaces with a file path. Every cut is flagged with a sibling `<field>_truncated: true`. Caps: round and step reasoning text 4,000 characters; a tool call's query, reason, excerpt, `result_summary` and `error_message` 2,000; raw tool `result` 300; `prompt_text` 8,000, sized by its JSON length; `current_step` 300; category 80; tool and source names 200; cycle ids 100. `inspect_session` `session_info` carries only its known fields, each capped. A list that still does not fit loses items from the end and says so with `<list>_total`, `<list>_returned`, `next_start` and a `note` (which names the caller's `limit` when that ended the page); the five tools take optional `start` and `limit` to read the rest. Other shortened lists report their size: `categories_total`, `available_prompt_cycle_ids_total` (the last 100 are listed, also when a cycle is not found), `unique_sources_total`, `all_sources_returned`, `prompt_cycles_returned`. As a last resort the result's longest strings are shortened (listed in `truncated_by_size_guard`) and trailing items of the paged list dropped, with `next_start` kept true. `category_filter` also accepts a category as `categories` lists it, `ui_link` is built only from id-like project and session ids (otherwise omitted), and a cycle id cut for display (`prompt_cycle_id_truncated`) can be passed back to select its cycle. A next page is tied to what it indexes: the `note` of `get_chain_of_thought`, `get_investigation_queries` and `get_investigation_sources` names the `prompt_cycle_id` (and `category_filter`) to keep on the next call, since without it the latest cycle with data is read and that can change while a session runs; a paged `get_investigation_status` summary carries `steps_kind` (`tool_calls` for a live run, `rounds` once it is over) and `prompt_cycle_id`; and a `start` past the end of a list returns a `note` saying so and to read again from `start: 0`, instead of an unexplained empty page. `get_rca` and `get_session_summary` are held to the same 45,000 characters: `get_rca` cuts an `rca` that does not fit to what the other fields leave (`rca_truncated`, `rca_total_chars`; `section_titles` still lists every section), and `get_session_summary`, which returns the report twice (`sections`, and `analysis`, the sections joined), leaves `analysis` out when both do not fit (`analysis_omitted: true`; `get_rca` returns it). Results that fit are unchanged.
- `add_connection_to_project` no longer waits for the project by default: `wait_for_ready` now defaults to `false`, and the call returns a readiness snapshot (`ready`, `state`, `training_state`, `next_steps`). MCP clients used to time out during the up-to-300 s wait. Use `wait_for_project_ready` to wait, or pass `wait_for_ready: true` for the old behavior. A project in an error state, or a failed snapshot read, no longer fails an add that succeeded: the result carries a `warning`.
- The prompt tools (`rerun_session`, `continue_investigation`, `investigate_alert`, `create_manual_investigation`) keep reading the stream for 1.5 seconds after raven's first frame, to catch an error that follows at once, so they return about 1.5 s later than before. `NEUBIRD_PROMPT_SETTLE_MS` sets the window (`0` disables it, the maximum is `10000`).

### Fixed

- `get_rca` `session_info` carries the session's `name`, `session_type` and `investigation_status` instead of empty strings. They come from one extra single-cycle inspect read; if it fails, the three fields are omitted and the RCA is returned intact.
- `list_sessions` with `only_uninvestigated` returns not-started sessions of both `SESSION_TYPE_ALERT` and `SESSION_TYPE_INCIDENT` (one request, using raven's `session_types`); it used to ask for incidents only, so alert sessions never appeared. `filters_applied` reports `session_types` instead of `session_type`.
- `rerun_session` establishes that a session is idle before it posts, and refuses the rerun when it cannot: a rerun of a running session is a second paid investigation. It reads the session's cycles in one page of 500 and, when `pagination.total` says more exist, the last one, so a running 21st cycle is no longer missed; when raven sends no `pagination.total` it looks one cycle past the page, and refuses if one follows or the look cannot be read. A session whose own `investigation_status` is in progress is refused whatever its cycle list says, since a run can be reported before its prompt cycle is listed. Because a session whose run never started can report that for good, the refusal (for a running session or a running latest cycle) says how to get out: check `get_investigation_status`, and if it shows no progress, stop the investigation in the NeuBird UI and re-run it, or start a new investigation. It refuses a manual (`SESSION_TYPE_USER`) session before posting, pointing at `continue_investigation` and `create_manual_investigation`, instead of passing on raven's HTML 500. An unknown project is reported as such, not as "Session not found".
- Prompt tools report an error that follows the first frame at once (for example an exhausted LLM budget behind a `phase` frame). Only falcon's `type: "error"` frame or an untyped frame is read as the run's error: a failed tool call (`tool_done` carrying `error`), which the run recovers from, no longer reports the prompt as rejected while the investigation carries on. An HTML error body (a 500 page, a proxy page) is replaced by `NeuBird returned HTTP <status> (<statusText>)`.
- `list_sessions` with `date_from`/`date_to`: the page walk no longer stops at a row created before `date_from` (raven pages by `updated_at`; it stops once a row was last updated before `date_from`); a datetime without an offset is read as UTC; `date_from`/`date_to` accept only `YYYY-MM-DD` or a full ISO 8601 datetime, and `2026-09` is rejected before raven is called.
- A backend error text is cut at 500 characters, in a tool error's message and in its `details.reason` (raven's reason is cut wherever a tool error carries it): a 400 with a 60 KB plain-text body, a long JSON `error` and a long `Investigation failed: …` frame used to produce tool errors of 60,000 characters.
- `rerun_session` no longer calls a stream that ended before its first frame a rejection. It says the stream ended before NeuBird confirmed the rerun and that the investigation may have started, with the status tool to check before sending again.
- The prompt tools no longer read a run's final `STATUS_DONE` frame as a rejection when raven set an `error` on it (its partial-success path, "Internal server error occurred during filter chain processing.").
- `get_rca`, the quiet-stream check in `get_investigation_status` and the readiness snapshot in `add_connection_to_project` make one attempt of at most 8 seconds instead of up to four of 30 s, so a slow `inspect` or project list no longer delays the answer. On failure they behave as before (the RCA without `name`, `session_type` and `investigation_status`; the live data; `ready: null` with a warning). A session `name` in `get_rca` is cut at 500 characters.
- The size guard on the five investigation read tools no longer rewrites one list's `next_start` when it trims another (it turned `investigation_steps`' `next_start: 60` negative) or adds a `_total` to a list that does not page.
- `get_investigation_status` no longer reports a finished investigation as in progress, or an older prompt cycle's progress, while its live stream stays open. When nothing in the stream has shown the run advancing for 45 seconds (a progress, tool-call or sources frame does; a `:keepalive` or an unreadable frame only shows the connection is up, and raven keeps sending keepalives on the stream of a run that has ended), the tool reads raven's overview, at most once per 45 seconds. If the run has settled it stops the stream and answers from the overview; if a newer prompt cycle is running it stops the old stream and follows the new one; if raven says the run is still going, or the overview cannot be read, it keeps the live data. Of two overlapping status calls, one whose read returns after the other has stopped or replaced the stream no longer stops the replacement or reports its own older snapshot.
- The tools that read a session's overview (`get_investigation_status`, `get_chain_of_thought`, `get_investigation_queries`, `get_investigation_sources`, `get_follow_up_suggestions`, `inspect_session`) read it to `pagination.total` instead of trusting one page of 500 cycles, so "the latest cycle" is the session's latest on a session longer than a page; the status tool could stop the live stream of the real latest cycle and attach to an old one. A session whose cycles cannot all be read (a page fails or comes back empty before the total, or there are more than ten pages) is an error, not a partial list, and the error says so: `Session <id> has <total> prompt cycles; could not read them all (<cause>).` The tools that take a `prompt_cycle_id` can still read a cycle that is among the pages that were read (the error says how many cycles that is; nothing is read past the tenth page); such a result leaves out `available_prompt_cycle_ids`, since the cycles read are not the session's latest, and gives `available_prompt_cycle_ids_total` and a `prompt_cycles_note` instead. `get_follow_up_suggestions` lists at most the last 100 cycle ids when a `prompt_cycle_id` is not found, like the other tools.
- `inspect_session` lists a long session's newest prompt cycles instead of its oldest. It asks inspect for 500 cycles instead of raven's default page of the 20 oldest, reads the tail with one more request when that page is still not the whole session, and, when the cycles do not all fit the result, keeps the latest ones (oldest first within the list). `prompt_cycle_count` is raven's total, and `prompt_cycles_returned` with a `prompt_cycles_note` ("the latest N of M") says when the list is not all of them; when raven sends no total for a full page, the note says the list is the first N and the session may have more.

### Security

- HTTP transport binds each session to the user who opened it. A bearer for another user on an existing `Mcp-Session-Id` gets `404 Session not found` (the client starts its own session) instead of reaching the owner's cached data and saved default project. A refreshed bearer is validated before it replaces the session's token, so one that fails is `401` and the session keeps its last good token.
- HTTP transport validates a first-party bearer only at a trusted issuer's userinfo: NeuBird's Auth0 tenants (`https://neubirdai-api.us.auth0.com/` and `https://devbirdai-api.us.auth0.com/`), `OAUTH_ISSUER`, and each entry of the new comma-separated `AUTH0_ISSUERS`. A token whose `iss` is anything else is `401 Bearer token issuer is not trusted`, and no request is made to it. The server used to call whatever `iss` the unverified token named, so anyone running their own userinfo endpoint could be taken for any user, and a caller could point the server at any URL. A deployment whose first-party tokens come from any other issuer must list it in `AUTH0_ISSUERS`.
- Logs mask credentials at every level: the login password, connection secrets (API keys, app keys, client secrets, service account keys, tokens, the AWS external ID), OAuth tokens, `Authorization` headers, and credentials inside URLs (`user:password@` and secret query parameters such as `token=`). `HAWKEYE_LOG_LEVEL=debug` no longer writes them to stderr.

## [4.0.0] - 2026-10-07

### Removed

- **Breaking: HTTP transport no longer accepts email/password headers.** `/mcp` accepts only OAuth bearer tokens; `X-NeuBird-Email`/`X-NeuBird-Password` and legacy `X-Hawkeye-*` headers get `401`. Stdio mode is unchanged.
- `apply_session_instruction` was removed. It has no skill equivalent, because skills are project- or organization-scoped, not per session. Create the skill on the project with `create_skill`, then call `rerun_session` or `create_manual_investigation`.

### Added

- HTTP transport advertises OAuth protected-resource metadata (RFC 9728) so MCP clients can discover the auth server, and sends `WWW-Authenticate` on all `/mcp` 401s.
- HTTP transport exchanges MCP-audience tokens through the neubird-auth on-behalf-of flow.
- New skill tools: `create_skill`, `list_skills`, `delete_skill`, `update_skill_status`, `validate_skill`.

### Changed

- Project-instruction tools are deprecated aliases for the new skills API (`/v1/skill`). Skill types now include `SKILL_TYPE_INCIDENT_CREATION_RULE` and `SKILL_TYPE_NOISE_FILTER`.
- `list_sessions` uses the v2 session list; date filters are applied client-side.
- `get_rca`, `get_session_summary` and `get_rca_score` read the v2 session summary (fixes 405s).
- **Breaking output change:** `get_session_report` is built from the v2 session summary (the v1 report endpoint returns empty data). Each report no longer includes `prompt` or `create_time`; the response adds `sessions_with_time_saved`, and each report can carry an `error` field when its summary could not be read.
- `get_incident_report` now returns a clear error: the backend removed the organization-wide incident report. The tool stays registered so existing client configs keep working.
- `external_tool_name` is documented as ignored by the backend.
- `rerun_session` no longer accepts `wait_for_completion`/`max_wait_seconds` (they were ignored; callers that still send them are not rejected, the values are dropped silently).

### Fixed

- Invalid bearer tokens return `401` (with the OAuth challenge) instead of `500`.
- `rerun_session` actually reruns the investigation (it previously called a read-only endpoint). It reports reruns the backend rejects, and refuses to rerun a session whose investigation is still in progress.
- Session inspect sends the `request_id` the backend requires.
- `get_project_details` reads the project from the `spec` returned by the details endpoint; `update_project` no longer blanks project instructions.
- `get_connection_info` no longer returns connection credential/config blocks (`*_connection_info`); it returns identity and status fields only.
- Resource types display their names; `list_connection_resources` reports `has_more` correctly.
- `update_skill_status` no longer resends skill files.
- Connection type values match the backend (`CONNECTION_TYPE_KUBERNETES`, `CONNECTION_TYPE_LOG_DATADOG`).
- `list_projects` filtering recognizes the backend `PROJECT_STATE_*` values.
- Tests are isolated from the developer's local NeuBird environment and credential files; `build/` is no longer tracked.
- Security: MCP SDK, axios, fast-uri, proxy-addr, form-data, hono, body-parser, qs and ip-address updated to clear Dependabot/CVE advisories; Docker image moved to an Alpine 3.22 base.

## [3.1.0] - 2026-04-21

### Added

- **Credential-file fallback at startup.** When stdio-mode `NEUBIRD_EMAIL`/`NEUBIRD_PASSWORD` env vars are not set, the server now reads `~/.config/neubird/neubird.json` (the file the Falcon CLI writes with `neubird login`). Lets MCP client plugins spawn the server without declaring an `env` block — important for Claude Code plugins that can't resolve `${user_config.*}` tokens at spawn time.
- **Profile selection via `NEUBIRD_PROFILE`.** Reads `~/.config/neubird/neubird-<profile>.json`, falling back to the default file if the profile-specific one is missing.
- **Windows platform support** for credential lookup (`%APPDATA%\neubird\`). Matches Falcon's `os.UserConfigDir()` behavior.
- **Bearer-token credentials.** When the credential file has an `access_token` but no `ace_creds`, the server uses the bearer token directly and skips login. `expires_at` is honored with a 5-minute safety buffer so expired tokens are rejected early with a clear error instead of a cryptic 401.

### Changed

- Startup error message now points at `neubird login` when neither env vars nor the credential file provide valid credentials.
- Removed misleading "NEUBIRD_EMAIL: ✓ Set / ✗ Not set" echo at module-import time — it looked only at env vars and would lie when credentials came from the file.

### Compatibility

No breaking changes. Env-var-based deploys (server mode, K8s) keep working exactly as before; env always takes precedence over the file.

## [3.0.0] - 2026-04-21

### Changed

- **Rebranded from Hawkeye to NeuBird.** Package published under the `@neubirdai` npm scope as `@neubirdai/mcp-server-neubird`. Unscoped `mcp-server-neubird` is published as a thin redirect shim that depends on the scoped package; `hawkeye-mcp-server` continues to be published as a legacy wrapper. All three package names install and run the same server.
- **Default tool prefix is now `neubird_`** (e.g., `neubird_investigate_alert`). Set `NEUBIRD_TOOL_PREFIX=hawkeye` to restore the legacy `hawkeye_*` prefix.
- **Environment variables prefer `NEUBIRD_*`.** `HAWKEYE_EMAIL`, `HAWKEYE_PASSWORD`, `HAWKEYE_BASE_URL`, and other legacy `HAWKEYE_*` variables are still accepted; `NEUBIRD_*` takes precedence when both are set.
- **HTTP auth headers prefer `X-NeuBird-*`.** Legacy `X-Hawkeye-Email` / `X-Hawkeye-Password` headers are still accepted.

### Compatibility

No breaking changes to runtime behavior. Existing `hawkeye-mcp-server` installations, `HAWKEYE_*` env vars, and `X-Hawkeye-*` headers continue to work.

## [2.0.13] - 2025-11-24

### Added

- **State file persistence**: Settings now persist across server restarts in `~/.hawkeye-mcp/state.json`
  - Default project UUID persists when set via `hawkeye_set_default_project`
  - Base URL persists when switched via `hawkeye_switch_instance`
  - No more manual MCP config file edits needed
  - State file automatically created on first use

- **UI link in investigation status**: `hawkeye_get_investigation_status` now includes `ui_link` field
  - Direct link to view investigation in Hawkeye web UI
  - Format: `https://{instance}/console/project/{project_uuid}/session/{session_uuid}?tab=results`

### Changed

- **Configuration priority**:
  - Default project: state file > env var > auto-select first project
  - Base URL: state file > env var > default sandbox URL
  - State persists across restarts without config changes

## [2.0.10] - 2025-11-24

### Changed

- **Simplified investigation architecture**: Removed worker thread approach for manual investigations
  - Removed `StreamingService`, `InvestigationTracker`, and worker thread infrastructure
  - Manual investigations now use fire-and-forget approach with API polling
  - Users should poll with `hawkeye_inspect_session` or `hawkeye_get_chain_of_thought` to monitor progress
  - Simplified codebase, removed memory isolation issues
  - Cleaned build artifacts - package size reduced from 723.3 kB to 680.1 kB

### Removed

- Worker thread-based streaming for manual investigations
- `src/services/streaming.service.ts`
- `src/services/investigation-tracker.ts`
- `src/workers/stream-consumer.ts`
- `src/utils/progress-tracker.ts`
- `stream_progress` parameter from `hawkeye_investigate_alert`

### Fixed

- Investigation progress tracking now queries API directly instead of relying on isolated worker thread memory
- `hawkeye_get_investigation_status` now properly reflects investigation state from API

## [2.0.9] - 2025-11-24

### Note
- Published with stale build artifacts, superseded by 2.0.10

## [2.0.8] - 2025-11-23

### Fixed

- **hawkeye_create_manual_investigation now supports wait_for_completion**: Added missing `wait_for_completion` and `max_wait_seconds` parameters
  - Tool now properly handles `wait_for_completion: true` by polling the investigation tracker
  - Polls every 5 seconds until completion or timeout
  - Returns full RCA when investigation completes
  - Returns timeout response with progress if max wait time exceeded
  - Previously these parameters were silently ignored, causing confusion

### Added

- **Polling logic for manual investigations**: When `wait_for_completion: true`:
  - Automatically polls investigation tracker every 5 seconds
  - Fetches and returns RCA on completion
  - Throws error if investigation fails
  - Returns timeout response with current progress if exceeded `max_wait_seconds`

## [2.0.7] - 2025-11-23

### Added

- **Enhanced Debug Logging**: Added comprehensive logging throughout worker thread stream consumer
  - Worker lifecycle logs (start, connection, completion)
  - Chunk reception and processing logs
  - Progress update logs with message previews
  - Error logs with full stack traces
  - Session UUID included in all worker log messages for traceability

### Changed

- **Improved Debugging**: All worker thread operations now log to stderr for troubleshooting
  - Logs include: Base URL, project UUID, stream connection status
  - Each log prefixed with `[Worker <session_uuid>]` for easy filtering
  - Chunk size and message count tracking
  - Stream end notifications with statistics

### Documentation

- **Added Claude Code Logging Reference**: New `CLAUDE_CODE_LOGGING.md` document
  - Comprehensive guide to finding and reading Claude Code logs
  - MCP server logging configuration and testing
  - Quick reference commands for log searching
  - Locations of conversation logs and MCP server output

## [2.0.6] - 2025-11-23

### 🎉 Fixed - Background Stream Processing

This release fixes the critical streaming issue where the `/v1/inference/session` API response was not being consumed, causing "stream has been aborted" errors.

### Added

- **Worker Thread Stream Consumer**: New background worker that consumes streaming responses
  - Created `src/workers/stream-consumer.ts` - Dedicated worker thread for stream consumption
  - Created `src/services/investigation-tracker.ts` - In-memory state tracker for ongoing investigations
  - Worker processes SSE stream data and updates tracker in real-time

- **Live Progress Tracking**: Investigations now tracked in-memory with real-time updates
  - `investigationTracker` stores progress updates, status, and completion messages
  - Progress updates available immediately when polling with `hawkeye_get_investigation_status`
  - Tracks: starting → in_progress → completed/failed states

### Changed

- **`create-manual-investigation` now spawns worker thread**:
  - Creates session via `/v1/inference/new_session`
  - Spawns background worker to consume `/v1/inference/session` stream
  - Returns immediately with session_uuid
  - Worker handles all streaming data asynchronously

- **`get-investigation-status` enhanced**:
  - First checks in-memory tracker for live progress
  - Falls back to API query if not tracked
  - Returns progress percentage based on progress update count
  - Shows current step from latest progress message

### Technical Details

- **Root Cause**: `/v1/inference/session` returns a **stream** of `ProcessPromptResponse` objects
- **Previous Behavior**: Stream was opened but never consumed, causing connection errors
- **New Behavior**: Worker thread consumes entire stream in background, updating shared state
- **Architecture**:
  - Main thread: Returns immediately to MCP client
  - Worker thread: Consumes stream, sends messages back to main thread
  - Shared state: `investigationTracker` Map stores live progress
  - Polling: LLM polls every 10-15 seconds to get latest state

### Fixed

- ✅ "stream has been aborted" errors when creating manual investigations
- ✅ Blocking behavior while waiting for stream to complete
- ✅ No feedback during investigation progress
- ✅ MCP protocol limitation (no streaming to client) now handled elegantly

## [2.0.5] - 2025-11-23

### Fixed

- **Removed remaining `wait_for_completion` references from guidance service documentation**
  - Removed references at line 253 in connection sync best practices
  - Removed references at line 530 in onboarding workflow instructions
  - These were documentation strings that suggested using the removed parameter
  - Ensures LLMs no longer see any mentions of `wait_for_completion` in help/guidance

## [2.0.2] - 2025-11-23

### 🚨 BREAKING CHANGE: Removed wait_for_completion

This is a **critical** fix that removes the problematic `wait_for_completion` parameter that was causing investigations to block unnecessarily.

### Removed

- **Removed `wait_for_completion` parameter** from ALL investigation tools:
  - `hawkeye_create_manual_investigation` - NO MORE wait_for_completion
  - `hawkeye_investigate_alert` - NO MORE wait_for_completion
  - `hawkeye_continue_investigation` - NO MORE wait_for_completion
  - `hawkeye_rerun_session` - NO MORE wait_for_completion
- **Removed `max_wait_seconds` parameter** from all investigation tools

### Changed

- **ALL investigations now return immediately** with clear polling instructions
- All investigation tools now return:
  - `session_uuid` - For tracking the investigation
  - `status: 'in_progress'` - Current status
  - `estimated_completion_time` - How long to expect (e.g., "2-5 minutes")
  - `next_steps` - Clear instructions on what to do next
  - `polling_instructions` - Structured polling guidance with tool name and interval
- LLMs are now **instructed to poll every 10-15 seconds** using `hawkeye_get_investigation_status`
- Once status is `completed`, LLMs should call `hawkeye_get_rca` to retrieve results

### Fixed

- TypeScript interfaces in `src/types/mcp.ts` no longer define `wait_for_completion`
- Zod validation schemas in `src/utils/validation.ts` no longer include `wait_for_completion`
- Tool implementations no longer have conditional wait logic - always return immediately
- MCP tool schema generation will no longer show `wait_for_completion` as an option

### Enhanced

- **`hawkeye_get_investigation_status` now shows real-time progress**:
  - Checks `prompt_cycle` messages for latest `CONTENT_TYPE_PROGRESS_STATUS` updates
  - Humanizes technical progress messages with emojis and clear descriptions:
    - `PromptGate` → "🔧 Preparing telemetry sources"
    - `SelectTablesFirst` → "🔍 Classifying datasources"
    - `SQLSplitExecute` → "🔎 Consulting telemetry"
    - `SplitAnswer` → "🧠 Analyzing telemetry data"
  - Falls back to `chain_of_thoughts` if no progress messages available
  - Provides users with visibility into what Hawkeye is currently doing

## [2.0.0] - 2025-11-23

### 🎉 Major Feature: Real-Time Streaming Investigation Progress

This is a **major** release that fundamentally improves the investigation user experience by providing real-time progress updates during investigations.

### Added

- **🌊 NEW: Streaming Investigation Service** (`src/services/streaming.service.ts`)
  - Real-time Server-Sent Events (SSE) streaming from Hawkeye API
  - Parses progress updates, interim analysis, and completion messages
  - Async generator for clean iteration over progress updates

- **📊 NEW: Progress Tracker Utility** (`src/utils/progress-tracker.ts`)
  - Humanizes technical progress messages into user-friendly updates
  - Maps component actions to emojis and clear descriptions
  - Tracks elapsed time, phase progression, and query/analysis counts
  - Examples:
    - `PromptGate (Preparing Telemetry Sources)` → `🔧 Preparing telemetry sources [2s]`
    - `SQLSplitExecute (Consulting Telemetry)` → `🔎 Consulting telemetry (Query 7) [1m 30s]`

- **Enhanced `hawkeye_create_manual_investigation`**
  - New `stream_progress` parameter (default: `true`)
  - Returns progress log, elapsed time, and investigation summary when streaming
  - Provides phase-by-phase visibility into investigation workflow

- **Enhanced `hawkeye_investigate_alert`**
  - New `stream_progress` parameter (default: `true`)
  - Streams progress for new alert investigations
  - Same real-time feedback as manual investigations

### Changed

- **Better User Experience** - Users no longer wait 5-10 minutes with no feedback
- **Progress Visibility** - See exactly what Hawkeye is doing in real-time:
  - 🔧 Preparing telemetry sources
  - 📚 Loading investigation context
  - 🔍 Classifying datasources
  - ⚡ Generating investigation queries
  - 🔎 Consulting telemetry (with query counts)
  - 🧠 Analyzing telemetry data (with analysis counts)
  - 📝 Summarizing results
- **Progress Estimates** - Estimated progress percentage (0-100%) based on current phase
- **Detailed Summaries** - Get counts of steps, queries executed, and analyses performed

### Technical Details

- New service: `StreamingService` - handles SSE parsing and async iteration
- New utility: `ProgressTracker` - humanizes progress messages with emojis and timing
- Updated `ToolServices` interface to include `streamingService`
- Updated `HttpClient` with `getAxiosInstance()` method for streaming support
- Updated both investigation tools to support streaming by default
- Added comprehensive streaming test: `test-streaming-manual-investigation.mjs`

### Benefits

- 🚀 **Better UX** - Real-time feedback eliminates anxiety during long investigations
- 📊 **Transparency** - Users see exactly what Hawkeye is doing and how long it takes
- 🎯 **Progress Tracking** - Estimated completion percentage and phase information
- 📝 **Detailed Logs** - Complete progress log for debugging and analysis
- ⚡ **Default On** - Streaming is enabled by default, users can opt-out if needed

### Migration Notes

- No breaking changes to existing tool signatures
- `stream_progress` parameter is optional and defaults to `true`
- Users can set `stream_progress: false` to use original polling behavior
- All existing code continues to work without modification

## [1.5.0] - 2025-11-23

### Added
- **NEW TOOL: `hawkeye_set_default_project`** - Set the default project for the current session
  - Allows switching between projects without specifying project_uuid on every operation
  - Use natural language: "Switch to project HTM-Azure"
  - All tools that accept optional `project_uuid` will use the default when not specified
- **Enhanced `hawkeye_list_projects`** - Now shows which project is the default
  - Added `is_default` flag to each project in the response
  - Renamed `default_project` to `default_project_uuid` for clarity
  - Makes it easy to see which project is currently active

### Benefits
- 🎯 **Better workflow** - Switch project context once, then investigate without repeating project UUID
- 📋 **Clearer state** - Always know which project is the default when listing projects
- 💬 **Natural interaction** - Say "switch to project X" instead of looking up UUIDs

### Technical Details
- New tool: `src/tools/set-default-project.ts`
- Updated: `src/tools/index.ts` - Added tool and enhanced list projects output
- Total tools: 40 (was 39)

## [1.4.0] - 2025-11-21

### Added
- **🎯 Comprehensive RCA with Corrective Actions** - `hawkeye_get_rca` now returns formatted analysis including:
  - Incident summary and description
  - Timeline of events
  - Evidence and root cause
  - **Corrective actions with bash scripts** - executable commands to fix issues
  - **Time savings metrics** - shows manual vs Hawkeye investigation time
- **📊 NEW TOOL: `hawkeye_get_rca_score`** - Get quality scores for investigations:
  - Accuracy scores (root cause correctness, impact analysis, timeline)
  - Completeness scores (data sources, remediation steps, prevention measures, business impact)
  - Qualitative feedback (trust level, missing elements, improvement suggestions)

### Changed
- **Upgraded to `/v1/inference/session/summary` API** - Now uses the same endpoint as the Hawkeye UI for consistency
- **Updated SessionSummary types** - Added `analysis`, `time_saved_summary`, and nested structure fields
- **Updated `getSessionSummary` service** - Now accepts `projectUuid` parameter
- **Removed backwards compatibility code** - Cleaned up legacy methods and deprecated fields
- **Project cleanup** - Removed 22 development/debug test files and generated JSON artifacts

### Benefits
- 🔧 **Actionable insights** - Get executable bash scripts to fix issues immediately
- ⏱️ **Quantified value** - See exact time savings (e.g., "Saved 17 minutes: Manual 25min → Hawkeye 8min")
- 🎖️ **Quality visibility** - Understand investigation quality with detailed scoring
- 📦 **Cleaner codebase** - Removed legacy code and test artifacts

### Technical Details
- New tool: `src/tools/get-rca-score.ts`
- Updated: `src/tools/get-rca.ts` to use session summary endpoint
- Updated: `src/types/hawkeye.ts` - Enhanced SessionSummary interface
- Updated: `src/services/session.service.ts` - Added projectUuid to getSessionSummary
- Removed: `src-old/` directory and 22 test files
- All tests passing, build successful

---

## [1.3.0] - 2025-11-21

### Added
- **NEW TOOLS: Investigation Data Breakdown** - Redesigned `hawkeye_inspect_session` into 6 focused tools for better performance and UX:
  - `hawkeye_get_rca` ⭐ **NEW** - Get RCA summary only (2-5k tokens, ~10x faster)
  - `hawkeye_get_chain_of_thought` **NEW** - Get investigation reasoning steps
  - `hawkeye_get_investigation_queries` **NEW** - Get query execution logs
  - `hawkeye_get_investigation_sources` **NEW** - Get data sources consulted
  - `hawkeye_get_follow_up_suggestions` **NEW** - Get suggested follow-up questions
  - `hawkeye_inspect_session` **MODIFIED** - Now returns metadata only (1k tokens vs 48k)

### Changed
- **10x Performance Improvement** - Initial investigation summary retrieval now uses ~2-5k tokens instead of ~48k
- **Progressive Disclosure Workflow** - Users can now fetch exactly what they need: summary → reasoning → queries → sources
- **Updated Documentation** - README, USAGE, and examples updated to showcase new workflow
- **Better Tool Descriptions** - Each tool now has clear purpose and usage guidance

### Benefits
- ⚡ **10x faster** response times for common use cases
- 🎯 **Get exactly what you need** - no more overwhelming data dumps
- 💰 **Token efficient** - significantly reduced API costs
- 🔍 **Better UX** - natural progressive investigation flow

---

## [1.2.2] - 2025-11-20

### Fixed
- **Critical Bug: Instance Switching Now Works Correctly** - Fixed bug where switching instances updated the config but not the HttpClient's axios instance, causing all API calls to still go to the previous instance
  - Added `setBaseUrl()` method to HttpClient to update the axios baseURL at runtime
  - Added `getBaseUrl()` method to HttpClient for debugging
  - Updated `switchInstance` tool to call `httpClient.setBaseUrl()` when switching instances
  - Updated ToolServices interface to include httpClient reference
  - Instance switching now properly routes all subsequent API calls to the new instance

### Technical Details
- The bug occurred because HttpClient was initialized once at server startup with a base URL
- When switching instances, the config was updated but the HttpClient's internal axios instance retained the old URL
- The fix ensures both config and HttpClient are updated atomically during instance switching

---

## [1.2.1] - 2025-11-20

### Enhanced
- **Smart URL Normalization for Instance Switching** - The `hawkeye_switch_instance` tool now accepts flexible URL formats:
  - Just subdomain: `"prod"` → `https://prod.app.neubird.ai/api`
  - Partial URL: `"prod.app.neubird.ai"` → `https://prod.app.neubird.ai/api`
  - Full URL: preserved with smart completion
  - Automatic `https://` prefix addition
  - Automatic `/api` path suffix addition
  - Custom domain support

### Added
- Comprehensive URL normalization examples in documentation
- New "Working with Multiple Hawkeye Instances" section in USAGE.md
- Complete tool specification for `hawkeye_switch_instance` in SPECIFICATION.md
- Test suite for URL normalization (7 test cases, 100% passing)

### Changed
- Updated tool description to clarify flexible URL input formats
- Enhanced error messages with URL normalization information

---

## [1.2.0] - 2025-11-20

### Added
- **Instance Switching** - New `hawkeye_switch_instance` tool for managing multiple Hawkeye environments
  - Switch between dev/staging/production environments
  - Support for multiple customer deployments
  - Automatic authentication token clearing
  - Automatic project cache clearing
  - URL validation

### Changed
- Added `clearCache()` method to ProjectService
- Added `clearTokenCache()` method to AuthenticationService
- Updated ToolServices interface to include authService

---

## [1.1.0] - 2025-11-19

### Added
- **Search Functionality** - New `search_term` parameter for `hawkeye_list_sessions`
  - Search incidents by title using keywords (e.g., "load avg", "database", "timeout")
  - Case-insensitive partial matching
  - Works with both investigated and uninvestigated incidents
  - Can be combined with other filters

### Changed
- Updated documentation with search examples
- Enhanced USAGE.md with search use cases

---

## [1.0.2] - 2025-11-19

### Enhanced
- **Tool Descriptions** - Improved clarity to help LLMs select the correct tool
  - Added explicit "START new" vs "ALREADY STARTED" language
  - Added "Do NOT use" warnings to prevent tool confusion
  - Enhanced parameter descriptions for alert_id and session_uuid
  - Added `investigation_hint` to list_sessions response for uninvestigated incidents

### Changed
- Updated tool descriptions for `hawkeye_investigate_alert` and `hawkeye_continue_investigation`
- Added contextual hints in responses to guide proper tool usage

---

## [1.0.1] - 2025-11-19

### Added
- **Compact Mode** - Automatic token optimization for large result sets
  - Auto-enables for >10 sessions in list_sessions
  - Strips verbose fields (raw_data, detailed grouped_incidents)
  - 88.5% token reduction (from ~78KB to ~9KB for 20 sessions)
  - Keeps essential fields: id, title, priority, status, create_time
  - Manual control via `compact` parameter

### Enhanced
- Added helpful hints in responses (compact_hint, pagination_hint, investigation_hint)

---

## [1.0.0] - 2024-11-19

### Added

#### Core Features
- Initial release of Hawkeye MCP Server
- Full Model Context Protocol (MCP) implementation
- Authentication service with token caching and automatic refresh
- Project management and selection
- Session management and investigation lifecycle

#### Investigation Tools
- `hawkeye_list_projects` - List all available Hawkeye projects
- `hawkeye_investigate_alert` - Find existing RCAs or create new investigations for alert IDs
- `hawkeye_get_investigation_status` - Check investigation progress and results
- `hawkeye_continue_investigation` - Ask follow-up questions on existing investigations

#### Session Management & Analytics
- `hawkeye_list_sessions` - List sessions with advanced filtering capabilities:
  - Pagination support (page/limit parameters)
  - Date range filtering (date_from/date_to)
  - Investigation status filtering (uninvestigated, in progress, completed)
  - Session type filtering (incident vs manual)
  - Convenience parameter `only_uninvestigated` for quick filtering
  - Option to hide grouped incidents
- `hawkeye_inspect_session` - Get detailed session information with:
  - All prompt cycles
  - Chain of thoughts (analysis steps)
  - Data sources used
  - Follow-up suggestions
- `hawkeye_get_session_report` - Get session summaries with time-saved metrics
- `hawkeye_get_session_summary` - Get detailed quality scores and analysis metrics
- `hawkeye_get_incident_report` - Get organization-wide analytics:
  - MTTR (Mean Time To Resolution)
  - Total time saved
  - Noise reduction percentage
  - Incident breakdown by type and priority

#### Configuration & Environment
- Comprehensive environment variable support
- Configurable polling and timeouts
- Optional logging configuration
- Default project and organization settings

#### Documentation
- Comprehensive README with quick start guide
- Detailed INSTALLATION.md with platform-specific instructions
- Complete USAGE.md with workflows and examples
- Technical SPECIFICATION.md with API reference
- MIT License

### Changed
- Standardized all environment variables to use `HAWKEYE_` prefix (was `RAVEN_`)
- Package renamed from `raven-api-services` to `hawkeye-mcp-server`
- Updated to public npm package (was private)

### Technical Details
- Node.js >= 20.0.0 required
- Built with TypeScript for type safety
- Uses @modelcontextprotocol/sdk ^1.10.0
- HTTP client with Axios ^1.9.0
- Runtime validation with Zod ^3.24.3

### Supported Platforms
- macOS (Intel and Apple Silicon)
- Windows 10/11
- Linux (Ubuntu, Debian, Fedora, etc.)

### Supported AI Agents
- Claude Desktop (macOS, Windows)
- Cursor.ai (macOS, Windows, Linux)
- Continue.dev (VS Code extension)
- Any MCP-compatible AI agent

---

## [Unreleased]

## [4.1.0] - 2026-10-10

### Planned Features
- Custom investigation creation with natural language timeframes
- Streaming support for real-time progress updates
- Interactive setup wizard (`hawkeye-mcp init`)
- Health check command (`hawkeye-mcp test-connection`)
- CLI flags (`--version`, `--help`)
- Additional filtering options (priority, incident type)
- Pre-built binaries for platforms without Node.js

---

## How to Update

### For Users

```bash
# Update to latest version
npm update -g hawkeye-mcp-server

# Or reinstall
npm install -g hawkeye-mcp-server@latest
```

### For npx Users

npx automatically uses the latest version, but you can force a cache clear:

```bash
# Clear npx cache and use latest
npx clear-npx-cache
npx hawkeye-mcp-server
```

---

## Support

For questions or issues, contact support@neubird.ai
