#
tokens: 7054/50000 10/10 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .gitignore
├── assets
│   ├── demo-claude.gif
│   └── demo-cline.gif
├── Dockerfile
├── LICENSE
├── package.json
├── README.md
├── smithery.yaml
├── src
│   ├── handlers.ts
│   ├── index.ts
│   ├── tools.ts
│   └── types.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
node_modules/
build/
backup/
*.log
.env*
.DS_Store
.package-lock.json

```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# MCP Server for ArangoDB

[![smithery badge](https://smithery.ai/badge/@ravenwits/mcp-server-arangodb)](https://smithery.ai/server/@ravenwits/mcp-server-arangodb)

A Model Context Protocol server for ArangoDB

This is a TypeScript-based MCP server that provides database interaction capabilities through ArangoDB. It implements core database operations and allows seamless integration with ArangoDB through MCP tools. You can use it wih Claude app and also extension for VSCode that works with mcp like Cline!

## Features

### Tools

- `arango_query` - Execute AQL queries

  - Takes an AQL query string as required parameter
  - Optionally accepts bind variables for parameterized queries
  - Returns query results as JSON

- `arango_insert` - Insert documents into collections

  - Takes collection name and document object as required parameters
  - Automatically generates document key if not provided
  - Returns the created document metadata

- `arango_update` - Update existing documents

  - Takes collection name, document key, and update object as required parameters
  - Returns the updated document metadata

- `arango_remove` - Remove documents from collections

  - Takes collection name and document key as required parameters
  - Returns the removed document metadata

- `arango_backup` - Backup all collections to JSON files

  - Takes output directory path as required parameter
  - Creates JSON files for each collection with current data
  - Useful for data backup and migration purposes

- `arango_list_collections` - List all collections in the database

  - Returns array of collection information including names, IDs, and types

- `arango_create_collection` - Create a new collection in the database
  - Takes collection name as required parameter
  - Optionally specify collection type (document or edge collection)
  - Configure waitForSync behavior for write operations
  - Returns collection information including name, type, and status

## Installation

### Installing via NPM

To install `arango-server` globally via NPM, run the following command:

```bash
npm install -g arango-server
```

### Running via NPX

To run `arango-server` directly without installation, use the following command:

```bash
npx arango-server
```

### Configuring for VSCode Agent

To use `arango-server` with the VSCode Copilot agent, you must have at least **VSCode 1.99.0 installed** and follow these steps:

1. **Create or edit the MCP configuration file**:

   - **Workspace-specific configuration**: Create or edit the `.vscode/mcp.json` file in your workspace.
   - **User-specific configuration**: Optionally, specify the server in the [setting(mcp)](vscode://settings/mcp) VS Code [user settings](https://code.visualstudio.com/docs/getstarted/personalize-vscode#_configure-settings) to enable the MCP server across all workspaces.

     _Tip: You can refer [here](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) to the MCP configuration documentation of VSCode for more details on how to set up the configuration file._

2. **Add the following configuration**:

   ```json
   {
   	"servers": {
   		"arango-mcp": {
   			"type": "stdio",
   			"command": "npx",
   			"args": ["arango-server"],
   			"env": {
   				"ARANGO_URL": "http://localhost:8529",
   				"ARANGO_DB": "v20",
   				"ARANGO_USERNAME": "app",
   				"ARANGO_PASSWORD": "75Sab@MYa3Dj8Fc"
   			}
   		}
   	}
   }
   ```

3. **Start the MCP server**:

   - Open the Command Palette in VSCode (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac).
   - Run the command `MCP: Start Server` and select `arango-mcp` from the list.

4. **Verify the server**:
   - Open the Chat view in VSCode and switch to Agent mode.
   - Use the `Tools` button to verify that the `arango-server` tools are available.

### Installing via Smithery

To install ArangoDB for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@ravenwits/mcp-server-arangodb):

```bash
npx -y @smithery/cli install @ravenwits/mcp-server-arangodb --client claude
```

#### To use with Claude Desktop

Go to: `Settings > Developer > Edit Config` or

- MacOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%/Claude/claude_desktop_config.json`

#### To use with Cline VSCode Extension

Go to: `Cline Extension > MCP Servers > Edit Configuration` or

- MacOS: `~/Library/Application Support/Code/User/globalStorage/cline.cline/config.json`
- Windows: `%APPDATA%/Code/User/globalStorage/cline.cline/config.json`

Add the following configuration to the `mcpServers` section:

```json
{
	"mcpServers": {
		"arango": {
			"command": "node",
			"args": ["/path/to/arango-server/build/index.js"],
			"env": {
				"ARANGO_URL": "your_database_url",
				"ARANGO_DB": "your_database_name",
				"ARANGO_USERNAME": "your_username",
				"ARANGO_PASSWORD": "your_password"
			}
		}
	}
}
```

### Environment Variables

The server requires the following environment variables:

- `ARANGO_URL` - ArangoDB server URL (note: 8529 is the default port for ArangoDB for local development)
- `ARANGO_DB` - Database name
- `ARANGO_USERNAME` - Database user
- `ARANGO_PASSWORD` - Database password

## Usage

You can pretty much provide any meaningful prompt and Claude will try to execute the appropriate function.

Some example propmts:

- "List all collections in the database"
- "Query all users"
- "Insert a new document with name 'John Doe' and email "<[email protected]>' to the 'users' collection"
- "Update the document with key '123456' or name 'Jane Doe' to change the age to 48"
- "Create a new collection named 'products'"

### Usage with Claude App

![Demo of using ArangoDB MCP server with Claude App](./assets/demo-claude.gif)

### Uasge with Cline VSCode extension

![Demo of using ArangoDB MCP server with Cline VSCode extension](./assets/demo-cline.gif)

Query all users:

```typescript
{
  "query": "FOR user IN users RETURN user"
}
```

Insert a new document:

```typescript
{
  "collection": "users",
  "document": {
    "name": "John Doe",
    "email": "[email protected]"
  }
}
```

Update a document:

```typescript
{
  "collection": "users",
  "key": "123456",
  "update": {
    "name": "Jane Doe"
  }
}
```

Remove a document:

```typescript
{
  "collection": "users",
  "key": "123456"
}
```

List all collections:

```typescript
{
} // No parameters required
```

Backup database collections:

```typescript
{
  "outputDir": "./backup" // Specify an absolute output directory path for the backup files (optional)
  "collection": "users" // Specify a collection name to backup (optional) If no collection name is provided, all collections will be backed up
  "docLimit": 1000 // Specify the maximum number of documents to backup per collection (optional), if not provided, all documents will be backed up (not having a limit might cause timeout for large collections)
}
```

Create a new collection:

```typescript
{
  "name": "products",
  "type": "document", // "document" or "edge" (optional, defaults to "document")
  "waitForSync": false // Optional, defaults to false
}
```

Note: The server is database-structure agnostic and can work with any collection names or structures as long as they follow ArangoDB's document and edge collection models.

## Disclaimer

### For Development Use Only

This tool is designed for local development environments only. While technically it could connect to a production database, this would create significant security risks and is explicitly discouraged. We use it exclusively with our development databases to maintain separation of concerns and protect production data.

## Development

1. Clone the repository
2. Install dependencies:

   ```bash
   npm run build
   ```

3. For development with auto-rebuild:

   ```bash
   npm run watch
   ```

### Debugging

Since MCP servers communicate over stdio, debugging can be challenging. recommended debugging can be done by using [MCP Inspector](https://github.com/modelcontextprotocol/inspector) for development:

```bash
npm run inspector
```

The Inspector will provide a URL to access debugging tools in your browser.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

```

--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------

```typescript
import { CollectionType } from 'arangojs/collection';

// Type definitions for request arguments
export interface BackupArgs {
	outputDir: string;
	collection?: string;
	docLimit?: number;
}

export interface QueryArgs {
	query: string;
	bindVars?: Record<string, unknown>;
}

export interface CollectionDocumentArgs {
	collection: string;
	document: Record<string, unknown>;
}

export interface CollectionKeyArgs {
	collection: string;
	key: string;
}

export interface UpdateDocumentArgs extends CollectionKeyArgs {
	update: Record<string, unknown>;
}

export interface CreateCollectionArgs {
	name: string;
	type?: 'document' | 'edge'; // Changed from CollectionType to string literals
	waitForSync?: boolean;
}

```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
# Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml

startCommand:
  type: stdio
  configSchema:
    # JSON Schema defining the configuration options for the MCP.
    type: object
    required:
      - arangoUrl
      - arangoDb
      - arangoUsername
      - arangoPassword
    properties:
      arangoUrl:
        type: string
        description: The URL of the ArangoDB server.
      arangoDb:
        type: string
        description: The name of the database to connect to.
      arangoUsername:
        type: string
        description: The username for database authentication.
      arangoPassword:
        type: string
        description: The password for database authentication.
  commandFunction:
    # A function that produces the CLI command to start the MCP on stdio.
    |-
    (config) => ({command: 'node', args: ['build/index.js'], env: {ARANGO_URL: config.arangoUrl, ARANGO_DB: config.arangoDatabase, ARANGO_USERNAME: config.arangoUsername, ARANGO_PASSWORD: config.arangoPassword}})

```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
# Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile
# Use a Node.js image
FROM node:22.12-alpine AS builder

# Create app directory
WORKDIR /app

# Install app dependencies
COPY package.json package-lock.json ./
RUN npm install --ignore-scripts

# Copy source code and build the project
COPY . .
RUN npm run build

# Use a smaller base image for the final build
FROM node:22-alpine AS release

# Create app directory
WORKDIR /app

# Copy the built files and node_modules from the builder stage
COPY --from=builder /app/build /app/build
COPY --from=builder /app/package.json /app/package.json
COPY --from=builder /app/package-lock.json /app/package-lock.json
COPY --from=builder /app/node_modules /app/node_modules

# Expose the default ArangoDB port
EXPOSE 8529

# Set environment variables (these should be overridden at runtime)
ENV ARANGO_URL=http://localhost:8529
ENV ARANGO_DB=your_database_name
ENV ARANGO_USERNAME=your_username
ENV ARANGO_PASSWORD=your_password

# Command to run the server
CMD ["node", "build/index.js"]

```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
	"name": "arango-server",
	"version": "0.4.4",
	"description": "A Model Context Protocol Server for ArangoDB",
	"type": "module",
	"bin": {
		"arango-server": "./build/index.js"
	},
	"files": [
		"build"
	],
	"scripts": {
		"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
		"prepare": "npm run build",
		"watch": "tsc --watch",
		"inspector": "npx @modelcontextprotocol/inspector build/index.js",
		"dev": "tsc --watch",
		"start": "node build/index.js",
		"test": "jest",
		"lint": "eslint . --ext .ts",
		"format": "prettier --write \"src/**/*.ts\""
	},
	"keywords": [
		"arango",
		"arangodb",
		"mcp",
		"model-context-protocol"
	],
	"repository": {
		"type": "git",
		"url": "git+https://github.com/ravenwits/mcp-server-arangodb.git"
	},
	"homepage": "https://github.com/ravenwits/mcp-server-arangodb#readme",
	"author": "Alp Sarıyer <[email protected]>",
	"license": "MIT",
	"dependencies": {
		"@modelcontextprotocol/sdk": "0.6.0",
		"arangojs": "^9.2.0"
	},
	"devDependencies": {
		"@types/node": "^20.11.24",
		"typescript": "^5.3.3"
	}
}

```

--------------------------------------------------------------------------------
/src/tools.ts:
--------------------------------------------------------------------------------

```typescript
import { Tool } from '@modelcontextprotocol/sdk/types.js';
import { CollectionType } from 'arangojs/collection';

export function createToolDefinitions(): Tool[] {
	return [
		{
			name: API_TOOLS.QUERY as string,
			description: 'Execute an AQL query',
			inputSchema: {
				type: 'object',
				properties: {
					query: {
						type: 'string',
						description: 'AQL query string',
					},
					bindVars: {
						type: 'object',
						description: 'Query bind variables',
						additionalProperties: { type: 'object' },
					},
				},
				required: ['query'],
			},
		},
		{
			name: API_TOOLS.INSERT as string,
			description: 'Insert a document into a collection',
			inputSchema: {
				type: 'object',
				properties: {
					collection: {
						type: 'string',
						description: 'Collection name',
					},
					document: {
						type: 'object',
						description: 'Document to insert',
						additionalProperties: { type: 'object' },
					},
				},
				required: ['collection', 'document'],
			},
		},
		{
			name: API_TOOLS.UPDATE as string,
			description: 'Update a document in a collection',
			inputSchema: {
				type: 'object',
				properties: {
					collection: {
						type: 'string',
						description: 'Collection name',
					},
					key: {
						type: 'string',
						description: 'Document key',
					},
					update: {
						type: 'object',
						description: 'Update object',
						additionalProperties: { type: 'object' },
					},
				},
				required: ['collection', 'key', 'update'],
			},
		},
		{
			name: API_TOOLS.REMOVE as string,
			description: 'Remove a document from a collection',
			inputSchema: {
				type: 'object',
				properties: {
					collection: {
						type: 'string',
						description: 'Collection name',
					},
					key: {
						type: 'string',
						description: 'Document key',
					},
				},
				required: ['collection', 'key'],
			},
		},
		{
			name: API_TOOLS.BACKUP as string,
			description: 'Backup collections to JSON files.',
			inputSchema: {
				type: 'object',
				properties: {
					outputDir: {
						type: 'string',
						description: 'An absolute directory path to store backup files',
						default: './backup',
						optional: true,
					},
					collection: {
						type: 'string',
						description: 'Collection name to backup. If not provided, backs up all collections.',
						optional: true,
					},
					docLimit: {
						type: 'integer',
						description: 'Limit the number of documents to backup. If not provided, backs up all documents.',
						optional: true,
					},
				},
				required: ['outputDir'],
			},
		},
		{
			name: API_TOOLS.COLLECTIONS as string,
			description: 'List all collections in the database',
			inputSchema: {
				type: 'object',
				properties: {},
			},
		},
		{
			name: API_TOOLS.CREATE_COLLECTION as string,
			description: 'Create a new collection in the database',
			inputSchema: {
				type: 'object',
				properties: {
					name: {
						type: 'string',
						description: 'Name of the collection to create',
					},
					type: {
						type: 'string',
						description: 'Type of collection to create ("document" or "edge")',
						default: 'document',
						enum: ['document', 'edge'],
					},
					waitForSync: {
						type: 'boolean',
						description: 'If true, wait for data to be synchronized to disk before returning',
						default: false,
					},
				},
				required: ['name'],
			},
		},
	];
}

export enum API_TOOLS {
	QUERY = 'arango_query',
	INSERT = 'arango_insert',
	UPDATE = 'arango_update',
	REMOVE = 'arango_remove',
	BACKUP = 'arango_backup',
	COLLECTIONS = 'arango_list_collections',
	CREATE_COLLECTION = 'arango_create_collection',
}

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { Database } from 'arangojs';
import { readFileSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import { createToolDefinitions } from './tools.js';
import { ToolHandlers } from './handlers.js';

// Get package version from package.json
const __dirname = dirname(fileURLToPath(import.meta.url));
const packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
const MAX_RECONNECTION_ATTEMPTS = 3;
const RECONNECTION_DELAY = 1000; // 1 second

// Get connection details from environment variables
const ARANGO_URL = process.env.ARANGO_URL || 'http://localhost:8529';
const ARANGO_DB = process.env.ARANGO_DB || '_system';
const ARANGO_USERNAME = process.env.ARANGO_USERNAME;
const ARANGO_PASSWORD = process.env.ARANGO_PASSWORD;
const TOOLS = createToolDefinitions();

if (!ARANGO_USERNAME || !ARANGO_PASSWORD) {
	throw new Error('ARANGO_USERNAME and ARANGO_PASSWORD environment variables are required');
}

class ArangoServer {
	private server: Server;
	private db!: Database; // Using definite assignment assertion
	private isConnected: boolean = false;
	private reconnectionAttempts: number = 0;
	private toolHandlers: ToolHandlers;

	constructor() {
		this.initializeDatabase();

		// Initialize MCP server
		this.server = new Server(
			{
				name: 'arango-server',
				version: packageJson.version,
			},
			{
				capabilities: {
					tools: {},
				},
			},
		);

		// Initialize tool handlers
		this.toolHandlers = new ToolHandlers(this.db, TOOLS, this.ensureConnection.bind(this));

		// Set up request handlers
		this.server.setRequestHandler(ListToolsRequestSchema, () => this.toolHandlers.handleListTools());
		this.server.setRequestHandler(CallToolRequestSchema, (request) => this.toolHandlers.handleCallTool(request));

		// Error handling
		this.server.onerror = (error) => console.error('[MCP Error]', error);
		process.on('SIGINT', async () => {
			await this.server.close();
			process.exit(0);
		});
	}

	private async initializeDatabase() {
		try {
			this.db = new Database([ARANGO_URL]);
			this.db.useBasicAuth(ARANGO_USERNAME, ARANGO_PASSWORD);
			this.db = this.db.database(ARANGO_DB);

			// Test connection
			await this.checkConnection();
			this.isConnected = true;
			this.reconnectionAttempts = 0;
			console.info('Successfully connected to ArangoDB');
		} catch (error) {
			console.error('Failed to initialize database:', error instanceof Error ? error.message : 'Unknown error');
			await this.handleConnectionError();
		}
	}

	private async checkConnection(): Promise<void> {
		try {
			await this.db.version();
		} catch (error) {
			this.isConnected = false;
			throw error;
		}
	}

	private async handleConnectionError(): Promise<void> {
		if (this.reconnectionAttempts >= MAX_RECONNECTION_ATTEMPTS) {
			throw new Error(`Failed to connect after ${MAX_RECONNECTION_ATTEMPTS} attempts`);
		}

		this.reconnectionAttempts++;
		console.error(`Attempting to reconnect (${this.reconnectionAttempts}/${MAX_RECONNECTION_ATTEMPTS})...`);

		await new Promise((resolve) => setTimeout(resolve, RECONNECTION_DELAY));
		await this.initializeDatabase();
	}

	private async ensureConnection(): Promise<void> {
		if (!this.isConnected) {
			await this.handleConnectionError();
		}
	}

	async run() {
		const transport = new StdioServerTransport();
		await this.server.connect(transport);
		console.error('ArangoDB MCP server running on stdio');
	}
}

const server = new ArangoServer();
server.run().catch(console.error);

```

--------------------------------------------------------------------------------
/src/handlers.ts:
--------------------------------------------------------------------------------

```typescript
import { ErrorCode, McpError, Request, Tool } from '@modelcontextprotocol/sdk/types.js';
import { Database } from 'arangojs';
import { CollectionStatus, CollectionType, CreateCollectionOptions } from 'arangojs/collection';
import { promises as fs } from 'fs';
import { join, resolve } from 'path';
import { API_TOOLS } from './tools.js';
import { BackupArgs, CollectionDocumentArgs, CollectionKeyArgs, CreateCollectionArgs, QueryArgs, UpdateDocumentArgs } from './types.js';

const PARALLEL_BACKUP_CHUNKS = 5;

export class ToolHandlers {
	constructor(private db: Database, private tools: Tool[], private ensureConnection: () => Promise<void>) {}

	async handleListTools() {
		return {
			tools: this.tools,
		};
	}

	async handleCallTool(request: Request) {
		try {
			await this.ensureConnection();

			switch (request.params?.name) {
				case API_TOOLS.QUERY: {
					const args = request.params.arguments as QueryArgs;
					try {
						const cursor = await this.db.query(args.query, args.bindVars || {});
						const result = await cursor.all();
						return {
							content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
						};
					} catch (error) {
						throw new McpError(ErrorCode.InvalidRequest, `Query execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
					}
				}

				case API_TOOLS.INSERT: {
					const args = request.params.arguments as CollectionDocumentArgs;
					try {
						const coll = this.db.collection(args.collection);
						const result = await coll.save(args.document);
						return {
							content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
						};
					} catch (error) {
						throw new McpError(ErrorCode.InvalidRequest, `Insert operation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
					}
				}

				case API_TOOLS.UPDATE: {
					const args = request.params.arguments as UpdateDocumentArgs;
					try {
						const coll = this.db.collection(args.collection);
						const result = await coll.update(args.key, args.update);
						return {
							content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
						};
					} catch (error) {
						throw new McpError(ErrorCode.InvalidRequest, `Update operation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
					}
				}

				case API_TOOLS.REMOVE: {
					const args = request.params.arguments as CollectionKeyArgs;
					try {
						const coll = this.db.collection(args.collection);
						const result = await coll.remove(args.key);
						return {
							content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
						};
					} catch (error) {
						throw new McpError(ErrorCode.InvalidRequest, `Remove operation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
					}
				}

				case API_TOOLS.COLLECTIONS: {
					try {
						const collections = await this.db.listCollections();
						return {
							content: [{ type: 'text', text: JSON.stringify(collections, null, 2) }],
						};
					} catch (error) {
						throw new McpError(ErrorCode.InternalError, `Failed to list collections: ${error instanceof Error ? error.message : 'Unknown error'}`);
					}
				}

				case API_TOOLS.CREATE_COLLECTION: {
					const args = request.params.arguments as CreateCollectionArgs;
					try {
						const options: CreateCollectionOptions & { type?: CollectionType } = {
							waitForSync: args.waitForSync || false,
						};

						// Map string type to CollectionType enum
						if (args.type === 'edge') {
							options.type = CollectionType.EDGE_COLLECTION;
						} else {
							// Default to document collection
							options.type = CollectionType.DOCUMENT_COLLECTION;
						}

						const collection = await this.db.createCollection(
							args.name,
							options as CreateCollectionOptions & {
								type: typeof options.type extends CollectionType.EDGE_COLLECTION ? CollectionType.EDGE_COLLECTION : CollectionType.DOCUMENT_COLLECTION;
							},
						);

						// Return a simplified response without circular references
						const properties = await collection.properties();
						const response = {
							name: collection.name,
							indexes: collection.indexes(),
							type: CollectionType[properties.type],
							status: CollectionStatus[properties.status],
						};

						return {
							content: [{ type: 'text', text: JSON.stringify(response, null, 2) }],
						};
					} catch (error) {
						throw new McpError(ErrorCode.InvalidRequest, `Failed to create collection: ${error instanceof Error ? error.message : 'Unknown error'}`);
					}
				}

				case API_TOOLS.BACKUP: {
					const args = request.params.arguments as BackupArgs;
					const outputDir = resolve(args.outputDir);
					const collection = args.collection;
					const docLimit = args.docLimit;

					try {
						await fs.mkdir(outputDir, { recursive: true, mode: 0o755 });
					} catch (error) {
						throw new McpError(ErrorCode.InternalError, `Failed to create backup directory: ${error instanceof Error ? error.message : 'Unknown error'}`);
					}

					try {
						const results = [];
						async function backupCollection(db: Database, outputDir: string, collection?: string, docLimit?: number) {
							try {
								const cursor = await db.query({
									query: docLimit ? 'FOR doc IN @@collection LIMIT @limit RETURN doc' : 'FOR doc IN @@collection RETURN doc',
									bindVars: {
										'@collection': collection,
										...(docLimit && { limit: docLimit }),
									},
								});
								const data = await cursor.all();
								const filePath = join(outputDir, `${collection}.json`);
								await fs.writeFile(filePath, JSON.stringify(data, null, 2));
								return {
									collection,
									status: 'success',
									count: data.length,
									outputFile: filePath,
								};
							} catch (error) {
								return {
									collection,
									status: 'error',
									error: error instanceof Error ? error.message : 'Unknown error',
								};
							}
						}

						if (collection) {
							// Backup single collection
							console.info(`Backing up collection: ${collection}`);
							results.push(await backupCollection(this.db, outputDir, collection, docLimit));
						} else {
							// Backup all collections in parallel chunks
							const collections = await this.db.listCollections();
							console.info(`Found ${collections.length} collections to backup.`);

							// Process collections in chunks
							for (let i = 0; i < collections.length; i += PARALLEL_BACKUP_CHUNKS) {
								const chunk = collections.slice(i, i + PARALLEL_BACKUP_CHUNKS);
								const backupPromises = chunk.map((collection) => {
									console.info(`Backing up collection: ${collection.name}`);
									return backupCollection(this.db, outputDir, collection.name, docLimit);
								});

								// Wait for the current chunk to complete before processing the next
								const chunkResults = await Promise.all(backupPromises);
								results.push(...chunkResults);
							}
						}

						return {
							content: [
								{
									type: 'text',
									text: JSON.stringify(
										{
											status: 'completed',
											outputDirectory: outputDir,
											results,
										},
										null,
										2,
									),
								},
							],
						};
					} catch (error) {
						throw new McpError(ErrorCode.InternalError, `Backup failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
					}
				}

				default:
					throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params?.name}`);
			}
		} catch (error: unknown) {
			if (error instanceof McpError) throw error;

			// Check if it's a connection error
			if (error instanceof Error && error.message.includes('connect')) {
				throw new McpError(ErrorCode.InternalError, `Database connection lost: ${error.message}`);
			}

			throw new McpError(ErrorCode.InternalError, `Database error: ${error instanceof Error ? error.message : 'Unknown error'}`);
		}
	}
}

```