From 1c9f4e94aeea42ddeaa9d38762b716fdb89e1b07 Mon Sep 17 00:00:00 2001 From: Artemiy Vereshchinskiy Date: Tue, 15 Jul 2025 00:05:45 +0700 Subject: [PATCH] Implemented MCP server --- packages/mcp-server/.env.example | 8 + packages/mcp-server/Dockerfile | 16 + packages/mcp-server/EXAMPLES.md | 63 ++ packages/mcp-server/README.md | 97 +++ packages/mcp-server/esbuild.config.js | 93 +++ packages/mcp-server/glama.json | 7 + packages/mcp-server/index.ts | 510 ++++++++++++++++ packages/mcp-server/package.json | 39 ++ packages/mcp-server/tools.ts | 556 ++++++++++++++++++ packages/mcp-server/tools/AttachRelation.ts | 44 ++ .../mcp-server/tools/BulkCreateRecords.ts | 40 ++ .../mcp-server/tools/BulkDeleteRecords.ts | 42 ++ packages/mcp-server/tools/CreateRecord.ts | 28 + packages/mcp-server/tools/DeleteProperty.ts | 27 + packages/mcp-server/tools/DeleteRecord.ts | 27 + packages/mcp-server/tools/DeleteRecordById.ts | 27 + packages/mcp-server/tools/DetachRelation.ts | 44 ++ packages/mcp-server/tools/ExportRecords.ts | 51 ++ packages/mcp-server/tools/FindOneRecord.ts | 27 + packages/mcp-server/tools/FindProperty.ts | 29 + packages/mcp-server/tools/FindPropertyById.ts | 24 + packages/mcp-server/tools/FindRecords.ts | 43 ++ packages/mcp-server/tools/FindRelations.ts | 36 ++ packages/mcp-server/tools/FindUniqRecord.ts | 27 + packages/mcp-server/tools/GetLabels.ts | 30 + packages/mcp-server/tools/GetProperties.ts | 27 + packages/mcp-server/tools/GetRecord.ts | 24 + packages/mcp-server/tools/GetSettings.ts | 23 + packages/mcp-server/tools/HelpAddToClient.ts | 66 +++ packages/mcp-server/tools/OpenBrowser.ts | 54 ++ packages/mcp-server/tools/PropertyValues.ts | 36 ++ packages/mcp-server/tools/SetRecord.ts | 27 + packages/mcp-server/tools/TransactionBegin.ts | 29 + .../mcp-server/tools/TransactionCommit.ts | 28 + packages/mcp-server/tools/TransactionGet.ts | 27 + .../mcp-server/tools/TransactionRollback.ts | 28 + packages/mcp-server/tools/UpdateRecord.ts | 27 + packages/mcp-server/tsconfig.json | 113 ++++ packages/mcp-server/util/db.ts | 32 + packages/mcp-server/vitest.config.ts | 27 + pnpm-lock.yaml | 526 +---------------- 41 files changed, 2534 insertions(+), 495 deletions(-) create mode 100644 packages/mcp-server/.env.example create mode 100644 packages/mcp-server/Dockerfile create mode 100644 packages/mcp-server/EXAMPLES.md create mode 100644 packages/mcp-server/README.md create mode 100644 packages/mcp-server/esbuild.config.js create mode 100644 packages/mcp-server/glama.json create mode 100644 packages/mcp-server/index.ts create mode 100644 packages/mcp-server/package.json create mode 100644 packages/mcp-server/tools.ts create mode 100644 packages/mcp-server/tools/AttachRelation.ts create mode 100644 packages/mcp-server/tools/BulkCreateRecords.ts create mode 100644 packages/mcp-server/tools/BulkDeleteRecords.ts create mode 100644 packages/mcp-server/tools/CreateRecord.ts create mode 100644 packages/mcp-server/tools/DeleteProperty.ts create mode 100644 packages/mcp-server/tools/DeleteRecord.ts create mode 100644 packages/mcp-server/tools/DeleteRecordById.ts create mode 100644 packages/mcp-server/tools/DetachRelation.ts create mode 100644 packages/mcp-server/tools/ExportRecords.ts create mode 100644 packages/mcp-server/tools/FindOneRecord.ts create mode 100644 packages/mcp-server/tools/FindProperty.ts create mode 100644 packages/mcp-server/tools/FindPropertyById.ts create mode 100644 packages/mcp-server/tools/FindRecords.ts create mode 100644 packages/mcp-server/tools/FindRelations.ts create mode 100644 packages/mcp-server/tools/FindUniqRecord.ts create mode 100644 packages/mcp-server/tools/GetLabels.ts create mode 100644 packages/mcp-server/tools/GetProperties.ts create mode 100644 packages/mcp-server/tools/GetRecord.ts create mode 100644 packages/mcp-server/tools/GetSettings.ts create mode 100644 packages/mcp-server/tools/HelpAddToClient.ts create mode 100644 packages/mcp-server/tools/OpenBrowser.ts create mode 100644 packages/mcp-server/tools/PropertyValues.ts create mode 100644 packages/mcp-server/tools/SetRecord.ts create mode 100644 packages/mcp-server/tools/TransactionBegin.ts create mode 100644 packages/mcp-server/tools/TransactionCommit.ts create mode 100644 packages/mcp-server/tools/TransactionGet.ts create mode 100644 packages/mcp-server/tools/TransactionRollback.ts create mode 100644 packages/mcp-server/tools/UpdateRecord.ts create mode 100644 packages/mcp-server/tsconfig.json create mode 100644 packages/mcp-server/util/db.ts create mode 100644 packages/mcp-server/vitest.config.ts diff --git a/packages/mcp-server/.env.example b/packages/mcp-server/.env.example new file mode 100644 index 00000000..d7542499 --- /dev/null +++ b/packages/mcp-server/.env.example @@ -0,0 +1,8 @@ +# This is an example .env file for the RushDB MCP Server +# Copy this to .env and update with your actual values + +# Required: Your RushDB API key +RUSHDB_API_KEY=your-rushdb-api-key-here + +# The server will automatically use this environment variable +# when running the MCP server diff --git a/packages/mcp-server/Dockerfile b/packages/mcp-server/Dockerfile new file mode 100644 index 00000000..b9325fc4 --- /dev/null +++ b/packages/mcp-server/Dockerfile @@ -0,0 +1,16 @@ +FROM node:23.11-slim AS node_base +WORKDIR /app + +FROM node_base AS builder +COPY package.json package-lock.json tsconfig.json ./ +RUN --mount=type=cache,target=/root/.npm npm ci --ignore-scripts --omit-dev + +COPY . ./ +RUN --mount=type=cache,target=/root/.npm npm run build + +FROM node_base +COPY package.json package-lock.json ./ +COPY --from=builder /app/build ./build +ENV NODE_ENV=production +RUN --mount=type=cache,target=/root/.npm npm ci --ignore-scripts --omit-dev +ENTRYPOINT ["node", "/app/build/index.js"] diff --git a/packages/mcp-server/EXAMPLES.md b/packages/mcp-server/EXAMPLES.md new file mode 100644 index 00000000..49512706 --- /dev/null +++ b/packages/mcp-server/EXAMPLES.md @@ -0,0 +1,63 @@ +# Example Configuration + +Here are example configurations for different MCP clients: + +## Claude Desktop + +Add this to your `claude_desktop_config.json` file: + +```json +{ + "mcpServers": { + "rushdb": { + "command": "npx", + "args": ["@rushdb/mcp-server"], + "env": { + "RUSHDB_API_KEY": "your-rushdb-api-key-here" + } + } + } +} +``` + +## VS Code MCP Extension + +If you're using a VS Code MCP extension, add this to your settings: + +```json +{ + "mcp.servers": { + "rushdb": { + "command": "npx", + "args": ["@rushdb/mcp-server"], + "env": { + "RUSHDB_API_KEY": "your-rushdb-api-key-here" + } + } + } +} +``` + +## Example Usage + +Once configured, you can use the RushDB MCP server like this: + +### Create a record +``` +Create a new customer record with name "John Doe", email "john@example.com", and age 30 +``` + +### Find records +``` +Find all customers with age greater than 25 +``` + +### Create relationships +``` +Attach a "PURCHASED" relationship from customer ID abc123 to product ID def456 +``` + +### Export data +``` +Export all customer records to CSV format +``` diff --git a/packages/mcp-server/README.md b/packages/mcp-server/README.md new file mode 100644 index 00000000..a197a432 --- /dev/null +++ b/packages/mcp-server/README.md @@ -0,0 +1,97 @@ +# RushDB MCP Server + +A Model Context Protocol server providing access to RushDB's Labeled Meta Property Graph (LMPG) database. + +## Features + +- **Record Management**: Create, read, update, and delete records +- **Graph Operations**: Attach and detach relationships between records +- **Advanced Querying**: Search across records using RushDB's flexible query language +- **Label & Property Discovery**: Browse labels and properties in your database +- **Bulk Operations**: Efficient bulk create and delete operations +- **Data Export**: Export records to CSV format +- **LMPG Architecture**: Work with RushDB's revolutionary property-first graph model + +## Quick Start + +1. **Install the package**: + ```bash + npm install -g @rushdb/mcp-server + ``` + +2. **Get your RushDB API key** from [rushdb.com](https://rushdb.com) + +3. **Configure your MCP client** (e.g., Claude Desktop): + ```json + { + "mcpServers": { + "rushdb": { + "command": "npx", + "args": ["@rushdb/mcp-server"], + "env": { + "RUSHDB_API_KEY": "your-rushdb-api-key-here" + } + } + } + } + ``` + +## Available Tools + +### Database Discovery +- `GetLabels` - List all record labels and their counts +- `GetProperties` - List all properties in the database + +### Record Operations +- `CreateRecord` - Create a new record +- `UpdateRecord` - Update an existing record +- `DeleteRecord` - Delete a record by ID +- `GetRecord` - Retrieve a record by ID +- `FindRecords` - Search for records using query conditions + +### Relationship Management +- `AttachRelation` - Create relationships between records +- `DetachRelation` - Remove relationships between records +- `FindRelations` - Search for relationships + +### Bulk Operations +- `BulkCreateRecords` - Create multiple records at once +- `BulkDeleteRecords` - Delete multiple records matching a query + +### Data Export +- `ExportRecords` - Export records to CSV format + +### Utilities +- `OpenBrowser` - Open URLs in browser +- `HelpAddToClient` - Get setup instructions + +## Environment Variables + +- `RUSHDB_API_KEY` - Your RushDB API key (required) + +## About RushDB's LMPG Architecture + +RushDB uses a revolutionary Labeled Meta Property Graph (LMPG) architecture where: + +- **Properties are first-class citizens** with their own nodes +- **Records are connected through shared properties** +- **Relationships emerge automatically** based on property overlap +- **No rigid schemas** - data structure evolves naturally +- **Cross-domain insights** through property traversal + +This enables unprecedented flexibility in data modeling and querying. + +## Development + +To build from source: + +```bash +git clone +cd rushdb/packages/mcp-server +npm install +npm run build +``` + +## License + +Apache 2.0 diff --git a/packages/mcp-server/esbuild.config.js b/packages/mcp-server/esbuild.config.js new file mode 100644 index 00000000..b47df5e4 --- /dev/null +++ b/packages/mcp-server/esbuild.config.js @@ -0,0 +1,93 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { build } from 'esbuild' +import { fileURLToPath } from 'url' +import { dirname, resolve } from 'path' +import fs from 'fs' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +// Check if watch mode is enabled +const isWatch = process.argv.includes('--watch') +// Check if production mode is enabled +const isProd = process.argv.includes('--prod') + +const buildOptions = { + entryPoints: ['index.ts'], + bundle: true, + platform: 'node', + target: 'node18', + format: 'esm', + outfile: 'build/index.js', + banner: { + js: '#!/usr/bin/env node' + }, + external: [ + // External packages that should not be bundled + '@rushdb/javascript-sdk', + '@modelcontextprotocol/sdk', + 'jsonschema', + 'dotenv' + ], + minify: isProd, + sourcemap: !isProd, + logLevel: 'info' +} + +async function runBuild() { + try { + if (isWatch) { + // Watch mode + const ctx = await build({ + ...buildOptions, + watch: { + onRebuild(error, result) { + if (error) { + console.error('Watch build failed:', error) + } else { + // Make the output file executable + fs.chmodSync('build/index.js', '755') + console.log('Watch build succeeded:', new Date().toLocaleTimeString()) + } + } + } + }) + + // Make the output file executable after initial build + fs.chmodSync('build/index.js', '755') + console.log('Watch mode started, waiting for changes...') + + // Keep the process running + process.stdin.on('close', () => { + ctx.stop() + process.exit(0) + }) + } else { + // One-time build + await build(buildOptions) + + // Make the output file executable + fs.chmodSync('build/index.js', '755') + + console.log(`Build completed successfully in ${isProd ? 'production' : 'development'} mode!`) + } + } catch (error) { + console.error('Build failed:', error) + process.exit(1) + } +} + +runBuild() diff --git a/packages/mcp-server/glama.json b/packages/mcp-server/glama.json new file mode 100644 index 00000000..13f39e53 --- /dev/null +++ b/packages/mcp-server/glama.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://glama.ai/mcp/schemas/server.json", + "maintainers": [ + "1pxone", + "h3yAlias" + ] +} diff --git a/packages/mcp-server/index.ts b/packages/mcp-server/index.ts new file mode 100644 index 00000000..0e4d0af1 --- /dev/null +++ b/packages/mcp-server/index.ts @@ -0,0 +1,510 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Server } from '@modelcontextprotocol/sdk/server/index.js' +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' +import { + CallToolRequestSchema, + ErrorCode, + ListToolsRequestSchema, + McpError +} from '@modelcontextprotocol/sdk/types.js' +import { ToolName, tools } from './tools.js' +import { GetLabels } from './tools/GetLabels.js' +import { GetProperties } from './tools/GetProperties.js' +import { CreateRecord } from './tools/CreateRecord.js' +import { UpdateRecord } from './tools/UpdateRecord.js' +import { DeleteRecord } from './tools/DeleteRecord.js' +import { FindRecords } from './tools/FindRecords.js' +import { GetRecord } from './tools/GetRecord.js' +import { AttachRelation } from './tools/AttachRelation.js' +import { DetachRelation } from './tools/DetachRelation.js' +import { FindRelations } from './tools/FindRelations.js' +import { BulkCreateRecords } from './tools/BulkCreateRecords.js' +import { BulkDeleteRecords } from './tools/BulkDeleteRecords.js' +import { ExportRecords } from './tools/ExportRecords.js' +import { OpenBrowser } from './tools/OpenBrowser.js' +import { HelpAddToClient } from './tools/HelpAddToClient.js' +import { SetRecord } from './tools/SetRecord.js' +import { FindOneRecord } from './tools/FindOneRecord.js' +import { FindUniqRecord } from './tools/FindUniqRecord.js' +import { DeleteRecordById } from './tools/DeleteRecordById.js' +import { PropertyValues } from './tools/PropertyValues.js' +import { FindProperty } from './tools/FindProperty.js' +import { FindPropertyById } from './tools/FindPropertyById.js' +import { DeleteProperty } from './tools/DeleteProperty.js' +import { TransactionBegin } from './tools/TransactionBegin.js' +import { TransactionCommit } from './tools/TransactionCommit.js' +import { TransactionRollback } from './tools/TransactionRollback.js' +import { TransactionGet } from './tools/TransactionGet.js' +import { GetSettings } from './tools/GetSettings.js' + +const server = new Server( + { + name: 'rushdb-mcp-server', + version: '1.0.0' + }, + { + capabilities: { + tools: { + list: true, + call: true + } + } + } +) + +server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools + } +}) + +server.setRequestHandler(CallToolRequestSchema, async (request) => { + const toolName = request.params.name as ToolName + const args = request.params.arguments || {} + + try { + switch (toolName) { + case 'GetLabels': + const labels = await GetLabels() + return { + content: [ + { + type: 'text', + text: + labels.length > 0 ? + labels.map((l) => `${l.name}: ${l.count} records`).join('\n') + : 'No labels found' + } + ] + } + + case 'GetProperties': + const properties = await GetProperties() + return { + content: [ + { + type: 'text', + text: properties.length > 0 ? JSON.stringify(properties, null, 2) : 'No properties found' + } + ] + } + + case 'CreateRecord': + const createResult = await CreateRecord({ + label: args.label as string, + data: args.data as Record + }) + return { + content: [ + { + type: 'text', + text: `${createResult.message}\nID: ${createResult.id}` + } + ] + } + + case 'UpdateRecord': + const updateResult = await UpdateRecord({ + recordId: args.recordId as string, + label: args.label as string, + data: args.data as Record + }) + return { + content: [ + { + type: 'text', + text: updateResult.message + } + ] + } + + case 'DeleteRecord': + const deleteResult = await DeleteRecord({ + recordId: args.recordId as string + }) + return { + content: [ + { + type: 'text', + text: deleteResult.message + } + ] + } + + case 'FindRecords': + const foundRecords = await FindRecords({ + labels: args.labels as string[] | undefined, + where: args.where as Record | undefined, + limit: args.limit as number | undefined, + skip: args.skip as number | undefined + }) + + return { + content: [ + { + type: 'text', + text: + foundRecords.length === 0 ? + 'No matching records found.' + : JSON.stringify(foundRecords, null, 2) + } + ] + } + + case 'GetRecord': + const record = await GetRecord({ + recordId: args.recordId as string + }) + return { + content: [ + { + type: 'text', + text: JSON.stringify(record, null, 2) + } + ] + } + + case 'AttachRelation': + const attachResult = await AttachRelation({ + sourceId: args.sourceId as string, + targetId: args.targetId as string, + relationType: args.relationType as string | undefined, + direction: args.direction as 'outgoing' | 'incoming' | 'bidirectional' | undefined + }) + return { + content: [ + { + type: 'text', + text: attachResult.message + } + ] + } + + case 'DetachRelation': + const detachResult = await DetachRelation({ + sourceId: args.sourceId as string, + targetId: args.targetId as string, + relationType: args.relationType as string | undefined, + direction: args.direction as 'outgoing' | 'incoming' | 'bidirectional' | undefined + }) + return { + content: [ + { + type: 'text', + text: detachResult.message + } + ] + } + + case 'FindRelations': + const relations = await FindRelations({ + where: args.where as Record | undefined, + limit: args.limit as number | undefined + }) + return { + content: [ + { + type: 'text', + text: relations.length > 0 ? JSON.stringify(relations, null, 2) : 'No relations found' + } + ] + } + + case 'BulkCreateRecords': + const bulkCreateResult = await BulkCreateRecords({ + label: args.label as string, + data: args.data as Record[] + }) + return { + content: [ + { + type: 'text', + text: `${bulkCreateResult.message}\nIDs: ${bulkCreateResult.ids.join(', ')}` + } + ] + } + + case 'BulkDeleteRecords': + const bulkDeleteResult = await BulkDeleteRecords({ + labels: args.labels as string[] | undefined, + where: args.where as Record + }) + return { + content: [ + { + type: 'text', + text: bulkDeleteResult.message + } + ] + } + + case 'ExportRecords': + const exportResult = await ExportRecords({ + labels: args.labels as string[] | undefined, + where: args.where as Record | undefined, + limit: args.limit as number | undefined + }) + return { + content: [ + { + type: 'text', + text: `Export completed at ${exportResult.dateTime}\n\n${exportResult.csv}` + } + ] + } + + case 'OpenBrowser': + const openBrowserResult = await OpenBrowser({ + url: args.url as string + }) + return { + content: [ + { + type: 'text', + text: openBrowserResult.message + } + ] + } + + case 'HelpAddToClient': + const helpAddToClientResult = await HelpAddToClient() + return { + content: [ + { + type: 'text', + text: helpAddToClientResult.instructions + } + ] + } + + case 'SetRecord': + const setResult = await SetRecord({ + recordId: args.recordId as string, + label: args.label as string, + data: args.data as Record + }) + return { + content: [ + { + type: 'text', + text: setResult.message + } + ] + } + + case 'FindOneRecord': + const foundOneRecord = await FindOneRecord({ + labels: args.labels as string[] | undefined, + where: args.where as Record | undefined + }) + return { + content: [ + { + type: 'text', + text: foundOneRecord ? JSON.stringify(foundOneRecord, null, 2) : 'No matching record found.' + } + ] + } + + case 'FindUniqRecord': + const foundUniqRecord = await FindUniqRecord({ + labels: args.labels as string[] | undefined, + where: args.where as Record | undefined + }) + return { + content: [ + { + type: 'text', + text: foundUniqRecord ? JSON.stringify(foundUniqRecord, null, 2) : 'No unique record found.' + } + ] + } + + case 'DeleteRecordById': + const deleteByIdResult = await DeleteRecordById({ + recordId: args.recordId as string + }) + return { + content: [ + { + type: 'text', + text: deleteByIdResult.message + } + ] + } + + case 'PropertyValues': + const propertyValues = await PropertyValues({ + propertyId: args.propertyId as string, + query: args.query as string | undefined, + orderBy: args.orderBy as 'asc' | 'desc' | undefined, + limit: args.limit as number | undefined, + skip: args.skip as number | undefined + }) + return { + content: [ + { + type: 'text', + text: propertyValues ? JSON.stringify(propertyValues, null, 2) : 'No property values found' + } + ] + } + + case 'FindProperty': + const foundProperties = await FindProperty({ + where: args.where as Record | undefined, + limit: args.limit as number | undefined, + skip: args.skip as number | undefined + }) + return { + content: [ + { + type: 'text', + text: + foundProperties.length > 0 ? JSON.stringify(foundProperties, null, 2) : 'No properties found' + } + ] + } + + case 'FindPropertyById': + const foundProperty = await FindPropertyById({ + propertyId: args.propertyId as string + }) + return { + content: [ + { + type: 'text', + text: foundProperty ? JSON.stringify(foundProperty, null, 2) : 'Property not found' + } + ] + } + + case 'DeleteProperty': + const deletePropertyResult = await DeleteProperty({ + propertyId: args.propertyId as string + }) + return { + content: [ + { + type: 'text', + text: deletePropertyResult.message + } + ] + } + + case 'TransactionBegin': + const beginResult = await TransactionBegin({ + ttl: args.ttl as number | undefined + }) + return { + content: [ + { + type: 'text', + text: `${beginResult.message}\nTransaction ID: ${beginResult.transactionId}` + } + ] + } + + case 'TransactionCommit': + const commitResult = await TransactionCommit({ + transactionId: args.transactionId as string + }) + return { + content: [ + { + type: 'text', + text: commitResult.message + } + ] + } + + case 'TransactionRollback': + const rollbackResult = await TransactionRollback({ + transactionId: args.transactionId as string + }) + return { + content: [ + { + type: 'text', + text: rollbackResult.message + } + ] + } + + case 'TransactionGet': + const transactionInfo = await TransactionGet({ + transactionId: args.transactionId as string + }) + return { + content: [ + { + type: 'text', + text: JSON.stringify(transactionInfo, null, 2) + } + ] + } + + case 'GetSettings': + const settings = await GetSettings() + return { + content: [ + { + type: 'text', + text: JSON.stringify(settings, null, 2) + } + ] + } + + default: + throw new McpError(ErrorCode.MethodNotFound, 'Tool not found') + } + } catch (error) { + console.error('Error executing tool:', error) + + // Check if error is related to API endpoint or missing env vars + if ( + error instanceof Error && + (error.message.includes('RUSHDB_API_KEY') || + error.message.includes('Invalid URL') || + error.message.includes('Failed to fetch') || + error.message.includes('Network error') || + !process.env.RUSHDB_API_KEY) + ) { + // Open browser for configuration + return { + content: [ + { + type: 'text', + text: "It seems like you haven't configured your RushDB credentials. Would you like me to open the RushDB dashboard for you so you can sign up and get your credentials?" + } + ] + } + } + + // For other errors, return the error message + return { + content: [ + { + type: 'text', + text: `Error: ${error instanceof Error ? error.message : String(error)}` + } + ] + } + } +}) + +const transport = new StdioServerTransport() +await server.connect(transport) diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json new file mode 100644 index 00000000..86e42972 --- /dev/null +++ b/packages/mcp-server/package.json @@ -0,0 +1,39 @@ +{ + "name": "@rushdb/mcp-server", + "version": "1.0.0", + "description": "RushDB MCP Server - Model Context Protocol server for RushDB", + "type": "module", + "main": "./build/index.js", + "bin": { + "rushdb-mcp": "./build/index.js" + }, + "files": [ + "build" + ], + "scripts": { + "build:esbuild": "node esbuild.config.js", + "build": "rimraf build && node esbuild.config.js --prod", + "watch:esbuild": "node esbuild.config.js --watch", + "prepare": "npm run build", + "watch": "tsc --watch", + "inspector": "npx @modelcontextprotocol/inspector build/index.js", + "test": "vitest run", + "test:watch": "vitest" + }, + "dependencies": { + "@rushdb/javascript-sdk": "workspace:*", + "@modelcontextprotocol/sdk": "^1.6.1", + "dotenv": "^16.4.7", + "jsonschema": "^1.5.0" + }, + "devDependencies": { + "@rushdb/javascript-sdk": "workspace:*", + "@modelcontextprotocol/inspector": "^0.4.1", + "@types/node": "^20.17.23", + "esbuild": "^0.25.0", + "rimraf": "^6.0.1", + "typescript": "5.7.2", + "vitest": "^1.6.1" + }, + "license": "Apache-2.0" +} \ No newline at end of file diff --git a/packages/mcp-server/tools.ts b/packages/mcp-server/tools.ts new file mode 100644 index 00000000..0d796750 --- /dev/null +++ b/packages/mcp-server/tools.ts @@ -0,0 +1,556 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { Schema } from 'jsonschema' + +export type ToolName = + | 'GetLabels' + | 'GetProperties' + | 'CreateRecord' + | 'UpdateRecord' + | 'DeleteRecord' + | 'FindRecords' + | 'GetRecord' + | 'AttachRelation' + | 'DetachRelation' + | 'FindRelations' + | 'BulkCreateRecords' + | 'BulkDeleteRecords' + | 'ExportRecords' + | 'OpenBrowser' + | 'HelpAddToClient' + | 'SetRecord' + | 'FindOneRecord' + | 'FindUniqRecord' + | 'DeleteRecordById' + | 'PropertyValues' + | 'FindProperty' + | 'FindPropertyById' + | 'DeleteProperty' + | 'TransactionBegin' + | 'TransactionCommit' + | 'TransactionRollback' + | 'TransactionGet' + | 'GetSettings' + +type Tool = { + name: ToolName + description: string + inputSchema: Schema +} + +export const tools: Tool[] = [ + { + name: 'GetLabels', + description: 'Get all record labels in the RushDB database', + inputSchema: { + type: 'object', + properties: {}, + required: [] + } + }, + { + name: 'GetProperties', + description: 'Get all properties in the RushDB database', + inputSchema: { + type: 'object', + properties: {}, + required: [] + } + }, + { + name: 'CreateRecord', + description: 'Create a new record in the database', + inputSchema: { + type: 'object', + properties: { + label: { + type: 'string', + description: 'Label for the record' + }, + data: { + type: 'object', + description: 'The record data to insert' + } + }, + required: ['label', 'data'] + } + }, + { + name: 'UpdateRecord', + description: 'Update an existing record in the database', + inputSchema: { + type: 'object', + properties: { + recordId: { + type: 'string', + description: 'ID of the record to update' + }, + label: { + type: 'string', + description: 'Label for the record' + }, + data: { + type: 'object', + description: 'The updated record data' + } + }, + required: ['recordId', 'label', 'data'] + } + }, + { + name: 'DeleteRecord', + description: 'Delete a record from the database', + inputSchema: { + type: 'object', + properties: { + recordId: { + type: 'string', + description: 'ID of the record to delete' + } + }, + required: ['recordId'] + } + }, + { + name: 'FindRecords', + description: 'Find records in the database using a search query', + inputSchema: { + type: 'object', + properties: { + labels: { + type: 'array', + items: { type: 'string' }, + description: 'Filter by record labels' + }, + where: { + type: 'object', + description: 'Search conditions for finding records' + }, + limit: { + type: 'number', + description: 'Maximum number of records to return', + default: 10 + }, + skip: { + type: 'number', + description: 'Number of records to skip', + default: 0 + } + }, + required: [] + } + }, + { + name: 'GetRecord', + description: 'Get a specific record by ID', + inputSchema: { + type: 'object', + properties: { + recordId: { + type: 'string', + description: 'ID of the record to retrieve' + } + }, + required: ['recordId'] + } + }, + { + name: 'AttachRelation', + description: 'Create a relationship between two records', + inputSchema: { + type: 'object', + properties: { + sourceId: { + type: 'string', + description: 'ID of the source record' + }, + targetId: { + type: 'string', + description: 'ID of the target record' + }, + relationType: { + type: 'string', + description: 'Type of the relationship' + }, + direction: { + type: 'string', + enum: ['outgoing', 'incoming', 'bidirectional'], + description: 'Direction of the relationship', + default: 'outgoing' + } + }, + required: ['sourceId', 'targetId'] + } + }, + { + name: 'DetachRelation', + description: 'Remove a relationship between two records', + inputSchema: { + type: 'object', + properties: { + sourceId: { + type: 'string', + description: 'ID of the source record' + }, + targetId: { + type: 'string', + description: 'ID of the target record' + }, + relationType: { + type: 'string', + description: 'Type of the relationship to remove' + }, + direction: { + type: 'string', + enum: ['outgoing', 'incoming', 'bidirectional'], + description: 'Direction of the relationship', + default: 'outgoing' + } + }, + required: ['sourceId', 'targetId'] + } + }, + { + name: 'FindRelations', + description: 'Find relationships in the database', + inputSchema: { + type: 'object', + properties: { + where: { + type: 'object', + description: 'Search conditions for finding relationships' + }, + limit: { + type: 'number', + description: 'Maximum number of relationships to return', + default: 10 + } + }, + required: [] + } + }, + { + name: 'BulkCreateRecords', + description: 'Create multiple records in a single operation', + inputSchema: { + type: 'object', + properties: { + label: { + type: 'string', + description: 'Label for all records' + }, + data: { + type: 'array', + description: 'Array of record data to insert', + items: { + type: 'object' + } + } + }, + required: ['label', 'data'] + } + }, + { + name: 'BulkDeleteRecords', + description: 'Delete multiple records matching a query', + inputSchema: { + type: 'object', + properties: { + labels: { + type: 'array', + items: { type: 'string' }, + description: 'Filter by record labels' + }, + where: { + type: 'object', + description: 'Search conditions for records to delete' + } + }, + required: ['where'] + } + }, + { + name: 'ExportRecords', + description: 'Export records to CSV format', + inputSchema: { + type: 'object', + properties: { + labels: { + type: 'array', + items: { type: 'string' }, + description: 'Filter by record labels' + }, + where: { + type: 'object', + description: 'Search conditions for records to export' + }, + limit: { + type: 'number', + description: 'Maximum number of records to export' + } + }, + required: [] + } + }, + { + name: 'OpenBrowser', + description: 'Open a web browser to a specific URL', + inputSchema: { + type: 'object', + properties: { + url: { + type: 'string', + description: 'The URL to open in the browser' + } + }, + required: ['url'] + } + }, + { + name: 'HelpAddToClient', + description: 'Help the user add the RushDB MCP server to their MCP client', + inputSchema: { + type: 'object', + properties: {}, + required: [] + } + }, + { + name: 'SetRecord', + description: 'Set all fields of a record to the provided values (replaces existing values)', + inputSchema: { + type: 'object', + properties: { + recordId: { + type: 'string', + description: 'ID of the record to set' + }, + label: { + type: 'string', + description: 'Label for the record' + }, + data: { + type: 'object', + description: 'The new record data to set' + } + }, + required: ['recordId', 'label', 'data'] + } + }, + { + name: 'FindOneRecord', + description: 'Find a single record that matches the given search criteria', + inputSchema: { + type: 'object', + properties: { + labels: { + type: 'array', + items: { type: 'string' }, + description: 'Filter by record labels' + }, + where: { + type: 'object', + description: 'Search conditions for finding the record' + } + }, + required: [] + } + }, + { + name: 'FindUniqRecord', + description: 'Find a unique record that matches the given search criteria', + inputSchema: { + type: 'object', + properties: { + labels: { + type: 'array', + items: { type: 'string' }, + description: 'Filter by record labels' + }, + where: { + type: 'object', + description: 'Search conditions for finding the unique record' + } + }, + required: [] + } + }, + { + name: 'DeleteRecordById', + description: 'Delete a record by its ID', + inputSchema: { + type: 'object', + properties: { + recordId: { + type: 'string', + description: 'ID of the record to delete' + } + }, + required: ['recordId'] + } + }, + { + name: 'PropertyValues', + description: 'Get all values for a specific property', + inputSchema: { + type: 'object', + properties: { + propertyId: { + type: 'string', + description: 'ID of the property to get values for' + }, + query: { + type: 'string', + description: 'Optional search query for filtering values' + }, + orderBy: { + type: 'string', + enum: ['asc', 'desc'], + description: 'Order direction for the values' + }, + limit: { + type: 'number', + description: 'Maximum number of values to return' + }, + skip: { + type: 'number', + description: 'Number of values to skip' + } + }, + required: ['propertyId'] + } + }, + { + name: 'FindProperty', + description: 'Find properties in the database using a search query', + inputSchema: { + type: 'object', + properties: { + where: { + type: 'object', + description: 'Search conditions for finding properties' + }, + limit: { + type: 'number', + description: 'Maximum number of properties to return', + default: 10 + }, + skip: { + type: 'number', + description: 'Number of properties to skip', + default: 0 + } + }, + required: [] + } + }, + { + name: 'FindPropertyById', + description: 'Find a specific property by ID', + inputSchema: { + type: 'object', + properties: { + propertyId: { + type: 'string', + description: 'ID of the property to retrieve' + } + }, + required: ['propertyId'] + } + }, + { + name: 'DeleteProperty', + description: 'Delete a property from the database', + inputSchema: { + type: 'object', + properties: { + propertyId: { + type: 'string', + description: 'ID of the property to delete' + } + }, + required: ['propertyId'] + } + }, + { + name: 'TransactionBegin', + description: 'Begin a new database transaction', + inputSchema: { + type: 'object', + properties: { + ttl: { + type: 'number', + description: 'Time to live for the transaction in seconds' + } + }, + required: [] + } + }, + { + name: 'TransactionCommit', + description: 'Commit a database transaction', + inputSchema: { + type: 'object', + properties: { + transactionId: { + type: 'string', + description: 'ID of the transaction to commit' + } + }, + required: ['transactionId'] + } + }, + { + name: 'TransactionRollback', + description: 'Rollback a database transaction', + inputSchema: { + type: 'object', + properties: { + transactionId: { + type: 'string', + description: 'ID of the transaction to rollback' + } + }, + required: ['transactionId'] + } + }, + { + name: 'TransactionGet', + description: 'Get information about a database transaction', + inputSchema: { + type: 'object', + properties: { + transactionId: { + type: 'string', + description: 'ID of the transaction to get information for' + } + }, + required: ['transactionId'] + } + }, + { + name: 'GetSettings', + description: 'Get the current database settings and configuration', + inputSchema: { + type: 'object', + properties: {}, + required: [] + } + } +] as const satisfies { + name: ToolName + description: string + inputSchema: Schema +}[] diff --git a/packages/mcp-server/tools/AttachRelation.ts b/packages/mcp-server/tools/AttachRelation.ts new file mode 100644 index 00000000..f2a9f048 --- /dev/null +++ b/packages/mcp-server/tools/AttachRelation.ts @@ -0,0 +1,44 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function AttachRelation(params: { + sourceId: string + targetId: string + relationType?: string + direction?: 'outgoing' | 'incoming' | 'bidirectional' +}) { + const { sourceId, targetId, relationType, direction = 'outgoing' } = params + const db = await ensureInitialized() + + const options: any = {} + if (relationType) { + options.type = relationType + } + if (direction) { + options.direction = direction + } + + await db.records.attach({ + source: sourceId, + target: targetId, + options + }) + + return { + success: true, + message: `Relationship attached from '${sourceId}' to '${targetId}'` + } +} diff --git a/packages/mcp-server/tools/BulkCreateRecords.ts b/packages/mcp-server/tools/BulkCreateRecords.ts new file mode 100644 index 00000000..8663581f --- /dev/null +++ b/packages/mcp-server/tools/BulkCreateRecords.ts @@ -0,0 +1,40 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +type BulkCreateRecordsArgs = { + label: string + data: Record[] +} + +type BulkCreateRecordsResult = { + message: string + ids: string[] +} + +export async function BulkCreateRecords({ + label, + data +}: BulkCreateRecordsArgs): Promise { + const db = await ensureInitialized() + + const result = await db.records.createMany({ label, data }) + const ids = result.data.map((record: any) => record.id()) + + return { + message: `Successfully created ${ids.length} records with label '${label}'`, + ids + } +} diff --git a/packages/mcp-server/tools/BulkDeleteRecords.ts b/packages/mcp-server/tools/BulkDeleteRecords.ts new file mode 100644 index 00000000..ad1b2f7b --- /dev/null +++ b/packages/mcp-server/tools/BulkDeleteRecords.ts @@ -0,0 +1,42 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +type BulkDeleteRecordsArgs = { + labels?: string[] + where: Record +} + +type BulkDeleteRecordsResult = { + message: string +} + +export async function BulkDeleteRecords({ + labels, + where +}: BulkDeleteRecordsArgs): Promise { + const db = await ensureInitialized() + + const searchQuery: any = { where } + if (labels && labels.length > 0) { + searchQuery.labels = labels + } + + const result = await db.records.delete(searchQuery) + + return { + message: result.data?.message || 'Records deleted successfully' + } +} diff --git a/packages/mcp-server/tools/CreateRecord.ts b/packages/mcp-server/tools/CreateRecord.ts new file mode 100644 index 00000000..f30f18c5 --- /dev/null +++ b/packages/mcp-server/tools/CreateRecord.ts @@ -0,0 +1,28 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function CreateRecord(params: { label: string; data: Record }) { + const { label, data } = params + const db = await ensureInitialized() + + const result = await db.records.create({ label, data }) + + return { + success: true, + id: result.id(), + message: `Record created successfully with label '${label}'` + } +} diff --git a/packages/mcp-server/tools/DeleteProperty.ts b/packages/mcp-server/tools/DeleteProperty.ts new file mode 100644 index 00000000..77efaccf --- /dev/null +++ b/packages/mcp-server/tools/DeleteProperty.ts @@ -0,0 +1,27 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function DeleteProperty(params: { propertyId: string }) { + const { propertyId } = params + const db = await ensureInitialized() + + await db.properties.delete(propertyId) + + return { + success: true, + message: `Property '${propertyId}' deleted successfully` + } +} diff --git a/packages/mcp-server/tools/DeleteRecord.ts b/packages/mcp-server/tools/DeleteRecord.ts new file mode 100644 index 00000000..cd8f3cf7 --- /dev/null +++ b/packages/mcp-server/tools/DeleteRecord.ts @@ -0,0 +1,27 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function DeleteRecord(params: { recordId: string }) { + const { recordId } = params + const db = await ensureInitialized() + + await db.records.deleteById(recordId) + + return { + success: true, + message: `Record '${recordId}' deleted successfully` + } +} diff --git a/packages/mcp-server/tools/DeleteRecordById.ts b/packages/mcp-server/tools/DeleteRecordById.ts new file mode 100644 index 00000000..86a3c113 --- /dev/null +++ b/packages/mcp-server/tools/DeleteRecordById.ts @@ -0,0 +1,27 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function DeleteRecordById(params: { recordId: string }) { + const { recordId } = params + const db = await ensureInitialized() + + await db.records.deleteById(recordId) + + return { + success: true, + message: `Record '${recordId}' deleted successfully` + } +} diff --git a/packages/mcp-server/tools/DetachRelation.ts b/packages/mcp-server/tools/DetachRelation.ts new file mode 100644 index 00000000..4ae19b2d --- /dev/null +++ b/packages/mcp-server/tools/DetachRelation.ts @@ -0,0 +1,44 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function DetachRelation(params: { + sourceId: string + targetId: string + relationType?: string + direction?: 'outgoing' | 'incoming' | 'bidirectional' +}) { + const { sourceId, targetId, relationType, direction = 'outgoing' } = params + const db = await ensureInitialized() + + const options: any = {} + if (relationType) { + options.typeOrTypes = relationType + } + if (direction) { + options.direction = direction + } + + await db.records.detach({ + source: sourceId, + target: targetId, + options + }) + + return { + success: true, + message: `Relationship detached from '${sourceId}' to '${targetId}'` + } +} diff --git a/packages/mcp-server/tools/ExportRecords.ts b/packages/mcp-server/tools/ExportRecords.ts new file mode 100644 index 00000000..5ecdaed4 --- /dev/null +++ b/packages/mcp-server/tools/ExportRecords.ts @@ -0,0 +1,51 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function ExportRecords(params: { + labels?: string[] + where?: Record + limit?: number +}) { + const { labels, where, limit } = params + const db = await ensureInitialized() + + const searchQuery: any = {} + if (labels && labels.length > 0) { + searchQuery.labels = labels + } + if (where) { + searchQuery.where = where + } + if (limit) { + searchQuery.limit = limit + } + + const result = await db.records.export(searchQuery) + + if (result.success && result.data) { + return { + csv: result.data.fileContent, + dateTime: result.data.dateTime, + message: 'Records exported successfully' + } + } + + return { + csv: '', + dateTime: new Date().toISOString(), + message: 'No records found to export' + } +} diff --git a/packages/mcp-server/tools/FindOneRecord.ts b/packages/mcp-server/tools/FindOneRecord.ts new file mode 100644 index 00000000..55b273fd --- /dev/null +++ b/packages/mcp-server/tools/FindOneRecord.ts @@ -0,0 +1,27 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function FindOneRecord(params: { labels?: string[]; where?: Record }) { + const { labels, where } = params + const db = await ensureInitialized() + + const result = await db.records.findOne({ + ...(labels && { labels }), + ...(where && { where }) + }) + + return result?.data || null +} diff --git a/packages/mcp-server/tools/FindProperty.ts b/packages/mcp-server/tools/FindProperty.ts new file mode 100644 index 00000000..54a784bc --- /dev/null +++ b/packages/mcp-server/tools/FindProperty.ts @@ -0,0 +1,29 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function FindProperty(params: { where?: Record; limit?: number; skip?: number }) { + const { where, limit, skip } = params + const db = await ensureInitialized() + + const searchQuery: Record = {} + if (where) searchQuery.where = where + if (limit) searchQuery.limit = limit + if (skip) searchQuery.skip = skip + + const result = await db.properties.find(searchQuery) + + return result.data +} diff --git a/packages/mcp-server/tools/FindPropertyById.ts b/packages/mcp-server/tools/FindPropertyById.ts new file mode 100644 index 00000000..147efaf5 --- /dev/null +++ b/packages/mcp-server/tools/FindPropertyById.ts @@ -0,0 +1,24 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function FindPropertyById(params: { propertyId: string }) { + const { propertyId } = params + const db = await ensureInitialized() + + const result = await db.properties.findById(propertyId) + + return result.data +} diff --git a/packages/mcp-server/tools/FindRecords.ts b/packages/mcp-server/tools/FindRecords.ts new file mode 100644 index 00000000..968eaac9 --- /dev/null +++ b/packages/mcp-server/tools/FindRecords.ts @@ -0,0 +1,43 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function FindRecords(params: { + labels?: string[] + where?: Record + limit?: number + skip?: number +}) { + const { labels, where, limit = 10, skip = 0 } = params + const db = await ensureInitialized() + + const searchQuery: any = {} + if (labels && labels.length > 0) { + searchQuery.labels = labels + } + if (where) { + searchQuery.where = where + } + if (limit) { + searchQuery.limit = limit + } + if (skip) { + searchQuery.skip = skip + } + + const result = await db.records.find(searchQuery) + + return result.data.map((record: any) => record.data) +} diff --git a/packages/mcp-server/tools/FindRelations.ts b/packages/mcp-server/tools/FindRelations.ts new file mode 100644 index 00000000..97fff1f7 --- /dev/null +++ b/packages/mcp-server/tools/FindRelations.ts @@ -0,0 +1,36 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function FindRelations(params: { where?: Record; limit?: number }) { + const { where, limit = 10 } = params + const db = await ensureInitialized() + + const searchQuery: any = {} + if (where) { + searchQuery.where = where + } + if (limit) { + searchQuery.limit = limit + } + + const result = await db.relationships.find(searchQuery) + + if (result.success && result.data) { + return result.data + } + + return [] +} diff --git a/packages/mcp-server/tools/FindUniqRecord.ts b/packages/mcp-server/tools/FindUniqRecord.ts new file mode 100644 index 00000000..a5df3aca --- /dev/null +++ b/packages/mcp-server/tools/FindUniqRecord.ts @@ -0,0 +1,27 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function FindUniqRecord(params: { labels?: string[]; where?: Record }) { + const { labels, where } = params + const db = await ensureInitialized() + + const result = await db.records.findUniq({ + ...(labels && { labels }), + ...(where && { where }) + }) + + return result?.data || null +} diff --git a/packages/mcp-server/tools/GetLabels.ts b/packages/mcp-server/tools/GetLabels.ts new file mode 100644 index 00000000..2408ae1a --- /dev/null +++ b/packages/mcp-server/tools/GetLabels.ts @@ -0,0 +1,30 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function GetLabels() { + const db = await ensureInitialized() + + const response = await db.labels.find({}) + + if (response.success && response.data) { + return Object.entries(response.data).map(([name, count]) => ({ + name, + count + })) + } + + return [] +} diff --git a/packages/mcp-server/tools/GetProperties.ts b/packages/mcp-server/tools/GetProperties.ts new file mode 100644 index 00000000..0a79ccd4 --- /dev/null +++ b/packages/mcp-server/tools/GetProperties.ts @@ -0,0 +1,27 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function GetProperties() { + const db = await ensureInitialized() + + const response = await db.properties.find({}) + + if (response.success && response.data) { + return response.data + } + + return [] +} diff --git a/packages/mcp-server/tools/GetRecord.ts b/packages/mcp-server/tools/GetRecord.ts new file mode 100644 index 00000000..2fc7ae69 --- /dev/null +++ b/packages/mcp-server/tools/GetRecord.ts @@ -0,0 +1,24 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function GetRecord(params: { recordId: string }) { + const { recordId } = params + const db = await ensureInitialized() + + const result = await db.records.findById(recordId) + + return result.data +} diff --git a/packages/mcp-server/tools/GetSettings.ts b/packages/mcp-server/tools/GetSettings.ts new file mode 100644 index 00000000..d628ce59 --- /dev/null +++ b/packages/mcp-server/tools/GetSettings.ts @@ -0,0 +1,23 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function GetSettings() { + const db = await ensureInitialized() + + const result = await db.settings.get() + + return result.data +} diff --git a/packages/mcp-server/tools/HelpAddToClient.ts b/packages/mcp-server/tools/HelpAddToClient.ts new file mode 100644 index 00000000..1e0566d2 --- /dev/null +++ b/packages/mcp-server/tools/HelpAddToClient.ts @@ -0,0 +1,66 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export async function HelpAddToClient() { + return { + instructions: `To add the RushDB MCP server to your MCP client, follow these steps: + +1. **Install the RushDB MCP Server**: + \`\`\`bash + npm install -g @rushdb/mcp-server + \`\`\` + +2. **Get your RushDB API Key**: + - Visit https://rushdb.com + - Sign up for an account or log in + - Navigate to your API settings to get your API key + +3. **Configure your MCP client**: + Add the following to your MCP client configuration: + + **For Claude Desktop** (~/Library/Application Support/Claude/claude_desktop_config.json): + \`\`\`json + { + "mcpServers": { + "rushdb": { + "command": "npx", + "args": ["@rushdb/mcp-server"], + "env": { + "RUSHDB_API_KEY": "your-rushdb-api-key-here" + } + } + } + } + \`\`\` + + **For other MCP clients**, check their documentation for how to add MCP servers. + +4. **Restart your MCP client** to load the RushDB server. + +5. **Test the connection** by asking your client to list the available RushDB tools. + +**Available Environment Variables**: +- \`RUSHDB_API_KEY\`: Your RushDB API key (required) + +**What you can do with RushDB MCP Server**: +- Create, read, update, and delete records +- Search across records using RushDB's powerful query language +- Manage relationships between records +- Export data to CSV +- Browse labels and properties in your database +- Work with RushDB's Labeled Meta Property Graph (LMPG) architecture + +For more information, visit https://docs.rushdb.com` + } +} diff --git a/packages/mcp-server/tools/OpenBrowser.ts b/packages/mcp-server/tools/OpenBrowser.ts new file mode 100644 index 00000000..11f015cf --- /dev/null +++ b/packages/mcp-server/tools/OpenBrowser.ts @@ -0,0 +1,54 @@ +import { execFile } from "child_process"; +import { platform } from "os"; +import { URL } from "url"; + +export async function OpenBrowser(params: { url: string }) { + const { url } = params; + + // Validate URL to prevent command injection + let validatedUrl: string; + try { + // Validate URL format + const parsedUrl = new URL(url); + // Only allow http and https protocols + if (!['http:', 'https:'].includes(parsedUrl.protocol)) { + return { + success: false, + message: "Invalid URL protocol. Only http and https are supported.", + }; + } + validatedUrl = parsedUrl.toString(); + } catch (e) { + return { + success: false, + message: `Invalid URL format: ${e instanceof Error ? e.message : String(e)}`, + }; + } + + // Determine the command based on platform + const command = + platform() === "darwin" + ? "open" + : platform() === "win32" + ? "start" + : "xdg-open"; + + return new Promise<{ success: boolean; message: string }>( + (resolve) => { + // Use execFile instead of exec to prevent command injection + execFile(command, [validatedUrl], (error) => { + if (error) { + resolve({ + success: false, + message: `Failed to open browser: ${error.message}`, + }); + } else { + resolve({ + success: true, + message: `Successfully opened ${validatedUrl} in default browser`, + }); + } + }); + } + ); +} diff --git a/packages/mcp-server/tools/PropertyValues.ts b/packages/mcp-server/tools/PropertyValues.ts new file mode 100644 index 00000000..619d0647 --- /dev/null +++ b/packages/mcp-server/tools/PropertyValues.ts @@ -0,0 +1,36 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function PropertyValues(params: { + propertyId: string + query?: string + orderBy?: 'asc' | 'desc' + limit?: number + skip?: number +}) { + const { propertyId, query, orderBy, limit, skip } = params + const db = await ensureInitialized() + + const searchQuery: Record = {} + if (query) searchQuery.query = query + if (orderBy) searchQuery.orderBy = orderBy + if (limit) searchQuery.limit = limit + if (skip) searchQuery.skip = skip + + const result = await db.properties.values(propertyId, searchQuery) + + return result.data +} diff --git a/packages/mcp-server/tools/SetRecord.ts b/packages/mcp-server/tools/SetRecord.ts new file mode 100644 index 00000000..2a21440a --- /dev/null +++ b/packages/mcp-server/tools/SetRecord.ts @@ -0,0 +1,27 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function SetRecord(params: { recordId: string; label: string; data: Record }) { + const { recordId, label, data } = params + const db = await ensureInitialized() + + await db.records.set({ target: recordId, label, data }) + + return { + success: true, + message: `Record '${recordId}' set successfully with label '${label}'` + } +} diff --git a/packages/mcp-server/tools/TransactionBegin.ts b/packages/mcp-server/tools/TransactionBegin.ts new file mode 100644 index 00000000..848c12bc --- /dev/null +++ b/packages/mcp-server/tools/TransactionBegin.ts @@ -0,0 +1,29 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function TransactionBegin(params: { ttl?: number }) { + const { ttl } = params + const db = await ensureInitialized() + + const config = ttl ? { ttl } : undefined + const transaction = await db.tx.begin(config) + + return { + success: true, + transactionId: transaction.id, + message: `Transaction started with ID: ${transaction.id}` + } +} diff --git a/packages/mcp-server/tools/TransactionCommit.ts b/packages/mcp-server/tools/TransactionCommit.ts new file mode 100644 index 00000000..26cfa589 --- /dev/null +++ b/packages/mcp-server/tools/TransactionCommit.ts @@ -0,0 +1,28 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function TransactionCommit(params: { transactionId: string }) { + const { transactionId } = params + const db = await ensureInitialized() + + const result = await db.tx.commit(transactionId) + + return { + success: true, + message: `Transaction '${transactionId}' committed successfully`, + data: result.data + } +} diff --git a/packages/mcp-server/tools/TransactionGet.ts b/packages/mcp-server/tools/TransactionGet.ts new file mode 100644 index 00000000..7d770e93 --- /dev/null +++ b/packages/mcp-server/tools/TransactionGet.ts @@ -0,0 +1,27 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function TransactionGet(params: { transactionId: string }) { + const { transactionId } = params + const db = await ensureInitialized() + + const transaction = await db.tx.get(transactionId) + + return { + id: transaction.id, + message: `Transaction information retrieved successfully` + } +} diff --git a/packages/mcp-server/tools/TransactionRollback.ts b/packages/mcp-server/tools/TransactionRollback.ts new file mode 100644 index 00000000..5bd06e61 --- /dev/null +++ b/packages/mcp-server/tools/TransactionRollback.ts @@ -0,0 +1,28 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function TransactionRollback(params: { transactionId: string }) { + const { transactionId } = params + const db = await ensureInitialized() + + const result = await db.tx.rollback(transactionId) + + return { + success: true, + message: `Transaction '${transactionId}' rolled back successfully`, + data: result.data + } +} diff --git a/packages/mcp-server/tools/UpdateRecord.ts b/packages/mcp-server/tools/UpdateRecord.ts new file mode 100644 index 00000000..ae65e459 --- /dev/null +++ b/packages/mcp-server/tools/UpdateRecord.ts @@ -0,0 +1,27 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ensureInitialized } from '../util/db.js' + +export async function UpdateRecord(params: { recordId: string; label: string; data: Record }) { + const { recordId, label, data } = params + const db = await ensureInitialized() + + await db.records.update({ target: recordId, label, data }) + + return { + success: true, + message: `Record updated successfully` + } +} diff --git a/packages/mcp-server/tsconfig.json b/packages/mcp-server/tsconfig.json new file mode 100644 index 00000000..30c7745f --- /dev/null +++ b/packages/mcp-server/tsconfig.json @@ -0,0 +1,113 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "libReplacement": true, /* Enable lib replacement. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "NodeNext" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "nodenext" /* Specify how TypeScript looks up a file from a given module specifier. */, + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./build" /* Specify an output folder for all emitted files. */, + // "removeComments": true, /* Disable emitting comments. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ + // "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/packages/mcp-server/util/db.ts b/packages/mcp-server/util/db.ts new file mode 100644 index 00000000..4bf0a310 --- /dev/null +++ b/packages/mcp-server/util/db.ts @@ -0,0 +1,32 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import 'dotenv/config' +import RushDB from '@rushdb/javascript-sdk' + +const token = process.env.RUSHDB_API_KEY + +if (!token) { + throw new Error('RUSHDB_API_KEY environment variable is required') +} + +export const db = new RushDB(token) + +// Ensure RushDB is initialized +export const ensureInitialized = async () => { + if (!RushDB.isInitialized()) { + await db.waitForInitialization() + } + return db +} diff --git a/packages/mcp-server/vitest.config.ts b/packages/mcp-server/vitest.config.ts new file mode 100644 index 00000000..05513d10 --- /dev/null +++ b/packages/mcp-server/vitest.config.ts @@ -0,0 +1,27 @@ +// Copyright Collect Software, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['**/*.test.ts'], + setupFiles: ['./tests/setup.ts'], + coverage: { + reporter: ['text', 'json', 'html'] + } + } +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cba30c0e..264cc1cc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,7 +63,7 @@ importers: version: 8.0.3 jest: specifier: 29.5.0 - version: 29.5.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)) + version: 29.5.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)) jest-ts-webcompat-resolver: specifier: 1.0.0 version: 1.0.0(jest-resolve@29.7.0) @@ -148,25 +148,22 @@ importers: packages/mcp-server: dependencies: - '@datastax/astra-db-ts': - specifier: ^1.5.0 - version: 1.5.0 '@modelcontextprotocol/sdk': specifier: ^1.6.1 version: 1.13.2 + '@rushdb/javascript-sdk': + specifier: workspace:* + version: link:../javascript-sdk dotenv: specifier: ^16.4.7 version: 16.6.1 jsonschema: specifier: ^1.5.0 version: 1.5.0 - mcp-evals: - specifier: ^1.0.18 - version: 1.0.18(react@19.1.0)(ws@8.18.0)(zod@3.23.8) devDependencies: '@modelcontextprotocol/inspector': specifier: ^0.4.1 - version: 0.4.1(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.19.2)(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(typescript@5.8.3) + version: 0.4.1(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.19.2)(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(typescript@5.7.2) '@types/node': specifier: ^20.17.23 version: 20.19.2 @@ -177,8 +174,8 @@ importers: specifier: ^6.0.1 version: 6.0.1 typescript: - specifier: ^5.8.2 - version: 5.8.3 + specifier: 5.7.2 + version: 5.7.2 vitest: specifier: ^1.6.1 version: 1.6.1(@types/node@20.19.2)(terser@5.37.0) @@ -737,50 +734,6 @@ packages: resolution: {integrity: sha512-CyneQqxoFwTGOqBVe8DSED0uQrU3q4+xpgvl0kbNHctv/kdBRgOKSSJgyB7j+08mUKaHchelMmwNVmQf5XaJrA==} engines: {node: '>=12'} - '@actions/core@1.11.1': - resolution: {integrity: sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==} - - '@actions/exec@1.1.1': - resolution: {integrity: sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==} - - '@actions/http-client@2.2.3': - resolution: {integrity: sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==} - - '@actions/io@1.1.3': - resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==} - - '@ai-sdk/openai@1.3.22': - resolution: {integrity: sha512-QwA+2EkG0QyjVR+7h6FE7iOu2ivNqAVMm9UJZkVxxTk5OIq5fFJDTEI/zICEMuHImTTXR2JjsL6EirJ28Jc4cw==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.0.0 - - '@ai-sdk/provider-utils@2.2.8': - resolution: {integrity: sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.23.8 - - '@ai-sdk/provider@1.1.3': - resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==} - engines: {node: '>=18'} - - '@ai-sdk/react@1.2.12': - resolution: {integrity: sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==} - engines: {node: '>=18'} - peerDependencies: - react: 19.1.0 - zod: ^3.23.8 - peerDependenciesMeta: - zod: - optional: true - - '@ai-sdk/ui-utils@1.2.11': - resolution: {integrity: sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.23.8 - '@algolia/autocomplete-core@1.17.9': resolution: {integrity: sha512-O7BxrpLDPJWWHv/DLA9DRFWs+iY1uOJZkqUwjS5HSZAGcl0hIVCQ97LTLewiZmZ402JYUrun+8NqFP+hCknlbQ==} @@ -914,9 +867,6 @@ packages: '@antfu/utils@0.7.10': resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==} - '@anthropic-ai/sdk@0.8.1': - resolution: {integrity: sha512-59etePenCizVx1O8Qhi1T1ruE04ISfNzCnyhZNcsss1QljsLmYS83jttarMNEvGYcsUF7rwxw2lzcC3Zbxao7g==} - '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} @@ -2311,10 +2261,6 @@ packages: peerDependencies: postcss: ^8.4 - '@datastax/astra-db-ts@1.5.0': - resolution: {integrity: sha512-Z9pEVyyHfglh8XAKrIASxdvORdei4pLUKDDGarqYvBkA9B9rKdqqdN+4I42Dz8paU5uscu8FwM5mc+Ly/U6jfA==} - engines: {node: '>=14.0.0'} - '@dependents/detective-less@3.0.2': resolution: {integrity: sha512-1YUvQ+e0eeTWAHoN8Uz2x2U37jZs6IGutiIE5LXId7cxfUGhtZjzxE06FdUiuiRrW+UE0vNCdSNPH2lY4dQCOQ==} engines: {node: '>=12'} @@ -2848,10 +2794,6 @@ packages: '@fastify/ajv-compiler@3.6.0': resolution: {integrity: sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ==} - '@fastify/busboy@2.1.1': - resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} - engines: {node: '>=14'} - '@fastify/cors@8.2.1': resolution: {integrity: sha512-2H2MrDD3ea7g707g1CNNLWb9/tYbmw7HS+MK2SDcgjxwzbOFR93JortelTIO8DBFsZqFtEpKNxiZfSyrGgYcbw==} @@ -4872,9 +4814,6 @@ packages: '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - '@types/diff-match-patch@1.0.36': - resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==} - '@types/ejs@3.1.5': resolution: {integrity: sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==} @@ -4974,9 +4913,6 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} - '@types/node-fetch@2.6.12': - resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} - '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} @@ -5090,9 +5026,6 @@ packages: '@types/three@0.171.0': resolution: {integrity: sha512-oLuT1SAsT+CUg/wxUTFHo0K3NtJLnx9sJhZWQJp/0uXqFpzSk1hRHmvWvpaAWSfvx2db0lVKZ5/wV0I0isD2mQ==} - '@types/tough-cookie@4.0.5': - resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} - '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -5476,24 +5409,10 @@ packages: resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} - agentkeepalive@4.6.0: - resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} - engines: {node: '>= 8.0.0'} - aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} - ai@4.3.16: - resolution: {integrity: sha512-KUDwlThJ5tr2Vw0A1ZkbDKNME3wzWhuVfAOwIvFUzl1TPVDFAXDFTXio3p+jaKneB+dKNCvFFlolYmmgHttG1g==} - engines: {node: '>=18'} - peerDependencies: - react: 19.1.0 - zod: ^3.23.8 - peerDependenciesMeta: - react: - optional: true - ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -5541,9 +5460,6 @@ packages: alien-signals@0.4.14: resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} - already@2.2.1: - resolution: {integrity: sha512-qk6RIVMS/R1yTvBzfIL1T76PsIL7DIVCINoLuFw2YXKLpLtsTobqdChMs8m3OhuPS3CEE3+Ra5ibYiqdyogbsQ==} - an-array@1.0.0: resolution: {integrity: sha512-M175GYI7RmsYu24Ok383yZQa3eveDfNnmhTe3OQ3bm70bEovz2gWenH+ST/n32M8lrwLWk74hcPds5CDRPe2wg==} @@ -5857,9 +5773,6 @@ packages: bare-stream@2.6.1: resolution: {integrity: sha512-eVZbtKM+4uehzrsj49KtCy3Pbg7kO1pJ3SKZ1SFrIH/0pnj9scuGGgUlNDf/7qS8WKtGdiJY5Kyhs/ivYPTB/g==} - base-64@0.1.0: - resolution: {integrity: sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==} - base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -6013,9 +5926,6 @@ packages: resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} engines: {node: '>= 0.4'} - callguard@2.0.0: - resolution: {integrity: sha512-I3nd+fuj20FK1qu00ImrbH+II+8ULS6ioYr9igqR1xyqySoqc3DiHEyUM0mkoAdKeLGg2CtGnO8R3VRQX5krpQ==} - callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -6119,9 +6029,6 @@ packages: chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - charenc@0.0.2: - resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} - check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} @@ -6568,9 +6475,6 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - crypt@0.0.2: - resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} - crypto-random-string@4.0.0: resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} engines: {node: '>=12'} @@ -7203,9 +7107,6 @@ packages: didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - diff-match-patch@1.0.5: - resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} - diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7218,9 +7119,6 @@ packages: resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} - digest-fetch@1.3.0: - resolution: {integrity: sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==} - dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -7923,10 +7821,6 @@ packages: resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==} engines: {node: '>=0.4.0'} - fetch-h2@3.0.2: - resolution: {integrity: sha512-Lo6UPdMKKc9Ond7yjG2vq0mnocspOLh1oV6+XZdtfdexacvMSz5xm3WoQhTAdoR2+UqPlyMNqcqfecipoD+l/A==} - engines: {node: '>=12'} - fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} @@ -8045,9 +7939,6 @@ packages: typescript: '>3.6.0' webpack: ^5.11.0 - form-data-encoder@1.7.2: - resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} - form-data-encoder@2.1.4: resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} engines: {node: '>= 14.17'} @@ -8060,10 +7951,6 @@ packages: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} - formdata-node@4.4.1: - resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} - engines: {node: '>= 12.20'} - formidable@2.1.2: resolution: {integrity: sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==} @@ -8628,9 +8515,6 @@ packages: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} - humanize-ms@1.2.1: - resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} - husky@8.0.3: resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==} engines: {node: '>=14'} @@ -9346,9 +9230,6 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -9370,11 +9251,6 @@ packages: jsonc-parser@3.3.1: resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} - jsondiffpatch@0.6.0: - resolution: {integrity: sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -9756,15 +9632,6 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - mcp-evals@1.0.18: - resolution: {integrity: sha512-khDcEG0XWshdCRirqLXogNoDLmzFA86QyuKoi5ioXsbeRZ3XQra8Zsg7vD+C0K5vwkFIoB1vTuPjHEHMhdLFtQ==} - hasBin: true - peerDependencies: - react: 19.1.0 - - md5@2.3.0: - resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} - mdast-util-directive@3.0.0: resolution: {integrity: sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q==} @@ -10554,11 +10421,6 @@ packages: node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - deprecated: Use your platform's native DOMException instead - node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} @@ -10741,18 +10603,6 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - openai@4.104.0: - resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} - hasBin: true - peerDependencies: - ws: ^8.18.0 - zod: ^3.23.8 - peerDependenciesMeta: - ws: - optional: true - zod: - optional: true - openapi-types@12.1.3: resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} @@ -11915,9 +11765,6 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - psl@1.15.0: - resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} - pug-attrs@3.0.0: resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==} @@ -12015,9 +11862,6 @@ packages: resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} engines: {node: '>=6'} - querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -13349,10 +13193,6 @@ packages: three@0.171.0: resolution: {integrity: sha512-Y/lAXPaKZPcEdkKjh0JOAHVv8OOnv/NDJqm0wjfCzyQmfKxV7zvkwsnBgPBKTzJHToSOhRGQAGbPJObT59B/PQ==} - throttleit@2.1.0: - resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} - engines: {node: '>=18'} - through2@4.0.2: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} @@ -13407,9 +13247,6 @@ packages: tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - to-arraybuffer@1.0.1: - resolution: {integrity: sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==} - to-object-path@0.3.0: resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} engines: {node: '>=0.10.0'} @@ -13448,10 +13285,6 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - tough-cookie@4.1.4: - resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} - engines: {node: '>=6'} - tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -13583,15 +13416,6 @@ packages: peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - tsx@4.20.3: - resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==} - engines: {node: '>=18.0.0'} - hasBin: true - - tunnel@0.0.6: - resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} - engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -13656,9 +13480,6 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - typed-emitter@2.1.0: - resolution: {integrity: sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==} - typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} @@ -13681,11 +13502,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} - engines: {node: '>=14.17'} - hasBin: true - uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} @@ -13714,10 +13530,6 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici@5.29.0: - resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} - engines: {node: '>=14.0'} - undici@6.21.0: resolution: {integrity: sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==} engines: {node: '>=18.17'} @@ -13808,10 +13620,6 @@ packages: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} - universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -13864,9 +13672,6 @@ packages: resolution: {integrity: sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==} engines: {node: '>=4'} - url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - urlpattern-polyfill@10.0.0: resolution: {integrity: sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==} @@ -14176,14 +13981,6 @@ packages: resolution: {integrity: sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A==} engines: {node: '>=10.0.0'} - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} - engines: {node: '>= 8'} - - web-streams-polyfill@4.0.0-beta.3: - resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} - engines: {node: '>= 14'} - webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -14490,56 +14287,6 @@ snapshots: three-forcegraph: 1.42.11(three@0.171.0) three-render-objects: 1.32.1(three@0.171.0) - '@actions/core@1.11.1': - dependencies: - '@actions/exec': 1.1.1 - '@actions/http-client': 2.2.3 - - '@actions/exec@1.1.1': - dependencies: - '@actions/io': 1.1.3 - - '@actions/http-client@2.2.3': - dependencies: - tunnel: 0.0.6 - undici: 5.29.0 - - '@actions/io@1.1.3': {} - - '@ai-sdk/openai@1.3.22(zod@3.23.8)': - dependencies: - '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.23.8) - zod: 3.23.8 - - '@ai-sdk/provider-utils@2.2.8(zod@3.23.8)': - dependencies: - '@ai-sdk/provider': 1.1.3 - nanoid: 3.3.8 - secure-json-parse: 2.7.0 - zod: 3.23.8 - - '@ai-sdk/provider@1.1.3': - dependencies: - json-schema: 0.4.0 - - '@ai-sdk/react@1.2.12(react@19.1.0)(zod@3.23.8)': - dependencies: - '@ai-sdk/provider-utils': 2.2.8(zod@3.23.8) - '@ai-sdk/ui-utils': 1.2.11(zod@3.23.8) - react: 19.1.0 - swr: 2.3.3(react@19.1.0) - throttleit: 2.1.0 - optionalDependencies: - zod: 3.23.8 - - '@ai-sdk/ui-utils@1.2.11(zod@3.23.8)': - dependencies: - '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.23.8) - zod: 3.23.8 - zod-to-json-schema: 3.24.6(zod@3.23.8) - '@algolia/autocomplete-core@1.17.9(@algolia/client-search@5.18.0)(algoliasearch@5.18.0)(search-insights@2.17.3)': dependencies: '@algolia/autocomplete-plugin-algolia-insights': 1.17.9(@algolia/client-search@5.18.0)(algoliasearch@5.18.0)(search-insights@2.17.3) @@ -14733,20 +14480,6 @@ snapshots: '@antfu/utils@0.7.10': {} - '@anthropic-ai/sdk@0.8.1': - dependencies: - '@types/node': 18.19.68 - '@types/node-fetch': 2.6.12 - abort-controller: 3.0.0 - agentkeepalive: 4.6.0 - digest-fetch: 1.3.0 - form-data-encoder: 1.7.2 - formdata-node: 4.4.1 - node-fetch: 2.7.0 - web-streams-polyfill: 3.3.3 - transitivePeerDependencies: - - encoding - '@babel/code-frame@7.26.2': dependencies: '@babel/helper-validator-identifier': 7.25.9 @@ -15912,14 +15645,14 @@ snapshots: '@commitlint/types': 17.8.1 '@types/node': 20.5.1 chalk: 4.1.2 - cosmiconfig: 8.3.6(typescript@5.8.3) - cosmiconfig-typescript-loader: 4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@5.8.3))(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3))(typescript@5.8.3) + cosmiconfig: 8.3.6(typescript@5.7.2) + cosmiconfig-typescript-loader: 4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@5.7.2))(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2))(typescript@5.7.2) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 resolve-from: 5.0.0 ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.7.2) - typescript: 5.8.3 + typescript: 5.7.2 transitivePeerDependencies: - '@swc/core' - '@swc/wasm' @@ -16499,13 +16232,6 @@ snapshots: dependencies: postcss: 8.5.6 - '@datastax/astra-db-ts@1.5.0': - dependencies: - fetch-h2: 3.0.2 - safe-stable-stringify: 2.5.0 - typed-emitter: 2.1.0 - uuidv7: 0.6.3 - '@dependents/detective-less@3.0.2': dependencies: gonzales-pe: 4.3.0 @@ -17532,8 +17258,6 @@ snapshots: ajv-formats: 2.1.1(ajv@8.17.1) fast-uri: 2.4.0 - '@fastify/busboy@2.1.1': {} - '@fastify/cors@8.2.1': dependencies: fastify-plugin: 4.5.1 @@ -17763,7 +17487,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3))': + '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -17777,7 +17501,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)) + jest-config: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -18082,14 +17806,14 @@ snapshots: - supports-color - utf-8-validate - '@modelcontextprotocol/inspector@0.4.1(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.19.2)(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(typescript@5.8.3)': + '@modelcontextprotocol/inspector@0.4.1(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.19.2)(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0)(typescript@5.7.2)': dependencies: '@modelcontextprotocol/inspector-client': 0.4.1(@types/react-dom@19.1.0(@types/react@19.1.0))(@types/react@19.1.0) '@modelcontextprotocol/inspector-server': 0.4.1 concurrently: 9.2.0 shell-quote: 1.8.2 spawn-rx: 5.1.2 - ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.19.2)(typescript@5.8.3) + ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.19.2)(typescript@5.7.2) transitivePeerDependencies: - '@swc/core' - '@swc/wasm' @@ -18393,7 +18117,8 @@ snapshots: '@one-ini/wasm@0.1.1': {} - '@opentelemetry/api@1.9.0': {} + '@opentelemetry/api@1.9.0': + optional: true '@pkgjs/parseargs@0.11.0': optional: true @@ -19797,8 +19522,6 @@ snapshots: dependencies: '@types/ms': 0.7.34 - '@types/diff-match-patch@1.0.36': {} - '@types/ejs@3.1.5': optional: true @@ -19908,11 +19631,6 @@ snapshots: '@types/ms@0.7.34': {} - '@types/node-fetch@2.6.12': - dependencies: - '@types/node': 20.19.2 - form-data: 4.0.1 - '@types/node-forge@1.3.11': dependencies: '@types/node': 20.19.2 @@ -20053,8 +19771,6 @@ snapshots: fflate: 0.8.2 meshoptimizer: 0.18.1 - '@types/tough-cookie@4.0.5': {} - '@types/trusted-types@2.0.7': optional: true @@ -20593,27 +20309,11 @@ snapshots: agent-base@7.1.3: optional: true - agentkeepalive@4.6.0: - dependencies: - humanize-ms: 1.2.1 - aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 indent-string: 4.0.0 - ai@4.3.16(react@19.1.0)(zod@3.23.8): - dependencies: - '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.23.8) - '@ai-sdk/react': 1.2.12(react@19.1.0)(zod@3.23.8) - '@ai-sdk/ui-utils': 1.2.11(zod@3.23.8) - '@opentelemetry/api': 1.9.0 - jsondiffpatch: 0.6.0 - zod: 3.23.8 - optionalDependencies: - react: 19.1.0 - ajv-formats@2.1.1(ajv@8.12.0): optionalDependencies: ajv: 8.12.0 @@ -20680,8 +20380,6 @@ snapshots: alien-signals@0.4.14: optional: true - already@2.2.1: {} - an-array@1.0.0: {} ansi-align@3.0.1: @@ -21033,8 +20731,6 @@ snapshots: streamx: 2.21.1 optional: true - base-64@0.1.0: {} - base64-js@1.5.1: {} base@0.11.2: @@ -21262,8 +20958,6 @@ snapshots: call-bind-apply-helpers: 1.0.1 get-intrinsic: 1.2.7 - callguard@2.0.0: {} - callsites@3.1.0: {} camel-case@3.0.0: @@ -21372,8 +21066,6 @@ snapshots: chardet@0.7.0: {} - charenc@0.0.2: {} - check-error@1.0.3: dependencies: get-func-name: 2.0.2 @@ -21805,12 +21497,12 @@ snapshots: - '@swc/core' - '@swc/wasm' - cosmiconfig-typescript-loader@4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@5.8.3))(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3))(typescript@5.8.3): + cosmiconfig-typescript-loader@4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@5.7.2))(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2))(typescript@5.7.2): dependencies: '@types/node': 20.5.1 - cosmiconfig: 8.3.6(typescript@5.8.3) + cosmiconfig: 8.3.6(typescript@5.7.2) ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.7.2) - typescript: 5.8.3 + typescript: 5.7.2 cosmiconfig@7.1.0: dependencies: @@ -21829,15 +21521,6 @@ snapshots: optionalDependencies: typescript: 5.7.2 - cosmiconfig@8.3.6(typescript@5.8.3): - dependencies: - import-fresh: 3.3.0 - js-yaml: 4.1.0 - parse-json: 5.2.0 - path-type: 4.0.0 - optionalDependencies: - typescript: 5.8.3 - cosmiconfig@9.0.0(typescript@5.7.2): dependencies: env-paths: 2.2.1 @@ -21848,13 +21531,13 @@ snapshots: typescript: 5.7.2 optional: true - create-jest@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)): + create-jest@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)) + jest-config: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -21879,8 +21562,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - crypt@0.0.2: {} - crypto-random-string@4.0.0: dependencies: type-fest: 1.4.0 @@ -22551,8 +22232,6 @@ snapshots: didyoumean@1.2.2: {} - diff-match-patch@1.0.5: {} - diff-sequences@29.6.3: {} diff@4.0.2: {} @@ -22560,11 +22239,6 @@ snapshots: diff@5.2.0: optional: true - digest-fetch@1.3.0: - dependencies: - base-64: 0.1.0 - md5: 2.3.0 - dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -23661,16 +23335,6 @@ snapshots: dependencies: xml-js: 1.6.11 - fetch-h2@3.0.2: - dependencies: - '@types/tough-cookie': 4.0.5 - already: 2.2.1 - callguard: 2.0.0 - get-stream: 6.0.1 - through2: 4.0.2 - to-arraybuffer: 1.0.1 - tough-cookie: 4.1.4 - fflate@0.8.2: {} figures@3.2.0: @@ -23840,8 +23504,6 @@ snapshots: typescript: 4.9.5 webpack: 5.79.0(@swc/core@1.10.1(@swc/helpers@0.5.15))(esbuild@0.21.5) - form-data-encoder@1.7.2: {} - form-data-encoder@2.1.4: {} form-data@4.0.1: @@ -23852,11 +23514,6 @@ snapshots: format@0.2.2: {} - formdata-node@4.4.1: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 4.0.0-beta.3 - formidable@2.1.2: dependencies: dezalgo: 1.0.4 @@ -24653,10 +24310,6 @@ snapshots: human-signals@5.0.0: {} - humanize-ms@1.2.1: - dependencies: - ms: 2.1.3 - husky@8.0.3: {} iconv-lite@0.4.24: @@ -25158,16 +24811,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)): + jest-cli@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)) + create-jest: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)) + jest-config: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -25177,7 +24830,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)): + jest-config@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -25433,12 +25086,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.5.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)): + jest@29.5.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)) + jest-cli: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -25447,10 +25100,10 @@ snapshots: jest@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.7.2)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.8.3)) + jest-cli: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -25525,8 +25178,6 @@ snapshots: json-schema-traverse@1.0.0: {} - json-schema@0.4.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} json5@1.0.2: @@ -25541,12 +25192,6 @@ snapshots: jsonc-parser@3.3.1: {} - jsondiffpatch@0.6.0: - dependencies: - '@types/diff-match-patch': 1.0.36 - chalk: 5.4.1 - diff-match-patch: 1.0.5 - jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 @@ -25962,30 +25607,6 @@ snapshots: math-intrinsics@1.1.0: {} - mcp-evals@1.0.18(react@19.1.0)(ws@8.18.0)(zod@3.23.8): - dependencies: - '@actions/core': 1.11.1 - '@ai-sdk/openai': 1.3.22(zod@3.23.8) - '@anthropic-ai/sdk': 0.8.1 - '@modelcontextprotocol/sdk': 1.13.2 - ai: 4.3.16(react@19.1.0)(zod@3.23.8) - chalk: 4.1.2 - dotenv: 16.6.1 - openai: 4.104.0(ws@8.18.0)(zod@3.23.8) - react: 19.1.0 - tsx: 4.20.3 - transitivePeerDependencies: - - encoding - - supports-color - - ws - - zod - - md5@2.3.0: - dependencies: - charenc: 0.0.2 - crypt: 0.0.2 - is-buffer: 1.1.6 - mdast-util-directive@3.0.0: dependencies: '@types/mdast': 4.0.4 @@ -27553,8 +27174,6 @@ snapshots: node-abort-controller@3.1.1: {} - node-domexception@1.0.0: {} - node-emoji@1.11.0: dependencies: lodash: 4.17.21 @@ -27742,21 +27361,6 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - openai@4.104.0(ws@8.18.0)(zod@3.23.8): - dependencies: - '@types/node': 18.19.68 - '@types/node-fetch': 2.6.12 - abort-controller: 3.0.0 - agentkeepalive: 4.6.0 - form-data-encoder: 1.7.2 - formdata-node: 4.4.1 - node-fetch: 2.7.0 - optionalDependencies: - ws: 8.18.0 - zod: 3.23.8 - transitivePeerDependencies: - - encoding - openapi-types@12.1.3: {} opener@1.5.2: {} @@ -29033,10 +28637,6 @@ snapshots: proxy-from-env@1.1.0: {} - psl@1.15.0: - dependencies: - punycode: 2.3.1 - pug-attrs@3.0.0: dependencies: constantinople: 4.0.1 @@ -29182,8 +28782,6 @@ snapshots: split-on-first: 1.1.0 strict-uri-encode: 2.0.0 - querystringify@2.2.0: {} - queue-microtask@1.2.3: {} queue-tick@1.0.1: @@ -30914,8 +30512,6 @@ snapshots: three@0.171.0: {} - throttleit@2.1.0: {} - through2@4.0.2: dependencies: readable-stream: 3.6.2 @@ -30952,8 +30548,6 @@ snapshots: tmpl@1.0.5: {} - to-arraybuffer@1.0.1: {} - to-object-path@0.3.0: dependencies: kind-of: 3.2.2 @@ -30987,13 +30581,6 @@ snapshots: totalist@3.0.1: {} - tough-cookie@4.1.4: - dependencies: - psl: 1.15.0 - punycode: 2.3.1 - universalify: 0.2.0 - url-parse: 1.5.10 - tr46@0.0.3: {} traverse@0.6.10: @@ -31123,27 +30710,6 @@ snapshots: yn: 3.1.1 optionalDependencies: '@swc/core': 1.10.1(@swc/helpers@0.5.15) - optional: true - - ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.19.2)(typescript@5.8.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.19.2 - acorn: 8.14.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.8.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - optionalDependencies: - '@swc/core': 1.10.1(@swc/helpers@0.5.15) ts-node@9.1.1(typescript@4.9.5): dependencies: @@ -31197,15 +30763,6 @@ snapshots: tslib: 1.14.1 typescript: 4.9.5 - tsx@4.20.3: - dependencies: - esbuild: 0.25.5 - get-tsconfig: 4.8.1 - optionalDependencies: - fsevents: 2.3.3 - - tunnel@0.0.6: {} - type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -31272,10 +30829,6 @@ snapshots: possible-typed-array-names: 1.0.0 reflect.getprototypeof: 1.0.10 - typed-emitter@2.1.0: - optionalDependencies: - rxjs: 7.6.0 - typedarray-to-buffer@3.1.5: dependencies: is-typedarray: 1.0.0 @@ -31295,8 +30848,6 @@ snapshots: typescript@5.7.2: {} - typescript@5.8.3: {} - uc.micro@2.1.0: {} ufo@1.5.4: {} @@ -31324,10 +30875,6 @@ snapshots: undici-types@6.21.0: {} - undici@5.29.0: - dependencies: - '@fastify/busboy': 2.1.1 - undici@6.21.0: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -31448,8 +30995,6 @@ snapshots: universalify@0.1.2: {} - universalify@0.2.0: {} - universalify@2.0.1: {} unpipe@1.0.0: {} @@ -31509,11 +31054,6 @@ snapshots: dependencies: prepend-http: 2.0.0 - url-parse@1.5.10: - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - urlpattern-polyfill@10.0.0: optional: true @@ -31830,10 +31370,6 @@ snapshots: transitivePeerDependencies: - encoding - web-streams-polyfill@3.3.3: {} - - web-streams-polyfill@4.0.0-beta.3: {} - webidl-conversions@3.0.1: {} webpack-bundle-analyzer@4.10.2: