Skip to content

Releases: sitefinitysteve/SitefinityCommunity.Mcp

v3.8.0

Choose a tag to compare

@github-actions github-actions released this 08 Sep 23:39

Added

  • New skill sitefinity-dynamic-content-sql (18 skills). Gets Module Builder content out of the database as flat rows for reports, Power BI, audits and migration inventories, where the classic pain is that one item is spread over sf_dynamic_content, a per-type table, mangled junction tables and sf_content_link. The skill covers:
    • The storage model — lifecycle columns vs field values, one row per state (Master / Temp / Live / Deleted) each with its own per-type and junction rows, what unpublish, expiry and delete actually do to those rows, hierarchy (parent_id always points at the parent's master), taxonomy vs multi-select Choices junctions (val is a taxon id or a choice value), single-select Choices, related data and media through sf_content_link with its per-lifecycle availability flags, Address fields (sf_addresses), Link fields (JSON), default URLs, owners.
    • Resolving a type to its tables from the platform's own metadata — sf_meta_data_mapping first, naming convention second, and a column-signature match for types whose table carries a hand-chosen name; junction tables through sys.foreign_keys (they are not in the mapping) with a name-mangling-aware match back to the field.
    • Publication state — Published / Scheduled / Expired / Unpublished / Draft / Deleted derived from the rows and the scheduler, reconciled against the approval trail and raw counts.
    • reference/flatten-dynamic-content.sql — a generator with four modes: select runs the flattened query, sql returns it, view creates one view per type for BI, and poco emits the matching C# row class. Every taxonomy, multi-choice, related-item and address field becomes a JSON column with PascalCase keys. Runs as a plain batch with no DDL rights, or wrapped as a stored procedure; inputs that reach generated code are validated.
    • reference/FlatRowSupport.cs — base row class, TaxonRef / RelatedRef / AddressRef, and null-safe parsers using ServiceStack.Text (already in every Sitefinity bin folder, no JsConfig changes), with Dapper and EF Core mapping notes. Compiles on .NET Framework 4.8 and .NET 8.
    • Verified on Sitefinity 15.4 against a production-sized database across eight type shapes, including two types whose tables carry hand-chosen names; the generated class was compiled and exercised against the bundled ServiceStack.Text.

Changed

  • sitefinity-database-structure corrects the junction-table guidance: Module Builder junction tables are not listed in sf_meta_data_mapping (find them through sys.foreign_keys), the mapping can miss whole types, multi-select Choices fields also produce junction tables (val is the choice value, not a taxon id), and sf_url_data.item_type can be NULL on dynamic rows.
  • sitefinity-best-practices routes flat-SQL / reporting questions to the new skill and states the table-discovery rule.
  • sitefinity-react-vite8-guide is vendor-neutral. mountWidget now lives in mount.tsx with a hand-rolled error boundary that forwards to a pluggable reportError / setErrorReporter sink; @sentry/react is no longer a required dependency or a file name, and Sentry appears only in an optional "8a" wiring example (any monitoring SDK fits the same seam). bun and oxlint/oxfmt are described as the reference project's choices rather than requirements, with npm / ESLint / Prettier called out as equivalent. The Vue guide's description, the README row and the skill router were reworded to match.
  • README install guidance recommends the global (-g) install and notes that npx skills update never adds new skills, so a release that ships a new skill needs add again.

v3.7.0

Choose a tag to compare

@github-actions github-actions released this 08 Sep 20:00

Added

  • sitefinity-api-helpers skill — a verified cheat sheet of the platform helpers production Sitefinity code actually reaches for, so custom code stops re-implementing them badly: ToSitefinityUITime and the other DateTime/string extensions, GetValue / GetString / SetValue on any data item, GetRelatedItems and content links, lifecycle helpers (GetLive, IsPublished), media URL resolution, page URLs, identity and permission checks (ClaimsManager, RoleManager, IsGranted), elevated privilege, design/preview/index mode detection, TypeResolutionService, and Config.Get. Every signature was verified on Sitefinity 15.4.8636 and cross-checked against real-world usage, with call counts noted where they show which helper is the idiom.
  • sitefinity-react-vite8-guide skill — the React 19 counterpart to the existing Vue 3 guide: React 19 + Vite 8 (Rolldown) + Tailwind CSS v4 + shadcn/ui on classic Sitefinity MVC (MvcControllerProxy widgets, not the ASP.NET Core Renderer). Covers data-island widgets, per-widget code splitting, the React root lifecycle inside Sitefinity's page editor (mount, remount, teardown), keeping content search-indexable, error boundaries with a pluggable error-reporting hook, the HMR dev server, and lint/format tooling — plus how to migrate widgets over from the Vue 3 guide.

Changed

  • sitefinity_where_used widget Origin now reports "custom" for any widget whose controller/type namespace is not Sitefinity's own (Telerik.Sitefinity.*, Progress.Sitefinity.*), "sitefinity" for the platform's, and "unknown" only when no type is present. The previous build hard-coded one site's namespace and labelled everything else "unknown".
  • Skills: sitefinity-database-structure rewritten with corrected table mappings and relationship logic, verified on Sitefinity 15.4.8636 against a live database, with a column-by-column relationship map and re-runnable verification queries under reference/; companion page skills corrected (the schema has FKs, but only on structural tables; form controls use content_id / id3; what a version snapshot restores). Example emails and site names in docs and tests replaced with neutral placeholders.
  • sitefinity-adminapp-extensions rewritten and verified against Sitefinity 15.4: how bundles are discovered, concatenated (file-name order), cached and served (/admin-bridge/extensions, sf:DisableAdminAppExtensionsCache); the full v1 extension-point surface (fields, widget designers, commands, columns, item hooks, field bindings, editor, selectors, notifications, themes, tree, DAM); FieldBase as it really is; the shortText vs shortTextDefault rule and the 34 FieldTypes members the 15.3 typings lack; the widget-undefined key for complex sub-fields; HTTP_PREFIX as the sfprefix sentinel; and where the official samples repo is stale.
  • sitefinity-widget-expert gains a verified routing section: how extra URL segments start as an implicit 404, which mechanisms mark them resolved ([RelativeRoute], IRouteMapper, convention dispatch, RouteHelper.SetUrlParametersResolved), why HttpNotFound() matters, and how ViewBag.Title / MetadataFields + PageTitleMode become the page title.
  • Skill consolidation (18 -> 17). sitefinity-toolbox-icons is folded into sitefinity-widget-expert as its "Toolbox icons" section (icon classes, verification, page-editor MVC badge CSS). sitefinity-widget-expert no longer duplicates the attribute catalogue - its fifteen attribute sections are replaced by a one-screen working set that points at sitefinity-designer-attributes, which now links back. Removes ~200 lines that had already drifted between the two files. Every toolbox icon class now carries a description of what its tile actually shows (all 57 tiles inspected), grouped by what a widget does rather than by Sitefinity's original module, with the labelled sheet shipped as reference/toolbox-icons-sheet.png.

v3.6.0

Choose a tag to compare

@github-actions github-actions released this 29 Aug 01:56

Added

  • sitefinity_get_scheduled_task_status — the "is something running, hung, or broken right now?" tool, backed by the new GET /mcp/scheduled-tasks endpoint reading Sitefinity's SchedulingManager. Two sections, both bounded status-filtered queries — the scheduled-task store is never enumerated:
    • RunningNow (cap 25) — every genuinely running task, with Name (its CLR type, as the admin's Scheduled tasks screen shows it), the item it is working on, StartedUtc / StartedLocal, StartedSource (Sitefinity has no dedicated "started" column, so the proxy used is stated rather than implied), RunningForSeconds, reported progress, and IsSearchIndexRebuild + IndexName for reindex tasks. A large RunningForSeconds on a normally-quick task is a hung task.
    • Failed (cap 10, newest execution first) — task rows whose scheduler status is Failed, with ScheduledForUtc / ExecutedOnUtc (and both local forms) and the failure message. This is the section nobody looks at: a reindex that failed weeks ago sits here silently while search serves stale results.
    • A row counts as running only when IsRunning AND its scheduler status is Started. Sitefinity leaves IsRunning set on rows that later failed or were left pending, so filtering on it alone reports months-old failed and pending tasks as running — and double-lists the failed ones, which also appear in Failed. When the status cannot be read at all, RunningNow comes back empty rather than unfiltered: a wrong "running" claim sends someone hunting a process that ended months ago.
    • Successfully completed rows are deliberately not returned — the scheduler deletes them, so the table is not a history. HistoryNote points at sitefinity_search_logs with the pattern Scheduler: Task executed.
  • sitefinity_list_search_indexes — the "why is search stale?" tool, backed by GET /mcp/search-indexes. Lists every configured search index (a search-index pipe on a publishing point; uncapped, since sites have a handful) with catalog name, admin title, publishing point, backend/provider, active state, whether the backend says the index Exists, DocumentCount where a count is obtainable, LastUpdatedUtc / Local plus LastUpdatedSource (the on-disk catalogue folder for file-backed backends, otherwise the publishing point's last publication date), IsRebuilding + RebuildProgress, ContentSources, and — usually the whole answer — LastReindexStatus (running / failed / completed / unknown) with LastReindexUtc / Local, cross-referenced against the scheduler's own reindex rows.
    • Reindex cross-referencing matches on a normalized name. A scheduled-task row names an index the way the admin does (Docs Index); the pipe names it the way a search query does (docs-index). Comparing those literally matches nothing, which would leave a failed reindex showing LastReindexStatus: "unknown" on exactly the indexes that are broken. The display name is compared first, then both sides fall back to a form with case and separators stripped.
    • Each index carries both names — catalog Name and display Title (never blank: it falls back through the publishing point's localized title and name to the catalog name) — so agents and humans recognize the same index.
    • Title is never a type name. The pipe's UIName is the pipe TYPE's label (SearchIndexPipe) on at least some Sitefinity versions — worse than blank, because it looks like a real answer — so candidates that name a pipe or type are rejected outright, the publishing point's title and name are preferred, and the title is otherwise derived from the catalog name (docs-index to Docs Index). TitleSource says which was used.
    • Backend falls back to the concrete search service type when the pipe names no provider. Sitefinity's search-service decorators are unwrapped by scanning the wrapper's own properties and fields for the first member whose value is itself a search service — identified by TYPE, since the member is not named consistently across versions.
    • When the backend stays hidden the response degrades honestly: Backend and DocumentCount report null rather than the wrapper's type name, the index-folder probe is skipped, and a single response-level warning names the wrapper and says what is unavailable — instead of a near-identical note on every index. Last-updated still falls back to the publishing point's last publication date.
    • Every publishing provider is queried, search provider first. Sitefinity keeps search indexes under their own publishing provider — PublishingConfig.SearchProviderName (SearchPublishingProvider) — while PublishingManager.GetManager() opens the default OAPublishingProvider, so a default-provider scan finds nothing on a site that plainly has indexes. The pipes are read from GetPipeSettings() directly rather than by walking publishing points (an index whose point cannot be traversed is still found), with provider-level security suppressed since an MCP request carries no Sitefinity identity. ProvidersScanned reports which providers were queried and each index carries its PublishingProvider, so an empty list is diagnosable rather than merely wrong.
    • Everything is resolved defensively and reflectively: the search API differs across Lucene, Azure Search, Elasticsearch and hybrid backends, so anything unobtainable produces a per-index Warnings entry and a null field rather than a guess or a 500. A null DocumentCount means "not obtainable here", never "empty".
  • Plugin version handshake. GET /mcp/ping now reports PluginVersion from the new McpPluginInfo.Version constant, and ApiKeyValidationService caches it alongside the capability roster on the same ping (no extra round trip). sitefinity_check_status prints the MCP server version, the site plugin version, and a verdict — and a 404 from any plugin route is mapped to the same advice, naming both versions.
    • Never just "out of date". Every mismatch message carries the fix: a plugin behind the server gets the four steps (pull the repo at the matching tag, run install-plugin.ps1 -Target "<Sitefinity web project>", rebuild the solution, recycle the app pool); a server behind the plugin gets npm install -g sitefinity-comm-mcp@latest plus a client restart; a plugin from 3.5.0 or earlier reports no version and is named as such.
    • PluginVersionAdvisor.Compare ignores pre-release suffixes and treats unparsable input as equal, so a malformed version can never produce a false "out of date" claim.
    • The version now lives in FOUR places and they must agree: the csproj <Version>, npm/package.json, McpPluginInfo.Version, and the CHANGELOG.md heading. The release skill's table was updated accordingly.
  • New capability element: Scheduled Tasks (Admin > Advanced > McpSettings > Scheduled Tasks, capability constant Tasks, McpTasksToolElement). Gates both new endpoints, defaults to enabled like every other capability, appears in the /mcp/ping roster, and pre-blocks both tools client-side with the usual "disabled by the Sitefinity administrator" message. A plugin that reports no Tasks flag is treated as enabled, so nothing changes on upgrade.

Changed

  • sitefinity_investigate_incident's description now points at sitefinity_get_scheduled_task_status for what is running or failing right now — the incident tool reconstructs a past moment, the scheduler tool reads the present one.
  • The plugin-out-of-date 404 message is now produced centrally by PluginVersionAdvisor and names both versions plus the update commands, instead of the previous one-line "re-run install-plugin.ps1".

Notes

  • Timestamps stay pre-formatted strings on the wire, as with the incident endpoint: ServiceStack serializes a DateTime DTO property as /Date(ms)/, an instant, which destroys a server-local wall time. UTC values are yyyy-MM-ddTHH:mm:ssZ, local values yyyy-MM-ddTHH:mm:ss with no suffix, and each response states ServerTimeZoneId / ServerUtcOffsetMinutes once. JsConfig is never touched — Sitefinity's own backend shares the ServiceStack instance.
  • All outbound strings from the new endpoints pass through McpSecretRedactor. A blank value is emitted as null rather than an empty string, so "this row has no value here" stays distinguishable from "the value was blanked out".

v3.5.0

Choose a tag to compare

@github-actions github-actions released this 29 Aug 00:53

Added

  • Per-capability enable/disable in the Sitefinity admin. Admin > Advanced > McpSettings now carries a nested element per capability — Logs, Metadata, Content, Forms, Config Reader, Where Used, Permissions, Incident — each with an Enabled checkbox. Everything defaults to enabled, so upgrading changes nothing until an administrator turns something off. Maintenance needs no new element: the existing Allow Write Operations flag already gates it.
    • The plugin is the security boundary. Every service handler calls McpCapabilities.EnsureEnabled(...) as its first line and returns HTTP 403 with a structured { Disabled, Reason } body when the capability is off. A missing or unreadable config section fails open to the shipped defaults — a config read error must never silently disable a working install.
    • Incident additionally gates the three OS-level sources it reads: Allow IIS Logs, Allow Event Logs, Allow HTTPERR. A disabled source is skipped and reported as a Warnings entry ("IIS source disabled by administrator…") rather than failing the call — the same shape as the existing ACL-denied warnings. Candidate discovery and cross-source search honour the flags too.
    • GET /mcp/ping now returns a Features roster listing every capability's state (plus Maintenance, mirroring Allow Write Operations). The MCP server caches it alongside the existing key-validation result and refuses a disabled tool up front — "This tool is disabled by the Sitefinity administrator (Admin > Advanced > McpSettings > Forms)" — with no network call. This is a courtesy layer: the plugin re-checks on every request, so a stale roster can never grant access. A plugin that reports no roster (any build before 3.5.0) is treated as everything-enabled, so the MCP server stays fully backwards compatible.
    • A 403 carrying the capability-disabled body is mapped to the same friendly message wherever it arrives, covering a stale cached roster, a setting changed mid-session, and remote-mode log tools (never pre-blocked, because in local mode they read the filesystem directly).
  • Form submission privacy controls under McpSettings > Forms:
    • Allow Responses (default on) — uncheck to keep form definitions readable while /mcp/forms/{id}/responses returns 403, so an assistant can reason about a form's shape without ever seeing what people submitted.
    • Excluded Fields (default blank) — comma-separated field names (SSN, HealthCard) stripped from every submission. Case-insensitive exact match on the field name. Removed before redaction and before SearchTerm matching, so an excluded field cannot be discovered by searching for its value; it is omitted entirely rather than replaced with a placeholder, and the response reports which fields were excluded.
  • Brute-force throttling and constant-time key comparison in McpApiKeyAttribute (no configuration, nothing to turn on):
    • 10 failed authentication attempts from one IP within a 5-minute rolling window freeze that IP for 15 minutes, answered with HTTP 429 and a Retry-After header. Requests presenting no key count as failures — they are probes.
    • A valid key always wins. The presented key is evaluated before the freeze is enforced, so a correct key unfreezes the IP and resets its counter. This prevents a lockout-DoS: bad-key traffic from the same NAT/egress address as the legitimate MCP server can never lock it out.
    • The bucket is the direct connection IP; X-Forwarded-For / X-Real-IP are deliberately ignored (ServiceStack's IRequest.RemoteIp honours them, which would let one client evade the throttle by rotating a header).
    • Fails open by construction — every throttle call site swallows its own exceptions, so a bug degrades to "no throttling" and a plain 401 rather than a 500. Memory is bounded at 10,000 tracked IPs, pruning expired entries first and never evicting a frozen one.
    • Constant-time API key comparison — walks the full length of both byte arrays accumulating inequality (seeded with the length difference) instead of returning at the first mismatch, so response timing cannot leak a key prefix. Hand-rolled because .NET Framework 4.8 has no CryptographicOperations.FixedTimeEquals.
    • The Enabled and blank-config-key checks keep their existing precedence and are unaffected.
  • Request audit log — new Audit Requests setting (McpSettings, default on). Every request through the [McpApiKey] choke point, accepted or rejected, appends one line to App_Data\Sitefinity\Logs\McpAudit.log: {utcIso}Z | ip={directIp} | xff={X-Forwarded-For or -} | {METHOD} {path} | {redactedQuery} | auth={valid|invalid-key|missing-key|throttled|disabled}.
    • Requests only, never results. Two IP fields, deliberately never conflated: ip= is the direct TCP address (trustworthy, and what the throttle keys on); xff= is the X-Forwarded-For header verbatim (- when absent, capped at 200 chars, redactor-scanned) — the real client behind a proxy, but forgeable, so informational only.
    • Query strings are secret-redacted with the same per-parameter deny-list plus pattern scan used for IIS queries; newlines and pipes are stripped from every field so a crafted URL cannot forge log lines.
    • Rejected keys are fingerprinted, never written. An invalid-key line carries attempted: len={n} prefix={6 chars} sha256={12 hex} — enough to identify a stale or cross-environment key by hashing your own, without the log ever holding a credential (the invalid keys that occur in practice are nearly-valid ones). A valid key is never fingerprinted in any form.
    • Rolls at 10 MB keeping 3 archives; writes are lock-guarded and append-only. The entire path fails open — a locked file, full disk or unresolvable path degrades to no auditing and never affects the request.
    • The file lives in the standard Sitefinity Logs folder on purpose, so the audit trail is itself MCP-inspectable via sitefinity_read_log_file("McpAudit.log") and sitefinity_search_logs.
  • Configuration section hiding under McpSettings > Config Reader:
    • Excluded Sections (default blank) — comma-separated section names hidden from the MCP entirely: omitted from /mcp/config, refused with 403 from /mcp/config/{SectionName} (re-checked against the resolved type name so an alias can't slip past), and filtered out of /mcp/settings/search before Take and the returned count, so a hidden section can't be inferred from a short page. A Config / .config suffix is optional — Authentication matches AuthenticationConfig and Authentication.config — and * wildcards are supported (Auth*, *Security*), matched against both the raw and suffix-stripped name with a 1s regex timeout; a malformed pattern is ignored rather than failing the call.

Changed

  • The IisLogPath setting moved from the top level of McpSettings into the Incident element (Admin > Advanced > McpSettings > Incident > IIS Log Path). 3.0.0 was never published to npm, so no install in the wild carries the old top-level property; there is no back-compat shim. Re-enter the path if you had set it on a 3.0.0 preview build.
  • sitefinity_investigate_incident's description now notes that individual sources can be switched off by the administrator and come back as warnings.
  • Every capability gets its own named element class (McpLogsToolElement, McpMetadataToolElement, … McpIncidentToolElement) on a shared McpToolElement base, even when it adds nothing beyond Enabled — so a future per-tool setting has an obvious home without a config migration. All of them live in McpConfig.cs; the feature added no new plugin source files.

v3.0.0

Choose a tag to compare

@github-actions github-actions released this 28 Aug 23:37

Added

  • sitefinity_investigate_incident — one tool, three modes, for outage forensics across four log sources: Sitefinity's own logs, the site's IIS W3C access log, the Windows Application + System event logs (WAS app-pool crashes, Application Error 1000, .NET Runtime 1026), and the http.sys HTTPERR log (the 503s that never reach the site log because the app pool was already dead).
    • Discovery (no arguments): scans a lookback period (default 72h, max 14 days) for crash-shaped signals and returns clustered candidate incident moments, newest first.
    • Window (time): reconstructs one moment across all four sources — IIS is returned as aggregates only (per-minute counts, status histogram with sub-status, capped 5xx and slowest lists), never raw lines.
    • Search (query): sweeps every source for a case-insensitive substring (a username, an order id, a URL) — matched after secret redaction, so it cannot probe for redacted values.
    • Every entry carries both TimestampUtc and TimestampLocal as pre-formatted ISO strings, with the server time zone and the DST-correct offset at the queried instant — Sitefinity logs (local), W3C/HTTPERR (UTC), and event records (UTC) can no longer be misread against each other.
    • Bounded by fixed per-source caps, a 2M-line scan ceiling, a 30-second wall-clock budget, and a one-scan-at-a-time gate (HTTP 429) — partial results carry warnings, never hangs. Denied event-log or IIS-folder ACLs degrade to warnings carrying the exact net localgroup / icacls fix.
    • New plugin endpoint GET /mcp/incident-window (McpSystemLogService.cs — one new plugin source file) and new optional Sitefinity setting IIS Log Path (Admin > Advanced > McpSettings) overriding the auto-detected W3SVC{siteId} folder.
    • cs(Cookie) / cs(Authorization) columns are never read; cs-username and client IPs are deliberately retained (they are what makes correlation possible). All other output is secret-redacted, with IIS query strings deny-listed per parameter name.

Changed

  • BREAKING: log tools consolidated from six to four. sitefinity_read_error_log, sitefinity_read_trace_log, and sitefinity_get_last_error were removed — they differed from sitefinity_read_log_file only by a preset argument. sitefinity_read_log_file now defaults fileName to Error.log (no-args = latest errors; count: 1 = the most recent entry with full stack trace). sitefinity_search_logs and sitefinity_list_log_files are unchanged. No plugin endpoints were removed.
  • Microsoft.Extensions.Hosting / Microsoft.Extensions.Http bumped 9.0.4 → 10.0.11.
  • AGENTS.md fully re-synced from CLAUDE.md (it had drifted).

v2.0.4

Choose a tag to compare

@github-actions github-actions released this 23 Aug 00:14

Fixed

  • Plugin sources emitted XML doc comment warnings (CS1570/CS1574) in host Sitefinity solutions. The plugin .cs files compile inside the customer's project, which usually has GenerateDocumentationFile enabled, so malformed doc XML surfaced as warnings in their build. Escaped a raw & in a query-string example, qualified a cref pointing at a member of another type, and replaced two crefs to the PageNode.GetFullUrl() extension method (which never resolves through the extended type) with plain <c> markup.

v2.0.3

Choose a tag to compare

@github-actions github-actions released this 18 Aug 19:52

Fixed

  • npm package README: replaced a headerless markdown table that npmjs.com's renderer appears to reject, leaving the package page blank.

v2.0.2

Choose a tag to compare

@github-actions github-actions released this 18 Aug 19:44

Fixed

  • npm install failed when Git for Windows' GNU tar shadowed the system tar. The installer extracted with absolute Windows paths, which GNU tar parses as a remote rsh host (C: → host C). Extraction now runs with relative paths from the package directory, which every tar accepts.

Added

  • npm README: claude mcp add one-liner for registering the server with Claude Code.

v2.0.1

Choose a tag to compare

@github-actions github-actions released this 18 Aug 19:41

Fixed

  • ARM support in the npm distribution. npm install -g sitefinity-comm-mcp failed outright on Windows-on-ARM and ARM Linux — the release pipeline only built x64 (plus macOS arm64) binaries and the installer's platform map rejected everything else. Releases now ship win-arm64 and linux-arm64 self-contained binaries as well, and the installer maps all six platforms.

v2.0.0

Choose a tag to compare

@github-actions github-actions released this 18 Aug 19:38

Goes all-in on the modern MCP spec — structured tool output with published schemas, human-readable tool titles, a new full-text search across all Advanced Settings — and makes installation a one-liner. Major version because the tool output contract changed: data tools now return structuredContent and report failures as protocol errors.

Added

  • sitefinity_search_settings — full-text search across ALL Advanced Settings via the backend advanced-settings-search Lucene index (Sitefinity 14.1+). Answers "which section is setting X in?" — the question a section dump can't, because it requires already knowing the section. Each hit carries the setting's caption, breadcrumb path, and owning section, ready to feed into sitefinity_get_config_section + pathFilter. Implemented fully reflectively on the plugin side (the search API drifts across Sitefinity versions); when the index is disabled or missing, the response sets IndexAvailable: false and explains how to enable it instead of erroring. Result values are secret-redacted — the index stores config values.
  • Structured tool output (UseStructuredContent). The 16 data-returning tools (config, content, forms, pages, permissions, taxonomies, templates, where-used, maintenance) now return typed response models: each publishes an outputSchema in tools/list and returns structuredContent alongside the text, so clients can consume results without parsing JSON out of a text block. The 6 human-formatted tools (logs, status, routes, environments, site info) intentionally stay textual.
  • Human-readable Title on all 32 tools (e.g. "Search Advanced Settings") for clients that render tool lists.
  • One-line installation. The server is now a packaged dotnet tool: dotnet tool install -g SitefinityCommunity.Mcp puts sitefinity-mcp on PATH — no clone, no build. Releases also attach self-contained single-file binaries (win-x64, linux-x64, osx-x64/arm64) that run without any .NET install.

Changed

  • Tool errors are now protocol errors. Data tools throw McpException instead of returning "Error: ..." strings — clients see a proper isError result with the same guidance text (plugin-missing hints, write-gate refusals, validation messages).
  • ToolOutputLimiter also bounds structuredContent. An oversized structured payload is serialized into the same JSON-RPC frame as text and can kill the transport just as easily; since a sliced JSON object is useless, an over-limit structured payload is dropped whole with an explanatory note while the (truncated) text carries the data.

Fixed

  • sitefinity_list_page_routes regained its diagnostic detail. Each page line again carries [Published]/[Draft] status and a [URL eval: Mode] flag when URL evaluation routes sub-paths into the page; both route tools print "No issues detected." when the warnings list is empty.
  • McpSettingsSearchService registered in McpServicePlugin (service registration is an explicit list, not assembly scan).
  • Settings search queries are built the way Sitefinity's own query builder does it — an OR SearchQueryGroup of per-field SearchTerms (the Lucene service compiles SearchGroup, not Text), executed under RunWithElevatedPrivilege because the secured advanced-settings-search publishing point silently returns an empty set for non-backend identities. Result paths are rendered as readable breadcrumbs (contentViewConfig > ContentViewControls > … > Fields > HighContrast).

Upgrading

The plugin changed (new service + registration), so redeploy the plugin source (install-plugin.ps1 — a NEW file must be registered in the .csproj, so use the installer, not a bare copy) and recycle. Restart the MCP server for the client-side changes. Behavior change for API consumers: data tools now return results in structuredContent (camelCase keys per SDK convention) and report failures as isError results instead of "Error: ..." text.