Metabase Release Notes
196 release notes curated from 69 sources by the Releasebot Team. Last updated: Sep 19, 2026
- Sep 18, 2026
- Date parsed from source:Sep 18, 2026
- First seen by Releasebot:Sep 19, 2026
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
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.
- Sep 18, 2026
- Date parsed from source:Sep 18, 2026
- First seen by Releasebot:Sep 19, 2026
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
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
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:
- Hubspot release notes188 release notes · Latest Sep 16, 2026
- Plaid release notes84 release notes · Latest Sep 11, 2026
- n8n release notes68 release notes · Latest Sep 15, 2026
- Cursor release notes134 release notes · Latest Sep 10, 2026
- Obsidian release notes113 release notes · Latest Sep 15, 2026
- Perplexity release notes30 release notes · Latest Aug 24, 2026
- Sep 18, 2026
- Date parsed from source:Sep 18, 2026
- First seen by Releasebot:Sep 18, 2026
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
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
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
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
embedding-sdk-0.64.0-beta.0
Metabase ships embedding-sdk-0.64.0-beta.0 tagging SDK version.
- Sep 18, 2026
- Date parsed from source:Sep 18, 2026
- First seen by Releasebot:Sep 18, 2026
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
embedding-sdk-0.64.0-alpha.4
Metabase tags the SDK version embedding-sdk-0.64.0-alpha.4.
- Sep 16, 2026
- Date parsed from source:Sep 16, 2026
- First seen by Releasebot:Sep 10, 2026
- Modified by Releasebot:Sep 17, 2026
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
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
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
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.