Skip to content

Commit 91a8e09

Browse files
authored
Merge pull request #63 from SaltusDev/feature/mcp-v1
Feature/mcp v1
2 parents 2ce844f + 764f453 commit 91a8e09

154 files changed

Lines changed: 16862 additions & 1052 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Setup PHP
2+
description: Setup PHP with tools and restore Composer dependency cache
3+
4+
inputs:
5+
php-version:
6+
description: PHP version to install
7+
required: false
8+
default: "8.3"
9+
extensions:
10+
description: PHP extensions to install
11+
required: false
12+
default: ""
13+
cache-key:
14+
description: Cache key for Composer packages
15+
required: true
16+
cache-restore-keys:
17+
description: Newline-separated restore keys for the Composer cache
18+
required: false
19+
default: ""
20+
21+
runs:
22+
using: composite
23+
steps:
24+
- name: Setup PHP ${{ inputs.php-version }}
25+
uses: shivammathur/setup-php@v2
26+
with:
27+
php-version: ${{ inputs.php-version }}
28+
coverage: none
29+
tools: composer:v2
30+
extensions: ${{ inputs.extensions }}
31+
32+
- name: Get Composer cache directory
33+
id: composer-cache
34+
shell: bash
35+
run: echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT"
36+
37+
- name: Cache Composer packages
38+
uses: actions/cache@v6
39+
with:
40+
path: ${{ steps.composer-cache.outputs.dir }}
41+
key: ${{ inputs.cache-key }}
42+
restore-keys: ${{ inputs.cache-restore-keys }}

.github/workflows/ci.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main, feature/**]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
name: PHP ${{ matrix.php }} — tests
12+
runs-on: ubuntu-latest
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
php: ['7.4', '8.0', '8.1', '8.2', '8.3']
17+
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- name: Set up PHP ${{ matrix.php }}
22+
uses: shivammathur/setup-php@v2
23+
with:
24+
php-version: ${{ matrix.php }}
25+
tools: composer:v2
26+
coverage: none
27+
28+
- name: Validate composer.json
29+
run: composer validate --strict
30+
31+
- name: Cache Composer dependencies
32+
uses: actions/cache@v4
33+
with:
34+
path: vendor
35+
key: composer-${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('composer.json') }}
36+
restore-keys: |
37+
composer-${{ runner.os }}-${{ matrix.php }}-
38+
composer-${{ runner.os }}-
39+
40+
- name: Install dependencies
41+
run: composer install --prefer-dist --no-progress
42+
43+
- name: Run PHPUnit
44+
run: ./vendor/bin/phpunit -c phpunit.xml
45+
46+
- name: Run PHPStan
47+
run: ./vendor/bin/phpstan analyse --memory-limit=2G --no-progress
48+
49+
- name: Run PHPCS
50+
run: ./vendor/bin/phpcs --standard=phpcs.xml

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ vendor/
66
**/.DS_Store
77
.vscode
88
*~
9-
saltus-framework.code-workspace
9+
saltus-framework.code-workspace
10+
tests/tester.php

CHANGELOG.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,62 @@
33

44
## [Unreleased]
55

6+
### Fixed
7+
- Fixed single-post REST export so `/saltus-framework/v1/export/{post_id}` returns WXR for only the requested post instead of the entire post type.
8+
- Fixed framework lifecycle hook registration by allowing `Core` to receive the consuming plugin bootstrap file for activation/deactivation hooks.
9+
- Tightened WordPress-native MCP/Abilities permission callbacks so mutating post and term tools fail closed when required target arguments are missing.
10+
- Fixed structured settings updates so nested arrays, booleans, numbers, and null values are preserved while string values and keys are sanitized recursively.
11+
- Fixed settings sanitization so non-stringable object payloads cannot fatal during REST/MCP settings updates.
12+
- Fixed single-post REST export so WordPress core download headers from `export_wp()` do not leak into REST responses.
13+
- Fixed health error-rate reporting so validation and rate-limit outcomes remain visible but do not mark framework health as degraded.
14+
- Fixed the non-WordPress JSON encoding fallback in `AbilityRuntime`.
15+
- Cleared the remaining PHPStan Level 7 issues in `Modeler`, REST route registration, and MCP taxonomy REST-base handling.
16+
- Added an explicit model name accessor contract so `Modeler` no longer depends on concrete model properties.
17+
18+
### Changed
19+
- Added regression coverage for export isolation, plugin-file lifecycle hook registration, fail-closed MCP ability permissions, and structured settings payloads.
20+
- Brought `AssetLoader` back under PHPStan analysis with a typed `AssetLoadingService` base class.
21+
- Removed the standalone stdio MCP server path; WP7 MCP/Abilities is now the only supported MCP transport.
22+
- Migrated MCP audit logging, rate limiting, and caching to WordPress-native storage around WP7 ability execution.
23+
- Moved MCP audit retention cleanup from the audit write path to a daily WP-Cron event.
24+
25+
## [2.0.0] - 2026-06-30
26+
27+
### Added
28+
- MCP/Abilities integration: WordPress 7.0 native ability definitions through AbilityRegistrar
29+
- MCP protocol server with stdio transport: initialize, tools/list, tools/call, resources/list, resources/read, prompts/list, prompts/get
30+
- REST API namespace `saltus-framework/v1/` with 9 routes: models, duplicate, export, settings (GET/PUT), meta (aggregate + per-CPT), reorder
31+
- 16 MCP tools (9 Phase 1 CRUD + 7 Phase 2): models, posts, terms, duplicate, export, settings, reorder, meta fields
32+
- 3 MCP prompt templates for post/content generation workflows
33+
- Meta field normalization: nested Codestar fields flattened to explicit paths with JSON-schema-like types
34+
- ToolFactory for shared tool definitions between MCP and WordPress-native abilities
35+
- Caching layer (CacheInterface + InMemoryCache) for WordPressClient GET requests
36+
- Sliding-window rate limiter (default 60 req/60s) for tool calls
37+
- Audit trail logger with JSON records to STDERR and optional file
38+
- Structured error codes (ErrorCode constants + McpError value object with resolution hints)
39+
- Config::fromEnv for environment-variable-based configuration (15 env vars)
40+
- 243 PHPUnit tests across MCP, REST, and framework core
41+
42+
### Fixed
43+
- Rate limiter race condition in concurrent test scenarios
44+
- ModelFactory static make method call operator
45+
- WalkerTaxonomyDropdown incompatible void return type
46+
- WordPress key length validation in get_registration_name()
47+
- Admin columns non-string return from get_edit_term_link
48+
- Various type safety issues across services, models, assets, admin columns, meta, drag-drop, and container
49+
50+
### Changed
51+
- Version bumped to 2.0.0
52+
- Type safety improvements across the entire codebase
53+
- MCP Server uses ToolFactory for unified tool definitions
54+
- Config constructor refactored to array bag pattern
55+
- PHP 8.3+ required (str_starts_with in McpError)
56+
- PHPStan Level 7 compliance for all src/MCP/ and src/Rest/ code
57+
- PHPUnit configuration with strict flags, random execution order, and failOn* rules
58+
59+
## [1.3.5] - 2026-06-20
60+
- Chore: Package it for packagist
61+
662
## [1.3.4] - 2026-04-07
763
- New: Add h3 to meta sections
864
- Fix: typo in drag and drop filter

README.md

Lines changed: 109 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ Saltus Framework helps you develop WordPress plugins that are based on Custom Po
33

44
We built it to make things easier and faster for developers with different skills. Add metaboxes, settings pages and other enhancements with just a few lines of code.
55

6+
Visit saltus.dev for more information.
7+
68
## Version
79

8-
### Current version [1.3.4] - 2026-04-07
10+
### Current version [2.0.0] - 2026-06-30
911

1012
See [change log file](CHANGELOG.md) for full details.
1113

@@ -28,23 +30,36 @@ See [change log file](CHANGELOG.md) for full details.
2830

2931
Saltus Framework requires PHP 7.4+
3032

33+
### Installation
34+
35+
Install the framework in your plugin with Composer:
36+
37+
```bash
38+
composer require saltus/framework
39+
```
40+
3141
## Getting Started
3242

3343
### Demo
3444

3545
Refer to the [Framework Demo](https://github.com/SaltusDev/framework-demo) for a complete plugin example and to the [Wiki](https://github.com/SaltusDev/saltus-framework/wiki) for complete documentation.
3646

3747

38-
Once the framework is included in your plugin, you can initialize it the following way:
48+
Once the framework is installed and Composer's autoloader is loaded by your plugin, you can initialize it the following way:
3949

4050
```php
51+
$autoload = __DIR__ . '/vendor/autoload.php';
52+
if ( is_readable( $autoload ) ) {
53+
require_once $autoload;
54+
}
55+
4156
if ( class_exists( \Saltus\WP\Framework\Core::class ) ) {
4257

4358
/*
4459
* The path to the plugin root directory is mandatory,
4560
* so it loads the models from a subdirectory.
4661
*/
47-
$framework = new \Saltus\WP\Framework\Core( dirname( __FILE__ ) );
62+
$framework = new \Saltus\WP\Framework\Core( dirname( __FILE__ ), __FILE__ );
4863
$framework->register();
4964

5065
/**
@@ -168,8 +183,98 @@ Includes support for [github-updater](https://github.com/afragen/github-updater)
168183
* Clone [github-updater](https://github.com/afragen/github-updater) to your sites plugins/ folder
169184
* Activate via WordPress
170185

186+
## WordPress-Native MCP/Abilities
187+
188+
Saltus Framework exposes its AI-facing tool surface through the WordPress-native MCP/Abilities API. Native WordPress MCP clients can discover and call the `saltus/*` abilities directly from the active plugin.
189+
190+
For full documentation, see [docs/MCP.md](docs/MCP.md). For client integration guidance, see [docs/MCP-CLIENTS.md](docs/MCP-CLIENTS.md). These pages are source material for the future Saltus MCP documentation site.
191+
192+
### Quick Start
193+
194+
Install and activate the plugin that uses Saltus Framework on a WordPress version with the Abilities API. Saltus registers its abilities during `wp_abilities_api_init`; clients that understand WordPress-native MCP/Abilities can discover the `saltus/*` tools from WordPress.
195+
196+
The standalone local stdio MCP server has been removed. Saltus MCP development targets WordPress-native abilities instead.
197+
198+
### Capability Dispatch
199+
200+
Abilities dispatch through WordPress REST requests, so existing REST permission callbacks and `current_user_can()` checks remain authoritative. WordPress versions without the Abilities API simply skip Saltus ability registration.
201+
202+
### Service Gating and `is_needed()`
203+
204+
To keep the application performant and clean, the framework separates REST/MCP route registration from the execution of admin and frontend hooks using a two-pass registration model:
205+
- **First Pass (Unconditional):** Services implementing `RestRouteProvider` or `ToolContributor` are instantiated unconditionally during plugin boot to register endpoints and tools. No scripts, styles, or hooks are wired up.
206+
- **Second Pass (Gated):** Services are registered in the main service container, which strictly enforces the `is_needed()` gate (defined by the `Conditional` interface). If `is_needed()` returns `false` (e.g. an admin-only feature on a frontend page, or a disabled feature), the service is skipped, avoiding loading unneeded scripts, styles, or hooks.
207+
208+
Saltus wraps ability execution with WordPress-native audit logging, rate limiting, and transient caching. Read-only abilities can be cached in transients, mutating abilities clear the MCP cache, rate limits are keyed by the current user or request identifier, and audit records are written to the Saltus MCP audit table. Expired audit rows are removed by a daily WP-Cron retention job.
209+
210+
### Available Tools
211+
212+
| Tool | Description |
213+
|------|-------------|
214+
| `get_health` | Get Saltus Framework health, version, error rate, latency, cache, and rate-limit status |
215+
| `list_models` | List all registered CPTs and taxonomies |
216+
| `get_model` | Get details of a specific post type or taxonomy |
217+
| `list_posts` | Query posts with filters (status, search, pagination) |
218+
| `get_post` | Get a single post with all fields and meta |
219+
| `create_post` | Create a new post in any CPT |
220+
| `update_post` | Update an existing post's fields and meta |
221+
| `delete_post` | Trash or force delete a post |
222+
| `list_terms` | List terms from a taxonomy |
223+
| `create_term` | Create a new term in a taxonomy |
224+
| `duplicate_post` | Duplicate a WordPress post |
225+
| `export_post` | Export a post as WXR |
226+
| `get_settings` | Get Saltus settings for a post type |
227+
| `update_settings` | Update Saltus settings for a post type |
228+
| `reorder_posts` | Batch update post menu order |
229+
| `list_meta_fields` | Discover Saltus meta field definitions across all registered CPTs |
230+
| `get_meta_fields` | Get Saltus meta field definitions for a post type |
231+
232+
Meta field discovery preserves the raw Saltus/Codestar configuration in `meta` and includes normalized MCP-friendly metadata in `normalized.fields` and `normalized.rest_meta_keys`. Nested fields are exposed as paths such as `points_info.coordinates.latitude`, with JSON-schema-like types and REST writability information.
233+
234+
### Requirements
235+
236+
- WordPress 7.0+ or a WordPress build that provides the Abilities API
237+
- A WordPress-native MCP/Abilities client
238+
- The plugin using Saltus Framework must be active
239+
240+
### Configuration
241+
242+
No local MCP server configuration is required for the WordPress-native path. Runtime behavior can be tuned with WordPress filters:
243+
244+
| Filter | Purpose |
245+
|--------|---------|
246+
| `saltus/framework/mcp/audit/enabled` | Enable or disable audit writes |
247+
| `saltus/framework/mcp/audit/retention_days` | Set audit retention before daily WP-Cron cleanup |
248+
| `saltus/framework/mcp/rate_limit/enabled` | Enable or disable rate limiting |
249+
| `saltus/framework/mcp/rate_limit/max_requests` | Set max ability calls per window |
250+
| `saltus/framework/mcp/rate_limit/window_seconds` | Set the rate-limit window |
251+
| `saltus/framework/mcp/rate_limit/identifier` | Override the rate-limit identifier |
252+
| `saltus/framework/mcp/cache/enabled` | Enable or disable transient caching |
253+
| `saltus/framework/mcp/cache/ttl` | Set cache TTL per tool |
254+
| `saltus/framework/mcp/cache/cacheable` | Override whether a tool is cacheable |
255+
256+
### Generated MCP documentation
257+
258+
The detailed MCP ability reference is generated from the `src/MCP/Tools` source classes:
259+
260+
```bash
261+
composer docs:mcp
262+
```
263+
264+
This refreshes `docs/MCP-ABILITIES.md` and the generated ability table in `docs/MCP.md`.
265+
171266
## Building
172267

268+
### Quality checks
269+
270+
Run the static analysis and coding-standard checks from the repository root:
271+
272+
```bash
273+
composer phpstan
274+
composer phpcs
275+
composer validate --strict
276+
```
277+
173278
### Disadvantages of classmap
174279
As we move from 'files' to 'classmap', heed this:
175-
> Manual Updates: If you add new classes, you must regenerate the classmap by running composer dump-autoload.
280+
> Manual Updates: If you add new classes, you must regenerate the classmap by running composer dump-autoload.

0 commit comments

Comments
 (0)