Skip to main content
Glama

Skill Management MCP Server

by fkesheh
test_mcp_server.py•13.4 kB
"""Integration tests for MCP server.""" import pytest from unittest.mock import patch from skill_mcp.models import ( ListSkillsInput, GetSkillDetailsInput, ReadSkillFileInput, CreateSkillFileInput, UpdateSkillFileInput, DeleteSkillFileInput, RunSkillScriptInput, ReadSkillEnvInput, UpdateSkillEnvInput, ) from skill_mcp.tools.skill_tools import SkillTools from skill_mcp.tools.file_tools import FileTools from skill_mcp.tools.script_tools import ScriptTools @pytest.mark.asyncio async def test_list_skills_tool(sample_skill, temp_skills_dir): """Test list_skills tool.""" with patch("skill_mcp.services.skill_service.SKILLS_DIR", temp_skills_dir): result = await SkillTools.list_skills() assert len(result) > 0 text = result[0].text assert "test-skill" in text @pytest.mark.asyncio async def test_get_skill_details_tool(sample_skill, temp_skills_dir): """Test get_skill_details tool.""" with patch("skill_mcp.services.skill_service.SKILLS_DIR", temp_skills_dir): input_data = GetSkillDetailsInput(skill_name="test-skill") result = await SkillTools.get_skill_details(input_data) assert len(result) > 0 text = result[0].text assert "test-skill" in text assert "scripts" in text.lower() @pytest.mark.asyncio async def test_read_file_tool(sample_skill, temp_skills_dir): """Test read_skill_file tool.""" with patch("skill_mcp.services.file_service.SKILLS_DIR", temp_skills_dir): input_data = ReadSkillFileInput(skill_name="test-skill", file_path="SKILL.md") result = await FileTools.read_skill_file(input_data) assert len(result) > 0 text = result[0].text assert "test-skill" in text @pytest.mark.asyncio async def test_create_update_delete_file_flow(sample_skill, temp_skills_dir): """Test create, update, delete file flow.""" with patch("skill_mcp.services.file_service.SKILLS_DIR", temp_skills_dir): # Create create_input = CreateSkillFileInput( skill_name="test-skill", file_path="test.txt", content="initial" ) result = await FileTools.create_skill_file(create_input) assert "Successfully created" in result[0].text # Read read_input = ReadSkillFileInput(skill_name="test-skill", file_path="test.txt") result = await FileTools.read_skill_file(read_input) assert "initial" in result[0].text # Update update_input = UpdateSkillFileInput( skill_name="test-skill", file_path="test.txt", content="updated" ) result = await FileTools.update_skill_file(update_input) assert "Successfully updated" in result[0].text # Read again result = await FileTools.read_skill_file(read_input) assert "updated" in result[0].text # Delete delete_input = DeleteSkillFileInput( skill_name="test-skill", file_path="test.txt" ) result = await FileTools.delete_skill_file(delete_input) assert "Successfully deleted" in result[0].text @pytest.mark.asyncio async def test_read_nonexistent_file(temp_skills_dir): """Test reading a nonexistent file.""" with patch("skill_mcp.services.file_service.SKILLS_DIR", temp_skills_dir): read_input = ReadSkillFileInput(skill_name="test-skill", file_path="nonexistent.txt") result = await FileTools.read_skill_file(read_input) assert "Error" in result[0].text @pytest.mark.asyncio async def test_create_file_in_nested_dir(sample_skill, temp_skills_dir): """Test creating a file in a nested directory.""" import time with patch("skill_mcp.services.file_service.SKILLS_DIR", temp_skills_dir): # Use timestamp for unique filename unique_name = f"nested_file_{int(time.time() * 1000000)}.md" create_input = CreateSkillFileInput( skill_name="test-skill", file_path=f"docs/nested/{unique_name}", content="nested file" ) result = await FileTools.create_skill_file(create_input) assert "Successfully created" in result[0].text # Verify we can read it read_input = ReadSkillFileInput(skill_name="test-skill", file_path=f"docs/nested/{unique_name}") result = await FileTools.read_skill_file(read_input) assert "nested file" in result[0].text @pytest.mark.asyncio async def test_update_nonexistent_file(sample_skill, temp_skills_dir): """Test updating a nonexistent file.""" with patch("skill_mcp.services.file_service.SKILLS_DIR", temp_skills_dir): update_input = UpdateSkillFileInput( skill_name="test-skill", file_path="nonexistent.txt", content="content" ) result = await FileTools.update_skill_file(update_input) assert "Error" in result[0].text @pytest.mark.asyncio async def test_delete_nonexistent_file(sample_skill, temp_skills_dir): """Test deleting a nonexistent file.""" with patch("skill_mcp.services.file_service.SKILLS_DIR", temp_skills_dir): delete_input = DeleteSkillFileInput( skill_name="test-skill", file_path="nonexistent.txt" ) result = await FileTools.delete_skill_file(delete_input) assert "Error" in result[0].text @pytest.mark.asyncio async def test_create_file_with_large_content(sample_skill, temp_skills_dir): """Test creating a file with large content.""" import time with patch("skill_mcp.services.file_service.SKILLS_DIR", temp_skills_dir): large_content = "x" * 10000 # Use timestamp for unique filename unique_name = f"large_{int(time.time() * 1000000)}.txt" create_input = CreateSkillFileInput( skill_name="test-skill", file_path=unique_name, content=large_content ) result = await FileTools.create_skill_file(create_input) assert "10000 characters" in result[0].text @pytest.mark.asyncio async def test_run_skill_script(sample_skill, temp_skills_dir): """Test run_skill_script tool with invalid script.""" with patch("skill_mcp.services.script_service.SKILLS_DIR", temp_skills_dir): input_data = RunSkillScriptInput( skill_name="test-skill", script_path="scripts/nonexistent.py" ) result = await ScriptTools.run_skill_script(input_data) assert len(result) > 0 # Should handle error gracefully assert "Error" in result[0].text or "does not exist" in result[0].text @pytest.mark.asyncio async def test_run_shell_script_tool_error(sample_skill, temp_skills_dir): """Test running a shell script through tools with error.""" with patch("skill_mcp.services.script_service.SKILLS_DIR", temp_skills_dir): input_data = RunSkillScriptInput( skill_name="test-skill", script_path="scripts/nonexistent.sh" ) result = await ScriptTools.run_skill_script(input_data) assert len(result) > 0 assert "Error" in result[0].text or "does not exist" in result[0].text @pytest.mark.asyncio async def test_run_script_with_args_error(sample_skill, temp_skills_dir): """Test running script with arguments but script doesn't exist.""" with patch("skill_mcp.services.script_service.SKILLS_DIR", temp_skills_dir): input_data = RunSkillScriptInput( skill_name="test-skill", script_path="scripts/nonexistent.py", args=["arg1", "arg2"] ) result = await ScriptTools.run_skill_script(input_data) assert len(result) > 0 assert "Error" in result[0].text or "does not exist" in result[0].text @pytest.mark.asyncio async def test_read_skill_env(skill_with_env, temp_skills_dir): """Test read_skill_env tool.""" with patch("skill_mcp.services.env_service.SKILLS_DIR", temp_skills_dir): input_data = ReadSkillEnvInput(skill_name="test-skill") result = await ScriptTools.read_skill_env(input_data) assert len(result) > 0 text = result[0].text assert "API_KEY" in text assert "DATABASE_URL" in text @pytest.mark.asyncio async def test_read_skill_env_empty(sample_skill, temp_skills_dir): """Test read_skill_env with no environment variables.""" with patch("skill_mcp.services.env_service.SKILLS_DIR", temp_skills_dir): input_data = ReadSkillEnvInput(skill_name="test-skill") result = await ScriptTools.read_skill_env(input_data) assert len(result) > 0 text = result[0].text assert "No environment variables" in text @pytest.mark.asyncio async def test_update_skill_env(sample_skill, temp_skills_dir): """Test update_skill_env tool.""" with patch("skill_mcp.services.env_service.SKILLS_DIR", temp_skills_dir): input_data = UpdateSkillEnvInput( skill_name="test-skill", content="NEW_VAR=value\nANOTHER=test" ) result = await ScriptTools.update_skill_env(input_data) assert "Successfully updated" in result[0].text # Verify it was updated read_input = ReadSkillEnvInput(skill_name="test-skill") read_result = await ScriptTools.read_skill_env(read_input) assert "NEW_VAR" in read_result[0].text @pytest.mark.asyncio async def test_get_script_tools_list(): """Test get_script_tools returns all tools.""" tools = ScriptTools.get_script_tools() assert len(tools) == 3 tool_names = [t.name for t in tools] assert "run_skill_script" in tool_names assert "read_skill_env" in tool_names assert "update_skill_env" in tool_names @pytest.mark.asyncio async def test_server_list_tools(): """Test MCP server list_tools endpoint.""" from skill_mcp.server import list_tools tools = await list_tools() assert len(tools) > 0 tool_names = [t.name for t in tools] # Check all expected tools are present assert "list_skills" in tool_names assert "get_skill_details" in tool_names assert "read_skill_file" in tool_names assert "create_skill_file" in tool_names assert "update_skill_file" in tool_names assert "delete_skill_file" in tool_names assert "run_skill_script" in tool_names assert "read_skill_env" in tool_names assert "update_skill_env" in tool_names @pytest.mark.asyncio async def test_server_list_skills_tool(sample_skill, temp_skills_dir): """Test server call_tool for list_skills.""" from skill_mcp.server import call_tool with patch("skill_mcp.services.skill_service.SKILLS_DIR", temp_skills_dir): result = await call_tool("list_skills", {}) assert len(result) > 0 assert "test-skill" in result[0].text @pytest.mark.asyncio async def test_server_get_skill_details_tool(sample_skill, temp_skills_dir): """Test server call_tool for get_skill_details.""" from skill_mcp.server import call_tool with patch("skill_mcp.services.skill_service.SKILLS_DIR", temp_skills_dir): result = await call_tool("get_skill_details", {"skill_name": "test-skill"}) assert len(result) > 0 assert "test-skill" in result[0].text @pytest.mark.asyncio async def test_server_read_skill_file_tool(sample_skill, temp_skills_dir): """Test server call_tool for read_skill_file.""" from skill_mcp.server import call_tool with patch("skill_mcp.services.file_service.SKILLS_DIR", temp_skills_dir): result = await call_tool( "read_skill_file", {"skill_name": "test-skill", "file_path": "SKILL.md"} ) assert len(result) > 0 assert "test-skill" in result[0].text @pytest.mark.asyncio async def test_server_unknown_tool(): """Test server call_tool with unknown tool.""" from skill_mcp.server import call_tool result = await call_tool("unknown_tool", {}) assert "Unknown tool" in result[0].text @pytest.mark.asyncio async def test_server_call_tool_with_exception(): """Test server call_tool handles exceptions.""" from skill_mcp.server import call_tool # Call a tool with invalid arguments should be handled gracefully result = await call_tool("list_skills", {"invalid_arg": "value"}) # Should return a result (might succeed if extra args are ignored, or error) assert len(result) > 0 assert isinstance(result[0].text, str) @pytest.mark.asyncio async def test_get_file_tools_list(): """Test get_file_tools returns all tools.""" tools = FileTools.get_file_tools() assert len(tools) == 4 tool_names = [t.name for t in tools] assert "read_skill_file" in tool_names assert "create_skill_file" in tool_names assert "update_skill_file" in tool_names assert "delete_skill_file" in tool_names @pytest.mark.asyncio async def test_get_skill_tools_list(): """Test get_skill_tools returns all tools.""" tools = SkillTools.get_list_tools() assert len(tools) == 2 tool_names = [t.name for t in tools] assert "list_skills" in tool_names assert "get_skill_details" in tool_names

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/fkesheh/skill-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server