From 8bb8e5507e36856b1b6c20ef591d95244cb903bf Mon Sep 17 00:00:00 2001 From: Deivid Soto Date: Thu, 12 Feb 2026 15:44:09 +0100 Subject: [PATCH] chore: align project config with torrentclaw org standards --- .editorconfig | 15 +++++ .github/workflows/ci.yml | 69 +++++++++++++++++++ .github/workflows/release.yml | 41 ++++++++++++ .gitignore | 24 ++++++- CONTRIBUTING.md | 64 ++++++++++++++++++ Makefile | 34 ++++++++++ README.md | 120 ++++++++++++++++++++++------------ lefthook.yml | 36 ++++++++++ package.json | 10 ++- 9 files changed, 367 insertions(+), 46 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 CONTRIBUTING.md create mode 100644 Makefile create mode 100644 lefthook.yml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..00f2c60 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2b84a95 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,69 @@ +name: CI + +on: + pull_request: + branches: [main] + push: + branches: [main] + +permissions: + contents: read + +jobs: + lint-commits: + name: Lint commits + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Validate conventional commits + run: | + base="${{ github.event.pull_request.base.sha }}" + head="${{ github.event.pull_request.head.sha }}" + pattern='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?(!)?: .{1,}$' + + failed=0 + while IFS= read -r msg; do + first_line=$(echo "$msg" | head -1) + if ! echo "$first_line" | grep -qE "$pattern"; then + echo "FAIL: $first_line" + failed=1 + fi + done < <(git log --format="%s" "$base".."$head") + + if [ "$failed" -eq 1 ]; then + echo "" + echo "Some commits do not follow Conventional Commits format." + echo "Expected: [scope][!]: " + echo "See: https://www.conventionalcommits.org/" + exit 1 + fi + echo "All commits follow Conventional Commits format." + + build-and-test: + name: Build & test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install dependencies + run: npm ci + + - name: Check formatting + run: npx prettier --check . + + - name: Typecheck + run: npx tsc --noEmit + + - name: Build + run: npm run build + + - name: Test + run: npm test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..8a489af --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,41 @@ +name: Release + +on: + push: + tags: + - "v*" + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + registry-url: "https://registry.npmjs.org" + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build + + - name: Test + run: npm test + + - name: Publish to npm + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: GitHub Release + uses: softprops/action-gh-release@v2 + with: + generate_release_notes: true diff --git a/.gitignore b/.gitignore index 3d49673..632ab78 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,27 @@ node_modules/ build/ coverage/ *.tsbuildinfo -.env + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# OS .DS_Store +Thumbs.db +desktop.ini + +# Temp +/tmp/ +*.tmp + +# Lefthook +lefthook-local.yml +.lefthookrc.local + +# Environment +.env +.env.local diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6e1cb0f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,64 @@ +# Contributing to torrentclaw-mcp + +Thanks for your interest in contributing! Here's how you can help. + +## Getting Started + +1. Fork the repository +2. Clone your fork: `git clone https://github.com//torrentclaw-mcp.git` +3. Install dev tools and git hooks: + ```bash + make install-tools + make hooks + ``` +4. Create a branch: `git checkout -b feat/my-feature` +5. Make your changes +6. Test locally: `make build && make test` +7. Commit with a clear message (see below) — the commit-msg hook will validate the format +8. Push and open a Pull Request + +## Requirements + +- Node.js 18+ +- npm +- [lefthook](https://github.com/evilmartians/lefthook) (installed via `make install-tools`) + +## Commit Messages + +Commits are validated automatically by a git hook. We follow [Conventional Commits](https://www.conventionalcommits.org/): + +``` +[optional scope][!]: +``` + +Valid types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert` + +Examples: + +``` +feat: add new audio codec detection +fix(scanner): correct HDR10 detection for MKV files +docs: update README examples +refactor: simplify piece selection logic +feat!: redesign output format +``` + +## Code Style + +- Run `npx prettier --write .` before committing (or `make fmt`) +- TypeScript strict mode is enabled +- Keep functions focused and small +- Add comments only where the logic isn't self-evident + +## Reporting Bugs + +Open an issue with: + +- What you expected to happen +- What actually happened +- Steps to reproduce +- Your Node.js version and OS + +## License + +By contributing, you agree that your contributions will be licensed under the project's [MIT License](LICENSE). diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..972f4ac --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +.PHONY: build test fmt lint typecheck version version-next release install-tools hooks clean + +build: + npm run build + +test: + npm test + +fmt: + npx prettier --write . + +typecheck: + npx tsc --noEmit + +lint: fmt typecheck + +version: + @node -p "require('./package.json').version" + +version-next: + @echo "Use: npm version [patch|minor|major] --no-git-tag-version" + +release: + @echo "Use: npm version , then git push origin v" + +install-tools: + npm install + @command -v lefthook >/dev/null 2>&1 || npm install -g lefthook + +hooks: + lefthook install + +clean: + rm -rf build coverage diff --git a/README.md b/README.md index 6934ed4..f361966 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ # torrentclaw-mcp -MCP server for [TorrentClaw](https://torrentclaw.com) — search movies and TV shows with torrent download options, streaming availability, and metadata. +[![npm version](https://img.shields.io/npm/v/torrentclaw-mcp)](https://www.npmjs.com/package/torrentclaw-mcp) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) +[![CI](https://github.com/torrentclaw/torrentclaw-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/torrentclaw/torrentclaw-mcp/actions/workflows/ci.yml) +[![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org) + +[Model Context Protocol](https://modelcontextprotocol.io/) server for [TorrentClaw](https://torrentclaw.com) — giving AI assistants the ability to search movies and TV shows, find torrents with magnet links, check streaming availability, and explore cast/crew metadata. + +torrentclaw-mcp is developed by [TorrentClaw](https://torrentclaw.com) as part of its open-source ecosystem. It wraps the TorrentClaw API into the MCP standard so that any compatible AI assistant (Claude, GPT, etc.) can access the platform's search and discovery features natively. ## Quick Start @@ -8,26 +15,32 @@ MCP server for [TorrentClaw](https://torrentclaw.com) — search movies and TV s npx torrentclaw-mcp ``` -No API key required. +No API key required (optional for higher rate limits). -## Available Tools +## What can it do? -| Tool | Description | -| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | -| `search_content` | Search movies/shows with filters (query, type, genre, year, rating, quality, language, sort). Returns content with torrents and magnet links. | -| `get_popular` | Get popular content ranked by user clicks | -| `get_recent` | Get recently added content | -| `get_watch_providers` | Streaming availability by country (Netflix, Disney+, etc.) | -| `get_credits` | Cast and director for a title | -| `get_torrent_url` | Get .torrent file download URL from info hash | +### Tools -## Resources +| Tool | Description | +| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `search_content` | Search movies/shows with filters (query, type, genre, year, rating, quality, language, audio, HDR, season, episode, sort). Returns torrents, magnet links, and optional streaming info. | +| `autocomplete` | Type-ahead search suggestions (up to 8 results). Use to validate titles before a full search. | +| `get_popular` | Get popular content ranked by user clicks | +| `get_recent` | Get recently added content | +| `get_watch_providers` | Streaming availability by country (Netflix, Disney+, etc.) | +| `get_credits` | Cast and director for a title | +| `get_torrent_url` | Get .torrent file download URL from info hash | +| `track_interaction` | Track user interaction with a torrent (magnet click, download, copy) | +| `submit_scan_request` | Submit a torrent for audio/video quality analysis via [TrueSpec](https://github.com/torrentclaw/truespec) | +| `get_scan_status` | Check the status of a torrent scan request | + +### Resources | URI | Description | | --------------------- | ----------------------------------------------------- | | `torrentclaw://stats` | Catalog statistics (content/torrent counts by source) | -## Prompts +### Prompts | Prompt | Description | | ---------------- | -------------------------------------------------------- | @@ -68,39 +81,56 @@ Add to `.mcp.json` or `~/.claude/settings.json`: } ``` -### Self-hosted +### Environment Variables -Point to your own TorrentClaw instance: +| Variable | Default | Description | +| --------------------- | ------------------------- | -------------------------------------------------------------- | +| `TORRENTCLAW_API_URL` | `https://torrentclaw.com` | Base URL of the TorrentClaw API | +| `TORRENTCLAW_API_KEY` | _(none)_ | Optional API key for authenticated access (higher rate limits) | + +## Project Structure -```json -{ - "mcpServers": { - "torrentclaw": { - "command": "npx", - "args": ["-y", "torrentclaw-mcp"], - "env": { - "TORRENTCLAW_API_URL": "http://localhost:3030", - "TORRENTCLAW_ALLOW_PRIVATE": "true" - } - } - } -} ``` - -## Environment Variables - -| Variable | Default | Description | -| --------------------------- | ------------------------- | ---------------------------------------------------------------------- | -| `TORRENTCLAW_API_URL` | `https://torrentclaw.com` | Base URL of the TorrentClaw API | -| `TORRENTCLAW_ALLOW_PRIVATE` | `false` | Set to `true` to allow private/localhost URLs (for self-hosted setups) | +. +├── src/ +│ ├── index.ts # MCP server entry point +│ ├── config.ts # Configuration & URL validation +│ ├── api-client.ts # TorrentClaw API client with caching +│ ├── types.ts # TypeScript interfaces for API responses +│ ├── prompts.ts # MCP prompt definitions +│ ├── tools/ # MCP tool implementations +│ │ ├── search-content.ts +│ │ ├── autocomplete.ts +│ │ ├── get-popular.ts +│ │ ├── get-recent.ts +│ │ ├── get-watch-providers.ts +│ │ ├── get-credits.ts +│ │ ├── get-torrent-url.ts +│ │ ├── track-interaction.ts +│ │ └── scan-request.ts +│ ├── formatters/ # Output formatting +│ │ ├── content.ts +│ │ ├── providers.ts +│ │ └── credits.ts +│ └── resources/ # MCP resources +│ └── stats.ts +├── tests/ # Test suite (vitest) +├── .github/workflows/ # CI/CD (lint, build, test, release) +├── lefthook.yml # Git hooks (commit lint, prettier, tsc) +├── Makefile # Dev workflow (build, test, lint, fmt) +├── CONTRIBUTING.md # Contribution guidelines +├── LICENSE # MIT +└── README.md +``` ## Development ```bash -git clone https://github.com/buryni/torrentclaw-mcp.git +git clone https://github.com/torrentclaw/torrentclaw-mcp.git cd torrentclaw-mcp -npm install -npm run build +make install-tools +make hooks +make build && make test ``` Test with MCP Inspector: @@ -109,12 +139,16 @@ Test with MCP Inspector: npx @modelcontextprotocol/inspector node build/index.js ``` -Run tests: +## About TorrentClaw -```bash -npm test -``` +[TorrentClaw](https://torrentclaw.com) is an open platform focused on improving the quality and reliability of torrent metadata. Our mission is to make torrent search engines more accurate and the torrent ecosystem healthier — by building tools that verify, enrich, and standardize metadata across the network. + +torrentclaw-mcp is part of the TorrentClaw open-source ecosystem, alongside [TrueSpec](https://github.com/torrentclaw/truespec) (torrent metadata verification). + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. ## License -MIT +MIT License — see [LICENSE](LICENSE) for details. diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000..7e1a368 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,36 @@ +commit-msg: + commands: + validate: + run: | + msg=$(head -1 {1}) + if ! echo "$msg" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?(!)?: .{1,}$'; then + echo "" + echo "ERROR: Invalid commit message format." + echo "" + echo " Got: $msg" + echo "" + echo " Expected: [optional scope][!]: " + echo "" + echo " Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert" + echo " Examples:" + echo " feat: add new audio codec detection" + echo " fix(scanner): correct HDR10 detection for MKV files" + echo " feat!: redesign output format" + echo "" + exit 1 + fi + +pre-commit: + parallel: true + commands: + prettier: + glob: "*.{ts,js,json,md,yml,yaml}" + run: npx prettier --check {staged_files} + typecheck: + glob: "*.ts" + run: npx tsc --noEmit + +pre-push: + commands: + test: + run: npm test diff --git a/package.json b/package.json index 5d174d6..db3f53d 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,8 @@ "dev": "tsx src/index.ts", "test": "vitest run", "test:watch": "vitest", + "fmt": "prettier --write .", + "fmt:check": "prettier --check .", "lint": "tsc --noEmit", "prepublishOnly": "npm run build" }, @@ -35,11 +37,15 @@ "agent", "media" ], - "author": "buryni", + "author": "TorrentClaw (https://torrentclaw.com)", "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/buryni/torrentclaw-mcp" + "url": "https://github.com/torrentclaw/torrentclaw-mcp" + }, + "homepage": "https://github.com/torrentclaw/torrentclaw-mcp#readme", + "bugs": { + "url": "https://github.com/torrentclaw/torrentclaw-mcp/issues" }, "engines": { "node": ">=18.0.0"