Releases: groupdocs-metadata/GroupDocs.Metadata.Mcp
Release list
26.7.3
26.7.3 — Full configuration surface in install snippets (docs/infra only)
What changed
No server code changes — the bump republishes so the refreshed README (install
buttons above the fold, Codex/Windsurf guides, fixed one-click links) reaches the
NuGet package page, Docker/GHCR, and the MCP Registry.
- Every install snippet and one-click deeplink (VS Code / Cursor buttons, Claude
Desktop/Code, VS Code, VS 2022, Cursor, Windsurf, Cline, Rider, Codex) now
pre-fills all supported environment variables so users see the full
configuration surface in the install dialog:GROUPDOCS_MCP_STORAGE_PATH— placeholder documents folderGROUPDOCS_MCP_OUTPUT_PATH— same folder as storage by defaultGROUPDOCS_LICENSE_PATH— empty by default (evaluation mode)
- Verified in
GroupDocs.Mcp.Core'sLicenseManager: an empty license path is
handled identically to an unset one (string.IsNullOrEmptyguard → evaluation
mode with a log warning; a wrong path only logs;SetLicenseFromPathis wrapped
in try/catch) — an empty value can never fail the server.
Migration / impact
Drop-in — the server binary is identical apart from the version stamp.
Full Changelog: 26.7.2...26.7.3
26.7.2
26.7.2 — Discoverability & one-click install uplift (docs/infra only)
What changed
Rollout of the org-wide MCP repo improvement plan (piloted on GroupDocs.Conversion.Mcp
26.7.1). No server code changes — the bump ships the new README to the NuGet package page.
- README: badge row (NuGet version/downloads, Docker pulls, MCP Registry, Tests-repo CI,
MIT), demo placeholder, one-click VS Code / Cursor install buttons, pointer to
ready-made client configs (Claude Code, VS 2022, Cursor, Windsurf, Cline, Rider), and a
Licensing section documenting the product's evaluation-mode limits with temporary
license / purchase links. install/config.json+install/generate-install-links.ps1: canonical install config;
the generator emitsinstall/generated/(per-client snippets + deeplinks) and rewrites
the README install-buttons block idempotently. CI drift guard added to
build_packages.yml(-Checkfails the build when generated content is stale).- Hygiene:
SECURITY.md,CONTRIBUTING.md, issue templates,smithery.yaml,
docker/README.hub.md, llms.txt licensing section,.vscode/mcp.jsonpublished-package
entry, GitHub topics.
Why
AI-agent users find MCP servers through registries, GitHub topics, and READMEs; installers
copy the first snippet they see. One canonical config keeps every rendered snippet correct
permanently, and licensing up front removes the main evaluation-mode surprise.
Migration / impact
Drop-in — the server binary is identical to 26.7.1 apart from the version stamp.
Full Changelog: 26.7.1...26.7.2
26.7.1
26.7.1 — SearchMetadata + WriteMetadata tools, selective RemoveMetadata
Follow-up to 26.7.0 (engine bump + GetDocumentInfo + descriptive errors). Grows the tool
surface from 3 to 5 and turns the server into a full read/write/search/remove facade over
the GroupDocs.Metadata SDK.
What changed
New tool: search_metadata
- Returns only the properties matching a
category/nameContains/valueContainsfilter —
a thin predicate layer over the engine'sFindProperties. Answers targeted questions like
"show me the author" or "does this have GPS?" without dumping the whole property set. - Read-only (no
Save), so it works in evaluation mode. - Returns
{ count, properties: [{ name, value, category }] }. On failure the text starts with
Metadata search failed for '<file>': ….
New tool: write_metadata
- Sets, changes, or adds a property (Author, Title, Subject, Keywords, Comments, Copyright,
Company, Manager) and saves the updated file.mode=set(default) oradd. - Uses the GroupDocs.Metadata Tags taxonomy (
SetProperties/AddPropertieswith a
Tags.*predicate) so one friendly field name maps to the correct per-format field
automatically (PDF Info/XMP, Office document properties, EXIF/IPTC for images) and is created
when absent. Requires a license (likeremove_metadata). Failure prefix:
Metadata write failed for '<file>': ….
Extended: remove_metadata gains selective removal
- New optional
categoriesargument:gps,author,comments,company,dates,
software,copyright,keywords,personal— removed viaRemovePropertiesby tag. - Omitting
categories(or passingall) preserves the previous full-wipe (Sanitize)
behavior. Fully backward compatible — no change for existing callers.
Shared internals
Tools/MetadataCategories.cs— one category→tag-predicate map, used by bothsearch_metadata
and selectiveremove_metadata(single source of truth for the taxonomy).Tools/ToolError.cs— the descriptive-error formatter, previously duplicated per tool, now
extracted and used by all five tools.- Note: GroupDocs.Metadata ships its own
GroupDocs.Metadata.Common.Func<T,TResult>delegate
(Java-port artifact) thatFindProperties/SetProperties/RemovePropertiesconsume — the
helpers alias it (MetadataPredicate) to disambiguate fromSystem.Func.
Migration / impact
- Drop-in. No changes to existing
read_metadata/remove_metadata/get_document_info
wire names or behavior. Three new capabilities are additive. write_metadataand selectiveremove_metadataneed a license (they callSave); their
integration tests branch onGROUPDOCS_LICENSE_PATH.search_metadataruns everywhere.
Full Changelog: 26.7.0...26.7.1
26.7.0
26.7.0 — Engine bump to GroupDocs.Metadata 26.6.0 (TFM-split package), new GetDocumentInfo tool + descriptive tool errors
What changed
New tool: GetDocumentInfo
- Adds a third MCP tool (
get_document_info) that returns a document's file type, MIME type,
page count, byte size, and encryption status as JSON — a lightweight structural check that
does not enumerate metadata properties (useReadMetadatafor the full dump). - Mirrors the cross-product
GetDocumentInfoconvention (e.g. GroupDocs.Watermark.Mcp),
including theDocument-info lookup failed for '<file>': ...error contract. - Returns fields
fileName,fileFormat,mimeType,pageCount,sizeBytes,isEncrypted.
Engine: GroupDocs.Metadata 26.1.0 → 26.6.0
build/dependencies.props:<GroupDocsMetadata>bumped26.1.0→26.6.0.- 26.6.0 is the first TFM-split release. The
GroupDocs.Metadatametapackage is now
a thin façade over per-TFM runtime sub-packages (.Net472/.Net60/.Net80). Under
ournet10.0target NuGet resolves theGroupDocs.Metadata.Net80runtime assemblies. - That sub-package now declares its native/graphics dependencies itself:
SkiaSharp3.119.2 +SkiaSharp.NativeAssets.Win32+SkiaSharp.NativeAssets.Linux
(solibSkiaSharp.sois now delivered transitively), andAspose.Drawing/Aspose.Drawing.Common26.4.0 — a fully managed, cross-platform
GDI+ replacement — alongsideSystem.Drawing.Common8.0.0.
Removed the manual SkiaSharp Linux workaround
- Dropped the
SkiaSharp.NativeAssets.Linux.NoDependenciesPackageReference and the
<SkiaSharp>version property. They existed only because the pre-split engine's nuspec
declared managed SkiaSharp with no native Linux asset. 26.6.0's.Net80sub-package brings
the native asset transitively, so the workaround is now redundant (and, pinned at a different
version, risked double-placinglibSkiaSharp.so). - Note the engine pulls the full
SkiaSharp.NativeAssets.Linux(which dlopens
libfontconfigat runtime), not the self-containedNoDependenciesvariant.libfontconfig1
is already installed indocker/Dockerfileand the Tests repo'sintegration.yml, so no new
gap on Linux.
Descriptive tool errors (previously "Pitfall #18")
ReadMetadataToolandRemoveMetadataToolnow wrap the engine call in
try/catch (Exception ex) { return FormatException(...); }. Failures (corrupted input,
unsupported formats, missing native deps, and — forRemoveMetadata— evaluation-mode
Save()) now return a descriptive string instead of MCP's opaque
"An error occurred invoking '<tool>'":ReadMetadata→Metadata read failed for '<file>': <Type>: <msg>[ | inner(...)]RemoveMetadata→Metadata removal failed for '<file>': <Type>: <msg>[ | inner(...)]
Why
- Keeps the server on the current engine and, more importantly, moves it onto the modern
TFM-split package whose.Net80runtime declares the native graphics assets it needs — the
right long-term footing for cross-platform (Linux/macOS) runs viadnx. - Descriptive errors make native-dependency and eval-mode failures diagnosable by AI agents
and integration tests instead of surfacing as a generic MCP invocation error.
Migration / impact
- Drop-in for consumers. No public-API or wire-name changes (
read_metadata,remove_metadata). - Integration tests that asserted
IsError == truefor the eval-modeRemoveMetadatapath must
pivot to matching the"Metadata removal failed for"prefix (done in the Tests repo, changelog 003). System.Drawing.EnableUnixSupportis kept in the csproj but is now inert — it was removed
inSystem.Drawing.Common7.0+, and 26.6.0 pulls 8.0.0. Whetherlibgdiplus/ the flag can be
dropped entirely (relying on Aspose.Drawing) is tracked as an open item in
assets/2026-07-01.md, pending confirmation on the 3-OS CI matrix.
Full Changelog: 26.5.1...26.7.0
26.5.1
26.5.1 — ReadMetadata JSON response no longer truncated mid-document
What changed
ReadMetadataToolnow returns raw JSON directly instead of routing it throughOutputHelper.TruncateText.OutputHelper.TruncateTextis intended for plain-text output: when the input exceedsMcpConfig.MaxOutputCharacters(default 5000), it appends a[Output truncated — showing first X of Y characters. ...]marker on a new line. That marker is non-JSON and breaks any consumer usingJsonDocument.Parse/JsonSerializer.Deserializeon the response.- Affected callers in practice: PDFs with rich XMP / image-bearing documents with extensive EXIF / Office documents with many custom properties (any of these can push the metadata JSON past 5 KB), plus any client that strict-parses the tool response. Lenient consumers (Claude, Cursor, VS Code Copilot) tolerate the trailing marker, so user-visible AI-agent flows in 26.4.4 are unaffected.
Why
Tools that emit structured JSON should always return valid JSON regardless of size. Truncation should be expressed inside the JSON document (e.g. capped inner array + truncated: true flag) rather than by appending a non-JSON marker line. In practice the response is bounded by API realities (a few KB to ~30 KB for richly-tagged documents), so removing the wrapping is sufficient — no in-document truncation needed today.
Skip from 26.4.4 to 26.5.1
This release skips the 26.5.0 patch number — that label was used by the sibling Conversion / Comparison / Viewer MCP servers for their initial public release, and bumping Metadata in lockstep with the family fix keeps version-discovery tooling consistent across the four products. CalVer doesn't require contiguous patch numbers within a YY.MM band; no prior consumer pinned =26.5.0 on Metadata because that build never existed.
Migration / impact
Drop-in replacement for 26.4.4. No public-API or wire-name changes. Tool responses now contain only the JSON document; previous trailing marker line for ~5KB+ responses is gone. Strict-JSON parsers that broke against 26.4.4 work cleanly against 26.5.1.
Full Changelog: 26.4.4...26.5.1
26.4.4
Linux runtime fixes (SkiaSharp + libgdiplus), README polish, and Docker image OCI labels
What changed
Linux native asset fix (the real production bug)
- build/dependencies.props — added
<SkiaSharp>3.119.0</SkiaSharp>under "External Dependency Versions" with an inline comment requiring this property to stay in lockstep with whatever SkiaSharp version$(GroupDocsMetadata)transitively pulls (ABI-incompatible otherwise). - src/GroupDocs.Metadata.Mcp/GroupDocs.Metadata.Mcp.csproj — added
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="$(SkiaSharp)" />. Inline comment flags this as a workaround for the upstreamGroupDocs.Metadatanuspec gap and notes it can be dropped once the upstream nuspec declares the platform native asset packages.
Before: the published 26.4.3 nupkg shipped tools/net10.0/any/runtimes/{win-*,osx}/native/libSkiaSharp.{dll,dylib} but no linux-*/native/libSkiaSharp.so — GroupDocs.Metadata's nuspec only declares <dependency id="SkiaSharp" version="3.119.0" /> (managed assembly only), so dnx-installed packages on Ubuntu had nothing to load when SkiaSharp's SKObject..cctor ran. The integration tests crashed with SkiaSharpVersion.CheckNativeLibraryCompatible → unhandled finalizer exception → MCP server process exited unexpectedly on every Ubuntu CI job.
After: the 26.4.4 nupkg ships all 12 Linux native variants (linux-x64, linux-arm64, linux-musl-x64, linux-arm, linux-x86, linux-loongarch64, linux-riscv64, plus the four linux-musl-* siblings). Verified via Expand-Archive of the locally-built nupkg; the previously-empty runtimes/linux-* paths now contain the expected libSkiaSharp.so files (8.8 MB for linux-x64).
libgdiplus / System.Drawing.Common Linux fix (the second Linux production bug)
- docker/Dockerfile — added an
apt-get install -y --no-install-recommends libgdiplus libfontconfig1step in thefinalstage (underUSER root, with cache cleanup after) so the runtime image has the GDI+ implementation thatSystem.Drawing.Common6.0.0 P/Invokes on Linux. - src/GroupDocs.Metadata.Mcp/GroupDocs.Metadata.Mcp.csproj — added
<RuntimeHostConfigurationOption Include="System.Drawing.EnableUnixSupport" Value="true" />. Emitted into the publishedruntimeconfig.json; without it,System.Drawing.Common6.0.0's static initializer throwsPlatformNotSupportedExceptionon first bitmap allocation regardless of whetherlibgdiplusis present.
Before: reading metadata from a JPEG (sample.jpg from the integration tests) through the published Docker image produced this stack:
System.TypeInitializationException: The type initializer for 'Gdip' threw an exception.
---> System.PlatformNotSupportedException: System.Drawing.Common is not supported on non-Windows platforms.
at System.Drawing.LibraryResolver.EnsureRegistered()
at System.Drawing.SafeNativeMethods.Gdip.PlatformInitialize()
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height) ← inside GroupDocs.Metadata
PDF/DOCX/XLSX paths were unaffected (those don't go through Bitmap). Only image formats (JPEG, PNG, image-bearing PDFs) tripped this.
After: the runtime config flag flips the gate, and libgdiplus.so is loadable from the container's /usr/lib/x86_64-linux-gnu/. JPEG/PNG read_metadata calls succeed.
README polish — install snippets default to unpinned
- README.md — three install snippets reworked to lead with the unpinned form and show pinning as the explicit alternative:
- Top install snippet —
dnx GroupDocs.Metadata.Mcp --yesis now the lead, with@26.4.4shown below as the "for shared configs / CI" pinning option. - Claude Desktop config block —
"args": ["GroupDocs.Metadata.Mcp", "--yes"]with a callout explaining how to swap in the pinned form. - VS Code / Copilot config block — same treatment.
- Top install snippet —
- README.md — new "Documentation & guides" section above the License heading, linking to the companion GroupDocs.Metadata.Mcp.Tests repo and its six per-channel how-to guides (NuGet install, Docker, MCP registry verification, Claude Desktop, VS Code / Copilot, integration tests). Includes a one-sentence note that the Tests repo exercises every advertised tool against the published NuGet artifact on Linux / macOS / Windows in CI.
Docker image OCI labels
- docker/Dockerfile — added
ARG VERSION=devand aLABELblock on thefinalstage with seven OCI standard labels:image.title,image.description,image.version,image.source,image.url,image.licenses,image.vendor. - .github/workflows/publish_docker.yml — added
build-args: VERSION=${{ steps.version.outputs.version }}to thedocker/build-push-action@v6step, so each release substitutes the real package version into the label at build time.
Why
Linux native asset fix: the GroupDocs.Metadata published nuspec declares only <dependency id="SkiaSharp"> — neither SkiaSharp.NativeAssets.Linux.NoDependencies nor any other native-asset package is listed. This is fine for normal application consumers (the .NET runtime loads natives from the consumer's resolved package graph), but <PackAsTool>true</PackAsTool> packages a self-contained tool layout — the runtimes/<rid>/native/ content is only copied for RIDs whose native-asset packages are in this project's resolved graph. Win32 and macOS native libs reach the MCP package transitively through some other Aspose dep; Linux doesn't. Adding the explicit SkiaSharp.NativeAssets.Linux.NoDependencies reference here patches the gap until the upstream GroupDocs.Metadata nuspec is fixed to declare it directly. Tied to $(SkiaSharp) so the lock-step is one property edit at every upstream bump rather than scattered.
libgdiplus / System.Drawing.Common Linux fix: Microsoft made System.Drawing.Common Windows-only by default in .NET 6 — non-Windows callers throw PlatformNotSupportedException from the static initializer unless the System.Drawing.EnableUnixSupport runtime config flag is set. The flag must be declared on the entry-point project (the one that emits runtimeconfig.json), not on a referenced library — so even though the upstream GroupDocs.Metadata.csproj source has it, the flag doesn't propagate to consumers. Combined with the missing libgdiplus system package in the Debian-based runtime image (the mcr.microsoft.com/dotnet/aspnet:10.0 base intentionally omits it for image-size reasons), every JPEG/PNG read_metadata call on Linux failed. Both pieces are required: opt-in alone gives DllNotFoundException, libgdiplus alone gives PlatformNotSupportedException. The fix has a hard expiry — the EnableUnixSupport flag was removed in System.Drawing.Common 7.0+; GroupDocs.Metadata 26.x pins 6.0.0 so the flag still works. If upstream ever bumps past 6.0.0 without migrating off System.Drawing, this stops working and the consumer needs a different escape hatch.
README polish: users upgrading the package on their own cadence (every 1–2 months in the typical case) shouldn't have to copy-paste a new version into their MCP client config every release. The unpinned form is the natural default for solo / dev use; pinning is the deliberate choice for committed / CI configs. Mirrors how npx / dnx are typically used elsewhere. The new Documentation & guides section makes the companion test repo (which already provides per-channel walkthroughs) discoverable from the canonical README — previously users hit the package page with no hint that step-by-step guides exist outside this repo.
Docker image OCI labels: the published image inherited org.opencontainers.image.version from the base mcr.microsoft.com/dotnet/aspnet:10.0 image, which sets the label to the Ubuntu OS version (24.04). Verified by inspecting ghcr.io/groupdocs-metadata/metadata-net-mcp:latest:
$ docker inspect ... --format '{{index .Config.Labels "org.opencontainers.image.version"}}'
24.04
Effect: every release pushed to ghcr.io / Docker Hub since the project began carries the same 24.04 version label, regardless of whether the underlying GroupDocs.Metadata.Mcp version is 26.4.0 or 26.4.3. The label is one of the standard ways tooling (Renovate, Dependabot, registry UIs, security scanners) infers what's running, and a wrong/stuck value defeats them.
After this fix, docker inspect ghcr.io/groupdocs-metadata/metadata-net-mcp:26.4.4 will return "version":"26.4.4". Local docker build runs without --build-arg VERSION=... get version=dev — self-identifying as a non-release build instead of inheriting the misleading 24.04.
The other six labels (title, description, source, url, licenses, vendor) are static — they don't need to change between releases — but were missing entirely from the inherited set, so registries and clients couldn't surface basic metadata about what the image is or who publishes it.
Migration / impact
- No API changes, no tool changes, no breaking config changes. The csproj edit produces a larger published nupkg (~8 MB extra for the Linux native libs), the Docker image grows ~3 MB compressed for libgdiplus + libfontconfig1, and consumers see the same MCP tool surface. The Docker label additions are pure metadata — container behaviour is identical.
- For users on Linux: 26.4.3 was effectively broken in two stages —
dnxcrashed during finalization on first SkiaSharp use (server never started), and even when it ran (Docker), JPEG/PNG metadata reads threwPlatformNotSupportedException. 26.4.4 is the first release thednxflow works on Linux at all, *and...
26.4.3
MCP Registry NuGet ownership marker + corrected registry URL
What changed
- README.md — added
<!-- mcp-name: io.github.groupdocs-metadata/groupdocs-metadata-mcp -->footer marker. The MCP Registry reads this from the published NuGet package as the NuGet-side ownership proof, complementing the GitHub OIDC namespace claim. - src/GroupDocs.Metadata.Mcp/.mcp/server.json —
packages[0].registryBaseUrlchanged fromhttps://api.nuget.orgto the fully-qualified V3 indexhttps://api.nuget.org/v3/index.json, which is what the Registry's server-side validation expects forregistryType: nuget. - .github/workflows/publish_prod.yml — removed the
MCP_REGISTRY_PUBLISHopt-in variable gate; thepublish_mcp_registryjob now runs on every release via GitHub OIDC, consistent with how NuGet and Docker publishing work. - RELEASE.md — dropped the opt-in variable from the secrets/variables table, removed the "One-time MCP Registry setup" section (replaced with a shorter namespace-verification note), and synced
main→masterthroughout to match the repo's actual default branch.
Why
26.4.2 reached NuGet and both container registries cleanly but the MCP Registry publish failed twice — first on a URL-format check, then on the missing ownership marker (which NuGet packages treat as immutable, so 26.4.2 couldn't be retro-fixed). 26.4.3 lands all three corrections in one shot so the full four-channel release pipeline (NuGet + ghcr.io + Docker Hub + MCP Registry) publishes end-to-end from a single tag.
Migration / impact
None for consumers. No API changes, no tool changes. The README gains an HTML-comment footer that's invisible when rendered.
Full Changelog: 26.4.2...26.4.3
26.4.2
Fix Docker image + enable MCP Registry publishing
What changed
- docker/Dockerfile — switched from a custom
adduserstep toUSER $APP_UID, the non-root user pre-shipped bymcr.microsoft.com/dotnet/aspnet:10.0(UID 1654). The previousaddusercommand was Debian-specific and broke on the Azure Linux base image that Microsoft now uses for .NET 10. - src/GroupDocs.Metadata.Mcp/.mcp/server.json — shortened
descriptionto fit the MCP schema's 100-character cap and dropped inaccurate "write" wording (the server only exposesReadMetadataandRemoveMetadata, no write tool). - .github/workflows/run_tests.yml — replaced the ajv-cli schema-validation step with
check-jsonschema, which handles the MCP schema's cross-draft$refto the draft-07 meta-schema natively instead of tripping ajv's strict mode. - MCP Registry publishing enabled —
MCP_REGISTRY_PUBLISH=truerepo variable now set, sopublish_prod.yml → publish_mcp_registryruns on every release via GitHub OIDC.
Why
The 26.4.1 release succeeded on NuGet but the Docker image build blew up on the adduser step (Azure Linux base doesn't ship Debian's adduser wrapper), and the MCP Registry step was gated behind an opt-in variable that hadn't been set — so 26.4.1 was never listed at registry.modelcontextprotocol.io. 26.4.2 is the end-to-end verification that all three channels (NuGet + Docker + MCP Registry) publish cleanly from a single release.
Migration / impact
None for consumers. No API changes, no behaviour changes — same two tools, same env vars, same schema.
Full Changelog: 26.4.1...26.4.2
26.4.1
Fix repository URL + bump Core to 26.4.1
What changed
PackageProjectUrl,RepositoryUrl, andPackageReleaseNotesin build/dependencies.props now use the canonical repo URLhttps://github.com/groupdocs-metadata/GroupDocs.Metadata.Mcp. Previous value (groupdocs/groupdocs-metadata-mcp) was wrong on both the org and the casing.- src/GroupDocs.Metadata.Mcp/.mcp/server.json
repository.urlupdated to the same canonical URL and MCP Registrynamealigned toio.github.groupdocs-metadata/groupdocs-metadata-mcpso GitHub OIDC namespace verification succeeds. Bothversionfields bumped to26.4.1. - README.md —
dnx GroupDocs.Metadata.Mcp@…pinned version updated in all three snippets (install, Claude Desktop, VS Code). - Upgraded
GroupDocs.Mcp.Coredependency from26.4.0to26.4.1(which carries the matching URL fix for the Core packages).
Why
git clone against the hyphenated URL redirected, but deep links like /releases/tag/26.4.0 on the NuGet "Project website" button did not — users hit a GitHub 404 instead of the release notes.
Migration / impact
None for consumers upgrading from 26.4.0 to 26.4.1 — no API changes, just metadata corrections. The next nuget.org listing will link correctly.
Full Changelog: https://github.com/groupdocs-metadata/GroupDocs.Metadata.Mcp/commits/26.4.1