import logging from pathlib import Path import pytest from pydantic import AnyUrl from mcp.server.mcpserver import Context from mcp.server.mcpserver.exceptions import ResourceNotFoundError from mcp.server.mcpserver.resources import FileResource, FunctionResource, ResourceManager, ResourceTemplate @pytest.fixture() def temp_file(tmp_path: Path): """Create a temporary file for testing. File is automatically cleaned up after the test if it still exists. """ tmp_file = tmp_path / "file" tmp_file.touch() yield tmp_file def test_init_with_resources(temp_file: Path, caplog: pytest.LogCaptureFixture): resource = FileResource(uri=f"file://{temp_file}", name="test", path=temp_file) manager = ResourceManager(resources=[resource]) assert manager.list_resources() == [resource] duplicate_resource = FileResource(uri=f"file://{temp_file}", name="duplicate", path=temp_file) with caplog.at_level(logging.WARNING): manager = ResourceManager(True, resources=[resource, duplicate_resource]) assert "Resource already exists" in caplog.text assert manager.list_resources() == [resource] def test_add_resource(temp_file: Path): """Test adding a resource.""" manager = ResourceManager() resource = FileResource(uri=f"file://{temp_file}", name="test", path=temp_file) added = manager.add_resource(resource) assert added == resource assert manager.list_resources() == [resource] def test_add_duplicate_resource(temp_file: Path): """Test adding the same resource twice.""" manager = ResourceManager() resource = FileResource(uri=f"file://{temp_file}", name="test", path=temp_file) first = manager.add_resource(resource) second = manager.add_resource(resource) assert first == second assert manager.list_resources() == [resource] def test_warn_on_duplicate_resources(temp_file: Path, caplog: pytest.LogCaptureFixture): """Test warning on duplicate resources.""" manager = ResourceManager() resource = FileResource(uri=f"file://{temp_file}", name="test", path=temp_file) manager.add_resource(resource) manager.add_resource(resource) assert "Resource already exists" in caplog.text def test_disable_warn_on_duplicate_resources(temp_file: Path, caplog: pytest.LogCaptureFixture): """Test disabling warning on duplicate resources.""" manager = ResourceManager(warn_on_duplicate_resources=False) resource = FileResource(uri=f"file://{temp_file}", name="test", path=temp_file) manager.add_resource(resource) manager.add_resource(resource) assert "Resource already exists" not in caplog.text @pytest.mark.anyio async def test_get_resource(temp_file: Path): """Test getting a resource by URI.""" manager = ResourceManager() resource = FileResource(uri=f"file://{temp_file}", name="test", path=temp_file) manager.add_resource(resource) retrieved = await manager.get_resource(resource.uri, Context()) assert retrieved == resource @pytest.mark.anyio async def test_get_resource_from_template(): """Test getting a resource through a template.""" manager = ResourceManager() def greet(name: str) -> str: return f"Hello, {name}!" template = ResourceTemplate.from_function(fn=greet, uri_template="greet://{name}", name="greeter") manager._templates[template.uri_template] = template resource = await manager.get_resource(AnyUrl("greet://world"), Context()) assert isinstance(resource, FunctionResource) content = await resource.read() assert content == "Hello, world!" @pytest.mark.anyio async def test_get_unknown_resource(): """Test getting a non-existent resource.""" manager = ResourceManager() with pytest.raises(ResourceNotFoundError, match="Unknown resource"): await manager.get_resource(AnyUrl("unknown://test"), Context()) def test_list_resources(temp_file: Path): """Test listing all resources.""" manager = ResourceManager() resource1 = FileResource(uri=f"file://{temp_file}", name="test1", path=temp_file) resource2 = FileResource(uri=f"file://{temp_file}2", name="test2", path=temp_file) manager.add_resource(resource1) manager.add_resource(resource2) resources = manager.list_resources() assert len(resources) == 2 assert resources == [resource1, resource2] def get_item(id: str) -> str: ... def test_add_template_with_metadata(): """Test that ResourceManager.add_template() accepts and passes meta parameter.""" manager = ResourceManager() metadata = {"source": "database", "cached": True} template = manager.add_template(fn=get_item, uri_template="resource://items/{id}", meta=metadata) assert template.meta is not None assert template.meta == metadata assert template.meta["source"] == "database" assert template.meta["cached"] is True def test_add_template_without_metadata(): """Test that ResourceManager.add_template() works without meta parameter.""" manager = ResourceManager() template = manager.add_template(fn=get_item, uri_template="resource://items/{id}") assert template.meta is None