@@ -2,9 +2,10 @@ import type { JSONRPCMessage } from '@modelcontextprotocol/core';
22import { InMemoryTransport , isStandardSchema , LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/core' ;
33import { describe , expect , expectTypeOf , it , vi } from 'vitest' ;
44import * as z from 'zod/v4' ;
5+
56import { McpServer } from '../../src/index.js' ;
6- import type { InferRawShape } from '../../src/server/mcp.js' ;
77import { completable } from '../../src/server/completable.js' ;
8+ import type { InferRawShape } from '../../src/server/mcp.js' ;
89
910describe ( 'registerTool/registerPrompt accept raw Zod shape (auto-wrapped)' , ( ) => {
1011 it ( 'registerTool accepts a raw shape for inputSchema and auto-wraps it' , ( ) => {
@@ -119,6 +120,55 @@ describe('registerTool/registerPrompt accept raw Zod shape (auto-wrapped)', () =
119120
120121 await server . close ( ) ;
121122 } ) ;
123+
124+ it ( 'returns a protocol error for invalid tool arguments' , async ( ) => {
125+ const server = new McpServer ( { name : 't' , version : '1.0.0' } ) ;
126+
127+ const handler = vi . fn ( async ( ) => ( {
128+ content : [ { type : 'text' as const , text : 'should not run' } ]
129+ } ) ) ;
130+ server . registerTool ( 'echo' , { inputSchema : { x : z . number ( ) } } , handler ) ;
131+
132+ const [ client , srv ] = InMemoryTransport . createLinkedPair ( ) ;
133+ await server . connect ( srv ) ;
134+ await client . start ( ) ;
135+
136+ const responses : JSONRPCMessage [ ] = [ ] ;
137+ client . onmessage = m => responses . push ( m ) ;
138+
139+ await client . send ( {
140+ jsonrpc : '2.0' ,
141+ id : 1 ,
142+ method : 'initialize' ,
143+ params : {
144+ protocolVersion : LATEST_PROTOCOL_VERSION ,
145+ capabilities : { } ,
146+ clientInfo : { name : 'c' , version : '1.0.0' }
147+ }
148+ } as JSONRPCMessage ) ;
149+ await client . send ( { jsonrpc : '2.0' , method : 'notifications/initialized' } as JSONRPCMessage ) ;
150+ await client . send ( {
151+ jsonrpc : '2.0' ,
152+ id : 2 ,
153+ method : 'tools/call' ,
154+ params : { name : 'echo' , arguments : { x : 'not-a-number' } }
155+ } as JSONRPCMessage ) ;
156+
157+ await vi . waitFor ( ( ) => expect ( responses . some ( r => 'id' in r && r . id === 2 ) ) . toBe ( true ) ) ;
158+
159+ expect ( handler ) . not . toHaveBeenCalled ( ) ;
160+ const response = responses . find ( r => 'id' in r && r . id === 2 ) as {
161+ error ?: { code : number ; message : string } ;
162+ result ?: unknown ;
163+ } ;
164+ expect ( response . result ) . toBeUndefined ( ) ;
165+ expect ( response . error ) . toMatchObject ( {
166+ code : - 32_602 ,
167+ message : expect . stringContaining ( 'Invalid arguments for tool echo' )
168+ } ) ;
169+
170+ await server . close ( ) ;
171+ } ) ;
122172} ) ;
123173
124174describe ( 'InferRawShape' , ( ) => {
0 commit comments