226 lines
4.6 KiB
Markdown
226 lines
4.6 KiB
Markdown
# Adding New Packages
|
||
|
||
## Directory Structure
|
||
|
||
```text
|
||
packages/
|
||
├── default.nix # Package aggregator
|
||
└── <package-name>/
|
||
└── package.nix # Package derivation
|
||
```
|
||
|
||
## Step‑by‑Step Guide
|
||
|
||
1. **Create the package directory**
|
||
|
||
```bash
|
||
mkdir -p packages/<package-name>
|
||
```
|
||
|
||
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 .#<package-name>
|
||
./result/bin/<package-name>
|
||
```
|
||
|
||
## 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.
|