From 9b105232c25bbee6bb461498c74c22edf6cba129 Mon Sep 17 00:00:00 2001 From: Skirano Date: Tue, 19 Nov 2024 18:44:01 -0500 Subject: [PATCH 01/13] added duckduckgo --- package.json | 1 + src/duckduckgo/README.md | 39 ++++++++ src/duckduckgo/index.ts | 166 +++++++++++++++++++++++++++++++++++ src/duckduckgo/package.json | 30 +++++++ src/duckduckgo/tsconfig.json | 10 +++ 5 files changed, 246 insertions(+) create mode 100644 src/duckduckgo/README.md create mode 100644 src/duckduckgo/index.ts create mode 100644 src/duckduckgo/package.json create mode 100644 src/duckduckgo/tsconfig.json diff --git a/package.json b/package.json index 72ad23f4..abb1ea90 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "publish-all": "npm publish --workspaces --access public && npm publish --access public" }, "dependencies": { + "@modelcontextprotocol/server-duckduckgo": "*", "@modelcontextprotocol/server-everything": "*", "@modelcontextprotocol/server-gdrive": "*", "@modelcontextprotocol/server-postgres": "*", diff --git a/src/duckduckgo/README.md b/src/duckduckgo/README.md new file mode 100644 index 00000000..fb6ae376 --- /dev/null +++ b/src/duckduckgo/README.md @@ -0,0 +1,39 @@ +# DuckDuckGo MCP Server +MCP server providing search functionality via DuckDuckGo's HTML interface. + +## Core Concepts +### Resources +Single resource endpoint for search results: +```duckduckgo://search``` + +### Tools +Search tool with configurable result count: +```json +{ + "name": "search", + "arguments": { + "query": "your search query", + "numResults": 5 // optional, defaults to 5 + } +} +``` + +## Implementation Details +- HTML scraping via JSDOM +- Clean result formatting with titles, snippets, and URLs +- Error handling for network/parsing issues +- Request rate limiting built-in via DuckDuckGo's interface + +## Usage Example +```typescript +// Search tool response format +{ + content: [{ + type: "text", + text: "Title: Example Result\nSnippet: Result description...\nURL: https://..." + }] +} +``` + +## Development +Requires Node.js and npm. Uses ES modules. diff --git a/src/duckduckgo/index.ts b/src/duckduckgo/index.ts new file mode 100644 index 00000000..e463142d --- /dev/null +++ b/src/duckduckgo/index.ts @@ -0,0 +1,166 @@ +#!/usr/bin/env node + +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { + CallToolRequestSchema, + ListResourcesRequestSchema, + ListToolsRequestSchema, + ReadResourceRequestSchema, +} from "@modelcontextprotocol/sdk/types.js"; +import fetch from "node-fetch"; +import { JSDOM } from "jsdom"; + +const server = new Server( + { + name: "example-servers/duckduckgo", + version: "0.1.0", + }, + { + capabilities: { + tools: {}, + resources: {}, // Required since we're using ListResourcesRequestSchema + }, + }, +); + +// Add Resources List Handler - Important for showing up in the tools list +server.setRequestHandler(ListResourcesRequestSchema, async () => { + return { + resources: [ + { + uri: "duckduckgo://search", + mimeType: "text/plain", + name: "DuckDuckGo Search Results", + }, + ], + }; +}); + +// Add Read Resource Handler +server.setRequestHandler(ReadResourceRequestSchema, async (request) => { + if (request.params.uri.toString() === "duckduckgo://search") { + return { + contents: [ + { + uri: "duckduckgo://search", + mimeType: "text/plain", + text: "DuckDuckGo search interface", + }, + ], + }; + } + throw new Error("Resource not found"); +}); + +server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [ + { + name: "search", + description: + "Performs a search using DuckDuckGo and returns the top search results. " + + "Returns titles, snippets, and URLs of the search results. " + + "Use this tool when you need to search for current information on the internet.", + inputSchema: { + type: "object", + properties: { + query: { + type: "string", + description: "The search query to look up", + }, + numResults: { + type: "number", + description: "Number of results to return (default: 5)", + default: 5, + }, + }, + required: ["query"], + }, + }, + ], + }; +}); + +server.setRequestHandler(CallToolRequestSchema, async (request) => { + if (request.params.name === "search") { + try { + const { query, numResults = 5 } = request.params.arguments as { + query: string; + numResults?: number; + }; + + const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`; + const headers = { + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", + }; + + const response = await fetch(url, { headers }); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const html = await response.text(); + const dom = new JSDOM(html); + const document = dom.window.document; + + const results = []; + const resultElements = document.querySelectorAll(".result"); + + for (let i = 0; i < Math.min(numResults, resultElements.length); i++) { + const result = resultElements[i]; + const titleElem = result.querySelector(".result__title"); + const snippetElem = result.querySelector(".result__snippet"); + const urlElem = result.querySelector(".result__url"); + + if (titleElem && snippetElem) { + results.push({ + title: titleElem.textContent?.trim() || "", + snippet: snippetElem.textContent?.trim() || "", + url: urlElem?.getAttribute("href") || "", + }); + } + } + + const formattedResults = results + .map( + (result) => + `Title: ${result.title}\nSnippet: ${result.snippet}\nURL: ${result.url}\n`, + ) + .join("\n"); + + return { + content: [ + { + type: "text", + text: formattedResults || "No results found.", + }, + ], + }; + } catch (error) { + return { + content: [ + { + type: "text", + text: `Error performing search: ${error instanceof Error ? error.message : String(error)}`, + }, + ], + isError: true, + }; + } + } + + throw new Error(`Unknown tool: ${request.params.name}`); +}); + +async function runServer() { + const transport = new StdioServerTransport(); + await server.connect(transport); + console.error("DuckDuckGo MCP Server running on stdio"); +} + +runServer().catch((error) => { + console.error("Fatal error running server:", error); + process.exit(1); +}); diff --git a/src/duckduckgo/package.json b/src/duckduckgo/package.json new file mode 100644 index 00000000..89a30463 --- /dev/null +++ b/src/duckduckgo/package.json @@ -0,0 +1,30 @@ +{ + "name": "@modelcontextprotocol/server-duckduckgo", + "version": "0.1.0", + "description": "MCP server for DuckDuckGo search", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/servers/issues", + "type": "module", + "bin": { + "mcp-server-duckduckgo": "dist/index.js" + }, + "files": ["dist"], + "scripts": { + "build": "tsc && shx chmod +x dist/*.js", + "prepare": "npm run build", + "watch": "tsc --watch" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "0.5.0", + "jsdom": "^24.0.0", + "node-fetch": "^3.3.2" + }, + "devDependencies": { + "shx": "^0.3.4", + "typescript": "^5.6.2", + "@types/jsdom": "^21.1.6", + "@types/node": "^20.10.0" + } +} diff --git a/src/duckduckgo/tsconfig.json b/src/duckduckgo/tsconfig.json new file mode 100644 index 00000000..ec5da158 --- /dev/null +++ b/src/duckduckgo/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "." + }, + "include": [ + "./**/*.ts" + ] +} From 49c6b19d6565c8096c042cc6a3c42b46bcc0c42d Mon Sep 17 00:00:00 2001 From: Skirano Date: Wed, 20 Nov 2024 00:48:13 -0500 Subject: [PATCH 02/13] added filesystem --- package.json | 1 + src/filesystem/index.ts | 600 +++++++++++++++++++++++++++++++++++ src/filesystem/package.json | 30 ++ src/filesystem/tsconfig.json | 12 + 4 files changed, 643 insertions(+) create mode 100644 src/filesystem/index.ts create mode 100644 src/filesystem/package.json create mode 100644 src/filesystem/tsconfig.json diff --git a/package.json b/package.json index abb1ea90..047179f8 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "dependencies": { "@modelcontextprotocol/server-duckduckgo": "*", "@modelcontextprotocol/server-everything": "*", + "@modelcontextprotocol/server-filesystem": "*", "@modelcontextprotocol/server-gdrive": "*", "@modelcontextprotocol/server-postgres": "*", "@modelcontextprotocol/server-puppeteer": "*", diff --git a/src/filesystem/index.ts b/src/filesystem/index.ts new file mode 100644 index 00000000..2a2de0c4 --- /dev/null +++ b/src/filesystem/index.ts @@ -0,0 +1,600 @@ +#!/usr/bin/env node + +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { + CallToolRequestSchema, + ListResourcesRequestSchema, + ListToolsRequestSchema, + ReadResourceRequestSchema, +} from "@modelcontextprotocol/sdk/types.js"; +import fs from "fs/promises"; +import path from "path"; +import { promisify } from "util"; +import { exec as execCallback } from "child_process"; + +// Define interfaces for the tool arguments +interface ReadFileArgs { + path: string; +} + +interface ReadMultipleFilesArgs { + paths: string[]; +} + +interface WriteFileArgs { + path: string; + content: string; +} + +interface CreateDirectoryArgs { + path: string; +} + +interface ListDirectoryArgs { + path: string; +} + +interface DeleteFileArgs { + path: string; + recursive?: boolean; +} + +interface MoveFileArgs { + source: string; + destination: string; +} + +interface SearchFilesArgs { + path: string; + pattern: string; +} + +interface FileInfo { + size: number; + created: Date; + modified: Date; + accessed: Date; + isDirectory: boolean; + isFile: boolean; + permissions: string; +} + +const exec = promisify(execCallback); + +const server = new Server( + { + name: "example-servers/filesystem", + version: "0.1.0", + }, + { + capabilities: { + tools: {}, + resources: {}, // Need this since we're using resources + }, + }, +); + +// Add Resources List Handler +server.setRequestHandler(ListResourcesRequestSchema, async () => { + return { + resources: [ + { + uri: "file://system", + mimeType: "text/plain", + name: "File System Operations", + }, + ], + }; +}); + +// Add Read Resource Handler +server.setRequestHandler(ReadResourceRequestSchema, async (request) => { + if (request.params.uri.toString() === "file://system") { + return { + contents: [ + { + uri: "file://system", + mimeType: "text/plain", + text: "File system operations interface", + }, + ], + }; + } + throw new Error("Resource not found"); +}); + +server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [ + { + name: "read_file", + description: + "Read the complete contents of a file from the file system. " + + "Handles various text encodings and provides detailed error messages " + + "if the file cannot be read. Use this tool when you need to examine " + + "the contents of a single file.", + inputSchema: { + type: "object", + properties: { + path: { + type: "string", + description: + "Absolute or relative path to the file you want to read", + }, + }, + required: ["path"], + }, + }, + { + name: "read_multiple_files", + description: + "Read the contents of multiple files simultaneously. This is more " + + "efficient than reading files one by one when you need to analyze " + + "or compare multiple files. Each file's content is returned with its " + + "path as a reference. Failed reads for individual files won't stop " + + "the entire operation.", + inputSchema: { + type: "object", + properties: { + paths: { + type: "array", + items: { + type: "string", + }, + description: + "List of file paths to read. Can be absolute or relative paths.", + }, + }, + required: ["paths"], + }, + }, + { + name: "write_file", + description: + "Create a new file or completely overwrite an existing file with new content. " + + "This tool will create any necessary parent directories automatically. " + + "Use with caution as it will overwrite existing files without warning. " + + "Handles text content with proper encoding.", + inputSchema: { + type: "object", + properties: { + path: { + type: "string", + description: + "Path where the file should be written. Parent directories will be created if needed.", + }, + content: { + type: "string", + description: + "Content to write to the file. Can include newlines and special characters.", + }, + }, + required: ["path", "content"], + }, + }, + { + name: "create_directory", + description: + "Create a new directory or ensure a directory exists. Can create multiple " + + "nested directories in one operation. If the directory already exists, " + + "this operation will succeed silently. Perfect for setting up directory " + + "structures for projects or ensuring required paths exist.", + inputSchema: { + type: "object", + properties: { + path: { + type: "string", + description: + "Path of the directory to create. Will create parent directories if they don't exist.", + }, + }, + required: ["path"], + }, + }, + { + name: "list_directory", + description: + "Get a detailed listing of all files and directories in a specified path. " + + "Results clearly distinguish between files and directories with [FILE] and [DIR] " + + "prefixes. This tool is essential for understanding directory structure and " + + "finding specific files within a directory.", + inputSchema: { + type: "object", + properties: { + path: { + type: "string", + description: + "Path of the directory to list. Must be an existing directory.", + }, + }, + required: ["path"], + }, + }, + { + name: "delete_file", + description: + "Remove files or directories from the file system. Can handle both individual " + + "files and directories. For directories, you can specify recursive deletion to " + + "remove all contents. Use with extreme caution as deletions are permanent and " + + "cannot be undone.", + inputSchema: { + type: "object", + properties: { + path: { + type: "string", + description: "Path of the file or directory to delete", + }, + recursive: { + type: "boolean", + description: + "If true, recursively delete directories and their contents. Required for non-empty directories.", + default: false, + }, + }, + required: ["path"], + }, + }, + { + name: "move_file", + description: + "Move or rename files and directories. Can move files between directories " + + "and rename them in a single operation. If the destination exists, the " + + "operation will fail. Works across different directories and can be used " + + "for simple renaming within the same directory.", + inputSchema: { + type: "object", + properties: { + source: { + type: "string", + description: "Current path of the file or directory", + }, + destination: { + type: "string", + description: + "New path where the file or directory should be moved to", + }, + }, + required: ["source", "destination"], + }, + }, + { + name: "search_files", + description: + "Recursively search for files and directories matching a pattern. " + + "Searches through all subdirectories from the starting path. The search " + + "is case-insensitive and matches partial names. Returns full paths to all " + + "matching items. Great for finding files when you don't know their exact location.", + inputSchema: { + type: "object", + properties: { + path: { + type: "string", + description: "Starting directory for the search", + }, + pattern: { + type: "string", + description: + "Text pattern to search for in file and directory names", + }, + }, + required: ["path", "pattern"], + }, + }, + { + name: "get_file_info", + description: + "Retrieve detailed metadata about a file or directory. Returns comprehensive " + + "information including size, creation time, last modified time, permissions, " + + "and type. This tool is perfect for understanding file characteristics " + + "without reading the actual content.", + inputSchema: { + type: "object", + properties: { + path: { + type: "string", + description: + "Path to the file or directory to get information about", + }, + }, + required: ["path"], + }, + }, + ], + }; +}); + +async function getFileStats(filePath: string): Promise { + const stats = await fs.stat(filePath); + return { + size: stats.size, + created: stats.birthtime, + modified: stats.mtime, + accessed: stats.atime, + isDirectory: stats.isDirectory(), + isFile: stats.isFile(), + permissions: stats.mode.toString(8).slice(-3), + }; +} + +async function searchFiles( + rootPath: string, + pattern: string, +): Promise { + const results: string[] = []; + + async function search(currentPath: string) { + const entries = await fs.readdir(currentPath, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(currentPath, entry.name); + + if (entry.name.toLowerCase().includes(pattern.toLowerCase())) { + results.push(fullPath); + } + + if (entry.isDirectory()) { + await search(fullPath); + } + } + } + + await search(rootPath); + return results; +} + +// Add type guard functions for each argument type +function isReadFileArgs(args: unknown): args is ReadFileArgs { + return ( + typeof args === "object" && + args !== null && + "path" in args && + typeof (args as ReadFileArgs).path === "string" + ); +} + +function isReadMultipleFilesArgs(args: unknown): args is ReadMultipleFilesArgs { + return ( + typeof args === "object" && + args !== null && + "paths" in args && + Array.isArray((args as ReadMultipleFilesArgs).paths) && + (args as ReadMultipleFilesArgs).paths.every( + (path) => typeof path === "string", + ) + ); +} + +function isWriteFileArgs(args: unknown): args is WriteFileArgs { + return ( + typeof args === "object" && + args !== null && + "path" in args && + "content" in args && + typeof (args as WriteFileArgs).path === "string" && + typeof (args as WriteFileArgs).content === "string" + ); +} + +function isCreateDirectoryArgs(args: unknown): args is CreateDirectoryArgs { + return ( + typeof args === "object" && + args !== null && + "path" in args && + typeof (args as CreateDirectoryArgs).path === "string" + ); +} + +function isListDirectoryArgs(args: unknown): args is ListDirectoryArgs { + return ( + typeof args === "object" && + args !== null && + "path" in args && + typeof (args as ListDirectoryArgs).path === "string" + ); +} + +function isDeleteFileArgs(args: unknown): args is DeleteFileArgs { + const deleteArgs = args as DeleteFileArgs; + return ( + typeof args === "object" && + args !== null && + "path" in args && + typeof deleteArgs.path === "string" && + (deleteArgs.recursive === undefined || + typeof deleteArgs.recursive === "boolean") + ); +} + +function isMoveFileArgs(args: unknown): args is MoveFileArgs { + return ( + typeof args === "object" && + args !== null && + "source" in args && + "destination" in args && + typeof (args as MoveFileArgs).source === "string" && + typeof (args as MoveFileArgs).destination === "string" + ); +} + +function isSearchFilesArgs(args: unknown): args is SearchFilesArgs { + return ( + typeof args === "object" && + args !== null && + "path" in args && + "pattern" in args && + typeof (args as SearchFilesArgs).path === "string" && + typeof (args as SearchFilesArgs).pattern === "string" + ); +} + +server.setRequestHandler(CallToolRequestSchema, async (request) => { + try { + const { name, arguments: args } = request.params; + + switch (name) { + case "read_file": { + if (!isReadFileArgs(args)) { + throw new Error("Invalid arguments for read_file"); + } + const content = await fs.readFile(args.path, "utf-8"); + return { + content: [{ type: "text", text: content }], + }; + } + + case "read_multiple_files": { + if (!isReadMultipleFilesArgs(args)) { + throw new Error("Invalid arguments for read_multiple_files"); + } + const results = await Promise.all( + args.paths.map(async (filePath: string) => { + try { + const content = await fs.readFile(filePath, "utf-8"); + return `${filePath}:\n${content}\n`; + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : String(error); + return `${filePath}: Error - ${errorMessage}`; + } + }), + ); + return { + content: [{ type: "text", text: results.join("\n---\n") }], + }; + } + + case "write_file": { + if (!isWriteFileArgs(args)) { + throw new Error("Invalid arguments for write_file"); + } + await fs.writeFile(args.path, args.content, "utf-8"); + return { + content: [ + { type: "text", text: `Successfully wrote to ${args.path}` }, + ], + }; + } + + case "create_directory": { + if (!isCreateDirectoryArgs(args)) { + throw new Error("Invalid arguments for create_directory"); + } + await fs.mkdir(args.path, { recursive: true }); + return { + content: [ + { + type: "text", + text: `Successfully created directory ${args.path}`, + }, + ], + }; + } + + case "list_directory": { + if (!isListDirectoryArgs(args)) { + throw new Error("Invalid arguments for list_directory"); + } + const entries = await fs.readdir(args.path, { withFileTypes: true }); + const formatted = entries + .map( + (entry) => + `${entry.isDirectory() ? "[DIR]" : "[FILE]"} ${entry.name}`, + ) + .join("\n"); + return { + content: [{ type: "text", text: formatted }], + }; + } + + case "delete_file": { + if (!isDeleteFileArgs(args)) { + throw new Error("Invalid arguments for delete_file"); + } + const stats = await fs.stat(args.path); + if (stats.isDirectory()) { + if (args.recursive) { + await fs.rm(args.path, { recursive: true }); + } else { + await fs.rmdir(args.path); + } + } else { + await fs.unlink(args.path); + } + return { + content: [ + { type: "text", text: `Successfully deleted ${args.path}` }, + ], + }; + } + + case "move_file": { + if (!isMoveFileArgs(args)) { + throw new Error("Invalid arguments for move_file"); + } + await fs.rename(args.source, args.destination); + return { + content: [ + { + type: "text", + text: `Successfully moved ${args.source} to ${args.destination}`, + }, + ], + }; + } + + case "search_files": { + if (!isSearchFilesArgs(args)) { + throw new Error("Invalid arguments for search_files"); + } + const results = await searchFiles(args.path, args.pattern); + return { + content: [ + { + type: "text", + text: + results.length > 0 ? results.join("\n") : "No matches found", + }, + ], + }; + } + + case "get_file_info": { + if (!isCreateDirectoryArgs(args)) { + throw new Error("Invalid arguments for get_file_info"); + } + const info = await getFileStats(args.path); + return { + content: [ + { + type: "text", + text: Object.entries(info) + .map(([key, value]) => `${key}: ${value}`) + .join("\n"), + }, + ], + }; + } + + default: + throw new Error(`Unknown tool: ${name}`); + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + return { + content: [{ type: "text", text: `Error: ${errorMessage}` }], + isError: true, + }; + } +}); + +async function runServer() { + const transport = new StdioServerTransport(); + await server.connect(transport); + console.error("MCP Server running on stdio"); +} + +runServer().catch((error) => { + console.error("Fatal error running server:", error); + process.exit(1); +}); diff --git a/src/filesystem/package.json b/src/filesystem/package.json new file mode 100644 index 00000000..8bc2b770 --- /dev/null +++ b/src/filesystem/package.json @@ -0,0 +1,30 @@ +{ + "name": "@modelcontextprotocol/server-filesystem", + "version": "0.1.0", + "description": "MCP server for filesystem access", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/servers/issues", + "type": "module", + "bin": { + "mcp-server-filesystem": "dist/index.js" + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsc && shx chmod +x dist/*.js", + "prepare": "npm run build", + "watch": "tsc --watch" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "0.5.0", + "glob": "^10.3.10" + }, + "devDependencies": { + "@types/node": "^20.11.0", + "shx": "^0.3.4", + "typescript": "^5.3.3" + } +} diff --git a/src/filesystem/tsconfig.json b/src/filesystem/tsconfig.json new file mode 100644 index 00000000..c0c20f35 --- /dev/null +++ b/src/filesystem/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": ".", + "moduleResolution": "NodeNext", + "module": "NodeNext" + }, + "include": [ + "./**/*.ts" + ] +} From 4f25b1e1d1f7d1dd81983cef772e89251fe78fca Mon Sep 17 00:00:00 2001 From: Skirano Date: Wed, 20 Nov 2024 00:50:09 -0500 Subject: [PATCH 03/13] Create README.md --- src/filesystem/README.md | 55 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/filesystem/README.md diff --git a/src/filesystem/README.md b/src/filesystem/README.md new file mode 100644 index 00000000..214e6d7e --- /dev/null +++ b/src/filesystem/README.md @@ -0,0 +1,55 @@ +# Filesystem MCP Server + +Node.js server implementing Model Context Protocol (MCP) for filesystem operations. + +## Features + +- Read/write files +- Create/list/delete directories +- Move files/directories +- Search files +- Get file metadata + +## Usage + +1. Install dependencies: + ``` + npm install @modelcontextprotocol/sdk + ``` + +2. Run server: + ``` + node index.js + ``` + +3. Server runs on stdio, communicate using MCP. + +## API + +### Resources + +- `file://system`: File system operations interface + +### Tools + +1. `read_file`: Read file contents +2. `read_multiple_files`: Read multiple files +3. `write_file`: Create/overwrite file +4. `create_directory`: Create directory +5. `list_directory`: List directory contents +6. `delete_file`: Delete file/directory +7. `move_file`: Move/rename file/directory +8. `search_files`: Search files/directories +9. `get_file_info`: Get file metadata + +## Implementation + +- Uses `@modelcontextprotocol/sdk` +- Async file operations with `fs/promises` +- Type guards for argument validation +- Error handling and detailed descriptions + +## Notes + +- Careful with `delete_file` and `write_file` (overwrites existing) +- File paths can be absolute or relative From 124ff86101fab180becda1beeb9a177ae2b0dc34 Mon Sep 17 00:00:00 2001 From: Mahesh Murag Date: Wed, 20 Nov 2024 01:09:52 -0500 Subject: [PATCH 04/13] Minor updates to duckduckgo --- src/duckduckgo/index.ts | 165 +++++++++++++++++++++------------------- 1 file changed, 87 insertions(+), 78 deletions(-) diff --git a/src/duckduckgo/index.ts b/src/duckduckgo/index.ts index e463142d..7125ce02 100644 --- a/src/duckduckgo/index.ts +++ b/src/duckduckgo/index.ts @@ -7,10 +7,33 @@ import { ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, + Tool, } from "@modelcontextprotocol/sdk/types.js"; import fetch from "node-fetch"; import { JSDOM } from "jsdom"; +const SEARCH_TOOL: Tool = { + name: "duckduckgo_search", + description: + "Performs a search using DuckDuckGo and returns the top search results. " + + "Returns titles, snippets, and URLs of the search results. ", + inputSchema: { + type: "object", + properties: { + query: { + type: "string", + description: "The search query to look up", + }, + numResults: { + type: "number", + description: "Number of results to return (default: 10)", + default: 10, + }, + }, + required: ["query"], + }, +}; + const server = new Server( { name: "example-servers/duckduckgo", @@ -19,25 +42,21 @@ const server = new Server( { capabilities: { tools: {}, - resources: {}, // Required since we're using ListResourcesRequestSchema + resources: {}, }, }, ); -// Add Resources List Handler - Important for showing up in the tools list -server.setRequestHandler(ListResourcesRequestSchema, async () => { - return { - resources: [ - { - uri: "duckduckgo://search", - mimeType: "text/plain", - name: "DuckDuckGo Search Results", - }, - ], - }; -}); +server.setRequestHandler(ListResourcesRequestSchema, async () => ({ + resources: [ + { + uri: "duckduckgo://search", + mimeType: "text/plain", + name: "DuckDuckGo Search Results", + }, + ], +})); -// Add Read Resource Handler server.setRequestHandler(ReadResourceRequestSchema, async (request) => { if (request.params.uri.toString() === "duckduckgo://search") { return { @@ -53,76 +72,57 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => { throw new Error("Resource not found"); }); -server.setRequestHandler(ListToolsRequestSchema, async () => { - return { - tools: [ - { - name: "search", - description: - "Performs a search using DuckDuckGo and returns the top search results. " + - "Returns titles, snippets, and URLs of the search results. " + - "Use this tool when you need to search for current information on the internet.", - inputSchema: { - type: "object", - properties: { - query: { - type: "string", - description: "The search query to look up", - }, - numResults: { - type: "number", - description: "Number of results to return (default: 5)", - default: 5, - }, - }, - required: ["query"], - }, - }, - ], +server.setRequestHandler(ListToolsRequestSchema, async () => ({ + tools: [SEARCH_TOOL], +})); + +async function performSearch(query: string, numResults: number = 10) { + const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`; + const headers = { + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", }; -}); + + const response = await fetch(url, { headers }); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const html = await response.text(); + const dom = new JSDOM(html); + const document = dom.window.document; + + const results = []; + const resultElements = document.querySelectorAll(".result"); + + for (let i = 0; i < Math.min(numResults, resultElements.length); i++) { + const result = resultElements[i]; + const titleElem = result.querySelector(".result__title"); + const snippetElem = result.querySelector(".result__snippet"); + const urlElem = result.querySelector(".result__url"); + + if (titleElem && snippetElem) { + results.push({ + title: titleElem.textContent?.trim() || "", + snippet: snippetElem.textContent?.trim() || "", + url: urlElem?.getAttribute("href") || "", + }); + } + } + + return results; +} server.setRequestHandler(CallToolRequestSchema, async (request) => { - if (request.params.name === "search") { + if (request.params.name === "duckduckgo_search") { try { - const { query, numResults = 5 } = request.params.arguments as { + const { query, numResults = 10 } = request.params.arguments as { query: string; numResults?: number; }; - const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`; - const headers = { - "User-Agent": - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", - }; - - const response = await fetch(url, { headers }); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const html = await response.text(); - const dom = new JSDOM(html); - const document = dom.window.document; - - const results = []; - const resultElements = document.querySelectorAll(".result"); - - for (let i = 0; i < Math.min(numResults, resultElements.length); i++) { - const result = resultElements[i]; - const titleElem = result.querySelector(".result__title"); - const snippetElem = result.querySelector(".result__snippet"); - const urlElem = result.querySelector(".result__url"); - - if (titleElem && snippetElem) { - results.push({ - title: titleElem.textContent?.trim() || "", - snippet: snippetElem.textContent?.trim() || "", - url: urlElem?.getAttribute("href") || "", - }); - } - } - + const results = await performSearch(query, numResults); + const formattedResults = results .map( (result) => @@ -137,6 +137,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { text: formattedResults || "No results found.", }, ], + isError: false, }; } catch (error) { return { @@ -151,7 +152,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { } } - throw new Error(`Unknown tool: ${request.params.name}`); + return { + content: [ + { + type: "text", + text: `Unknown tool: ${request.params.name}`, + }, + ], + isError: true, + }; }); async function runServer() { @@ -163,4 +172,4 @@ async function runServer() { runServer().catch((error) => { console.error("Fatal error running server:", error); process.exit(1); -}); +}); \ No newline at end of file From 64f8e4db054e4eb0103bc4c498210041dbe8a2bf Mon Sep 17 00:00:00 2001 From: Mahesh Murag Date: Wed, 20 Nov 2024 01:24:23 -0500 Subject: [PATCH 05/13] Minor updates to filesystem --- src/duckduckgo/README.md | 42 +++++++++-------- src/duckduckgo/index.ts | 3 +- src/duckduckgo/package.json | 12 ++--- src/filesystem/README.md | 90 ++++++++++++++++++++++++------------- src/filesystem/index.ts | 1 - 5 files changed, 88 insertions(+), 60 deletions(-) diff --git a/src/duckduckgo/README.md b/src/duckduckgo/README.md index fb6ae376..74e25193 100644 --- a/src/duckduckgo/README.md +++ b/src/duckduckgo/README.md @@ -1,39 +1,37 @@ # DuckDuckGo MCP Server + MCP server providing search functionality via DuckDuckGo's HTML interface. -## Core Concepts +## Components + ### Resources -Single resource endpoint for search results: +Single resource endpoint for search interface: ```duckduckgo://search``` ### Tools -Search tool with configurable result count: -```json +- **duckduckgo_search** + - Performs a search using DuckDuckGo and returns the top search results + - Inputs: + - `query` (string, required): The search query to look up + - `numResults` (number, optional): Number of results to return (default: 10) + - Returns titles, snippets, and URLs of the search results + +## Usage Example +```javascript +// Example tool call { - "name": "search", + "name": "duckduckgo_search", "arguments": { "query": "your search query", - "numResults": 5 // optional, defaults to 5 + "numResults": 10 } } -``` - -## Implementation Details -- HTML scraping via JSDOM -- Clean result formatting with titles, snippets, and URLs -- Error handling for network/parsing issues -- Request rate limiting built-in via DuckDuckGo's interface -## Usage Example -```typescript -// Search tool response format +// Example response format: { - content: [{ - type: "text", - text: "Title: Example Result\nSnippet: Result description...\nURL: https://..." + "content": [{ + "type": "text", + "text": "Title: Result Title\nSnippet: Result description...\nURL: https://example.com\n\nTitle: Another Result\n..." }] } ``` - -## Development -Requires Node.js and npm. Uses ES modules. diff --git a/src/duckduckgo/index.ts b/src/duckduckgo/index.ts index 7125ce02..c1d316ac 100644 --- a/src/duckduckgo/index.ts +++ b/src/duckduckgo/index.ts @@ -16,7 +16,8 @@ const SEARCH_TOOL: Tool = { name: "duckduckgo_search", description: "Performs a search using DuckDuckGo and returns the top search results. " + - "Returns titles, snippets, and URLs of the search results. ", + "Returns titles, snippets, and URLs of the search results. " + + "Use this tool to search for current information on the internet.", inputSchema: { type: "object", properties: { diff --git a/src/duckduckgo/package.json b/src/duckduckgo/package.json index 89a30463..a09297ea 100644 --- a/src/duckduckgo/package.json +++ b/src/duckduckgo/package.json @@ -10,7 +10,9 @@ "bin": { "mcp-server-duckduckgo": "dist/index.js" }, - "files": ["dist"], + "files": [ + "dist" + ], "scripts": { "build": "tsc && shx chmod +x dist/*.js", "prepare": "npm run build", @@ -18,13 +20,13 @@ }, "dependencies": { "@modelcontextprotocol/sdk": "0.5.0", - "jsdom": "^24.0.0", + "jsdom": "^24.1.3", "node-fetch": "^3.3.2" }, "devDependencies": { - "shx": "^0.3.4", - "typescript": "^5.6.2", "@types/jsdom": "^21.1.6", - "@types/node": "^20.10.0" + "@types/node": "^20.10.0", + "shx": "^0.3.4", + "typescript": "^5.6.2" } } diff --git a/src/filesystem/README.md b/src/filesystem/README.md index 214e6d7e..3c23f956 100644 --- a/src/filesystem/README.md +++ b/src/filesystem/README.md @@ -10,20 +10,6 @@ Node.js server implementing Model Context Protocol (MCP) for filesystem operatio - Search files - Get file metadata -## Usage - -1. Install dependencies: - ``` - npm install @modelcontextprotocol/sdk - ``` - -2. Run server: - ``` - node index.js - ``` - -3. Server runs on stdio, communicate using MCP. - ## API ### Resources @@ -32,24 +18,66 @@ Node.js server implementing Model Context Protocol (MCP) for filesystem operatio ### Tools -1. `read_file`: Read file contents -2. `read_multiple_files`: Read multiple files -3. `write_file`: Create/overwrite file -4. `create_directory`: Create directory -5. `list_directory`: List directory contents -6. `delete_file`: Delete file/directory -7. `move_file`: Move/rename file/directory -8. `search_files`: Search files/directories -9. `get_file_info`: Get file metadata - -## Implementation - -- Uses `@modelcontextprotocol/sdk` -- Async file operations with `fs/promises` -- Type guards for argument validation -- Error handling and detailed descriptions +- **read_file** + - Read complete contents of a file + - Input: `path` (string) + - Reads complete file contents with UTF-8 encoding + +- **read_multiple_files** + - Read multiple files simultaneously + - Input: `paths` (string[]) + - Failed reads won't stop the entire operation + +- **write_file** + - Create new file or overwrite existing + - Inputs: + - `path` (string): File location + - `content` (string): File content + +- **create_directory** + - Create new directory or ensure it exists + - Input: `path` (string) + - Creates parent directories if needed + - Succeeds silently if directory exists + +- **list_directory** + - List directory contents with [FILE] or [DIR] prefixes + - Input: `path` (string) + +- **delete_file** + - Remove files or directories + - Inputs: + - `path` (string) + - `recursive` (boolean, optional): For directory deletion + - Use with caution - deletions are permanent + +- **move_file** + - Move or rename files and directories + - Inputs: + - `source` (string) + - `destination` (string) + - Fails if destination exists + +- **search_files** + - Recursively search for files/directories + - Inputs: + - `path` (string): Starting directory + - `pattern` (string): Search pattern + - Case-insensitive matching + - Returns full paths to matches + +- **get_file_info** + - Get detailed file/directory metadata + - Input: `path` (string) + - Returns: + - Size + - Creation time + - Modified time + - Access time + - Type (file/directory) + - Permissions ## Notes -- Careful with `delete_file` and `write_file` (overwrites existing) +- Exercise caution with `delete_file` (deletes files permanently) and `write_file` (overwrites existing files) - File paths can be absolute or relative diff --git a/src/filesystem/index.ts b/src/filesystem/index.ts index 2a2de0c4..dcff5af0 100644 --- a/src/filesystem/index.ts +++ b/src/filesystem/index.ts @@ -153,7 +153,6 @@ server.setRequestHandler(ListToolsRequestSchema, async () => { name: "write_file", description: "Create a new file or completely overwrite an existing file with new content. " + - "This tool will create any necessary parent directories automatically. " + "Use with caution as it will overwrite existing files without warning. " + "Handles text content with proper encoding.", inputSchema: { From f78ac17926aac019dcbffe2dbb5638b45b24c8f8 Mon Sep 17 00:00:00 2001 From: Mahesh Murag Date: Wed, 20 Nov 2024 01:32:40 -0500 Subject: [PATCH 06/13] Minor updates to filesystem --- package-lock.json | 519 +++++++++++++++++++++++++++++++++++++++ src/filesystem/README.md | 9 +- src/filesystem/index.ts | 62 ----- 3 files changed, 520 insertions(+), 70 deletions(-) diff --git a/package-lock.json b/package-lock.json index 977c234d..0f5c4dee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "src/*" ], "dependencies": { + "@modelcontextprotocol/server-duckduckgo": "*", "@modelcontextprotocol/server-everything": "*", "@modelcontextprotocol/server-gdrive": "*", "@modelcontextprotocol/server-postgres": "*", @@ -64,6 +65,10 @@ "zod": "^3.23.8" } }, + "node_modules/@modelcontextprotocol/server-duckduckgo": { + "resolved": "src/duckduckgo", + "link": true + }, "node_modules/@modelcontextprotocol/server-everything": { "resolved": "src/everything", "link": true @@ -180,6 +185,18 @@ "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", "dev": true }, + "node_modules/@types/jsdom": { + "version": "21.1.7", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", + "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -239,6 +256,13 @@ "@types/send": "*" } }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -343,6 +367,12 @@ "node": ">=4" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/b4a": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", @@ -589,6 +619,18 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -652,6 +694,18 @@ } } }, + "node_modules/cssstyle": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", + "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", + "license": "MIT", + "dependencies": { + "rrweb-cssom": "^0.7.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", @@ -660,6 +714,53 @@ "node": ">= 14" } }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -668,6 +769,12 @@ "ms": "2.0.0" } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "license": "MIT" + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -697,6 +804,15 @@ "node": ">= 14" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -753,6 +869,18 @@ "once": "^1.4.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -956,6 +1084,29 @@ "pend": "~1.2.0" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/finalhandler": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", @@ -973,6 +1124,32 @@ "node": ">= 0.8" } }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1255,6 +1432,18 @@ "node": ">= 0.4" } }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -1468,6 +1657,12 @@ "node": ">=8" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "license": "MIT" + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -1511,6 +1706,80 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, + "node_modules/jsdom": { + "version": "24.1.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.3.tgz", + "integrity": "sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ==", + "license": "MIT", + "dependencies": { + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.4", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", @@ -1668,6 +1937,25 @@ "node": ">= 0.4.0" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -1687,6 +1975,12 @@ } } }, + "node_modules/nwsapi": { + "version": "2.2.13", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.13.tgz", + "integrity": "sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==", + "license": "MIT" + }, "node_modules/object-inspect": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", @@ -1817,6 +2111,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "license": "MIT", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -2107,6 +2413,15 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "node_modules/psl": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.10.0.tgz", + "integrity": "sha512-KSKHEbjAnpUuAUserOq0FxGXCUrzC3WniuSJhvdbs102rL55266ZcHBqLWOsG30spQMlPdpy7icATiAQehg/iA==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + } + }, "node_modules/pump": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", @@ -2116,6 +2431,15 @@ "once": "^1.3.1" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/puppeteer": { "version": "23.8.0", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.8.0.tgz", @@ -2187,6 +2511,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, "node_modules/queue-tick": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", @@ -2245,6 +2575,12 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -2270,6 +2606,12 @@ "node": ">=4" } }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -2294,6 +2636,18 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -2566,6 +2920,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "license": "MIT" + }, "node_modules/tar-fs": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", @@ -2607,6 +2967,30 @@ "node": ">=0.6" } }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -2678,6 +3062,16 @@ "node": ">= 0.8" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", @@ -2716,11 +3110,65 @@ "node": ">= 0.8" } }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -2771,6 +3219,21 @@ } } }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT" + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -2837,6 +3300,62 @@ "zod": "^3.23.3" } }, + "src/duckduckgo": { + "name": "@modelcontextprotocol/server-duckduckgo", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "0.5.0", + "jsdom": "^24.1.3", + "node-fetch": "^3.3.2" + }, + "bin": { + "mcp-server-duckduckgo": "dist/index.js" + }, + "devDependencies": { + "@types/jsdom": "^21.1.6", + "@types/node": "^20.10.0", + "shx": "^0.3.4", + "typescript": "^5.6.2" + } + }, + "src/duckduckgo/node_modules/@types/node": { + "version": "20.17.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz", + "integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "src/duckduckgo/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "src/duckduckgo/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "src/everything": { "name": "@modelcontextprotocol/server-everything", "version": "0.1.0", diff --git a/src/filesystem/README.md b/src/filesystem/README.md index 3c23f956..302fc4c4 100644 --- a/src/filesystem/README.md +++ b/src/filesystem/README.md @@ -44,13 +44,6 @@ Node.js server implementing Model Context Protocol (MCP) for filesystem operatio - List directory contents with [FILE] or [DIR] prefixes - Input: `path` (string) -- **delete_file** - - Remove files or directories - - Inputs: - - `path` (string) - - `recursive` (boolean, optional): For directory deletion - - Use with caution - deletions are permanent - - **move_file** - Move or rename files and directories - Inputs: @@ -79,5 +72,5 @@ Node.js server implementing Model Context Protocol (MCP) for filesystem operatio ## Notes -- Exercise caution with `delete_file` (deletes files permanently) and `write_file` (overwrites existing files) +- Exercise caution with `write_file`, since it can overwrite an existing file - File paths can be absolute or relative diff --git a/src/filesystem/index.ts b/src/filesystem/index.ts index dcff5af0..25e22bea 100644 --- a/src/filesystem/index.ts +++ b/src/filesystem/index.ts @@ -35,11 +35,6 @@ interface ListDirectoryArgs { path: string; } -interface DeleteFileArgs { - path: string; - recursive?: boolean; -} - interface MoveFileArgs { source: string; destination: string; @@ -210,30 +205,6 @@ server.setRequestHandler(ListToolsRequestSchema, async () => { required: ["path"], }, }, - { - name: "delete_file", - description: - "Remove files or directories from the file system. Can handle both individual " + - "files and directories. For directories, you can specify recursive deletion to " + - "remove all contents. Use with extreme caution as deletions are permanent and " + - "cannot be undone.", - inputSchema: { - type: "object", - properties: { - path: { - type: "string", - description: "Path of the file or directory to delete", - }, - recursive: { - type: "boolean", - description: - "If true, recursively delete directories and their contents. Required for non-empty directories.", - default: false, - }, - }, - required: ["path"], - }, - }, { name: "move_file", description: @@ -393,18 +364,6 @@ function isListDirectoryArgs(args: unknown): args is ListDirectoryArgs { ); } -function isDeleteFileArgs(args: unknown): args is DeleteFileArgs { - const deleteArgs = args as DeleteFileArgs; - return ( - typeof args === "object" && - args !== null && - "path" in args && - typeof deleteArgs.path === "string" && - (deleteArgs.recursive === undefined || - typeof deleteArgs.recursive === "boolean") - ); -} - function isMoveFileArgs(args: unknown): args is MoveFileArgs { return ( typeof args === "object" && @@ -506,27 +465,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { }; } - case "delete_file": { - if (!isDeleteFileArgs(args)) { - throw new Error("Invalid arguments for delete_file"); - } - const stats = await fs.stat(args.path); - if (stats.isDirectory()) { - if (args.recursive) { - await fs.rm(args.path, { recursive: true }); - } else { - await fs.rmdir(args.path); - } - } else { - await fs.unlink(args.path); - } - return { - content: [ - { type: "text", text: `Successfully deleted ${args.path}` }, - ], - }; - } - case "move_file": { if (!isMoveFileArgs(args)) { throw new Error("Invalid arguments for move_file"); From 1902c3bebb95f95f97a0eb8fdec70c8204ce99bf Mon Sep 17 00:00:00 2001 From: Mahesh Murag Date: Wed, 20 Nov 2024 01:35:43 -0500 Subject: [PATCH 07/13] Minor updates to filesystem --- package-lock.json | 382 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 380 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f5c4dee..7730c30e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "dependencies": { "@modelcontextprotocol/server-duckduckgo": "*", "@modelcontextprotocol/server-everything": "*", + "@modelcontextprotocol/server-filesystem": "*", "@modelcontextprotocol/server-gdrive": "*", "@modelcontextprotocol/server-postgres": "*", "@modelcontextprotocol/server-puppeteer": "*", @@ -55,6 +56,102 @@ "node": ">=14.0.0" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@modelcontextprotocol/sdk": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-0.5.0.tgz", @@ -73,6 +170,10 @@ "resolved": "src/everything", "link": true }, + "node_modules/@modelcontextprotocol/server-filesystem": { + "resolved": "src/filesystem", + "link": true + }, "node_modules/@modelcontextprotocol/server-gdrive": { "resolved": "src/gdrive", "link": true @@ -89,6 +190,16 @@ "resolved": "src/slack", "link": true }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@puppeteer/browsers": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.4.1.tgz", @@ -381,8 +492,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/bare-events": { "version": "2.5.0", @@ -694,6 +804,20 @@ } } }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/cssstyle": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", @@ -835,6 +959,12 @@ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1367902.tgz", "integrity": "sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg==" }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -1124,6 +1254,22 @@ "node": ">= 0.8" } }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", @@ -1685,6 +1831,27 @@ "node": ">=8" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -1911,6 +2078,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", @@ -2083,6 +2259,12 @@ "node": ">= 14" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2140,12 +2322,43 @@ "node": ">=0.10.0" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/path-to-regexp": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", @@ -2735,6 +2948,27 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/shelljs": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", @@ -2785,6 +3019,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -2897,6 +3143,21 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -2908,6 +3169,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -3178,6 +3452,21 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -3194,6 +3483,24 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -3375,6 +3682,77 @@ "typescript": "^5.6.2" } }, + "src/filesystem": { + "name": "@modelcontextprotocol/server-filesystem", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "0.5.0", + "glob": "^10.3.10" + }, + "bin": { + "mcp-server-filesystem": "dist/index.js" + }, + "devDependencies": { + "@types/node": "^20.11.0", + "shx": "^0.3.4", + "typescript": "^5.3.3" + } + }, + "src/filesystem/node_modules/@types/node": { + "version": "20.17.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz", + "integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "src/filesystem/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "src/filesystem/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "src/filesystem/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "src/gdrive": { "name": "@modelcontextprotocol/server-gdrive", "version": "0.1.0", From 016f885a9c74a3d8730804d0e3c9e597d4a99afe Mon Sep 17 00:00:00 2001 From: Skirano Date: Wed, 20 Nov 2024 15:50:41 -0500 Subject: [PATCH 08/13] brave search --- package.json | 3 +- src/brave-search/README.md | 94 +++++++ src/brave-search/index.ts | 472 +++++++++++++++++++++++++++++++++ src/brave-search/package.json | 32 +++ src/brave-search/tsconfig.json | 10 + 5 files changed, 610 insertions(+), 1 deletion(-) create mode 100644 src/brave-search/README.md create mode 100644 src/brave-search/index.ts create mode 100644 src/brave-search/package.json create mode 100644 src/brave-search/tsconfig.json diff --git a/package.json b/package.json index 047179f8..b0ef6fa8 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@modelcontextprotocol/server-gdrive": "*", "@modelcontextprotocol/server-postgres": "*", "@modelcontextprotocol/server-puppeteer": "*", - "@modelcontextprotocol/server-slack": "*" + "@modelcontextprotocol/server-slack": "*", + "@modelcontextprotocol/server-brave-search": "*" } } diff --git a/src/brave-search/README.md b/src/brave-search/README.md new file mode 100644 index 00000000..2c1661d9 --- /dev/null +++ b/src/brave-search/README.md @@ -0,0 +1,94 @@ +# Brave Search MCP Server + +An MCP server implementation that integrates the Brave Search API, providing both web and local search capabilities through the Model Context Protocol. + +## Features + +- **Web Search**: General queries, news, articles, with pagination and freshness controls +- **Local Search**: Find businesses, restaurants, and services with detailed information +- **Flexible Filtering**: Control result types, safety levels, and content freshness +- **Smart Fallbacks**: Local search automatically falls back to web when no results are found + +## Configuration + +### Client Configuration +Add this to your MCP client config: + +```json +"brave-search": { + "command": "mcp-server-brave-search", + "env": { + "BRAVE_API_KEY": "YOUR_API_KEY_HERE" + } +} +``` + +Alternatively, you can set the API key as an environment variable: + +```bash +export BRAVE_API_KEY='your_actual_api_key_here' +``` + +### Getting an API Key +1. Sign up for a Brave Search API account +2. Choose a plan (Free tier available) +3. Generate your API key from the developer dashboard + +## Tools + +### brave_web_search +Performs general web searches: + +```javascript +{ + "name": "brave_web_search", + "arguments": { + "query": "latest AI developments", + "count": 10, + "freshness": "pw", // Past week + "safesearch": "moderate" + } +} +``` + +### brave_local_search +Finds local businesses and services: + +```javascript +{ + "name": "brave_local_search", + "arguments": { + "query": "pizza near Central Park", + "count": 5, + "units": "imperial" + } +} +``` + +## Key Implementation Details + +- Rate limiting to respect API quotas (1 request/second, 15000/month) +- Parallel fetching of POI details and descriptions for local search +- Type-safe argument validation +- Comprehensive error handling and logging + +## Development + +```bash +# Install dependencies +npm install + +# Build the server +npm run build + +# Run the server +mcp-server-brave-search +``` + +## Contributing + +Contributions welcome! Please check the issues tab or submit a PR. + +## License + +MIT - see [LICENSE](LICENSE) file for details. diff --git a/src/brave-search/index.ts b/src/brave-search/index.ts new file mode 100644 index 00000000..1f814dbe --- /dev/null +++ b/src/brave-search/index.ts @@ -0,0 +1,472 @@ +#!/usr/bin/env node + +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { + CallToolRequestSchema, + ListResourcesRequestSchema, + ListToolsRequestSchema, + ReadResourceRequestSchema, + Tool, +} from "@modelcontextprotocol/sdk/types.js"; +import fetch from "node-fetch"; + +// Define tool schemas +const WEB_SEARCH_TOOL: Tool = { + name: "brave_web_search", + description: + "Performs a web search using the Brave Search API, ideal for general queries, news, articles, and online content. " + + "Use this for broad information gathering, recent events, or when you need diverse web sources. " + + "Supports pagination, content filtering, and freshness controls. " + + "Maximum 20 results per request, with offset for pagination. " + + "Additional features:\n" + + "- Safesearch: moderate (default), strict, or off\n" + + "- Freshness: filter by recency (past day/week/month/year)\n" + + "- Result types: web, news, videos, discussions\n" + + "- Spell check and query alteration support", + inputSchema: { + type: "object", + properties: { + query: { + type: "string", + description: "Search query (max 400 chars, 50 words)" + }, + count: { + type: "number", + description: "Number of results (1-20, default 10)", + default: 10 + }, + offset: { + type: "number", + description: "Pagination offset (max 9, default 0)", + default: 0 + }, + freshness: { + type: "string", + description: "Filter by recency: pd (past day), pw (past week), pm (past month), or custom date range", + enum: ["pd", "pw", "pm", "py"] + }, + safesearch: { + type: "string", + description: "Content filtering level", + enum: ["off", "moderate", "strict"], + default: "moderate" + }, + country: { + type: "string", + description: "2-letter country code for localized results", + default: "US" + }, + search_lang: { + type: "string", + description: "Search language (2+ char code)", + default: "en" + }, + ui_lang: { + type: "string", + description: "UI language preference", + default: "en-US" + }, + result_filter: { + type: "string", + description: "Comma-separated result types: web, news, videos, discussions, locations", + default: null + } + }, + required: ["query"], + }, +}; + +const LOCAL_SEARCH_TOOL: Tool = { + name: "brave_local_search", + description: + "Searches for local businesses and places using Brave's Local Search API. " + + "Best for queries related to physical locations, businesses, restaurants, services, etc. " + + "Returns detailed information including:\n" + + "- Business names and addresses\n" + + "- Ratings and review counts\n" + + "- Phone numbers and opening hours\n" + + "- AI-generated descriptions\n" + + "Use this when the query implies 'near me' or mentions specific locations. " + + "Automatically falls back to web search if no local results are found.", + inputSchema: { + type: "object", + properties: { + query: { + type: "string", + description: "Local search query (e.g. 'pizza near Central Park')" + }, + count: { + type: "number", + description: "Number of results (1-20, default 5)", + default: 5 + }, + units: { + type: "string", + description: "Measurement system for distances", + enum: ["metric", "imperial"] + }, + country: { + type: "string", + description: "2-letter country code for localized results", + default: "US" + }, + search_lang: { + type: "string", + description: "Search language (2+ char code)", + default: "en" + }, + ui_lang: { + type: "string", + description: "UI language preference", + default: "en-US" + } + }, + required: ["query"] + } +}; + +// Server implementation +const server = new Server( + { + name: "example-servers/brave-search", + version: "0.1.0", + }, + { + capabilities: { + tools: {}, + resources: {}, + }, + }, +); + +// Check for API key +const BRAVE_API_KEY = process.env.BRAVE_API_KEY!; +if (!BRAVE_API_KEY) { + console.error("Error: BRAVE_API_KEY environment variable is required"); + process.exit(1); +} + +const RATE_LIMIT = { + perSecond: 1, + perMonth: 15000 +}; + +let requestCount = { + second: 0, + month: 0, + lastReset: Date.now() +}; + +function checkRateLimit() { + const now = Date.now(); + if (now - requestCount.lastReset > 1000) { + requestCount.second = 0; + requestCount.lastReset = now; + } + if (requestCount.second >= RATE_LIMIT.perSecond || + requestCount.month >= RATE_LIMIT.perMonth) { + throw new Error('Rate limit exceeded'); + } + requestCount.second++; + requestCount.month++; +} + +interface BraveWeb { + web?: { + results?: Array<{ + title: string; + description: string; + url: string; + language?: string; + published?: string; + rank?: number; + }>; + }; + locations?: { + results?: Array<{ + id: string; // Required by API + title?: string; + }>; + }; +} + +interface BraveLocation { + id: string; + name: string; + address: { + streetAddress?: string; + addressLocality?: string; + addressRegion?: string; + postalCode?: string; + }; + coordinates?: { + latitude: number; + longitude: number; + }; + phone?: string; + rating?: { + ratingValue?: number; + ratingCount?: number; + }; + openingHours?: string[]; + priceRange?: string; +} + +interface BravePoiResponse { + results: BraveLocation[]; +} + +interface BraveDescription { + descriptions: {[id: string]: string}; +} + +// Type guard functions for arguments +function isBraveWebSearchArgs(args: unknown): args is { query: string; count?: number } { + return ( + typeof args === "object" && + args !== null && + "query" in args && + typeof (args as { query: string }).query === "string" + ); +} + +function isBraveLocalSearchArgs(args: unknown): args is { query: string; count?: number } { + return ( + typeof args === "object" && + args !== null && + "query" in args && + typeof (args as { query: string }).query === "string" + ); +} + +// API functions +async function performWebSearch(query: string, count: number = 10, offset: number = 0) { + checkRateLimit(); + const url = new URL('https://api.search.brave.com/res/v1/web/search'); + url.searchParams.set('q', query); + url.searchParams.set('search_lang', 'en'); + url.searchParams.set('count', Math.min(count, 20).toString()); // API limit + url.searchParams.set('offset', offset.toString()); + url.searchParams.set('result_filter', 'web'); + url.searchParams.set('text_decorations', '0'); + url.searchParams.set('spellcheck', '0'); + url.searchParams.set('safesearch', 'moderate'); + url.searchParams.set('freshness', 'pw'); // Past week results + + const response = await fetch(url, { + headers: { + 'Accept': 'application/json', + 'Accept-Encoding': 'gzip', + 'X-Subscription-Token': BRAVE_API_KEY + } + }); + + if (!response.ok) { + throw new Error(`Brave API error: ${response.status} ${response.statusText}\n${await response.text()}`); + } + + const data = await response.json() as BraveWeb; + + // Extract just web results + const results = (data.web?.results || []).map(result => ({ + title: result.title || '', + description: result.description || '', + url: result.url || '' + })); + + return results.map(r => + `Title: ${r.title}\nDescription: ${r.description}\nURL: ${r.url}` + ).join('\n\n'); +} + +async function performLocalSearch(query: string, count: number = 5) { + checkRateLimit(); + // Initial search to get location IDs + const webUrl = new URL('https://api.search.brave.com/res/v1/web/search'); + webUrl.searchParams.set('q', query); + webUrl.searchParams.set('search_lang', 'en'); + webUrl.searchParams.set('result_filter', 'locations'); + webUrl.searchParams.set('count', Math.min(count, 20).toString()); + + const webResponse = await fetch(webUrl, { + headers: { + 'Accept': 'application/json', + 'Accept-Encoding': 'gzip', + 'X-Subscription-Token': BRAVE_API_KEY + } + }); + + if (!webResponse.ok) { + throw new Error(`Brave API error: ${webResponse.status} ${webResponse.statusText}\n${await webResponse.text()}`); + } + + const webData = await webResponse.json() as BraveWeb; + const locationIds = webData.locations?.results?.filter((r): r is {id: string; title?: string} => r.id != null).map(r => r.id) || []; + + if (locationIds.length === 0) { + return performWebSearch(query, count); // Fallback to web search + } + + // Get POI details and descriptions in parallel + const [poisData, descriptionsData] = await Promise.all([ + getPoisData(locationIds), + getDescriptionsData(locationIds) + ]); + + return formatLocalResults(poisData, descriptionsData); +} + +async function getPoisData(ids: string[]): Promise { + checkRateLimit(); + const url = new URL('https://api.search.brave.com/res/v1/local/pois'); + ids.filter(Boolean).forEach(id => url.searchParams.append('ids', id)); + const response = await fetch(url, { + headers: { + 'Accept': 'application/json', + 'Accept-Encoding': 'gzip', + 'X-Subscription-Token': BRAVE_API_KEY + } + }); + + if (!response.ok) { + throw new Error(`Brave API error: ${response.status} ${response.statusText}\n${await response.text()}`); + } + + const poisResponse = await response.json() as BravePoiResponse; + return poisResponse; +} + +async function getDescriptionsData(ids: string[]): Promise { + checkRateLimit(); + const url = new URL('https://api.search.brave.com/res/v1/local/descriptions'); + ids.filter(Boolean).forEach(id => url.searchParams.append('ids', id)); + const response = await fetch(url, { + headers: { + 'Accept': 'application/json', + 'Accept-Encoding': 'gzip', + 'X-Subscription-Token': BRAVE_API_KEY + } + }); + + if (!response.ok) { + throw new Error(`Brave API error: ${response.status} ${response.statusText}\n${await response.text()}`); + } + + const descriptionsData = await response.json() as BraveDescription; + return descriptionsData; +} + +function formatLocalResults(poisData: BravePoiResponse, descData: BraveDescription): string { + return (poisData.results || []).map(poi => { + const address = [ + poi.address?.streetAddress ?? '', + poi.address?.addressLocality ?? '', + poi.address?.addressRegion ?? '', + poi.address?.postalCode ?? '' + ].filter(part => part !== '').join(', ') || 'N/A'; + + return `Name: ${poi.name} +Address: ${address} +Phone: ${poi.phone || 'N/A'} +Rating: ${poi.rating?.ratingValue ?? 'N/A'} (${poi.rating?.ratingCount ?? 0} reviews) +Price Range: ${poi.priceRange || 'N/A'} +Hours: ${(poi.openingHours || []).join(', ') || 'N/A'} +Description: ${descData.descriptions[poi.id] || 'No description available'} +`; + }).join('\n---\n') || 'No local results found'; +} + +// Resource handlers +server.setRequestHandler(ListResourcesRequestSchema, async () => ({ + resources: [ + { + uri: "brave://search", + mimeType: "text/plain", + name: "Brave Search Interface", + }, + ], +})); + +server.setRequestHandler(ReadResourceRequestSchema, async (request) => { + if (request.params.uri.toString() === "brave://search") { + return { + contents: [ + { + uri: "brave://search", + mimeType: "text/plain", + text: "Brave Search API interface", + }, + ], + }; + } + throw new Error("Resource not found"); +}); + +// Tool handlers +server.setRequestHandler(ListToolsRequestSchema, async () => ({ + tools: [WEB_SEARCH_TOOL, LOCAL_SEARCH_TOOL], +})); + +server.setRequestHandler(CallToolRequestSchema, async (request) => { + try { + const { name, arguments: args } = request.params; + + if (!args) { + throw new Error("No arguments provided"); + } + + switch (name) { + case "brave_web_search": { + if (!isBraveWebSearchArgs(args)) { + throw new Error("Invalid arguments for brave_web_search"); + } + const { query, count = 10 } = args; + const results = await performWebSearch(query, count); + return { + content: [{ type: "text", text: results }], + isError: false, + }; + } + + case "brave_local_search": { + if (!isBraveLocalSearchArgs(args)) { + throw new Error("Invalid arguments for brave_local_search"); + } + const { query, count = 5 } = args; + const results = await performLocalSearch(query, count); + return { + content: [{ type: "text", text: results }], + isError: false, + }; + } + + default: + return { + content: [{ type: "text", text: `Unknown tool: ${name}` }], + isError: true, + }; + } + } catch (error) { + return { + content: [ + { + type: "text", + text: `Error: ${error instanceof Error ? error.message : String(error)}`, + }, + ], + isError: true, + }; + } +}); + +async function runServer() { + const transport = new StdioServerTransport(); + await server.connect(transport); + console.error("Brave Search MCP Server running on stdio"); +} + +runServer().catch((error) => { + console.error("Fatal error running server:", error); + process.exit(1); +}); diff --git a/src/brave-search/package.json b/src/brave-search/package.json new file mode 100644 index 00000000..3769c583 --- /dev/null +++ b/src/brave-search/package.json @@ -0,0 +1,32 @@ +{ + "name": "@modelcontextprotocol/server-brave-search", + "version": "0.1.0", + "description": "MCP server for Brave Search API integration", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/servers/issues", + "type": "module", + "bin": { + "mcp-server-brave-search": "dist/index.js" + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsc && shx chmod +x dist/*.js", + "prepare": "npm run build", + "watch": "tsc --watch" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "0.5.0", + "jsdom": "^24.1.3", + "node-fetch": "^3.3.2" + }, + "devDependencies": { + "@types/jsdom": "^21.1.6", + "@types/node": "^20.10.0", + "shx": "^0.3.4", + "typescript": "^5.6.2" + } +} diff --git a/src/brave-search/tsconfig.json b/src/brave-search/tsconfig.json new file mode 100644 index 00000000..087f641d --- /dev/null +++ b/src/brave-search/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "." + }, + "include": [ + "./**/*.ts" + ] + } From 7e89d8323f74b6bee06e7e6bd712fbb7b0e26cd5 Mon Sep 17 00:00:00 2001 From: Mahesh Murag Date: Wed, 20 Nov 2024 22:15:01 -0500 Subject: [PATCH 09/13] Updated Brave --- package-lock.json | 61 ++++++++++++++++++++++++ src/brave-search/README.md | 98 ++++++++++---------------------------- src/brave-search/index.ts | 97 +------------------------------------ 3 files changed, 87 insertions(+), 169 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7730c30e..94a2c794 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "src/*" ], "dependencies": { + "@modelcontextprotocol/server-brave-search": "*", "@modelcontextprotocol/server-duckduckgo": "*", "@modelcontextprotocol/server-everything": "*", "@modelcontextprotocol/server-filesystem": "*", @@ -162,6 +163,10 @@ "zod": "^3.23.8" } }, + "node_modules/@modelcontextprotocol/server-brave-search": { + "resolved": "src/brave-search", + "link": true + }, "node_modules/@modelcontextprotocol/server-duckduckgo": { "resolved": "src/duckduckgo", "link": true @@ -3607,6 +3612,62 @@ "zod": "^3.23.3" } }, + "src/brave-search": { + "name": "@modelcontextprotocol/server-brave-search", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "0.5.0", + "jsdom": "^24.1.3", + "node-fetch": "^3.3.2" + }, + "bin": { + "mcp-server-brave-search": "dist/index.js" + }, + "devDependencies": { + "@types/jsdom": "^21.1.6", + "@types/node": "^20.10.0", + "shx": "^0.3.4", + "typescript": "^5.6.2" + } + }, + "src/brave-search/node_modules/@types/node": { + "version": "20.17.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz", + "integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "src/brave-search/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "src/brave-search/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "src/duckduckgo": { "name": "@modelcontextprotocol/server-duckduckgo", "version": "0.1.0", diff --git a/src/brave-search/README.md b/src/brave-search/README.md index 2c1661d9..0c118e29 100644 --- a/src/brave-search/README.md +++ b/src/brave-search/README.md @@ -1,6 +1,6 @@ # Brave Search MCP Server -An MCP server implementation that integrates the Brave Search API, providing both web and local search capabilities through the Model Context Protocol. +An MCP server implementation that integrates the Brave Search API, providing both web and local search capabilities. ## Features @@ -9,86 +9,38 @@ An MCP server implementation that integrates the Brave Search API, providing bot - **Flexible Filtering**: Control result types, safety levels, and content freshness - **Smart Fallbacks**: Local search automatically falls back to web when no results are found -## Configuration +## Tools -### Client Configuration -Add this to your MCP client config: +- **brave_web_search** + - Execute web searches with pagination and filtering + - Inputs: + - `query` (string): Search terms + - `count` (number, optional): Results per page (max 20) + - `offset` (number, optional): Pagination offset (max 9) -```json -"brave-search": { - "command": "mcp-server-brave-search", - "env": { - "BRAVE_API_KEY": "YOUR_API_KEY_HERE" - } -} -``` +- **brave_local_search** + - Search for local businesses and services + - Inputs: + - `query` (string): Local search terms + - `count` (number, optional): Number of results (max 20) + - Automatically falls back to web search if no local results found -Alternatively, you can set the API key as an environment variable: -```bash -export BRAVE_API_KEY='your_actual_api_key_here' -``` +## Configuration ### Getting an API Key -1. Sign up for a Brave Search API account -2. Choose a plan (Free tier available) -3. Generate your API key from the developer dashboard - -## Tools +1. Sign up for a [Brave Search API account](https://brave.com/search/api/) +2. Choose a plan (Free tier available with 2,000 queries/month) +3. Generate your API key [from the developer dashboard](https://api.search.brave.com/app/keys) -### brave_web_search -Performs general web searches: - -```javascript -{ - "name": "brave_web_search", - "arguments": { - "query": "latest AI developments", - "count": 10, - "freshness": "pw", // Past week - "safesearch": "moderate" - } -} -``` +### Usage with Claude Desktop +Add this to your `claude_desktop_config.json`: -### brave_local_search -Finds local businesses and services: - -```javascript -{ - "name": "brave_local_search", - "arguments": { - "query": "pizza near Central Park", - "count": 5, - "units": "imperial" +```json +"mcp-server-brave-search": { + "command": "mcp-server-brave-search", + "env": { + "BRAVE_API_KEY": "YOUR_API_KEY_HERE" } } ``` - -## Key Implementation Details - -- Rate limiting to respect API quotas (1 request/second, 15000/month) -- Parallel fetching of POI details and descriptions for local search -- Type-safe argument validation -- Comprehensive error handling and logging - -## Development - -```bash -# Install dependencies -npm install - -# Build the server -npm run build - -# Run the server -mcp-server-brave-search -``` - -## Contributing - -Contributions welcome! Please check the issues tab or submit a PR. - -## License - -MIT - see [LICENSE](LICENSE) file for details. diff --git a/src/brave-search/index.ts b/src/brave-search/index.ts index 1f814dbe..596dc9f7 100644 --- a/src/brave-search/index.ts +++ b/src/brave-search/index.ts @@ -4,26 +4,18 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, - ListResourcesRequestSchema, ListToolsRequestSchema, - ReadResourceRequestSchema, Tool, } from "@modelcontextprotocol/sdk/types.js"; import fetch from "node-fetch"; -// Define tool schemas const WEB_SEARCH_TOOL: Tool = { name: "brave_web_search", description: "Performs a web search using the Brave Search API, ideal for general queries, news, articles, and online content. " + "Use this for broad information gathering, recent events, or when you need diverse web sources. " + "Supports pagination, content filtering, and freshness controls. " + - "Maximum 20 results per request, with offset for pagination. " + - "Additional features:\n" + - "- Safesearch: moderate (default), strict, or off\n" + - "- Freshness: filter by recency (past day/week/month/year)\n" + - "- Result types: web, news, videos, discussions\n" + - "- Spell check and query alteration support", + "Maximum 20 results per request, with offset for pagination. ", inputSchema: { type: "object", properties: { @@ -41,37 +33,6 @@ const WEB_SEARCH_TOOL: Tool = { description: "Pagination offset (max 9, default 0)", default: 0 }, - freshness: { - type: "string", - description: "Filter by recency: pd (past day), pw (past week), pm (past month), or custom date range", - enum: ["pd", "pw", "pm", "py"] - }, - safesearch: { - type: "string", - description: "Content filtering level", - enum: ["off", "moderate", "strict"], - default: "moderate" - }, - country: { - type: "string", - description: "2-letter country code for localized results", - default: "US" - }, - search_lang: { - type: "string", - description: "Search language (2+ char code)", - default: "en" - }, - ui_lang: { - type: "string", - description: "UI language preference", - default: "en-US" - }, - result_filter: { - type: "string", - description: "Comma-separated result types: web, news, videos, discussions, locations", - default: null - } }, required: ["query"], }, @@ -86,7 +47,6 @@ const LOCAL_SEARCH_TOOL: Tool = { "- Business names and addresses\n" + "- Ratings and review counts\n" + "- Phone numbers and opening hours\n" + - "- AI-generated descriptions\n" + "Use this when the query implies 'near me' or mentions specific locations. " + "Automatically falls back to web search if no local results are found.", inputSchema: { @@ -101,26 +61,6 @@ const LOCAL_SEARCH_TOOL: Tool = { description: "Number of results (1-20, default 5)", default: 5 }, - units: { - type: "string", - description: "Measurement system for distances", - enum: ["metric", "imperial"] - }, - country: { - type: "string", - description: "2-letter country code for localized results", - default: "US" - }, - search_lang: { - type: "string", - description: "Search language (2+ char code)", - default: "en" - }, - ui_lang: { - type: "string", - description: "UI language preference", - default: "en-US" - } }, required: ["query"] } @@ -135,7 +75,6 @@ const server = new Server( { capabilities: { tools: {}, - resources: {}, }, }, ); @@ -221,7 +160,6 @@ interface BraveDescription { descriptions: {[id: string]: string}; } -// Type guard functions for arguments function isBraveWebSearchArgs(args: unknown): args is { query: string; count?: number } { return ( typeof args === "object" && @@ -240,19 +178,12 @@ function isBraveLocalSearchArgs(args: unknown): args is { query: string; count?: ); } -// API functions async function performWebSearch(query: string, count: number = 10, offset: number = 0) { checkRateLimit(); const url = new URL('https://api.search.brave.com/res/v1/web/search'); url.searchParams.set('q', query); - url.searchParams.set('search_lang', 'en'); url.searchParams.set('count', Math.min(count, 20).toString()); // API limit url.searchParams.set('offset', offset.toString()); - url.searchParams.set('result_filter', 'web'); - url.searchParams.set('text_decorations', '0'); - url.searchParams.set('spellcheck', '0'); - url.searchParams.set('safesearch', 'moderate'); - url.searchParams.set('freshness', 'pw'); // Past week results const response = await fetch(url, { headers: { @@ -377,32 +308,6 @@ Description: ${descData.descriptions[poi.id] || 'No description available'} }).join('\n---\n') || 'No local results found'; } -// Resource handlers -server.setRequestHandler(ListResourcesRequestSchema, async () => ({ - resources: [ - { - uri: "brave://search", - mimeType: "text/plain", - name: "Brave Search Interface", - }, - ], -})); - -server.setRequestHandler(ReadResourceRequestSchema, async (request) => { - if (request.params.uri.toString() === "brave://search") { - return { - contents: [ - { - uri: "brave://search", - mimeType: "text/plain", - text: "Brave Search API interface", - }, - ], - }; - } - throw new Error("Resource not found"); -}); - // Tool handlers server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [WEB_SEARCH_TOOL, LOCAL_SEARCH_TOOL], From afcbee06aacdc5f1a1107db6b0105f06491469f0 Mon Sep 17 00:00:00 2001 From: Mahesh Murag Date: Wed, 20 Nov 2024 22:16:10 -0500 Subject: [PATCH 10/13] Updated Brave --- src/duckduckgo/README.md | 37 -------- src/duckduckgo/index.ts | 176 ----------------------------------- src/duckduckgo/package.json | 32 ------- src/duckduckgo/tsconfig.json | 10 -- 4 files changed, 255 deletions(-) delete mode 100644 src/duckduckgo/README.md delete mode 100644 src/duckduckgo/index.ts delete mode 100644 src/duckduckgo/package.json delete mode 100644 src/duckduckgo/tsconfig.json diff --git a/src/duckduckgo/README.md b/src/duckduckgo/README.md deleted file mode 100644 index 74e25193..00000000 --- a/src/duckduckgo/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# DuckDuckGo MCP Server - -MCP server providing search functionality via DuckDuckGo's HTML interface. - -## Components - -### Resources -Single resource endpoint for search interface: -```duckduckgo://search``` - -### Tools -- **duckduckgo_search** - - Performs a search using DuckDuckGo and returns the top search results - - Inputs: - - `query` (string, required): The search query to look up - - `numResults` (number, optional): Number of results to return (default: 10) - - Returns titles, snippets, and URLs of the search results - -## Usage Example -```javascript -// Example tool call -{ - "name": "duckduckgo_search", - "arguments": { - "query": "your search query", - "numResults": 10 - } -} - -// Example response format: -{ - "content": [{ - "type": "text", - "text": "Title: Result Title\nSnippet: Result description...\nURL: https://example.com\n\nTitle: Another Result\n..." - }] -} -``` diff --git a/src/duckduckgo/index.ts b/src/duckduckgo/index.ts deleted file mode 100644 index c1d316ac..00000000 --- a/src/duckduckgo/index.ts +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/env node - -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { - CallToolRequestSchema, - ListResourcesRequestSchema, - ListToolsRequestSchema, - ReadResourceRequestSchema, - Tool, -} from "@modelcontextprotocol/sdk/types.js"; -import fetch from "node-fetch"; -import { JSDOM } from "jsdom"; - -const SEARCH_TOOL: Tool = { - name: "duckduckgo_search", - description: - "Performs a search using DuckDuckGo and returns the top search results. " + - "Returns titles, snippets, and URLs of the search results. " + - "Use this tool to search for current information on the internet.", - inputSchema: { - type: "object", - properties: { - query: { - type: "string", - description: "The search query to look up", - }, - numResults: { - type: "number", - description: "Number of results to return (default: 10)", - default: 10, - }, - }, - required: ["query"], - }, -}; - -const server = new Server( - { - name: "example-servers/duckduckgo", - version: "0.1.0", - }, - { - capabilities: { - tools: {}, - resources: {}, - }, - }, -); - -server.setRequestHandler(ListResourcesRequestSchema, async () => ({ - resources: [ - { - uri: "duckduckgo://search", - mimeType: "text/plain", - name: "DuckDuckGo Search Results", - }, - ], -})); - -server.setRequestHandler(ReadResourceRequestSchema, async (request) => { - if (request.params.uri.toString() === "duckduckgo://search") { - return { - contents: [ - { - uri: "duckduckgo://search", - mimeType: "text/plain", - text: "DuckDuckGo search interface", - }, - ], - }; - } - throw new Error("Resource not found"); -}); - -server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools: [SEARCH_TOOL], -})); - -async function performSearch(query: string, numResults: number = 10) { - const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`; - const headers = { - "User-Agent": - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", - }; - - const response = await fetch(url, { headers }); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const html = await response.text(); - const dom = new JSDOM(html); - const document = dom.window.document; - - const results = []; - const resultElements = document.querySelectorAll(".result"); - - for (let i = 0; i < Math.min(numResults, resultElements.length); i++) { - const result = resultElements[i]; - const titleElem = result.querySelector(".result__title"); - const snippetElem = result.querySelector(".result__snippet"); - const urlElem = result.querySelector(".result__url"); - - if (titleElem && snippetElem) { - results.push({ - title: titleElem.textContent?.trim() || "", - snippet: snippetElem.textContent?.trim() || "", - url: urlElem?.getAttribute("href") || "", - }); - } - } - - return results; -} - -server.setRequestHandler(CallToolRequestSchema, async (request) => { - if (request.params.name === "duckduckgo_search") { - try { - const { query, numResults = 10 } = request.params.arguments as { - query: string; - numResults?: number; - }; - - const results = await performSearch(query, numResults); - - const formattedResults = results - .map( - (result) => - `Title: ${result.title}\nSnippet: ${result.snippet}\nURL: ${result.url}\n`, - ) - .join("\n"); - - return { - content: [ - { - type: "text", - text: formattedResults || "No results found.", - }, - ], - isError: false, - }; - } catch (error) { - return { - content: [ - { - type: "text", - text: `Error performing search: ${error instanceof Error ? error.message : String(error)}`, - }, - ], - isError: true, - }; - } - } - - return { - content: [ - { - type: "text", - text: `Unknown tool: ${request.params.name}`, - }, - ], - isError: true, - }; -}); - -async function runServer() { - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error("DuckDuckGo MCP Server running on stdio"); -} - -runServer().catch((error) => { - console.error("Fatal error running server:", error); - process.exit(1); -}); \ No newline at end of file diff --git a/src/duckduckgo/package.json b/src/duckduckgo/package.json deleted file mode 100644 index a09297ea..00000000 --- a/src/duckduckgo/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "@modelcontextprotocol/server-duckduckgo", - "version": "0.1.0", - "description": "MCP server for DuckDuckGo search", - "license": "MIT", - "author": "Anthropic, PBC (https://anthropic.com)", - "homepage": "https://modelcontextprotocol.io", - "bugs": "https://github.com/modelcontextprotocol/servers/issues", - "type": "module", - "bin": { - "mcp-server-duckduckgo": "dist/index.js" - }, - "files": [ - "dist" - ], - "scripts": { - "build": "tsc && shx chmod +x dist/*.js", - "prepare": "npm run build", - "watch": "tsc --watch" - }, - "dependencies": { - "@modelcontextprotocol/sdk": "0.5.0", - "jsdom": "^24.1.3", - "node-fetch": "^3.3.2" - }, - "devDependencies": { - "@types/jsdom": "^21.1.6", - "@types/node": "^20.10.0", - "shx": "^0.3.4", - "typescript": "^5.6.2" - } -} diff --git a/src/duckduckgo/tsconfig.json b/src/duckduckgo/tsconfig.json deleted file mode 100644 index ec5da158..00000000 --- a/src/duckduckgo/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist", - "rootDir": "." - }, - "include": [ - "./**/*.ts" - ] -} From f87704fbf363bfd199fdba36c4badeb236183b8f Mon Sep 17 00:00:00 2001 From: Mahesh Murag Date: Wed, 20 Nov 2024 22:18:40 -0500 Subject: [PATCH 11/13] Updated Brave --- src/filesystem/README.md | 76 ----- src/filesystem/index.ts | 537 ----------------------------------- src/filesystem/package.json | 30 -- src/filesystem/tsconfig.json | 12 - 4 files changed, 655 deletions(-) delete mode 100644 src/filesystem/README.md delete mode 100644 src/filesystem/index.ts delete mode 100644 src/filesystem/package.json delete mode 100644 src/filesystem/tsconfig.json diff --git a/src/filesystem/README.md b/src/filesystem/README.md deleted file mode 100644 index 302fc4c4..00000000 --- a/src/filesystem/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# Filesystem MCP Server - -Node.js server implementing Model Context Protocol (MCP) for filesystem operations. - -## Features - -- Read/write files -- Create/list/delete directories -- Move files/directories -- Search files -- Get file metadata - -## API - -### Resources - -- `file://system`: File system operations interface - -### Tools - -- **read_file** - - Read complete contents of a file - - Input: `path` (string) - - Reads complete file contents with UTF-8 encoding - -- **read_multiple_files** - - Read multiple files simultaneously - - Input: `paths` (string[]) - - Failed reads won't stop the entire operation - -- **write_file** - - Create new file or overwrite existing - - Inputs: - - `path` (string): File location - - `content` (string): File content - -- **create_directory** - - Create new directory or ensure it exists - - Input: `path` (string) - - Creates parent directories if needed - - Succeeds silently if directory exists - -- **list_directory** - - List directory contents with [FILE] or [DIR] prefixes - - Input: `path` (string) - -- **move_file** - - Move or rename files and directories - - Inputs: - - `source` (string) - - `destination` (string) - - Fails if destination exists - -- **search_files** - - Recursively search for files/directories - - Inputs: - - `path` (string): Starting directory - - `pattern` (string): Search pattern - - Case-insensitive matching - - Returns full paths to matches - -- **get_file_info** - - Get detailed file/directory metadata - - Input: `path` (string) - - Returns: - - Size - - Creation time - - Modified time - - Access time - - Type (file/directory) - - Permissions - -## Notes - -- Exercise caution with `write_file`, since it can overwrite an existing file -- File paths can be absolute or relative diff --git a/src/filesystem/index.ts b/src/filesystem/index.ts deleted file mode 100644 index 25e22bea..00000000 --- a/src/filesystem/index.ts +++ /dev/null @@ -1,537 +0,0 @@ -#!/usr/bin/env node - -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { - CallToolRequestSchema, - ListResourcesRequestSchema, - ListToolsRequestSchema, - ReadResourceRequestSchema, -} from "@modelcontextprotocol/sdk/types.js"; -import fs from "fs/promises"; -import path from "path"; -import { promisify } from "util"; -import { exec as execCallback } from "child_process"; - -// Define interfaces for the tool arguments -interface ReadFileArgs { - path: string; -} - -interface ReadMultipleFilesArgs { - paths: string[]; -} - -interface WriteFileArgs { - path: string; - content: string; -} - -interface CreateDirectoryArgs { - path: string; -} - -interface ListDirectoryArgs { - path: string; -} - -interface MoveFileArgs { - source: string; - destination: string; -} - -interface SearchFilesArgs { - path: string; - pattern: string; -} - -interface FileInfo { - size: number; - created: Date; - modified: Date; - accessed: Date; - isDirectory: boolean; - isFile: boolean; - permissions: string; -} - -const exec = promisify(execCallback); - -const server = new Server( - { - name: "example-servers/filesystem", - version: "0.1.0", - }, - { - capabilities: { - tools: {}, - resources: {}, // Need this since we're using resources - }, - }, -); - -// Add Resources List Handler -server.setRequestHandler(ListResourcesRequestSchema, async () => { - return { - resources: [ - { - uri: "file://system", - mimeType: "text/plain", - name: "File System Operations", - }, - ], - }; -}); - -// Add Read Resource Handler -server.setRequestHandler(ReadResourceRequestSchema, async (request) => { - if (request.params.uri.toString() === "file://system") { - return { - contents: [ - { - uri: "file://system", - mimeType: "text/plain", - text: "File system operations interface", - }, - ], - }; - } - throw new Error("Resource not found"); -}); - -server.setRequestHandler(ListToolsRequestSchema, async () => { - return { - tools: [ - { - name: "read_file", - description: - "Read the complete contents of a file from the file system. " + - "Handles various text encodings and provides detailed error messages " + - "if the file cannot be read. Use this tool when you need to examine " + - "the contents of a single file.", - inputSchema: { - type: "object", - properties: { - path: { - type: "string", - description: - "Absolute or relative path to the file you want to read", - }, - }, - required: ["path"], - }, - }, - { - name: "read_multiple_files", - description: - "Read the contents of multiple files simultaneously. This is more " + - "efficient than reading files one by one when you need to analyze " + - "or compare multiple files. Each file's content is returned with its " + - "path as a reference. Failed reads for individual files won't stop " + - "the entire operation.", - inputSchema: { - type: "object", - properties: { - paths: { - type: "array", - items: { - type: "string", - }, - description: - "List of file paths to read. Can be absolute or relative paths.", - }, - }, - required: ["paths"], - }, - }, - { - name: "write_file", - description: - "Create a new file or completely overwrite an existing file with new content. " + - "Use with caution as it will overwrite existing files without warning. " + - "Handles text content with proper encoding.", - inputSchema: { - type: "object", - properties: { - path: { - type: "string", - description: - "Path where the file should be written. Parent directories will be created if needed.", - }, - content: { - type: "string", - description: - "Content to write to the file. Can include newlines and special characters.", - }, - }, - required: ["path", "content"], - }, - }, - { - name: "create_directory", - description: - "Create a new directory or ensure a directory exists. Can create multiple " + - "nested directories in one operation. If the directory already exists, " + - "this operation will succeed silently. Perfect for setting up directory " + - "structures for projects or ensuring required paths exist.", - inputSchema: { - type: "object", - properties: { - path: { - type: "string", - description: - "Path of the directory to create. Will create parent directories if they don't exist.", - }, - }, - required: ["path"], - }, - }, - { - name: "list_directory", - description: - "Get a detailed listing of all files and directories in a specified path. " + - "Results clearly distinguish between files and directories with [FILE] and [DIR] " + - "prefixes. This tool is essential for understanding directory structure and " + - "finding specific files within a directory.", - inputSchema: { - type: "object", - properties: { - path: { - type: "string", - description: - "Path of the directory to list. Must be an existing directory.", - }, - }, - required: ["path"], - }, - }, - { - name: "move_file", - description: - "Move or rename files and directories. Can move files between directories " + - "and rename them in a single operation. If the destination exists, the " + - "operation will fail. Works across different directories and can be used " + - "for simple renaming within the same directory.", - inputSchema: { - type: "object", - properties: { - source: { - type: "string", - description: "Current path of the file or directory", - }, - destination: { - type: "string", - description: - "New path where the file or directory should be moved to", - }, - }, - required: ["source", "destination"], - }, - }, - { - name: "search_files", - description: - "Recursively search for files and directories matching a pattern. " + - "Searches through all subdirectories from the starting path. The search " + - "is case-insensitive and matches partial names. Returns full paths to all " + - "matching items. Great for finding files when you don't know their exact location.", - inputSchema: { - type: "object", - properties: { - path: { - type: "string", - description: "Starting directory for the search", - }, - pattern: { - type: "string", - description: - "Text pattern to search for in file and directory names", - }, - }, - required: ["path", "pattern"], - }, - }, - { - name: "get_file_info", - description: - "Retrieve detailed metadata about a file or directory. Returns comprehensive " + - "information including size, creation time, last modified time, permissions, " + - "and type. This tool is perfect for understanding file characteristics " + - "without reading the actual content.", - inputSchema: { - type: "object", - properties: { - path: { - type: "string", - description: - "Path to the file or directory to get information about", - }, - }, - required: ["path"], - }, - }, - ], - }; -}); - -async function getFileStats(filePath: string): Promise { - const stats = await fs.stat(filePath); - return { - size: stats.size, - created: stats.birthtime, - modified: stats.mtime, - accessed: stats.atime, - isDirectory: stats.isDirectory(), - isFile: stats.isFile(), - permissions: stats.mode.toString(8).slice(-3), - }; -} - -async function searchFiles( - rootPath: string, - pattern: string, -): Promise { - const results: string[] = []; - - async function search(currentPath: string) { - const entries = await fs.readdir(currentPath, { withFileTypes: true }); - - for (const entry of entries) { - const fullPath = path.join(currentPath, entry.name); - - if (entry.name.toLowerCase().includes(pattern.toLowerCase())) { - results.push(fullPath); - } - - if (entry.isDirectory()) { - await search(fullPath); - } - } - } - - await search(rootPath); - return results; -} - -// Add type guard functions for each argument type -function isReadFileArgs(args: unknown): args is ReadFileArgs { - return ( - typeof args === "object" && - args !== null && - "path" in args && - typeof (args as ReadFileArgs).path === "string" - ); -} - -function isReadMultipleFilesArgs(args: unknown): args is ReadMultipleFilesArgs { - return ( - typeof args === "object" && - args !== null && - "paths" in args && - Array.isArray((args as ReadMultipleFilesArgs).paths) && - (args as ReadMultipleFilesArgs).paths.every( - (path) => typeof path === "string", - ) - ); -} - -function isWriteFileArgs(args: unknown): args is WriteFileArgs { - return ( - typeof args === "object" && - args !== null && - "path" in args && - "content" in args && - typeof (args as WriteFileArgs).path === "string" && - typeof (args as WriteFileArgs).content === "string" - ); -} - -function isCreateDirectoryArgs(args: unknown): args is CreateDirectoryArgs { - return ( - typeof args === "object" && - args !== null && - "path" in args && - typeof (args as CreateDirectoryArgs).path === "string" - ); -} - -function isListDirectoryArgs(args: unknown): args is ListDirectoryArgs { - return ( - typeof args === "object" && - args !== null && - "path" in args && - typeof (args as ListDirectoryArgs).path === "string" - ); -} - -function isMoveFileArgs(args: unknown): args is MoveFileArgs { - return ( - typeof args === "object" && - args !== null && - "source" in args && - "destination" in args && - typeof (args as MoveFileArgs).source === "string" && - typeof (args as MoveFileArgs).destination === "string" - ); -} - -function isSearchFilesArgs(args: unknown): args is SearchFilesArgs { - return ( - typeof args === "object" && - args !== null && - "path" in args && - "pattern" in args && - typeof (args as SearchFilesArgs).path === "string" && - typeof (args as SearchFilesArgs).pattern === "string" - ); -} - -server.setRequestHandler(CallToolRequestSchema, async (request) => { - try { - const { name, arguments: args } = request.params; - - switch (name) { - case "read_file": { - if (!isReadFileArgs(args)) { - throw new Error("Invalid arguments for read_file"); - } - const content = await fs.readFile(args.path, "utf-8"); - return { - content: [{ type: "text", text: content }], - }; - } - - case "read_multiple_files": { - if (!isReadMultipleFilesArgs(args)) { - throw new Error("Invalid arguments for read_multiple_files"); - } - const results = await Promise.all( - args.paths.map(async (filePath: string) => { - try { - const content = await fs.readFile(filePath, "utf-8"); - return `${filePath}:\n${content}\n`; - } catch (error) { - const errorMessage = - error instanceof Error ? error.message : String(error); - return `${filePath}: Error - ${errorMessage}`; - } - }), - ); - return { - content: [{ type: "text", text: results.join("\n---\n") }], - }; - } - - case "write_file": { - if (!isWriteFileArgs(args)) { - throw new Error("Invalid arguments for write_file"); - } - await fs.writeFile(args.path, args.content, "utf-8"); - return { - content: [ - { type: "text", text: `Successfully wrote to ${args.path}` }, - ], - }; - } - - case "create_directory": { - if (!isCreateDirectoryArgs(args)) { - throw new Error("Invalid arguments for create_directory"); - } - await fs.mkdir(args.path, { recursive: true }); - return { - content: [ - { - type: "text", - text: `Successfully created directory ${args.path}`, - }, - ], - }; - } - - case "list_directory": { - if (!isListDirectoryArgs(args)) { - throw new Error("Invalid arguments for list_directory"); - } - const entries = await fs.readdir(args.path, { withFileTypes: true }); - const formatted = entries - .map( - (entry) => - `${entry.isDirectory() ? "[DIR]" : "[FILE]"} ${entry.name}`, - ) - .join("\n"); - return { - content: [{ type: "text", text: formatted }], - }; - } - - case "move_file": { - if (!isMoveFileArgs(args)) { - throw new Error("Invalid arguments for move_file"); - } - await fs.rename(args.source, args.destination); - return { - content: [ - { - type: "text", - text: `Successfully moved ${args.source} to ${args.destination}`, - }, - ], - }; - } - - case "search_files": { - if (!isSearchFilesArgs(args)) { - throw new Error("Invalid arguments for search_files"); - } - const results = await searchFiles(args.path, args.pattern); - return { - content: [ - { - type: "text", - text: - results.length > 0 ? results.join("\n") : "No matches found", - }, - ], - }; - } - - case "get_file_info": { - if (!isCreateDirectoryArgs(args)) { - throw new Error("Invalid arguments for get_file_info"); - } - const info = await getFileStats(args.path); - return { - content: [ - { - type: "text", - text: Object.entries(info) - .map(([key, value]) => `${key}: ${value}`) - .join("\n"), - }, - ], - }; - } - - default: - throw new Error(`Unknown tool: ${name}`); - } - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${errorMessage}` }], - isError: true, - }; - } -}); - -async function runServer() { - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error("MCP Server running on stdio"); -} - -runServer().catch((error) => { - console.error("Fatal error running server:", error); - process.exit(1); -}); diff --git a/src/filesystem/package.json b/src/filesystem/package.json deleted file mode 100644 index 8bc2b770..00000000 --- a/src/filesystem/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "@modelcontextprotocol/server-filesystem", - "version": "0.1.0", - "description": "MCP server for filesystem access", - "license": "MIT", - "author": "Anthropic, PBC (https://anthropic.com)", - "homepage": "https://modelcontextprotocol.io", - "bugs": "https://github.com/modelcontextprotocol/servers/issues", - "type": "module", - "bin": { - "mcp-server-filesystem": "dist/index.js" - }, - "files": [ - "dist" - ], - "scripts": { - "build": "tsc && shx chmod +x dist/*.js", - "prepare": "npm run build", - "watch": "tsc --watch" - }, - "dependencies": { - "@modelcontextprotocol/sdk": "0.5.0", - "glob": "^10.3.10" - }, - "devDependencies": { - "@types/node": "^20.11.0", - "shx": "^0.3.4", - "typescript": "^5.3.3" - } -} diff --git a/src/filesystem/tsconfig.json b/src/filesystem/tsconfig.json deleted file mode 100644 index c0c20f35..00000000 --- a/src/filesystem/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist", - "rootDir": ".", - "moduleResolution": "NodeNext", - "module": "NodeNext" - }, - "include": [ - "./**/*.ts" - ] -} From 252c57a293cdef92252917c445e3bd2da5f104dd Mon Sep 17 00:00:00 2001 From: Mahesh Murag Date: Wed, 20 Nov 2024 22:22:11 -0500 Subject: [PATCH 12/13] Updated Brave --- package-lock.json | 2 -- src/brave-search/package.json | 2 -- 2 files changed, 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 94a2c794..77b4e75b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3618,14 +3618,12 @@ "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "0.5.0", - "jsdom": "^24.1.3", "node-fetch": "^3.3.2" }, "bin": { "mcp-server-brave-search": "dist/index.js" }, "devDependencies": { - "@types/jsdom": "^21.1.6", "@types/node": "^20.10.0", "shx": "^0.3.4", "typescript": "^5.6.2" diff --git a/src/brave-search/package.json b/src/brave-search/package.json index 3769c583..1b39f592 100644 --- a/src/brave-search/package.json +++ b/src/brave-search/package.json @@ -20,11 +20,9 @@ }, "dependencies": { "@modelcontextprotocol/sdk": "0.5.0", - "jsdom": "^24.1.3", "node-fetch": "^3.3.2" }, "devDependencies": { - "@types/jsdom": "^21.1.6", "@types/node": "^20.10.0", "shx": "^0.3.4", "typescript": "^5.6.2" From dc123c1f926e4fdad5691fc053c574c5a3716a74 Mon Sep 17 00:00:00 2001 From: Mahesh Murag Date: Wed, 20 Nov 2024 22:25:09 -0500 Subject: [PATCH 13/13] Updated Brave --- package-lock.json | 763 +--------------------------------------------- package.json | 2 - 2 files changed, 4 insertions(+), 761 deletions(-) diff --git a/package-lock.json b/package-lock.json index 319a7fe0..55939430 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,9 +13,7 @@ ], "dependencies": { "@modelcontextprotocol/server-brave-search": "*", - "@modelcontextprotocol/server-duckduckgo": "*", "@modelcontextprotocol/server-everything": "*", - "@modelcontextprotocol/server-filesystem": "*", "@modelcontextprotocol/server-gdrive": "*", "@modelcontextprotocol/server-memory": "*", "@modelcontextprotocol/server-postgres": "*", @@ -58,102 +56,6 @@ "node": ">=14.0.0" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@modelcontextprotocol/sdk": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-0.5.0.tgz", @@ -168,18 +70,10 @@ "resolved": "src/brave-search", "link": true }, - "node_modules/@modelcontextprotocol/server-duckduckgo": { - "resolved": "src/duckduckgo", - "link": true - }, "node_modules/@modelcontextprotocol/server-everything": { "resolved": "src/everything", "link": true }, - "node_modules/@modelcontextprotocol/server-filesystem": { - "resolved": "src/filesystem", - "link": true - }, "node_modules/@modelcontextprotocol/server-gdrive": { "resolved": "src/gdrive", "link": true @@ -204,16 +98,6 @@ "resolved": "src/slack", "link": true }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/@puppeteer/browsers": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.4.1.tgz", @@ -310,18 +194,6 @@ "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", "dev": true }, - "node_modules/@types/jsdom": { - "version": "21.1.7", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", - "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" - } - }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -390,13 +262,6 @@ "@types/send": "*" } }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -515,7 +380,8 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/bare-events": { "version": "2.5.0", @@ -827,32 +693,6 @@ } } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cssstyle": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", - "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", - "license": "MIT", - "dependencies": { - "rrweb-cssom": "^0.7.1" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", @@ -861,53 +701,6 @@ "node": ">= 14" } }, - "node_modules/data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "license": "MIT", - "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/data-urls/node_modules/tr46": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", - "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/data-urls/node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/data-urls/node_modules/whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", - "license": "MIT", - "dependencies": { - "tr46": "^5.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -916,12 +709,6 @@ "ms": "2.0.0" } }, - "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "license": "MIT" - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -982,12 +769,6 @@ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1367902.tgz", "integrity": "sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg==" }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -1022,18 +803,6 @@ "once": "^1.4.0" } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -1277,22 +1046,6 @@ "node": ">= 0.8" } }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/form-data": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", @@ -1601,18 +1354,6 @@ "node": ">= 0.4" } }, - "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "license": "MIT", - "dependencies": { - "whatwg-encoding": "^3.1.1" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -1826,12 +1567,6 @@ "node": ">=8" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "license": "MIT" - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -1854,27 +1589,6 @@ "node": ">=8" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -1896,80 +1610,6 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, - "node_modules/jsdom": { - "version": "24.1.3", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.3.tgz", - "integrity": "sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ==", - "license": "MIT", - "dependencies": { - "cssstyle": "^4.0.1", - "data-urls": "^5.0.0", - "decimal.js": "^10.4.3", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.5", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.12", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.7.1", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.4", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0", - "ws": "^8.18.0", - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "canvas": "^2.11.2" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/tr46": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", - "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/jsdom/node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/jsdom/node_modules/whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", - "license": "MIT", - "dependencies": { - "tr46": "^5.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", @@ -2101,15 +1741,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", @@ -2174,12 +1805,6 @@ } } }, - "node_modules/nwsapi": { - "version": "2.2.13", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.13.tgz", - "integrity": "sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==", - "license": "MIT" - }, "node_modules/object-inspect": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", @@ -2282,12 +1907,6 @@ "node": ">= 14" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "license": "BlueOak-1.0.0" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2316,18 +1935,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse5": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", - "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", - "license": "MIT", - "dependencies": { - "entities": "^4.5.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -2345,43 +1952,12 @@ "node": ">=0.10.0" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" - }, "node_modules/path-to-regexp": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", @@ -2649,15 +2225,6 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, - "node_modules/psl": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.10.0.tgz", - "integrity": "sha512-KSKHEbjAnpUuAUserOq0FxGXCUrzC3WniuSJhvdbs102rL55266ZcHBqLWOsG30spQMlPdpy7icATiAQehg/iA==", - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - } - }, "node_modules/pump": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", @@ -2667,15 +2234,6 @@ "once": "^1.3.1" } }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/puppeteer": { "version": "23.8.0", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.8.0.tgz", @@ -2747,12 +2305,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "license": "MIT" - }, "node_modules/queue-tick": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", @@ -2811,12 +2363,6 @@ "node": ">=0.10.0" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "license": "MIT" - }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -2842,12 +2388,6 @@ "node": ">=4" } }, - "node_modules/rrweb-cssom": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", - "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", - "license": "MIT" - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -2872,18 +2412,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "license": "ISC", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -2971,27 +2499,6 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/shelljs": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", @@ -3042,18 +2549,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -3166,21 +2661,6 @@ "node": ">=8" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3192,19 +2672,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -3217,12 +2684,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "license": "MIT" - }, "node_modules/tar-fs": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", @@ -3264,30 +2725,6 @@ "node": ">=0.6" } }, - "node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", - "license": "BSD-3-Clause", - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -3358,16 +2795,6 @@ "node": ">= 0.8" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "license": "MIT", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "node_modules/url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", @@ -3406,18 +2833,6 @@ "node": ">= 0.8" } }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "license": "MIT", - "dependencies": { - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -3432,39 +2847,6 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "license": "MIT", - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -3474,21 +2856,6 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -3505,24 +2872,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -3548,21 +2897,6 @@ } } }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "license": "Apache-2.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "license": "MIT" - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -3686,6 +3020,7 @@ "src/duckduckgo": { "name": "@modelcontextprotocol/server-duckduckgo", "version": "0.1.0", + "extraneous": true, "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "0.5.0", @@ -3702,43 +3037,6 @@ "typescript": "^5.6.2" } }, - "src/duckduckgo/node_modules/@types/node": { - "version": "20.17.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz", - "integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "src/duckduckgo/node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "src/duckduckgo/node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "src/everything": { "name": "@modelcontextprotocol/server-everything", "version": "0.1.0", @@ -3761,6 +3059,7 @@ "src/filesystem": { "name": "@modelcontextprotocol/server-filesystem", "version": "0.1.0", + "extraneous": true, "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "0.5.0", @@ -3775,60 +3074,6 @@ "typescript": "^5.3.3" } }, - "src/filesystem/node_modules/@types/node": { - "version": "20.17.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz", - "integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "src/filesystem/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "src/filesystem/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "src/filesystem/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "src/gdrive": { "name": "@modelcontextprotocol/server-gdrive", "version": "0.1.0", diff --git a/package.json b/package.json index 325c9a9f..57e35a1d 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,7 @@ "publish-all": "npm publish --workspaces --access public && npm publish --access public" }, "dependencies": { - "@modelcontextprotocol/server-duckduckgo": "*", "@modelcontextprotocol/server-everything": "*", - "@modelcontextprotocol/server-filesystem": "*", "@modelcontextprotocol/server-gdrive": "*", "@modelcontextprotocol/server-postgres": "*", "@modelcontextprotocol/server-puppeteer": "*",