@@ -1470,6 +1470,131 @@ describe('@payloadcms/plugin-mcp', () => {
14701470 } )
14711471 } )
14721472
1473+ describe ( 'Virtual Fields' , ( ) => {
1474+ it ( 'should not include virtual fields in createPosts tool schema' , async ( ) => {
1475+ const apiKey = await getApiKey ( true )
1476+ const response = await restClient . POST ( '/mcp' , {
1477+ body : JSON . stringify ( {
1478+ id : 1 ,
1479+ jsonrpc : '2.0' ,
1480+ method : 'tools/list' ,
1481+ params : { } ,
1482+ } ) ,
1483+ headers : {
1484+ Accept : 'application/json, text/event-stream' ,
1485+ Authorization : `Bearer ${ apiKey } ` ,
1486+ 'Content-Type' : 'application/json' ,
1487+ } ,
1488+ } )
1489+
1490+ const json = await parseStreamResponse ( response )
1491+
1492+ const createTool = json . result . tools . find ( ( t : any ) => t . name === 'createPosts' )
1493+ expect ( createTool ) . toBeDefined ( )
1494+ expect ( createTool . inputSchema . properties . computedTitle ) . toBeUndefined ( )
1495+ } )
1496+
1497+ it ( 'should not include virtual fields in updatePosts tool schema' , async ( ) => {
1498+ const apiKey = await getApiKey ( true )
1499+ const response = await restClient . POST ( '/mcp' , {
1500+ body : JSON . stringify ( {
1501+ id : 1 ,
1502+ jsonrpc : '2.0' ,
1503+ method : 'tools/list' ,
1504+ params : { } ,
1505+ } ) ,
1506+ headers : {
1507+ Accept : 'application/json, text/event-stream' ,
1508+ Authorization : `Bearer ${ apiKey } ` ,
1509+ 'Content-Type' : 'application/json' ,
1510+ } ,
1511+ } )
1512+
1513+ const json = await parseStreamResponse ( response )
1514+
1515+ const updateTool = json . result . tools . find ( ( t : any ) => t . name === 'updatePosts' )
1516+ expect ( updateTool ) . toBeDefined ( )
1517+ expect ( updateTool . inputSchema . properties . computedTitle ) . toBeUndefined ( )
1518+ } )
1519+
1520+ it ( 'should ignore virtual fields when creating a post via MCP' , async ( ) => {
1521+ const apiKey = await getApiKey ( )
1522+ const response = await restClient . POST ( '/mcp' , {
1523+ body : JSON . stringify ( {
1524+ id : 1 ,
1525+ jsonrpc : '2.0' ,
1526+ method : 'tools/call' ,
1527+ params : {
1528+ name : 'createPosts' ,
1529+ arguments : {
1530+ title : 'Virtual Field Create Test' ,
1531+ content : 'Testing virtual field exclusion on create' ,
1532+ } ,
1533+ } ,
1534+ } ) ,
1535+ headers : {
1536+ Accept : 'application/json, text/event-stream' ,
1537+ Authorization : `Bearer ${ apiKey } ` ,
1538+ 'Content-Type' : 'application/json' ,
1539+ } ,
1540+ } )
1541+
1542+ const json = await parseStreamResponse ( response )
1543+
1544+ expect ( json . result ) . toBeDefined ( )
1545+ expect ( json . result . content [ 0 ] . text ) . toContain (
1546+ 'Resource created successfully in collection "posts"!' ,
1547+ )
1548+ expect ( json . result . content [ 0 ] . text ) . toContain ( '"title": "Virtual Field Create Test"' )
1549+ expect ( json . result . content [ 0 ] . text ) . not . toContain ( '"computedTitle"' )
1550+
1551+ // Clean up
1552+ const createdId = JSON . parse (
1553+ json . result . content [ 0 ] . text . match ( / ` ` ` j s o n \n ( [ \s \S ] * ?) \n ` ` ` / ) ?. [ 1 ] || '{}' ,
1554+ ) . id
1555+ if ( createdId ) {
1556+ await payload . delete ( { id : createdId , collection : 'posts' } )
1557+ }
1558+ } )
1559+
1560+ it ( 'should ignore virtual fields when updating a post via MCP' , async ( ) => {
1561+ const post = await payload . create ( {
1562+ collection : 'posts' ,
1563+ data : { title : 'Virtual Field Update Test' } ,
1564+ } )
1565+
1566+ const apiKey = await getApiKey ( true , false )
1567+ const response = await restClient . POST ( '/mcp' , {
1568+ body : JSON . stringify ( {
1569+ id : 1 ,
1570+ jsonrpc : '2.0' ,
1571+ method : 'tools/call' ,
1572+ params : {
1573+ name : 'updatePosts' ,
1574+ arguments : {
1575+ id : post . id ,
1576+ title : 'Virtual Field Updated Title' ,
1577+ } ,
1578+ } ,
1579+ } ) ,
1580+ headers : {
1581+ Accept : 'application/json, text/event-stream' ,
1582+ Authorization : `Bearer ${ apiKey } ` ,
1583+ 'Content-Type' : 'application/json' ,
1584+ } ,
1585+ } )
1586+
1587+ const json = await parseStreamResponse ( response )
1588+
1589+ expect ( json . result ) . toBeDefined ( )
1590+ expect ( json . result . content [ 0 ] . text ) . toContain ( 'Document updated successfully' )
1591+ expect ( json . result . content [ 0 ] . text ) . toContain ( '"title": "Virtual Field Updated Title"' )
1592+ expect ( json . result . content [ 0 ] . text ) . not . toContain ( '"computedTitle"' )
1593+
1594+ await payload . delete ( { id : post . id , collection : 'posts' } )
1595+ } )
1596+ } )
1597+
14731598 describe ( 'payloadAPI context' , ( ) => {
14741599 it ( 'should call operations with the payloadAPI context as MCP' , async ( ) => {
14751600 await payload . create ( {
0 commit comments