Skip to content

Release/1.1#4

Merged
jack-arturo merged 4 commits into
mainfrom
release/1.1
Jan 4, 2026
Merged

Release/1.1#4
jack-arturo merged 4 commits into
mainfrom
release/1.1

Conversation

@jack-arturo

Copy link
Copy Markdown
Member

This pull request delivers a major update (v1.1.0) focused on robust multi-site support for Local by Flywheel, improved tooling, and modernized development dependencies. The server now reliably auto-selects the correct Local site/database via a clear priority order, introduces tools for inspecting site selection and listing available sites, and migrates ESLint configuration to the new flat config format. Several environment variables and dependency updates are also included.

Multi-site detection & explicit selection:

  • Implements a priority-based site selection mechanism for connecting to the correct Local site/database, considering SITE_ID, SITE_NAME, working directory, running processes, and filesystem fallbacks. Selection method and site metadata are now logged at startup. [1] [2] [3]
  • Adds support for new environment variables: SITE_ID, SITE_NAME, and LOCAL_SITES_JSON to control site selection and configuration. [1] [2]

New tools for site introspection:

  • Introduces the mysql_current_site tool to return metadata about the currently connected Local site and the selection method used. [1] [2] [3]
  • Adds the mysql_list_sites tool to enumerate all available Local sites and their running status. [1] [2] [3]

Development tooling & dependency updates:

  • Migrates ESLint configuration from legacy to v9 flat config, removing .eslintrc.cjs and .eslintignore, and adding eslint.config.js. Updates related dev dependencies for ESLint, TypeScript, and others. [1] [2] [3] [4]
  • Updates MCP SDK to 1.25.1, TypeScript to 5.9.3, dotenv, and other dependencies to latest versions. [1] [2]

Documentation & metadata:

  • Updates README.md and CHANGELOG.md to document multi-site support, new tools, configuration variables, and usage examples. [1] [2] [3] [4]
  • Updates copyright year in LICENSE.
  • Bumps package version to 1.1.0.

These changes significantly improve the reliability, transparency, and usability of the MCP server in multi-site Local environments.

jack-arturo and others added 2 commits January 4, 2026 13:23
- Migrate from ESLint 8 (.eslintrc.cjs) to ESLint 9 (eslint.config.js)
- Update MCP SDK to 1.25.1 (from 0.5.0)
- Update dotenv to 17.2.3 (major version bump)
- Update TypeScript to 5.9.3
- Update @typescript-eslint/* to 8.50.1
- Update eslint-plugin-unused-imports to 4.3.0
- Update prettier to 3.7.4
- Fix npm audit vulnerability (qs package)
- Update copyright year to 2024-2026

BREAKING CHANGE: Requires ESLint 9+ for linting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements priority-based site selection for Local by Flywheel sites using SITE_ID, SITE_NAME, working directory, process, or filesystem fallback. Adds new tools: mysql_current_site (shows current site and selection method) and mysql_list_sites (lists all available sites and their status). Updates documentation, improves error messages, enhances startup logging, and introduces write operation support (mysql_write) gated by MYSQL_ALLOW_WRITES. Updates dependencies and refactors types and local site detection logic.
@coderabbitai

coderabbitai Bot commented Jan 4, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This pull request updates the project to version 1.1.0 with multi-site support for Local WordPress environments, upgrades ESLint to the flat config format, modernizes dependencies, adds MySQL write query capabilities, and documents the new site detection and selection functionality.

Changes

Cohort / File(s) Summary
ESLint Configuration Upgrade
.eslintignore, .eslintrc.cjs, eslint.config.js
Migrated from .eslintrc.cjs to eslint.config.js (flat config format). Removed dist and node_modules from .eslintignore entries. New configuration wires ESLint recommended, TypeScript-ESLint rules, Prettier compatibility, and unused-imports plugin targeting src/**/*.ts.
Package Management & Versioning
package.json, CHANGELOG.md
Bumped version to 1.1.0. Restructured devDependencies: upgraded ESLint to ^9.39.0, TypeScript to ^5.9.3, added @typescript-eslint/parser, eslint-config-prettier, eslint-plugin-unused-imports, globals, and other tooling updates. Added 1.1.0 release notes documenting site context detection, new tools, and environment variables.
Documentation & Legal
README.md, LICENSE
Updated LICENSE copyright to 2024-2026. Added comprehensive Multi-Site Support section to README detailing priority-based site selection workflow, environment variables (SITE_ID, SITE_NAME, LOCAL_SITES_JSON, LOCAL_RUN_DIR), and new tool documentation for mysql_current_site and mysql_list_sites with examples.
Core Type Definitions
src/types.ts
Added four new exported interfaces: WriteResult (for write operation responses), LocalSiteEntry (site configuration structure), LocalSitesConfig (sites.json structure), and SiteSelectionResult (site detection result with selection method).
Local Site Detection & Selection
src/local-detector.ts
Introduced multi-faceted site detection with new functions: loadLocalSitesConfig, findSiteByName, findSiteByPath, buildSiteInfoFromEntry, selectSite (priority-based: SITE_ID → SITE_NAME → CWD → process/filesystem fallback), and listAvailableSites. Extended getLocalMySQLConfig to include _siteSelection metadata and integrate new detection pipeline.
MySQL Write Operations
src/mysql-client.ts
Added public method executeWriteQuery for parameterized write operations. Validates SQL (single statement, non-empty), enforces allowed operations (INSERT, UPDATE, DELETE), requires WHERE clauses for UPDATE/DELETE, blocks SELECT subqueries, and returns WriteResult with affectedRows, insertId, and changedRows.
MCP Server Integration
src/index.ts
Integrated site selection into startup flow with currentSiteSelection state variable. Added MYSQL_ALLOW_WRITES toggle for conditional mysql_write tool registration. Exposed two new public tools: mysql_current_site (current site details) and mysql_list_sites (available sites enumeration). Extended tool execution handling with JSON responses for write operations and site queries.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant MCPServer as MCP Server<br/>(src/index.ts)
    participant Detector as Site Detector<br/>(src/local-detector.ts)
    participant Loader as Config Loader
    participant MySQLClient

    rect rgb(240, 248, 255)
    Note over Client,MySQLClient: Startup - Site Selection Flow
    Client->>MCPServer: Initialize server
    MCPServer->>Detector: selectSite()
    alt Environment-based (Priority 1-2)
        Detector->>Loader: Check SITE_ID / SITE_NAME env vars
        Loader-->>Detector: Site found or not found
    end
    alt CWD Detection (Priority 3)
        Detector->>Loader: Match process CWD with sites
        Loader-->>Detector: Matching site or none
    end
    alt Process/Filesystem Fallback (Priority 4+)
        Detector->>Loader: loadLocalSitesConfig()
        Loader-->>Detector: LocalSitesConfig
        Detector->>Loader: findSiteByPath() / detect process
        Loader-->>Detector: Site entry
    end
    Detector->>Detector: buildSiteInfoFromEntry()
    Detector-->>MCPServer: SiteSelectionResult
    MCPServer->>MySQLClient: Create connection<br/>(host, port, user, password)
    MySQLClient-->>MCPServer: Connection ready
    MCPServer->>MCPServer: Store currentSiteSelection
    MCPServer-->>Client: Server initialized
    end

    rect rgb(240, 255, 240)
    Note over Client,MySQLClient: Runtime - Site Tools
    Client->>MCPServer: Call mysql_current_site
    MCPServer-->>Client: Return currentSiteSelection details
    Client->>MCPServer: Call mysql_list_sites
    MCPServer->>Detector: listAvailableSites()
    Detector->>Loader: loadLocalSitesConfig()
    Loader-->>Detector: All configured sites
    Detector-->>MCPServer: Array of sites with running status
    MCPServer-->>Client: Return sites + currentSiteId
    end

    rect rgb(255, 250, 240)
    Note over Client,MySQLClient: Runtime - Write Operations
    Client->>MCPServer: Call mysql_write(sql, params)
    alt MYSQL_ALLOW_WRITES enabled
        MCPServer->>MySQLClient: executeWriteQuery(sql, params)
        MySQLClient->>MySQLClient: Validate: single statement,<br/>allowed operation, WHERE clauses
        MySQLClient->>MySQLClient: Execute parameterized query
        MySQLClient-->>MCPServer: WriteResult{affectedRows, ...}
        MCPServer-->>Client: Return WriteResult
    else Writes disabled
        MCPServer-->>Client: Return error: writes not allowed
    end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Release/1.1' is partially related to the changeset; it indicates a release version but lacks specificity about the main features (multi-site support, tooling updates). Consider a more descriptive title such as 'Release v1.1: Add multi-site support and modernize dev tooling' to better convey the primary changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description comprehensively details all major changes including multi-site support, new tools, ESLint migration, dependency updates, and documentation improvements, directly aligned with the changeset.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/index.ts (1)

20-25: Consider typing the debug log parameters.

The static analysis flagged any[]. While acceptable for a debug utility, you could use unknown[] for stricter typing.

🔎 Proposed change
-function debugLog(...args: any[]) {
+function debugLog(...args: unknown[]) {
src/local-detector.ts (1)

207-216: Consider adding JSON schema validation.

JSON.parse will throw a generic error if sites.json is malformed. Consider wrapping with a try-catch for a more descriptive error message.

🔎 Proposed enhancement
 export function loadLocalSitesConfig(): LocalSitesConfig {
   const sitesJsonPath = getSitesJsonPath();
   debugLog(`Loading sites.json from: ${sitesJsonPath}`);

   const content = fs.readFileSync(sitesJsonPath, 'utf8');
-  return JSON.parse(content) as LocalSitesConfig;
+  try {
+    return JSON.parse(content) as LocalSitesConfig;
+  } catch (error: any) {
+    throw new Error(`Failed to parse sites.json at ${sitesJsonPath}: ${error.message}`);
+  }
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d7c4457 and ca52e0b.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (11)
  • .eslintignore
  • .eslintrc.cjs
  • CHANGELOG.md
  • LICENSE
  • README.md
  • eslint.config.js
  • package.json
  • src/index.ts
  • src/local-detector.ts
  • src/mysql-client.ts
  • src/types.ts
💤 Files with no reviewable changes (2)
  • .eslintrc.cjs
  • .eslintignore
🧰 Additional context used
🧬 Code graph analysis (3)
src/index.ts (2)
src/types.ts (1)
  • SiteSelectionResult (52-63)
src/local-detector.ts (2)
  • getLocalMySQLConfig (430-457)
  • listAvailableSites (404-424)
src/mysql-client.ts (1)
src/types.ts (1)
  • WriteResult (19-23)
src/local-detector.ts (1)
src/types.ts (4)
  • LocalSitesConfig (45-47)
  • LocalSiteEntry (28-40)
  • LocalSiteInfo (1-6)
  • SiteSelectionResult (52-63)
🪛 GitHub Check: test
src/index.ts

[warning] 20-20:
Unexpected any. Specify a different type

🔇 Additional comments (27)
LICENSE (1)

4-4: LGTM! Copyright year updated appropriately.

The copyright range now includes 2024-2026, which aligns with the 1.1.0 release date.

package.json (1)

3-3: Version bump to 1.1.0 is appropriate.

The version increment correctly reflects the new features (multi-site support, new tools) documented in the CHANGELOG.

CHANGELOG.md (1)

3-35: LGTM! Clear and comprehensive release notes.

The 1.1.0 changelog entry effectively documents the multi-site support features, new tools, environment variables, and dependency updates. The priority-based site selection workflow is clearly explained.

src/mysql-client.ts (2)

2-2: LGTM! WriteResult type import added.

The WriteResult type is correctly imported to support the new write query functionality.


76-135: Excellent safety validations for write operations.

The executeWriteQuery method implements multiple layers of security checks:

✓ Single-statement enforcement with trailing semicolon support
✓ Restricts operations to INSERT, UPDATE, DELETE only
✓ Blocks schema operations (CREATE/DROP/ALTER/TRUNCATE)
✓ Requires parameterized queries for UPDATE/DELETE to prevent unintended bulk operations
✓ Blocks subqueries for additional safety
✓ Properly maps mysql2 ResultSetHeader to WriteResult interface

The validation approach strikes a good balance between security and usability. The requirement for params on UPDATE/DELETE (line 105) is a pragmatic safety measure that encourages explicit, parameterized WHERE clauses.

eslint.config.js (1)

1-45: ESLint v9 flat config migration verified and working correctly.

The flat config executes without errors. ESLint 9.39.0 and all plugins (typescript-eslint 8.50.1, eslint-config-prettier 10.1.0, unused-imports 4.3.0) are compatible and functioning as expected. Linting runs successfully with only 19 expected warnings from intentional rule configurations (@typescript-eslint/no-explicit-any: warn and unused eslint-disable directives), no unexpected errors.

README.md (3)

92-151: Well-documented multi-site support.

The multi-site documentation clearly explains the priority-based selection mechanism with practical examples for explicit site selection, working directory detection, and connection verification. This aligns well with the selectSite() implementation in src/local-detector.ts.


195-232: Good tool documentation with example responses.

The mysql_current_site and mysql_list_sites tool documentation includes clear input/output examples that match the implementations in src/index.ts.


338-345: Clear environment variable documentation.

The Site Selection Variables table provides a concise reference for the new configuration options.

src/types.ts (3)

18-23: Clean write result interface.

The WriteResult interface properly captures the essential metadata from MySQL write operations with appropriate optional fields for insertId and changedRows.


25-47: Well-structured site configuration types.

The LocalSiteEntry and LocalSitesConfig types properly model Local's sites.json structure. Using Omit<LocalSiteEntry, 'id'> for the config values is correct since the id becomes the object key.


49-63: Good use of discriminated union for selection method.

The selectionMethod union type provides clear traceability for debugging which site selection strategy was used.

src/index.ts (7)

17-18: Secure write gating via environment variable.

The MYSQL_ALLOW_WRITES toggle provides a clear opt-in mechanism for write operations, keeping the default behavior read-only.


27-46: Good separation of site selection metadata from config.

Extracting _siteSelection before passing config to MySQLClient is clean, and the startup logging provides useful visibility into which site was selected and how.


114-130: Well-defined tool schemas for site inspection.

The mysql_current_site and mysql_list_sites tools follow the established pattern with empty input schemas, consistent with their read-only nature.


133-154: Conditional tool registration is appropriate.

Registering mysql_write only when MYSQL_ALLOW_WRITES=true prevents the tool from even appearing in the tool list when writes are disabled.


205-218: Defense-in-depth check on write operations.

The additional allowWrites check in the handler provides defense-in-depth, guarding against potential future code paths that might bypass the conditional tool registration.


220-259: Clear handling for missing site selection.

Returning a structured error object when currentSiteSelection is undefined provides useful feedback to callers, indicating fallback to environment variables.


261-297: Robust error handling for site listing.

The nested try-catch properly handles failures from listAvailableSites() and returns a structured error response instead of propagating exceptions.

src/local-detector.ts (8)

5-10: Clean type imports from shared types module.

Importing the types from ./types.js maintains good separation of concerns.


170-205: Good cross-platform path resolution for sites.json.

The function properly handles macOS, Windows (with both LOCALAPPDATA and APPDATA), and Linux paths with appropriate fallbacks.


218-225: Correct tilde expansion and path normalization.

The function properly handles ~ expansion using the user's home directory and resolves to absolute paths.


227-240: Case-insensitive site name lookup is user-friendly.

Converting both the input and stored names to lowercase before comparison provides a better developer experience.


242-258: Safe path prefix matching.

Appending path.sep before the startsWith check on line 252 correctly prevents false positives like /Users/dev matching /Users/developer.


260-294: Clear error message when site is not running.

The error message includes the site name, ID, expected socket path, and actionable guidance to start the site in Local.


401-424: Simple and effective site enumeration.

The listAvailableSites function cleanly maps all configured sites with their running status based on socket existence.


426-456: Clean integration of site selection into config.

The updated getLocalMySQLConfig properly integrates the new selectSite() workflow and exposes _siteSelection for upstream consumers while maintaining the existing return structure.

Comment thread package.json
Comment on lines +59 to +70
"@eslint/js": "^9.39.2",
"@types/node": "^22.0.0",
"@typescript-eslint/eslint-plugin": "^8.50.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-unused-imports": "^3.1.0",
"eslint-config-prettier": "^9.1.0",
"prettier": "^3.3.3"
"@typescript-eslint/parser": "^8.50.1",
"eslint": "^9.39.0",
"eslint-config-prettier": "^10.1.0",
"eslint-plugin-unused-imports": "^4.3.0",
"globals": "^16.0.0",
"prettier": "^3.7.4",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.50.1"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat package.json | head -80 | tail -40

Repository: verygoodplugins/mcp-local-wp

Length of output: 1084


🌐 Web query:

@types/node v22 Node 18 compatibility

💡 Result:

Short answer: @types/node v22 provides typings for Node.js v22 and can introduce types/APIs not present in Node 18. That can cause TypeScript compile errors when your runtime is Node 18 — so use the matching @types major for your Node runtime (e.g. @types/node@18 for Node 18) or pin the types to the Node major you target. [1][2][3][4]

What to do

  • Pin the types: npm i -D @types/node@18 (or use an exact semver like 18.x) so your typings match your Node runtime. [1][3]
  • Alternatively: set "types" / "typeRoots" in tsconfig, or use skipLibCheck as a last resort to silence mismatches. [2][3]
  • If upgrading Node to v22 (recommended long-term), then move to @types/node@22. [1]

References

  • @types/node v22 package (npm). [1]
  • Explanation that @types/node major/minor map to Node versions (community/StackOverflow). [2]
  • DefinitelyTyped discussion about selecting the correct @types/node for your Node version. [3]
  • Example of real-world compile break when types and runtime versions mismatch (puppeteer issue). [4]

Sources
[1] npm: @types/node (v22) — https://www.npmjs.com/package/%40types/node (see v22).
[2] StackOverflow: relationship between Node.js and @types/node versions.
[3] DefinitelyTyped discussion: how to install correct @types/node for current Node.
[4] Puppeteer GitHub issue showing compile errors when types/runtime diverge.


🏁 Script executed:

cat package.json | grep -A 5 '"engines"'

Repository: verygoodplugins/mcp-local-wp

Length of output: 192


Update @types/node to v18 to match the Node 18+ engine requirement.

@types/node v22 is designed for Node.js v22 and includes type definitions for v22-specific APIs. Using it with a Node 18+ engine requirement can cause TypeScript compilation errors. Update @types/node to ^18.0.0 to align with the "node": ">=18.0.0" engine specification, or upgrade the engine requirement to Node 22+ if the project targets it.

🤖 Prompt for AI Agents
In package.json around lines 59 to 70, the @types/node dependency is set to
^22.0.0 which mismatches the project's node engine requirement (>=18.0.0);
change the @types/node version to ^18.0.0 (or alternatively update the engine
field to >=22.0.0 if you intend to target Node 22+) so TypeScript uses the
correct Node 18 type definitions and avoids compilation errors.

Comment thread src/local-detector.ts
Comment on lines +369 to +399
// Priority 4 & 5: Fall back to existing detection (process or filesystem)
debugLog('No explicit site selection, falling back to auto-detection');
const siteInfo = findActiveLocalSocket();

// Try to look up site metadata from sites.json
let siteName = siteInfo.siteId;
let sitePath = 'unknown';
let domain = 'unknown';
let selectionMethod: SiteSelectionResult['selectionMethod'] = 'filesystem_fallback';

try {
const sites = loadLocalSitesConfig();
const site = sites[siteInfo.siteId];
if (site) {
siteName = site.name;
sitePath = normalizeSitePath(site.path);
domain = site.domain;
selectionMethod = 'process_detection';
}
} catch {
// sites.json not available, use defaults
}

return {
siteInfo,
siteName,
sitePath,
domain,
selectionMethod,
};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential inaccuracy in selectionMethod for fallback path.

When falling back to findActiveLocalSocket(), the code sets selectionMethod to 'process_detection' if the site is found in sites.json (line 386). However, findActiveLocalSocket() might have used filesystem fallback internally. Consider propagating the actual detection method from findActiveLocalSocket() for more accurate reporting.

🔎 Context

The current logic:

  • Lines 371: Calls findActiveLocalSocket() which internally tries process detection first, then filesystem fallback
  • Lines 377-390: Sets selectionMethod to 'process_detection' if site metadata found, otherwise 'filesystem_fallback'

This conflates "found in sites.json" with "detected via process", but findActiveLocalSocket() might have fallen back to filesystem scan even when sites.json metadata exists.

One option is to have findActiveLocalSocket() return which method it used, or accept this minor inaccuracy for simplicity.

The findActiveLocalSocket function now returns both the detected site info and the method used ('process_detection' or 'filesystem_fallback'). The selectSite function is updated to use this detection method for more accurate reporting. Also improves error handling for unknown error types.
Update version numbers in package-lock.json and server.json from 1.0.1 to 1.1.0 to reflect a new release.
@jack-arturo jack-arturo merged commit a16aea6 into main Jan 4, 2026
5 checks passed
@jack-arturo jack-arturo deleted the release/1.1 branch January 4, 2026 14:52
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.

1 participant