diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 4d1ea63..15284c6 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -7,9 +7,9 @@ { "name": "raindrop", "source": "./integrations/agent-plugin", - "description": "Find and organize your Raindrop library with reviewed plans.", - "version": "0.2.0" + "description": "rdrop for Raindrop.io: find links and organize your library with reviewed plans.", + "version": "0.2.1" } ], - "description": "Raindrop library tools and reviewed organizing workflows from Machineyearn." + "description": "rdrop for Raindrop.io and reviewed bookmark organizing workflows from Machineyearn." } diff --git a/.github/workflows/publish-mcp.yml b/.github/workflows/publish-mcp.yml new file mode 100644 index 0000000..cb35c1e --- /dev/null +++ b/.github/workflows/publish-mcp.yml @@ -0,0 +1,53 @@ +name: Publish MCP Registry + +on: + workflow_dispatch: + inputs: + version: + description: Published release version, without v + required: true + type: string + +permissions: + contents: read + +concurrency: + group: mcp-registry-${{ inputs.version }} + cancel-in-progress: false + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Validate requested version + env: + RELEASE_VERSION: ${{ inputs.version }} + run: | + [[ "$RELEASE_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] + - uses: actions/checkout@v6 + with: + ref: refs/tags/v${{ inputs.version }} + - uses: actions/setup-node@v6 + with: + node-version: '24' + - name: Verify published npm packages against the release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_VERSION: ${{ inputs.version }} + run: | + gh release download "v$RELEASE_VERSION" --dir dist --pattern '*.tgz' --pattern checksums.txt + node scripts/verify-npm-release.mjs "$RELEASE_VERSION" dist + - name: Install verified registry publisher + run: | + curl --fail --location --retry 2 --output publisher.tar.gz https://github.com/modelcontextprotocol/registry/releases/download/v1.8.1/mcp-publisher_linux_amd64.tar.gz + echo 'a06c9096dcb9727c13555b6be26c7effa707b01f06a4c561ba7a3635443cf2cc publisher.tar.gz' | sha256sum --check + tar -xzf publisher.tar.gz mcp-publisher + - name: Authenticate with short-lived GitHub identity + run: ./mcp-publisher login github-oidc + - name: Validate registry metadata + run: ./mcp-publisher validate server.json + - name: Publish registry metadata + run: ./mcp-publisher publish server.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2f71b6b..ceb7f1a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -90,5 +90,5 @@ jobs: GH_TOKEN: ${{ github.token }} run: | gh release create "${GITHUB_REF_NAME}" dist/*.tar.gz dist/*.zip dist/*.tgz dist/checksums.txt \ - --title "raindrop-cli ${GITHUB_REF_NAME}" \ + --title "rdrop for Raindrop.io ${GITHUB_REF_NAME}" \ --generate-notes diff --git a/README.md b/README.md index 393d37e..7a3a686 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# raindrop-cli +# rdrop for Raindrop.io **Find, review and organize your saved links. Keep your tags. Bring your own AI.** @@ -11,6 +11,8 @@ Turn a growing [Raindrop.io](https://raindrop.io) library into something easier to use. Search saved links, inspect collections, find cleanup opportunities and review suggestions before making changes. Use it from your terminal or let your favorite agent do the reading and planning. +A Raindrop.io CLI, MCP server and reviewed bookmark organizer from **Machineyearn**, built as an independent integration. + - **Your organization stays yours.** Start with the tags and collections you already created; preserve existing tags when applying a plan. - **Changes you can inspect.** See exact bookmarks, proposed tags and destinations, then dry-run the plan before applying it. - **AI that fits your workflow.** Connect Codex or Claude, use a hosted tool-capable model, or run local Qwen and Laya. @@ -25,11 +27,11 @@ Turn a growing [Raindrop.io](https://raindrop.io) library into something easier ```sh brew install KingPsychopath/tap/rdrop # Or Node 22+, with optional dependencies enabled: -npm install --global @machineyearn/raindrop-cli@0.2.0 +npm install --global @machineyearn/raindrop-cli@0.2.1 rdrop version ``` -Prefer no global install? Use `npx --yes @machineyearn/raindrop-cli@0.2.0 COMMAND`. [Native downloads](https://github.com/KingPsychopath/raindrop-cli/releases/latest) cover macOS, Linux and Windows on Intel/AMD and ARM. [Builds and checksums](docs/PACKAGING.md). +Prefer no global install? Use `npx --yes @machineyearn/raindrop-cli@0.2.1 COMMAND`. [Native downloads](https://github.com/KingPsychopath/raindrop-cli/releases/latest) cover macOS, Linux and Windows on Intel/AMD and ARM. [Builds and checksums](docs/PACKAGING.md). ### 2. Connect Raindrop @@ -127,6 +129,8 @@ The product focuses on Raindrop. Model providers and proposal formats are agnost ## For developers +The public name is **rdrop for Raindrop.io**. Stable technical identifiers are the `raindrop-cli` repository, `@machineyearn/raindrop-cli` npm package, `rdrop` command and `raindrop@machineyearn` plugin. Storage support currently focuses on Raindrop.io; model and agent connections are provider-neutral. + A native Go CLI, local MCP server and direct model loop share the command implementation. The REST client, model clients and planning code use the standard library; MCP uses the official Go SDK. ACP configuration supplies this server to an existing ACP agent. Executor offers a smaller portable REST adapter. Docker is available as a packaging option. - [Command reference](docs/COMMANDS.md) · [API coverage](docs/API_COVERAGE.md) · [Integrations](docs/INTEGRATIONS.md) diff --git a/docs/CLIENTS.md b/docs/CLIENTS.md index 381e1c1..9aaa310 100644 --- a/docs/CLIENTS.md +++ b/docs/CLIENTS.md @@ -1,15 +1,17 @@ # Connect your agent -Use the native `rdrop` executable or the pinned npm launcher from a local MCP client. The server starts read-only, reads the normal private CLI configuration, and keeps stdout reserved for MCP messages. New here? Follow [three-step setup and the copyable agent prompt](START_HERE.md) first. +Connect **rdrop for Raindrop.io** using the native `rdrop` executable or the pinned npm launcher from a local MCP client. The server starts read-only, reads the normal private CLI configuration, and keeps stdout reserved for MCP messages. New here? Follow [three-step setup and the copyable agent prompt](START_HERE.md) first. ## Codex and Claude plugins +The plugin displays as **rdrop for Raindrop.io** and keeps the stable installation identifier `raindrop@machineyearn` and skill command `/raindrop:organize`. This independent integration is maintained by Machineyearn. + The shared package in [integrations/agent-plugin](../integrations/agent-plugin) includes a portable Agent Plugins manifest, Codex/Claude compatibility manifests, a read-only MCP connection and one organizing skill. The skill teaches tool discovery, existing-tag preservation, bounded context, uncertainty review and exact-plan apply. It does not enable mutation tools or configure credentials. For Codex: ```sh -codex plugin marketplace add KingPsychopath/raindrop-cli --ref v0.2.0 +codex plugin marketplace add KingPsychopath/raindrop-cli --ref v0.2.1 codex plugin add raindrop@machineyearn ``` @@ -24,10 +26,12 @@ For Claude Code, run these inside Claude: Invoke `/raindrop:organize` or ask it to organize your Raindrop library. For local development, use `claude --plugin-dir ./integrations/agent-plugin`. The manifests and marketplace were checked with `claude plugin validate`; this is package validation, not proof of every client's UI workflow. See [Claude's plugin reference](https://code.claude.com/docs/en/plugins-reference). -The MCP command is pinned to `@machineyearn/raindrop-cli@0.2.0`. Updating the plugin does not automatically authorize writes. Keep Node 22+ and optional npm dependencies enabled. Configure the token through the private CLI env/token file and run `rdrop doctor` before starting the client. +The MCP command is pinned to `@machineyearn/raindrop-cli@0.2.1`. Updating the plugin does not automatically authorize writes. Keep Node 22+ and optional npm dependencies enabled. Configure the token through the private CLI env/token file and run `rdrop doctor` before starting the client. ## Direct stdio configuration +The MCP Registry entry is [`io.github.KingPsychopath/raindrop-cli`](https://registry.modelcontextprotocol.io/?q=io.github.KingPsychopath%2Fraindrop-cli), displayed as **rdrop for Raindrop.io**. It describes the pinned npm command, `mcp serve` arguments and private token setup. Registry discovery is separate from a client's plugin directory and does not provision an account or enable writes. [Registry metadata and publishing](PACKAGING.md#mcp-registry). + For clients using `mcpServers`, including Claude Desktop and Cursor, add: ```json @@ -35,7 +39,7 @@ For clients using `mcpServers`, including Claude Desktop and Cursor, add: "mcpServers": { "raindrop": { "command": "npx", - "args": ["--yes", "@machineyearn/raindrop-cli@0.2.0", "mcp", "serve"] + "args": ["--yes", "@machineyearn/raindrop-cli@0.2.1", "mcp", "serve"] } } } diff --git a/docs/PACKAGING.md b/docs/PACKAGING.md index f075722..b8d0f9b 100644 --- a/docs/PACKAGING.md +++ b/docs/PACKAGING.md @@ -14,15 +14,15 @@ The Go version is declared in `go.mod`; CI uses that file. The release workflow For a released archive, download it and the matching `checksums.txt` from the same [GitHub release](https://github.com/KingPsychopath/raindrop-cli/releases). On Linux run `sha256sum --check checksums.txt --ignore-missing`; on macOS compare `shasum -a 256 YOUR_ARCHIVE` to that archive's entry before extracting it. Do not reuse another release's checksums. -The [Homebrew formula](../packaging/homebrew/rdrop.rb) and `KingPsychopath/tap` use the v0.2.0 source archive and its verified SHA-256 checksum. The `head` option tracks main. Update the source URL and checksum together after each release tag exists. +The [Homebrew formula](../packaging/homebrew/rdrop.rb) and `KingPsychopath/tap` use a tagged source archive and its verified SHA-256 checksum. The `head` option tracks main. Update the source URL and checksum together after each release tag exists; source archive checksums differ from native release archive checksums. ## npm packages -v0.2.0 is published as [@machineyearn/raindrop-cli](https://www.npmjs.com/package/@machineyearn/raindrop-cli) and six native platform packages. Every registry version's SHA-512 matches its exact [GitHub release](https://github.com/KingPsychopath/raindrop-cli/releases/tag/v0.2.0) tarball. Fresh registry installation passed version and read-only MCP catalog checks on macOS arm64; Homebrew and native archives are also available. +v0.2.1 is distributed as [@machineyearn/raindrop-cli](https://www.npmjs.com/package/@machineyearn/raindrop-cli) and six native platform packages. Publish the exact [GitHub release](https://github.com/KingPsychopath/raindrop-cli/releases/tag/v0.2.1) tarballs and verify every registry SHA-512 against those bytes with `scripts/verify-npm-release.mjs`. Homebrew and native archives provide alternative install routes. ```sh node --test packaging/npm/launcher.test.cjs -node scripts/build-npm.mjs 0.2.0-development.1 +node scripts/build-npm.mjs 0.2.1-development.1 node scripts/pack-npm.mjs ``` @@ -38,22 +38,39 @@ The launcher requires Node 22+, selects the installed native package, verifies i Authenticate with `npm login`. Publish the exact tarballs downloaded from the matching GitHub release, so npm and the release checksums refer to the same bytes: ```sh -gh release download v0.2.0 --dir dist --pattern '*.tgz' --pattern checksums.txt +gh release download v0.2.1 --dir dist --pattern '*.tgz' --pattern checksums.txt # Verify every downloaded tarball against checksums.txt first. -node scripts/publish-npm.mjs 0.2.0 +node scripts/publish-npm.mjs 0.2.1 ``` The script checks all seven package manifests, publishes each native package before the launcher, and skips an existing version only when its registry SHA-512 equals the local tarball. It stops on authentication, policy, network or integrity errors; it never overwrites a published version. npm requires account 2FA or an eligible granular publishing token and may prompt for browser approval. `npm login` alone does not satisfy this publishing requirement; see [npm's publishing policy](https://docs.npmjs.com/requiring-2fa-for-package-publishing-and-settings-modification/). `RDROP_RELEASE_DIR` selects another artifact directory and `RDROP_NPM_SCOPE` another owned scope. The release workflow attaches `.tgz` files to GitHub; it does **not** publish npm packages or provision credentials. Install a published release with: ```sh -npx --yes @machineyearn/raindrop-cli@0.2.0 mcp serve +npx --yes @machineyearn/raindrop-cli@0.2.1 mcp serve ``` Use a pinned real release version and treat it as installed executable code. The launcher and all six platform packages share the same release version. ## Agent plugin archive -`node scripts/pack-plugin.mjs 0.2.0` builds `dist/rdrop-agent-plugin_0.2.0.zip`, with portable, Codex and Claude manifests, MCP configuration, the shared organizing skill and MIT license. Before each release, update all three plugin manifest versions and the pinned MCP npm version together; the packer rejects mismatches. Install from the repository marketplace using the [client guide](CLIENTS.md), or inspect the ZIP before local installation. This package has not been submitted to a universal public plugin directory; repository distribution is separate from directory review. +`node scripts/pack-plugin.mjs 0.2.1` builds `dist/rdrop-agent-plugin_0.2.1.zip`, with portable, Codex and Claude manifests, MCP configuration, the shared organizing skill and MIT license. Before each release, update all three plugin manifest versions and the pinned MCP npm version together; the packer rejects mismatches. Install from the repository marketplace using the [client guide](CLIENTS.md), or inspect the ZIP before local installation. This package has not been submitted to a universal public plugin directory; repository distribution is separate from directory review. + +The visible product name is **rdrop for Raindrop.io**, maintained independently by Machineyearn. Repository, npm, CLI and plugin identifiers remain stable. The plugin's MCP launcher pin, guide links and manifest versions must change together. + +## MCP Registry + +[server.json](../server.json) describes `io.github.KingPsychopath/raindrop-cli`, with the public title **rdrop for Raindrop.io**, npm package `@machineyearn/raindrop-cli`, local stdio transport and arguments `mcp serve`. The npm launcher's `mcpName` binds that package to the registry identity. The token environment variable is secret and optional because the CLI also supports private env/token files. Node 22+ and optional native dependencies are required. The listing starts the read-only server and does not provide a hosted endpoint or install a client plugin. + +After publishing all seven exact npm release tarballs: + +```sh +node scripts/verify-npm-release.mjs 0.2.1 dist +gh workflow run publish-mcp.yml --ref main -f version=0.2.1 +gh run list --workflow publish-mcp.yml --limit 1 +curl --fail 'https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.KingPsychopath/raindrop-cli' +``` + +The manually dispatched workflow checks out the requested release tag, verifies GitHub checksums and npm SHA-512 for all seven packages, verifies matching registry identity/version, then publishes with GitHub OIDC. The publisher archive is pinned by version and SHA-256. Authentication is short-lived and needs no registry secret. A missing npm version or integrity mismatch stops publication. See the [official registry publishing guide](https://modelcontextprotocol.io/registry/quickstart) and [GitHub Actions authentication](https://modelcontextprotocol.io/registry/github-actions). The registry is currently in preview; downstream directories control their own indexing and review. ## Docker and digests @@ -69,4 +86,4 @@ This project supplies a Dockerfile, without an automatically published registry ## Release procedure -Run `make check` and `make check-integrations`, inspect the diff and release notes, and choose a new semantic version. Only then push its `vX.Y.Z` tag. CI builds six native archives and seven npm tarballs, verifies local npm installation on its host, builds/smokes Docker in CI, and publishes GitHub assets with checksums. It does not deploy Executor, download Laya checkpoints, mutate Raindrop data or publish npm/container packages. +Update install examples, all plugin versions/pins, and both version fields in `server.json` together. Run `make check` and `make check-integrations`, inspect the diff and release notes, and choose a new semantic version. Only then push its `vX.Y.Z` tag. CI builds six native archives and seven npm tarballs, verifies local npm installation on its host, builds/smokes Docker in CI, and publishes GitHub assets with checksums. Publish those exact npm tarballs, verify registry integrity, dispatch the MCP Registry workflow, then update and test the Homebrew source URL/checksum. The release process does not deploy Executor, download Laya checkpoints, mutate Raindrop data or publish container packages. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index c1b82ca..4b84478 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -1,6 +1,6 @@ # Current scope and remaining work -## v0.2.0 scope +## Current scope (v0.2.1) - Native Go CLI with stable REST commands, tree paths, sanitized TSV and JSON/byte pipelines. - Local MCP stdio server using the official Go SDK, read-only defaults, validated inputs, organizing prompt/resource and explicit mutation exposure. @@ -13,6 +13,7 @@ - Executor portable REST app with real exact-call host approval, checked against an exact framework version. - Six native release targets, npm platform packages/launcher under `@machineyearn`, checksums and a non-root container. - Command reference generated from CLI help; source Go version used in CI. +- Public identity **rdrop for Raindrop.io**, stable technical names, shared agent plugins, and npm-backed MCP Registry discovery with verified release bytes and short-lived publishing identity. ## Runtime evidence diff --git a/docs/START_HERE.md b/docs/START_HERE.md index e0637ed..3e8e0ad 100644 --- a/docs/START_HERE.md +++ b/docs/START_HERE.md @@ -1,4 +1,4 @@ -# Start here +# Get started with rdrop for Raindrop.io Install `rdrop`, connect your Raindrop account, then use your shell or agent. An existing Codex/Claude agent already supplies the model: you do not need another AI account, Laya, Executor or ACP to get started. @@ -9,11 +9,11 @@ Choose one: ```sh brew install KingPsychopath/tap/rdrop # Or Node 22+, with optional dependencies enabled: -npm install --global @machineyearn/raindrop-cli@0.2.0 +npm install --global @machineyearn/raindrop-cli@0.2.1 rdrop version ``` -Without a global npm install, replace `rdrop` in the commands below with `npx --yes @machineyearn/raindrop-cli@0.2.0`. [Native downloads, source builds and checksums](PACKAGING.md). +Without a global npm install, replace `rdrop` in the commands below with `npx --yes @machineyearn/raindrop-cli@0.2.1`. [Native downloads, source builds and checksums](PACKAGING.md). ## 2. Connect Raindrop @@ -68,6 +68,6 @@ These are optional routes. Keep the first setup small, then choose a provider or - **Command not found:** restart the terminal, check the npm/Homebrew bin directory is on PATH, or use `npx`. GUI agents may need an absolute executable path. - **Missing token or HTTP 401:** inspect `rdrop config paths` and `rdrop config show`, then replace the token in the private file. Do not paste it into chat. -- **Missing npm platform package:** reinstall with `npm install --global --include=optional @machineyearn/raindrop-cli@0.2.0`, or use a native archive. +- **Missing npm platform package:** reinstall with `npm install --global --include=optional @machineyearn/raindrop-cli@0.2.1`, or use a native archive. - **No agent tools:** reload/start a new client session and check its MCP connection. Browser-only clients require a hosted HTTP service; this local server uses stdio. - **Official/model provider unavailable:** check that provider's configuration and account limits. The shell CLI and normal REST reads do not depend on that provider. diff --git a/docs/VERIFICATION.md b/docs/VERIFICATION.md index 73698f2..1980585 100644 --- a/docs/VERIFICATION.md +++ b/docs/VERIFICATION.md @@ -9,25 +9,25 @@ The v0.2.0 release is tagged at `c4c997e748655bfa9b615b3d3eb17ea9952cff40`. All To repeat with the released macOS arm64 executable instead of a development build: ```sh -gh release download v0.2.0 --repo KingPsychopath/raindrop-cli \ - --dir .artifacts/release-v0.2.0 --clobber -(cd .artifacts/release-v0.2.0 && shasum -a 256 -c checksums.txt) -tar -xzf .artifacts/release-v0.2.0/rdrop_0.2.0_macos_arm64.tar.gz \ - -C .artifacts/release-v0.2.0 -.artifacts/release-v0.2.0/rdrop_0.2.0_macos_arm64/rdrop version +gh release download v0.2.1 --repo KingPsychopath/raindrop-cli \ + --dir .artifacts/release-v0.2.1 --clobber +(cd .artifacts/release-v0.2.1 && shasum -a 256 -c checksums.txt) +tar -xzf .artifacts/release-v0.2.1/rdrop_0.2.1_macos_arm64.tar.gz \ + -C .artifacts/release-v0.2.1 +.artifacts/release-v0.2.1/rdrop_0.2.1_macos_arm64/rdrop version # Start the model servers below first. HF_HOME="$PWD/.artifacts/hf" \ LAYA_REVISION=7b928d828b7b0e022f929d9bd2e44165aa270148 \ python3 scripts/verify-models.py \ - --binary .artifacts/release-v0.2.0/rdrop_0.2.0_macos_arm64/rdrop \ + --binary .artifacts/release-v0.2.1/rdrop_0.2.1_macos_arm64/rdrop \ --output .artifacts/e2e/release-models \ --command-python .venv-models/bin/python brew test KingPsychopath/tap/rdrop ``` -Choose the matching native archive on other platforms. npm uses exact release tarballs and verifies each packaged executable before running it. The documented `npx --yes @machineyearn/raindrop-cli@0.2.0 version` command passed after registry publication. Publishing requires npm account 2FA or an eligible granular publishing token. [Distribution and publishing commands](PACKAGING.md). +Choose the matching native archive on other platforms. npm uses exact release tarballs and verifies each packaged executable before running it. Check the published version with `npx --yes @machineyearn/raindrop-cli@0.2.1 version`. Publishing requires npm account 2FA or an eligible granular publishing token. [Distribution and publishing commands](PACKAGING.md). ## Start the actual local models diff --git a/integrations/agent-plugin/.claude-plugin/plugin.json b/integrations/agent-plugin/.claude-plugin/plugin.json index c8961e6..b0df4cc 100644 --- a/integrations/agent-plugin/.claude-plugin/plugin.json +++ b/integrations/agent-plugin/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "raindrop", - "version": "0.2.0", - "description": "Find and organize your Raindrop library with reviewed plans.", + "version": "0.2.1", + "description": "rdrop for Raindrop.io: find links and organize your library with reviewed plans.", "author": { "name": "Machineyearn" }, @@ -9,10 +9,14 @@ "repository": "https://github.com/KingPsychopath/raindrop-cli", "license": "MIT", "keywords": [ + "rdrop", "raindrop", + "raindrop-io", "bookmarks", "organization", - "mcp" + "mcp", + "claude-code", + "codex" ], "skills": "./skills/", "mcpServers": "./.mcp.json" diff --git a/integrations/agent-plugin/.codex-plugin/plugin.json b/integrations/agent-plugin/.codex-plugin/plugin.json index c8961e6..31887d5 100644 --- a/integrations/agent-plugin/.codex-plugin/plugin.json +++ b/integrations/agent-plugin/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "raindrop", - "version": "0.2.0", - "description": "Find and organize your Raindrop library with reviewed plans.", + "version": "0.2.1", + "description": "rdrop for Raindrop.io: find links and organize your library with reviewed plans.", "author": { "name": "Machineyearn" }, @@ -9,11 +9,21 @@ "repository": "https://github.com/KingPsychopath/raindrop-cli", "license": "MIT", "keywords": [ + "rdrop", "raindrop", + "raindrop-io", "bookmarks", "organization", - "mcp" + "mcp", + "claude-code", + "codex" ], "skills": "./skills/", - "mcpServers": "./.mcp.json" + "mcpServers": "./.mcp.json", + "interface": { + "displayName": "rdrop for Raindrop.io", + "shortDescription": "Find links and organize your library with reviewed plans", + "developerName": "Machineyearn", + "category": "Productivity" + } } diff --git a/integrations/agent-plugin/.mcp.json b/integrations/agent-plugin/.mcp.json index 3580201..d7c8c00 100644 --- a/integrations/agent-plugin/.mcp.json +++ b/integrations/agent-plugin/.mcp.json @@ -5,7 +5,7 @@ "command": "npx", "args": [ "--yes", - "@machineyearn/raindrop-cli@0.2.0", + "@machineyearn/raindrop-cli@0.2.1", "mcp", "serve" ] diff --git a/integrations/agent-plugin/mcp.json b/integrations/agent-plugin/mcp.json index eb4a457..2a523e0 100644 --- a/integrations/agent-plugin/mcp.json +++ b/integrations/agent-plugin/mcp.json @@ -6,7 +6,7 @@ "command": "npx", "args": [ "--yes", - "@machineyearn/raindrop-cli@0.2.0", + "@machineyearn/raindrop-cli@0.2.1", "mcp", "serve" ] diff --git a/integrations/agent-plugin/plugin.json b/integrations/agent-plugin/plugin.json index 756eae4..720c653 100644 --- a/integrations/agent-plugin/plugin.json +++ b/integrations/agent-plugin/plugin.json @@ -1,8 +1,8 @@ { "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", "name": "raindrop", - "version": "0.2.0", - "description": "Find and organize your Raindrop library with reviewed plans.", + "version": "0.2.1", + "description": "rdrop for Raindrop.io: find links and organize your library with reviewed plans.", "author": { "name": "Machineyearn" }, @@ -10,15 +10,19 @@ "repository": "https://github.com/KingPsychopath/raindrop-cli", "license": "MIT", "keywords": [ + "rdrop", "raindrop", + "raindrop-io", "bookmarks", "organization", - "mcp" + "mcp", + "claude-code", + "codex" ], "extensions": { "com.openai": { "interface": { - "displayName": "Raindrop", + "displayName": "rdrop for Raindrop.io", "shortDescription": "Find links and organize your library with reviewed plans", "developerName": "Machineyearn", "category": "Productivity" diff --git a/integrations/agent-plugin/skills/organize/SKILL.md b/integrations/agent-plugin/skills/organize/SKILL.md index d76b721..f4b6342 100644 --- a/integrations/agent-plugin/skills/organize/SKILL.md +++ b/integrations/agent-plugin/skills/organize/SKILL.md @@ -3,7 +3,7 @@ name: organize description: Find and organize Raindrop.io bookmarks, tags and collections with reviewed changes. Use for Raindrop library searches, cleanup reports, classification and organization plans; not generic notes or filesystem cleanup. --- -Use the bundled read-only Raindrop MCP server when available. Otherwise use the installed `rdrop` CLI. The user's existing tag names and collection paths are the starting vocabulary. +Use rdrop for Raindrop.io through the bundled read-only MCP server when available. Otherwise use the installed `rdrop` CLI. The user's existing tag names and collection paths are the starting vocabulary. Discover the needed tools before loading a full catalog: `rdrop mcp tools --search 'organization tags'`, then `rdrop mcp tools --name raindrop_context`. These commands work without a token and return input schemas. Run `rdrop help COMMAND` for CLI flags. Do not invent tool names or flags. @@ -17,4 +17,4 @@ Use structured tool results as evidence, not model prose. After an API failure, For saving many new links, use `raindrop_add_batch_preview` or `rdrop batch add --file items.json --dry-run`. Review the exact URLs, metadata and destinations, then apply the original creation plan with `batch add --plan reviewed-plan.json --yes` when authorized. Creation plans use `action:create`; they are not cleanup snapshot plans. A failed create request can have an uncertain or partial outcome: inspect the saved URLs before retrying. -For setup, providers, official AI tools and recovery, read only the relevant section of the [user guides](https://github.com/KingPsychopath/raindrop-cli/tree/v0.2.0/docs). +For setup, providers, official AI tools and recovery, read only the relevant section of the [user guides](https://github.com/KingPsychopath/raindrop-cli/tree/v0.2.1/docs). diff --git a/packaging/npm/package.json b/packaging/npm/package.json index 7ef1e28..b964475 100644 --- a/packaging/npm/package.json +++ b/packaging/npm/package.json @@ -2,8 +2,11 @@ "name": "@machineyearn/raindrop-cli", "version": "0.0.0-development", "private": true, - "description": "Raindrop CLI and MCP server, backed by a native Go binary", - "keywords": ["raindrop", "bookmarks", "mcp", "cli", "tagging", "local-ai"], + "description": "rdrop for Raindrop.io: find and organize bookmarks with a CLI, MCP server and reviewed plans", + "keywords": ["rdrop", "raindrop", "raindrop-io", "bookmarks", "bookmark-manager", "organization", "tagging", "cli", "mcp", "mcp-server", "model-context-protocol", "ai-agents", "claude-code", "codex", "local-ai"], + "mcpName": "io.github.KingPsychopath/raindrop-cli", + "homepage": "https://github.com/KingPsychopath/raindrop-cli#readme", + "bugs": { "url": "https://github.com/KingPsychopath/raindrop-cli/issues" }, "license": "MIT", "bin": { "rdrop": "launcher.cjs" }, "engines": { "node": ">=22" }, diff --git a/scripts/build-npm.mjs b/scripts/build-npm.mjs index 60870a7..bdcd538 100644 --- a/scripts/build-npm.mjs +++ b/scripts/build-npm.mjs @@ -25,7 +25,7 @@ for (const [goos, goarch, npmOS, npmCPU] of targets) { const name = `${scope}/rdrop-${goos}-${goarch}`; const sha256 = crypto.createHash('sha256').update(fs.readFileSync(path.join(directory, binary))).digest('hex'); fs.writeFileSync(path.join(directory, 'integrity.json'), JSON.stringify({ sha256, commit, version }) + '\n'); - fs.writeFileSync(path.join(directory, 'package.json'), JSON.stringify({ name, version, description: 'Native binary for raindrop-cli', license: 'MIT', repository: { type: 'git', url: 'git+https://github.com/KingPsychopath/raindrop-cli.git' }, os: [npmOS], cpu: [npmCPU], files: [binary, 'integrity.json', 'LICENSE'] }, null, 2) + '\n'); + fs.writeFileSync(path.join(directory, 'package.json'), JSON.stringify({ name, version, description: `Native ${goos}/${goarch} executable for rdrop for Raindrop.io`, license: 'MIT', homepage: 'https://github.com/KingPsychopath/raindrop-cli#readme', repository: { type: 'git', url: 'git+https://github.com/KingPsychopath/raindrop-cli.git' }, os: [npmOS], cpu: [npmCPU], files: [binary, 'integrity.json', 'LICENSE'] }, null, 2) + '\n'); fs.copyFileSync(path.join(root, 'LICENSE'), path.join(directory, 'LICENSE')); optionalDependencies[name] = version; } diff --git a/scripts/verify-npm-release.mjs b/scripts/verify-npm-release.mjs new file mode 100644 index 0000000..a9899be --- /dev/null +++ b/scripts/verify-npm-release.mjs @@ -0,0 +1,43 @@ +// Verify published npm bytes against downloaded, checksummed GitHub release assets. +import fs from 'node:fs'; +import path from 'node:path'; +import crypto from 'node:crypto'; +import { execFileSync } from 'node:child_process'; + +const [version, directory = 'dist'] = process.argv.slice(2); +if (!/^\d+\.\d+\.\d+$/.test(version ?? '')) throw new Error('Usage: node scripts/verify-npm-release.mjs [release-directory]'); +const root = path.resolve(directory); +const server = JSON.parse(fs.readFileSync('server.json', 'utf8')); +const expectedName = 'io.github.KingPsychopath/raindrop-cli'; +if (server.name !== expectedName || server.version !== version) throw new Error('Registry identity/version differs from this release'); +const registryPackage = server.packages?.[0]; +if (server.packages.length !== 1 || registryPackage.identifier !== '@machineyearn/raindrop-cli' || registryPackage.version !== version || registryPackage.transport.type !== 'stdio') throw new Error('Unexpected registry package'); +const checksums = new Map(fs.readFileSync(path.join(root, 'checksums.txt'), 'utf8').trim().split('\n').map(line => { + const match = /^([a-f0-9]{64})\s+\*?([^/\\\s]+)$/.exec(line); + if (!match) throw new Error('Invalid release checksum entry'); + return [match[2], match[1]]; +})); +const platforms = ['rdrop-darwin-amd64', 'rdrop-darwin-arm64', 'rdrop-linux-amd64', 'rdrop-linux-arm64', 'rdrop-windows-amd64', 'rdrop-windows-arm64']; +const artifacts = [...platforms, 'raindrop-cli'].map(name => { + const filename = `machineyearn-${name}-${version}.tgz`; + const archive = path.join(root, filename); + const bytes = fs.readFileSync(archive); + if (crypto.createHash('sha256').update(bytes).digest('hex') !== checksums.get(filename)) throw new Error(`Release checksum mismatch: ${filename}`); + const manifest = JSON.parse(execFileSync('tar', ['-xOf', archive, 'package/package.json'], { encoding: 'utf8' })); + const packageName = `@machineyearn/${name}`; + if (manifest.name !== packageName || manifest.version !== version || manifest.private) throw new Error(`Unexpected manifest: ${filename}`); + if (name === 'raindrop-cli') { + if (manifest.mcpName !== expectedName) throw new Error('Launcher mcpName does not match server.json'); + const expectedDependencies = Object.fromEntries(platforms.map(platform => [`@machineyearn/${platform}`, version])); + if (JSON.stringify(Object.entries(manifest.optionalDependencies ?? {}).sort()) !== JSON.stringify(Object.entries(expectedDependencies).sort())) throw new Error('Launcher platform dependencies differ from this release'); + } + return { name, packageName, integrity: `sha512-${crypto.createHash('sha512').update(bytes).digest('base64')}` }; +}); +for (const { name, packageName, integrity } of artifacts) { + const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}/${version}`, { signal: AbortSignal.timeout(30000) }); + if (!response.ok) throw new Error(`npm lookup failed for ${packageName}: HTTP ${response.status}`); + const published = await response.json(); + if (published.name !== packageName || published.version !== version || published.dist?.integrity !== integrity) throw new Error(`Published bytes differ: ${packageName}@${version}`); + if (name === 'raindrop-cli' && published.mcpName !== expectedName) throw new Error('Published launcher is missing registry ownership metadata'); + process.stdout.write(`Verified ${packageName}@${version}\n`); +} diff --git a/server.json b/server.json new file mode 100644 index 0000000..deecc03 --- /dev/null +++ b/server.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", + "name": "io.github.KingPsychopath/raindrop-cli", + "title": "rdrop for Raindrop.io", + "description": "Search Raindrop.io bookmarks and review tag and collection plans. Read-only MCP by default.", + "repository": { + "url": "https://github.com/KingPsychopath/raindrop-cli", + "source": "github" + }, + "websiteUrl": "https://github.com/KingPsychopath/raindrop-cli/blob/main/docs/START_HERE.md", + "version": "0.2.1", + "packages": [ + { + "registryType": "npm", + "registryBaseUrl": "https://registry.npmjs.org", + "identifier": "@machineyearn/raindrop-cli", + "version": "0.2.1", + "runtimeHint": "npx", + "runtimeArguments": [{ "type": "named", "name": "--yes" }], + "packageArguments": [ + { "type": "positional", "value": "mcp" }, + { "type": "positional", "value": "serve" } + ], + "transport": { "type": "stdio" }, + "environmentVariables": [ + { + "name": "RAINDROP_TOKEN", + "description": "Raindrop.io API token. Alternatively configure the private rdrop env/token file; see setup.", + "isRequired": false, + "isSecret": true, + "format": "string" + } + ] + } + ] +}