@@ -324,38 +324,38 @@ async def test_tool_audio_helper(self, tmp_path: Path):
324
324
# Check structured content - Image return type should NOT have structured output
325
325
assert result .structuredContent is None
326
326
327
- @pytest .mark .anyio
328
- async def test_tool_audio_suffix_detection (self , tmp_path : Path ):
329
- # Test different audio file extensions
330
- test_cases = [
327
+ @pytest .mark .parametrize (
328
+ "filename,expected_mime_type" ,
329
+ [
331
330
("test.wav" , "audio/wav" ),
332
331
("test.mp3" , "audio/mpeg" ),
333
332
("test.ogg" , "audio/ogg" ),
334
333
("test.flac" , "audio/flac" ),
335
334
("test.aac" , "audio/aac" ),
336
335
("test.m4a" , "audio/mp4" ),
337
336
("test.unknown" , "application/octet-stream" ), # Unknown extension fallback
338
- ]
339
-
337
+ ],
338
+ )
339
+ @pytest .mark .anyio
340
+ async def test_tool_audio_suffix_detection (self , tmp_path : Path , filename : str , expected_mime_type : str ):
341
+ """Test that Audio helper correctly detects MIME types from file suffixes"""
340
342
mcp = FastMCP ()
341
343
mcp .add_tool (audio_tool_fn )
342
- async with client_session (mcp ._mcp_server ) as client :
343
- for filename , expected_mime_type in test_cases :
344
- # Create a test audio file with the specific extension
345
- audio_path = tmp_path / filename
346
- audio_path .write_bytes (b"fake audio data" )
344
+
345
+ # Create a test audio file with the specific extension
346
+ audio_path = tmp_path / filename
347
+ audio_path .write_bytes (b"fake audio data" )
347
348
348
- result = await client .call_tool ("audio_tool_fn" , {"path" : str (audio_path )})
349
- assert len (result .content ) == 1
350
- content = result .content [0 ]
351
- assert isinstance (content , AudioContent )
352
- assert content .type == "audio"
353
- assert content .mimeType == expected_mime_type , (
354
- f"Expected { expected_mime_type } for { filename } , got { content .mimeType } "
355
- )
356
- # Verify base64 encoding
357
- decoded = base64 .b64decode (content .data )
358
- assert decoded == b"fake audio data"
349
+ async with client_session (mcp ._mcp_server ) as client :
350
+ result = await client .call_tool ("audio_tool_fn" , {"path" : str (audio_path )})
351
+ assert len (result .content ) == 1
352
+ content = result .content [0 ]
353
+ assert isinstance (content , AudioContent )
354
+ assert content .type == "audio"
355
+ assert content .mimeType == expected_mime_type
356
+ # Verify base64 encoding
357
+ decoded = base64 .b64decode (content .data )
358
+ assert decoded == b"fake audio data"
359
359
360
360
@pytest .mark .anyio
361
361
async def test_tool_mixed_content (self ):
@@ -389,17 +389,22 @@ async def test_tool_mixed_content(self):
389
389
assert structured_result [i ][key ] == value
390
390
391
391
@pytest .mark .anyio
392
- async def test_tool_mixed_list_with_image (self , tmp_path : Path ):
392
+ async def test_tool_mixed_list_with_audio_and_image (self , tmp_path : Path ):
393
393
"""Test that lists containing Image objects and other types are handled
394
394
correctly"""
395
395
# Create a test image
396
396
image_path = tmp_path / "test.png"
397
397
image_path .write_bytes (b"test image data" )
398
398
399
+ # Create a test audio
400
+ audio_path = tmp_path / "test.wav"
401
+ audio_path .write_bytes (b"test audio data" )
402
+
399
403
def mixed_list_fn () -> list :
400
404
return [
401
405
"text message" ,
402
406
Image (image_path ),
407
+ Audio (audio_path ),
403
408
{"key" : "value" },
404
409
TextContent (type = "text" , text = "direct content" ),
405
410
]
@@ -418,56 +423,20 @@ def mixed_list_fn() -> list:
418
423
assert isinstance (content2 , ImageContent )
419
424
assert content2 .mimeType == "image/png"
420
425
assert base64 .b64decode (content2 .data ) == b"test image data"
421
- # Check dict conversion
422
- content3 = result .content [2 ]
423
- assert isinstance (content3 , TextContent )
424
- assert '"key": "value"' in content3 .text
425
- # Check direct TextContent
426
- content4 = result .content [3 ]
427
- assert isinstance (content4 , TextContent )
428
- assert content4 .text == "direct content"
429
- # Check structured content - untyped list with Image objects should NOT have structured output
430
- assert result .structuredContent is None
431
-
432
- @pytest .mark .anyio
433
- async def test_tool_mixed_list_with_audio (self , tmp_path : Path ):
434
- """Test that lists containing Audio objects and other types are handled
435
- correctly"""
436
- # Create a test audio
437
- audio_path = tmp_path / "test.wav"
438
- audio_path .write_bytes (b"test audio data" )
439
-
440
- def mixed_list_fn () -> list :
441
- return [
442
- "text message" ,
443
- Audio (audio_path ),
444
- {"key" : "value" },
445
- TextContent (type = "text" , text = "direct content" ),
446
- ]
447
-
448
- mcp = FastMCP ()
449
- mcp .add_tool (mixed_list_fn )
450
- async with client_session (mcp ._mcp_server ) as client :
451
- result = await client .call_tool ("mixed_list_fn" , {})
452
- assert len (result .content ) == 4
453
- # Check text conversion
454
- content1 = result .content [0 ]
455
- assert isinstance (content1 , TextContent )
456
- assert content1 .text == "text message"
457
426
# Check audio conversion
458
- content2 = result .content [1 ]
459
- assert isinstance (content2 , AudioContent )
460
- assert content2 .mimeType == "audio/wav"
461
- assert base64 .b64decode (content2 .data ) == b"test audio data"
462
- # Check dict conversion
463
427
content3 = result .content [2 ]
464
- assert isinstance (content3 , TextContent )
465
- assert '"key": "value"' in content3 .text
466
- # Check direct TextContent
428
+ assert isinstance (content3 , AudioContent )
429
+ assert content3 .mimeType == "audio/wav"
430
+ assert base64 .b64decode (content3 .data ) == b"test audio data"
431
+ # Check dict conversion
467
432
content4 = result .content [3 ]
468
433
assert isinstance (content4 , TextContent )
469
- assert content4 .text == "direct content"
470
- # Check structured content - untyped list with Audio objects should NOT have structured output
434
+ assert '"key": "value"' in content4 .text
435
+ # Check direct TextContent
436
+ content5 = result .content [4 ]
437
+ assert isinstance (content5 , TextContent )
438
+ assert content5 .text == "direct content"
439
+ # Check structured content - untyped list with Image objects should NOT have structured output
471
440
assert result .structuredContent is None
472
441
473
442
@pytest .mark .anyio
0 commit comments