diff --git a/packages/default.nix b/packages/default.nix index c89d7f3..5b87f22 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -24,5 +24,6 @@ transmission-mcp = pkgs.callPackage ./transmission-mcp/package.nix { }; sabnzbd-mcp = pkgs.callPackage ./sabnzbd-mcp/package.nix { }; jellyfin-mcp = pkgs.callPackage ./jellyfin-mcp/package.nix { }; + nextcloud-mcp-server = pkgs.callPackage ./nextcloud-mcp-server/package.nix { }; # example-mcp-server = pkgs.callPackage ./example-mcp-server/package.nix { }; } diff --git a/packages/nextcloud-mcp-server/package.nix b/packages/nextcloud-mcp-server/package.nix new file mode 100644 index 0000000..9fbfdc8 --- /dev/null +++ b/packages/nextcloud-mcp-server/package.nix @@ -0,0 +1,312 @@ +{ + lib, + python3Packages, + fetchFromGitHub, + fetchPypi, +}: + +let + # ────────────────────────────────────────────────────────────── + # Inlined packages not yet in nixpkgs (20 total) + # Organized in dependency order: tiers 1 → 4 + # ────────────────────────────────────────────────────────────── + + # ── Tier 1: leaf packages (no deps on other missing packages) ── + + pythonvcard4 = python3Packages.buildPythonPackage rec { + pname = "pythonvcard4"; + version = "0.2.0"; + pyproject = true; + build-system = [ python3Packages.setuptools python3Packages.wheel ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + doCheck = false; + meta = with lib; { description = "vCard parsing library"; homepage = "https://github.com/GNOME/python-vcard4"; license = licenses.gpl3Plus; }; + }; + + prometheus-client = python3Packages.buildPythonPackage rec { + pname = "prometheus_client"; + version = "0.25.0"; + pyproject = true; + build-system = [ python3Packages.setuptools python3Packages.wheel ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + doCheck = false; + meta = with lib; { description = "Prometheus monitoring system client"; homepage = "https://github.com/prometheus/client_python"; license = licenses.asl20; }; + }; + + python-json-logger = python3Packages.buildPythonPackage rec { + pname = "python-json-logger"; + version = "4.1.0"; + pyproject = true; + build-system = [ python3Packages.setuptools python3Packages.wheel ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + doCheck = false; + meta = with lib; { description = "JSON formatter for python logging"; homepage = "https://github.com/nhairs/python-json-logger"; license = licenses.bsd2; }; + }; + + importlib-metadata = python3Packages.buildPythonPackage rec { + pname = "importlib_metadata"; + version = "8.7.1"; + pyproject = true; + build-system = [ python3Packages.setuptools python3Packages.wheel ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = with python3Packages; [ zipp ]; + doCheck = false; + meta = with lib; { description = "Read metadata from Python packages"; homepage = "https://github.com/python/importlib_metadata"; license = licenses.asl20; }; + }; + + googleapis-common-protos = python3Packages.buildPythonPackage rec { + pname = "googleapis-common-protos"; + version = "1.75.0"; + pyproject = true; + build-system = [ python3Packages.setuptools python3Packages.wheel ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = with python3Packages; [ protobuf ]; + doCheck = false; + meta = with lib; { description = "Common protobufs used in Google APIs"; homepage = "https://github.com/googleapis/python-api-common-protos"; license = licenses.asl20; }; + }; + + opentelemetry-api = python3Packages.buildPythonPackage rec { + pname = "opentelemetry-api"; + version = "1.39.1"; + pyproject = true; + build-system = [ python3Packages.hatchling ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = with python3Packages; [ deprecated importlib-metadata ]; + doCheck = false; + meta = with lib; { description = "OpenTelemetry Python API"; homepage = "https://github.com/open-telemetry/opentelemetry-python"; license = licenses.asl20; }; + }; + + opentelemetry-proto = python3Packages.buildPythonPackage rec { + pname = "opentelemetry-proto"; + version = "1.39.1"; + pyproject = true; + build-system = [ python3Packages.hatchling ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = with python3Packages; [ protobuf ]; + doCheck = false; + meta = with lib; { description = "OpenTelemetry Python Proto"; homepage = "https://github.com/open-telemetry/opentelemetry-python"; license = licenses.asl20; }; + }; + + # ── Tier 2 (depend on Tier 1) ── + + opentelemetry-semantic-conventions = python3Packages.buildPythonPackage rec { + pname = "opentelemetry-semantic-conventions"; + version = "0.60b1"; + pyproject = true; + build-system = [ python3Packages.hatchling ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = [ opentelemetry-api ] ++ (with python3Packages; [ deprecated ]); + doCheck = false; + meta = with lib; { description = "OpenTelemetry Semantic Conventions"; homepage = "https://github.com/open-telemetry/semantic-conventions"; license = licenses.asl20; }; + }; + + opentelemetry-sdk = python3Packages.buildPythonPackage rec { + pname = "opentelemetry-sdk"; + version = "1.39.1"; + pyproject = true; + build-system = [ python3Packages.hatchling ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = [ opentelemetry-api opentelemetry-semantic-conventions ] ++ (with python3Packages; [ typing-extensions ]); + doCheck = false; + meta = with lib; { description = "OpenTelemetry Python SDK"; homepage = "https://github.com/open-telemetry/opentelemetry-python"; license = licenses.asl20; }; + }; + + x-wr-timezone = python3Packages.buildPythonPackage rec { + pname = "x_wr_timezone"; + version = "2.0.1"; + pyproject = true; + build-system = [ python3Packages.setuptools python3Packages.wheel ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = with python3Packages; [ icalendar ]; + doCheck = false; + meta = with lib; { description = "X-WR-TIMEZONE iCalendar property handling"; homepage = "https://github.com/niccokunzmann/x-wr-timezone"; license = licenses.lgpl3Plus; }; + }; + + opentelemetry-util-http = python3Packages.buildPythonPackage rec { + pname = "opentelemetry-util-http"; + version = "0.60b1"; + pyproject = true; + build-system = [ python3Packages.hatchling ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + doCheck = false; + meta = with lib; { description = "OpenTelemetry HTTP utilities"; homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib"; license = licenses.asl20; }; + }; + + opentelemetry-exporter-otlp-proto-common = python3Packages.buildPythonPackage rec { + pname = "opentelemetry-exporter-otlp-proto-common"; + version = "1.39.1"; + pyproject = true; + build-system = [ python3Packages.hatchling ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = [ opentelemetry-proto ]; + doCheck = false; + meta = with lib; { description = "OpenTelemetry OTLP exporter proto common"; homepage = "https://github.com/open-telemetry/opentelemetry-python"; license = licenses.asl20; }; + }; + + # ── Tier 3 (depend on Tier 1+2) ── + + opentelemetry-instrumentation = python3Packages.buildPythonPackage rec { + pname = "opentelemetry-instrumentation"; + version = "0.60b1"; + pyproject = true; + build-system = [ python3Packages.hatchling ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = [ opentelemetry-api opentelemetry-semantic-conventions ] ++ (with python3Packages; [ wrapt packaging ]); + doCheck = false; + meta = with lib; { description = "OpenTelemetry instrumentation base"; homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib"; license = licenses.asl20; }; + }; + + recurring-ical-events = python3Packages.buildPythonPackage rec { + pname = "recurring-ical-events"; + version = "3.8.2"; + pyproject = true; + build-system = [ python3Packages.hatchling ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = [ x-wr-timezone ] ++ (with python3Packages; [ icalendar python-dateutil ]); + doCheck = false; + meta = with lib; { description = "Recurring iCalendar event expander"; homepage = "https://github.com/niccokunzmann/python-recurring-ical-events"; license = licenses.lgpl3Plus; }; + }; + + opentelemetry-exporter-otlp-proto-grpc = python3Packages.buildPythonPackage rec { + pname = "opentelemetry-exporter-otlp-proto-grpc"; + version = "1.39.1"; + pyproject = true; + build-system = [ python3Packages.hatchling ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = [ opentelemetry-api opentelemetry-sdk opentelemetry-proto opentelemetry-exporter-otlp-proto-common googleapis-common-protos ] ++ (with python3Packages; [ grpcio deprecated ]); + doCheck = false; + meta = with lib; { description = "OpenTelemetry OTLP gRPC exporter"; homepage = "https://github.com/open-telemetry/opentelemetry-python"; license = licenses.asl20; }; + }; + + qdrant-client = python3Packages.buildPythonPackage rec { + pname = "qdrant-client"; + version = "1.18.0"; + pyproject = true; + build-system = [ python3Packages.poetry-core ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = with python3Packages; [ grpcio httpx numpy portalocker protobuf pydantic urllib3 ]; + doCheck = false; + meta = with lib; { description = "Qdrant vector search engine client"; homepage = "https://github.com/qdrant/qdrant-client"; license = licenses.asl20; }; + }; + + # ── Tier 4 (depend on Tier 1-3) ── + + opentelemetry-instrumentation-asgi = python3Packages.buildPythonPackage rec { + pname = "opentelemetry-instrumentation-asgi"; + version = "0.60b1"; + pyproject = true; + build-system = [ python3Packages.hatchling ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = [ opentelemetry-api opentelemetry-instrumentation opentelemetry-semantic-conventions opentelemetry-util-http ] ++ (with python3Packages; [ asgiref ]); + doCheck = false; + meta = with lib; { description = "OpenTelemetry ASGI instrumentation"; homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib"; license = licenses.asl20; }; + }; + + opentelemetry-instrumentation-httpx = python3Packages.buildPythonPackage rec { + pname = "opentelemetry-instrumentation-httpx"; + version = "0.60b1"; + pyproject = true; + build-system = [ python3Packages.hatchling ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = [ opentelemetry-api opentelemetry-instrumentation opentelemetry-semantic-conventions opentelemetry-util-http ] ++ (with python3Packages; [ httpx wrapt ]); + doCheck = false; + meta = with lib; { description = "OpenTelemetry HTTPX instrumentation"; homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib"; license = licenses.asl20; }; + }; + + opentelemetry-instrumentation-logging = python3Packages.buildPythonPackage rec { + pname = "opentelemetry-instrumentation-logging"; + version = "0.60b1"; + pyproject = true; + build-system = [ python3Packages.hatchling ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = [ opentelemetry-api opentelemetry-instrumentation ]; + doCheck = false; + meta = with lib; { description = "OpenTelemetry logging instrumentation"; homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib"; license = licenses.asl20; }; + }; + + langchain-text-splitters = python3Packages.buildPythonPackage rec { + pname = "langchain-text-splitters"; + version = "1.1.2"; + pyproject = true; + build-system = [ python3Packages.poetry-core ]; + src = fetchPypi { inherit pname version; hash = lib.fakeHash; }; + propagatedBuildInputs = with python3Packages; [ langchain-core ]; + doCheck = false; + meta = with lib; { description = "LangChain text splitting utilities"; homepage = "https://github.com/langchain-ai/langchain"; license = licenses.mit; }; + }; + +in +python3Packages.buildPythonApplication rec { + pname = "nextcloud-mcp-server"; + version = "0.89.0"; + pyproject = true; + + src = fetchFromGitHub { + owner = "cbcoutinho"; + repo = "nextcloud-mcp-server"; + rev = "v${version}"; + hash = lib.fakeHash; + }; + + build-system = [ python3Packages.hatchling ]; + + # All dependencies — both from nixpkgs and our inlined packages + dependencies = with python3Packages; [ + # ── nixpkgs packages ── + mcp httpx pillow icalendar pydantic click caldav pyjwt + aiosqlite alembic authlib fastembed anthropic boto3 starlette + jinja2 markdownify pymupdf pymupdf4llm openai dynaconf + mistralai sqlalchemy + + # ── Inlined packages ── + pythonvcard4 prometheus-client python-json-logger importlib-metadata + googleapis-common-protos opentelemetry-api opentelemetry-proto + opentelemetry-semantic-conventions opentelemetry-sdk + x-wr-timezone opentelemetry-util-http opentelemetry-exporter-otlp-proto-common + opentelemetry-instrumentation recurring-ical-events + opentelemetry-exporter-otlp-proto-grpc qdrant-client + opentelemetry-instrumentation-asgi opentelemetry-instrumentation-httpx + opentelemetry-instrumentation-logging langchain-text-splitters + ]; + + # Relax strict version pins in pyproject.toml so inlined packages match + postPatch = '' + substituteInPlace pyproject.toml \ + --replace-fail '"prometheus-client>=0.21.0"' '"prometheus-client"' \ + --replace-fail '"mcp>=1.27,<1.28"' '"mcp"' \ + --replace-fail '"mcp[cli]>=1.27,<1.28"' '"mcp"' \ + --replace-fail '"pymupdf4llm>=0.2.2"' '"pymupdf4llm"' \ + --replace-fail '"pymupdf>=1.26.6"' '"pymupdf"' \ + --replace-fail '"qrant-client>=1.17.0"' '"qdrant-client"' \ + --replace-fail '"opentelemetry-api>=1.28.2"' '"opentelemetry-api"' \ + --replace-fail '"opentelemetry-sdk>=1.28.2"' '"opentelemetry-sdk"' \ + --replace-fail '"opentelemetry-instrumentation-asgi>=0.49b2"' '"opentelemetry-instrumentation-asgi"' \ + --replace-fail '"opentelemetry-instrumentation-httpx>=0.49b2"' '"opentelemetry-instrumentation-httpx"' \ + --replace-fail '"opentelemetry-instrumentation-logging>=0.49b2"' '"opentelemetry-instrumentation-logging"' \ + --replace-fail '"opentelemetry-exporter-otlp-proto-grpc>=1.28.2"' '"opentelemetry-exporter-otlp-proto-grpc"' \ + --replace-fail '"python-json-logger>=3.2.0"' '"python-json-logger"' \ + --replace-fail '"pythonvcard4>=0.2.0"' '"pythonvcard4"' + ''; + + postInstall = '' + # Ensure the CLI entry point is discoverable + mkdir -p $out/bin + if [ ! -f "$out/bin/nextcloud-mcp-server" ]; then + cat > $out/bin/nextcloud-mcp-server << 'PYEOF' +#!/bin/sh +exec ${python3Packages.python}/bin/python -m nextcloud_mcp_server.cli "$@" +PYEOF + chmod +x $out/bin/nextcloud-mcp-server + fi + ''; + + doCheck = false; + + meta = with lib; { + description = "MCP server for Nextcloud — files (WebDAV), calendar (CalDAV), contacts (CardDAV), notes, deck, talk, and sharing"; + homepage = "https://github.com/cbcoutinho/nextcloud-mcp-server"; + license = licenses.agpl3Only; + mainProgram = "nextcloud-mcp-server"; + platforms = platforms.all; + }; +}