feat: add database/collection/storage enhancements, file download, array attributes, remove messaging tools
This commit is contained in:
72
README.md
72
README.md
@@ -6,33 +6,32 @@
|
|||||||

|

|
||||||

|

|
||||||
|
|
||||||
**Transform Claude into your intelligent Appwrite management assistant**
|
**Transform Claude into your intelligent Appwrite management assistant**
|
||||||
*16 optimized tools • Core Appwrite operations • Context-efficient design • Production-ready*
|
*12 optimized tools • Core Appwrite operations • Context-efficient design • Production-ready*
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
A **context-optimized Model Context Protocol (MCP)** server that provides Claude with essential Appwrite integration. This version focuses on core functionality with action-based combined tools, offering database operations, user management, storage, messaging, and team management in an efficient package designed to stay under MCP context limits.
|
A **context-optimized Model Context Protocol (MCP)** server that provides Claude with essential Appwrite integration. This version focuses on core functionality with action-based combined tools, offering database operations, user management, storage, and team management in an efficient package designed to stay under MCP context limits.
|
||||||
|
|
||||||
## 🚀 Features
|
## 🚀 Features
|
||||||
|
|
||||||
**🎯 Core Appwrite Operations:**
|
**🎯 Core Appwrite Operations:**
|
||||||
- **Database Management** - Create, list, and delete databases
|
- **Database Management** - Create, get, list, update, and delete databases with enabled status
|
||||||
- **Collection Operations** - Full collection lifecycle management
|
- **Collection Operations** - Full collection lifecycle with document security and search support
|
||||||
- **Document CRUD** - Complete document operations with bulk support
|
- **Document CRUD** - Complete document operations with bulk support and advanced queries
|
||||||
- **User Management** - User operations including bulk processing and preferences
|
- **User Management** - User operations including bulk processing and preferences
|
||||||
- **Storage Management** - Bucket and file operations with URL generation
|
- **Storage Management** - Complete bucket operations with advanced configuration (file size limits, allowed extensions, compression, encryption, antivirus) and file upload/download
|
||||||
- **Team Management** - Complete team administration
|
- **Team Management** - Team CRUD operations
|
||||||
- **Messaging Service** - Messages, topics, and subscriber management
|
- **Attribute & Index Management** - Schema management with array support and bulk operations
|
||||||
- **Attribute & Index Management** - Schema management with bulk operations
|
|
||||||
- **Health Monitoring** - System health checks
|
- **Health Monitoring** - System health checks
|
||||||
|
|
||||||
**⚡ Action-Based Design:**
|
**⚡ Action-Based Design:**
|
||||||
- **Single tools handle multiple operations** using action parameters
|
- **Single tools handle multiple operations** using action parameters
|
||||||
- **Bulk operations integrated** into respective categories
|
- **Bulk operations integrated** into respective categories
|
||||||
- **Context-optimized** - 88% fewer tools than original
|
- **Context-optimized** - Efficient tool design for reduced token usage
|
||||||
- **Maintained functionality** - All core features preserved
|
- **Advanced features** - Document security, file download, bucket encryption, array attributes
|
||||||
|
|
||||||
## 📦 Quick Start
|
## 📦 Quick Start
|
||||||
|
|
||||||
@@ -167,14 +166,14 @@ Once integrated, you should be able to use commands like:
|
|||||||
- "Create a new user with email test@example.com"
|
- "Create a new user with email test@example.com"
|
||||||
- "Show me all collections in my database"
|
- "Show me all collections in my database"
|
||||||
|
|
||||||
## 🛠️ Available Tools (16 Total)
|
## 🛠️ Available Tools (12 Total)
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>🗄️ Database Operations (1 tool)</strong></summary>
|
<summary><strong>🗄️ Database Operations (1 tool)</strong></summary>
|
||||||
|
|
||||||
| Tool | Actions | Description |
|
| Tool | Actions | Description |
|
||||||
|------|---------|-------------|
|
|------|---------|-------------|
|
||||||
| `manage_database` | create, list, delete | Comprehensive database management |
|
| `manage_database` | create, get, list, update, delete | Comprehensive database management with enabled status |
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@@ -183,7 +182,7 @@ Once integrated, you should be able to use commands like:
|
|||||||
|
|
||||||
| Tool | Actions | Description |
|
| Tool | Actions | Description |
|
||||||
|------|---------|-------------|
|
|------|---------|-------------|
|
||||||
| `collection_operations` | create, get, list, update, delete | Complete collection lifecycle management |
|
| `collection_operations` | create, get, list, update, delete | Complete collection lifecycle with document security, enabled status, and search |
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@@ -192,7 +191,7 @@ Once integrated, you should be able to use commands like:
|
|||||||
|
|
||||||
| Tool | Actions | Description |
|
| Tool | Actions | Description |
|
||||||
|------|---------|-------------|
|
|------|---------|-------------|
|
||||||
| `attribute_operations` | create, get, list, update, delete, bulk_create, bulk_delete | Full attribute management with bulk operations |
|
| `attribute_operations` | create, get, list, update, delete, bulk_create, bulk_delete | Full attribute management with array support and bulk operations |
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@@ -230,8 +229,8 @@ Once integrated, you should be able to use commands like:
|
|||||||
|
|
||||||
| Tool | Actions/Description |
|
| Tool | Actions/Description |
|
||||||
|------|--------------------|
|
|------|--------------------|
|
||||||
| `bucket_operations` | create, get, list, update, delete |
|
| `bucket_operations` | create, get, list, update, delete - with advanced configuration (file size limits, allowed extensions, compression, encryption, antivirus) |
|
||||||
| `file_operations` | get, create, update, delete, list |
|
| `file_operations` | get, create, update, delete, list, download - with actual file download implementation |
|
||||||
| `get_file_url` | Generate download, preview, or view URLs with transformations |
|
| `get_file_url` | Generate download, preview, or view URLs with transformations |
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
@@ -246,17 +245,6 @@ Once integrated, you should be able to use commands like:
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><strong>📧 Messaging Operations (3 tools)</strong></summary>
|
|
||||||
|
|
||||||
| Tool | Actions | Description |
|
|
||||||
|------|---------|-------------|
|
|
||||||
| `messaging_message_operations` | create, get, list, update, delete | Complete message management |
|
|
||||||
| `messaging_topic_operations` | create, get, list, update, delete | Complete topic management |
|
|
||||||
| `messaging_subscriber_operations` | create, get, list, delete | Complete subscriber management |
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>🏥 Health Monitoring (1 tool)</strong></summary>
|
<summary><strong>🏥 Health Monitoring (1 tool)</strong></summary>
|
||||||
|
|
||||||
@@ -278,21 +266,21 @@ Once integrated, you should be able to use commands like:
|
|||||||
- **Appwrite Cloud**: `https://cloud.appwrite.io/v1`
|
- **Appwrite Cloud**: `https://cloud.appwrite.io/v1`
|
||||||
- **Self-hosted**: `https://your-domain.com/v1`
|
- **Self-hosted**: `https://your-domain.com/v1`
|
||||||
3. **🔐 API Key**: Create a new API key in your Appwrite console under **Settings > API Keys**
|
3. **🔐 API Key**: Create a new API key in your Appwrite console under **Settings > API Keys**
|
||||||
- ✅ Required scopes: `databases.read`, `databases.write`, `users.read`, `users.write`, `storage.read`, `storage.write`, `messages.read`, `messages.write`, `topics.read`, `topics.write`, `subscribers.read`, `subscribers.write`, `teams.read`, `teams.write`, `health.read`
|
- ✅ Required scopes: `databases.read`, `databases.write`, `users.read`, `users.write`, `storage.read`, `storage.write`, `teams.read`, `teams.write`, `health.read`
|
||||||
|
|
||||||
### 🎯 VS Official Implementation
|
### 🎯 VS Official Implementation
|
||||||
|
|
||||||
| Feature | Our Implementation | Official Appwrite MCP |
|
| Feature | Our Implementation | Official Appwrite MCP |
|
||||||
|---------|-------------------|----------------------|
|
|---------|-------------------|----------------------|
|
||||||
| **Tools Available** | 🟢 16 optimized tools (context-efficient) | 🟡 195 tools (selective enabling) |
|
| **Tools Available** | 🟢 12 optimized tools (context-efficient) | 🟡 195 tools (selective enabling) |
|
||||||
| **Context Usage** | 🟢 Under 25,000 tokens (88% reduction) | 🔴 Over 60,000 tokens |
|
| **Context Usage** | 🟢 Optimized token usage | 🔴 Over 60,000 tokens |
|
||||||
| **Tool Design** | 🟢 Action-based combined tools | 🟡 Individual tools for each operation |
|
| **Tool Design** | 🟢 Action-based combined tools | 🟡 Individual tools for each operation |
|
||||||
| **Core Operations** | 🟢 All essential Appwrite features | 🟡 Database tools only (context limits) |
|
| **Core Operations** | 🟢 All essential database, user, storage, and team features | 🟡 Database tools only (context limits) |
|
||||||
| **Messaging Service** | 🟢 Messages, topics, subscribers | 🟡 Selective enabling required |
|
| **Storage Operations** | 🟢 Complete file operations with download & advanced bucket config | 🟡 Basic bucket operations |
|
||||||
| **Storage Operations** | 🟢 Complete file operations & uploads | 🟡 Basic bucket operations |
|
|
||||||
| **User Management** | 🟢 CRUD + preferences + bulk operations | 🟡 Basic CRUD only |
|
| **User Management** | 🟢 CRUD + preferences + bulk operations | 🟡 Basic CRUD only |
|
||||||
|
| **Advanced Features** | 🟢 Document security, file encryption, array attributes, compression | 🔴 Limited |
|
||||||
| **Bulk Operations** | 🟢 Integrated into respective categories | 🔴 Not available |
|
| **Bulk Operations** | 🟢 Integrated into respective categories | 🔴 Not available |
|
||||||
| **Error Handling** | 🟢 Comprehensive | 🟡 Basic |
|
| **Error Handling** | 🟢 Comprehensive with validation | 🟡 Basic |
|
||||||
| **Language** | 🟡 TypeScript/Node.js | 🟢 Python |
|
| **Language** | 🟡 TypeScript/Node.js | 🟢 Python |
|
||||||
| **Maintenance** | 🟢 Easier with fewer tools | 🟡 Complex with many tools |
|
| **Maintenance** | 🟢 Easier with fewer tools | 🟡 Complex with many tools |
|
||||||
|
|
||||||
@@ -372,18 +360,6 @@ Once integrated, you can use natural language commands with Claude to interact w
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><strong>📧 Messaging & Communication</strong></summary>
|
|
||||||
|
|
||||||
```
|
|
||||||
✨ "List all messaging topics"
|
|
||||||
✨ "Create a topic for user announcements"
|
|
||||||
✨ "Add subscribers to the announcements topic"
|
|
||||||
✨ "Send a message to all subscribers"
|
|
||||||
✨ "List all messages and their delivery status"
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
360
src/index.ts
360
src/index.ts
@@ -8,23 +8,22 @@ import {
|
|||||||
ListToolsRequestSchema,
|
ListToolsRequestSchema,
|
||||||
McpError,
|
McpError,
|
||||||
} from "@modelcontextprotocol/sdk/types.js";
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
import {
|
import {
|
||||||
Client,
|
Client,
|
||||||
Databases,
|
Databases,
|
||||||
Users,
|
Users,
|
||||||
Storage,
|
Storage,
|
||||||
Teams,
|
Teams,
|
||||||
Account,
|
Account,
|
||||||
Health,
|
Health,
|
||||||
Messaging,
|
ID,
|
||||||
ID,
|
Query,
|
||||||
Query,
|
Permission,
|
||||||
Permission,
|
|
||||||
Role,
|
Role,
|
||||||
IndexType
|
IndexType
|
||||||
} from "node-appwrite";
|
} from "node-appwrite";
|
||||||
import { InputFile } from "node-appwrite/file";
|
import { InputFile } from "node-appwrite/file";
|
||||||
import { readFileSync, existsSync } from "fs";
|
import { readFileSync, writeFileSync, existsSync } from "fs";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import * as dotenv from "dotenv";
|
import * as dotenv from "dotenv";
|
||||||
|
|
||||||
@@ -43,7 +42,6 @@ class AppwriteMCPServer {
|
|||||||
private teams: Teams | null = null;
|
private teams: Teams | null = null;
|
||||||
private account: Account | null = null;
|
private account: Account | null = null;
|
||||||
private health: Health | null = null;
|
private health: Health | null = null;
|
||||||
private messaging: Messaging | null = null;
|
|
||||||
private config: AppwriteConfig | null = null;
|
private config: AppwriteConfig | null = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -99,7 +97,6 @@ class AppwriteMCPServer {
|
|||||||
this.teams = new Teams(this.client);
|
this.teams = new Teams(this.client);
|
||||||
this.account = new Account(this.client);
|
this.account = new Account(this.client);
|
||||||
this.health = new Health(this.client);
|
this.health = new Health(this.client);
|
||||||
this.messaging = new Messaging(this.client);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupToolHandlers(): void {
|
private setupToolHandlers(): void {
|
||||||
@@ -109,13 +106,14 @@ class AppwriteMCPServer {
|
|||||||
// Database Operations
|
// Database Operations
|
||||||
{
|
{
|
||||||
name: "manage_database",
|
name: "manage_database",
|
||||||
description: "Manage database operations (create, list, delete)",
|
description: "Manage database operations (create, get, list, update, delete)",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
action: { type: "string", description: "Action to perform", enum: ["create", "list", "delete"] },
|
action: { type: "string", description: "Action to perform", enum: ["create", "get", "list", "update", "delete"] },
|
||||||
databaseId: { type: "string", description: "ID of the database (required for delete, optional for create)" },
|
databaseId: { type: "string", description: "ID of the database (required for get/update/delete, optional for create)" },
|
||||||
name: { type: "string", description: "Name of the database (required for create)" }
|
name: { type: "string", description: "Name of the database (required for create/update)" },
|
||||||
|
enabled: { type: "boolean", description: "Enable or disable database (optional for create/update)" }
|
||||||
},
|
},
|
||||||
required: ["action"]
|
required: ["action"]
|
||||||
}
|
}
|
||||||
@@ -132,7 +130,11 @@ class AppwriteMCPServer {
|
|||||||
databaseId: { type: "string", description: "ID of the database" },
|
databaseId: { type: "string", description: "ID of the database" },
|
||||||
collectionId: { type: "string", description: "ID of the collection (optional for create/list, required for get/update/delete)" },
|
collectionId: { type: "string", description: "ID of the collection (optional for create/list, required for get/update/delete)" },
|
||||||
name: { type: "string", description: "Collection name (required for create/update)" },
|
name: { type: "string", description: "Collection name (required for create/update)" },
|
||||||
permissions: { type: "array", description: "Collection permissions (optional)", items: { type: "string" } }
|
permissions: { type: "array", description: "Collection permissions (optional)", items: { type: "string" } },
|
||||||
|
documentSecurity: { type: "boolean", description: "Enable document-level security (optional)" },
|
||||||
|
enabled: { type: "boolean", description: "Enable or disable collection (optional)" },
|
||||||
|
queries: { type: "array", description: "Query filters for list action (optional)", items: { type: "string" } },
|
||||||
|
search: { type: "string", description: "Search term for filtering results (optional)" }
|
||||||
},
|
},
|
||||||
required: ["action", "databaseId"]
|
required: ["action", "databaseId"]
|
||||||
}
|
}
|
||||||
@@ -149,13 +151,14 @@ class AppwriteMCPServer {
|
|||||||
databaseId: { type: "string", description: "ID of the database" },
|
databaseId: { type: "string", description: "ID of the database" },
|
||||||
collectionId: { type: "string", description: "ID of the collection" },
|
collectionId: { type: "string", description: "ID of the collection" },
|
||||||
key: { type: "string", description: "Attribute key (required for create/get/update/delete)" },
|
key: { type: "string", description: "Attribute key (required for create/get/update/delete)" },
|
||||||
type: {
|
type: {
|
||||||
type: "string",
|
type: "string",
|
||||||
description: "Attribute type (required for create/update)",
|
description: "Attribute type (required for create/update)",
|
||||||
enum: ["string", "integer", "float", "boolean", "datetime", "email", "ip", "url", "enum", "relationship"]
|
enum: ["string", "integer", "float", "boolean", "datetime", "email", "ip", "url", "enum", "relationship"]
|
||||||
},
|
},
|
||||||
required: { type: "boolean", description: "Is attribute required (required for create/update)" },
|
required: { type: "boolean", description: "Is attribute required (required for create/update)" },
|
||||||
default: { type: "string", description: "Default value (optional)" },
|
default: { type: "string", description: "Default value (optional)" },
|
||||||
|
array: { type: "boolean", description: "Is attribute an array (optional, default: false)" },
|
||||||
size: { type: "number", description: "Size for string/ip/url attributes (optional)" },
|
size: { type: "number", description: "Size for string/ip/url attributes (optional)" },
|
||||||
min: { type: "number", description: "Minimum value for integer/float attributes (optional)" },
|
min: { type: "number", description: "Minimum value for integer/float attributes (optional)" },
|
||||||
max: { type: "number", description: "Maximum value for integer/float attributes (optional)" },
|
max: { type: "number", description: "Maximum value for integer/float attributes (optional)" },
|
||||||
@@ -179,13 +182,14 @@ class AppwriteMCPServer {
|
|||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
key: { type: "string", description: "Attribute key" },
|
key: { type: "string", description: "Attribute key" },
|
||||||
type: {
|
type: {
|
||||||
type: "string",
|
type: "string",
|
||||||
description: "Attribute type",
|
description: "Attribute type",
|
||||||
enum: ["string", "integer", "float", "boolean", "datetime", "email", "ip", "url", "enum", "relationship"]
|
enum: ["string", "integer", "float", "boolean", "datetime", "email", "ip", "url", "enum", "relationship"]
|
||||||
},
|
},
|
||||||
required: { type: "boolean", description: "Is attribute required" },
|
required: { type: "boolean", description: "Is attribute required" },
|
||||||
default: { type: "string", description: "Default value (optional)" },
|
default: { type: "string", description: "Default value (optional)" },
|
||||||
|
array: { type: "boolean", description: "Is attribute an array (optional, default: false)" },
|
||||||
size: { type: "number", description: "Size for string/ip/url attributes (optional)" },
|
size: { type: "number", description: "Size for string/ip/url attributes (optional)" },
|
||||||
min: { type: "number", description: "Minimum value for integer/float attributes (optional)" },
|
min: { type: "number", description: "Minimum value for integer/float attributes (optional)" },
|
||||||
max: { type: "number", description: "Maximum value for integer/float attributes (optional)" },
|
max: { type: "number", description: "Maximum value for integer/float attributes (optional)" },
|
||||||
@@ -380,7 +384,12 @@ class AppwriteMCPServer {
|
|||||||
name: { type: "string", description: "Bucket name (required for create/update)" },
|
name: { type: "string", description: "Bucket name (required for create/update)" },
|
||||||
permissions: { type: "array", description: "Bucket permissions (optional)", items: { type: "string" } },
|
permissions: { type: "array", description: "Bucket permissions (optional)", items: { type: "string" } },
|
||||||
fileSecurity: { type: "boolean", description: "Enable file security (optional)" },
|
fileSecurity: { type: "boolean", description: "Enable file security (optional)" },
|
||||||
enabled: { type: "boolean", description: "Enable bucket (optional)" }
|
enabled: { type: "boolean", description: "Enable bucket (optional)" },
|
||||||
|
maximumFileSize: { type: "number", description: "Maximum file size in bytes (optional, max 50MB)" },
|
||||||
|
allowedFileExtensions: { type: "array", description: "Allowed file extensions (optional)", items: { type: "string" } },
|
||||||
|
compression: { type: "string", description: "Compression algorithm (optional)", enum: ["none", "gzip", "zstd"] },
|
||||||
|
encryption: { type: "boolean", description: "Enable encryption (optional)" },
|
||||||
|
antivirus: { type: "boolean", description: "Enable antivirus scanning (optional)" }
|
||||||
},
|
},
|
||||||
required: ["action"]
|
required: ["action"]
|
||||||
}
|
}
|
||||||
@@ -389,14 +398,15 @@ class AppwriteMCPServer {
|
|||||||
// File Operations
|
// File Operations
|
||||||
{
|
{
|
||||||
name: "file_operations",
|
name: "file_operations",
|
||||||
description: "Manage file operations (get, create, update, delete, list)",
|
description: "Manage file operations (get, create, update, delete, list, download)",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
action: { type: "string", description: "Action to perform", enum: ["get", "create", "update", "delete", "list"] },
|
action: { type: "string", description: "Action to perform", enum: ["get", "create", "update", "delete", "list", "download"] },
|
||||||
bucketId: { type: "string", description: "Bucket ID" },
|
bucketId: { type: "string", description: "Bucket ID" },
|
||||||
fileId: { type: "string", description: "File ID (optional for create/list, required for get/update/delete)" },
|
fileId: { type: "string", description: "File ID (optional for create/list, required for get/update/delete/download)" },
|
||||||
filePath: { type: "string", description: "Local file path to upload (required for create)" },
|
filePath: { type: "string", description: "Local file path to upload (required for create)" },
|
||||||
|
downloadPath: { type: "string", description: "Local path to save downloaded file (required for download)" },
|
||||||
name: { type: "string", description: "File name (optional for update)" },
|
name: { type: "string", description: "File name (optional for update)" },
|
||||||
permissions: { type: "array", description: "File permissions (optional)", items: { type: "string" } }
|
permissions: { type: "array", description: "File permissions (optional)", items: { type: "string" } }
|
||||||
},
|
},
|
||||||
@@ -446,62 +456,7 @@ class AppwriteMCPServer {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Messaging Message Operations
|
// Health Monitoring
|
||||||
{
|
|
||||||
name: "messaging_message_operations",
|
|
||||||
description: "Manage messaging message operations (create, get, list, update, delete)",
|
|
||||||
inputSchema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
action: { type: "string", description: "Action to perform", enum: ["create", "get", "list", "update", "delete"] },
|
|
||||||
messageId: { type: "string", description: "Message ID (optional for create/list, required for get/update/delete)" },
|
|
||||||
subject: { type: "string", description: "Message subject (optional)" },
|
|
||||||
content: { type: "string", description: "Message content (required for create)" },
|
|
||||||
topics: { type: "array", description: "Topic IDs (optional)", items: { type: "string" } },
|
|
||||||
users: { type: "array", description: "User IDs (optional)", items: { type: "string" } },
|
|
||||||
targets: { type: "array", description: "Target IDs (optional)", items: { type: "string" } },
|
|
||||||
status: { type: "string", description: "Message status (optional for update)" },
|
|
||||||
queries: { type: "array", description: "Query filters (optional for list)", items: { type: "string" } }
|
|
||||||
},
|
|
||||||
required: ["action"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Messaging Topic Operations
|
|
||||||
{
|
|
||||||
name: "messaging_topic_operations",
|
|
||||||
description: "Manage messaging topic operations (create, get, list, update, delete)",
|
|
||||||
inputSchema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
action: { type: "string", description: "Action to perform", enum: ["create", "get", "list", "update", "delete"] },
|
|
||||||
topicId: { type: "string", description: "Topic ID (optional for create/list, required for get/update/delete)" },
|
|
||||||
name: { type: "string", description: "Topic name (required for create)" },
|
|
||||||
description: { type: "string", description: "Topic description (optional)" },
|
|
||||||
queries: { type: "array", description: "Query filters (optional for list)", items: { type: "string" } }
|
|
||||||
},
|
|
||||||
required: ["action"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Messaging Subscriber Operations
|
|
||||||
{
|
|
||||||
name: "messaging_subscriber_operations",
|
|
||||||
description: "Manage messaging subscriber operations (create, get, list, delete)",
|
|
||||||
inputSchema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
action: { type: "string", description: "Action to perform", enum: ["create", "get", "list", "delete"] },
|
|
||||||
topicId: { type: "string", description: "Topic ID" },
|
|
||||||
subscriberId: { type: "string", description: "Subscriber ID (optional for create/list, required for get/delete)" },
|
|
||||||
targetId: { type: "string", description: "Target ID (required for create)" },
|
|
||||||
queries: { type: "array", description: "Query filters (optional for list)", items: { type: "string" } }
|
|
||||||
},
|
|
||||||
required: ["action", "topicId"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Health Monitoring (kept separate)
|
|
||||||
{
|
{
|
||||||
name: "get_health",
|
name: "get_health",
|
||||||
description: "Get overall health status of Appwrite services",
|
description: "Get overall health status of Appwrite services",
|
||||||
@@ -568,16 +523,6 @@ class AppwriteMCPServer {
|
|||||||
case "team_operations":
|
case "team_operations":
|
||||||
return await this.teamOperations(request.params.arguments);
|
return await this.teamOperations(request.params.arguments);
|
||||||
|
|
||||||
// Messaging Operations
|
|
||||||
case "messaging_message_operations":
|
|
||||||
return await this.messagingMessageOperations(request.params.arguments);
|
|
||||||
|
|
||||||
case "messaging_topic_operations":
|
|
||||||
return await this.messagingTopicOperations(request.params.arguments);
|
|
||||||
|
|
||||||
case "messaging_subscriber_operations":
|
|
||||||
return await this.messagingSubscriberOperations(request.params.arguments);
|
|
||||||
|
|
||||||
case "get_health":
|
case "get_health":
|
||||||
return await this.getHealth();
|
return await this.getHealth();
|
||||||
|
|
||||||
@@ -600,25 +545,40 @@ class AppwriteMCPServer {
|
|||||||
|
|
||||||
private async manageDatabaseOperations(args: any) {
|
private async manageDatabaseOperations(args: any) {
|
||||||
if (!this.databases) throw new Error("Databases not initialized");
|
if (!this.databases) throw new Error("Databases not initialized");
|
||||||
|
|
||||||
const { action, databaseId, name } = args;
|
const { action, databaseId, name, enabled } = args;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "create":
|
case "create":
|
||||||
if (!name) throw new Error("Name is required for create action");
|
if (!name) throw new Error("Name is required for create action");
|
||||||
const dbId = databaseId || ID.unique();
|
const dbId = databaseId || ID.unique();
|
||||||
const database = await this.databases.create(dbId, name);
|
const database = await this.databases.create(dbId, name, enabled);
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `Database created successfully:\n- ID: ${database.$id}\n- Name: ${database.name}\n- Created: ${database.$createdAt}` }]
|
content: [{ type: "text", text: `Database created successfully:\n- ID: ${database.$id}\n- Name: ${database.name}\n- Enabled: ${database.enabled}\n- Created: ${database.$createdAt}` }]
|
||||||
|
};
|
||||||
|
|
||||||
|
case "get":
|
||||||
|
if (!databaseId) throw new Error("databaseId is required for get action");
|
||||||
|
const getDb = await this.databases.get(databaseId);
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: `Database Details:\n- ID: ${getDb.$id}\n- Name: ${getDb.name}\n- Enabled: ${getDb.enabled}\n- Created: ${getDb.$createdAt}\n- Updated: ${getDb.$updatedAt}` }]
|
||||||
};
|
};
|
||||||
|
|
||||||
case "list":
|
case "list":
|
||||||
const databases = await this.databases.list();
|
const databases = await this.databases.list();
|
||||||
const dbList = databases.databases.map(db => `- ${db.name} (${db.$id})`).join('\n');
|
const dbList = databases.databases.map(db => `- ${db.name} (${db.$id}) - ${db.enabled ? 'enabled' : 'disabled'}`).join('\n');
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `Databases (${databases.total}):\n${dbList}` }]
|
content: [{ type: "text", text: `Databases (${databases.total}):\n${dbList}` }]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case "update":
|
||||||
|
if (!databaseId) throw new Error("databaseId is required for update action");
|
||||||
|
if (!name) throw new Error("name is required for update action");
|
||||||
|
const updatedDb = await this.databases.update(databaseId, name, enabled);
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: `Database updated successfully:\n- ID: ${updatedDb.$id}\n- Name: ${updatedDb.name}\n- Enabled: ${updatedDb.enabled}` }]
|
||||||
|
};
|
||||||
|
|
||||||
case "delete":
|
case "delete":
|
||||||
if (!databaseId) throw new Error("databaseId is required for delete action");
|
if (!databaseId) throw new Error("databaseId is required for delete action");
|
||||||
await this.databases.delete(databaseId);
|
await this.databases.delete(databaseId);
|
||||||
@@ -633,28 +593,38 @@ class AppwriteMCPServer {
|
|||||||
|
|
||||||
private async collectionOperations(args: any) {
|
private async collectionOperations(args: any) {
|
||||||
if (!this.databases) throw new Error("Databases not initialized");
|
if (!this.databases) throw new Error("Databases not initialized");
|
||||||
|
|
||||||
const { action, databaseId, collectionId, name, permissions } = args;
|
const { action, databaseId, collectionId, name, permissions, documentSecurity, enabled, queries, search } = args;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "create":
|
case "create":
|
||||||
if (!name) throw new Error("Name is required for create action");
|
if (!name) throw new Error("Name is required for create action");
|
||||||
const colId = collectionId || ID.unique();
|
const colId = collectionId || ID.unique();
|
||||||
const collection = await this.databases.createCollection(databaseId, colId, name, permissions);
|
const collection = await this.databases.createCollection(databaseId, colId, name, permissions, documentSecurity, enabled);
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `Collection created successfully:\n- ID: ${collection.$id}\n- Name: ${collection.name}\n- Database: ${collection.databaseId}` }]
|
content: [{ type: "text", text: `Collection created successfully:\n- ID: ${collection.$id}\n- Name: ${collection.name}\n- Database: ${collection.databaseId}\n- Document Security: ${collection.documentSecurity}\n- Enabled: ${collection.enabled}` }]
|
||||||
};
|
};
|
||||||
|
|
||||||
case "get":
|
case "get":
|
||||||
if (!collectionId) throw new Error("collectionId is required for get action");
|
if (!collectionId) throw new Error("collectionId is required for get action");
|
||||||
const getCollection = await this.databases.getCollection(databaseId, collectionId);
|
const getCollection = await this.databases.getCollection(databaseId, collectionId);
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `Collection Details:\n- ID: ${getCollection.$id}\n- Name: ${getCollection.name}\n- Attributes: ${getCollection.attributes.length}\n- Indexes: ${getCollection.indexes.length}` }]
|
content: [{ type: "text", text: `Collection Details:\n- ID: ${getCollection.$id}\n- Name: ${getCollection.name}\n- Attributes: ${getCollection.attributes.length}\n- Indexes: ${getCollection.indexes.length}\n- Document Security: ${getCollection.documentSecurity}\n- Enabled: ${getCollection.enabled}` }]
|
||||||
};
|
};
|
||||||
|
|
||||||
case "list":
|
case "list":
|
||||||
const collections = await this.databases.listCollections(databaseId, [Query.limit(5000)]);
|
const parsedQueries: string[] = [];
|
||||||
const colList = collections.collections.map(col => `- ${col.name} (${col.$id})`).join('\n');
|
if (queries && Array.isArray(queries)) {
|
||||||
|
for (const queryStr of queries) {
|
||||||
|
parsedQueries.push(this.parseQuery(queryStr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!parsedQueries.some(q => q.includes('limit'))) {
|
||||||
|
parsedQueries.push(Query.limit(5000));
|
||||||
|
}
|
||||||
|
|
||||||
|
const collections = await this.databases.listCollections(databaseId, parsedQueries, search);
|
||||||
|
const colList = collections.collections.map(col => `- ${col.name} (${col.$id}) - ${col.enabled ? 'enabled' : 'disabled'}`).join('\n');
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `Collections in database ${databaseId} (${collections.total}):\n${colList}` }]
|
content: [{ type: "text", text: `Collections in database ${databaseId} (${collections.total}):\n${colList}` }]
|
||||||
};
|
};
|
||||||
@@ -662,9 +632,9 @@ class AppwriteMCPServer {
|
|||||||
case "update":
|
case "update":
|
||||||
if (!collectionId) throw new Error("collectionId is required for update action");
|
if (!collectionId) throw new Error("collectionId is required for update action");
|
||||||
if (!name) throw new Error("Name is required for update action");
|
if (!name) throw new Error("Name is required for update action");
|
||||||
const updatedCollection = await this.databases.updateCollection(databaseId, collectionId, name, permissions);
|
const updatedCollection = await this.databases.updateCollection(databaseId, collectionId, name, permissions, documentSecurity, enabled);
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `Collection updated successfully:\n- ID: ${updatedCollection.$id}\n- Name: ${updatedCollection.name}` }]
|
content: [{ type: "text", text: `Collection updated successfully:\n- ID: ${updatedCollection.$id}\n- Name: ${updatedCollection.name}\n- Document Security: ${updatedCollection.documentSecurity}\n- Enabled: ${updatedCollection.enabled}` }]
|
||||||
};
|
};
|
||||||
|
|
||||||
case "delete":
|
case "delete":
|
||||||
@@ -1278,22 +1248,33 @@ class AppwriteMCPServer {
|
|||||||
|
|
||||||
private async bucketOperations(args: any) {
|
private async bucketOperations(args: any) {
|
||||||
if (!this.storage) throw new Error("Storage not initialized");
|
if (!this.storage) throw new Error("Storage not initialized");
|
||||||
|
|
||||||
const { action, bucketId, name, permissions, fileSecurity, enabled } = args;
|
const { action, bucketId, name, permissions, fileSecurity, enabled, maximumFileSize, allowedFileExtensions, compression, encryption, antivirus } = args;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "create":
|
case "create":
|
||||||
if (!name) throw new Error("name is required for create action");
|
if (!name) throw new Error("name is required for create action");
|
||||||
const bucket = await this.storage.createBucket(bucketId || ID.unique(), name, permissions, fileSecurity, enabled);
|
const bucket = await this.storage.createBucket(
|
||||||
|
bucketId || ID.unique(),
|
||||||
|
name,
|
||||||
|
permissions,
|
||||||
|
fileSecurity,
|
||||||
|
enabled,
|
||||||
|
maximumFileSize,
|
||||||
|
allowedFileExtensions,
|
||||||
|
compression,
|
||||||
|
encryption,
|
||||||
|
antivirus
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `Bucket created successfully:\n- ID: ${bucket.$id}\n- Name: ${bucket.name}\n- Enabled: ${bucket.enabled}` }]
|
content: [{ type: "text", text: `Bucket created successfully:\n- ID: ${bucket.$id}\n- Name: ${bucket.name}\n- Enabled: ${bucket.enabled}\n- File Security: ${bucket.fileSecurity}\n- Max File Size: ${bucket.maximumFileSize || 'unlimited'} bytes\n- Compression: ${bucket.compression}\n- Encryption: ${bucket.encryption}\n- Antivirus: ${bucket.antivirus}` }]
|
||||||
};
|
};
|
||||||
|
|
||||||
case "get":
|
case "get":
|
||||||
if (!bucketId) throw new Error("bucketId is required for get action");
|
if (!bucketId) throw new Error("bucketId is required for get action");
|
||||||
const getBucket = await this.storage.getBucket(bucketId);
|
const getBucket = await this.storage.getBucket(bucketId);
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `Bucket Details:\n- ID: ${getBucket.$id}\n- Name: ${getBucket.name}\n- Enabled: ${getBucket.enabled}\n- File Security: ${getBucket.fileSecurity}` }]
|
content: [{ type: "text", text: `Bucket Details:\n- ID: ${getBucket.$id}\n- Name: ${getBucket.name}\n- Enabled: ${getBucket.enabled}\n- File Security: ${getBucket.fileSecurity}\n- Max File Size: ${getBucket.maximumFileSize || 'unlimited'} bytes\n- Allowed Extensions: ${getBucket.allowedFileExtensions?.join(', ') || 'all'}\n- Compression: ${getBucket.compression}\n- Encryption: ${getBucket.encryption}\n- Antivirus: ${getBucket.antivirus}` }]
|
||||||
};
|
};
|
||||||
|
|
||||||
case "list":
|
case "list":
|
||||||
@@ -1305,9 +1286,20 @@ class AppwriteMCPServer {
|
|||||||
|
|
||||||
case "update":
|
case "update":
|
||||||
if (!bucketId || !name) throw new Error("bucketId and name are required for update action");
|
if (!bucketId || !name) throw new Error("bucketId and name are required for update action");
|
||||||
const updatedBucket = await this.storage.updateBucket(bucketId, name, permissions, fileSecurity, enabled);
|
const updatedBucket = await this.storage.updateBucket(
|
||||||
|
bucketId,
|
||||||
|
name,
|
||||||
|
permissions,
|
||||||
|
fileSecurity,
|
||||||
|
enabled,
|
||||||
|
maximumFileSize,
|
||||||
|
allowedFileExtensions,
|
||||||
|
compression,
|
||||||
|
encryption,
|
||||||
|
antivirus
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `Bucket updated successfully:\n- ID: ${updatedBucket.$id}\n- Name: ${updatedBucket.name}` }]
|
content: [{ type: "text", text: `Bucket updated successfully:\n- ID: ${updatedBucket.$id}\n- Name: ${updatedBucket.name}\n- Enabled: ${updatedBucket.enabled}` }]
|
||||||
};
|
};
|
||||||
|
|
||||||
case "delete":
|
case "delete":
|
||||||
@@ -1324,8 +1316,8 @@ class AppwriteMCPServer {
|
|||||||
|
|
||||||
private async fileOperations(args: any) {
|
private async fileOperations(args: any) {
|
||||||
if (!this.storage) throw new Error("Storage not initialized");
|
if (!this.storage) throw new Error("Storage not initialized");
|
||||||
|
|
||||||
const { action, bucketId, fileId, filePath, name, permissions } = args;
|
const { action, bucketId, fileId, filePath, downloadPath, name, permissions } = args;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "get":
|
case "get":
|
||||||
@@ -1338,14 +1330,35 @@ class AppwriteMCPServer {
|
|||||||
case "create":
|
case "create":
|
||||||
if (!filePath) throw new Error("filePath is required for create action");
|
if (!filePath) throw new Error("filePath is required for create action");
|
||||||
if (!existsSync(filePath)) throw new Error(`File not found: ${filePath}`);
|
if (!existsSync(filePath)) throw new Error(`File not found: ${filePath}`);
|
||||||
|
|
||||||
const fileBuffer = readFileSync(filePath);
|
const fileBuffer = readFileSync(filePath);
|
||||||
const inputFile = InputFile.fromBuffer(fileBuffer, filePath.split('/').pop() || 'file');
|
const inputFile = InputFile.fromBuffer(fileBuffer, filePath.split(/[/\\]/).pop() || 'file');
|
||||||
const createdFile = await this.storage.createFile(bucketId, fileId || ID.unique(), inputFile, permissions);
|
const createdFile = await this.storage.createFile(bucketId, fileId || ID.unique(), inputFile, permissions);
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `File uploaded successfully:\n- ID: ${createdFile.$id}\n- Name: ${createdFile.name}\n- Size: ${createdFile.sizeOriginal} bytes` }]
|
content: [{ type: "text", text: `File uploaded successfully:\n- ID: ${createdFile.$id}\n- Name: ${createdFile.name}\n- Size: ${createdFile.sizeOriginal} bytes` }]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case "download":
|
||||||
|
if (!fileId) throw new Error("fileId is required for download action");
|
||||||
|
if (!downloadPath) throw new Error("downloadPath is required for download action");
|
||||||
|
|
||||||
|
// Get file metadata first
|
||||||
|
const downloadFile = await this.storage.getFile(bucketId, fileId);
|
||||||
|
|
||||||
|
// Get download URL and fetch the file
|
||||||
|
const downloadUrl = this.storage.getFileDownload(bucketId, fileId);
|
||||||
|
|
||||||
|
// Use fetch to download the file
|
||||||
|
const response = await fetch(downloadUrl.toString());
|
||||||
|
if (!response.ok) throw new Error(`Failed to download file: ${response.statusText}`);
|
||||||
|
|
||||||
|
const buffer = Buffer.from(await response.arrayBuffer());
|
||||||
|
writeFileSync(downloadPath, buffer);
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: `File downloaded successfully:\n- ID: ${downloadFile.$id}\n- Name: ${downloadFile.name}\n- Size: ${downloadFile.sizeOriginal} bytes\n- Saved to: ${downloadPath}` }]
|
||||||
|
};
|
||||||
|
|
||||||
case "update":
|
case "update":
|
||||||
if (!fileId) throw new Error("fileId is required for update action");
|
if (!fileId) throw new Error("fileId is required for update action");
|
||||||
const updatedFile = await this.storage.updateFile(bucketId, fileId, name, permissions);
|
const updatedFile = await this.storage.updateFile(bucketId, fileId, name, permissions);
|
||||||
@@ -1447,121 +1460,6 @@ class AppwriteMCPServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async messagingMessageOperations(args: any) {
|
|
||||||
if (!this.messaging) throw new Error("Messaging not initialized");
|
|
||||||
|
|
||||||
const { action, messageId, subject, content, topics, users, targets, status, queries } = args;
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
case "create":
|
|
||||||
if (!content) throw new Error("content is required for create action");
|
|
||||||
// Note: Using a placeholder - actual Appwrite messaging API may differ
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Message operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
case "get":
|
|
||||||
if (!messageId) throw new Error("messageId is required for get action");
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Message operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
case "list":
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Message operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
case "update":
|
|
||||||
if (!messageId) throw new Error("messageId is required for update action");
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Message operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
case "delete":
|
|
||||||
if (!messageId) throw new Error("messageId is required for delete action");
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Message operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error(`Unknown action: ${action}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async messagingTopicOperations(args: any) {
|
|
||||||
if (!this.messaging) throw new Error("Messaging not initialized");
|
|
||||||
|
|
||||||
const { action, topicId, name, description, queries } = args;
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
case "create":
|
|
||||||
if (!name) throw new Error("name is required for create action");
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Topic operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
case "get":
|
|
||||||
if (!topicId) throw new Error("topicId is required for get action");
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Topic operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
case "list":
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Topic operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
case "update":
|
|
||||||
if (!topicId) throw new Error("topicId is required for update action");
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Topic operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
case "delete":
|
|
||||||
if (!topicId) throw new Error("topicId is required for delete action");
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Topic operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error(`Unknown action: ${action}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async messagingSubscriberOperations(args: any) {
|
|
||||||
if (!this.messaging) throw new Error("Messaging not initialized");
|
|
||||||
|
|
||||||
const { action, topicId, subscriberId, targetId, queries } = args;
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
case "create":
|
|
||||||
if (!targetId) throw new Error("targetId is required for create action");
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Subscriber operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
case "get":
|
|
||||||
if (!subscriberId) throw new Error("subscriberId is required for get action");
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Subscriber operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
case "list":
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Subscriber operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
case "delete":
|
|
||||||
if (!subscriberId) throw new Error("subscriberId is required for delete action");
|
|
||||||
return {
|
|
||||||
content: [{ type: "text", text: `Subscriber operation not fully implemented in current Appwrite SDK version` }]
|
|
||||||
};
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error(`Unknown action: ${action}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getHealth() {
|
private async getHealth() {
|
||||||
if (!this.health) throw new Error("Health not initialized");
|
if (!this.health) throw new Error("Health not initialized");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user