# Adding New Packages ## Directory Structure ```text packages/ ├── default.nix # Package aggregator └── / └── package.nix # Package derivation ``` ## Step‑by‑Step Guide 1. **Create the package directory** ```bash mkdir -p packages/ ``` 2. **Create `package.nix`** using the appropriate builder for the language: * Python (with pyproject.toml): `python3Packages.buildPythonApplication` * Python (script only): wrapper approach with `stdenv.mkDerivation` * Go: `buildGoModule` * Node.js: `buildNpmPackage` * Rust: `rustPlatform.buildRustPackage` 3. **Register** in `packages/default.nix`: ```nix { pkgs }: { manim-mcp-server = pkgs.callPackage ./manim-mcp-server/package.nix { }; # Add your new package here: new-mcp-server = pkgs.callPackage ./new-mcp-server/package.nix { }; } ``` 4. **Build and test**: ```bash nix build .# ./result/bin/ ``` ## Package Templates ### Python (with `pyproject.toml`) ```nix { lib, python3Packages, fetchFromGitHub }: python3Packages.buildPythonApplication rec { pname = "example-mcp-server"; version = "1.0.0"; pyproject = true; src = fetchFromGitHub { owner = "owner"; repo = "repo"; rev = "v${version}"; hash = "sha256-AAAA..."; # Use lib.fakeHash first, then update }; build-system = [ python3Packages.hatchling ]; dependencies = with python3Packages; [ mcp fastmcp ]; meta = with lib; { description = "Description of the MCP server"; homepage = "https://github.com/owner/repo"; license = licenses.mit; mainProgram = "example-mcp-server"; }; } ``` ### Python (script only, like `manim-mcp-server`) ```nix { lib, stdenv, fetchFromGitHub, makeWrapper, python3 }: let python = python3.withPackages (ps: with ps; [ mcp fastmcp # other dependencies ]); in stdenv.mkDerivation rec { pname = "example-mcp-server"; version = "0.0.1-unstable"; src = fetchFromGitHub { owner = "owner"; repo = "repo"; rev = "commit-hash"; hash = "sha256-AAAA..."; }; nativeBuildInputs = [ makeWrapper ]; dontBuild = true; installPhase = '' runHook preInstall mkdir -p $out/bin $out/lib/${pname} cp src/server.py $out/lib/${pname}/ makeWrapper ${python}/bin/python $out/bin/${pname} \ --add-flags "$out/lib/${pname}/server.py" runHook postInstall ''; meta = with lib; { description = "Description"; homepage = "https://github.com/owner/repo"; license = licenses.mit; mainProgram = pname; }; } ``` ### Go ```nix { lib, buildGoModule, fetchFromGitHub }: buildGoModule rec { pname = "example-mcp-server"; version = "1.0.0"; src = fetchFromGitHub { owner = "owner"; repo = "repo"; rev = "v${version}"; hash = "sha256-AAAA..."; }; vendorHash = "sha256-BBBB..."; # Use lib.fakeHash first ldflags = [ "-s" "-w" "-X main.version=${version}" ]; meta = with lib; { description = "Description"; homepage = "https://github.com/owner/repo"; license = licenses.mit; mainProgram = pname; }; } ``` ### Node.js (with `package-lock.json`) ```nix { lib, buildNpmPackage, fetchFromGitHub }: buildNpmPackage rec { pname = "example-mcp-server"; version = "1.0.0"; src = fetchFromGitHub { owner = "owner"; repo = "repo"; rev = "v${version}"; hash = "sha256-AAAA..."; }; npmDepsHash = "sha256-BBBB..."; # Use lib.fakeHash first dontNpmBuild = true; # If pre-built or no build step needed meta = with lib; { description = "Description"; homepage = "https://github.com/owner/repo"; license = licenses.mit; mainProgram = pname; }; } ``` ### Node.js (wrapper for npm packages without `package-lock.json`) ```nix { lib, stdenvNoCC, nodejs_22, makeWrapper }: stdenvNoCC.mkDerivation rec { pname = "example-mcp-server"; version = "1.0.0"; # No source needed - npx fetches the package dontUnpack = true; nativeBuildInputs = [ makeWrapper ]; installPhase = '' runHook preInstall mkdir -p $out/bin makeWrapper ${nodejs_22}/bin/npx $out/bin/${pname} \ --add-flags "--yes" \ --add-flags "@scope/package-name@${version}" runHook postInstall ''; meta = with lib; { description = "Description"; homepage = "https://github.com/owner/repo"; license = licenses.mit; mainProgram = pname; }; } ``` ## Calculating Hashes When adding a new package, use `lib.fakeHash` initially: ```nix hash = lib.fakeHash; ``` Then run `nix build` and copy the correct hash from the error message.