@smithery/cli 0.0.7 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@smithery/cli",
3
- "version": "0.0.7",
3
+ "version": "0.0.10",
4
+ "type": "commonjs",
4
5
  "private": false,
5
6
  "homepage": "https://smithery.ai/",
6
7
  "description": "A NPX command to install and list Model Context Protocols",
7
8
  "main": "dist/index.js",
8
9
  "scripts": {
9
- "build": "tsc && chmod +x dist/index.js",
10
+ "build": "node build.mjs && chmod +x dist/index.js",
10
11
  "start": "node dist/index.js",
11
12
  "test:list": "node --loader ts-node/esm src/index.ts list",
12
13
  "test:install": "node --loader ts-node/esm src/index.ts install",
@@ -20,31 +21,34 @@
20
21
  "pr-check": "node src/scripts/pr-check.js",
21
22
  "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --config jest.config.mjs --watch",
22
23
  "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --config jest.config.mjs --coverage",
24
+ "db:types": "npx supabase gen types typescript --project-id spjawbfpwezjfmicopsl --schema public > ./src/database.types.ts",
23
25
  "prepare": "npm run build",
24
26
  "lint": "npx @biomejs/biome lint --write",
25
27
  "format": "npx @biomejs/biome format --write"
26
28
  },
27
29
  "bin": {
28
- "@smithery/cli": "dist/index.js"
30
+ "cli": "dist/index.js"
29
31
  },
30
32
  "dependencies": {
31
33
  "@iarna/toml": "^2.2.5",
34
+ "@supabase/supabase-js": "^2.47.7",
32
35
  "@types/iarna__toml": "^2.0.5",
33
36
  "chalk": "^4.1.2",
34
37
  "cli-table3": "^0.6.5",
35
- "dotenv": "^16.4.5",
36
38
  "fuzzy": "^0.1.3",
37
39
  "inquirer": "^8.2.4",
38
40
  "inquirer-autocomplete-prompt": "^2.0.0",
39
41
  "open": "^10.1.0",
40
- "string-width": "^4.2.3",
41
- "typescript": "^4.0.0"
42
+ "string-width": "^4.2.3"
42
43
  },
43
44
  "devDependencies": {
45
+ "typescript": "^5.0.0",
44
46
  "@types/inquirer": "^8.2.4",
45
47
  "@types/inquirer-autocomplete-prompt": "^3.0.3",
46
48
  "@types/jest": "^29.5.14",
47
49
  "@types/node": "^14.0.0",
50
+ "dotenv": "^16.4.7",
51
+ "esbuild": "^0.24.0",
48
52
  "jest": "^29.7.0",
49
53
  "ts-jest": "^29.2.5",
50
54
  "ts-node": "^10.9.1",
@@ -53,15 +57,11 @@
53
57
  "files": [
54
58
  "dist",
55
59
  "README.md",
56
- "package.json",
57
- "packages",
58
- "LICENSE"
60
+ "package.json"
59
61
  ],
60
- "type": "module",
61
62
  "exports": {
62
63
  ".": {
63
64
  "import": "./dist/index.js"
64
65
  }
65
- },
66
- "license": "MIT"
66
+ }
67
67
  }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2024 Michael Latman
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,33 +0,0 @@
1
- import { exec } from "node:child_process";
2
- import { promisify } from "node:util";
3
- import { readFileSync } from "node:fs";
4
- import { join } from "node:path";
5
- import chalk from "chalk";
6
- const execAsync = promisify(exec);
7
- async function getCurrentVersion() {
8
- const packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
9
- return packageJson.version;
10
- }
11
- async function getLatestVersion() {
12
- const { stdout } = await execAsync("npm show @smithery/cli version");
13
- return stdout.trim();
14
- }
15
- export async function updatePackage() {
16
- try {
17
- const currentVersion = await getCurrentVersion();
18
- const latestVersion = await getLatestVersion();
19
- if (currentVersion !== latestVersion) {
20
- console.log(chalk.yellow(`\nA new version of @smithery/cli is available: ${latestVersion} (current: ${currentVersion})`));
21
- console.log(chalk.cyan("Installing update..."));
22
- // Use npx to ensure we get the latest version
23
- await execAsync("npx --yes @smithery/cli@latest");
24
- console.log(chalk.green("✓ Update complete\n"));
25
- // Exit after update to ensure the new version is used
26
- process.exit(0);
27
- }
28
- }
29
- catch (error) {
30
- // Log update check failure but continue with execution
31
- console.log(chalk.yellow("\nFailed to check for updates. Continuing with current version."));
32
- }
33
- }
@@ -1,25 +0,0 @@
1
- import chalk from "chalk";
2
- import { displayPackageDetailsWithActions } from "../utils/display.js";
3
- import { resolvePackage } from "../utils/package-resolver.js";
4
- import { handlePackageAction } from "../utils/package-actions.js";
5
- export async function get(packageId) {
6
- try {
7
- const pkg = await resolvePackage(packageId);
8
- if (!pkg) {
9
- console.log(chalk.yellow(`No package found with ID: ${packageId}`));
10
- return;
11
- }
12
- const action = await displayPackageDetailsWithActions(pkg);
13
- await handlePackageAction(pkg, action, {});
14
- }
15
- catch (error) {
16
- console.error(chalk.red("Error loading package:"));
17
- if (error instanceof Error && error.message.includes("fetch")) {
18
- console.error(chalk.red("Failed to connect to the package registry. Please check your internet connection."));
19
- }
20
- else {
21
- console.error(chalk.red(error instanceof Error ? error.message : String(error)));
22
- }
23
- process.exit(1);
24
- }
25
- }
@@ -1,76 +0,0 @@
1
- import { installPackage as installPkg } from "../utils/package-management.js";
2
- import inquirer from "inquirer";
3
- import chalk from "chalk";
4
- import { resolvePackage } from "../utils/package-resolver.js";
5
- import { VALID_CLIENTS } from "../utils/config.js";
6
- async function promptForRuntime() {
7
- const { runtime } = await inquirer.prompt([
8
- {
9
- type: "list",
10
- name: "runtime",
11
- message: "What runtime does this package use?",
12
- choices: [
13
- { name: "Node.js", value: "node" },
14
- { name: "Python", value: "python" },
15
- ],
16
- },
17
- ]);
18
- return runtime;
19
- }
20
- function createUnknownPackage(id, runtime, client) {
21
- return {
22
- id,
23
- name: id,
24
- description: "Unverified package",
25
- // runtime,
26
- vendor: "",
27
- sourceUrl: "",
28
- homepage: "",
29
- license: "",
30
- isInstalled: false,
31
- isVerified: false,
32
- client: client,
33
- connections: [
34
- {
35
- stdio: {
36
- command: runtime === "node" ? "npx" : "python",
37
- args: runtime === "node" ? ["-y", id] : ["-m", id],
38
- env: {},
39
- },
40
- },
41
- ],
42
- };
43
- }
44
- export async function installPackage(pkg) {
45
- return installPkg(pkg);
46
- }
47
- export async function install(packageId, client) {
48
- if (client && !VALID_CLIENTS.includes(client)) {
49
- console.error(chalk.red(`Invalid client: ${client}\nValid clients are: ${VALID_CLIENTS.join(", ")}`));
50
- process.exit(1);
51
- }
52
- const pkg = await resolvePackage(packageId, client);
53
- if (!pkg) {
54
- console.warn(chalk.yellow(`Package ${packageId} not found in registry.`));
55
- const { proceedWithInstall } = await inquirer.prompt([
56
- {
57
- type: "confirm",
58
- name: "proceedWithInstall",
59
- message: `Would you like to try installing ${packageId} anyway? This package hasn't been verified.`,
60
- default: false,
61
- },
62
- ]);
63
- if (proceedWithInstall) {
64
- console.log(chalk.cyan(`Proceeding with installation of ${packageId}...`));
65
- const runtime = await promptForRuntime();
66
- const unknownPkg = createUnknownPackage(packageId, runtime, client);
67
- await installPkg(unknownPkg);
68
- }
69
- else {
70
- console.log("Installation cancelled.");
71
- process.exit(1);
72
- }
73
- return;
74
- }
75
- await installPkg(pkg);
76
- }
@@ -1,31 +0,0 @@
1
- import inquirer from "inquirer";
2
- import chalk from "chalk";
3
- import { displayPackageDetailsWithActions } from "../utils/display.js";
4
- import { resolvePackages } from "../utils/package-resolver.js";
5
- import AutocompletePrompt from "inquirer-autocomplete-prompt";
6
- import { createPackagePrompt, printPackageListHeader } from "../utils/ui.js";
7
- import { handlePackageAction } from "../utils/package-actions.js";
8
- inquirer.registerPrompt("autocomplete", AutocompletePrompt);
9
- export async function listInstalledPackages() {
10
- const allPackages = await resolvePackages();
11
- const installedPackages = allPackages.filter((pkg) => pkg.isInstalled);
12
- if (installedPackages.length === 0) {
13
- console.log(chalk.yellow("\nNo MCP servers are currently installed."));
14
- return;
15
- }
16
- printPackageListHeader(installedPackages.length, "installed");
17
- const prompt = createPackagePrompt(installedPackages, {
18
- message: "Search and select a package:",
19
- });
20
- const answer = await inquirer.prompt([
21
- prompt,
22
- ]);
23
- if (!answer.selectedPackage) {
24
- return;
25
- }
26
- const action = await displayPackageDetailsWithActions(answer.selectedPackage);
27
- await handlePackageAction(answer.selectedPackage, action, {
28
- onUninstall: () => listInstalledPackages(),
29
- onBack: listInstalledPackages,
30
- });
31
- }
@@ -1,45 +0,0 @@
1
- import chalk from "chalk";
2
- import inquirer from "inquirer";
3
- import { displayPackageDetailsWithActions } from "../utils/display.js";
4
- import { resolvePackages } from "../utils/package-resolver.js";
5
- import AutocompletePrompt from "inquirer-autocomplete-prompt";
6
- import { createPackagePrompt, printPackageListHeader } from "../utils/ui.js";
7
- import { handlePackageAction } from "../utils/package-actions.js";
8
- // Register the autocomplete prompt
9
- inquirer.registerPrompt("autocomplete", AutocompletePrompt);
10
- export async function list() {
11
- try {
12
- const packages = await resolvePackages();
13
- // Add validation check for packages
14
- if (!Array.isArray(packages)) {
15
- throw new Error("Invalid package list returned");
16
- }
17
- // Add validation to ensure each package has the required properties
18
- if (packages.some((pkg) => !pkg || typeof pkg.id !== "string")) {
19
- throw new Error("Invalid package format: each package must have an id property");
20
- }
21
- printPackageListHeader(packages.length);
22
- // Only proceed if we have packages to display
23
- if (packages.length === 0) {
24
- console.log(chalk.yellow("No packages found."));
25
- return;
26
- }
27
- const prompt = createPackagePrompt(packages, { showInstallStatus: true });
28
- const answer = await inquirer.prompt([
29
- prompt,
30
- ]);
31
- // Validate the selected package
32
- if (!answer?.selectedPackage) {
33
- return;
34
- }
35
- const action = await displayPackageDetailsWithActions(answer.selectedPackage);
36
- await handlePackageAction(answer.selectedPackage, action, {
37
- onBack: list,
38
- });
39
- }
40
- catch (error) {
41
- console.error(chalk.red("Error loading package list:"));
42
- console.error(chalk.red(error instanceof Error ? error.message : String(error)));
43
- process.exit(1);
44
- }
45
- }
@@ -1,47 +0,0 @@
1
- import chalk from "chalk";
2
- import inquirer from "inquirer";
3
- import { resolvePackage } from "../utils/package-resolver.js";
4
- import { uninstallPackage } from "../utils/package-management.js";
5
- export async function uninstall(packageName) {
6
- console.error("!");
7
- try {
8
- // If no package name provided, show error
9
- if (!packageName) {
10
- console.error(chalk.red("Error: Package name is required"));
11
- console.log("Usage: @smithery/cli uninstall <package-name>");
12
- process.exit(1);
13
- }
14
- // Resolve the package
15
- const pkg = await resolvePackage(packageName);
16
- if (!pkg) {
17
- console.log(chalk.yellow(`Package ${packageName} not found.`));
18
- return;
19
- }
20
- if (!pkg.isInstalled) {
21
- console.log(chalk.yellow(`Package ${packageName} is not installed.`));
22
- return;
23
- }
24
- // Confirm uninstallation
25
- const { confirmUninstall } = await inquirer.prompt([
26
- {
27
- type: "confirm",
28
- name: "confirmUninstall",
29
- message: `Are you sure you want to uninstall ${packageName}?`,
30
- default: false,
31
- },
32
- ]);
33
- if (!confirmUninstall) {
34
- console.log("Uninstallation cancelled.");
35
- return;
36
- }
37
- // Perform uninstallation
38
- await uninstallPackage(packageName);
39
- console.log(chalk.green(`\nSuccessfully uninstalled ${packageName}`));
40
- console.log(chalk.yellow("\nNote: Please restart Claude for the changes to take effect."));
41
- }
42
- catch (error) {
43
- console.error(chalk.red("Failed to uninstall package:"));
44
- console.error(chalk.red(error instanceof Error ? error.message : String(error)));
45
- process.exit(1);
46
- }
47
- }
@@ -1,209 +0,0 @@
1
- import { exec } from 'child_process';
2
- import { promisify } from 'util';
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
- import { fileURLToPath } from 'url';
6
- import { dirname } from 'path';
7
- import * as TOML from '@iarna/toml';
8
- const execAsync = promisify(exec);
9
- const __filename = fileURLToPath(import.meta.url);
10
- const __dirname = dirname(__filename);
11
- const REPOS = [
12
- {
13
- url: 'https://github.com/modelcontextprotocol/servers.git',
14
- branch: 'main',
15
- packagePath: 'src',
16
- runtime: 'mixed'
17
- },
18
- {
19
- url: 'https://github.com/mcp-get/community-servers.git',
20
- branch: 'main',
21
- packagePath: 'src',
22
- runtime: 'mixed'
23
- }
24
- ];
25
- async function cloneRepo(config, tempDir) {
26
- const repoDir = path.join(tempDir, path.basename(config.url, '.git'));
27
- console.log(`Cloning ${config.url} into ${repoDir}...`);
28
- await execAsync(`git clone --depth 1 --branch ${config.branch} ${config.url} ${repoDir}`, { cwd: tempDir });
29
- return;
30
- }
31
- async function extractNodePackage(packageJsonPath, repoUrl, subPath) {
32
- try {
33
- const packageData = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
34
- const repoPath = `${repoUrl}/blob/main/${subPath}`;
35
- return {
36
- name: packageData.name || '',
37
- description: packageData.description || '',
38
- vendor: packageData.author || '',
39
- sourceUrl: repoPath,
40
- homepage: packageData.homepage || '',
41
- license: packageData.license || '',
42
- runtime: 'node'
43
- };
44
- }
45
- catch (error) {
46
- console.error(`Error extracting Node package from ${packageJsonPath}:`, error);
47
- return null;
48
- }
49
- }
50
- async function extractPythonPackage(pyprojectPath, repoUrl, subPath) {
51
- try {
52
- const pyprojectContent = fs.readFileSync(pyprojectPath, 'utf8');
53
- const pyproject = TOML.parse(pyprojectContent);
54
- if (!pyproject.project) {
55
- console.error(`No [project] section found in ${pyprojectPath}`);
56
- return null;
57
- }
58
- const { project } = pyproject;
59
- // Set vendor to Anthropic
60
- const vendor = 'Anthropic, PBC (https://anthropic.com)';
61
- // Set license to MIT
62
- const license = 'MIT';
63
- return {
64
- name: project.name || '',
65
- description: project.description || '',
66
- vendor,
67
- sourceUrl: `${repoUrl}/blob/main/${subPath}`,
68
- homepage: project.homepage || project.repository || repoUrl,
69
- license,
70
- runtime: 'python'
71
- };
72
- }
73
- catch (error) {
74
- console.error(`Error extracting Python package from ${pyprojectPath}:`, error);
75
- return null;
76
- }
77
- }
78
- export async function extractPackageInfo() {
79
- const tempDir = path.join(__dirname, '../../temp');
80
- const outputPath = path.join(__dirname, '../../packages/package-list.json');
81
- const commitMsgPath = path.join(__dirname, '../../temp/commit-msg.txt');
82
- console.log("Starting package extraction...");
83
- try {
84
- // Load existing packages
85
- let existingPackages = [];
86
- if (fs.existsSync(outputPath)) {
87
- existingPackages = JSON.parse(fs.readFileSync(outputPath, 'utf8'));
88
- }
89
- // Create temp directory if it doesn't exist
90
- if (!fs.existsSync(tempDir)) {
91
- fs.mkdirSync(tempDir, { recursive: true });
92
- }
93
- // Initialize commit message
94
- let commitMsg = "chore(packages): update MCP package list\n\nChanges:\n";
95
- let changes = [];
96
- // Process each repository
97
- const newPackages = [];
98
- for (const repo of REPOS) {
99
- await cloneRepo(repo, tempDir);
100
- const repoDir = path.join(tempDir, path.basename(repo.url, '.git'));
101
- const packagePath = path.join(repoDir, repo.packagePath);
102
- if (!fs.existsSync(packagePath))
103
- continue;
104
- const dirs = fs.readdirSync(packagePath);
105
- for (const dir of dirs) {
106
- const fullPath = path.join(packagePath, dir);
107
- if (!fs.statSync(fullPath).isDirectory())
108
- continue;
109
- // Try to extract as Node.js package
110
- const packageJsonPath = path.join(fullPath, 'package.json');
111
- if (fs.existsSync(packageJsonPath)) {
112
- const nodePackage = await extractNodePackage(packageJsonPath, repo.url.replace('.git', ''), path.join(repo.packagePath, dir));
113
- if (nodePackage) {
114
- newPackages.push(nodePackage);
115
- continue;
116
- }
117
- }
118
- // Try to extract as Python package
119
- const pyprojectPath = path.join(fullPath, 'pyproject.toml');
120
- if (fs.existsSync(pyprojectPath)) {
121
- const pythonPackage = await extractPythonPackage(pyprojectPath, repo.url.replace('.git', ''), path.join(repo.packagePath, dir));
122
- if (pythonPackage) {
123
- newPackages.push(pythonPackage);
124
- }
125
- }
126
- }
127
- }
128
- // Merge existing and new packages
129
- const mergedPackages = [...existingPackages];
130
- let hasChanges = false;
131
- for (const newPkg of newPackages) {
132
- const existingIndex = mergedPackages.findIndex(pkg => pkg.name === newPkg.name);
133
- if (existingIndex >= 0) {
134
- // Update existing package if there are changes
135
- if (JSON.stringify(mergedPackages[existingIndex]) !== JSON.stringify(newPkg)) {
136
- const oldPkg = mergedPackages[existingIndex];
137
- mergedPackages[existingIndex] = newPkg;
138
- hasChanges = true;
139
- console.log(`Updated package: ${newPkg.name}`);
140
- // Add detailed change information
141
- const changeDetails = [];
142
- if (oldPkg.description !== newPkg.description)
143
- changeDetails.push('description');
144
- if (oldPkg.vendor !== newPkg.vendor)
145
- changeDetails.push('vendor');
146
- if (oldPkg.license !== newPkg.license)
147
- changeDetails.push('license');
148
- if (oldPkg.homepage !== newPkg.homepage)
149
- changeDetails.push('homepage');
150
- if (oldPkg.sourceUrl !== newPkg.sourceUrl)
151
- changeDetails.push('sourceUrl');
152
- if (oldPkg.runtime !== newPkg.runtime)
153
- changeDetails.push('runtime');
154
- changes.push(`- Updated ${newPkg.name} (changed: ${changeDetails.join(', ')})`);
155
- }
156
- }
157
- else {
158
- // Add new package
159
- mergedPackages.push(newPkg);
160
- hasChanges = true;
161
- console.log(`Added new package: ${newPkg.name} (${newPkg.runtime})`);
162
- changes.push(`- Added new package: ${newPkg.name} (${newPkg.runtime})`);
163
- }
164
- }
165
- // Write updated packages to file if there are changes
166
- if (hasChanges) {
167
- fs.writeFileSync(outputPath, JSON.stringify(mergedPackages, null, 2));
168
- console.log('Package list updated successfully');
169
- // Write commit message with total number of changes
170
- if (changes.length === 0) {
171
- changes.push('- Initial package list creation');
172
- }
173
- commitMsg = `chore(packages): update MCP package list (${changes.length} packages)\n\nChanges:\n`;
174
- commitMsg += changes.join('\n');
175
- fs.writeFileSync(commitMsgPath, commitMsg);
176
- console.log('Commit message generated');
177
- }
178
- else {
179
- console.log('No changes detected in package list');
180
- }
181
- // Cleanup (but keep commit-msg.txt if it exists)
182
- const filesToKeep = new Set(['commit-msg.txt']);
183
- for (const file of fs.readdirSync(tempDir)) {
184
- if (!filesToKeep.has(file)) {
185
- const filePath = path.join(tempDir, file);
186
- fs.rmSync(filePath, { recursive: true, force: true });
187
- }
188
- }
189
- console.log('Temporary files cleaned up');
190
- return mergedPackages;
191
- }
192
- catch (error) {
193
- console.error('Error:', error);
194
- // Cleanup on error
195
- if (fs.existsSync(tempDir)) {
196
- fs.rmSync(tempDir, { recursive: true, force: true });
197
- }
198
- throw error;
199
- }
200
- }
201
- // Run the function if this file is executed directly
202
- if (import.meta.url === `file://${__filename}`) {
203
- extractPackageInfo()
204
- .then(() => console.log('Package extraction completed'))
205
- .catch(error => {
206
- console.error('Failed to extract packages:', error);
207
- process.exit(1);
208
- });
209
- }
@@ -1,94 +0,0 @@
1
- export const packageHelpers = {
2
- "@modelcontextprotocol/server-brave-search": {
3
- requiredEnvVars: {
4
- BRAVE_API_KEY: {
5
- description: "API key for Brave Search",
6
- required: true,
7
- },
8
- },
9
- },
10
- "@modelcontextprotocol/server-github": {
11
- requiredEnvVars: {
12
- GITHUB_PERSONAL_ACCESS_TOKEN: {
13
- description: "Personal access token for GitHub API access",
14
- required: true,
15
- },
16
- },
17
- },
18
- "@modelcontextprotocol/server-gitlab": {
19
- requiredEnvVars: {
20
- GITLAB_PERSONAL_ACCESS_TOKEN: {
21
- description: "Personal access token for GitLab API access",
22
- required: true,
23
- },
24
- GITLAB_API_URL: {
25
- description: "GitLab API URL (optional, for self-hosted instances)",
26
- required: false,
27
- },
28
- },
29
- },
30
- "@modelcontextprotocol/server-google-maps": {
31
- requiredEnvVars: {
32
- GOOGLE_MAPS_API_KEY: {
33
- description: "API key for Google Maps services",
34
- required: true,
35
- },
36
- },
37
- },
38
- "@modelcontextprotocol/server-slack": {
39
- requiredEnvVars: {
40
- SLACK_BOT_TOKEN: {
41
- description: "Slack Bot User OAuth Token (starts with xoxb-)",
42
- required: true,
43
- },
44
- SLACK_TEAM_ID: {
45
- description: "Slack Team/Workspace ID",
46
- required: true,
47
- },
48
- },
49
- },
50
- "@raygun.io/mcp-server-raygun": {
51
- requiredEnvVars: {
52
- RAYGUN_PAT_TOKEN: {
53
- description: "Personal access token for Raygun API access",
54
- required: true,
55
- },
56
- },
57
- },
58
- "@kagi/mcp-server-kagi": {
59
- requiredEnvVars: {
60
- KAGI_API_KEY: {
61
- description: "API key for Kagi Search",
62
- required: true,
63
- },
64
- },
65
- },
66
- "@exa/mcp-server": {
67
- requiredEnvVars: {
68
- EXA_API_KEY: {
69
- description: "API key for Exa AI Search",
70
- required: true,
71
- },
72
- },
73
- },
74
- "@search1api/mcp-server": {
75
- requiredEnvVars: {
76
- SEARCH1API_KEY: {
77
- description: "API key for Search1API",
78
- required: true,
79
- },
80
- },
81
- },
82
- "mcp-tinybird": {
83
- requiredEnvVars: {
84
- TB_API_URL: {
85
- description: "API URL for Tinybird",
86
- required: true,
87
- },
88
- TB_ADMIN_TOKEN: {
89
- description: "Admin token for Tinybird",
90
- required: true,
91
- },
92
- },
93
- },
94
- };