diff --git a/README.md b/README.md
index 67b6e67..64ce21d 100644
--- a/README.md
+++ b/README.md
@@ -197,15 +197,11 @@ Once integrated, you should be able to use commands like:
-🏷️ Attribute Management (7 tools)
+🏷️ Attribute Management (3 tools)
| Tool | Description |
|------|-------------|
-| `create_string_attribute` | Create a string attribute in a collection |
-| `create_integer_attribute` | Create an integer attribute in a collection |
-| `create_boolean_attribute` | Create a boolean attribute in a collection |
-| `create_email_attribute` | Create an email attribute in a collection |
-| `create_datetime_attribute` | Create a datetime attribute in a collection |
+| `create_attribute` | ✨ Create any attribute type (string, integer, float, boolean, datetime, email, IP, URL, enum, relationship) |
| `list_attributes` | List all attributes in a collection |
| `delete_attribute` | Delete an attribute from a collection |
@@ -236,17 +232,19 @@ Once integrated, you should be able to use commands like:
-👥 User Management (7 tools)
+👥 User Management (9 tools)
| Tool | Description |
|------|-------------|
| `create_user` | Create a new user |
-| `list_users` | List all users |
+| `list_users` | List all users ✨ *with verification status* |
| `get_user` | Get a user by ID |
| `update_user_email` | Update user email |
| `update_user_name` | Update user name |
| `update_user_password` | Update user password |
| `delete_user` | Delete a user |
+| `verify_user_email` | ✨ Verify a user's email address |
+| `unverify_user_email` | ✨ Unverify a user's email address |
@@ -352,10 +350,12 @@ Once integrated, you should be able to use commands like:
-⚡ Bulk Operations (6 tools)
+⚡ Bulk Operations (8 tools)
| Tool | Description |
|------|-------------|
+| `bulk_create_attributes` | ✨ Create multiple attributes at once in a collection |
+| `bulk_delete_attributes` | ✨ Delete multiple attributes at once from a collection |
| `bulk_create_users` | ✨ Create multiple users at once |
| `bulk_update_users` | ✨ Update multiple users at once |
| `bulk_delete_users` | ✨ Delete multiple users at once |
@@ -412,11 +412,14 @@ Once integrated, you can use natural language commands with Claude to interact w
🏷️ Schema & Attributes
```
-✨ "Add a string attribute called 'name' to the products collection with max size 255"
-✨ "Create a boolean attribute 'in_stock' in the products collection"
+✨ "Create a string attribute called 'name' in the products collection with max size 255"
+✨ "Add a boolean attribute 'in_stock' to the products collection"
+✨ "Create an enum attribute 'status' with values active, inactive, pending"
+✨ "Add a relationship attribute linking products to categories"
+✨ "Bulk create attributes: name (string), price (float), in_stock (boolean)"
+✨ "Bulk delete attributes: old_field1, deprecated_field2, unused_field3"
✨ "List all attributes in the products collection"
✨ "Create a unique index on the 'sku' attribute"
-✨ "Add an email attribute for 'contact_email'"
```
@@ -441,6 +444,8 @@ Once integrated, you can use natural language commands with Claude to interact w
✨ "Create a new user with email john@example.com and password SecurePass123"
✨ "List all users in the project"
✨ "Update user xyz123's name to 'John Doe'"
+✨ "Verify user abc123's email address"
+✨ "Unverify user xyz456's email verification"
✨ "Create a session for user john@example.com"
✨ "Bulk create 10 test users for demo purposes"
```
@@ -451,6 +456,10 @@ Once integrated, you can use natural language commands with Claude to interact w
⚡ Advanced Features (Exclusive)
```
+🚀 "Create a complete product schema with string, enum, float, and relationship attributes"
+🚀 "Bulk create 10 attributes at once for my e-commerce collection"
+🚀 "Add a relationship attribute linking orders to customers with two-way binding"
+🚀 "Create an enum attribute for user roles with admin, user, moderator values"
🚀 "Analyze this sample data and create a collection schema automatically"
🚀 "Suggest optimal indexes for my users collection based on usage"
🚀 "Validate this document data before creating it"
diff --git a/src/index.ts b/src/index.ts
index a84e299..ef69159 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -176,81 +176,102 @@ class AppwriteMCPServer {
// Attribute Operations
{
- name: "create_string_attribute",
- description: "Create a string attribute in a collection",
+ name: "create_attribute",
+ description: "Create any type of attribute in a collection (string, integer, float, boolean, datetime, email, IP, URL, enum, relationship)",
inputSchema: {
type: "object",
properties: {
databaseId: { type: "string", description: "ID of the database" },
collectionId: { type: "string", description: "ID of the collection" },
key: { type: "string", description: "Attribute key" },
- size: { type: "number", description: "Maximum size of the string" },
+ type: {
+ type: "string",
+ description: "Attribute type",
+ enum: ["string", "integer", "float", "boolean", "datetime", "email", "ip", "url", "enum", "relationship"]
+ },
required: { type: "boolean", description: "Is attribute required" },
- default: { type: "string", description: "Default value (optional)" }
+ default: { type: "string", description: "Default value (optional)" },
+ size: { type: "number", description: "Size for string/ip/url attributes (optional)" },
+ min: { type: "number", description: "Minimum value for integer/float attributes (optional)" },
+ max: { type: "number", description: "Maximum value for integer/float attributes (optional)" },
+ elements: {
+ type: "array",
+ items: { type: "string" },
+ description: "Array of allowed values for enum attributes (required for enum type)"
+ },
+ relatedCollection: { type: "string", description: "Related collection ID for relationship attributes (required for relationship type)" },
+ relationType: {
+ type: "string",
+ description: "Relationship type (required for relationship type)",
+ enum: ["oneToOne", "oneToMany", "manyToOne", "manyToMany"]
+ },
+ twoWay: { type: "boolean", description: "Is relationship two-way (optional for relationship type)" },
+ twoWayKey: { type: "string", description: "Two-way relationship key (optional for relationship type)" }
},
- required: ["databaseId", "collectionId", "key", "size", "required"]
+ required: ["databaseId", "collectionId", "key", "type", "required"]
}
},
{
- name: "create_integer_attribute",
- description: "Create an integer attribute in a collection",
+ name: "bulk_create_attributes",
+ description: "Create multiple attributes at once in a collection",
inputSchema: {
type: "object",
properties: {
databaseId: { type: "string", description: "ID of the database" },
collectionId: { type: "string", description: "ID of the collection" },
- key: { type: "string", description: "Attribute key" },
- required: { type: "boolean", description: "Is attribute required" },
- min: { type: "number", description: "Minimum value (optional)" },
- max: { type: "number", description: "Maximum value (optional)" },
- default: { type: "number", description: "Default value (optional)" }
+ attributes: {
+ type: "array",
+ description: "Array of attribute definitions",
+ items: {
+ type: "object",
+ properties: {
+ key: { type: "string", description: "Attribute key" },
+ type: {
+ type: "string",
+ description: "Attribute type",
+ enum: ["string", "integer", "float", "boolean", "datetime", "email", "ip", "url", "enum", "relationship"]
+ },
+ required: { type: "boolean", description: "Is attribute required" },
+ default: { type: "string", description: "Default value (optional)" },
+ size: { type: "number", description: "Size for string/ip/url attributes (optional)" },
+ min: { type: "number", description: "Minimum value for integer/float attributes (optional)" },
+ max: { type: "number", description: "Maximum value for integer/float attributes (optional)" },
+ elements: {
+ type: "array",
+ items: { type: "string" },
+ description: "Array of allowed values for enum attributes (required for enum type)"
+ },
+ relatedCollection: { type: "string", description: "Related collection ID for relationship attributes (required for relationship type)" },
+ relationType: {
+ type: "string",
+ description: "Relationship type (required for relationship type)",
+ enum: ["oneToOne", "oneToMany", "manyToOne", "manyToMany"]
+ },
+ twoWay: { type: "boolean", description: "Is relationship two-way (optional for relationship type)" },
+ twoWayKey: { type: "string", description: "Two-way relationship key (optional for relationship type)" }
+ },
+ required: ["key", "type", "required"]
+ }
+ }
},
- required: ["databaseId", "collectionId", "key", "required"]
+ required: ["databaseId", "collectionId", "attributes"]
}
},
{
- name: "create_boolean_attribute",
- description: "Create a boolean attribute in a collection",
+ name: "bulk_delete_attributes",
+ description: "Delete multiple attributes at once from a collection",
inputSchema: {
type: "object",
properties: {
databaseId: { type: "string", description: "ID of the database" },
collectionId: { type: "string", description: "ID of the collection" },
- key: { type: "string", description: "Attribute key" },
- required: { type: "boolean", description: "Is attribute required" },
- default: { type: "boolean", description: "Default value (optional)" }
+ attributeKeys: {
+ type: "array",
+ description: "Array of attribute keys to delete",
+ items: { type: "string" }
+ }
},
- required: ["databaseId", "collectionId", "key", "required"]
- }
- },
- {
- name: "create_email_attribute",
- description: "Create an email attribute in a collection",
- inputSchema: {
- type: "object",
- properties: {
- databaseId: { type: "string", description: "ID of the database" },
- collectionId: { type: "string", description: "ID of the collection" },
- key: { type: "string", description: "Attribute key" },
- required: { type: "boolean", description: "Is attribute required" },
- default: { type: "string", description: "Default value (optional)" }
- },
- required: ["databaseId", "collectionId", "key", "required"]
- }
- },
- {
- name: "create_datetime_attribute",
- description: "Create a datetime attribute in a collection",
- inputSchema: {
- type: "object",
- properties: {
- databaseId: { type: "string", description: "ID of the database" },
- collectionId: { type: "string", description: "ID of the collection" },
- key: { type: "string", description: "Attribute key" },
- required: { type: "boolean", description: "Is attribute required" },
- default: { type: "string", description: "Default value (optional)" }
- },
- required: ["databaseId", "collectionId", "key", "required"]
+ required: ["databaseId", "collectionId", "attributeKeys"]
}
},
{
@@ -476,6 +497,28 @@ class AppwriteMCPServer {
required: ["userId"]
}
},
+ {
+ name: "verify_user_email",
+ description: "Verify a user's email address",
+ inputSchema: {
+ type: "object",
+ properties: {
+ userId: { type: "string", description: "User ID" }
+ },
+ required: ["userId"]
+ }
+ },
+ {
+ name: "unverify_user_email",
+ description: "Unverify a user's email address",
+ inputSchema: {
+ type: "object",
+ properties: {
+ userId: { type: "string", description: "User ID" }
+ },
+ required: ["userId"]
+ }
+ },
// Storage Operations
{
@@ -1040,16 +1083,12 @@ class AppwriteMCPServer {
return await this.deleteCollection(request.params.arguments);
// Attribute Operations
- case "create_string_attribute":
- return await this.createStringAttribute(request.params.arguments);
- case "create_integer_attribute":
- return await this.createIntegerAttribute(request.params.arguments);
- case "create_boolean_attribute":
- return await this.createBooleanAttribute(request.params.arguments);
- case "create_email_attribute":
- return await this.createEmailAttribute(request.params.arguments);
- case "create_datetime_attribute":
- return await this.createDatetimeAttribute(request.params.arguments);
+ case "create_attribute":
+ return await this.createAttribute(request.params.arguments);
+ case "bulk_create_attributes":
+ return await this.bulkCreateAttributes(request.params.arguments);
+ case "bulk_delete_attributes":
+ return await this.bulkDeleteAttributes(request.params.arguments);
case "list_attributes":
return await this.listAttributes(request.params.arguments);
case "delete_attribute":
@@ -1090,6 +1129,10 @@ class AppwriteMCPServer {
return await this.updateUserPassword(request.params.arguments);
case "delete_user":
return await this.deleteUser(request.params.arguments);
+ case "verify_user_email":
+ return await this.verifyUserEmail(request.params.arguments);
+ case "unverify_user_email":
+ return await this.unverifyUserEmail(request.params.arguments);
// Storage Operations
case "create_bucket":
@@ -1316,119 +1359,165 @@ class AppwriteMCPServer {
}
// Attribute Operations
- private async createStringAttribute(args: any) {
+
+ private async createAttribute(args: any) {
if (!this.databases) throw new Error("Databases not initialized");
- const { databaseId, collectionId, key, size, required, default: defaultValue } = args;
-
- const attribute = await this.databases.createStringAttribute(
+ const {
databaseId,
collectionId,
key,
- size,
+ type,
required,
- defaultValue
- );
+ default: defaultValue,
+ size,
+ min,
+ max,
+ elements,
+ relatedCollection,
+ relationType,
+ twoWay,
+ twoWayKey
+ } = args;
+
+ let attribute;
+
+ switch (type) {
+ case 'string':
+ attribute = await this.databases.createStringAttribute(
+ databaseId, collectionId, key, size || 255, required, defaultValue
+ );
+ break;
+ case 'integer':
+ attribute = await this.databases.createIntegerAttribute(
+ databaseId, collectionId, key, required, min, max, defaultValue
+ );
+ break;
+ case 'float':
+ attribute = await this.databases.createFloatAttribute(
+ databaseId, collectionId, key, required, min, max, defaultValue
+ );
+ break;
+ case 'boolean':
+ attribute = await this.databases.createBooleanAttribute(
+ databaseId, collectionId, key, required, defaultValue
+ );
+ break;
+ case 'datetime':
+ attribute = await this.databases.createDatetimeAttribute(
+ databaseId, collectionId, key, required, defaultValue
+ );
+ break;
+ case 'email':
+ attribute = await this.databases.createEmailAttribute(
+ databaseId, collectionId, key, required, defaultValue
+ );
+ break;
+ case 'ip':
+ attribute = await this.databases.createIpAttribute(
+ databaseId, collectionId, key, required, defaultValue
+ );
+ break;
+ case 'url':
+ attribute = await this.databases.createUrlAttribute(
+ databaseId, collectionId, key, required, defaultValue
+ );
+ break;
+ case 'enum':
+ if (!elements || elements.length === 0) {
+ throw new Error("Enum attributes require 'elements' array with allowed values");
+ }
+ attribute = await this.databases.createEnumAttribute(
+ databaseId, collectionId, key, elements, required, defaultValue
+ );
+ break;
+ case 'relationship':
+ if (!relatedCollection || !relationType) {
+ throw new Error("Relationship attributes require 'relatedCollection' and 'relationType'");
+ }
+ attribute = await this.databases.createRelationshipAttribute(
+ databaseId, collectionId, relatedCollection, relationType, twoWay, key, twoWayKey
+ );
+ break;
+ default:
+ throw new Error(`Unsupported attribute type: ${type}`);
+ }
return {
content: [
{
type: "text",
- text: `String attribute '${key}' created successfully in collection ${collectionId}`
+ text: `${type.charAt(0).toUpperCase() + type.slice(1)} attribute '${key}' created successfully in collection ${collectionId}`
}
]
};
}
- private async createIntegerAttribute(args: any) {
+ private async bulkCreateAttributes(args: any) {
if (!this.databases) throw new Error("Databases not initialized");
- const { databaseId, collectionId, key, required, min, max, default: defaultValue } = args;
+ const { databaseId, collectionId, attributes } = args;
- const attribute = await this.databases.createIntegerAttribute(
- databaseId,
- collectionId,
- key,
- required,
- min,
- max,
- defaultValue
- );
+ const results = [];
+ const errors = [];
+
+ for (const attr of attributes) {
+ try {
+ await this.createAttribute({
+ databaseId,
+ collectionId,
+ ...attr
+ });
+ results.push(`✅ ${attr.key} (${attr.type})`);
+ } catch (error) {
+ errors.push(`❌ ${attr.key} (${attr.type}): ${error}`);
+ }
+ }
return {
content: [
{
type: "text",
- text: `Integer attribute '${key}' created successfully in collection ${collectionId}`
+ text: `Bulk Attribute Creation Results:
+
+Successful (${results.length}):
+${results.join('\n')}
+
+${errors.length > 0 ? `Failed (${errors.length}):
+${errors.join('\n')}` : ''}`
}
]
};
}
- private async createBooleanAttribute(args: any) {
+ private async bulkDeleteAttributes(args: any) {
if (!this.databases) throw new Error("Databases not initialized");
- const { databaseId, collectionId, key, required, default: defaultValue } = args;
+ const { databaseId, collectionId, attributeKeys } = args;
- const attribute = await this.databases.createBooleanAttribute(
- databaseId,
- collectionId,
- key,
- required,
- defaultValue
- );
+ const results = [];
+ const errors = [];
+
+ for (const key of attributeKeys) {
+ try {
+ await this.databases.deleteAttribute(databaseId, collectionId, key);
+ results.push(`✅ ${key}`);
+ } catch (error) {
+ errors.push(`❌ ${key}: ${error}`);
+ }
+ }
return {
content: [
{
type: "text",
- text: `Boolean attribute '${key}' created successfully in collection ${collectionId}`
- }
- ]
- };
- }
+ text: `Bulk Attribute Deletion Results:
- private async createEmailAttribute(args: any) {
- if (!this.databases) throw new Error("Databases not initialized");
-
- const { databaseId, collectionId, key, required, default: defaultValue } = args;
-
- const attribute = await this.databases.createEmailAttribute(
- databaseId,
- collectionId,
- key,
- required,
- defaultValue
- );
-
- return {
- content: [
- {
- type: "text",
- text: `Email attribute '${key}' created successfully in collection ${collectionId}`
- }
- ]
- };
- }
+Successful (${results.length}):
+${results.join('\n')}
- private async createDatetimeAttribute(args: any) {
- if (!this.databases) throw new Error("Databases not initialized");
-
- const { databaseId, collectionId, key, required, default: defaultValue } = args;
-
- const attribute = await this.databases.createDatetimeAttribute(
- databaseId,
- collectionId,
- key,
- required,
- defaultValue
- );
-
- return {
- content: [
- {
- type: "text",
- text: `Datetime attribute '${key}' created successfully in collection ${collectionId}`
+${errors.length > 0 ? `Failed (${errors.length}):
+${errors.join('\n')}` : ''}`
}
]
};
@@ -1665,7 +1754,7 @@ class AppwriteMCPServer {
const users = await this.users.list(queries || []);
const userList = users.users.map((user: any) =>
- `- ${user.name || 'No name'} (${user.email}) - ID: ${user.$id}`
+ `- ${user.name || 'No name'} (${user.email}) - ID: ${user.$id} - ${user.emailVerification ? '✅ Verified' : '❌ Unverified'}`
).join('\n');
return {
@@ -1763,6 +1852,40 @@ class AppwriteMCPServer {
};
}
+ private async verifyUserEmail(args: any) {
+ if (!this.users) throw new Error("Users service not initialized");
+
+ const { userId } = args;
+
+ await this.users.updateEmailVerification(userId, true);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: `User ${userId} email verification status updated to verified ✅`
+ }
+ ]
+ };
+ }
+
+ private async unverifyUserEmail(args: any) {
+ if (!this.users) throw new Error("Users service not initialized");
+
+ const { userId } = args;
+
+ await this.users.updateEmailVerification(userId, false);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: `User ${userId} email verification status updated to unverified ❌`
+ }
+ ]
+ };
+ }
+
// Storage Operations
private async createBucket(args: any) {
if (!this.storage) throw new Error("Storage service not initialized");