Skip to content

Conversation

@stevenceuppens
Copy link
Contributor

What?

Adds full localization support to the MCP plugin's resource operations (create, update, find, delete).

Why?

The MCP plugin did not expose Payload's localization capabilities. Users with multilingual content could not create or manage translations through MCP, limiting the plugin's usefulness for international projects. This brings MCP feature parity with Payload's REST API.

How?

  • Add locale and fallbackLocale parameters to all resource tools (create, update, find, delete)
  • Pass locale parameters through to underlying Payload operations
  • Add comprehensive integration tests for localization features (6 new tests, all passing)
  • Update documentation with localization usage examples and MCP client configuration
  • Follow Payload REST API localization pattern for consistency

Testing:

pnpm test:int plugin-mcp
# All 15 tests passing (9 existing + 6 new localization tests)

Example Usage:

// Create content in English
{ "name": "createPosts", "arguments": { "title": "Hello", "locale": "en" }}

// Add Spanish translation
{ "name": "updatePosts", "arguments": { "id": "123", "title": "Hola", "locale": "es" }}

// Retrieve all translations
{ "name": "findPosts", "arguments": { "id": "123", "locale": "all" }}

Fixes #

@stevenceuppens stevenceuppens changed the title feat(plugin-mcp): add localization support to resource operations feat(mcp): add localization support to resource operations Oct 24, 2025
@stevenceuppens stevenceuppens changed the title feat(mcp): add localization support to resource operations feat: add localization support to MCP resource operations Oct 24, 2025
@DanRibbens DanRibbens requested a review from Copilot October 27, 2025 14:52
Copy link
Contributor

Copilot AI left a comment

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 adds comprehensive localization support to the MCP plugin, enabling multilingual content management through MCP that matches Payload's REST API capabilities.

Key Changes:

  • Added locale and fallbackLocale parameters to all resource operations (create, update, find, delete)
  • Implemented 6 new integration tests covering localization scenarios (all passing)
  • Updated documentation with localization usage examples and MCP client setup guide

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
test/plugin-mcp/int.spec.ts Added 6 comprehensive localization tests and updated getApiKey helper to support update/delete permissions
test/plugin-mcp/config.ts Configured localization with en/es/fr locales and enabled update/delete operations for Posts collection
test/plugin-mcp/collections/Posts.ts Marked title and content fields as localized
packages/plugin-mcp/src/mcp/tools/schemas.ts Added locale and fallbackLocale parameters to find, create, update, and delete tool schemas
packages/plugin-mcp/src/mcp/tools/resource/update.ts Implemented locale parameter handling in update operation and added to schema
packages/plugin-mcp/src/mcp/tools/resource/find.ts Implemented locale parameter handling in find operation
packages/plugin-mcp/src/mcp/tools/resource/delete.ts Implemented locale parameter handling in delete operation
packages/plugin-mcp/src/mcp/tools/resource/create.ts Implemented locale parameter handling in create operation with schema restructuring
docs/plugins/mcp.mdx Added comprehensive documentation for MCP client setup and localization features with examples

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

@kendelljoseph
Copy link
Contributor

This is a great start @stevenceuppens!

I'll dig into more detail today.

Copy link
Contributor

@DanRibbens DanRibbens left a comment

Choose a reason for hiding this comment

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

stevenceuppens added a commit to stevenceuppens/payload that referenced this pull request Nov 4, 2025
The MCP plugin's resource tools (find, update, delete) were only accepting
string IDs, which caused validation errors when using PostgreSQL. PostgreSQL
uses numeric IDs by default, while MongoDB uses string-based ObjectIDs.

Changes:
- Updated ID parameter schemas to accept both string and number types
- Added ID-to-string conversion in find, update, and delete tools
- Ensured backward compatibility with MongoDB's string IDs

This fixes test failures in PR payloadcms#14334 where all 4 localization tests were
failing with "Expected string, received number" validation errors in the
PostgreSQL integration test suite.

All 15 tests now pass in both PostgreSQL and MongoDB.

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

Co-Authored-By: Claude <noreply@anthropic.com>
@stevenceuppens
Copy link
Contributor Author

stevenceuppens commented Nov 4, 2025

PR Update: PostgreSQL & Partial Update Fixes

Two commits added to resolve testing issues:

PostgreSQL ID Compatibility (e004c551d)

Issue: 4 localization tests failing in PostgreSQL due to numeric vs string ID mismatch
Fix: Updated MCP tool schemas to accept both string | number for IDs, with conversion to string for Payload operations
Files: Updated schemas and resource handlers (find/update/delete)

Partial Update Support (1696f9ecc)

Issue: Update tool required ALL fields, making single-field updates impossible
Fix: Applied .partial() to update schema, making all fields optional

- ...convertedFields.shape,
+ ...convertedFields.partial().shape,

Result: Both fixes maintain backward compatibility. All 15 tests pass in MongoDB and PostgreSQL.

stevenceuppens added a commit to stevenceuppens/payload that referenced this pull request Nov 5, 2025
The MCP plugin's resource tools (find, update, delete) were only accepting
string IDs, which caused validation errors when using PostgreSQL. PostgreSQL
uses numeric IDs by default, while MongoDB uses string-based ObjectIDs.

Changes:
- Updated ID parameter schemas to accept both string and number types
- Added ID-to-string conversion in find, update, and delete tools
- Ensured backward compatibility with MongoDB's string IDs

This fixes test failures in PR payloadcms#14334 where all 4 localization tests were
failing with "Expected string, received number" validation errors in the
PostgreSQL integration test suite.

All 15 tests now pass in both PostgreSQL and MongoDB.

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

Co-Authored-By: Claude <noreply@anthropic.com>
@stevenceuppens
Copy link
Contributor Author

I've rebased this PR to resolve the merge conflicts.

@stevenceuppens
Copy link
Contributor Author

@kendelljoseph @DanRibbens - can you give my PR another review :)

@jonathanelmgren
Copy link
Contributor

Bumping this. Would be really nice to have and seems like an easy merge :)

@stevenceuppens
Copy link
Contributor Author

@kendelljoseph @DanRibbens Can you give my PR another review please? 🙂

@kendelljoseph
Copy link
Contributor

@stevenceuppens Hey! I'll look at this right now. Lets get this done today :)

Copy link
Contributor

@kendelljoseph kendelljoseph left a comment

Choose a reason for hiding this comment

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

This is looking and working great! A much needed improvement! There are also improvements in this PR for Postgres users too, so this is all around a great addition!

We just need to have code conflicts resolved.

The comments about docs you can do as a part of resolving as well -- if not, I will make those improvements with a docs only PR.

stevenceuppens and others added 6 commits November 15, 2025 14:53
- Add locale and fallbackLocale parameters to all resource tools (create, update, find, delete)
- Add comprehensive integration tests for localization features
- Update documentation with localization usage examples and MCP client configuration
- Follow Payload REST API localization pattern for consistency
Updated documentation to accurately reflect that HTTP is the currently supported connection method, with REDIS and STDIO under consideration for future releases. Added a dedicated "Connection Methods" section with HTTP configuration example to provide clearer guidance for users.

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

Co-Authored-By: Claude <noreply@anthropic.com>
The MCP plugin's resource tools (find, update, delete) were only accepting
string IDs, which caused validation errors when using PostgreSQL. PostgreSQL
uses numeric IDs by default, while MongoDB uses string-based ObjectIDs.

Changes:
- Updated ID parameter schemas to accept both string and number types
- Added ID-to-string conversion in find, update, and delete tools
- Ensured backward compatibility with MongoDB's string IDs

This fixes test failures in PR payloadcms#14334 where all 4 localization tests were
failing with "Expected string, received number" validation errors in the
PostgreSQL integration test suite.

All 15 tests now pass in both PostgreSQL and MongoDB.

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

Co-Authored-By: Claude <noreply@anthropic.com>
Previously, the MCP update tool required all collection fields to be provided
when updating a document, even for partial updates. This was because the
schema converter preserved the 'required' status of fields from the collection
schema.

Changes:
- Use Zod's `.partial()` method on converted fields to make all fields optional
- This allows updating a single field without providing all required fields
- Maintains backward compatibility with full updates

Fixes issue where users couldn't update a single field (like a title) without
passing in all the document data. This was particularly problematic with
complex nested fields like layout blocks.

Example:
Before: updatePosts({ id: 1, title: "New Title", content: "...", ... }) ❌
After:  updatePosts({ id: 1, title: "New Title" }) ✅

All 15 tests pass in both PostgreSQL and MongoDB.

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove unnecessary String() conversions for IDs in delete, find, and update tools
  - Payload operations accept both string and number IDs natively
  - Conversion was confusing and didn't provide PostgreSQL compatibility benefits
- Update MCP documentation:
  - Clarify HTTP-only transport support (remove REDIS/STDIO mentions)
  - Add detailed VSCode and Cursor MCP client configuration examples
  - Update localization examples to use proper JSON-RPC 2.0 format
  - Recommend npx mcp-remote approach for better compatibility

Addresses review comments from @JarrodMFlesch and @kendelljoseph

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

Co-Authored-By: Claude <noreply@anthropic.com>
…lity

- Fix beforeRead hook in Posts collection to handle localized fields
  - Handle both object (localized) and string (non-localized) field values
  - Apply MCP hook override to all locale values when field is localized
- Update test expectations to match new MCP hook behavior
  - Replace "Title Override: " prefix with " (MCP Hook Override)" suffix
  - Hook adds suffix to all localized values when locale="all"
- Add products collection to API key in test helper
  - Fixes "should list tools" test expecting 4 tools

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

Co-Authored-By: Claude <noreply@anthropic.com>
@kendelljoseph kendelljoseph changed the title feat: add localization support to MCP resource operations feat(plugin-mcp): add localization support to MCP resource operations Nov 20, 2025
Copy link
Contributor

@kendelljoseph kendelljoseph left a comment

Choose a reason for hiding this comment

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

  • fix: id number | string for postgres
  • feat: CRUD resource tools support locale and fallbackLocale

Looks great, 👍🏿

Copy link
Contributor

@DanRibbens DanRibbens left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution!

@DanRibbens DanRibbens merged commit a3f490b into payloadcms:main Nov 20, 2025
186 of 188 checks passed
@github-actions
Copy link
Contributor

🚀 This is included in version v3.65.0

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.

5 participants