Releases: sitefinitysteve/SitefinityCommunity.Mcp
Release list
v3.8.0
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 oversf_dynamic_content, a per-type table, mangled junction tables andsf_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_idalways points at the parent's master), taxonomy vs multi-select Choices junctions (valis a taxon id or a choice value), single-select Choices, related data and media throughsf_content_linkwith 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_mappingfirst, naming convention second, and a column-signature match for types whose table carries a hand-chosen name; junction tables throughsys.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:selectruns the flattened query,sqlreturns it,viewcreates one view per type for BI, andpocoemits 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 usingServiceStack.Text(already in every Sitefinity bin folder, noJsConfigchanges), 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.
- 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 (
Changed
sitefinity-database-structurecorrects the junction-table guidance: Module Builder junction tables are not listed insf_meta_data_mapping(find them throughsys.foreign_keys), the mapping can miss whole types, multi-select Choices fields also produce junction tables (valis the choice value, not a taxon id), andsf_url_data.item_typecan be NULL on dynamic rows.sitefinity-best-practicesroutes flat-SQL / reporting questions to the new skill and states the table-discovery rule.sitefinity-react-vite8-guideis vendor-neutral.mountWidgetnow lives inmount.tsxwith a hand-rolled error boundary that forwards to a pluggablereportError/setErrorReportersink;@sentry/reactis 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 thatnpx skills updatenever adds new skills, so a release that ships a new skill needsaddagain.
v3.7.0
Added
sitefinity-api-helpersskill — a verified cheat sheet of the platform helpers production Sitefinity code actually reaches for, so custom code stops re-implementing them badly:ToSitefinityUITimeand the otherDateTime/string extensions,GetValue/GetString/SetValueon any data item,GetRelatedItemsand 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, andConfig.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-guideskill — the React 19 counterpart to the existing Vue 3 guide: React 19 + Vite 8 (Rolldown) + Tailwind CSS v4 + shadcn/ui on classic Sitefinity MVC (MvcControllerProxywidgets, 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_usedwidgetOriginnow 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-structurerewritten 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 underreference/; companion page skills corrected (the schema has FKs, but only on structural tables; form controls usecontent_id/id3; what a version snapshot restores). Example emails and site names in docs and tests replaced with neutral placeholders. sitefinity-adminapp-extensionsrewritten 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);FieldBaseas it really is; theshortTextvsshortTextDefaultrule and the 34FieldTypesmembers the 15.3 typings lack; thewidget-undefinedkey for complex sub-fields;HTTP_PREFIXas thesfprefixsentinel; and where the official samples repo is stale.sitefinity-widget-expertgains a verified routing section: how extra URL segments start as an implicit 404, which mechanisms mark them resolved ([RelativeRoute],IRouteMapper, convention dispatch,RouteHelper.SetUrlParametersResolved), whyHttpNotFound()matters, and howViewBag.Title/MetadataFields+PageTitleModebecome the page title.- Skill consolidation (18 -> 17).
sitefinity-toolbox-iconsis folded intositefinity-widget-expertas its "Toolbox icons" section (icon classes, verification, page-editor MVC badge CSS).sitefinity-widget-expertno longer duplicates the attribute catalogue - its fifteen attribute sections are replaced by a one-screen working set that points atsitefinity-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 asreference/toolbox-icons-sheet.png.
v3.6.0
Added
sitefinity_get_scheduled_task_status— the "is something running, hung, or broken right now?" tool, backed by the newGET /mcp/scheduled-tasksendpoint reading Sitefinity'sSchedulingManager. 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, andIsSearchIndexRebuild+IndexNamefor reindex tasks. A largeRunningForSecondson a normally-quick task is a hung task. - Failed (cap 10, newest execution first) — task rows whose scheduler status is
Failed, withScheduledForUtc/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
IsRunningAND its scheduler status isStarted. Sitefinity leavesIsRunningset 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,RunningNowcomes 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.
HistoryNotepoints atsitefinity_search_logswith the patternScheduler: Task executed.
- RunningNow (cap 25) — every genuinely running task, with
sitefinity_list_search_indexes— the "why is search stale?" tool, backed byGET /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 indexExists,DocumentCountwhere a count is obtainable,LastUpdatedUtc/LocalplusLastUpdatedSource(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) withLastReindexUtc/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 showingLastReindexStatus: "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
Nameand displayTitle(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. Titleis never a type name. The pipe'sUINameis 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-indextoDocs Index).TitleSourcesays which was used.Backendfalls 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:
BackendandDocumentCountreportnullrather 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) — whilePublishingManager.GetManager()opens the defaultOAPublishingProvider, so a default-provider scan finds nothing on a site that plainly has indexes. The pipes are read fromGetPipeSettings()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.ProvidersScannedreports which providers were queried and each index carries itsPublishingProvider, 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
Warningsentry and a null field rather than a guess or a 500. A nullDocumentCountmeans "not obtainable here", never "empty".
- Reindex cross-referencing matches on a normalized name. A scheduled-task row names an index the way the admin does (
- Plugin version handshake.
GET /mcp/pingnow reportsPluginVersionfrom the newMcpPluginInfo.Versionconstant, andApiKeyValidationServicecaches it alongside the capability roster on the same ping (no extra round trip).sitefinity_check_statusprints 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 getsnpm install -g sitefinity-comm-mcp@latestplus a client restart; a plugin from 3.5.0 or earlier reports no version and is named as such. PluginVersionAdvisor.Compareignores 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 theCHANGELOG.mdheading. The release skill's table was updated accordingly.
- 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
- 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/pingroster, and pre-blocks both tools client-side with the usual "disabled by the Sitefinity administrator" message. A plugin that reports noTasksflag is treated as enabled, so nothing changes on upgrade.
Changed
sitefinity_investigate_incident's description now points atsitefinity_get_scheduled_task_statusfor 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
PluginVersionAdvisorand 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
DateTimeDTO property as/Date(ms)/, an instant, which destroys a server-local wall time. UTC values areyyyy-MM-ddTHH:mm:ssZ, local valuesyyyy-MM-ddTHH:mm:sswith no suffix, and each response statesServerTimeZoneId/ServerUtcOffsetMinutesonce.JsConfigis 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 asnullrather than an empty string, so "this row has no value here" stays distinguishable from "the value was blanked out".
v3.5.0
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
Enabledcheckbox. 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
Warningsentry ("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/pingnow returns aFeaturesroster listing every capability's state (plusMaintenance, 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).
- The plugin is the security boundary. Every service handler calls
- Form submission privacy controls under McpSettings > Forms:
- Allow Responses (default on) — uncheck to keep form definitions readable while
/mcp/forms/{id}/responsesreturns 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 beforeSearchTermmatching, 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.
- Allow Responses (default on) — uncheck to keep form definitions readable while
- 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-Afterheader. 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-IPare deliberately ignored (ServiceStack'sIRequest.RemoteIphonours 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
Enabledand blank-config-key checks keep their existing precedence and are unaffected.
- 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
- Request audit log — new Audit Requests setting (McpSettings, default on). Every request through the
[McpApiKey]choke point, accepted or rejected, appends one line toApp_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 theX-Forwarded-Forheader 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-keyline carriesattempted: 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")andsitefinity_search_logs.
- Requests only, never results. Two IP fields, deliberately never conflated:
- 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/searchbeforeTakeand the returned count, so a hidden section can't be inferred from a short page. AConfig/.configsuffix is optional —AuthenticationmatchesAuthenticationConfigandAuthentication.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.
- Excluded Sections (default blank) — comma-separated section names hidden from the MCP entirely: omitted from
Changed
- The
IisLogPathsetting 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 sharedMcpToolElementbase, even when it adds nothing beyondEnabled— so a future per-tool setting has an obvious home without a config migration. All of them live inMcpConfig.cs; the feature added no new plugin source files.
v3.0.0
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
TimestampUtcandTimestampLocalas 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/icaclsfix. - 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-detectedW3SVC{siteId}folder. cs(Cookie)/cs(Authorization)columns are never read;cs-usernameand 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, andsitefinity_get_last_errorwere removed — they differed fromsitefinity_read_log_fileonly by a preset argument.sitefinity_read_log_filenow defaultsfileNametoError.log(no-args = latest errors;count: 1= the most recent entry with full stack trace).sitefinity_search_logsandsitefinity_list_log_filesare unchanged. No plugin endpoints were removed. Microsoft.Extensions.Hosting/Microsoft.Extensions.Httpbumped 9.0.4 → 10.0.11.AGENTS.mdfully re-synced fromCLAUDE.md(it had drifted).
v2.0.4
Fixed
- Plugin sources emitted XML doc comment warnings (CS1570/CS1574) in host Sitefinity solutions. The plugin
.csfiles compile inside the customer's project, which usually hasGenerateDocumentationFileenabled, so malformed doc XML surfaced as warnings in their build. Escaped a raw&in a query-string example, qualified acrefpointing at a member of another type, and replaced twocrefs to thePageNode.GetFullUrl()extension method (which never resolves through the extended type) with plain<c>markup.
v2.0.3
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
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:→ hostC). Extraction now runs with relative paths from the package directory, which every tar accepts.
Added
- npm README:
claude mcp addone-liner for registering the server with Claude Code.
v2.0.1
Fixed
- ARM support in the npm distribution.
npm install -g sitefinity-comm-mcpfailed 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 shipwin-arm64andlinux-arm64self-contained binaries as well, and the installer maps all six platforms.
v2.0.0
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 backendadvanced-settings-searchLucene 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 intositefinity_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 setsIndexAvailable: falseand 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 anoutputSchemaintools/listand returnsstructuredContentalongside 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
Titleon 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.Mcpputssitefinity-mcpon 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
McpExceptioninstead of returning"Error: ..."strings — clients see a properisErrorresult with the same guidance text (plugin-missing hints, write-gate refusals, validation messages). ToolOutputLimiteralso boundsstructuredContent. 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_routesregained 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.McpSettingsSearchServiceregistered inMcpServicePlugin(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
SearchQueryGroupof per-fieldSearchTerms (the Lucene service compilesSearchGroup, notText), executed underRunWithElevatedPrivilegebecause the securedadvanced-settings-searchpublishing 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.