1
1
import shutil
2
2
import sys
3
+ import textwrap
3
4
import time
4
5
6
+ import anyio
5
7
import pytest
6
8
7
9
from mcp .client .session import ClientSession
@@ -178,3 +180,67 @@ async def test_stdio_client_immediate_completion():
178
180
elapsed = end_time - start_time
179
181
print (f"❌ Test failed after { elapsed :.1f} seconds: { e } " )
180
182
raise
183
+
184
+
185
+ @pytest .mark .anyio
186
+ @pytest .mark .skipif (sys .platform == "win32" , reason = "Windows signal handling is different" )
187
+ async def test_stdio_client_sigint_only_process ():
188
+ """
189
+ Test cleanup with a process that ignores SIGTERM but responds to SIGINT.
190
+
191
+ This tests Cristipufu's concern: processes that expect SIGINT (like many
192
+ Node.js servers or interactive tools) may not respond to SIGTERM, causing
193
+ hanging during cleanup.
194
+ """
195
+ # Create a Python script that ignores SIGTERM but handles SIGINT
196
+ script_content = textwrap .dedent (
197
+ """
198
+ import signal
199
+ import sys
200
+ import time
201
+
202
+ # Ignore SIGTERM (what process.terminate() sends)
203
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
204
+
205
+ # Handle SIGINT (Ctrl+C signal) by exiting cleanly
206
+ def sigint_handler(signum, frame):
207
+ sys.exit(0)
208
+
209
+ signal.signal(signal.SIGINT, sigint_handler)
210
+
211
+ # Keep running until SIGINT received
212
+ while True:
213
+ time.sleep(0.1)
214
+ """
215
+ )
216
+
217
+ server_params = StdioServerParameters (
218
+ command = "python" ,
219
+ args = ["-c" , script_content ],
220
+ )
221
+
222
+ start_time = time .time ()
223
+
224
+ try :
225
+ # Use anyio timeout to prevent test from hanging forever
226
+ with anyio .fail_after (5.0 ):
227
+ async with stdio_client (server_params ) as (read_stream , write_stream ):
228
+ # Let the process start and begin ignoring SIGTERM
229
+ await anyio .sleep (0.5 )
230
+ # Exit context triggers cleanup - this should not hang
231
+ pass
232
+
233
+ end_time = time .time ()
234
+ elapsed = end_time - start_time
235
+
236
+ # Should complete quickly even with SIGTERM-ignoring process
237
+ # This will fail if cleanup only uses process.terminate() without fallback
238
+ assert elapsed < 5.0 , (
239
+ f"stdio_client cleanup took { elapsed :.1f} seconds with SIGTERM-ignoring process. "
240
+ f"Expected < 5.0 seconds. This suggests the cleanup needs SIGINT/SIGKILL fallback."
241
+ )
242
+ except TimeoutError :
243
+ pytest .fail (
244
+ "stdio_client cleanup timed out after 5.0 seconds with SIGTERM-ignoring process. "
245
+ "This confirms the cleanup needs SIGINT/SIGKILL fallback for processes that ignore SIGTERM."
246
+ )
0 commit comments