Release/1.1#4
Conversation
- 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.
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the 📝 WalkthroughWalkthroughThis 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
Comment |
There was a problem hiding this comment.
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 useunknown[]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.parsewill throw a generic error ifsites.jsonis 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
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (11)
.eslintignore.eslintrc.cjsCHANGELOG.mdLICENSEREADME.mdeslint.config.jspackage.jsonsrc/index.tssrc/local-detector.tssrc/mysql-client.tssrc/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
executeWriteQuerymethod 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 interfaceThe 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: warnand 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 insrc/local-detector.ts.
195-232: Good tool documentation with example responses.The
mysql_current_siteandmysql_list_sitestool documentation includes clear input/output examples that match the implementations insrc/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
WriteResultinterface properly captures the essential metadata from MySQL write operations with appropriate optional fields forinsertIdandchangedRows.
25-47: Well-structured site configuration types.The
LocalSiteEntryandLocalSitesConfigtypes properly model Local'ssites.jsonstructure. UsingOmit<LocalSiteEntry, 'id'>for the config values is correct since theidbecomes the object key.
49-63: Good use of discriminated union for selection method.The
selectionMethodunion 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_WRITEStoggle 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
_siteSelectionbefore passing config toMySQLClientis 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_siteandmysql_list_sitestools follow the established pattern with empty input schemas, consistent with their read-only nature.
133-154: Conditional tool registration is appropriate.Registering
mysql_writeonly whenMYSQL_ALLOW_WRITES=trueprevents the tool from even appearing in the tool list when writes are disabled.
205-218: Defense-in-depth check on write operations.The additional
allowWritescheck 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
currentSiteSelectionis 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.jsmaintains good separation of concerns.
170-205: Good cross-platform path resolution for sites.json.The function properly handles macOS, Windows (with both
LOCALAPPDATAandAPPDATA), 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.sepbefore thestartsWithcheck on line 252 correctly prevents false positives like/Users/devmatching/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
listAvailableSitesfunction cleanly maps all configured sites with their running status based on socket existence.
426-456: Clean integration of site selection into config.The updated
getLocalMySQLConfigproperly integrates the newselectSite()workflow and exposes_siteSelectionfor upstream consumers while maintaining the existing return structure.
| "@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" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat package.json | head -80 | tail -40Repository: 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.
| // 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, | ||
| }; | ||
| } |
There was a problem hiding this comment.
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
selectionMethodto'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.
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:
SITE_ID,SITE_NAME, working directory, running processes, and filesystem fallbacks. Selection method and site metadata are now logged at startup. [1] [2] [3]SITE_ID,SITE_NAME, andLOCAL_SITES_JSONto control site selection and configuration. [1] [2]New tools for site introspection:
mysql_current_sitetool to return metadata about the currently connected Local site and the selection method used. [1] [2] [3]mysql_list_sitestool to enumerate all available Local sites and their running status. [1] [2] [3]Development tooling & dependency updates:
.eslintrc.cjsand.eslintignore, and addingeslint.config.js. Updates related dev dependencies for ESLint, TypeScript, and others. [1] [2] [3] [4]Documentation & metadata:
README.mdandCHANGELOG.mdto document multi-site support, new tools, configuration variables, and usage examples. [1] [2] [3] [4]LICENSE.These changes significantly improve the reliability, transparency, and usability of the MCP server in multi-site Local environments.