diff --git a/docs/appwrite-mcp-flow.svg b/docs/appwrite-mcp-flow.svg
index 2f2e26f..bf83bf2 100644
--- a/docs/appwrite-mcp-flow.svg
+++ b/docs/appwrite-mcp-flow.svg
@@ -115,7 +115,7 @@
search_docs
- hosted catalog · 40 services · 1007 tools
+ hosted catalog · 41 services · 1016 tools
writes need confirm_write: true
diff --git a/docs/tool-surface.md b/docs/tool-surface.md
index a9e2a27..ec930e7 100644
--- a/docs/tool-surface.md
+++ b/docs/tool-surface.md
@@ -20,7 +20,7 @@ flowchart LR
subgraph CAT[Internal catalog — authentication-aware]
direction LR
- K[OAuth: 40 services / 1007 tools
API key: 26 services / 663 tools]
+ K[OAuth: 41 services / 1016 tools
API key: 26 services / 663 tools]
end
CT -->|large output| R[(MCP resource
preview + URI)]
@@ -47,8 +47,8 @@ flowchart LR
`context=organization`, or `context=project`. Hosted calls enforce the required
top-level `organization_id` or `project_id` before making a request.
- **Access** is still gated per-route by the scopes granted to the OAuth token.
-- **Hosted OAuth** registers all 40 services and 1007 methods shipped by
- `appwrite-console` 0.7.0. This adds console control-plane services including
+- **Hosted OAuth** registers all 41 services and 1016 methods shipped by
+ `appwrite-console` 0.8.1. This adds console control-plane services including
projects, organizations, domains, migrations, dedicated databases, usage, VCS,
vectors, WAF, notifications, and regions.
- **API-key stdio** deliberately registers only the 663 project-key-compatible
diff --git a/pyproject.toml b/pyproject.toml
index f122dda..74e1f4a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,7 +6,7 @@ readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"anyio>=4.0.0",
- "appwrite-console>=0.7.1,<0.8",
+ "appwrite-console>=0.8.1,<0.9",
"docstring-parser>=0.16",
"mcp[cli]>=2,<3",
"python-dotenv>=1.0.1",
diff --git a/src/mcp_server_appwrite/catalog_policy.py b/src/mcp_server_appwrite/catalog_policy.py
index bd4d222..2be5675 100644
--- a/src/mcp_server_appwrite/catalog_policy.py
+++ b/src/mcp_server_appwrite/catalog_policy.py
@@ -83,6 +83,7 @@
}
),
"apps": frozenset({"delete_installation"}),
+ "avatars": frozenset({"delete_photo", "update_photo"}),
"documents_db": frozenset(
{
"create_documents",
diff --git a/tests/unit/test_server.py b/tests/unit/test_server.py
index dceb504..f52d465 100644
--- a/tests/unit/test_server.py
+++ b/tests/unit/test_server.py
@@ -923,8 +923,8 @@ def test_register_services_returns_fresh_manager(self):
{service.service_name for service in manager_a.services},
set(SERVICE_CLASSES),
)
- self.assertEqual(len(manager_a.services), 40)
- self.assertEqual(len(manager_a.get_all_tools()), 1007)
+ self.assertEqual(len(manager_a.services), 41)
+ self.assertEqual(len(manager_a.get_all_tools()), 1016)
def test_console_sdk_0_7_surface(self):
manager = register_services(object(), profile=OAUTH_PROFILE)
@@ -935,6 +935,8 @@ def test_console_sdk_0_7_surface(self):
self.assertIn("growth_create_conversation", tools)
self.assertIn("organization_create_project_key", tools)
self.assertIn("tables_db_create_cutover", tools)
+ self.assertIn("analytics_list_metrics", tools)
+ self.assertIn("avatars_update_photo", tools)
for removed_tool in (
"project_get_usage",
"projects_list_dev_keys",
@@ -984,6 +986,35 @@ def test_console_sdk_0_7_surface(self):
]
self.assertIn("bun-1.4", build_runtime["enum"])
+ def test_console_sdk_accepts_null_billing_fields(self):
+ # Cloud returns null for these fields; earlier SDKs rejected the
+ # responses (Sentry MCP-1G/1S/1F/1P/1N/1W).
+ from appwrite_console.models.dedicated_database_restoration import (
+ DedicatedDatabaseRestoration,
+ )
+ from appwrite_console.models.invoice import Invoice
+ from appwrite_console.models.organization import Organization
+ from appwrite_console.models.payment_method import PaymentMethod
+ from pydantic import TypeAdapter
+
+ cases = {
+ Organization: ("paymentMethodId",),
+ PaymentMethod: ("mandateId", "state", "lastError"),
+ Invoice: ("clientSecret", "lastError"),
+ DedicatedDatabaseRestoration: ("targetTime",),
+ }
+ for model, aliases in cases.items():
+ fields = {
+ field.alias or name: field for name, field in model.model_fields.items()
+ }
+ for alias in aliases:
+ with self.subTest(model=model.__name__, field=alias):
+ field = fields[alias]
+ self.assertFalse(field.is_required())
+ self.assertIsNone(
+ TypeAdapter(field.annotation).validate_python(None)
+ )
+
def test_advisor_tools_are_project_scoped(self):
manager = register_services(object(), profile=OAUTH_PROFILE)
advisor_tools = {
@@ -1013,6 +1044,9 @@ def test_api_key_profile_only_advertises_server_capabilities(self):
self.assertNotIn("organizations", service_names)
self.assertNotIn("documents_db_list_operations", tool_names)
self.assertNotIn("tables_db_create_cutover", tool_names)
+ self.assertNotIn("avatars_update_photo", tool_names)
+ self.assertNotIn("avatars_delete_photo", tool_names)
+ self.assertNotIn("analytics", service_names)
self.assertNotIn("growth", service_names)
for method in (
"create_ephemeral_project_key",
diff --git a/uv.lock b/uv.lock
index 711d866..47498e6 100644
--- a/uv.lock
+++ b/uv.lock
@@ -39,15 +39,15 @@ wheels = [
[[package]]
name = "appwrite-console"
-version = "0.7.1"
+version = "0.8.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pydantic" },
{ name = "requests" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/2f/0a/d1f4506b3dc54ecb55382aee503d249ebe58e9cf99b44167d5f640b3ecfd/appwrite_console-0.7.1.tar.gz", hash = "sha256:b62706c1497a47070797ecfb70fb3f8910706db9c54ad770a1eda79a962ee287", size = 320527, upload-time = "2026-10-01T19:17:01.769Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/02/b2/76bbf397aca3e8caaf52bd254dac54b85214fffd6d1a1d4dd40d353247dd/appwrite_console-0.8.1.tar.gz", hash = "sha256:1fbb764bb0c9e802f079019e375fe96f5a28e51553a4bce94246e7f18bf8cce5", size = 326599, upload-time = "2026-10-06T10:55:59.571Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/99/23/ae465cbc2f7a3e22a42793e4a77a52c0f2b26543fdc1eb01f81411b92fc1/appwrite_console-0.7.1-py3-none-any.whl", hash = "sha256:5b8b53a25dbc8b97080f006d5f71436738b6f312f519b8bc3c030a445e63423c", size = 554926, upload-time = "2026-10-01T19:17:00.369Z" },
+ { url = "https://files.pythonhosted.org/packages/65/c4/8001bfadd6f5af3fced6421a4b8651fe7b496cafd1fbe01777830d455c36/appwrite_console-0.8.1-py3-none-any.whl", hash = "sha256:c71ad412f932dffe0d244b78ed20368999be3ac6961719e8bd30069b56857768", size = 565106, upload-time = "2026-10-06T10:55:57.918Z" },
]
[[package]]
@@ -694,7 +694,7 @@ dev = [
[package.metadata]
requires-dist = [
{ name = "anyio", specifier = ">=4.0.0" },
- { name = "appwrite-console", specifier = ">=0.7.1,<0.8" },
+ { name = "appwrite-console", specifier = ">=0.8.1,<0.9" },
{ name = "argon2-cffi", marker = "extra == 'integration'", specifier = ">=23.1.0" },
{ name = "bcrypt", marker = "extra == 'integration'", specifier = ">=4.1.2" },
{ name = "docstring-parser", specifier = ">=0.16" },