diff --git a/README.md b/README.md index d95f6e5..97b320f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Appwrite MCP server -mcp-name: io.github.appwrite/mcp +[![MCP Registry Version](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fregistry.modelcontextprotocol.io%2Fv0.1%2Fservers%2Fio.github.appwrite%252Fmcp%2Fversions%2Flatest&query=%24.server.version&label=MCP%20Registry&logo=modelcontextprotocol)](https://registry.modelcontextprotocol.io/?q=io.github.appwrite%2Fmcp) A [Model Context Protocol](https://modelcontextprotocol.io) server for Appwrite. It exposes Appwrite's API — databases, users, functions, teams, storage, and more diff --git a/pyproject.toml b/pyproject.toml index bcbf4ed..600594c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ dependencies = [ "anyio>=4.0.0", "appwrite>=21.0.0,<22", "docstring-parser>=0.16", - "mcp[cli]>=1.12.0", + "mcp[cli]>=1.12.0,<2", "python-dotenv>=1.0.1", "starlette>=0.40.0", "uvicorn[standard]>=0.30.0", diff --git a/src/mcp_server_appwrite/constants.py b/src/mcp_server_appwrite/constants.py index 92c9109..0c437be 100644 --- a/src/mcp_server_appwrite/constants.py +++ b/src/mcp_server_appwrite/constants.py @@ -24,6 +24,8 @@ def _resolve_server_version() -> str: SERVER_VERSION = _resolve_server_version() +SERVER_WEBSITE_URL = "https://github.com/appwrite/mcp" +SERVER_ICON_URL = "https://mcp.appwrite.io/favicon.svg" DEFAULT_ENDPOINT = "https://cloud.appwrite.io/v1" # Region reported by single-region deployments; carries no region subdomain. diff --git a/src/mcp_server_appwrite/server.py b/src/mcp_server_appwrite/server.py index aa9fe6f..6163f78 100644 --- a/src/mcp_server_appwrite/server.py +++ b/src/mcp_server_appwrite/server.py @@ -53,7 +53,9 @@ HOSTED_PATH_GUIDANCE, MAX_FETCH_BYTES, MAX_INLINE_BYTES, + SERVER_ICON_URL, SERVER_VERSION, + SERVER_WEBSITE_URL, TRANSPORTS, VALIDATION_SERVICE_ORDER, ) @@ -966,7 +968,13 @@ def build_mcp_server(operator: Operator, *, transport: str = "http") -> Server: _configure_uploads(transport) instructions = build_instructions(transport) - server = Server("Appwrite MCP Server", instructions=instructions) + server = Server( + "Appwrite MCP Server", + version=SERVER_VERSION, + instructions=instructions, + website_url=SERVER_WEBSITE_URL, + icons=[types.Icon(src=SERVER_ICON_URL, mimeType="image/svg+xml")], + ) @server.list_tools() async def handle_list_tools() -> list[types.Tool]: diff --git a/tests/unit/test_server.py b/tests/unit/test_server.py index 28650d1..3369a47 100644 --- a/tests/unit/test_server.py +++ b/tests/unit/test_server.py @@ -28,6 +28,7 @@ build_client_for_request, build_instructions, build_introspection_client, + build_mcp_server, build_operator, execute_registered_tool, parse_args, @@ -116,6 +117,25 @@ def test_build_instructions_are_transport_specific(self): self.assertIn("Large results are stored as resources", stdio) self.assertIn("returns tool results inline", http) + def test_build_mcp_server_reports_appwrite_metadata(self): + server = build_mcp_server(Mock(), transport="stdio") + options = server.create_initialization_options() + + self.assertEqual(server.version, server_module.SERVER_VERSION) + self.assertEqual(options.website_url, server_module.SERVER_WEBSITE_URL) + self.assertEqual( + [ + icon.model_dump(by_alias=True, exclude_none=True) + for icon in options.icons + ], + [ + { + "src": server_module.SERVER_ICON_URL, + "mimeType": "image/svg+xml", + } + ], + ) + def test_http_tool_execution_does_not_block_event_loop(self): class BlockingOperator: def execute_public_tool(self, name, arguments): diff --git a/uv.lock b/uv.lock index 5cbe6d2..4ed9e6a 100644 --- a/uv.lock +++ b/uv.lock @@ -683,7 +683,7 @@ requires-dist = [ { name = "bcrypt", marker = "extra == 'integration'", specifier = ">=4.1.2" }, { name = "docstring-parser", specifier = ">=0.16" }, { name = "httpx", specifier = ">=0.27.0" }, - { name = "mcp", extras = ["cli"], specifier = ">=1.12.0" }, + { name = "mcp", extras = ["cli"], specifier = ">=1.12.0,<2" }, { name = "numpy", specifier = ">=2.0" }, { name = "openai", specifier = ">=1.40" }, { name = "opentelemetry-api", specifier = ">=1.27" },