Skip to content

Changelog

This page documents all notable changes to the toolregistry-hub project since the first official release version 0.4.14.

The format is based on Keep a Changelog, with project-specific grouping where useful.

[Unreleased]

Added

  • tools.jsonc hot reload (#144): with --config-reload the running server watches its config file (mtime/size polling, no new dependency) and applies a source-level diff to the live registry: an added source is registered, a removed source is unregistered, a source that leaves the configured scope (enabled: false, or filtered by mode/disabled/enabled) is disabled instead of unregistered, and a changed declaration is replaced. Reordering the list is not a change. A malformed file is logged and ignored, and the current registry keeps serving. The first poll after startup always runs, so an edit made between the registry build and the watcher start is not lost. Removing a tool_metadata entry keeps the value it set until restart, because the same fields are also writable from the admin panel; the panel can reset it immediately. The watcher is opt-in and per process; the built-in default tool list has no file to watch, and cross-process coordination for a multi-service deployment is not included.

Fixed

  • Config hot reload bypassed --profile (#234): a source registered by a reload did not pass through the deployment profile filter, so editing its declaration could re-expose a file_system, destructive, or privileged tool under --profile remote (or a network tool under --profile local). A reload now applies the same tag mapping to the tools it registers, without touching tools that were already registered.
  • Hub metadata defaults reset admin-panel edits on every reload (#232): apply_hub_overrides replayed _TOOL_METADATA over the whole registry on every applied diff, so a change to tags, defer, title, search_hint or an execution hint made from the admin panel was silently undone by the next unrelated config change. reload_registry now passes the names it registered to on_reload, and the callback annotates only those tools. Tools that already existed keep their current values; a tool registered by the reload still gets the Hub defaults, and the file's tool_metadata still wins afterwards.
  • A zero-tool source is no longer re-registered on every reload (#233): an empty name set meant an excluded source, a failed registration, or a successful registration that produced no tools, so the diff treated all three as needing registration and an MCP server that advertises no tools reconnected on every unrelated config change. A per-source status now records applied, excluded or failed: an applied source with no tools is left alone, a failed one retries, and an excluded one registers once it enters scope.

Changed

  • Vendored httpclient 0.6.4 → 0.7.1 (zerodep 48606bf): a redirect to a different origin no longer forwards Authorization, Proxy-Authorization or Cookie, and Digest authentication is attempted only while the request stays on the credential's origin (#287); every member of a multi-member gzip body is decoded instead of only the first; and Client/AsyncClient plus the convenience functions accept an optional max_response_size that caps a buffered body and raises ResponseTooLargeError above it. The parameter defaults to None, so every existing call buffers exactly as before, and a stream=True response is never capped. No hub code changes.

Security

  • Fetch applies an outbound address policy (#240, refs): fetch_content now validates the caller-supplied URL and proxy before any request. Only http/https are allowed; every resolved address must be globally routable (loopback, RFC 1918, link-local including 169.254.169.254, CGNAT, multicast, NAT64, 6to4, Teredo, ORCHID, and documentation/benchmarking ranges are refused), and a resolution failure is refused. IPv4-mapped and NAT64-embedded addresses are checked as IPv4. Redirects are checked after the fact: the body is discarded and FetchPolicyError is raised when response.url points into a private address. CDP checks document.location.href after navigation; VeilRender checks metadata.url; both refuse content when the final address is missing. Operators can opt in with Fetch(allow_private_hosts=True), FETCH_ALLOW_PRIVATE_HOSTS=1, or the constructor keyword in tools.jsonc; there is no per-call switch. Residual risk: the request that produced a refused redirect response has already been sent (blind SSRF), and DNS is resolved again at connect time (rebinding window) until zerodep ships follow_redirects=False and connect-time address pinning.
  • Fetch bounds the response body (#243): every request — markdown negotiation, the raw fetch, the Jina Reader call and VeilRender — now passes a 10 MiB max_response_size to the vendored HTTP client, which refuses an oversized Content-Length before reading any body and stops a chunked body as soon as it crosses the cap. ResponseTooLargeError is mapped to FetchError naming the caller-supplied host and the limit, never a resolved address. Previously the whole body was buffered before the content-type check ran, so one multi-gigabyte response could OOM a shared hub.

[0.12.0] - 2026-10-23

Fixed

  • The bare install now pulls the core library (#226, #225): [project].dependencies was empty, so pip install toolregistry-hub installed nothing that toolregistry_hub imports — every tool subclasses toolregistry.Tool and file_search imports toolregistry.parameter_models. The core library only arrived through the server extras, which is why server deployments worked and the documented library quickstart (pip install toolregistry-hub, then from toolregistry_hub import Calculator) failed with ModuleNotFoundError. toolregistry>=0.19.0,<1.0.0 is now a runtime dependency, matching the floor toolregistry-server>=0.7.0 already required; a packaging test asserts it stays there. This affects every published version, including 0.11.0.

Changed

  • Tool names are client-safe and consistent (#186, breaking): namespaces no longer contain / and the redundant prefixes are gone. web/websearch-search → web-search, web/websearch-list_engines → web-list_engines, web/fetch-fetch_content → web-fetch_content, fs/file_search-* → fs-*, fs/path_info-info → fs-info; the individual providers register as brave-search, tavily-search, searxng-search, brightdata-search, scrapeless-search and serper-search. Every name now matches [A-Za-z0-9_.-]{1,64}, so a client can forward it to a provider's function-name field unchanged. HTTP paths follow the same scheme (/tools/fs/glob, /tools/web/search). A regression test asserts that the default registry and the shipped data/tools.yaml only ever register client-safe, unique names. Update prompts, saved tool names and per-namespace configs.

[0.11.0] - 2026-10-23

Added

  • FileSearch honours .gitignore (#73): glob(), grep() and tree() skip ignored paths by default when the search root is inside a git repository, so results no longer fill up with node_modules/, __pycache__/ and build artifacts. Rules are read hierarchically (root file first, nested files on top) by a new dependency-free toolregistry_hub.gitignore matcher supporting negation, directory-only rules, anchoring, **, ? and character classes; git's rule that a path under an ignored directory cannot be re-included is preserved. A new respect_gitignore parameter (None = follow the repository, True = always apply rules found under the root, False = off) overrides the default on all three tools, and an explicitly named file passed to grep() is always searched.
  • Declared result schemas for structured tools (#189): ten tools now publish an MCP outputSchema and return structuredContent alongside the text block, so a client can read the result as data instead of re-parsing JSON out of a text block: weather-get_current/get_forecast/get_astronomy, datetime-convert_timezone, file_ops-read/edit/write, fs/path_info-info, web/fetch-fetch_content and bash-execute. The schemas are declared on ToolMetadata.extra["output_schema"] from a new toolregistry_hub.server.output_schemas table and describe the keys each tool always emits — no required list and additionalProperties: true, so a field the upstream API omits (fs/path_info-info returns only {"exists": false} for a missing path) never contradicts its published schema. Array-returning tools (fs/file_search-glob/grep, web/websearch-search, academics-search) deliberately declare nothing, because MCP structuredContent is an object.
  • MCP execution hints for the built-in tool set (#280): every tool now declares readOnlyHint, and most declare destructiveHint, idempotentHint and openWorldHint, so MCP hosts can auto-approve read-only calls (datetime-now, weather-*, websearch-search, academics-search, reader-*, fs/*, think, calculator, unit_converter, todolist) and reserve confirmation for bash-execute, file_ops-edit/write and cron-create/delete/shutdown. file_ops-read is now correctly declared read-only instead of inheriting the namespace's destructive tag, and cron-list is read-only. Human-readable titles are set for the main entry points.
  • Hub metadata overrides accept title and execution hints: _TOOL_METADATA entries can set title, read_only_hint, destructive_hint, idempotent_hint and open_world_hint, at namespace or method level. Fields the installed toolregistry does not define are skipped, so the hub keeps working against older cores.

Fixed

  • bash-execute deny list judges what rm deletes, not how the path is spelled (#6): rm -rf /tmp/build, /srv/app/cache and /etc/nginx/cache work again, while the root, the system directory names, unrecoverable trees (/usr/lib, /boot, /dev, /var/lib, /etc/ssh, …), $HOME/~, ./.. and shell spellings of them (//etc, ./, /et?, /{etc,usr}) stay blocked. Only rm's own operands are judged, so echo 'rm -rf /' runs. Commands are split on ;, &, | and newlines outside quotes and grouping/compound syntax is unwrapped (( … ), { …; }, !, then/do, case arms, function bodies), substitutions ($(…), backticks) and find -exec / sh -c / bash -lc payloads are checked, xargs without operands is refused, and GNU long-option prefixes (rm --rec -f) are recognised. Behaviour comes from bashtool 0.3.2 + 0.3.3, which this release pins; the mirrored cases are in tests/test_bash_tool.py and the security section of the Bash Tool page describes the new rules.
  • todolist-update acknowledges a simple update instead of returning None (#212): format="simple" is the default and ended in return None, so the common call handed the model the literal string "None" — it could not tell "recorded" from "nothing happened", the same symptom #185 and #202 fixed elsewhere. The default path now returns "todo list updated" (or "todo list cleared" for an empty input), the annotation is str, and the markdown/ascii renderings are unchanged.
  • cron-shutdown acknowledges the stop instead of returning None (#202): the method was annotated -> None, so tools/call handed the model the literal string None, which reads like a failed or empty call. It now returns "scheduler stopped". Together with #185 (think) this was the last NoneType return among the tools build_registry() produces.
  • SearXNG and Bright Data timeouts are errors, not empty results (#211): the last two engines of the #193 class turned a timeout into [], so a pinned engine during an outage looked like "no results for this topic". Both now raise SearchBackendError with a "timed out after Ns" message, like every other engine; a successful response with no results still returns [], and auto / parallel fall back to another engine rather than reporting an empty result.
  • A Reddit timeout is an error, not an empty result (#205): reddit was the one engine in _ENGINE_REGISTRY that still returned [] when Arctic Shift timed out, so pinning engine="reddit" during an outage looked like "this topic has no posts" — the symptom #193 describes, one engine over. It now raises SearchBackendError, like the other engines; a successful response with no posts still returns []. auto and parallel fall back to another engine instead of reporting an empty result.
  • think returns an acknowledgement instead of None (#185): the method was annotated -> None and ended in a bare return, so every tools/call handed the model the literal text "None" — meaningless in the transcript and easily read as a failure marker. It now returns e.g. "[reasoning] probe recorded" (mode only when focus_area is omitted).

Changed

  • Server floor is toolregistry-server>=0.7.0 (#187): the server now encodes dataclass tool results structurally, so web/websearch-search and academics-search return real JSON objects (title, url, content, score, …) instead of Python repr() strings inside the text block. No hub API change.
  • A developer's .env no longer changes which tests run (#210): tests/websearch/test_brightdata_engines.py called load_dotenv() at module scope, so every test collected after it inherited the keys and the skipif guards in unrelated modules stopped skipping — with a .env present, the live-call modules hit real APIs and failed on quota or response shape, and without one they skipped. The call now sits under if __name__ == "__main__":, test_debug_google_apis.py and test_serper_integration.py carry pytestmark = pytest.mark.integration and are deselected by default (pytest -m integration to run them), and tests/test_no_implicit_dotenv.py fails if a new module reintroduces an import-scope load_dotenv().
  • Vendored zerodep modules are flat again, with stale duplicates removed: soup and readability existed both as single modules and as package directories (soup.py + soup/soup.py), and cdp/websocket were package-only, so zerodep outdated could not see them. Everything is re-vendored with zerodep add in its default (flat) layout, which is what the CLI and the update workflow expect; the package copies are gone and zerodep outdated now reports all nine modules. Along the way soup goes 0.6.0 → 0.8.1 and httpclient 0.5.0 → 0.5.1. No hub code changes.
  • bash-execute timeouts are errors (#188, #190): BashTool.execute() now raises CommandTimeoutError instead of returning {"timed_out": true, "exit_code": -1} as a successful result, so MCP reports isError: true and the model sees why the command produced no output. The exception carries the partial stdout/stderr written before the kill. The timeout also kills the whole process tree now — previously only the shell=True child died and background children such as sleep 300 & kept running. Behaviour comes from bashtool 0.3.0, which this release pins.

Fixed

  • A failing search engine is now an error, not an empty list (#193): brave, tavily, serper, github and scrapeless returned [] on HTTP errors, timeouts, exhausted API keys and unparseable responses, so a caller could not tell "no results" from "this engine is broken" — and a pinned engine= looked like an empty topic. They now raise SearchBackendError, matching the policy searxng and brightdata already followed. auto and parallel still fall back to other engines; only a request that cannot be served raises, and it surfaces as isError: true with the provider's message.

Fixed

  • bash-execute deny list precision (#191): eval/exec are only blocked when they are the invoked command, so find … -exec, grep eval and echo > eval.txt work again. rm flags are normalised, so rm -r -f /x, rm --recursive --force /x and rm -Rf /x are blocked like rm -rf /x, including behind wrappers (sudo -u root, env -i, nice -n, timeout, xargs) and inside find -exec/-execdir payloads and sh -c strings. Segments now split on a single |, so checks see both sides of a pipe. rm -rf ./build remains allowed. Behaviour comes from bashtool 0.3.1, which this release pins.

[0.10.0] - 2026-09-16

Added

  • Academic search tools — new academics namespace with OpenAlex and arXiv engines. OpenAlex supports keyless polite-pool mode via OPENALEX_MAILTO. Priority order configurable via ACADEMIC_SEARCH_PRIORITY.
  • GitHub search engine — search GitHub repositories via REST API. No token required for public repos; optional GITHUB_TOKEN for higher rate limits with multi-key rotation.
  • Reddit search engine — search Reddit posts via Arctic Shift API (free, no auth). Requires subreddit scope in query (e.g. r/python web scraping).
  • Docker CI workflow — multi-arch (amd64 + arm64) Docker builds integrated into the release pipeline. Images published to DockerHub as oaklight/toolregistry-hub-server.
  • Test PyPI release workflow — CI workflow for publishing dev versions to Test PyPI, with Docker build support via testpypi flag.
  • Admin panel Caddy routing — centralized admin panel access at /admin/openapi/, /admin/mcp-http/, /admin/mcp-sse/ with HTTP basic auth. Admin panel binds to the same host as the main server for Docker networking compatibility.

Changed

  • toolregistry-server dependency bumped to >=0.6.0.
  • Adapted to toolregistry 0.18.0 — frozen Tool/ToolMetadata dataclasses and call_deferred integration.

Fixed

  • Engine schema narrowing — _configured_engine_names() now includes all configured engines (including reddit, github), not just priority-list engines. Previously engine="reddit" and engine="github" failed API schema validation.
  • File digest loss — prevent digest loss when file_ops-read output is truncated.

Improved

  • Streaming digest in file_ops-read digest_only mode for better performance.

[0.9.3] - 2026-08-06

Fixed

  • Release CI: include git submodules in build — v0.9.2 shipped without the bashtool submodule, causing ModuleNotFoundError on import. Added submodules: recursive to the release workflow's checkout step.

[0.9.2] - 2026-08-06 [YANKED]

Changed

  • BashTool extracted to submodule: Replaced the inline BashTool implementation with the bashtool submodule (v0.2.0). Removes sudo from the default deny list; adds BASHTOOL_UNSAFE env var to opt into unrestricted mode. Simplifies unsafe-mode tests.
  • Core dependency bumped to toolregistry>=0.15.0: Ensures users get the execution-stack refactor (ainvoke, aexecute_tool_calls, per-tool backend resolution, MCP v2 compatibility) from core.
  • Server dependency bumped to toolregistry-server>=0.4.3: Ensures server-side MCP v2 compatibility layer matches core.

Fixed

  • User config tool_metadata overrides hub defaults: Previously hub-supplied metadata silently won over user configuration; user-supplied tool_metadata now takes precedence.
  • Stable import path for _validate_command in shim: Fixes breakage when internal paths changed in the bashtool submodule.
  • ty 0.0.53+ type-check warnings resolved.

Infrastructure

  • Vendored dependencies updated: httpclient 0.4.4 → 0.4.5, readability 0.1.0 → 0.2.0, validate 0.4.3 → 0.6.1.
  • Dev tool versions pinned: ruff==0.15.20, ty==0.0.54, complexipy==5.6.1.

[0.9.1] - 2026-06-22

Changed

  • Server: Adopt toolregistry-server 0.4.0 architecture (#147) — migrates Hub to the upstream App/Adapter/registry_builder architecture. HubApp(App) overrides only prepare_registry() for Hub-specific registry construction; run_cli() and Adapter.add_cli_arguments() replace hand-rolled equivalents. Removes server/auth.py, server/routes/, and associated re-exports. Net −798 lines.
  • Server: Adopt ServerIdentity + CLI class from toolregistry-server (#149) — HubApp now accepts a ServerIdentity (HUB_IDENTITY: name, version, description, banner art) that flows automatically to the OpenAPI title, MCP server name, and CLI banner. HubCLI subclasses toolregistry_server.cli.CLI, overriding four methods (configure_subparsers, get_version_string, print_banner, dispatch) instead of reimplementing the main loop. main() reduced to one line: HubCLI().main(args). No user-visible CLI changes.

Improved

  • Server: Lazy-init HubApp + configure_subparsers hook — module-level HubApp is now created on first use, preventing double-instantiation when HubCLI creates its own instance. create_parser no longer digs into argparse private API (_subparsers._actions); Hub-specific arguments are now injected via the configure_subparsers(subparsers: dict[str, ArgumentParser]) callback.
  • Server: _run_update_check() helper — async event-loop boilerplate in _get_version_string and _print_hub_banner extracted into a shared _run_update_check() helper, eliminating duplication.

Fixed

  • Docker: add *.key and *.pem to .dockerignore — prevents private keys and certificates from being inadvertently included in Docker build context.

Docs

  • Fix jina strategy description and clarify that VEILRENDER_TOKEN is optional.

[0.9.0] - 2026-06-21

Added

  • Weather tool (#131) - new weather namespace with three methods powered by the free wttr.in JSON API. No API key required; uses the existing zero-dep httpclient.
    • get_current(location, units) - current conditions: temperature, feels-like, humidity, wind, precipitation, cloud cover, UV index, visibility, pressure.
    • get_forecast(location, days, units, include_hourly) - up to 3-day forecast with optional 3-hourly breakdowns.
    • get_astronomy(location) - sunrise/sunset, moonrise/moonset, moon phase and illumination.
    • Supports metric/imperial units, city names, coordinates, and airport codes. Tagged NETWORK + READ_ONLY.

Improved

  • Fetch: Reuse markdown negotiation response body (#132) - when Cloudflare Content Negotiation returns text/html instead of text/markdown (the common case), the response body is now preserved and passed directly to the Readability/Soup extraction pipeline, eliminating a redundant HTTP round-trip. Previously the HTML response was discarded and _fetch_raw issued an identical GET request to the same URL.
  • Fetch: Binary content-type early rejection (#132) - URLs returning binary content types (image/*, audio/*, video/*, font/*, application/pdf, application/zip, application/octet-stream, etc.) are now detected before entering the extraction pipeline and raise FetchError with a descriptive message. Previously binary responses were decoded as text and fed through Readability/Soup, producing garbage output.
  • Fetch: URL-level result cache (#135) - adds a per-instance URL result cache with configurable TTL (default 5 minutes) and LRU eviction (default 128 entries). Repeated fetches of the same URL within the TTL window return the cached result instantly. Only successful results are cached; errors always retry. Cache can be disabled with cache_ttl=0 or cleared via Fetch.clear_cache().
  • Fetch: Improved SPA detection with readability score (#138) - when the readability algorithm scores a page above the confidence threshold (score ≥ 20), SPA shell indicator matching is skipped entirely, preventing false positives on legitimate pages that happen to contain phrases like "loading...". Also tightens the SPA indicator list and adds a short-text threshold for broader indicators.
  • Fetch: Skip soup extraction when readability is sufficient (#139) - when readability produces a high-confidence result (score ≥ 100 and length ≥ 2000 characters), the soup extraction pass is skipped entirely. Profiling showed soup adds ~30-35% to local extraction time but contributes <16% additional content in these cases, saving 30-180 ms per page depending on document size. Applied to both the main _extract pipeline and the CDP rendering path. A debug log records skipped soup calls with score and length for post-deployment threshold tuning.
  • Fetch: Reduce cognitive complexity of _extract and _is_content_sufficient (#139) — refactored _extract (complexipy 26→16) and _is_content_sufficient (22→4) by extracting four helper functions, bringing both under the project’s complexity threshold of 15.
  • WebSearch: Parallel multi-engine search with BM25 dedup (#142) — new engine="parallel" mode that queries multiple search engines concurrently via ThreadPoolExecutor, deduplicates results by URL, and re-ranks with BM25 scoring. Default parallel engines configurable via WEBSEARCH_PARALLEL_ENGINES env var (default: brightdata,brave). Auto-skips unconfigured or failed engines with graceful fallback to auto mode. Also renames max_results → count in the search() signature and removes **kwargs for a cleaner LLM tool schema.
  • WebSearch: URL normalization for deduplication (#143) — dedup now normalizes URLs before comparison: strips www. prefix, removes trailing slashes, and filters common tracking parameters (utm_*, fbclid, gclid, msclkid, mc_*). Original URLs in search results are preserved unchanged.
  • Docker: Caddy gateway with unified entry point (#141) — adds a Caddy reverse proxy to unify three service backends behind a single port: /mcp → MCP streamable-http, /sse → MCP SSE, everything else → OpenAPI. Includes flush_interval -1 on all backends to prevent SSE/streaming buffering, backend services changed from ports to expose (no longer exposed to host directly), and /openapi convenience redirect to /docs.
  • Docker: deploy-dev Makefile target (#141) — make deploy-dev SSH_TARGET=host builds a wheel, builds the Docker image, transfers via zstd compression, and restarts the remote stack with health check.
  • FileOps: Claude Code-style read/edit/write digest workflow (#146) — replaces the deprecated read_file / write_file / append_file surface with a stateless, digest-based API:
    • read(path) → {content, digest, is_symlink, real_path} — reads file bytes, returns SHA-256 digest as a version token. Symlinks are allowed for reading; is_symlink and real_path are reported so callers can pass the real path to write operations.
    • edit(path, old_string, new_string, digest, replace_all=False, start_line=None) → {diff, digest} — exact string replacement guarded by digest; returns an updated digest so edits can chain without re-reading.
    • write(path, content, digest=None, mode="overwrite"|"append") → {digest} — atomic overwrite or append; new files need no digest, existing files require a matching digest to prevent silent overwrites. append mode decodes the existing file with its original encoding/BOM, appends as a string, then re-encodes, preserving UTF-16 and BOM-prefixed files correctly.
    • edit and write reject symlink paths (including .tmp intermediates). External modifications invalidate the digest and force a fresh read. 30 tests; no server-side state.

Internal

  • Rename _get_content_with_markdown_negotiation → _try_markdown_negotiation; return type changed from str to (md_content, fallback_body, fallback_ct) tuple for response reuse.
  • Add _is_binary_content_type() helper with prefix-based and exact-match detection.
  • 10 new tests covering response reuse path, fallback-to-_fetch_raw path, binary rejection, and parametrized binary/non-binary detection.
  • Add _should_skip_soup() predicate with _SOUP_SKIP_SCORE_THRESHOLD (100.0) and _SOUP_SKIP_MIN_LENGTH (2000) constants.
  • 11 new tests for soup-skip behaviour: 8 unit tests for _should_skip_soup, 3 integration tests for the full _extract pipeline.
  • Add dedup.py module with _normalize_url(), _tokenize(), _bm25_score(), and deduplicate_results(). 14 new tests for BM25 scoring, URL normalization, and dedup behaviour.
  • Add _search_parallel() strategy with ThreadPoolExecutor. 7 new tests for parallel mode (configured engines, skip unconfigured, handle failure, dedup, fallback, count cap).
  • Add Caddyfile reverse proxy config; refactor compose.yaml to use gateway service with IMAGE_TAG and GATEWAY_PORT variables; add deploy-dev target to Makefile.

Fixed

  • Fix README.md symlink target from readme_en.md (nonexistent) to README_en.md.

Improved (continued)

  • Fetch: VeilRender browser fallback (#140) — adds VeilRender as an optional remote headless browser fallback, positioned before CDP in the auto fallback chain. VeilRender renders JS-heavy pages via a REST API (POST /render) and re-parses the returned HTML with Readability/Soup. Configure via VEILRENDER_ENDPOINT and optionally VEILRENDER_TOKEN. When unconfigured, the strategy is hidden from the strategy Literal annotation at runtime.
  • Fetch: Structured return value (#140) — fetch_content now returns a FetchResult TypedDict instead of a plain string: {content, url, strategy, quality, content_type, cached, elapsed_ms, metadata}. The quality field is "high" or "low"; metadata carries strategy-specific fields such as readability_score and content_length.
  • Fetch: Explicit strategy parameter (#140) — fetch_content accepts an optional strategy argument (default "auto"). Available choices: auto, markdown, readability, soup, jina (always present), plus veilrender and cdp when their respective endpoints are configured. The Literal annotation is narrowed to available strategies at __init__ time via _narrow_strategy_annotation(). Explicit strategies bypass the fallback chain and run a single targeted extraction.
  • Fetch: Updated fallback chain (#140) — auto pipeline order: markdown → readability → soup → veilrender → cdp → jina → local_fallback. Docker compose.yaml retains direct service port mappings (55093/55094/55095) alongside the Caddy gateway.

Internal (continued)

  • Add FetchResult TypedDict, _make_result() factory, and _extract_with_strategy() / _extract_auto() split to replace the monolithic _extract(). Strategy-specific handlers factored into _strategy_markdown(), _strategy_local(), _strategy_browser(), _strategy_jina().
  • Add _render_with_veilrender() and _try_veilrender_extraction() mirroring the existing CDP helpers.
  • Add _try_browser_rendering() to encapsulate the VeilRender → CDP cascade in the auto pipeline.
  • Fetch._available_strategies() drives both runtime validation and Literal narrowing; veilrender / cdp appear only when their endpoints are set.
  • Server: Adopt ServerIdentity + CLI class from toolregistry-server (#149) — HubApp now accepts a ServerIdentity (HUB_IDENTITY with name, version, description, banner art), which flows automatically to the OpenAPI title, MCP server name, and CLI banner. HubCLI subclasses toolregistry_server.cli.CLI, overriding four methods (create_parser, get_version_string, print_banner, dispatch) instead of reimplementing the main loop. main() is reduced to one line: HubCLI().main(args). No user-visible CLI interface changes.

[0.8.3] - 2026-06-03

Added

  • CDP rendering stage for Fetch - when a CDP_ENDPOINT is configured, fetch-fetch attempts headless-browser rendering for SPA pages whose initial HTML is mostly empty JavaScript shells. Falls back to the plain HTTP response when CDP is unavailable or the page is already server-rendered.
  • New toolregistry_hub.utils.bind_literal() helper that returns a copy of a function with one parameter's annotation rewritten to Literal[*choices]. Used by tools that need to surface a runtime-driven enum in their MCP / JSON input schema without hand-rolling FunctionType shenanigans.

Fixed

  • SearXNG: switch JSON API requests from GET to POST (#115). Modern SearXNG instances with limiter: true block GET requests for format=json via Sec-Fetch-* header checks; POST bypasses the limiter and matches the upstream-documented JSON API usage. Also replaces silent return [] on HTTP errors with a typed SearchBackendError so callers can distinguish "no results" from "backend rejected the request".
  • unit_converter-convert input schema now exposes conversion as a closed enum of all 41 conversion function names instead of a free-form string (#117). MCP clients can validate locally and no longer need a discovery round-trip via list_conversions.
  • todolist-update accepts in_progress (also in-progress, inprogress) as an alias for pending (#116). The status enum is also now spelled out explicitly in the update docstring so it shows up in the generated tool description.
  • fetch-fetch now raises FetchError on HTTP failures and treats timeout as a wall-clock budget rather than per-request.
  • Bright Data websearch: align with official MCP package interface and increase default timeout.
  • Scrapeless websearch: increase default timeout; add cast() for ty type-checker compatibility.

Changed

  • unit_converter-help and calculator-help now accept calls without fn_name, returning an overview of all available functions (#120).
  • cron-list column header is now Job ID instead of ID, matching the job_id parameter on cron-delete (#118).
  • Breaking: file_ops-edit first parameter renamed from file_path to path for consistency with every other file_ops-* method and the reader-* family (#119). Callers using file_path= by keyword must switch to path=; positional usage is unaffected.
  • Vendor httpclient 0.4.2 and simplify SearXNG POST internals.
  • Rebuilt and pushed oaklight/toolregistry-hub-server:0.8.3 and latest.

Removed

  • FileOps.validate_path() (#113). The helper only screened for empty strings and a few shell-glob characters but its name implied real path validation, which misled MCP/LLM callers into treating nonexistent paths as valid. Use fs/path_info-info for actual path checks.

[0.8.2] - 2026-05-28

Changed

  • Apply tool_metadata config overrides when building the hub registry.
  • Support method-level tag and defer overrides from _TOOL_METADATA.
  • Bump server extras to require toolregistry-server>=0.3.2.
  • Fix package README metadata path to use README_en.md.
  • Switch the complexipy pre-commit hook to the official complexipy-pre-commit hook with explicit file filtering.

[0.8.1] - 2026-05-19

Added

  • --profile {remote,local} CLI flag for deployment context filtering. remote disables filesystem/shell/cron tools (they access the server's own filesystem, not the user's machine); local keeps only those local-machine tools and disables network/compute tools. Default: no filter.
  • Default tools.yaml manifest packaged with the hub for config-driven deployments.

Changed

  • Converged server layer to upstream APIs (resolves #109): deleted hub-specific tool_config.py (~355 lines) and its tests, replaced by toolregistry.config.{load_config, PythonSource, ToolConfig} from core. Hub now re-uses toolregistry-server's run_openapi_server(registry=, profile=) and run_mcp_server(registry=, profile=) directly for profile filtering.
  • _DEFAULT_TOOLS in registry.py migrated to list[PythonSource]; post-register hook wired via ToolRegistry.add_post_register_hook().
  • Config auto-discovery checks TOOLS_CONFIG env var, then tools.jsonc / tools.yaml / tools.yml in the current directory.
  • Bumped toolregistry-server requirement to >=0.3.1 across server extras.
  • Renamed README files to uppercase names used by package metadata and repository conventions.

Fixed

  • Use Callable[..., None] for _register_python_source_fn to satisfy type checking.
  • Wait for upstream PyPI availability before installing upstream releases in CI.

Dependencies

  • Update vendored httpclient module from 0.3.1 to 0.4.1 (zerodep)

[0.8.0] - 2026-04-06

New Features

  • Tool discovery with progressive disclosure

    • Call registry.enable_tool_discovery() to register a discover_tools tool for BM25F search across all registered tools
    • Less-used tools (FileReader, FileSearch, PathInfo, BashTool, CronTool, TodoList, UnitConverter) marked as deferred - discoverable via discover_tools but excluded from initial schema for smart clients
    • Add --tool-discovery / --no-tool-discovery CLI flag (default: enabled)
  • Think-augmented function calling

    • Inject a thought property into tool schemas for chain-of-thought reasoning (arXiv:2601.18282)
    • Built-in dedup prevents double injection when both server and harness enable it
    • Add --think-augment / --no-think-augment CLI flag (default: enabled)
  • ToolTag metadata for all registered tools

    • Assign ToolTag labels (READ_ONLY, DESTRUCTIVE, NETWORK, FILE_SYSTEM, PRIVILEGED) to every default tool based on its behavior
    • Tags are available via tool.metadata.tags for filtering and display
  • Fetch: Jina API key support with multi-key rotation

    • Fetch class now accepts optional api_keys parameter for Jina Reader authentication
    • Falls back to JINA_API_KEY environment variable (comma-separated for multiple keys)
    • Round-robin key rotation with automatic failure tracking (HTTP 401/403 → 1h cooldown, HTTP 429 → 5min cooldown)
  • Fetch: User-specified extraction engine

    • Add engine parameter to _extract(): "auto" (default fallback chain), "markdown", "readability", "soup", "jina"
    • Direct engine mode skips fallback chain - only the specified engine is tried
  • Fetch: Replace BS4 with readability + soup extraction pipeline (#87, #83)

    • Replace simplistic BeautifulSoup CSS selector extraction with multi-strategy pipeline: readability (Mozilla Readability.js port, intelligent article scoring) → soup (structural CSS fallback)
    • HTML fetched once and shared across both local strategies; readability preferred unless soup extracts >2x more content
    • Vendor readability and soup modules from zerodep into _vendor/ with nested layout
  • Fetch: Content-Type detection for non-HTML responses (#93, #92)

    • Rename _fetch_html → _fetch_raw returning (body, content_type) tuple
    • Short-circuit non-HTML content types (JSON, plain text, CSV, Markdown, XML, YAML) before the HTML extraction pipeline
    • Prevents mangling of structured data that was previously run through readability/soup extraction
  • Fetch: SPA content quality detection (#96, #94)

    • Add text structure analysis to _is_content_sufficient() to detect navigation-only extractions
    • Heuristic inspired by jusText: if >70% of lines are short (<30 chars) and fewer than 2 paragraph-length lines (>80 chars) exist, content is rejected as navigation garbage
    • Conservative: only triggers when text has >5 lines, so short valid content is unaffected
  • WebSearch: Unified entry point with dynamic engine selection

    • New WebSearch class registered at web/websearch namespace; the 6 individual provider tools (web/brave_search, web/tavily_search, etc.) are now deferred and discoverable via discover_tools
    • search(query, engine="auto", fallback=False, ...) - engine="auto" tries configured providers in priority order; specific engines fail loudly when their key is missing, or fall through to auto when fallback=True
    • Configurable priority via WEBSEARCH_PRIORITY environment variable (comma-separated names); default order is paid-providers-first
    • Per-instance dynamic narrowing of the engine Literal annotation: at construction time, the JSON schema seen by LLM clients only includes engines whose API keys are actually configured on this server
    • list_engines() helper for runtime introspection of available providers

Code Cleanup

  • Remove dead code from fetch.py: _get_lynx_useragent(), HEADERS_LYNX, _remove_emojis(), unused random import
  • Move Lynx-based user-agent generation to _legacy for future Chrome CDP reference
  • Convert Fetch from static utility to instance class for API key state management

Deprecations

  • FileSystem removed from default server registry
    • FileSystem class is no longer registered in server mode; replaced by PathInfo, FileSearch, and FileReader
    • The class itself is kept for library backward compatibility and still emits DeprecationWarning

Internal Changes

  • Zero external runtime dependencies (#98)

    • Replace httpx with vendored httpclient from zerodep - sync+async HTTP client using only stdlib
    • Replace ua-generator with vendored useragent module from zerodep
    • Replace pydantic with plain dataclasses in TodoList
    • Re-vendor all modules via zerodep CLI for consistent metadata and versioning
    • Result: dependencies = [] - the base package has zero PyPI runtime dependencies
  • Remove websearch_legacy module

    • Legacy Bing and Google HTML-scraping search providers archived to archive/websearch-legacy branch
    • Associated filter.py blocklist module also removed
    • All search functionality now served by API-based providers in websearch/
  • Add cognitive complexity analysis with complexipy (#103)

    • Add complexipy>=5.2.0 to dev dependencies with threshold 15, excluding _vendor/
    • Refactor 10 functions exceeding the threshold:
      • build_registry (31→7), load_tool_config (24→8), compare_versions (21→1)
      • SerperSearch::_search_impl (21→10), BraveSearch::_search_impl (20→9), _extract (20→11)
      • CronTool::_make_callback (19→9), FileSearch::_build_tree (17→14)
      • BrightDataSearch::_search_impl (17→14), TavilySearch::_search_impl (17→14)
    • Extract shared _handle_http_error into BaseSearch for websearch API key failover
  • Consolidate all zerodep vendored modules (structlog, scheduler, readability, soup) into _vendor/ with nested layout (#87)

  • Remove beautifulsoup4 external dependency; migrate websearch_legacy (bing, google) to zerodep soup (#87)
  • Exclude _vendor/ from ruff UP035 lint rule and ty type checking
  • Refactor CLI to always build registry with CLI flags instead of only when --config is set
  • Fix deprecated with_namespace= parameter in register_from_class() calls (now uses namespace=)

Fixes

  • SearXNG: Support optional X-API-Key header for protected instances (#85)
    • Add optional api_key parameter to SearXNGSearch, with fallback to SEARXNG_API_KEY environment variable
    • When set, sends X-API-Key header with JSON API requests; fully backwards compatible

[0.8.0] - 2026-04-06

Breaking Changes

  • FileOps: Replace diff-based editing with exact string replacement (#70, #62)
    • Removed replace_by_diff() and replace_by_git() methods
    • Added edit(file_path, old_string, new_string) with exact string matching
    • Supports replace_all for bulk replacement and start_line for disambiguation when multiple matches exist
    • Preserves file encoding (UTF-8/UTF-8-sig/UTF-16) and line endings (CRLF/LF)
    • Returns unified diff of changes

New Features

  • BashTool: Shell command execution with safety validation (#77, #66)

    • Execute shell commands via subprocess.run with configurable timeout and working directory
    • Built-in deny list blocks dangerous patterns (rm -rf, sudo, fork bombs, pipe-to-shell, git force push, etc.)
    • Deny list based on security survey of 6 AI coding CLI tools
    • Lazy upstream ToolMetadata integration for future permission system support
    • stdout/stderr truncation at 64KB to prevent memory exhaustion
  • FileReader: Multi-format file reading (#75, #65, #79)

    • read() - text files with line numbers and pagination (10MB cap, 2000 lines default)
    • read_notebook() - Jupyter notebooks with cell types and outputs (stdlib only)
    • read_pdf() - PDF text extraction via pypdf or pdfplumber (optional dependency)
    • read_image() - image files as multimodal content blocks ([TextBlock, ImageBlock]) with adaptive downsampling via Pillow (#79, #74)
    • Supports .png, .jpg, .jpeg, .gif, .webp formats
    • Auto-downsamples images exceeding the base64 size budget (default 5 MB) with format-specific quality floors
    • Add reader_image = ["Pillow>=10.0.0"] optional dependency group
  • FileSearch: File discovery tools (#72)

    • glob() - find files by pattern, sorted by modification time (1000 results cap)
    • grep() - regex content search with file filtering (200 results cap)
    • tree() - directory tree display with depth control (2000 entries cap)
  • PathInfo: Unified metadata query (#71)

    • Single info() call returns existence, type, size, modification time, and permissions
    • Replaces five separate FileSystem methods
    • Recursive size calculation for directories
  • CronTool: Scheduled prompt execution (#69, 4864ca7)

    • Cron expression scheduling with standard 5-field format
    • Recurring and one-shot modes with on_trigger callback for agent runtime integration
    • 7-day TTL auto-expiry for recurring jobs
    • Optional durable persistence via JSON file
    • Vendored zerodep/scheduler (v0.3.0) as internal dependency
  • API key failover with retry on auth/rate-limit errors (#53, 29bdd13)

    • Thread-safe failed key tracking in APIKeyParser with TTL-based auto-recovery (1h for 401/403, 5min for 429)
    • Fix double key consumption bug: replace _headers property with _build_headers(api_key) method
    • Retry loop in all API-key-based websearch providers (Brave, Tavily, Serper, Scrapeless, BrightData) that automatically tries the next valid key on 401/403/429 errors

Deprecations

  • FileSystem class deprecated (#76)

    • Replaced by PathInfo (metadata), FileSearch (discovery), and FileReader (reading)
    • All methods emit DeprecationWarning with migration guidance
    • Will be removed in a future major release
  • FileOps legacy methods deprecated (#76)

    • read_file() → use FileReader.read()
    • write_file() → use FileOps.edit() for modifications

Internal

  • Replace loguru with vendored zerodep/structlog (#80, 7e17fb4)
    • Remove loguru external dependency, replaced with vendored zero-dependency structlog module
    • All logging now uses get_logger() from internal _structlog module

Fixes

  • ty type-check error in tool_config.py (5890365)
    • Fixed dict type narrowing issue between ty 0.0.23 and 0.0.27

Build

  • Bump toolregistry-server minimum to >=0.1.2 for MCP parameter validation fix

CI

  • Enhanced upstream compatibility tests to cover toolregistry-server
  • Support multiple upstream packages in compat check (d8d25e4)
  • Add version validation and issues permission to upstream-compat workflow (f590cc0)

[0.7.0] - 2026-03-18

Breaking Changes

  • Server Code Migrated to toolregistry-server (#56, #57)

    • Server-related functionality (OpenAPI adapter, MCP adapter, CLI server commands) has been moved to the standalone toolregistry-server package
    • Users who relied on server features should install toolregistry-server separately
  • Minimum Python Version Upgraded to 3.10 (#54)

    • Python 3.8 and 3.9 no longer supported
    • Aligns with Python 3.9 EOL and MCP SDK requirements
  • is_configured Renamed to _is_configured (#58)

    • The method is now private and no longer exposed as a tool endpoint

New Features

  • Admin Panel Support (a88ab25)

    • Add --admin-port flag to enable admin panel for server management
    • Requires toolregistry-server>=0.1.1
  • Serper Search Provider (2305551)

    • Add Serper (serper.dev) search provider for Google search results
    • 2,500 free queries per month
    • Supports country, language, and location targeting
  • .env File Loading Support (#59)

    • Support for loading environment variables from .env files
    • Added --env-file and --no-env CLI options

Improvements

  • Dependency Updates

    • Bump toolregistry minimum to >=0.6.0
    • Bump toolregistry-server minimum to >=0.1.1
  • CI/CD

    • Add ruff/ty CI workflow for lint and type checking (e5b2f06)
    • Add upstream compatibility test workflow (79585d2)
    • Add lint and lint-fix targets to root Makefile

Refactoring

  • Modernize Type Annotations to Python 3.10+

    • Replaced legacy typing imports with modern Python 3.10+ syntax
  • MCP Server FastMCP Rewrite

    • Refactored MCP server implementation using FastMCP (official MCP SDK high-level API)
    • Fixed streamable-http transport timing issues
    • Fixed ASGI duplicate response errors

Documentation

  • Brave Search Pricing Update

    • Document Brave Search API free plan removal (Feb 2026)
    • Update to credit-based pricing: $5/1k requests with $5 free monthly credits (~1,000 queries)
  • Web Search Docs Refresh

    • Add Serper search documentation (EN/ZH)
    • Update free tier summary tables
    • Remove outdated "(Recommended)" labels

[0.6.0] - 2026-03-10

New Features

  • Startup Tool Configuration via JSONC (#37, #38)

    • Add JSONC (JSON with Comments) configuration file support for declarative tool loading at server startup
    • New tool_config.py module with JSONC parser and tool configuration loader
    • Add --tools-config CLI option to specify configuration file path
    • Provide tools.jsonc.example as a documented example configuration
    • Graceful fallback: loads all tools if no config file is specified
  • Auto-Route Generation from ToolRegistry (#31, #36)

    • Add autoroute.py module for automatic FastAPI route generation from registered tools in ToolRegistry
    • Introspect tools registered in ToolRegistry and automatically generate endpoint handlers
    • Eliminate the need for hand-written route boilerplate
    • Integrate auto-route into server startup with fallback to manual routes
    • Add comprehensive tests for autoroute functionality
  • Tool Environment Requirements and Central Registry (#30, #35)

    • Add @requires_env decorator to declare required environment variables on tool classes
    • Add Configurable protocol with is_configured() for instance-state readiness checks (structural subtyping)
    • Add build_registry() / get_registry() central registry that auto-disables unconfigured tools
    • Defer APIKeyParser and SearXNGSearch validation to call time, allowing graceful initialization without env vars
  • Nested Namespaces for WebSearch Tools (#39, #40)

    • Support nested namespaces like web/brave_search, producing URLs like /tools/web/brave_search/search
    • Hide internal methods (is_configured) from API endpoints via _HIDDEN_METHODS

Bug Fixes

  • Jina Reader Multi-Engine Retry (#43)

    • Separate httpx transport timeout from Jina X-Timeout (add 10s buffer) to prevent race conditions
    • Add X-Wait-For-Selector header with common content selectors for dynamic content
    • Add multi-engine retry: try browser first, fall back to cf-browser-rendering engine for JS-heavy websites
    • Extract _jina_reader_request() as low-level single-request function
  • Dockerfile Missing Server Dependencies

    • Local wheel install path now uses [server] extra instead of hardcoded dependency list
    • Ensures all dependencies are managed by pyproject.toml, preventing ModuleNotFoundError in Docker containers

Refactoring

  • Remove Legacy Hand-Written Route Files (#39, #40)

    • Remove calculator.py, datetime_tools.py, fetch.py, think.py, todo_list.py, unit_converter.py, and routes/websearch/ directory
    • Replace with auto-generated routes from ToolRegistry
    • Simplify routes/__init__.py to export only version_router
    • server_core.py uses auto-generated routes alongside version_router
  • Remove BingSearch (#34)

    • Remove deprecated BingSearch class, server route, and related tests
    • Rewrite and modernize websearch test suite for remaining engines
  • Restructure Server Optional Dependencies (#29, #33)

    • Update server_openapi and server_mcp extras to require toolregistry>=0.5.0
    • Refactor server extra to use self-referencing composition
  • Replace pyright with ty for type checking

  • APIKeyParser.__init__ no longer raises on missing keys; defers validation to call time

[0.5.6] - 2026-03-05

New Features

  • Web Fetch Improvements
    • Add Cloudflare content negotiation strategy for markdown extraction, increasing default timeout
    • Add strategy tracking logs to _extract() for better observability and debugging
    • Improve Jina Reader fallback: fix headers (remove placeholder selectors, add X-Engine: browser, X-Timeout), use POST with JSON body and structured JSON response parsing
    • Add _is_content_sufficient() to evaluate BeautifulSoup content quality (minimum length threshold + SPA shell indicator detection)
    • Improve _extract() fallback logic: low-quality BS4 content triggers Jina Reader; if Jina also fails, fall back to BS4 result
    • Enhance logging with strategy reasons and content quality metrics
    • Add comprehensive unit tests (43 test cases)

[0.5.5] - 2026-01-31

Refactoring

  • Think Tool Enhancement
    • Unify reason and think endpoints into single think endpoint
    • Reorder parameters and simplify thinking modes

Maintenance

  • Docker Improvements
    • Add REGISTRY_MIRROR build argument to Dockerfile for custom registry support
    • Add references/ directory to .dockerignore to reduce image size

[0.5.4.post1] - 2026-01-13

Bug Fixes

  • Version Endpoint Visibility
    • Hide version endpoints (/version/ and /version/check) from OpenAPI documentation using include_in_schema=False
    • Version endpoints remain fully functional and accessible via HTTP requests
    • Prevents version endpoints from being exposed as LLM tools in MCP mode

[0.5.4] - 2026-01-13

Refactoring

  • Unified Cognitive Tools Architecture
    • Consolidate reason and think endpoints into single think endpoint, combining structured reasoning and exploratory thinking
    • Merge thinking modes: analysis, hypothesis, planning, verification, correction (structured) with brainstorming, mental_simulation, perspective_taking, intuition (exploratory)
    • Simplify API surface by removing separate /reason endpoint and updating request models
    • Unify parameter naming: 'thought' → 'thought_process', 'thinking_type' → 'thinking_mode'
    • Refactor test suite with comprehensive coverage of all thinking modes and parameter combinations
    • Update documentation to reflect "recall + think" dual-tool cognitive architecture

New Features

  • PyPI Version Check & Update Notifications

    • Add comprehensive PyPI version checking system, inspired by argo-proxy implementation
    • New version_check.py module with async PyPI API calls and intelligent version comparison
    • Implement pre-release version support (alpha, beta, rc) and event loop safety handling
    • Add /version/ and /version/check API endpoints returning version info and update status
    • CLI adds --version parameter to display current version and check for updates
    • Enhanced startup banner with automatic version info and update notifications
    • Use standard library for version comparison without additional dependencies
    • Include complete synchronous test suite (10 tests)
  • ASCII Art Banner

    • Add new banner.py module with ASCII art banner
    • Implement centered alignment and consistent border styling (80-char width)
    • Display banner on CLI startup with show_banner=False parameter to disable

Documentation

  • Time-Sensitive Query Guidance for Web Search

    • Add IMPORTANT note in all websearch class docstrings
    • Emphasize LLMs have no inherent sense of time and training data may be outdated
    • Require checking current time with datetime tools for queries like "recent news"
    • Applied to all search provider classes
  • DateTime Tools Documentation Enhancement

    • Add detailed descriptions for now() and convert_timezone() methods
    • Expand parameter documentation with timezone format examples
    • Route descriptions directly reference method docstrings for better consistency

Maintenance

  • Version Attribute Fix
    • Update pyproject.toml to use version attribute instead of version
    • Add version variable in init.py following Python version convention
    • Maintain backward compatibility by keeping version variable

[0.5.3] - 2025-12-13

Refactoring

  • Multi-API Key Management System

    • Consolidate scattered API key implementations into centralized APIKeyParser utility
    • Replace individual API key management across websearch engines with unified system
    • Implement consistent API key rotation and error handling across all search providers
    • Refactor all websearch engines (Brave, Brightdata, Scrapeless, Tavily) to use centralized API key management
    • Improve search engine reliability and performance
    • Add rate limiting support to API key parser
  • Utils Module Structure

    • Migrate utils module to package structure for better organization
    • Add fn_namespace.py module for function namespace utilities
    • Improve module imports and dependencies
    • Simplify version extraction from pyproject.toml
    • Update build configuration for better reproducibility
  • Version Management System

    • Configure pyproject.toml to use dynamic version loading from toolregistry_hub.version
    • Remove hardcoded version from pyproject.toml, use setuptools dynamic version attribute
    • Centralize version management with single source of truth in __init__.py
    • Improve build process with setuptools dynamic version support

Bug Fixes

  • Docker Build Process

    • Fix Dockerfile package installation with server extras (fastapi, uvicorn, fastmcp)
    • Improve Makefile build logic for better package installation handling
    • Remove redundant docker/requirements.txt file
    • Enhance package installation logic for local wheel, specific version, and latest from PyPI
  • Type Annotations & Compatibility

    • Resolve type annotation and parameter naming issues for pyright compatibility
    • Fix type hints in server_core.py and websearch modules
    • Improve test compatibility and type safety

Documentation

  • Docker Documentation
    • Add comprehensive Docker documentation and migration guide
    • Add Docker README files in both English and Chinese
    • Provide OpenWebUI tool server migration documentation

[0.5.2] - 2025-12-12

New Features

  • Unit Converter API Routes

    • Add unit converter API routes
    • Refactor unit converter with base class and utility methods
    • Update unit converter tests
  • Web Search Enhancements

    • Add Scrapeless DeepSERP API (Google SERP) integration
    • Add Bright Data search (Google SERP) integration
    • Implement universal Google search results parser
    • Add Bright Data engines test for Bing and Yandex
    • Add environment variable support for Bing search proxy

Deprecations

  • Bing Search: Mark BingSearch as deprecated due to bot detection issues

Documentation

  • Update badge styles in README
  • Add DeepWiki badge to documentation
  • Update project description and README file
  • Add references directory to gitignore

[0.5.1] - 2025-12-05

Security & Authentication

  • MCP Server Authentication (#15)
    • Add Bearer Token authentication support for MCP server
    • Implement DebugTokenVerifier for MCP authentication
    • Support authenticated and open modes based on token configuration
    • Add comprehensive authentication event logging
    • Move token verification to FastAPI global dependencies
    • Refactor authentication architecture, decoupling routes and authentication concerns

Task Management

  • Todo List Tool Enhancements (#15)
    • Add Todo List tool with flexible input format support
    • Support both dictionary format and simple string format "[id] content (status)"
    • Implement comprehensive input validation with detailed error messages
    • Enhance status options with "pending" status
    • Support multiple output formats: 'simple' (no output), 'markdown', and 'ascii'
    • Add Markdown table generation API endpoint
    • Improve documentation and type annotations

Server

  • Architecture Refactoring
    • Create server_core.py module providing base FastAPI application
    • Remove authentication dependencies from all routes
    • Enable creation of both authenticated and non-authenticated server variants
    • Improve router discovery logging logic
    • Optimize server architecture for better maintainability

Date and Time

  • API Enhancements
    • Add TimeNowRequest model for time_now endpoint
    • Use structured request body instead of query parameters
    • Maintain backward compatibility with existing timezone name functionality
    • Improve API documentation structure

Documentation

  • Project Documentation
    • Update project description and README files
    • Change README reference from README.md to readme_en.md
    • Update PyPI and GitHub badge links
    • Improve documentation visual consistency

[0.5.0] - 2025-11-11

Security & Authentication

  • Multi Bearer Token Authentication (#11)
    • Support multiple Bearer tokens via environment variables or file configuration
    • Support API_BEARER_TOKEN environment variable (comma-separated)
    • Support API_BEARER_TOKENS_FILE file configuration (one token per line)
    • Add token caching mechanism for improved efficiency
    • Enhanced authentication logging and debugging features
    • New standalone multi-token authentication test suite

Server (#9)

  • REST API Server
    • New toolregistry-server CLI command-line tool
    • Support for OpenAPI and MCP server modes
    • Individual REST API endpoints for each tool:
      • Calculator API (/calculator)
      • DateTime API (/datetime)
      • Web Fetch API (/fetch)
      • Think Tool API (/think)
      • Web Search API (/websearch)
    • Automatic router discovery and registration mechanism
    • Recursive router discovery for nested modules

Docker

  • Complete Containerized Deployment Solution
    • Add Dockerfile for building container images
    • Provide .env.sample environment variable reference
    • Add requirements.txt for dependency installation
    • Provide compose.yaml and compose.dev.yaml orchestration configs
    • Add automated build and push Makefile
    • Optimize .dockerignore to reduce image size

Web Search (#8)

  • New Search Engine Support

    • Add Brave Search API integration
    • Add Tavily Search API integration
    • Add SearXNG search engine support
    • Refactor Bing search with modern implementation
  • Unified Search Architecture

    • Introduce BaseSearch abstract base class
    • Standardize search API method signatures
    • Use SearchResult dataclass for type safety
    • Unified header generation and content fetching logic
  • Advanced Search Features

    • Multi API key support (Brave and Tavily)
    • Pagination support for up to 180 results
    • Flexible search parameters and filtering options
    • Improved result parsing and error handling
  • User Agent Optimization

    • Replace fake-useragent with ua-generator
    • Dynamic user agent generation for better anti-bot evasion
    • Enhanced browser fingerprinting realism
  • Module Restructuring

    • Move modern search engines to websearch/ directory
    • Move legacy search implementations to websearch_legacy/ directory
    • Clean up outdated Google search modules

Timezone Enhancements (#5)

  • Timezone Support

    • DateTime.now() supports timezone parameter specification
    • New convert_timezone() timezone conversion functionality
    • Support IANA timezone names (e.g., "Asia/Shanghai")
    • Support UTC/GMT offset formats (e.g., "UTC+5:30", "GMT-3")
    • Handle fractional hour offsets (e.g., Nepal UTC+5:45)
  • Python Compatibility

    • Support Python 3.8 via backports.zoneinfo
    • Unified timezone parsing logic
    • Improved error handling and exception messages

Documentation (#10)

  • Documentation Structure Optimization
    • Refactor documentation structure for improved readability
    • Add multi-language documentation support
    • Detailed Docker deployment guides
    • Web search engine usage documentation
    • API endpoint and configuration instructions

Testing (#12)

  • Enhanced Test Coverage
    • Add 0.4.16a0 version testing
    • Multi-token authentication test suite
    • Timezone functionality unit tests
    • Web search engine testing

Refactoring

  • think_tool: Simplify think method return type
    • Change return type from Dict[str, str] to None
    • Remove unused typing import for Dict
    • Remove thought logging return value since it's not used

Documentation

  • Documentation hosting: Migrate documentation to ReadTheDocs hosting

[0.4.15] - 2025-08-11

New Features

  • DateTime Tool: Add DateTime utility for current time retrieval
  • ThinkTool: Add reasoning and brainstorming tool providing cognitive processing space for AI tool integration

Documentation

  • Enhance tool descriptions and usage examples
  • Update independence notice and package context
  • Improve README documentation structure

Maintenance

  • Bump version to 0.4.15
  • Update and optimize dependencies

[0.4.14] - First Official Release

Initial Release

  • Basic tool collection
  • Core functionality implementation
  • Basic documentation structure
  • Test framework establishment

Version Notes

Semantic Versioning

This project follows Semantic Versioning specification:

  • Major version: Incompatible API changes
  • Minor version: Backward-compatible functionality additions
  • Patch version: Backward-compatible bug fixes

Change Type Legend

  • New Features - New functionality or features
  • Refactoring - Code refactoring without functional changes
  • Bug Fixes - Error corrections
  • Documentation - Documentation updates
  • Security - Security-related improvements
  • Server - Server functionality
  • Docker - Containerization related
  • Search - Search functionality related
  • Timezone - Timezone functionality related
  • Testing - Testing-related improvements
  • Maintenance - Maintenance updates

Getting Updates

To get the latest version, use:

pip install --upgrade toolregistry-hub

Feedback and Suggestions

If you find any issues or have improvement suggestions, please submit an Issue in our GitHub repository.