Skip to main content
Glama
yonaka15
by yonaka15

pyodide_install-packages

Install Python packages in Pyodide environments for LLM-driven Python execution. Specify multiple packages using space-separated names.

Instructions

Install Python packages using Pyodide. Multiple packages can be specified using space-separated format.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
packageYesPython package(s) to install. For multiple packages, use space-separated format (e.g., 'numpy matplotlib pandas').

Implementation Reference

  • Handler logic for pyodide_install-packages: validates arguments using arktype and delegates to PyodideManager.installPackage
    case "pyodide_install-packages": {
      const installPythonPackagesArgs = isInstallPythonPackagesArgs(args);
      if (installPythonPackagesArgs instanceof type.errors) {
        throw installPythonPackagesArgs;
      }
      const { package: packageName } = installPythonPackagesArgs;
      const results = await pyodideManager.installPackage(packageName);
      return results;
    }
  • Tool schema defining name, description, and input schema for pyodide_install-packages
    export const INSTALL_PYTHON_PACKAGES_TOOL: Tool = {
      name: "pyodide_install-packages",
      description:
        "Install Python packages using Pyodide. Multiple packages can be specified using space-separated format.",
      inputSchema: {
        type: "object",
        properties: {
          package: {
            type: "string",
            description:
              "Python package(s) to install. For multiple packages, use space-separated format (e.g., 'numpy matplotlib pandas').",
          },
        },
        required: ["package"],
      },
    };
  • Registration of the pyodide_install-packages tool in the TOOLS array used for listTools
    const TOOLS: Tool[] = [
      tools.EXECUTE_PYTHON_TOOL,
      tools.INSTALL_PYTHON_PACKAGES_TOOL,
      tools.GET_MOUNT_POINTS_TOOL,
      tools.LIST_MOUNTED_DIRECTORY_TOOL,
      tools.READ_IMAGE_TOOL,
    ];
  • Core implementation of package installation: tries loadPackage first, falls back to micropip with wheel download for unsupported packages
    async installPackage(packageName: string) {
      if (!this.pyodide) {
        return formatCallToolError("Pyodide not initialized");
      }
    
      try {
        // パッケージ名をスペースで分割
        const packages = packageName
          .split(" ")
          .map((pkg) => pkg.trim())
          .filter(Boolean);
    
        if (packages.length === 0) {
          return formatCallToolError("No valid package names specified");
        }
    
        // 出力メッセージを集める
        const outputs: string[] = [];
    
        // 各パッケージを処理
        for (const pkg of packages) {
          try {
            // 1. まずpyodide.loadPackageでインストールを試みる
            outputs.push(`Attempting to install ${pkg} using loadPackage...`);
    
            try {
              await this.pyodide.loadPackage(pkg, {
                messageCallback: (msg) => {
                  outputs.push(`loadPackage: ${msg}`);
                },
                errorCallback: (err) => {
                  throw new Error(err);
                },
              });
              outputs.push(`Successfully installed ${pkg} using loadPackage.`);
              continue; // このパッケージは成功したので次のパッケージへ
            } catch (loadPackageError) {
              outputs.push(
                `loadPackage failed for ${pkg}: ${
                  loadPackageError instanceof Error
                    ? loadPackageError.message
                    : String(loadPackageError)
                }`
              );
              outputs.push(`Falling back to micropip for ${pkg}...`);
    
              // loadPackageが失敗した場合は、micropipを使用する
              // micropipがまだロードされていない場合はロードする
              try {
                // micropipをロードする
                await this.pyodide.loadPackage("micropip", {
                  messageCallback: (msg) => {
                    outputs.push(`loadPackage: ${msg}`);
                  },
                  errorCallback: (err) => {
                    throw new Error(err);
                  },
                });
              } catch (micropipLoadError) {
                throw new Error(
                  `Failed to load micropip: ${
                    micropipLoadError instanceof Error
                      ? micropipLoadError.message
                      : String(micropipLoadError)
                  }`
                );
              }
    
              // 2. micropipを使ったインストール処理
              // 一時ディレクトリを作成
              const tempDir = process.env.PYODIDE_CACHE_DIR || "./cache";
              if (!fs.existsSync(tempDir)) {
                fs.mkdirSync(tempDir, { recursive: true });
              }
    
              // Pyodide内のtempディレクトリを作成
              this.pyodide.FS.mkdirTree("/tmp/wheels");
    
              // PyPIからwheelのURLを取得
              const wheelUrl = await getWheelUrl(pkg);
              const wheelFilename = path.basename(wheelUrl);
              const localWheelPath = path.join(tempDir, wheelFilename);
    
              // wheelをダウンロード
              outputs.push(`Downloading wheel for ${pkg}...`);
              await downloadWheel(wheelUrl, localWheelPath);
    
              // wheelをPyodideのファイルシステムにコピー
              const wheelData = fs.readFileSync(localWheelPath);
              const pyodideWheelPath = `/tmp/wheels/${wheelFilename}`;
              this.pyodide.FS.writeFile(pyodideWheelPath, wheelData);
    
              // micropipでインストール
              const { output } = await withOutputCapture(
                this.pyodide,
                async () => {
                  await this.pyodide!.runPythonAsync(`
                    import micropip
                    await micropip.install("emfs:${pyodideWheelPath}")
                  `);
                },
                { suppressConsole: true }
              );
    
              outputs.push(
                `Successfully installed ${pkg} using micropip: ${output}`
              );
            }
          } catch (error) {
            // 個別のパッケージのエラーを記録して続行
            outputs.push(
              `Failed to install ${pkg}: ${
                error instanceof Error ? error.message : String(error)
              }`
            );
          }
        }
    
        return formatCallToolSuccess(outputs.join("\n\n"));
      } catch (error) {
        return formatCallToolError(error);
      }
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/yonaka15/mcp-pyodide'

If you have feedback or need assistance with the MCP directory API, please join our Discord server