Skip to content

Commit 9c082ac

Browse files
Stephan Ferraroclaude
andcommitted
build: complete the migration to MCP Bundles
Finishes the toolchain swap started with the 1.3.9 release. The manifest now declares manifest_version 0.4 — the schema marks dxt_version as deprecated — and the build emits .mcpb only. - scripts/build-dxt.sh -> scripts/build-mcpb.sh, npm run build:dxt -> build:mcpb - README and CLAUDE.md describe the bundle rather than the Desktop Extension, including why it must be packed from the staging copy: packing the working tree bundles every devDependency (~290 packages, 81 MB unpacked) - .gitignore covers *.mcpb alongside the legacy *.dxt The v1.3.9 release keeps both files attached, as a one-off, so anyone on a Claude Desktop build predating the rename is not stranded by a security release. Later releases carry .mcpb only, and the README says so. Verified: manifest validates against mcpb 2.1.2, and the rebuilt bundle unpacks and answers initialize outside the repository. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent d9497d9 commit 9c082ac

7 files changed

Lines changed: 49 additions & 53 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ Thumbs.db
115115
dist/
116116
build/
117117

118-
# DXT build artifacts
118+
# Bundle build artifacts
119+
*.mcpb
119120
*.dxt
120121
releases/

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- The bundle no longer ships devDependencies. It was packed from the working tree, so it carried vitest, TypeScript, ESLint and the packer itself: ~290 packages, 81 MB unpacked. It is now packed from a staging copy with production dependencies only — 116 packages, 3.7 MB. An extension that reaches SSH credentials should not carry a test runner around.
1313
- `manifest.json` was on 1.0.4 while the package was on 1.3.9, so a bundle could not be matched to a release. The versions are now kept in step, and the build fails if they drift.
1414
- The publish workflow no longer fails when a release is created for a version that was already published by hand; it checks npm first and skips.
15+
- The manifest now declares `manifest_version: "0.4"`; `dxt_version` is deprecated in the schema. The build script is `scripts/build-mcpb.sh` (`npm run build:mcpb`) and emits `.mcpb` only — v1.3.9 carries both extensions as a one-off so users on older Claude Desktop builds are not stranded.
1516
- **Ported to TypeScript.** The single self-contained `server.mjs` is now seven typed modules under `src/`, compiled to `dist/` by `tsc`: `server.ts` (MCP wiring and `main()`), `tools.ts` (tool schemas and dispatch), `ssh-client.ts`, `ssh-config-parser.ts`, `config-values.ts`, `platform.ts` (everything with module-load side effects) and `types.ts`. `bin/mcp-ssh.js` and the DXT package load `dist/server.js`; `dist/` is generated, not tracked in git, and built by the `prepare` script on install.
1617
- `tsconfig.json` runs `strict` plus `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `noImplicitOverride`, `noFallthroughCasesInSwitch`, `noPropertyAccessFromIndexSignature` and `verbatimModuleSyntax`. Test files are checked under a lighter config (`tsconfig.test.json`).
1718
- Added ESLint with `typescript-eslint` type-aware rules (`strictTypeChecked` + `stylisticTypeChecked`). Relaxations are documented in place; notably `prefer-nullish-coalescing` exempts strings and numbers, because `??` is *not* equivalent to `||` for a stripped launcher environment (an empty `%ProgramData%` must fall through, see #10) or for `timeout || DEFAULT`.

CLAUDE.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ directly and needs no build).
3434
- `npm publish` - Publish to npm (see PUBLISHING.md for details)
3535
- `npm pack` - Create tarball for testing
3636

37-
### DXT Package Building
38-
- `npm run build:dxt` - Build Desktop Extension (.dxt) package
39-
- `./scripts/build-dxt.sh` - Direct build script execution
37+
### MCP Bundle Building
38+
- `npm run build:mcpb` - Build the installable MCP Bundle (`.mcpb`) into `build/`
39+
- `./scripts/build-mcpb.sh` - Direct build script execution
4040

4141
## Architecture
4242

4343
TypeScript under `src/`, compiled to `dist/` by `tsc`. `dist/` is generated and not in git;
44-
`bin/mcp-ssh.js` and the DXT package both load `dist/server.js`.
44+
`bin/mcp-ssh.js` and the MCP Bundle both load `dist/server.js`.
4545

4646
### Modules
4747
- `src/server.ts` - Entry point. Wires the MCP server, registers handlers, exports `main()`
@@ -192,13 +192,15 @@ Configure in Claude Desktop's `claude_desktop_config.json`:
192192
- `ssh-config` - SSH configuration file parsing
193193
- Node.js built-ins: `child_process`, `fs/promises`, `os`, `path`
194194

195-
## Desktop Extension Support
195+
## MCP Bundle Support
196196

197-
The project supports Desktop Extensions (.dxt) for easy installation in Claude Desktop:
197+
The project ships an installable bundle for Claude Desktop:
198198

199-
- `manifest.json` - DXT package manifest with server configuration
200-
- `scripts/build-dxt.sh` - Build script that creates .dxt packages in `build/` directory
201-
- `.dxt` files are ZIP archives containing the manifest and server files
199+
- `manifest.json` - Bundle manifest. Uses `manifest_version` (the older `dxt_version` is deprecated in the schema), and its `version` must match `package.json` — the build fails on drift
200+
- `scripts/build-mcpb.sh` - Build script that writes `build/mcp-ssh-<version>.mcpb`
201+
- `.mcpb` files are ZIP archives containing the manifest, `dist/`, `bin/` and production `node_modules`
202+
- **Pack from the staging copy, never the working tree.** Packing the tree directly bundles every devDependency (~290 packages, 81 MB unpacked). An extension that reaches SSH credentials should not carry a test runner
203+
- The format was renamed from Desktop Extension (`.dxt`); `@anthropic-ai/dxt` is deprecated in favour of `@anthropic-ai/mcpb`
202204
- Built packages are excluded from git via `.gitignore` but can be uploaded to GitHub releases
203205

204206
## Threat Model
@@ -217,4 +219,4 @@ The LLM driving this MCP server is **not trusted** — its tool arguments can be
217219
- Production code is TypeScript in `src/`, compiled to `dist/`. Never edit `dist/` — it is regenerated on every build.
218220
- SSH operations require properly configured SSH keys or `@password` annotations
219221
- The agent runs over STDIO as an MCP server, not as a standalone application
220-
- DXT packages provide one-click installation alternative to manual JSON configuration
222+
- The MCP Bundle provides one-click installation as an alternative to manual JSON configuration

README.md

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@ This MCP server provides SSH operations through a clean, standardized interface
1010

1111
## Quick Start
1212

13-
### Desktop Extension Installation (Recommended)
13+
### MCP Bundle Installation (Recommended)
1414

15-
The easiest way to install MCP SSH Agent is through the Desktop Extension (.dxt) format:
15+
The easiest way to install MCP SSH Agent is as an MCP Bundle:
1616

17-
1. Download the latest `mcp-ssh-*.dxt` file from the [GitHub releases page](https://github.com/aiondadotcom/mcp-ssh/releases)
18-
2. Double-click the `.dxt` file to install it in Claude Desktop
17+
1. Download the latest `mcp-ssh-*.mcpb` file from the [GitHub releases page](https://github.com/aiondadotcom/mcp-ssh/releases)
18+
2. Double-click the `.mcpb` file to install it in Claude Desktop
19+
20+
> The bundle format was previously called a Desktop Extension and used the `.dxt`
21+
> extension. v1.3.9 shipped both files during the transition; later releases carry
22+
> `.mcpb` only. If your Claude Desktop is old enough to reject a `.mcpb` file,
23+
> update it or use one of the installation methods below.
1924
3. The SSH tools will be automatically available in your conversations with Claude
2025

2126
### Alternative Installation Methods
@@ -622,41 +627,35 @@ MCP SSH Agent gives an LLM the ability to drive `ssh` and `scp` on your behalf.
622627
- **Monitor SSH logs** regularly
623628
- **Use SSH key forwarding carefully** (disable when not needed)
624629

625-
## Building Desktop Extensions
630+
## Building the MCP Bundle
626631

627-
For developers who want to build DXT packages locally:
632+
For developers who want to build the bundle locally:
628633

629634
### Prerequisites
630635

631636
- Node.js 20 or higher
632637
- npm
633638

634-
### Building DXT Package
639+
### Building
635640

636641
```bash
637-
# Install dependencies
638642
npm install
639-
640-
# Build the DXT package
641-
npm run build:dxt
643+
npm run build:mcpb
642644
```
643645

644-
This creates a `.dxt` file in the `build/` directory that can be installed in Claude Desktop.
646+
This writes `build/mcp-ssh-<version>.mcpb`, installable in Claude Desktop.
645647

646-
### Publishing DXT Releases
648+
The bundle is packed from a staging copy containing only production dependencies,
649+
so it does not carry the test and build toolchain. The build refuses to run if
650+
`manifest.json` and `package.json` disagree on the version.
647651

648-
To publish a new DXT release:
652+
### Publishing a release
649653

650654
```bash
651-
# Build the DXT package
652-
npm run build:dxt
653-
654-
# Create a GitHub release with the DXT file
655-
gh release create v1.0.3 build/mcp-ssh-1.0.3.dxt --title "Release v1.0.3" --notes "MCP SSH Agent v1.0.3"
655+
npm run build:mcpb
656+
gh release upload v1.3.9 build/mcp-ssh-1.3.9.mcpb
656657
```
657658

658-
The DXT file will be available as a release asset for users to download and install.
659-
660659
## Contributing
661660

662661
Contributions are welcome! Please feel free to submit a Pull Request.
@@ -712,7 +711,7 @@ mcp-ssh/
712711
├── tsconfig.test.json # Relaxed options for test files
713712
├── eslint.config.mjs # typescript-eslint, type-aware rules
714713
├── vitest.config.mjs # Test and coverage configuration
715-
├── manifest.json # DXT package manifest
714+
├── manifest.json # MCP Bundle manifest
716715
├── package.json # Dependencies and scripts
717716
├── README.md # Documentation
718717
├── LICENSE # MIT License
@@ -722,7 +721,7 @@ mcp-ssh/
722721
├── start.sh # Development startup script
723722
├── start-silent.sh # Silent startup script
724723
├── scripts/
725-
│ └── build-dxt.sh # DXT package build script
724+
│ └── build-mcpb.sh # MCP Bundle build script
726725
└── doc/ # Documentation assets
727726
├── example.png # Usage example screenshot
728727
└── Claude.png # Claude Desktop integration example

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"dxt_version": "0.1",
2+
"manifest_version": "0.4",
33
"name": "mcp-ssh",
44
"version": "1.3.9",
55
"description": "Connect to SSH hosts, run commands, and transfer files securely through Claude Desktop",

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
"start": "node bin/mcp-ssh.js",
1515
"dev": "node bin/mcp-ssh.js",
1616
"build": "tsc -p tsconfig.build.json",
17-
"build:dxt": "./scripts/build-dxt.sh",
1817
"test": "vitest run --coverage",
1918
"test:watch": "vitest",
2019
"prepublishOnly": "npm run build && npm test",
@@ -23,7 +22,8 @@
2322
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
2423
"prepare": "npm run build",
2524
"lint": "eslint .",
26-
"lint:fix": "eslint . --fix"
25+
"lint:fix": "eslint . --fix",
26+
"build:mcpb": "./scripts/build-mcpb.sh"
2727
},
2828
"keywords": [
2929
"mcp",
Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
#!/bin/bash
22

3-
# Build script for creating the installable bundle for Claude Desktop.
3+
# Build script for creating the installable MCP Bundle for Claude Desktop.
44
#
5-
# The format was renamed: Anthropic's ".dxt" (Desktop Extension) is now ".mcpb"
6-
# (MCP Bundle), and @anthropic-ai/dxt is deprecated in favour of
7-
# @anthropic-ai/mcpb. The manifest format is unchanged and validates against the
8-
# new tool as-is. We emit BOTH files from the same bundle: .mcpb for current
9-
# Claude Desktop builds, .dxt as a byte-identical copy for older ones that only
10-
# recognise the previous extension.
5+
# Anthropic renamed the format: the ".dxt" Desktop Extension is now the ".mcpb"
6+
# MCP Bundle, @anthropic-ai/dxt is deprecated in favour of @anthropic-ai/mcpb,
7+
# and the manifest carries `manifest_version` rather than the deprecated
8+
# `dxt_version`. v1.3.9 shipped both extensions during the transition; from here
9+
# on only .mcpb is produced.
1110

1211
set -e
1312

@@ -17,7 +16,7 @@ GREEN='\033[0;32m'
1716
YELLOW='\033[1;33m'
1817
NC='\033[0m' # No Color
1918

20-
echo -e "${GREEN}Building MCP SSH bundle${NC}"
19+
echo -e "${GREEN}Building MCP SSH bundle (.mcpb)${NC}"
2120

2221
if ! command -v npx &> /dev/null; then
2322
echo -e "${RED}Error: npm/npx not found. Please install Node.js${NC}"
@@ -49,7 +48,6 @@ if [ "$PKG_VERSION" != "$MANIFEST_VERSION" ]; then
4948
fi
5049

5150
MCPB_FILE="mcp-ssh-${PKG_VERSION}.mcpb"
52-
DXT_FILE="mcp-ssh-${PKG_VERSION}.dxt"
5351

5452
echo -e "${YELLOW}Validating manifest...${NC}"
5553
npx mcpb validate manifest.json
@@ -75,15 +73,10 @@ mkdir -p "$STAGE/doc" && cp doc/Claude.png "$STAGE/doc/"
7573
echo -e "${YELLOW}Packing bundle...${NC}"
7674
npx mcpb pack "$STAGE" "$BUILD_DIR/$MCPB_FILE"
7775

78-
# Same archive under the legacy extension, for Claude Desktop builds predating
79-
# the rename.
80-
cp "$BUILD_DIR/$MCPB_FILE" "$BUILD_DIR/$DXT_FILE"
81-
8276
echo -e "${GREEN}✓ Bundle created: $BUILD_DIR/$MCPB_FILE${NC}"
83-
echo -e "${GREEN}✓ Legacy copy: $BUILD_DIR/$DXT_FILE${NC}"
8477
echo -e "${GREEN}✓ Size: $(ls -lh "$BUILD_DIR/$MCPB_FILE" | awk '{print $5}')${NC}"
8578

8679
echo -e "\n${YELLOW}Next steps:${NC}"
8780
echo "1. Test the bundle locally"
88-
echo "2. Attach both files to the GitHub release:"
89-
echo " gh release upload v${PKG_VERSION} $BUILD_DIR/$MCPB_FILE $BUILD_DIR/$DXT_FILE"
81+
echo "2. Attach it to the GitHub release:"
82+
echo " gh release upload v${PKG_VERSION} $BUILD_DIR/$MCPB_FILE"

0 commit comments

Comments
 (0)