Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ Join the `#core-ai` channel [on WordPress Slack](http://wordpress.slack.com) ([s

## Coding standards

In general, all code must follow the [WordPress Coding Standards and best practices](https://developer.wordpress.org/coding-standards/). All code in the Performance Lab plugin must follow these requirements:
In general, all code must follow the [WordPress Coding Standards and best practices](https://developer.wordpress.org/coding-standards/). All code in the MCP Adapter must follow these requirements:

- **WordPress**: 6.9+
- **PHP**: 7.4+

We include [several tools](#useful-commands) to help ensure your code meets contribution
We include [several tools](#useful-commands) to help ensure your code meets these standards.

## Guidelines

Expand All @@ -25,7 +25,7 @@ We include [several tools](#useful-commands) to help ensure your code meets cont

## Reporting Security Issues

Please see [SECURITY.md] (@TODO).
Please see [SECURITY.md](SECURITY.md).

## Local Setup

Expand Down
259 changes: 48 additions & 211 deletions README.md

Large diffs are not rendered by default.

26 changes: 1 addition & 25 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,6 @@ Documentation for the WordPress MCP Adapter - transform WordPress abilities into
- **[Contributing Guide](../CONTRIBUTING.md)** - Development setup, coding standards, and contribution workflow
- **[Testing Guide](guides/testing.md)** - Running and writing tests with wp-env

## Quick navigation

### New to MCP Adapter?
1. [Quick Start Guide](getting-started/README.md)
2. [Default Server](guides/default-server.md)
3. [Basic Examples](getting-started/basic-examples.md)
4. [Architecture Overview](architecture/overview.md)

### Build custom tools
1. [Creating Abilities](guides/creating-abilities.md)
2. [Basic Examples](getting-started/basic-examples.md)

### Custom authentication
1. [Transport Permissions](guides/transport-permissions.md) (recommended)
2. [Custom Transports](guides/custom-transports.md) (advanced)

### Upgrading
1. [Migrating to v0.5.0](migration/v0.5.0.md)
2. [Migrating to v0.3.0](migration/v0.3.0.md)

### Troubleshooting
1. [Common Issues](troubleshooting/common-issues.md)
2. [Installation Guide](getting-started/installation.md)

---

**Ready to get started?** Jump into the [Quick Start Guide](getting-started/README.md) and have your first MCP server running in minutes!
New to MCP Adapter? Start with the [Quick Start Guide](getting-started/README.md).
108 changes: 108 additions & 0 deletions docs/architecture/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,105 @@

This document explains how the MCP Adapter transforms WordPress abilities into MCP components and handles requests from AI agents.

## Directory structure

```
includes/
│
├── Plugin.php # Bootstrap — singleton, dependency check, initializes McpAdapter
├── Autoloader.php # PSR-4 autoloader
│
├── Core/ # Registry and server management
│ ├── McpAdapter.php # Main singleton registry; fires mcp_adapter_init
│ ├── McpServer.php # Individual server configuration and component access
│ ├── McpComponentRegistry.php # Stores and retrieves McpComponentInterface instances
│ ├── McpTransportFactory.php # Instantiates transports with dependency injection
│ └── McpVersionNegotiator.php # MCP protocol version negotiation
│
├── Abilities/ # Built-in meta-abilities for the default server
│ ├── DiscoverAbilitiesAbility.php # mcp-adapter/discover-abilities
│ ├── ExecuteAbilityAbility.php # mcp-adapter/execute-ability
│ ├── GetAbilityInfoAbility.php # mcp-adapter/get-ability-info
│ └── McpAbilityHelperTrait.php # Shared helpers (mcp.public check, mcp.type)
│
├── Cli/ # WP-CLI integration
│ ├── McpCommand.php # wp mcp-adapter serve / list
│ └── StdioServerBridge.php # Bridges WP-CLI stdin/stdout to MCP server
│
├── Domain/ # Business logic and MCP component models
│ ├── Contracts/
│ │ └── McpComponentInterface.php # Internal contract for all MCP components
│ ├── Utils/
│ │ ├── McpNameSanitizer.php # Converts ability names to MCP-safe names
│ │ ├── McpValidator.php # Validates names, URIs, and schemas
│ │ ├── McpAnnotationMapper.php # Maps ability meta.annotations to MCP DTOs
│ │ ├── SchemaTransformer.php # Transforms JSON Schema formats
│ │ ├── ContentBlockHelper.php # Factory for MCP content block DTOs
│ │ └── AbilityArgumentNormalizer.php # Normalizes empty {} input to null
│ ├── Tools/
│ │ ├── McpTool.php # Wraps Tool DTO with execution logic
│ │ ├── RegisterAbilityAsMcpTool.php # Converts a WordPress ability to McpTool
│ │ └── McpToolValidator.php # Validates tool names and schemas
│ ├── Resources/
│ │ ├── McpResource.php # Wraps Resource DTO with execution logic
│ │ ├── RegisterAbilityAsMcpResource.php # Converts a WordPress ability to McpResource
│ │ └── McpResourceValidator.php # Validates resource URIs and schemas
│ └── Prompts/
│ ├── Contracts/
│ │ └── McpPromptBuilderInterface.php # Interface for prompt message builders
│ ├── McpPrompt.php # Wraps Prompt DTO with execution logic
│ ├── McpPromptBuilder.php # Builds prompt messages from ability output
│ ├── McpPromptValidator.php # Validates prompt names and arguments
│ └── RegisterAbilityAsMcpPrompt.php # Converts a WordPress ability to McpPrompt
│
├── Handlers/ # JSON-RPC method handlers
│ ├── HandlerHelperTrait.php # Shared error response helpers
│ ├── Initialize/
│ │ └── InitializeHandler.php # Handles initialize / initialized
│ ├── Tools/
│ │ └── ToolsHandler.php # Handles tools/list, tools/call
│ ├── Resources/
│ │ └── ResourcesHandler.php # Handles resources/list, resources/read
│ ├── Prompts/
│ │ └── PromptsHandler.php # Handles prompts/list, prompts/get
│ └── System/
│ └── SystemHandler.php # Handles ping, notifications/cancelled
│
├── Infrastructure/
│ ├── ErrorHandling/
│ │ ├── Contracts/
│ │ │ └── McpErrorHandlerInterface.php # log( $message, $context, $type )
│ │ ├── ErrorLogMcpErrorHandler.php # Logs to PHP error_log
│ │ ├── NullMcpErrorHandler.php # No-op (null object pattern)
│ │ └── McpErrorFactory.php # Creates JSON-RPC error responses
│ └── Observability/
│ ├── Contracts/
│ │ └── McpObservabilityHandlerInterface.php # record_event( $event, $tags, $duration_ms )
│ ├── ErrorLogMcpObservabilityHandler.php # Logs events to PHP error_log
│ ├── NullMcpObservabilityHandler.php # No-op (null object pattern)
│ ├── ConsoleObservabilityHandler.php # Outputs events to stdout
│ ├── McpObservabilityHelperTrait.php # Tag management helpers
│ └── FailureReason.php # Standardized failure reason constants
│
├── Transport/
│ ├── Contracts/
│ │ ├── McpTransportInterface.php # Base transport contract
│ │ └── McpRestTransportInterface.php # REST transport contract (register_routes, check_permission)
│ ├── HttpTransport.php # Unified HTTP transport (MCP 2025-11-25)
│ └── Infrastructure/
│ ├── HttpRequestContext.php # Encapsulates HTTP request data
│ ├── HttpRequestHandler.php # Processes raw HTTP requests
│ ├── HttpSessionValidator.php # Validates Mcp-Session-Id header
│ ├── JsonRpcResponseBuilder.php # Builds JSON-RPC responses
│ ├── McpTransportContext.php # Bundles server + handlers for transport use
│ ├── McpTransportHelperTrait.php # Shared transport utilities
│ ├── RequestRouter.php # Routes MCP methods to handlers; records observability events
│ └── SessionManager.php # Creates and manages HTTP sessions
│
└── Servers/
└── DefaultServerFactory.php # Creates the default mcp-adapter-default-server
```

## System architecture

The MCP Adapter uses a two-layer architecture that separates protocol concerns from WordPress integration:
Expand Down Expand Up @@ -70,6 +169,15 @@ The remaining layers wire the Schema and Adapter layers together:
- **Name sanitization**: Uses `McpNameSanitizer` to normalize tool and prompt names
- **Validation**: Validates components with `McpValidator` when validation is enabled

### McpVersionNegotiator

Negotiates the MCP protocol version between client and server. If the client requests a supported version it is echoed back; otherwise the server falls back to the latest supported version.

**Supported protocol versions** (newest-first):
- `2025-11-25` (latest — recommended)
- `2025-06-18`
- `2024-11-05`

### McpTransportFactory
- **Purpose**: Creates transport instances with dependency injection
- **Context Creation**: Builds `McpTransportContext` with all required handlers
Expand Down
32 changes: 4 additions & 28 deletions docs/getting-started/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,10 @@ add_action( 'mcp_adapter_init', function( $adapter ) {
'My First MCP Server', // Human-readable name
'A simple MCP server for demonstration', // Description
'1.0.0', // Version
[ \WP\MCP\Transport\HttpTransport::class ], // Transport methods
array( \WP\MCP\Transport\HttpTransport::class ), // Transport methods
\WP\MCP\Infrastructure\ErrorHandling\ErrorLogMcpErrorHandler::class, // Error handler
[ 'my-plugin/get-site-info' ] // Abilities to expose as tools
null, // Observability handler (null = default)
array( 'my-plugin/get-site-info' ) // Abilities to expose as tools
);
});
```
Expand Down Expand Up @@ -142,40 +143,15 @@ curl -X POST "https://yoursite.com/wp-json/mcp/mcp-adapter-default-server" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

## What Just Happened?

1. **Ability Registration**: You created a WordPress ability that retrieves site information
2. **Automatic Exposure**: The MCP Adapter automatically exposes your ability as an MCP tool
3. **REST API Integration**: The adapter created REST endpoints for MCP communication
4. **AI Agent Access**: AI agents can now discover and use your functionality

## Next Steps

### Learn More
- **[Creating Abilities](../guides/creating-abilities.md)** - Build tools, resources, and prompts
- **[Installation Guide](installation.md)** - Detailed installation options
- **[Architecture Overview](../architecture/overview.md)** - Understand system design

### Advanced Topics
- **[Error Handling](../guides/error-handling.md)** - Custom logging and monitoring
- **[Transport Permissions](../guides/transport-permissions.md)** - Authentication and authorization
- **[CLI Usage](../guides/cli-usage.md)** - Command-line MCP server management

## Troubleshooting

**MCP Adapter not found?**
- Verify installation method (Composer vs Plugin)
- Check autoloader is loaded correctly
- Ensure WordPress Abilities API is available

**REST API not responding?**
- Test basic REST API: `curl "https://yoursite.com/wp-json/"`
- Verify permalink structure is not "Plain"
- Check WordPress user authentication

**Tool not appearing?**
- Confirm ability is registered during `wp_abilities_api_init`
- Verify ability name matches exactly in server configuration
- Check permission callback allows current user

For detailed troubleshooting, see the [Installation Guide](installation.md#troubleshooting).
See the [Common Issues guide](../troubleshooting/common-issues.md).
12 changes: 8 additions & 4 deletions docs/getting-started/basic-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,16 @@ add_action( 'wp_abilities_api_init', function() {
]
],
'execute_callback' => function( $input ) {
$post_data = [
if ( empty( $input['title'] ) ) {
return new \WP_Error( 'missing_title', 'Post title is required.' );
}

$post_data = array(
'post_title' => sanitize_text_field( $input['title'] ),
'post_content' => wp_kses_post( $input['content'] ),
'post_status' => in_array( $input['status'], ['draft', 'publish'] ) ? $input['status'] : 'draft',
'post_type' => 'post'
];
'post_status' => in_array( $input['status'], array( 'draft', 'publish' ), true ) ? $input['status'] : 'draft',
Comment thread
itsgajendraSingh marked this conversation as resolved.
'post_type' => 'post',
);

// Handle category if provided
if ( ! empty( $input['category'] ) ) {
Expand Down
3 changes: 2 additions & 1 deletion docs/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ class MyMcpPlugin {
'1.0.0',
[ \WP\MCP\Transport\HttpTransport::class ],
\WP\MCP\Infrastructure\ErrorHandling\ErrorLogMcpErrorHandler::class,
[ 'my-plugin/get-posts' ]
null, // observability handler (null = use default)
[ 'my-plugin/get-posts' ] // tools
Comment thread
itsgajendraSingh marked this conversation as resolved.
);
}

Expand Down
15 changes: 8 additions & 7 deletions docs/guides/custom-transports.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This guide covers how to implement custom transport layers for the MCP Adapter w

## Built-in Transports

- ✅ **`HttpTransport`** - Recommended (implements MCP 2025-06-18 specification)
- ✅ **`HttpTransport`** - Recommended (implements MCP 2025-11-25 specification)
- ✅ **`STDIO Transport`** - Available via WP-CLI commands

## When to Create Custom Transports
Expand Down Expand Up @@ -86,14 +86,14 @@ class ApiKeyTransport implements McpRestTransportInterface {
}

public function check_permission( \WP_REST_Request $request ) {
$api_key = $request->get_header( 'X-API-Key' );
$api_key = sanitize_text_field( $request->get_header( 'X-API-Key' ) );

if ( empty( $api_key ) ) {
return false;
}

// Validate against stored keys
$valid_keys = get_option( 'mcp_api_keys', [] );
$valid_keys = get_option( 'mcp_api_keys', array() );
return in_array( $api_key, $valid_keys, true );
}

Expand Down Expand Up @@ -131,9 +131,10 @@ add_action( 'mcp_adapter_init', function( $adapter ) {
'Secure MCP Server',
'MCP server with API key authentication',
'1.0.0',
[ ApiKeyTransport::class ], // Use custom transport
array( ApiKeyTransport::class ), // Use custom transport
\WP\MCP\Infrastructure\ErrorHandling\ErrorLogMcpErrorHandler::class,
[ 'my-plugin/secure-tool' ]
null, // Observability handler (null = default)
array( 'my-plugin/secure-tool' ) // Tools
);
});
```
Expand Down
51 changes: 9 additions & 42 deletions docs/guides/default-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,15 @@ add_filter( 'mcp_adapter_session_inactivity_timeout', function () {
} );
```

**`mcp_adapter_session_activity_update_interval`** — Minimum number of seconds between activity timestamp updates for an active session. Updating the timestamp on every request adds a database write; this interval throttles those writes. Default: `60` seconds.

```php
// Update activity timestamp at most every 5 minutes
add_filter( 'mcp_adapter_session_activity_update_interval', function () {
return 5 * MINUTE_IN_SECONDS;
} );
```

Sessions are stored in user meta and are cleaned up automatically when a new session is created or an existing session is validated.

### STDIO transport (WP-CLI)
Expand Down Expand Up @@ -424,48 +433,6 @@ add_filter('mcp_adapter_execute_ability_capability', function() {
});
```

## Customization

### Server Configuration Filter

You can customize the entire server configuration using the `mcp_adapter_default_server_config` filter:

```php
add_filter('mcp_adapter_default_server_config', function($config) {
// Change server name
$config['server_name'] = 'My Custom MCP Server';

// Add custom error handler
$config['error_handler'] = MyCustomErrorHandler::class;

// Add additional tools
$config['tools'][] = 'my-plugin/custom-tool';

return $config;
});
```

### Adding Resources and Prompts

The default server can be extended with resources and prompts:

```php
add_filter('mcp_adapter_default_server_config', function($config) {
// Add resources
$config['resources'] = [
'my-plugin/site-config',
'my-plugin/user-data'
];

// Add prompts
$config['prompts'] = [
'my-plugin/code-review',
'my-plugin/content-analysis'
];

return $config;
});
```

## Usage Examples

Expand Down
12 changes: 12 additions & 0 deletions docs/guides/observability.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,18 @@ All events use a **consistent naming pattern with status tags** for easier filte

The `failure_reason` tag provides specific context for errors. When WordPress abilities return `WP_Error` objects, the error code is used directly as the failure reason.

The `FailureReason` class (`WP\MCP\Infrastructure\Observability\FailureReason`) provides constants for all standard failure reasons. Use these constants in custom handlers to avoid hardcoding strings:

```php
use WP\MCP\Infrastructure\Observability\FailureReason;

public function record_event( string $event, array $tags = [], ?float $duration_ms = null ): void {
if ( isset( $tags['failure_reason'] ) && FailureReason::PERMISSION_DENIED === $tags['failure_reason'] ) {
// handle permission denied specifically
}
}
```

**Standard Failure Reasons:**

**Tool-related:**
Expand Down
3 changes: 2 additions & 1 deletion docs/troubleshooting/common-issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,8 @@ class MyErrorHandler implements \WP\MCP\Infrastructure\ErrorHandling\Contracts\M
// Check implementation
if ( ! in_array(
\WP\MCP\Infrastructure\ErrorHandling\Contracts\McpErrorHandlerInterface::class,
class_implements( MyErrorHandler::class )
class_implements( MyErrorHandler::class ),
true
)) {
error_log( 'Error handler missing interface' );
}
Expand Down
Loading