Metabase Release Notes

Follow

196 release notes curated from 69 sources by the Releasebot Team. Last updated: Sep 19, 2026

Get this feed:
  • Sep 18, 2026
    • Date parsed from source:
      Sep 18, 2026
    • First seen by Releasebot:
      Sep 19, 2026
    Metabase logo

    Metabase

    v0.64.0.1-beta: 🤖 v64 backported "Add a glossary tool to the MCP server" (#82768)

    Metabase adds an MCP glossary tool, with case-insensitive lookups, paged listings, and instance-aware descriptions that tell models to consult the glossary before answering. It also tightens tool validation, simplifies the API, and fixes glossary test and whitespace issues.

    Add a glossary tool to the MCP server (#82696)

    Let a v2 MCP tool describe itself from the instance's own data

    deftool gains an optional :description-suffix, a fn of no arguments whose
    result is appended to the tool description on every tools/list. The static
    part stays in the manifest cache and only the suffix is recomputed, so a
    suffix that reads the app DB doesn't drag the schema conversion along with it.
    tools-hash skips it on purpose. The keepalive polls that hash every 30 seconds
    on every open stream, so covering descriptions would buy a change notification
    for a suffix at the price of its query per stream per tick. A suffix reaches a
    client when it next lists tools instead.

    Add a glossary tool to the MCP server

    glossary() returns every term with its definition; glossary(term) returns
    one, matched case-insensitively, since a model echoes a term as it read it
    rather than as it happens to be stored.

    The term names ride the tool's own description rather than waiting behind the
    call. A model only looks a word up when something tells it the word is worth
    looking up, and the terms that most need a company definition are the ones
    that read as ordinary English -- account, active user, churn -- which a model
    believes it already understands. Metabot gets this for free by pasting the
    whole glossary into every message it sends, because it owns the prompt; here
    the description is the only channel that reaches the model unprompted.

    Definitions stay behind the call, and the term list is capped at 100. Nothing
    bounds a glossary -- no cap on entries, and a definition is TEXT -- and a
    description long enough for a client to truncate costs more than its tail is
    worth.

    A client may cache a description for the life of its session, so a term added
    mid-session shows up when that client next connects.

    Keep glossary out of the driver-test trigger set

    mcp now uses glossary, and mcp's transitive dependents are effectively the
    whole graph because some modules declare :uses :any. That made a glossary
    change reach driver, query-processor and transforms, so every glossary edit
    would have run the full driver suite. mcp is already excused from this for the
    same reason; glossary joins it rather than raising max-allowed-count, since
    none of it is driver logic.

    Also fixes two whitespace-linter errors: a literal U+2028 landed in the
    glossary test where an escape sequence was meant. The separator is now built
    with char, which is what the test was trying to say anyway.

    Reject a :description-suffix that only takes one argument

    ifn? was the wrong predicate. Keywords, maps, sets and vectors satisfy it but
    are callable only with one argument, so they passed registration and then threw
    ArityException at the first tools/list -- the deferred failure the guard exists
    to prevent. Worse, the accepted registration sat in the shared registry, so the
    throw came from listing any tool at all, not from the one that was wrong.

    Vars stay allowed: one holding a fn of no arguments is callable, and :handler
    is already registered as a var.

    Point the MCP server instructions at the glossary

    The initialize instructions are the only channel that reaches the model before
    any tool call, so this is where the glossary gets announced.

    The line is unconditional on purpose. An instruction to look a term up when you
    don't recognize it never fires, because the words that most need a company
    definition are the ones that read as ordinary English -- account, active user,
    churn -- which a model believes it already understands. So it asserts that
    these terms matter and to fetch them before answering, with no qualifier about
    which words. A test pins that: it fails if the line goes missing, and it fails
    if the line grows a "don't recognize" style qualifier.

    Static, so the instructions stay a compile-time constant. Whether an instance
    has any terms at all is reported by the tool's own description instead.

    Instruct rather than list, and page the glossary listing

    Three fixes from review.

    The description no longer names the terms. The old cap was on the number of
    terms, but the thing being protected is the length of a description clients
    truncate -- Claude Code at 2048 characters. Seventy ordinary-length terms
    produced 2444 characters with no pointer to the rest, so the client cut the
    tail and the model saw a partial list it had every reason to read as the whole
    glossary. That is worse than no list: a model believing the glossary is covered
    never calls. So the description now carries the count and an unconditional
    instruction to call before answering, which is inherently bounded and asks the
    model to notice nothing.

    glossary() is paged. It rendered every row, term and definition, into one
    block, with definition a TEXT column that nothing bounds at any layer. Now
    limit and offset through the usual list envelope, defaulting to 50 and matching
    browse_collection -- the closest analogue, a plain unranked listing of rows
    carrying prose.

    glossary(term) returns every match. term is unique case-sensitively, so "ARR"
    and "arr" are two entries with two meanings, and the lookup is deliberately
    case-insensitive because a model echoes a term as it read it. Taking the first
    match silently picked one and gave no sign the other existed.

    Make the glossary tool description static again

    The suffix reported how many terms an instance defines. The only thing that
    bought was letting a model skip one call on an instance with no glossary --
    a call that is cheap and self-correcting, since it returns "no terms are
    defined" and the model moves on. That does not pay for a public extension
    point on deftool, its load-time validation, and a query of every glossary row
    on every tools/list.

    So the instruction moves into the static description and the machinery goes.
    registry.clj is byte-identical to its state before this branch; every change
    it had carried was in service of the suffix, including the list-tools split
    that existed only so tools-hash could avoid computing one.

    The instruction itself is unchanged in substance and still unconditional: call
    glossary() before answering any question about this instance's data, with no
    qualifier about which words, because the words that most need a company
    definition read as ordinary English and the question will not say which ones
    are defined.

    Simplify description

    Fixes

    Read the glossary through its module API, not its db namespace

    The MCP tool required metabase.glossary.db, which meant exporting another
    module's raw Toucan namespace just to read from it. metabase.glossary.core is
    the module's stated API namespace and says so in its own docstring; it only
    lacked a read, which is why db had to be exported at all.

    So core gains entries, and db leaves the module's :api. Nothing outside the
    module reaches into it now.

    Match the glossary tests to the simpler unknown-term error

    The unknown-term error no longer names the terms that do exist, so the two
    tests asserting it did were red. They now assert what it says: the term the
    caller asked for.

    The third was the cleaning guard, which had been riding on that error naming a
    stored term. Retargeted onto a successful lookup, where stored text still
    reaches prose the model reads as the server speaking. It now covers the stored
    definition as well as the term -- definitions had no cleaning coverage before,
    and the definition is the longer field and the one a payload would fit in.

    The listing is deliberately not covered: list-content JSON-encodes its envelope
    and wraps it raw, so it is bounded by JSON escaping rather than by clean, and
    asserting otherwise would have been false.

    Co-authored-by: Eric Normand [email protected]

    Original source
  • Sep 18, 2026
    • Date parsed from source:
      Sep 18, 2026
    • First seen by Releasebot:
      Sep 19, 2026
    Metabase logo

    Metabase

    v0.64.0.x: 🤖 v64 backported "Add a glossary tool to the MCP server" (#82768)

    Metabase adds and refines an MCP glossary tool, with paged listings, case-insensitive lookups, static server instructions, and fixes for description handling, validation, and tests.

    Add a glossary tool to the MCP server (#82696)

    Let a v2 MCP tool describe itself from the instance's own data

    deftool gains an optional :description-suffix, a fn of no arguments whose result is appended to the tool description on every tools/list. The static part stays in the manifest cache and only the suffix is recomputed, so a suffix that reads the app DB doesn't drag the schema conversion along with it. tools-hash skips it on purpose. The keepalive polls that hash every 30 seconds on every open stream, so covering descriptions would buy a change notification for a suffix at the price of its query per stream per tick. A suffix reaches a client when it next lists tools instead.

    Add a glossary tool to the MCP server

    glossary() returns every term with its definition; glossary(term) returns one, matched case-insensitively, since a model echoes a term as it read it rather than as it happens to be stored.

    The term names ride the tool's own description rather than waiting behind the call. A model only looks a word up when something tells it the word is worth looking up, and the terms that most need a company definition are the ones that read as ordinary English -- account, active user, churn -- which a model believes it already understands. Metabot gets this for free by pasting the whole glossary into every message it sends, because it owns the prompt; here the description is the only channel that reaches the model unprompted.

    Definitions stay behind the call, and the term list is capped at 100. Nothing bounds a glossary -- no cap on entries, and a definition is TEXT -- and a description long enough for a client to truncate costs more than its tail is worth.

    A client may cache a description for the life of its session, so a term added mid-session shows up when that client next connects.

    Keep glossary out of the driver-test trigger set

    mcp now uses glossary, and mcp's transitive dependents are effectively the whole graph because some modules declare :uses :any. That made a glossary change reach driver, query-processor and transforms, so every glossary edit would have run the full driver suite. mcp is already excused from this for the same reason; glossary joins it rather than raising max-allowed-count, since none of it is driver logic.

    Also fixes two whitespace-linter errors: a literal U+2028 landed in the glossary test where an escape sequence was meant. The separator is now built with char, which is what the test was trying to say anyway.

    Reject a :description-suffix that only takes one argument

    ifn? was the wrong predicate. Keywords, maps, sets and vectors satisfy it but are callable only with one argument, so they passed registration and then threw ArityException at the first tools/list -- the deferred failure the guard exists to prevent. Worse, the accepted registration sat in the shared registry, so the throw came from listing any tool at all, not from the one that was wrong.

    Vars stay allowed: one holding a fn of no arguments is callable, and :handler is already registered as a var.

    Point the MCP server instructions at the glossary

    The initialize instructions are the only channel that reaches the model before any tool call, so this is where the glossary gets announced.

    The line is unconditional on purpose. An instruction to look a term up when you don't recognize it never fires, because the words that most need a company definition are the ones that read as ordinary English -- account, active user, churn -- which a model believes it already understands. So it asserts that these terms matter and to fetch them before answering, with no qualifier about which words. A test pins that: it fails if the line goes missing, and it fails if the line grows a "don't recognize" style qualifier.

    Static, so the instructions stay a compile-time constant. Whether an instance has any terms at all is reported by the tool's own description instead.

    Instruct rather than list, and page the glossary listing

    Three fixes from review.

    The description no longer names the terms. The old cap was on the number of terms, but the thing being protected is the length of a description clients truncate -- Claude Code at 2048 characters. Seventy ordinary-length terms produced 2444 characters with no pointer to the rest, so the client cut the tail and the model saw a partial list it had every reason to read as the whole glossary. That is worse than no list: a model believing the glossary is covered never calls. So the description now carries the count and an unconditional instruction to call before answering, which is inherently bounded and asks the model to notice nothing.

    glossary() is paged. It rendered every row, term and definition, into one block, with definition a TEXT column that nothing bounds at any layer. Now limit and offset through the usual list envelope, defaulting to 50 and matching browse_collection -- the closest analogue, a plain unranked listing of rows carrying prose.

    glossary(term) returns every match. term is unique case-sensitively, so "ARR" and "arr" are two entries with two meanings, and the lookup is deliberately case-insensitive because a model echoes a term as it read it. Taking the first match silently picked one and gave no sign the other existed.

    Make the glossary tool description static again

    The suffix reported how many terms an instance defines. The only thing that bought was letting a model skip one call on an instance with no glossary -- a call that is cheap and self-correcting, since it returns "no terms are defined" and the model moves on. That does not pay for a public extension point on deftool, its load-time validation, and a query of every glossary row on every tools/list.

    So the instruction moves into the static description and the machinery goes.

    registry.clj is byte-identical to its state before this branch; every change it had carried was in service of the suffix, including the list-tools split that existed only so tools-hash could avoid computing one.

    The instruction itself is unchanged in substance and still unconditional: call glossary() before answering any question about this instance's data, with no qualifier about which words, because the words that most need a company definition read as ordinary English and the question will not say which ones are defined.

    Simplify description

    Fixes

    Read the glossary through its module API, not its db namespace

    The MCP tool required metabase.glossary.db, which meant exporting another module's raw Toucan namespace just to read from it. metabase.glossary.core is the module's stated API namespace and says so in its own docstring; it only lacked a read, which is why db had to be exported at all.

    So core gains entries, and db leaves the module's :api. Nothing outside the module reaches into it now.

    Match the glossary tests to the simpler unknown-term error

    The unknown-term error no longer names the terms that do exist, so the two tests asserting it did were red. They now assert what it says: the term the caller asked for.

    The third was the cleaning guard, which had been riding on that error naming a stored term. Retargeted onto a successful lookup, where stored text still reaches prose the model reads as the server speaking. It now covers the stored definition as well as the term -- definitions had no cleaning coverage before, and the definition is the longer field and the one a payload would fit in.

    The listing is deliberately not covered: list-content JSON-encodes its envelope and wraps it raw, so it is bounded by JSON escaping rather than by clean, and asserting otherwise would have been false.

    Co-authored-by: Eric Normand [email protected]

    Original source
  • All of your release notes in one feed

    Join Releasebot and get updates from Metabase and hundreds of other software products.

    Create account
  • Sep 18, 2026
    • Date parsed from source:
      Sep 18, 2026
    • First seen by Releasebot:
      Sep 19, 2026
    Metabase logo

    Metabase

    v0.64.x: 🤖 v64 backported "Add a glossary tool to the MCP server" (#82768)

    Metabase adds a glossary tool to its MCP server, with paged term listings, case-insensitive lookups, and updated instructions that point models to the glossary before answering. It also tightens description-suffix validation and fixes glossary tests.

    Add a glossary tool to the MCP server (#82696)

    Let a v2 MCP tool describe itself from the instance's own data

    deftool gains an optional :description-suffix, a fn of no arguments whose
    result is appended to the tool description on every tools/list. The static
    part stays in the manifest cache and only the suffix is recomputed, so a
    suffix that reads the app DB doesn't drag the schema conversion along with it.
    tools-hash skips it on purpose. The keepalive polls that hash every 30 seconds
    on every open stream, so covering descriptions would buy a change notification
    for a suffix at the price of its query per stream per tick. A suffix reaches a
    client when it next lists tools instead.

    Add a glossary tool to the MCP server

    glossary() returns every term with its definition; glossary(term) returns
    one, matched case-insensitively, since a model echoes a term as it read it
    rather than as it happens to be stored.

    The term names ride the tool's own description rather than waiting behind the
    call. A model only looks a word up when something tells it the word is worth
    looking up, and the terms that most need a company definition are the ones
    that read as ordinary English -- account, active user, churn -- which a model
    believes it already understands. Metabot gets this for free by pasting the
    whole glossary into every message it sends, because it owns the prompt; here
    the description is the only channel that reaches the model unprompted.

    Definitions stay behind the call, and the term list is capped at 100. Nothing
    bounds a glossary -- no cap on entries, and a definition is TEXT -- and a
    description long enough for a client to truncate costs more than its tail is
    worth.

    A client may cache a description for the life of its session, so a term added
    mid-session shows up when that client next connects.

    Keep glossary out of the driver-test trigger set

    mcp now uses glossary, and mcp's transitive dependents are effectively the
    whole graph because some modules declare :uses :any. That made a glossary
    change reach driver, query-processor and transforms, so every glossary edit
    would have run the full driver suite. mcp is already excused from this for the
    same reason; glossary joins it rather than raising max-allowed-count, since
    none of it is driver logic.

    Also fixes two whitespace-linter errors: a literal U+2028 landed in the
    glossary test where an escape sequence was meant. The separator is now built
    with char, which is what the test was trying to say anyway.

    Reject a :description-suffix that only takes one argument

    ifn? was the wrong predicate. Keywords, maps, sets and vectors satisfy it but
    are callable only with one argument, so they passed registration and then threw
    ArityException at the first tools/list -- the deferred failure the guard exists
    to prevent. Worse, the accepted registration sat in the shared registry, so the
    throw came from listing any tool at all, not from the one that was wrong.

    Vars stay allowed: one holding a fn of no arguments is callable, and :handler
    is already registered as a var.

    Point the MCP server instructions at the glossary

    The initialize instructions are the only channel that reaches the model before
    any tool call, so this is where the glossary gets announced.

    The line is unconditional on purpose. An instruction to look a term up when you
    don't recognize it never fires, because the words that most need a company
    definition are the ones that read as ordinary English -- account, active user,
    churn -- which a model believes it already understands. So it asserts that
    these terms matter and to fetch them before answering, with no qualifier about
    which words. A test pins that: it fails if the line goes missing, and it fails
    if the line grows a "don't recognize" style qualifier.

    Static, so the instructions stay a compile-time constant. Whether an instance
    has any terms at all is reported by the tool's own description instead.

    Instruct rather than list, and page the glossary listing

    Three fixes from review.

    The description no longer names the terms. The old cap was on the number of
    terms, but the thing being protected is the length of a description clients
    truncate -- Claude Code at 2048 characters. Seventy ordinary-length terms
    produced 2444 characters with no pointer to the rest, so the client cut the
    tail and the model saw a partial list it had every reason to read as the whole
    glossary. That is worse than no list: a model believing the glossary is covered
    never calls. So the description now carries the count and an unconditional
    instruction to call before answering, which is inherently bounded and asks the
    model to notice nothing.

    glossary() is paged. It rendered every row, term and definition, into one
    block, with definition a TEXT column that nothing bounds at any layer. Now
    limit and offset through the usual list envelope, defaulting to 50 and matching
    browse_collection -- the closest analogue, a plain unranked listing of rows
    carrying prose.

    glossary(term) returns every match. term is unique case-sensitively, so "ARR"
    and "arr" are two entries with two meanings, and the lookup is deliberately
    case-insensitive because a model echoes a term as it read it. Taking the first
    match silently picked one and gave no sign the other existed.

    Make the glossary tool description static again

    The suffix reported how many terms an instance defines. The only thing that
    bought was letting a model skip one call on an instance with no glossary --
    a call that is cheap and self-correcting, since it returns "no terms are
    defined" and the model moves on. That does not pay for a public extension
    point on deftool, its load-time validation, and a query of every glossary row
    on every tools/list.

    So the instruction moves into the static description and the machinery goes.
    registry.clj is byte-identical to its state before this branch; every change
    it had carried was in service of the suffix, including the list-tools split
    that existed only so tools-hash could avoid computing one.

    The instruction itself is unchanged in substance and still unconditional: call
    glossary() before answering any question about this instance's data, with no
    qualifier about which words, because the words that most need a company
    definition read as ordinary English and the question will not say which ones
    are defined.

    Simplify description

    Fixes

    Read the glossary through its module API, not its db namespace

    The MCP tool required metabase.glossary.db, which meant exporting another
    module's raw Toucan namespace just to read from it. metabase.glossary.core is
    the module's stated API namespace and says so in its own docstring; it only
    lacked a read, which is why db had to be exported at all.

    So core gains entries, and db leaves the module's :api. Nothing outside the
    module reaches into it now.

    Match the glossary tests to the simpler unknown-term error

    The unknown-term error no longer names the terms that do exist, so the two
    tests asserting it did were red. They now assert what it says: the term the
    caller asked for.

    The third was the cleaning guard, which had been riding on that error naming a
    stored term. Retargeted onto a successful lookup, where stored text still
    reaches prose the model reads as the server speaking. It now covers the stored
    definition as well as the term -- definitions had no cleaning coverage before,
    and the definition is the longer field and the one a payload would fit in.

    The listing is deliberately not covered: list-content JSON-encodes its envelope
    and wraps it raw, so it is bounded by JSON escaping rather than by clean, and
    asserting otherwise would have been false.

    Co-authored-by: Eric Normand [email protected]

    Original source
  • Sep 18, 2026
    • Date parsed from source:
      Sep 18, 2026
    • First seen by Releasebot:
      Sep 18, 2026
    Metabase logo

    Metabase

    v0.63.18.1

    Metabase backports a fix for static viz Row Chart failures on remapped columns.

    🤖 v63 backported "Fix static viz Row Chart failures on remapped colum…

    Original source
  • Sep 18, 2026
    • Date parsed from source:
      Sep 18, 2026
    • First seen by Releasebot:
      Sep 18, 2026
    Metabase logo

    Metabase

    v0.63.18.x

    Metabase fixes static viz Row Chart failures on remapped columns in v63 backports.

    🤖 v63 backported "Fix static viz Row Chart failures on remapped colum…

    Original source
  • Similar to Metabase with recent updates:

  • Sep 18, 2026
    • Date parsed from source:
      Sep 18, 2026
    • First seen by Releasebot:
      Sep 18, 2026
    Metabase logo

    Metabase

    v0.63.x

    Metabase fixes static viz Row Chart failures on remapped columns in a v63 backport.

    🤖 v63 backported "Fix static viz Row Chart failures on remapped colum…

    Original source
  • Sep 18, 2026
    • Date parsed from source:
      Sep 18, 2026
    • First seen by Releasebot:
      Sep 18, 2026
    Metabase logo

    Metabase

    latest-oss

    Metabase fixes static viz Row Chart failures on remapped columns in a v63 backport.

    🤖 v63 backported "Fix static viz Row Chart failures on remapped colum…

    Original source
  • Sep 18, 2026
    • Date parsed from source:
      Sep 18, 2026
    • First seen by Releasebot:
      Sep 18, 2026
    Metabase logo

    Metabase

    latest-ee

    Metabase fixes static viz row chart failures on remapped columns.

    🤖 v63 backported "Fix static viz Row Chart failures on remapped colum…

    Original source
  • Sep 18, 2026
    • Date parsed from source:
      Sep 18, 2026
    • First seen by Releasebot:
      Sep 18, 2026
    Metabase logo

    Metabase

    embedding-sdk-64-stable

    Metabase releases Tagging SDK stable version for embedding-sdk-64-stable.

    Tagging SDK stable version embedding-sdk-64-stable

    Original source
  • Sep 18, 2026
    • Date parsed from source:
      Sep 18, 2026
    • First seen by Releasebot:
      Sep 18, 2026
    Metabase logo

    Metabase

    embedding-sdk-0.64.0-beta.0

    Metabase ships embedding-sdk-0.64.0-beta.0 tagging SDK version.

    Tagging SDK version

    embedding-sdk-0.64.0-beta.0

    Original source
  • Sep 18, 2026
    • Date parsed from source:
      Sep 18, 2026
    • First seen by Releasebot:
      Sep 18, 2026
    Metabase logo

    Metabase

    custom-viz-v2.0.0-canary.1

    Metabase ships @metabase/custom-viz 2.0.0-canary.1 canary release.

    @metabase/custom-viz 2.0.0-canary.1

    Original source
  • Sep 17, 2026
    • Date parsed from source:
      Sep 17, 2026
    • First seen by Releasebot:
      Sep 14, 2026
    • Modified by Releasebot:
      Sep 17, 2026
    Metabase logo

    Metabase

    embedding-sdk-0.64.0-alpha.4

    Metabase tags the SDK version embedding-sdk-0.64.0-alpha.4.

    Tagging SDK version

    embedding-sdk-0.64.0-alpha.4

    Original source
  • Sep 16, 2026
    • Date parsed from source:
      Sep 16, 2026
    • First seen by Releasebot:
      Sep 10, 2026
    • Modified by Releasebot:
      Sep 17, 2026
    Metabase logo

    Metabase

    Metabase 63.18

    Metabase ships v0.63.18.x with updated Docker and JAR downloads for Open Source and Enterprise.

    Upgrading

    Before you upgrade, back up your Metabase application database!

    Check out our upgrading instructions.

    Get the most out of Metabase. Learn more about advanced features, managed cloud, and first-class support.

    Metabase Open Source

    Docker image: metabase/metabase:v0.63.18.x

    JAR download: https://downloads.metabase.com/v0.63.18.x/metabase.jar

    Metabase Enterprise

    Docker image: metabase/metabase-enterprise:v1.63.18.x

    JAR download: https://downloads.metabase.com/enterprise/v1.63.18.x/metabase.jar

    Changelog

    Full Changelog

    Original source
  • Sep 11, 2026
    • Date parsed from source:
      Sep 11, 2026
    • First seen by Releasebot:
      Sep 12, 2026
    Metabase logo

    Metabase

    v0.63.17.2

    Metabase backports only re-running failed specs for SDK component tests.

    🤖 v63 backported "only re-run the failed specs for SDK component test…

    Original source
  • Sep 11, 2026
    • Date parsed from source:
      Sep 11, 2026
    • First seen by Releasebot:
      Sep 12, 2026
    Metabase logo

    Metabase

    v0.63.17.x

    Metabase backports only rerun failed specs for SDK component tests in v63.

    🤖 v63 backported "only re-run the failed specs for SDK component test…

    Original source
Releasebot

Curated by the Releasebot team

Releasebot is an aggregator of official release notes from hundreds of software vendors and thousands of sources.

Our editorial process involves the manual review and audit of release notes procured with the help of automated systems.