Skip to main content
Glama
ember-tooling

Ember MCP Server

detect_package_manager

Identifies the package manager in use by analyzing lockfiles and package.json, then provides the correct commands for installing dependencies, running scripts, and executing packages.

Instructions

Detect which package manager (pnpm, yarn, npm, bun) is being used in a workspace by examining lockfiles and package.json. Returns the appropriate commands to use for installing dependencies, running scripts, and executing packages. Use this tool BEFORE suggesting package installation or script execution commands to ensure you use the correct package manager.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
workspacePathYesAbsolute path to the workspace directory to analyze (e.g., '/path/to/project')

Implementation Reference

  • index.js:51-187 (registration)
    Tool registration in ListToolsRequestSchema handler. The 'detect_package_manager' tool is declared at lines 170-185 with name, description, and inputSchema (requires workspacePath).
    setupHandlers() {
      this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
        tools: [
          {
            name: "search_ember_docs",
            description:
              "Search through Ember.js documentation including API docs, guides, and community content. Returns relevant documentation with links to official sources. Use this for general queries about Ember concepts, features, or usage.",
            inputSchema: {
              type: "object",
              properties: {
                query: {
                  type: "string",
                  description:
                    "Search query (e.g., 'component lifecycle', 'tracked properties', 'routing')",
                },
                category: {
                  type: "string",
                  enum: ["all", "api", "guides", "community"],
                  description:
                    "Filter by documentation category (default: all)",
                },
                limit: {
                  type: "number",
                  description: "Maximum number of results (default: 5)",
                  default: 5,
                },
              },
              required: ["query"],
            },
          },
          {
            name: "get_api_reference",
            description:
              "Get detailed API reference documentation for a specific Ember class, module, or method. Returns full API documentation including parameters, return values, examples, and links to official API docs.",
            inputSchema: {
              type: "object",
              properties: {
                name: {
                  type: "string",
                  description:
                    "Name of the API element (e.g., 'Component', '@glimmer/component', 'Service', 'Router')",
                },
                type: {
                  type: "string",
                  enum: ["class", "module", "method", "property"],
                  description: "Type of API element (optional)",
                },
              },
              required: ["name"],
            },
          },
          {
            name: "get_best_practices",
            description:
              "Get Ember best practices and recommendations for specific topics. This includes modern patterns, anti-patterns to avoid, performance tips, and community-approved approaches. Always use this when providing implementation advice.",
            inputSchema: {
              type: "object",
              properties: {
                topic: {
                  type: "string",
                  description:
                    "Topic to get best practices for (e.g., 'component patterns', 'state management', 'testing', 'performance')",
                },
              },
              required: ["topic"],
            },
          },
          {
            name: "get_ember_version_info",
            description:
              "Get information about Ember versions, including current stable version, what's new in recent releases, and migration guides. Useful for understanding version-specific features and deprecations.",
            inputSchema: {
              type: "object",
              properties: {
                version: {
                  type: "string",
                  description:
                    "Specific version to get info about (optional, returns latest if not specified)",
                },
              },
            },
          },
          {
            name: "get_npm_package_info",
            description:
              "Get comprehensive information about an npm package including latest version, description, dependencies, maintainers, and more. Essential for understanding package details before upgrading dependencies.",
            inputSchema: {
              type: "object",
              properties: {
                packageName: {
                  type: "string",
                  description:
                    "Name of the npm package (e.g., 'ember-source', '@glimmer/component', 'ember-cli')",
                },
              },
              required: ["packageName"],
            },
          },
          {
            name: "compare_npm_versions",
            description:
              "Compare a current package version with the latest available version on npm. Shows if an update is needed and provides version details to help with dependency upgrades.",
            inputSchema: {
              type: "object",
              properties: {
                packageName: {
                  type: "string",
                  description:
                    "Name of the npm package (e.g., 'ember-source', '@glimmer/component')",
                },
                currentVersion: {
                  type: "string",
                  description:
                    "Current version being used (e.g., '4.12.0', '1.1.2')",
                },
              },
              required: ["packageName", "currentVersion"],
            },
          },
          {
            name: "detect_package_manager",
            description:
              "Detect which package manager (pnpm, yarn, npm, bun) is being used in a workspace by examining lockfiles and package.json. Returns the appropriate commands to use for installing dependencies, running scripts, and executing packages. Use this tool BEFORE suggesting package installation or script execution commands to ensure you use the correct package manager.",
            inputSchema: {
              type: "object",
              properties: {
                workspacePath: {
                  type: "string",
                  description:
                    "Absolute path to the workspace directory to analyze (e.g., '/path/to/project')",
                },
              },
              required: ["workspacePath"],
            },
          },
        ],
      }));
  • Input schema for detect_package_manager tool. Defines a single required parameter 'workspacePath' (string) - absolute path to the workspace directory.
    {
      name: "detect_package_manager",
      description:
        "Detect which package manager (pnpm, yarn, npm, bun) is being used in a workspace by examining lockfiles and package.json. Returns the appropriate commands to use for installing dependencies, running scripts, and executing packages. Use this tool BEFORE suggesting package installation or script execution commands to ensure you use the correct package manager.",
      inputSchema: {
        type: "object",
        properties: {
          workspacePath: {
            type: "string",
            description:
              "Absolute path to the workspace directory to analyze (e.g., '/path/to/project')",
          },
        },
        required: ["workspacePath"],
      },
    },
  • CallToolRequestSchema switch case dispatching 'detect_package_manager' to handleDetectPackageManager(args).
    case "detect_package_manager":
      return await this.handleDetectPackageManager(args);
  • handleDetectPackageManager method: calls packageManagerDetector.detectPackageManager(workspacePath), formats result via formatDetectionResult, returns text content or error.
    async handleDetectPackageManager(args) {
      const { workspacePath } = args;
    
      try {
        const result = await this.packageManagerDetector.detectPackageManager(workspacePath);
        const formattedResult = this.packageManagerDetector.formatDetectionResult(result);
    
        return {
          content: [
            {
              type: "text",
              text: formattedResult,
            },
          ],
        };
      } catch (error) {
        return {
          content: [
            {
              type: "text",
              text: `Error detecting package manager: ${error.message}`,
            },
          ],
          isError: true,
        };
      }
    }
  • PackageManagerDetector class containing detectPackageManager() (checks lockfiles: pnpm-lock.yaml, yarn.lock, package-lock.json, bun.lockb; then package.json packageManager field; falls back to npm), fileExists(), formatDetectionResult(), getCommandForScenario(), and getRunner().
    import { promises as fs } from 'fs';
    import { join, resolve } from 'path';
    
    /**
     * Service for detecting which package manager is being used in a project
     */
    export class PackageManagerDetector {
      constructor() {
        // Priority order for detection (lockfile -> manager name)
        this.lockfiles = {
          'pnpm-lock.yaml': 'pnpm',
          'yarn.lock': 'yarn',
          'package-lock.json': 'npm',
          'bun.lockb': 'bun',
        };
      }
    
      getRunner(manager) {
        return manager === 'npm' ? 'npx' : manager === 'bun' ? 'bunx' : manager;
      }
    
      /**
       * Detect the package manager used in a workspace
       * @param {string} workspacePath - Absolute path to the workspace directory
       * @returns {Promise<Object>} Package manager information
       */
      async detectPackageManager(workspacePath) {
        const resolvedPath = resolve(workspacePath);
    
        // Check for lockfiles
        for (const [lockfile, manager] of Object.entries(this.lockfiles)) {
          if (await this.fileExists(join(resolvedPath, lockfile))) {
            return {
              manager,
              lockfile,
              runner: this.getRunner(manager),
              detectionMethod: 'lockfile',
              confidence: 'high',
            };
          }
        }
    
        // Check package.json for packageManager field
        const packageJsonPath = join(resolvedPath, 'package.json');
        if (await this.fileExists(packageJsonPath)) {
          try {
            const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
            if (packageJson.packageManager) {
              const manager = packageJson.packageManager.match(/^([a-z]+)@/)?.[1];
              if (manager) {
                return {
                  manager,
                  lockfile: null,
                  runner: this.getRunner(manager),
                  detectionMethod: 'packageManager field',
                  confidence: 'high',
                };
              }
            }
          } catch (error) {
            // Continue to fallback
          }
        }
    
        // Fallback to npm (most common default)
        return {
          manager: 'npm',
          lockfile: null,
          runner: 'npx',
          detectionMethod: 'default fallback',
          confidence: 'low',
        };
      }
    
      /**
       * Check if a file exists
       * @param {string} filePath - Path to check
       * @returns {Promise<boolean>} True if file exists
       */
      async fileExists(filePath) {
        try {
          await fs.access(filePath);
          return true;
        } catch {
          return false;
        }
      }
    
      /**
       * Format detection result as human-readable text
       * @param {Object} result - Detection result from detectPackageManager
       * @returns {string} Formatted output
       */
      formatDetectionResult(result) {
        const { manager, runner, lockfile, detectionMethod, confidence } = result;
        
        let text = `# Package Manager: ${manager}\n\n`;
        
        if (lockfile) {
          text += `Detected via **${lockfile}** (${confidence} confidence)\n\n`;
        } else {
          text += `Detected via **${detectionMethod}** (${confidence} confidence)\n\n`;
        }
        
        text += `## Commands to use:\n\n`;
        text += `- Install: \`${manager} install\`\n`;
        text += `- Add package: \`${manager} ${manager === 'npm' ? 'install' : 'add'} <pkg>\`\n`;
        text += `- Remove package: \`${manager} ${manager === 'npm' ? 'uninstall' : 'remove'} <pkg>\`\n`;
        text += `- Run script: \`${manager} run <script>\`\n`;
        text += `- Execute binary: \`${runner} <command>\`\n`;
        
        if (manager === 'npm') {
          text += `\n**npm-specific notes:**\n`;
          text += `- Scripts require \`npm run <script>\` (can't omit \`run\`)\n`;
          text += `- Binaries use \`npx <command>\` (not \`npm exec\`)\n`;
          text += `- Pass args to scripts with \`--\`: \`npm run test -- --watch\`\n`;
        }
        
        if (confidence === 'low') {
          text += `\n⚠️ **Warning:** No lockfile found. Defaulting to npm. Consider committing your lockfile.\n`;
        }
        
        return text;
      }
    
      /**
       * Get usage instructions for a specific scenario
       * @param {Object} result - Detection result
       * @param {string} scenario - Scenario type (install, add, remove, run, execute)
       * @returns {string} Command to use
       */
      getCommandForScenario(result, scenario) {
        const { manager, runner } = result;
        
        const commands = {
          install: `${manager} install`,
          add: `${manager} ${manager === 'npm' ? 'install' : 'add'}`,
          remove: `${manager} ${manager === 'npm' ? 'uninstall' : 'remove'}`,
          run: `${manager} run`,
          execute: runner,
        };
        
        return commands[scenario] || manager;
      }
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, but description discloses that the tool examines lockfiles and package.json and returns commands. It implies a read-only operation without side effects. Does not mention specific behavioral traits like permissions or error cases, but the simple nature of detection makes this acceptable.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with purpose and usage guidance. Every sentence is necessary and concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple detection tool with one parameter and no output schema, the description covers the essential behavior: detection method, return value (commands), and usage recommendation. Complete for the given complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with the single parameter workspacePath having a description. The description repeats the schema's detail about absolute path but adds no new semantic meaning beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the tool detects package manager by examining lockfiles and package.json, naming the specific managers it can identify. It distinguishes from sibling tools that deal with npm versions and package info, so purpose is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly instructs to use this tool before suggesting package installation or script execution commands, providing clear usage context. However, it does not explicitly mention when not to use it, e.g., when package manager is already known.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/ember-tooling/ember-mcp'

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