Using Composer Path Repositories to Handle Module Dependencies During Development

Sometimes working on a Drupal contributed module requires making changes to the module’s composer.json so that you can update a dependency.

Have you run into this before? You’re working on a Drupal contrib module, and that module has a dependency on either another module or an external Composer package. That dependency is expressed in the module’s composer.json file and likely has a version constraint. So what happens when you want to update the module to use a newer version of the dependency, but the new version is outside the existing version constraint?

This is super common when the contributed module relies on a third-party library, like the Recurly module using the Recurly API SDK, or the OAuth module using the PHP library common to many different projects.

Here’s a recent example. I was working on the drupal/mcp_server module, which currently has a dependency on the modelcontextprotocol/php-sdk (mcp/sdk). I started by installing the module with composer require drupal/mcp_server. This gets the module and any dependencies.

The require section of the drupal/mcp_server module’s composer.json file looks like this:

  "require": {
    "php": "^8.3",
    "drupal/tool": "1.0.0-alpha9",
    "drupal/simple_oauth": "^6",
    "e0ipso/simple_oauth_21": "^1",
    "mcp/sdk": "^0.1.0"
  },

I want to update the module to use the newer 0.3.x version of the mcp/sdk. I can’t just composer update mcp/sdk because the version constraint doesn’t allow the newest release, and composer require mcp/sdk^0.3.0 won’t work because it’ll result in a dependency conflict. I can’t just modify the local composer.json file in the module because, when resolving the dependency tree, Composer will ping Drupal.org (Packagist) and use the version constraint from the hosted package, not from the locally installed module.

So how do I get my project to install mcp/sdk^0.3.0 so that I can work on updating the module’s code to use the new library?

Composer path repositories

One way to accomplish this is using a path repository. Composer installs packages from a repository: a list of packages and versions. By default, only the Packagist.org repository is registered. You can change this by adding repository configuration to your project’s composer.json file and telling Composer to use additional repositories when resolving dependencies.

Drupal actually does this already. If you look at your root composer.json file, you’ll see something like this:

    "repositories": [
        {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        }
    ],

That configuration tells Composer that, in addition to Packagist.org, it should use packages.drupal.org/8 as a place to search for packages. And that’s why packages like drupal/mcp_server work.

There are a bunch of different types of repositories, including path, which allows you to depend on a local directory. Read more about it here: https://getcomposer.org/doc/05-repositories.md#path

This approach works really well if you’re working on a contributed module within the context of a complete Drupal project. For example, working on adding an MCP server to the Drupalize.Me site and wanting to make (and test) the updates for the mcp/sdk in the context of that site.

Set up a path repository to work on a Drupal module

In the project’s root composer.json (the one that currently requires drupal/mcp_server, or whatever module you want to work on), add the following configuration:

  "repositories": [
    {
      "type": "path",
      "url": "web/modules/contrib/mcp_server",
      "options": {
        "symlink": false
      }
    },
    {
      "type": "composer",
      "url": "https://packages.drupal.org/8"
    }
  ],

This tells Composer to use web/modules/contrib/mcp_server as a repository. So when it goes to resolve drupal/mcp_server, it’ll find web/modules/contrib/mcp_server/composer.json, which has "name": "drupal/mcp_server", and say “Got it!” No more pinging Drupal.org for that specific package. Dependencies are resolved by searching through the repositories top to bottom until a match is found.

After making those changes, we can remove the Composer-managed version, clone the Git repo, and then tell Composer to use the locally cloned package:

# Remove the composer-managed version.
composer remove drupal/mcp_server

# Git clone your module.
cd web/modules/contrib
git clone https://github.com/yourusername/mcp_server.git mcp_server
cd ../../..

# Tell Composer to use the local path.
composer require drupal/mcp_server:@dev

Update the MCP SDK

Finally, we can update the mcp/sdk dependency.

Edit web/modules/contrib/mcp_server/composer.json:

{
  "require": {
    "mcp/sdk": "^0.3.0"
  }
}

Then run:

composer update mcp/sdk --with-all-dependencies

This should result in the 0.3.0 version of the mcp/sdk being downloaded into the vendor/ directory. And you can now begin the work of updating the contributed module’s code to use the latest version of the third-party dependency.

Similar Posts

  • Meet the New Drupalize.Me AI Assistant

    An experimental new way to explore our Drupal tutorials – powered by AI, guided by humans. We’ve been experimenting with different ways to use AI to make Drupalize.Me even more helpful for our members, and we’re excited about this first update: a new AI-powered chatbot that can search and summarize tutorials from our library. We’re…

  • 10 Best Hostinger Alternative 2025, Sep | Top Competitors

    When it comes to affordable web hosting services, Hostinger is often one of the first names that pops up. It’s budget-friendly, beginner-friendly, and offers a simple platform for individuals starting their online journey.  However, when it comes to handling enterprise-level workloads that need powerful hosting solutions, the question comes, Can Hostinger provide big dedicated solutions?…

  • 8 Best Free Security WordPress Plugins — Speckyboy

    Keeping your website secure is a 24/7 job. The right tools help keep watch – even when you can’t. They could be the difference between a hacked site and business as usual. WordPress security plugins are one part of that equation. Along with quality hosting and users practicing secure habits, a plugin can thwart common…

  • How to Implement a Shipping Strategy

    If you sell physical goods, your shipping strategy is one of the most important aspects of your success. Customers shopping online expect to pay as little as possible, but receive products quickly and in perfect condition.  How can you meet these expectations without losing money and set your business up for growth?  Start by establishing…

  • How to Use AI to Enhance Your WordPress Blog

    Blogging is still at the heart of WordPress’s strengths. The content management system (CMS) started as a blogging platform and continues to shine. Its goal is to democratize publishing, after all. Those old-school roots are still evident. However, new technologies are here to help you take your blog to the next level. We’re talking (of…