|
54 | 54 | pytestmark = pytest.mark.anyio |
55 | 55 |
|
56 | 56 | CATALOG_LOGGER = "mcp.server.skills.catalog" |
| 57 | +SERVER_LOGGER = "mcp.server.mcpserver.server" |
57 | 58 |
|
58 | 59 |
|
59 | 60 | class _RawResult(BaseModel): |
@@ -484,6 +485,31 @@ async def test_reading_a_file_that_changed_after_load_is_an_internal_error() -> |
484 | 485 | with pytest.raises(MCPError) as exc_info: |
485 | 486 | await client.read_resource("skill://git-workflow/SKILL.md") |
486 | 487 | assert exc_info.value.code == INTERNAL_ERROR |
| 488 | + assert exc_info.value.message == "skill://git-workflow/SKILL.md changed after the last scan" |
| 489 | + |
| 490 | + |
| 491 | +async def test_reading_a_file_deleted_after_load_is_an_internal_error_without_a_traceback( |
| 492 | + tmp_path: Path, caplog: pytest.LogCaptureFixture |
| 493 | +) -> None: |
| 494 | + """SDK-defined: a file removed before the next reload is an expected state, logged as a failed read, not a crash.""" |
| 495 | + (tmp_path / "git-workflow").mkdir() |
| 496 | + (tmp_path / "git-workflow" / "SKILL.md").write_bytes(_skill_md("git-workflow")) |
| 497 | + (tmp_path / "git-workflow" / "guide.md").write_bytes(b"# Guide\n") |
| 498 | + catalog = await SkillCatalog.load(FilesystemSkillProvider(tmp_path), parse_frontmatter=_parse) |
| 499 | + (tmp_path / "git-workflow" / "guide.md").unlink() |
| 500 | + |
| 501 | + with caplog.at_level(logging.INFO, logger=SERVER_LOGGER): |
| 502 | + async with Client(MCPServer("skills", extensions=[catalog])) as client: |
| 503 | + with pytest.raises(MCPError) as exc_info: |
| 504 | + await client.read_resource("skill://git-workflow/guide.md") |
| 505 | + |
| 506 | + assert exc_info.value.code == INTERNAL_ERROR |
| 507 | + assert ( |
| 508 | + exc_info.value.message |
| 509 | + == "skill://git-workflow/guide.md could not be read; it was deleted or became unreadable after the last scan" |
| 510 | + ) |
| 511 | + records = [record for record in caplog.records if record.name == SERVER_LOGGER] |
| 512 | + assert [(record.levelno, record.exc_info) for record in records] == [(logging.INFO, None)] |
487 | 513 |
|
488 | 514 |
|
489 | 515 | async def test_reading_a_uri_outside_the_catalog_is_invalid_params() -> None: |
|
0 commit comments