SitefinityCommunity.Mcp
Community supported Sitefinity CMS MCP server
Ask AI about SitefinityCommunity.Mcp
Powered by Claude ยท Grounded in docs
I know everything about SitefinityCommunity.Mcp. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
SitefinityCommunity.Mcp
A Model Context Protocol (MCP) server for Sitefinity CMS. Gives Claude Code (and any MCP client) direct access to Sitefinity logs, diagnostics, and CMS status.
Inspired by Laravel Boost โ designed as an extensible framework where adding new tools requires only creating a new class file.
Why this exists
MCP servers are popping up across the web development ecosystem โ Laravel has Boost, Rails and Next.js have their own โ and Sitefinity deserves one too.
I built this for myself. I work in Sitefinity every day and wanted the same AI-assisted workflow that other frameworks already have. Sitefinity's official repos exist on GitHub, but community PRs tend to sit โ and when you need something for your day-to-day, you can't wait indefinitely. This scratches my own itch first: if a feature would save me time on a real project, it gets built. That means it stays practical and actively maintained, not theoretical.
It's open source and community-driven โ contributions, ideas, and feedback are welcome. No guarantees on timelines (this is a side project), but because I use it daily, useful improvements tend to land quickly.
Features
- Log Tools โ Read error/trace logs, search across all log files with regex, get the last error
- Site Info โ Sitefinity version, .NET version, project name, configured languages, multisite info
- Module Inspector โ List all installed modules with type, status, and startup type
- Content Model โ Browse Module Builder dynamic types and their field definitions
- Page Inspector โ List all CMS page routes (via Sitemap API for performance), get full page details including template name, all widgets, and their configured properties
- Route Discovery โ Browse CMS page routes with URL evaluation warnings, ServiceStack API routes, and OData entity sets
- Status Check โ Verify if Sitefinity is bootstrapped and ready
- Multi-Environment โ Switch between dev/staging/prod environments on the fly
- Dual-Mode Logs โ Local filesystem access for dev, HTTP via companion plugin for remote servers
- Auto-Discovery โ New tools are picked up automatically via
[McpServerToolType]attribute - API Key Validation โ Proactive key matching between MCP server and Sitefinity plugin
Installation
There are two components to set up: the MCP server (runs on your dev machine) and the Sitefinity plugin (drops into your Sitefinity web app). Follow these steps in order.
Step 1 โ Get the MCP server
Clone this repo to your local machine:
git clone https://github.com/SitefinityCommunity/SitefinityCommunity.Mcp.git
cd SitefinityCommunity.Mcp
dotnet build
Step 2 โ Install the plugin into your Sitefinity project
The companion plugin exposes REST endpoints at /RestApi/mcp/* that the MCP server calls. It's distributed as source files (not a NuGet package) so it compiles against your existing Sitefinity assemblies โ no DLL binding conflicts across versions.
Run the install script, pointing it at your Sitefinity web app root:
.\install-plugin.ps1 -Target "C:\Path\To\SitefinityWebApp"
This copies the plugin source files into Code\Mcp\SitefinityCommunity\ in your project.
Then wire it up in Global.asax.cs inside your Bootstrapper_Initialized handler:
protected void Bootstrapper_Initialized(object sender, ExecutedEventArgs e)
{
if (e.CommandName == "Bootstrapped")
{
SitefinityCommunity.Mcp.SitefinityPlugin.McpInit.Register();
}
}
Build your Sitefinity project and recycle the app pool.
Step 3 โ Generate an API key
The MCP server and Sitefinity plugin authenticate with a shared API key. Generate a cryptographically secure one:
dotnet run --project src/SitefinityCommunity.Mcp -- generate-key
This prints a new 256-bit Base64 key. Copy it โ you'll use it in the next two steps.
Important: The key flow is one direction only โ generate it here, then paste it into both places. Do not copy the key back out of Sitefinity's Advanced config โ what's stored there is the encrypted value, not the original key.
Step 4 โ Configure the Sitefinity plugin
In Sitefinity Admin > Settings > Advanced > McpSettings:
- Paste the generated key into API Key
- Check Enabled (it's
falseby default โ you must opt in) - Save, then recycle the app pool โ the Enabled flag and API key are read at startup
The key is stored encrypted at rest via Sitefinity's [SecretData] mechanism. What you see in the Advanced config after saving is the encrypted form โ always use the original generated key in sitefinity-mcp.json.
Step 5 โ Create your config file
Create sitefinity-mcp.json somewhere on your machine (keep it gitignored โ it contains keys):
{
"defaultEnvironment": "dev",
"environments": {
"dev": {
"url": "https://dev.example.com",
"logsPath": "C:\\Path\\To\\Sitefinity\\App_Data\\Sitefinity\\Logs",
"sitefinityApiKey": "your-key-from-step-3"
},
"staging": {
"url": "https://staging.example.com",
"sitefinityApiKey": "your-staging-api-key"
}
}
}
sitefinityApiKeyโ paste the same key you put in Sitefinity AdminlogsPathโ set this when Sitefinity runs on the same machine (local mode). Omit it for remote servers โ logs are fetched via HTTP through the plugin insteadurlโ required for every environment
Step 6 โ Configure your AI client
Claude Code
Add to your project's .mcp.json:
{
"mcpServers": {
"sitefinity-mcp": {
"type": "stdio",
"command": "dotnet",
"args": ["run", "--project", "C:\\GitHub\\SitefinityCommunity.Mcp\\src\\SitefinityCommunity.Mcp"],
"env": {
"SITEFINITY_MCP_CONFIG": "C:\\Path\\To\\sitefinity-mcp.json"
}
}
}
}
VS Code
Create .vscode/mcp.json in your workspace (or run MCP: Add Server from the Command Palette):
{
"servers": {
"sitefinity-mcp": {
"command": "dotnet",
"args": ["run", "--project", "C:\\GitHub\\SitefinityCommunity.Mcp\\src\\SitefinityCommunity.Mcp"],
"env": {
"SITEFINITY_MCP_CONFIG": "C:\\Path\\To\\sitefinity-mcp.json"
}
}
}
}
Then open Chat in VS Code and approve the MCP trust prompt when asked.
Step 7 โ Verify the connection
Ask Claude: "Check if Sitefinity is running" โ it will call sitefinity_check_status. If the API keys don't match, you'll get a clear error message rather than a cryptic 401.
Key validation behavior:
- Keys match โ tools work normally
- Keys don't match โ tools return: "API key mismatch..." error
- Sitefinity unreachable โ tools proceed with a warning (so you can still read local logs when debugging a down server)
- Blank keys โ rejected on both sides (MCP server won't start; Sitefinity won't register endpoints)
Step 8 (optional) โ Install the Sitefinity skills
The repo ships curated skills that teach AI agents how to think about Sitefinity widgets and page composition. Skills are installable into Claude Code, Cursor, Codex, and GitHub Copilot.
Run the installer and it walks you through two choices: scope (project or global) and which agents to install into (detected ones are pre-selected).
# Interactive โ prompts for scope and agents
.\install-skills.ps1
# Non-interactive / CI
.\install-skills.ps1 -Scope project -Target "C:\Proj" -Agents claude,cursor -Force
.\install-skills.ps1 -Scope global -Agents claude -Force
How it installs: a canonical copy goes to <root>/.agents/skills/<name>/, then each selected agent's skills directory gets a symlink back to the canonical copy. Update the canonical copy once and every agent sees it.
Per-agent paths:
| Agent | Skills directory |
|---|---|
| Claude Code | .claude/skills/ |
| Cursor | .cursor/skills/ |
| Codex | .codex/skills/ |
| GitHub Copilot | .github/copilot/skills/ |
Windows note: creating directory symlinks needs Developer Mode (Settings โ System โ For developers) or an admin shell. If symlinks are unavailable the installer falls back to plain copies automatically โ updates just won't auto-propagate.
Currently bundled:
- sitefinity-widget-expert โ MVC widget development, designer attributes, view conventions, JSON persistence
- sitefinity-page-inspector โ Walks the MCP tools needed to inspect a page's widgets and their configured properties
Available Tools
| Tool | Description |
|---|---|
sitefinity_read_error_log | Last N entries from Error.log |
sitefinity_read_trace_log | Last N entries from Trace.log |
sitefinity_list_log_files | All .log files with size and modified date |
sitefinity_read_log_file | Read any log file by name |
sitefinity_search_logs | Regex search across all logs with context |
sitefinity_get_last_error | Most recent error with full details |
sitefinity_check_status | Check if Sitefinity is bootstrapped |
sitefinity_get_site_info | Sitefinity version, .NET version, project name, languages, multisite info |
sitefinity_list_modules | All installed modules with type, status, startup type |
sitefinity_list_dynamic_types | Module Builder types grouped by module with field counts |
sitefinity_get_type_fields | Field definitions for a specific dynamic type |
sitefinity_list_page_routes | All CMS page routes via Sitemap API (fast, cached). Includes URL evaluation warnings for pages with dynamic routing |
sitefinity_list_api_routes | ServiceStack REST API routes and OData entity sets |
sitefinity_get_page_details | Full page detail by ID, URL path, slug, or title. Returns page metadata, template name, and every widget on the page with its configured properties (including Level 2 Settings children) |
sitefinity_get_widget_properties | Full property details for a single widget by GUID + page identifier. Returns both Level 1 properties and Level 2 Settings children (designer field values, content, etc.) with higher truncation limits |
sitefinity_get_page_widget_tree | Page composition as a placeholder tree in sibling render order. Layout controls own nested _Col00/_Col01 child placeholders; widget Properties is a merged Level 1 + Level 2 view (Level 2 wins). Empty columns are pre-created from layout captions so structure is visible |
sitefinity_list_content | Paged live content items for any Sitefinity type (News, Blog, Module Builder types, etc.). Returns Id, Title, UrlName, Status, DateCreated, LastModified so widgets can reference real content Ids |
sitefinity_list_templates | All CMS page templates โ Id, Name, Framework (MVC/WebForms), ParentTemplateId, Culture |
sitefinity_list_taxonomies | All classifications (Categories, Tags, custom) plus a sample of top-level taxa keyed by taxonomy Id |
sitefinity_list_forms | All Sitefinity forms with field count and submission count |
sitefinity_get_form_fields | Field definitions for a given form โ returns the developer Name (the FieldName the Sitefinity API uses for entry values, e.g. FormTextBox_C001), Title, FieldType, IsRequired, and Choices. Pass debug=true to also dump the raw Properties/ChildProperties tree (useful when Name/Title come back empty on an unfamiliar Sitefinity version) |
sitefinity_list_form_responses | Form submissions, newest-first, with an optional case-insensitive searchTerm that filters entries by any field value (or IP / UserAgent). Sensitive-named field values (password/secret/apiKey/token/...) are redacted before search matching so sensitive values cannot leak via search |
sitefinity_list_environments | Show configured environments |
sitefinity_set_default_environment | Switch active environment |
Page Inspector
The page tools give your AI assistant visibility into Sitefinity's CMS page structure โ something that's otherwise locked inside the database and only visible through the Sitefinity backend UI.
sitefinity_list_page_routes โ Uses Sitefinity's Sitemap API (FrontendSiteMap provider) for performance. The sitemap is an in-memory cached representation of the page tree, so listing hundreds of pages is fast without hitting PageManager queries. Returns each page's URL, title, depth in the tree, and flags pages that use dynamic URL evaluation (which can cause routing surprises).
sitefinity_get_page_details โ Returns everything about a single page: metadata (ID, title, URL, template name, published status) and every widget placed on the page with their configured properties. Each widget includes its GUID, CLR type, placeholder location, caption, whether it's a layout control, Level 1 properties, and Level 2 Settings children (the actual designer field values). Accepts flexible lookup by:
- Page ID (Guid) โ
fefefa59-f39a-4ac9-bf2f-a54d005f135d - URL path โ
/about/team - URL slug โ
team - Page title โ
Our Team(exact match preferred, partial match with warning)
sitefinity_get_widget_properties โ Returns full property details for a single widget by its GUID and the page it's on (both from sitefinity_get_page_details results). Returns both Level 1 properties (ControllerName, ID, Settings) and Level 2 Settings children (SharedContentID, ProviderName, Model JSON, etc.) with higher truncation limits than the page-level view. Use this when you need to inspect the actual configured values of a specific widget.
sitefinity_get_page_widget_tree โ The full page composition: every widget on the page returned as a placeholder tree in sibling render order. Layout controls own child placeholders named {ControlId}_Col00, _Col01, โฆ โ their internal columns nest as child Placeholders on the layout WidgetNode. Each widget's Properties is a merged view of Level 1 (ORM) + Level 2 (Settings children), with Level 2 winning on conflict (what the widget designer actually saved). Empty columns are pre-created from the layout's grid-8+4 caption so the LLM can see intended structure. Pass includeLayoutControls=false to flatten layout nodes.
Live Content Queries
These three tools give the LLM direct visibility into real content, templates, and classifications so it can generate widget configs and code against actual Ids โ not placeholder strings.
sitefinity_list_content โ Paged list of live content items for any type full name (e.g., Telerik.Sitefinity.News.Model.NewsItem or a Module Builder dynamic type). Returns Id, Title, UrlName, Status, DateCreated, LastModified. Use sitefinity_list_dynamic_types first to discover available type names.
sitefinity_list_templates โ Every page template (MVC and WebForms), including template Id, parent template, and culture. Handy when generating a new page definition that needs to pin to a real template.
sitefinity_list_taxonomies โ Every classification (Categories, Tags, and any custom ones) plus a sample of top-level taxa keyed by taxonomy Id. So a widget configured with category/tag filters can reference the real taxon Ids.
Forms & Submissions
sitefinity_list_forms โ All Sitefinity forms with their field count and submission count.
sitefinity_get_form_fields โ Field definitions for one form (by Id or Name). Returns each field's developer name (the FieldName the Sitefinity API uses when reading entry values โ e.g. FormTextBox_C001), its display Title, FieldType, IsRequired flag, and Choices (for dropdowns/radios). Pass debug=true to additionally return a raw Properties/ChildProperties tree dump โ useful for diagnosing empty Name/Title on unfamiliar Sitefinity versions where the metadata lives at a different path under the control's Settings tree.
sitefinity_list_form_responses โ Form submissions for a form, ordered newest-first. Pass searchTerm to return only entries where any field value (or IpAddress / UserAgent) contains the term (case-insensitive substring). The response includes TotalCount (all entries on the form), MatchedCount (entries after the search filter), and echoes the SearchTerm you sent. Use take/skip to page through the matched set. Any field whose name looks sensitive (Password, ApiKey, Secret, Token, โฆ) is scrubbed before leaving Sitefinity and before search matching runs, so sensitive values can never leak via a crafted search term.
Secret Redaction
Every string returned by log tools, widget tools, form response tools, and list_content flows through a deny-list + pattern scanner. Values keyed by Password, ApiKey, Secret, etc. become [REDACTED]; embedded JWTs, AWS keys, GitHub PATs, Slack tokens, OpenAI keys, Azure connection strings, and Password=... connection-string fragments are replaced with [REDACTED:<kind>] tags. For dev debugging you can set "allowRawSecrets": true on a non-prod environment in sitefinity-mcp.json โ environments whose name starts with prod always redact regardless.
Security Model
Enabled flag โ The Enabled checkbox in Sitefinity Admin > Advanced > McpSettings acts as a kill switch with two enforcement layers:
- Startup gate โ
McpInit.Register()checksEnabledandApiKeybefore registering the ServiceStack plugin. If either is disabled/blank, the/RestApi/mcp/*routes don't exist at all (404, no attack surface). Requires app pool recycle to toggle. - Runtime gate โ The
[McpApiKey]request filter attribute checksEnabledon every request. If someone disables MCP in admin after startup, requests are immediately blocked without an app pool recycle.
Encryption at rest โ The API key in Sitefinity's config is marked with [SecretData], so it's stored encrypted in McpConfig.config. Sitefinity decrypts it transparently when the property is read in code.
Blank key protection โ Blank, empty, and whitespace-only keys are rejected at every checkpoint:
- MCP server config validation (
IsNullOrWhiteSpace) โ server won't start - Sitefinity startup (
McpInit.Register) โ plugin won't register endpoints - Sitefinity request filter (
McpApiKeyAttribute) โ requests blocked at runtime
Architecture
Two-component design:
- MCP Server (this repo) โ .NET console app using the official ModelContextProtocol SDK. Communicates with Claude Code via stdio.
- Sitefinity Plugin (source files) โ
.csfiles you drop into any Sitefinity web app. Registers ServiceStack endpoints at/RestApi/mcp/*for remote log access. Compiles against your existing assemblies โ no DLL conflicts.
โโโโโโโโโโโโโโโ stdio โโโโโโโโโโโโโโโโโโโโ
โ Claude Code โโโโโโโโโโโโโโบโ MCP Server โ
โ (MCP Client) โ โ (.NET console) โ
โโโโโโโโโโโโโโโ โโโโโโโโโโฌโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโผโโโโโโโโโโโโโโ
โ โ โ
Local logs HTTP + API Key โ
(if logsPath (X-MCP-API-Key) โ
is set) โ โ
โ โผ โผ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ โ Sitefinity โ โ Sitefinity โ
โ โ (Dev) โ โ (Staging) โ
โ โ /RestApi/ โ โ /RestApi/ โ
โ โ mcp/* โ โ mcp/* โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Plugin โฒ Plugin โฒ
โ source โ source โ
โผ files โ files โ
โโโโโโโโโโโโ โ โ
โ Log filesโ Sitefinity APIs: โ
โ on disk โ SystemManager, โ
โโโโโโโโโโโโ ModuleBuilder, โ
MultisiteManager โ
AppSettings โ
Local mode (dev): MCP server reads log files directly from disk via logsPath.
Remote mode (staging/prod): MCP server calls plugin REST endpoints at /RestApi/mcp/*, authenticated with X-MCP-API-Key header. The plugin queries Sitefinity's internal APIs and returns results as JSON.
Adding New Tools
Create a class, annotate it, inject services โ done. Zero changes to Program.cs:
[McpServerToolType]
public sealed class ContentTools(ISitefinityStatusService status)
{
[McpServerTool(Name = "sitefinity_list_pages", ReadOnly = true)]
[Description("List Sitefinity CMS pages.")]
public async Task<string> ListPages(CancellationToken ct = default)
{
var s = await status.CheckStatusAsync(ct);
if (!s.IsReady) return $"Sitefinity not ready: {s.Summary}";
// ... call Sitefinity OData API ...
}
}
Testing
Setup
- Copy
tests/test-config.example.jsontotests/test-config.json - Fill in your Sitefinity dev URL and API key (this file is gitignored)
Running Tests
# All tests (unit + integration)
dotnet test
# Unit tests only (no Sitefinity needed)
dotnet test --filter "Category=Unit"
# Integration tests only (requires running Sitefinity)
dotnet test --filter "Category=Integration"
Integration tests skip automatically if test-config.json is missing or
Sitefinity is unreachable โ they won't fail your build.
Author
Built by Steve McNiven-Scott (@SitefinitySteve | GitHub) โ Sitefinity MVP and long-time community contributor. Building developer tools for the Sitefinity community.
License
MIT
