Skip to content

Releases: groupdocs-metadata/GroupDocs.Metadata.Mcp

26.7.3

Choose a tag to compare

@github-actions github-actions released this 25 Jul 19:07

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 folder
    • GROUPDOCS_MCP_OUTPUT_PATH — same folder as storage by default
    • GROUPDOCS_LICENSE_PATHempty by default (evaluation mode)
  • Verified in GroupDocs.Mcp.Core's LicenseManager: an empty license path is
    handled identically to an unset one (string.IsNullOrEmpty guard → evaluation
    mode with a log warning; a wrong path only logs; SetLicenseFromPath is 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

Choose a tag to compare

@github-actions github-actions released this 24 Jul 18:35

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 emits install/generated/ (per-client snippets + deeplinks) and rewrites
    the README install-buttons block idempotently. CI drift guard added to
    build_packages.yml (-Check fails 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.json published-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

Choose a tag to compare

@github-actions github-actions released this 10 Jul 22:27

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 / valueContains filter —
    a thin predicate layer over the engine's FindProperties. 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) or add.
  • Uses the GroupDocs.Metadata Tags taxonomy (SetProperties/AddProperties with 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 (like remove_metadata). Failure prefix:
    Metadata write failed for '<file>': ….

Extended: remove_metadata gains selective removal

  • New optional categories argument: gps, author, comments, company, dates,
    software, copyright, keywords, personal — removed via RemoveProperties by tag.
  • Omitting categories (or passing all) 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 both search_metadata
    and selective remove_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) that FindProperties/SetProperties/RemoveProperties consume — the
    helpers alias it (MetadataPredicate) to disambiguate from System.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_metadata and selective remove_metadata need a license (they call Save); their
    integration tests branch on GROUPDOCS_LICENSE_PATH. search_metadata runs everywhere.

Full Changelog: 26.7.0...26.7.1

26.7.0

Choose a tag to compare

@github-actions github-actions released this 10 Jul 13:56

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 (use ReadMetadata for the full dump).
  • Mirrors the cross-product GetDocumentInfo convention (e.g. GroupDocs.Watermark.Mcp),
    including the Document-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> bumped 26.1.026.6.0.
  • 26.6.0 is the first TFM-split release. The GroupDocs.Metadata metapackage is now
    a thin façade over per-TFM runtime sub-packages (.Net472 / .Net60 / .Net80). Under
    our net10.0 target NuGet resolves the GroupDocs.Metadata.Net80 runtime assemblies.
  • That sub-package now declares its native/graphics dependencies itself:
    • SkiaSharp 3.119.2 + SkiaSharp.NativeAssets.Win32 + SkiaSharp.NativeAssets.Linux
      (so libSkiaSharp.so is now delivered transitively), and
    • Aspose.Drawing / Aspose.Drawing.Common 26.4.0 — a fully managed, cross-platform
      GDI+ replacement — alongside System.Drawing.Common 8.0.0.

Removed the manual SkiaSharp Linux workaround

  • Dropped the SkiaSharp.NativeAssets.Linux.NoDependencies PackageReference 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 .Net80 sub-package brings
    the native asset transitively, so the workaround is now redundant (and, pinned at a different
    version, risked double-placing libSkiaSharp.so).
  • Note the engine pulls the full SkiaSharp.NativeAssets.Linux (which dlopens
    libfontconfig at runtime), not the self-contained NoDependencies variant. libfontconfig1
    is already installed in docker/Dockerfile and the Tests repo's integration.yml, so no new
    gap on Linux.

Descriptive tool errors (previously "Pitfall #18")

  • ReadMetadataTool and RemoveMetadataTool now wrap the engine call in
    try/catch (Exception ex) { return FormatException(...); }. Failures (corrupted input,
    unsupported formats, missing native deps, and — for RemoveMetadata — evaluation-mode
    Save()) now return a descriptive string instead of MCP's opaque
    "An error occurred invoking '<tool>'":
    • ReadMetadataMetadata read failed for '<file>': <Type>: <msg>[ | inner(...)]
    • RemoveMetadataMetadata 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 .Net80 runtime declares the native graphics assets it needs — the
    right long-term footing for cross-platform (Linux/macOS) runs via dnx.
  • 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 == true for the eval-mode RemoveMetadata path must
    pivot to matching the "Metadata removal failed for" prefix (done in the Tests repo, changelog 003).
  • System.Drawing.EnableUnixSupport is kept in the csproj but is now inert — it was removed
    in System.Drawing.Common 7.0+, and 26.6.0 pulls 8.0.0. Whether libgdiplus / 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

Choose a tag to compare

@github-actions github-actions released this 03 May 23:48

26.5.1 — ReadMetadata JSON response no longer truncated mid-document

What changed

  • ReadMetadataTool now returns raw JSON directly instead of routing it through OutputHelper.TruncateText.
  • OutputHelper.TruncateText is intended for plain-text output: when the input exceeds McpConfig.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 using JsonDocument.Parse / JsonSerializer.Deserialize on 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

Choose a tag to compare

@github-actions github-actions released this 27 Apr 20:07

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 upstream GroupDocs.Metadata nuspec 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.soGroupDocs.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 libfontconfig1 step in the final stage (under USER root, with cache cleanup after) so the runtime image has the GDI+ implementation that System.Drawing.Common 6.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 published runtimeconfig.json; without it, System.Drawing.Common 6.0.0's static initializer throws PlatformNotSupportedException on first bitmap allocation regardless of whether libgdiplus is 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:
    1. Top install snippetdnx GroupDocs.Metadata.Mcp --yes is now the lead, with @26.4.4 shown below as the "for shared configs / CI" pinning option.
    2. Claude Desktop config block"args": ["GroupDocs.Metadata.Mcp", "--yes"] with a callout explaining how to swap in the pinned form.
    3. VS Code / Copilot config block — same treatment.
  • 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=dev and a LABEL block on the final stage 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 the docker/build-push-action@v6 step, 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 — dnx crashed during finalization on first SkiaSharp use (server never started), and even when it ran (Docker), JPEG/PNG metadata reads threw PlatformNotSupportedException. 26.4.4 is the first release the dnx flow works on Linux at all, *and...
Read more

26.4.3

Choose a tag to compare

@github-actions github-actions released this 22 Apr 15:42

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.jsonpackages[0].registryBaseUrl changed from https://api.nuget.org to the fully-qualified V3 index https://api.nuget.org/v3/index.json, which is what the Registry's server-side validation expects for registryType: nuget.
  • .github/workflows/publish_prod.yml — removed the MCP_REGISTRY_PUBLISH opt-in variable gate; the publish_mcp_registry job 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 mainmaster throughout 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

Choose a tag to compare

@github-actions github-actions released this 22 Apr 11:44

Fix Docker image + enable MCP Registry publishing

What changed

  • docker/Dockerfile — switched from a custom adduser step to USER $APP_UID, the non-root user pre-shipped by mcr.microsoft.com/dotnet/aspnet:10.0 (UID 1654). The previous adduser command 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 description to fit the MCP schema's 100-character cap and dropped inaccurate "write" wording (the server only exposes ReadMetadata and RemoveMetadata, 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 $ref to the draft-07 meta-schema natively instead of tripping ajv's strict mode.
  • MCP Registry publishing enabled — MCP_REGISTRY_PUBLISH=true repo variable now set, so publish_prod.yml → publish_mcp_registry runs 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

Choose a tag to compare

@github-actions github-actions released this 21 Apr 22:30

Fix repository URL + bump Core to 26.4.1

What changed

  • PackageProjectUrl, RepositoryUrl, and PackageReleaseNotes in build/dependencies.props now use the canonical repo URL https://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.url updated to the same canonical URL and MCP Registry name aligned to io.github.groupdocs-metadata/groupdocs-metadata-mcp so GitHub OIDC namespace verification succeeds. Both version fields bumped to 26.4.1.
  • README.mddnx GroupDocs.Metadata.Mcp@… pinned version updated in all three snippets (install, Claude Desktop, VS Code).
  • Upgraded GroupDocs.Mcp.Core dependency from 26.4.0 to 26.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