silverstripe-mcp
Validates AI-generated PHP code against Silverstripe 6 patterns, catching migration issues from SS5 to SS6.
README
Silverstripe MCP Server
A Model Context Protocol server that provides real-time validation feedback when AI assistants generate Silverstripe 6 PHP code. Catches common migration issues from Silverstripe 5 to 6 before they reach your codebase.
Documentation: Architecture | Agent Instructions Setup
The Problem
When using AI coding assistants like Claude Code with Silverstripe 6 projects, they often generate code with outdated patterns:
// AI generates this (SS5 style):
use SilverStripe\ORM\ArrayList;
use SilverStripe\View\ArrayData;
class MyTask extends BuildTask {
public function run(HTTPRequest $request) {
echo "Processing...";
}
}
This MCP server catches these issues immediately, allowing the AI to self-correct:
// After validation, AI generates this (SS6 style):
use SilverStripe\Model\List\ArrayList;
use SilverStripe\Model\ArrayData;
class MyTask extends BuildTask {
protected static string $commandName = 'my-task';
protected function execute(InputInterface $input, PolyOutput $output): int {
$output->writeln('Processing...');
return Command::SUCCESS;
}
}
How It Works
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ AI generates │────▶│ MCP validates │────▶│ AI fixes and │
│ PHP code │ │ against SS6 │ │ re-validates │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ PHP Analyzer │
│ (AST-based) │
└─────────────────┘
│
┌───────────┴───────────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Namespace │ │ BuildTask │
│ Validator │ │ Validator │
└─────────────┘ └─────────────┘
The server exposes an ss-validator tool that:
- Parses PHP code into an Abstract Syntax Tree (AST)
- Runs plugin-based validators against the code
- Returns issues with line numbers and suggested fixes
- The AI iterates until no issues remain
Quick Start
Installation
git clone https://github.com/sandervanscheepen/silverstripe-mcp
cd silverstripe-mcp
# Install dependencies
npm install
cd php && composer install && cd ..
# Build
npm run build
Then add to your MCP client (e.g., Claude Code):
claude mcp add silverstripe-mcp -- node /path/to/silverstripe-mcp/dist/index.js
Or add to your MCP client configuration file:
{
"mcpServers": {
"silverstripe": {
"command": "node",
"args": ["/path/to/silverstripe-mcp/dist/index.js"]
}
}
}
Agent Instructions Setup
To get the most out of this MCP server, add instructions to your AI agent's project instructions file (e.g., CLAUDE.md, .cursorrules, .github/copilot-instructions.md) that tell it to use the ss-validator tool on all generated PHP code. See Recommended Agent Instructions for full, minimal, and project-specific templates you can copy into your project.
Built-in Validators
Namespace Validator
Detects outdated Silverstripe 5 imports and suggests their Silverstripe 6 equivalents:
| SS5 Namespace | SS6 Namespace |
|---|---|
SilverStripe\ORM\ArrayList |
SilverStripe\Model\List\ArrayList |
SilverStripe\ORM\PaginatedList |
SilverStripe\Model\List\PaginatedList |
SilverStripe\ORM\Map |
SilverStripe\Model\List\Map |
SilverStripe\ORM\GroupedList |
SilverStripe\Model\List\GroupedList |
SilverStripe\View\ArrayData |
SilverStripe\Model\ArrayData |
SilverStripe\View\ViewableData |
SilverStripe\Model\ModelData |
SilverStripe\ORM\ValidationResult |
SilverStripe\Core\Validation\ValidationResult |
SilverStripe\ORM\ValidationException |
SilverStripe\Core\Validation\ValidationException |
BuildTask Validator
Detects old BuildTask patterns that need migration to PolyCommand:
| Issue | Detection | Suggestion |
|---|---|---|
| Deprecated method signature | run(HTTPRequest $request) |
execute(InputInterface $input, PolyOutput $output): int |
| Missing command name | No $commandName property |
protected static string $commandName = 'my-task'; |
| Output via echo | echo "..." |
$output->writeln('...') |
| Output via print | print "..." |
$output->writeln('...') |
FormField Value Validator
Detects usage of FormField::Value() which was split into three methods in SS6:
// Detects this:
$value = $field->Value();
// Suggests using one of:
$value = $field->dataValue(); // Raw data value
$value = $field->presentedValue(); // Value for display
$value = $field->processedValue(); // Value after form processing
Removed Method Validator
Detects calls to methods that were removed in Silverstripe 6:
| Removed Method | Suggestion |
|---|---|
Controller::has_curr() |
Use Controller::curr() with try/catch |
DataObject::getCMSValidator() |
Use getCMSCompositeValidator() instead |
Requirements::themedCSS() |
Use Requirements::css() with ThemeResourceLoader |
Requirements::themedJavascript() |
Use Requirements::javascript() with ThemeResourceLoader |
Object::useCustomClass() |
Use Injector configuration instead |
Deprecated Config API (deprecated-config)
Detects usage of the deprecated Config::inst()->get() pattern:
// Detects this:
$value = Config::inst()->get('SilverStripe\CMS\Model\SiteTree', 'allowed_children');
// Suggests this:
$value = SiteTree::config()->get('allowed_children');
Context-Aware Validators
The following validators auto-enable based on code context, minimizing overhead when analyzing code that doesn't need them:
Extension Hook Visibility (extension-hook-visibility)
Auto-enabled when: Class extends Extension, DataExtension, or SiteTreeExtension
SS6 changed many extension hook methods to protected. Detects public hooks in Extension classes:
class MyExtension extends DataExtension {
// Detects: should be protected
public function onBeforeWrite() { }
public function updateCMSFields($fields) { }
}
Configurable prefixes: onBefore, onAfter, update, augment (add more via additionalPrefixes).
Elemental Namespace (elemental-namespace)
Auto-enabled when: Any import starts with DNADesign\Elemental
For projects using dnadesign/silverstripe-elemental. Detects namespace changes in Elemental 6:
| SS5 Namespace | SS6 Namespace |
|---|---|
DNADesign\Elemental\TopPage\DataExtension |
DNADesign\Elemental\Extensions\TopPageElementExtension |
DNADesign\Elemental\TopPage\FluentExtension |
DNADesign\Elemental\Extensions\TopPageFluentElementExtension |
DNADesign\Elemental\TopPage\SiteTreeExtension |
DNADesign\Elemental\Extensions\TopPageSiteTreeExtension |
DNADesign\Elemental\Controllers\ElementSiteTreeFilterSearch |
DNADesign\Elemental\ORM\Search\ElementalSiteTreeSearchContext |
Also detects removed classes (GraphQL, ElementalLeftAndMainExtension, etc.).
Forcing All Plugins
To force-enable all validators regardless of context:
Via config (silverstripe-mcp.json):
{
"enableAllPlugins": true
}
Via tool argument:
{
"code": "<?php ...",
"enableAllPlugins": true
}
You can also explicitly enable individual auto-plugins to always run:
{
"plugins": {
"elemental-namespace": {
"enabled": true,
"additionalMappings": {
"Custom\\Old\\Class": "Custom\\New\\Class"
}
}
}
}
Configuration
Create silverstripe-mcp.json in your project root to customize behavior:
{
"phpBinary": "/path/to/php",
"targetVersion": "6.0",
"plugins": {
"namespace-validator": {
"enabled": true,
"additionalMappings": {
"App\\Legacy\\MyClass": "App\\Modern\\MyClass"
}
},
"buildtask-validator": {
"enabled": true
},
"deprecated-config": {
"enabled": true
},
"extension-hook-visibility": {
"enabled": true,
"additionalPrefixes": ["can", "provide"]
}
},
"customPlugins": [
"./my-plugins/CustomValidator.php"
]
}
See silverstripe-mcp.example.json for a complete example.
Configuration Options
| Option | Type | Description |
|---|---|---|
phpBinary |
string |
Path to PHP 8.3+ executable (auto-detected if not specified) |
targetVersion |
string |
Silverstripe version to validate against (default: "6.0") |
enableAllPlugins |
boolean |
Force-enable all plugins including context-aware ones (default: false) |
plugins |
object |
Per-plugin configuration |
plugins.*.enabled |
boolean |
Enable/disable a specific plugin |
plugins.namespace-validator.additionalMappings |
object |
Custom namespace migrations |
customPlugins |
string[] |
Paths to custom validator plugins |
PHP Binary Resolution
The server requires PHP 8.3+ (Silverstripe 6's minimum version). It resolves the PHP binary in this order:
- Config file:
phpBinaryinsilverstripe-mcp.json - Environment variable:
PHP_BINARY(if version >= 8.3) - Auto-detect: Common locations (Laragon, XAMPP, Homebrew, system paths)
- System PHP: Falls back to
phpcommand (if version >= 8.3)
If your system PHP is below 8.3, specify the path in your config:
{
"phpBinary": "C:/laragon/bin/php/php-8.3.22-Win32-vs16-x64/php.exe"
}
Or set the PHP_BINARY environment variable in your MCP client config:
{
"mcpServers": {
"silverstripe": {
"command": "node",
"args": ["/path/to/silverstripe-mcp/dist/index.js"],
"env": {
"PHP_BINARY": "/usr/local/bin/php8.3"
}
}
}
}
Writing Custom Plugins
Create a PHP class implementing ValidatorPluginInterface:
<?php
namespace MyOrg\MCPPlugins;
use SilverstripeMCP\Contracts\ValidatorPluginInterface;
use SilverstripeMCP\AnalysisContext;
use SilverstripeMCP\Issue;
use PhpParser\NodeVisitorAbstract;
use PhpParser\Node;
class DeprecatedMethodPlugin implements ValidatorPluginInterface
{
public function getName(): string
{
return 'deprecated-method-validator';
}
public function getDescription(): string
{
return 'Detects usage of deprecated methods';
}
public function getTargetVersions(): array
{
return ['6.*']; // Applies to all SS6.x versions
}
public function configure(array $options): void
{
// Handle configuration options
}
public function getVisitor(AnalysisContext $context): \PhpParser\NodeVisitor
{
return new class($context) extends NodeVisitorAbstract {
public function __construct(private AnalysisContext $context) {}
public function enterNode(Node $node): ?int
{
// Detect deprecated method calls
if ($node instanceof Node\Expr\MethodCall) {
$methodName = $node->name->toString();
if ($methodName === 'deprecatedMethod') {
$this->context->addIssue(new Issue(
type: 'deprecated_method',
message: 'deprecatedMethod() is deprecated in SS6',
line: $node->getLine(),
suggestion: 'Use newMethod() instead',
docsUrl: 'https://docs.silverstripe.org/...'
));
}
}
return null;
}
};
}
}
// Return the class name for auto-loading
return DeprecatedMethodPlugin::class;
Register in your configuration:
{
"customPlugins": [
"./plugins/DeprecatedMethodPlugin.php"
],
"plugins": {
"deprecated-method-validator": {
"enabled": true
}
}
}
Testing
The project includes comprehensive test suites for both PHP and TypeScript:
# Run PHP tests (PHPUnit)
cd php && composer test
# Run TypeScript tests (Vitest)
npm test
# Run all tests
npm run test:all
# Watch mode for development
npm run test:watch
Project Structure
silverstripe-mcp/
├── src/ # TypeScript MCP server
│ ├── index.ts # Entry point, stdio transport
│ ├── tools/
│ │ └── ss-validator.ts # Main validation tool
│ └── lib/
│ └── php-bridge.ts # PHP subprocess communication
│
├── php/ # PHP analyzer
│ ├── bin/
│ │ └── analyze # CLI entry point
│ ├── src/
│ │ ├── AnalyzerRunner.php # Plugin orchestration
│ │ ├── AnalysisContext.php # Shared analysis state
│ │ ├── Issue.php # Issue data structure
│ │ ├── Contracts/
│ │ │ └── ValidatorPluginInterface.php
│ │ ├── Plugins/ # Validator plugins
│ │ │ ├── NamespaceValidatorPlugin.php (core)
│ │ │ ├── BuildTaskValidatorPlugin.php (core)
│ │ │ ├── FormFieldValuePlugin.php (core)
│ │ │ ├── RemovedMethodPlugin.php (core)
│ │ │ ├── HookRenamePlugin.php (core)
│ │ │ ├── DeprecatedConfigPlugin.php (core)
│ │ │ ├── ExtensionHookVisibilityPlugin.php (auto: Extension classes)
│ │ │ └── ElementalNamespacePlugin.php (auto: Elemental imports)
│ │ └── Config/
│ │ ├── namespace-mappings.php
│ │ ├── removed-methods.php
│ │ ├── hook-renames.php
│ │ └── elemental-mappings.php
│ └── tests/ # PHPUnit tests
│
├── tests/ # Vitest tests
│ ├── php-bridge.test.ts
│ ├── ss-validator.test.ts
│ └── fixtures/
│
├── docs/
│ ├── architecture.md # Technical architecture
│ └── recommended-agent-instructions.md # Setup for AI agents
├── silverstripe-mcp.example.json # Example configuration
├── CLAUDE.md # Development instructions
└── README.md
Development
# Build and watch for changes
npm run dev
# Test PHP analyzer directly
cd php && php bin/analyze '{"code": "<?php use SilverStripe\\ORM\\ArrayList;"}'
# Example output:
{
"issues": [{
"type": "deprecated_import",
"message": "'SilverStripe\\ORM\\ArrayList' has moved to 'SilverStripe\\Model\\List\\ArrayList' in Silverstripe 6",
"line": 1,
"suggestion": "use SilverStripe\\Model\\List\\ArrayList;",
"docsUrl": "https://docs.silverstripe.org/en/6/changelogs/6.0.0/#renamed-classes"
}],
"suggestions": [],
"rerun": true
}
See CONTRIBUTING.md for detailed development instructions.
Requirements
- Node.js 18.0 or higher
- PHP 8.3 or higher
- Composer for PHP dependency management
Contributing
Contributions are welcome! See CONTRIBUTING.md for development setup, architecture details, and testing guidelines.
Credits
- Inspired by the Svelte MCP server which provides similar functionality for Svelte 5
- Built with nikic/php-parser for robust AST analysis
- Uses the Model Context Protocol specification
License
MIT License - see LICENSE for details.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.