Describe the Bug
The MCP plugin's simplifyRelationshipFields utility strips $ref options from oneOf unions but does not inject an ID-type replacement. For nullable relationship fields, this causes the field schema to collapse to { type: "null" }, making it impossible to pass a valid relationship ID through MCP create/update tools.
Root cause
In src/utils/schemaConversion/simplifyRelationshipFields.ts, when a nullable relationship field has a JSON schema like:
{
"oneOf": [
{ "type": "null" },
{ "$ref": "#/definitions/media" }
]
}
The function filters out the $ref option (lines 33-35), leaving only [{ "type": "null" }]. Since nonRefOptions.length === 1, it unwraps to just { "type": "null" } (lines 37-39).
The $ref option should be replaced with an ID-accepting type (e.g. { "type": ["string", "number"] }) rather than simply removed, since MCP clients need to pass relationship IDs, not populated objects.
Affected fields
Every nullable (non-required) relationship field on every collection. For example:
icon (relationship to media) → becomes { "type": "null" } in the MCP tool schema
tenant (relationship added by @payloadcms/plugin-multi-tenant) → becomes { "type": "null" }
Required relationship fields are also affected — they produce an empty schema {} (the oneOf only contains a $ref, so after filtering there are zero nonRefOptions).
Link to the code that reproduces this issue
https://github.com/payloadcms/payload/blob/main/packages/plugin-mcp/src/utils/schemaConversion/simplifyRelationshipFields.ts#L33-L48
Reproduction Steps
- Create a collection with a nullable relationship field:
{
name: 'icon',
type: 'relationship',
relationTo: 'media',
}
- Enable MCP plugin for that collection
- Connect an MCP client and inspect the
create tool's input schema
- The
icon field will show { "type": "null" } instead of accepting a string/number ID
- Attempting to create a document with
icon: 1 (a valid media ID) fails with a validation error
Suggested fix
When stripping $ref options, inject a replacement that accepts relationship IDs:
const nonRefOptions = processed.oneOf
.filter((option) => !(option && typeof option === 'object' && '$ref' in option))
.map((option) => simplifyRelationshipFields(option))
// If we removed $ref options, add an ID-accepting type
const hadRef = processed.oneOf.some(
(option) => option && typeof option === 'object' && '$ref' in option,
)
if (hadRef) {
nonRefOptions.push({ type: ['string', 'number'] })
}
Which area(s) are affected?
plugin: mcp
Environment Info
Relevant Packages:
payload: 3.81.0
@payloadcms/plugin-mcp: 3.81.0
@payloadcms/plugin-multi-tenant: 3.81.0
next: 15.3.1
react: 19.1.0
Describe the Bug
The MCP plugin's
simplifyRelationshipFieldsutility strips$refoptions fromoneOfunions but does not inject an ID-type replacement. For nullable relationship fields, this causes the field schema to collapse to{ type: "null" }, making it impossible to pass a valid relationship ID through MCP create/update tools.Root cause
In
src/utils/schemaConversion/simplifyRelationshipFields.ts, when a nullable relationship field has a JSON schema like:{ "oneOf": [ { "type": "null" }, { "$ref": "#/definitions/media" } ] }The function filters out the
$refoption (lines 33-35), leaving only[{ "type": "null" }]. SincenonRefOptions.length === 1, it unwraps to just{ "type": "null" }(lines 37-39).The
$refoption should be replaced with an ID-accepting type (e.g.{ "type": ["string", "number"] }) rather than simply removed, since MCP clients need to pass relationship IDs, not populated objects.Affected fields
Every nullable (non-required) relationship field on every collection. For example:
icon(relationship tomedia) → becomes{ "type": "null" }in the MCP tool schematenant(relationship added by@payloadcms/plugin-multi-tenant) → becomes{ "type": "null" }Required relationship fields are also affected — they produce an empty schema
{}(theoneOfonly contains a$ref, so after filtering there are zerononRefOptions).Link to the code that reproduces this issue
https://github.com/payloadcms/payload/blob/main/packages/plugin-mcp/src/utils/schemaConversion/simplifyRelationshipFields.ts#L33-L48
Reproduction Steps
createtool's input schemaiconfield will show{ "type": "null" }instead of accepting a string/number IDicon: 1(a valid media ID) fails with a validation errorSuggested fix
When stripping
$refoptions, inject a replacement that accepts relationship IDs:Which area(s) are affected?
plugin: mcp
Environment Info