Skip to content

feat: new MCP tools — run_command, LogTools, CacheTools, ModelTools - #7

Merged
josbeir merged 12 commits into
mainfrom
feat/new-tools
May 23, 2026
Merged

josbeir merged 12 commits into
mainfrom
feat/new-tools

Conversation

@josbeir

@josbeir josbeir commented May 23, 2026 •

Copy link
Copy Markdown
Owner

Overview

Adds four new MCP tool groups developed in TDD red/green cycles, one feature at a time.


Completed

Feature 1 — SubprocessRunner + run_command

src/Utility/SubprocessRunner.php (new)
Shared subprocess execution utility extracted from TinkerTools. Wraps proc_open with stdin piping, timeout + SIGKILL, and a consistent return shape {success, output, stderr, exit_code, [timed_out]}.

src/Tools/CommandTools — run_command MCP tool
Runs any registered CakePHP console command in a subprocess. Command names are validated against the application's CommandCollection before execution (allowlist), preventing arbitrary shell invocation. Timeout clamped to [1, 300] seconds. Each argument token in $args is individually escaped with escapeshellarg to prevent shell injection.

src/Tools/TinkerTools — refactored
Delegates all proc_open logic to SubprocessRunner; public API unchanged.

Tests: 13 for SubprocessRunner, 6 for run_command.


Feature 2 — LogTools

MCP tools for reading application logs:

  • log_list — list available log files with size/mtime metadata
  • log_read(file, lines, level) — tail lines from a log file, optionally filtered by level; path validated inside LOGS directory. Uses reverse-seek for plain reads (bounded memory) and a rolling-buffer for level-filtered reads. The lines parameter is clamped to [1, 5000].

Feature 3 — CacheTools

MCP tools for cache inspection and management:

  • cache_configs — list configured cache engines and their settings
  • cache_read(config, key) — read a cache entry
  • cache_write(config, key, value) — write a cache entry
  • cache_delete(config, key) — delete a cache entry
  • cache_clear(config) — clear a cache config

All write/read/delete/clear tools validate the config name against Cache::configured() and throw a ToolCallException for unknown configs.


Feature 4 — ModelTools

MCP tools for ORM introspection and querying:

  • orm_describe(alias, connection) — describe a Table's alias, table name, connection, primary key, display field, entity class, associations, and behaviors
  • orm_find(alias, connection, type, limit) — run a all/first/count find on a Table and return plain arrays; limit clamped to [1, 100]

josbeir added 8 commits May 23, 2026 12:06
…nkerTools

- Extract SubprocessRunner from TinkerTools for shared subprocess execution
- Add run_command MCP tool to CommandTools with collection-based allowlist
- Refactor TinkerTools to delegate proc_open logic to SubprocessRunner
- Add tests for SubprocessRunner (13 tests) and run_command (6 tests)
- log_list: lists .log files in LOGS dir with name/size/modified/path
- log_read: tails N lines from a log file with optional level filter
- Path traversal prevention via realpath validation inside LOGS
- 13 tests covering listing, reading, filtering, and security boundaries
On PHP 8.2 (Linux), proc_get_status() internally reaps the child process
zombie via waitpid() on the first call where running=false. A subsequent
proc_close() then returns -1 because the process has already been reaped.

Fix: capture $status['exitcode'] immediately when running=false, and use
proc_close() in the finally block only for resource cleanup.

Also:
- Replace glob() with Symfony Finder in LogTools (cleaner, handles edge cases)
- Extend log_list description to note non-filesystem logging returns []
- Fix PHPCS: change inline doc comment to multi-line on LogToolsTest property
CakePHP 5.2.0 (prefer-lowest) exits with code 1 for --help, while
newer versions exit 0. The integration test's goal is to verify the
subprocess mechanism works end-to-end, not to audit CakePHP's --help
behaviour, so assert output is non-empty and exit_code != -1 instead.
CakePHP 5.2.0 writes --help output to stderr; newer versions write to
stdout. Check both to avoid version-specific failures.
…ompat

stream_set_blocking() is unreliable for proc_open pipes on Windows —
fread() on a 'non-blocking' pipe still blocks there, causing the timeout
check to never fire (the process exits naturally after its full duration
and success=true is returned instead of timed_out=true/success=false).

Fix: poll only via proc_get_status() in a usleep(10ms) loop and do a
single stream_get_contents() read once the process has exited (or been
terminated). Output is intentionally limited to the OS pipe buffer
(~64 KB on Linux); this is acceptable for the commands this plugin runs.
@josbeir
josbeir marked this pull request as ready for review May 23, 2026 11:01
Copilot AI review requested due to automatic review settings May 23, 2026 11:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands the Synapse CakePHP MCP server plugin with new tool groups for subprocess-driven command execution, log inspection, cache inspection/management, and ORM introspection, while extracting shared subprocess logic into a reusable utility.

Changes:

  • Add Synapse\Utility\SubprocessRunner and refactor TinkerTools to delegate subprocess execution to it.
  • Add new MCP tool groups: run_command (CommandTools), LogTools (log_list, log_read), CacheTools (cache_*), and ModelTools (orm_describe, orm_find).
  • Add/extend PHPUnit coverage for the new utilities and tools.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/Utility/SubprocessRunner.php New proc_open wrapper for stdin piping, timeout handling, and output capture.
src/Tools/TinkerTools.php Refactors execution to use SubprocessRunner.
src/Tools/CommandTools.php Adds run_command MCP tool that shells out to bin/cake.php for allowlisted commands.
src/Tools/LogTools.php Adds log listing and tail-like reading with LOGS path validation.
src/Tools/CacheTools.php Adds cache configuration listing + CRUD-like cache entry tools.
src/Tools/ModelTools.php Adds ORM describe + basic find/query tooling.
tests/TestCase/Utility/SubprocessRunnerTest.php Unit tests for SubprocessRunner.
tests/TestCase/Tools/CommandToolsTest.php Adds unit + integration tests for run_command.
tests/TestCase/Tools/LogToolsTest.php Tests for log listing/reading + traversal protections.
tests/TestCase/Tools/CacheToolsTest.php Tests for cache config listing and cache read/write/delete/clear.
tests/TestCase/Tools/ModelToolsTest.php Tests for ORM describe/find behavior using fixtures.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Tools/CommandTools.php
Comment thread src/Utility/SubprocessRunner.php
Comment thread src/Utility/SubprocessRunner.php Outdated
Comment thread src/Tools/LogTools.php
Comment thread src/Tools/ModelTools.php
Comment thread src/Tools/CacheTools.php
@codecov-commenter

Copy link
Copy Markdown

⚠️ JUnit XML file not found

The CLI was unable to find any JUnit XML files to upload.
For more help, visit our troubleshooting guide.

@josbeir
josbeir merged commit 50db8e5 into main May 23, 2026
7 checks passed
@josbeir
josbeir deleted the feat/new-tools branch May 23, 2026 12:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants