ssh-mcp-pro 1.1.4 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/README.md +58 -10
- package/REGISTRY_SUBMISSION.md +3 -3
- package/SECURITY.md +4 -0
- package/SECURITY_DECISIONS.md +32 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -1
- package/dist/connector-profile.d.ts +3 -0
- package/dist/connector-profile.d.ts.map +1 -1
- package/dist/connector-profile.js +36 -14
- package/dist/connector-profile.js.map +1 -1
- package/dist/http-security.d.ts.map +1 -1
- package/dist/http-security.js +19 -4
- package/dist/http-security.js.map +1 -1
- package/dist/http-server-lifecycle.d.ts +17 -0
- package/dist/http-server-lifecycle.d.ts.map +1 -0
- package/dist/http-server-lifecycle.js +122 -0
- package/dist/http-server-lifecycle.js.map +1 -0
- package/dist/http-server-router.d.ts +28 -0
- package/dist/http-server-router.d.ts.map +1 -0
- package/dist/http-server-router.js +108 -0
- package/dist/http-server-router.js.map +1 -0
- package/dist/http-server-runtime.d.ts +21 -0
- package/dist/http-server-runtime.d.ts.map +1 -0
- package/dist/http-server-runtime.js +415 -0
- package/dist/http-server-runtime.js.map +1 -0
- package/dist/http-session-registry.d.ts +35 -0
- package/dist/http-session-registry.d.ts.map +1 -0
- package/dist/http-session-registry.js +96 -0
- package/dist/http-session-registry.js.map +1 -0
- package/dist/index.js +12 -5
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +8 -1
- package/dist/prompts.js.map +1 -1
- package/dist/remote/agent-cli.d.ts.map +1 -1
- package/dist/remote/agent-cli.js +20 -1
- package/dist/remote/agent-cli.js.map +1 -1
- package/dist/remote/agent-connection-lifecycle.d.ts +47 -0
- package/dist/remote/agent-connection-lifecycle.d.ts.map +1 -0
- package/dist/remote/agent-connection-lifecycle.js +304 -0
- package/dist/remote/agent-connection-lifecycle.js.map +1 -0
- package/dist/remote/agent-executor.d.ts.map +1 -1
- package/dist/remote/agent-executor.js +93 -68
- package/dist/remote/agent-executor.js.map +1 -1
- package/dist/remote/agent-handler.d.ts +22 -8
- package/dist/remote/agent-handler.d.ts.map +1 -1
- package/dist/remote/agent-handler.js +151 -98
- package/dist/remote/agent-handler.js.map +1 -1
- package/dist/remote/config.d.ts.map +1 -1
- package/dist/remote/config.js +14 -0
- package/dist/remote/config.js.map +1 -1
- package/dist/remote/control-plane.d.ts.map +1 -1
- package/dist/remote/control-plane.js +28 -3
- package/dist/remote/control-plane.js.map +1 -1
- package/dist/remote/oauth-handler.d.ts +2 -0
- package/dist/remote/oauth-handler.d.ts.map +1 -1
- package/dist/remote/oauth-handler.js +62 -1
- package/dist/remote/oauth-handler.js.map +1 -1
- package/dist/remote/policy-update-guard.d.ts +14 -0
- package/dist/remote/policy-update-guard.d.ts.map +1 -0
- package/dist/remote/policy-update-guard.js +27 -0
- package/dist/remote/policy-update-guard.js.map +1 -0
- package/dist/remote/policy.d.ts.map +1 -1
- package/dist/remote/policy.js +13 -2
- package/dist/remote/policy.js.map +1 -1
- package/dist/remote/safe-file.d.ts +5 -0
- package/dist/remote/safe-file.d.ts.map +1 -0
- package/dist/remote/safe-file.js +194 -0
- package/dist/remote/safe-file.js.map +1 -0
- package/dist/remote/store.d.ts +1 -0
- package/dist/remote/store.d.ts.map +1 -1
- package/dist/remote/store.js +5 -0
- package/dist/remote/store.js.map +1 -1
- package/dist/remote/types.d.ts +5 -0
- package/dist/remote/types.d.ts.map +1 -1
- package/dist/remote/websocket.d.ts +38 -13
- package/dist/remote/websocket.d.ts.map +1 -1
- package/dist/remote/websocket.js +90 -126
- package/dist/remote/websocket.js.map +1 -1
- package/dist/render-http.js +2 -1
- package/dist/render-http.js.map +1 -1
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +4 -2
- package/dist/retry.js.map +1 -1
- package/dist/server-http.d.ts +1 -1
- package/dist/server-http.d.ts.map +1 -1
- package/dist/server-http.js +1 -431
- package/dist/server-http.js.map +1 -1
- package/dist/tools/connector.provider.d.ts.map +1 -1
- package/dist/tools/connector.provider.js +5 -3
- package/dist/tools/connector.provider.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/output-schemas.d.ts.map +1 -1
- package/dist/tools/output-schemas.js +1 -0
- package/dist/tools/output-schemas.js.map +1 -1
- package/dist/tools/process.provider.d.ts +2 -0
- package/dist/tools/process.provider.d.ts.map +1 -1
- package/dist/tools/process.provider.js +60 -1
- package/dist/tools/process.provider.js.map +1 -1
- package/dist/tools/system.provider.d.ts +13 -0
- package/dist/tools/system.provider.d.ts.map +1 -1
- package/dist/tools/system.provider.js +304 -2
- package/dist/tools/system.provider.js.map +1 -1
- package/dist/types.d.ts +39 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +34 -0
- package/dist/types.js.map +1 -1
- package/docs/adding-a-device.md +127 -0
- package/docs/agent-runtime-config.md +34 -0
- package/docs/development/api-stability.md +44 -0
- package/docs/development/coding-standards.md +35 -0
- package/docs/development/commit-conventions.md +35 -0
- package/docs/development/dependency-management.md +60 -0
- package/docs/development/deprecation-policy.md +29 -0
- package/docs/development/local-setup.md +46 -0
- package/docs/development/release-process.md +57 -0
- package/docs/development/testing-policy.md +47 -0
- package/docs/explanation/architecture.md +44 -0
- package/docs/how-to/README.md +14 -0
- package/docs/how-to/configure-ssh-policy.md +50 -0
- package/docs/openssf-evidence.md +75 -0
- package/docs/openssf-gap-analysis.md +63 -0
- package/docs/openssf-proposal-links.md +37 -0
- package/docs/professionalization-plan.md +81 -0
- package/docs/reference/README.md +21 -0
- package/docs/reference/cli.md +41 -0
- package/docs/reference/compatibility.md +46 -0
- package/docs/reference/configuration.md +72 -0
- package/docs/remote-mcp-hardening.md +59 -0
- package/docs/repo-maturity-report.md +565 -0
- package/docs/security/assurance-case.md +58 -0
- package/docs/security/dependency-audit-exceptions.json +4 -0
- package/docs/security/dependency-audit-exceptions.md +15 -0
- package/docs/security/input-validation.md +54 -0
- package/docs/security/release-integrity.md +28 -0
- package/docs/security/scanning-policy.md +50 -0
- package/docs/security/secrets-management.md +49 -0
- package/docs/security/threat-model.md +65 -0
- package/docs/testing.md +24 -0
- package/docs/troubleshooting.md +56 -0
- package/docs/tutorials/getting-started.md +84 -0
- package/mcp.json +1 -1
- package/package.json +37 -18
- package/registry/ssh-mcp-pro/mcp.json +1 -1
- package/server.json +3 -3
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Dependency Audit Exceptions
|
|
2
|
+
|
|
3
|
+
Dependency audit exceptions are a last resort. They must be scoped to a specific distribution surface, include reachability evidence, name an owner, define a removal condition, and expire automatically. The machine-readable source of truth is [`dependency-audit-exceptions.json`](./dependency-audit-exceptions.json).
|
|
4
|
+
|
|
5
|
+
The canonical workspace, Docker image, and release lockfile must remain free of known moderate-or-higher advisories. `pnpm run audit:packed` separately installs the generated npm tarball as an external consumer and rejects every advisory that is not listed in the exception file. It also rejects expired or stale exceptions.
|
|
6
|
+
|
|
7
|
+
## Active exception
|
|
8
|
+
|
|
9
|
+
| Advisory | Package path | Scope | Reachability assessment | Owner | Expires |
|
|
10
|
+
| --- | --- | --- | --- | --- | --- |
|
|
11
|
+
| `GHSA-frvp-7c67-39w9` | `ssh-mcp-pro > @modelcontextprotocol/sdk > @hono/node-server` | Published npm consumer graph | The affected `serve-static` implementation is not imported or invoked by ssh-mcp-pro. HTTP entrypoints use the project's own Node HTTP implementation. | `@oaslananka` | 2026-08-23 |
|
|
12
|
+
|
|
13
|
+
The latest `@modelcontextprotocol/sdk` release still constrains `@hono/node-server` to the vulnerable 1.x major. Local, CI, and container installs use the patched 2.x major through the root workspace override. npm consumers do not inherit dependency-package overrides, so the exception remains visible only for the independently installed tarball.
|
|
14
|
+
|
|
15
|
+
Remove the exception immediately when the MCP SDK accepts `@hono/node-server >=2.0.5`, or before introducing any use of the Hono Node adapter or `serve-static`.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Input Validation
|
|
2
|
+
|
|
3
|
+
This summarizes where and how untrusted input is constrained, based on the environment
|
|
4
|
+
variables and policy behavior already documented in the
|
|
5
|
+
[README configuration table](../../README.md#configuration) and
|
|
6
|
+
[SECURITY_DECISIONS.md](../../SECURITY_DECISIONS.md). It intentionally stays at the
|
|
7
|
+
policy level rather than asserting internal implementation details this audit didn't
|
|
8
|
+
verify line-by-line.
|
|
9
|
+
|
|
10
|
+
## Schema-level validation
|
|
11
|
+
|
|
12
|
+
Tool inputs are validated with [zod](https://www.npmjs.com/package/zod) schemas (a
|
|
13
|
+
runtime dependency in `package.json`); policy file contents are checked against JSON
|
|
14
|
+
Schema tooling (`ajv` is a devDependency used in the validation scripts under
|
|
15
|
+
`scripts/`). Malformed input is expected to be rejected before it reaches SSH/filesystem
|
|
16
|
+
operations, rather than sanitized and passed through.
|
|
17
|
+
|
|
18
|
+
## Allow/deny lists, not blanket flags
|
|
19
|
+
|
|
20
|
+
Most of the security-relevant configuration surface is an allow/deny pair rather than a
|
|
21
|
+
single boolean, specifically so operators can scope access narrowly instead of an
|
|
22
|
+
all-or-nothing switch:
|
|
23
|
+
|
|
24
|
+
- `SSH_MCP_ALLOWED_HOSTS` / implicit deny of everything else.
|
|
25
|
+
- `SSH_MCP_COMMAND_ALLOW` / `SSH_MCP_COMMAND_DENY`.
|
|
26
|
+
- `SSH_MCP_PATH_ALLOW_PREFIXES` / `SSH_MCP_PATH_DENY_PREFIXES` (remote filesystem).
|
|
27
|
+
- `SSH_MCP_LOCAL_PATH_ALLOW_PREFIXES` / `SSH_MCP_LOCAL_PATH_DENY_PREFIXES` (local
|
|
28
|
+
transfer endpoints).
|
|
29
|
+
- `SSH_MCP_TUNNEL_ALLOW_BIND_HOSTS` / `SSH_MCP_TUNNEL_DENY_BIND_HOSTS` and the
|
|
30
|
+
equivalent remote-host/port allow/deny pairs for tunnels.
|
|
31
|
+
|
|
32
|
+
Deny lists are checked in addition to allow lists — see
|
|
33
|
+
[docs/how-to/configure-ssh-policy.md](../how-to/configure-ssh-policy.md) for how to use
|
|
34
|
+
both together.
|
|
35
|
+
|
|
36
|
+
## Size/resource bounds
|
|
37
|
+
|
|
38
|
+
Every buffer- or transfer-related setting has an explicit byte ceiling:
|
|
39
|
+
`SSH_MCP_MAX_COMMAND_OUTPUT_BYTES`, `SSH_MCP_MAX_FILE_SIZE`,
|
|
40
|
+
`SSH_MCP_MAX_FILE_WRITE_BYTES`, `SSH_MCP_MAX_TRANSFER_BYTES`,
|
|
41
|
+
`SSH_MCP_HTTP_MAX_REQUEST_BODY_BYTES`, and stream/session ceilings
|
|
42
|
+
(`SSH_MCP_MAX_STREAM_CHUNKS`, `SSH_MCP_MAX_SESSIONS`, `SSH_MCP_HTTP_MAX_SESSIONS`). These
|
|
43
|
+
exist to bound both memory use and the blast radius of any single tool call.
|
|
44
|
+
|
|
45
|
+
## Resolved gap (was: known gap)
|
|
46
|
+
|
|
47
|
+
Several CodeQL alerts (`js/file-access-to-http` / `js/http-to-file-access` in
|
|
48
|
+
`src/remote/agent-cli.ts` and `scripts/check-dependency-freshness.mjs`) were exactly
|
|
49
|
+
input-validation-shaped findings — untrusted file data influencing a network request, or
|
|
50
|
+
untrusted network data influencing a file write. As of 2026-07-03 all were dismissed
|
|
51
|
+
after independently re-verifying the rationale in `SECURITY_DECISIONS.md` against the
|
|
52
|
+
current code (not just re-asserting stale documentation) — see
|
|
53
|
+
[docs/repo-maturity-report.md](../repo-maturity-report.md) for the audit trail. 0 open
|
|
54
|
+
CodeQL alerts remain.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Release Integrity
|
|
2
|
+
|
|
3
|
+
How a release artifact can be verified, and what mechanism backs each guarantee. See
|
|
4
|
+
[docs/development/release-process.md](../development/release-process.md) for the full
|
|
5
|
+
release flow this is extracted from.
|
|
6
|
+
|
|
7
|
+
| Guarantee | Mechanism | Verify with |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| The tarball wasn't corrupted/tampered in transit | SHA-256 checksum generated in `release-assets` (`sha256sum "artifacts/${PACKAGE_FILE}" > ...sha256`) | `sha256sum -c ssh-mcp-pro-<version>.tgz.sha256` |
|
|
10
|
+
| The tarball was actually built by this repo's release workflow, from the commit it claims | `actions/attest-build-provenance` on the package | `gh attestation verify ssh-mcp-pro-<version>.tgz --owner oaslananka` |
|
|
11
|
+
| The SBOM matches the released package and wasn't tampered with | Separate checksum + separate `actions/attest-build-provenance` run with `sbom-path` set | `sha256sum -c sbom.cdx.json.sha256`, `gh attestation verify sbom.cdx.json --owner oaslananka` |
|
|
12
|
+
| What's actually inside the package (dependency inventory) | CycloneDX SBOM (`pnpm run sbom`) | Inspect `sbom.cdx.json` directly, or feed it to any CycloneDX-compatible scanner |
|
|
13
|
+
| npm package provenance (when published) | `npm publish --provenance` (conditional on `AUTO_RELEASE_PUBLISH` repo variable) | `npm view ssh-mcp-pro provenance`, or the "Provenance" panel on the npmjs.com package page |
|
|
14
|
+
| Container image integrity | Digest-pinned references, no mutable `latest` tag | See [docs/docker.md](../docker.md) |
|
|
15
|
+
|
|
16
|
+
## Current limitation
|
|
17
|
+
|
|
18
|
+
None of the above has been exercised against a real release yet — no release has been
|
|
19
|
+
published (see [docs/repo-maturity-report.md](../repo-maturity-report.md)). The
|
|
20
|
+
mechanisms are implemented and reviewed here on paper; they should be spot-checked
|
|
21
|
+
against the first actual release before being relied on operationally.
|
|
22
|
+
|
|
23
|
+
## What this does *not* claim
|
|
24
|
+
|
|
25
|
+
This project does not claim a specific SLSA build level. `actions/attest-build-provenance`
|
|
26
|
+
produces build provenance attestations (in-toto/SLSA-compatible statements), which is a
|
|
27
|
+
meaningfully strong signal, but claiming a specific SLSA level requires meeting that
|
|
28
|
+
level's full requirement set — not attempted here to avoid overclaiming.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Security scanning policy
|
|
2
|
+
|
|
3
|
+
This repository uses complementary scanners because no single tool covers source code,
|
|
4
|
+
dependencies, secrets, workflow configuration, and container images equally well.
|
|
5
|
+
|
|
6
|
+
## Required controls
|
|
7
|
+
|
|
8
|
+
| Surface | Primary control | Enforcement |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| TypeScript and workflows | CodeQL, Semgrep, and SonarQube Cloud | Required pull-request checks where configured |
|
|
11
|
+
| Dependency graph | `pnpm audit`, dependency review, Socket, and OSV verification | Moderate-or-higher audit findings fail the canonical quality gate unless a reviewed, expiring exception exists |
|
|
12
|
+
| Secrets | Gitleaks, SonarQube secrets, and Trivy filesystem scanning | New verified findings block merge |
|
|
13
|
+
| Container image | Trivy | Fixable High and Critical vulnerabilities fail the Docker workflow |
|
|
14
|
+
| Release artifacts | SBOM, package smoke tests, provenance, and registry metadata checks | Required before publishing |
|
|
15
|
+
|
|
16
|
+
## Container policy
|
|
17
|
+
|
|
18
|
+
The Docker workflow performs two scans against the image built from the pull-request or
|
|
19
|
+
release commit:
|
|
20
|
+
|
|
21
|
+
1. A SARIF scan reports all High and Critical findings to GitHub code scanning.
|
|
22
|
+
2. A separate enforcement scan fails on **fixable** High or Critical vulnerabilities.
|
|
23
|
+
|
|
24
|
+
`ignore-unfixed: true` is intentionally limited to the enforcement scan. Unfixed findings
|
|
25
|
+
remain visible in SARIF and must be reconsidered when a fix becomes available. The project
|
|
26
|
+
does not maintain wildcard ignores or an indefinite `.trivyignore` baseline. A temporary
|
|
27
|
+
exception must identify the advisory, explain the exposure, name an owner, and include an
|
|
28
|
+
expiry date in a reviewed repository file or issue.
|
|
29
|
+
|
|
30
|
+
Short-lived test-runner images, such as `Dockerfile.test`, are not required to define a
|
|
31
|
+
`HEALTHCHECK`; they do not run a service and exit when the test command completes.
|
|
32
|
+
|
|
33
|
+
## Local verification
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
osv-scanner scan source --recursive .
|
|
37
|
+
semgrep ci --dry-run
|
|
38
|
+
trivy fs --skip-dirs node_modules --scanners vuln,misconfig,secret .
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Container enforcement requires Docker access:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
docker build -t ssh-mcp-pro:local .
|
|
45
|
+
trivy image --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 ssh-mcp-pro:local
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Scanner output is evidence, not an automatic code-change mandate. Protocol-required
|
|
49
|
+
cryptography, bounded configuration regexes, and short-lived build images must be reviewed
|
|
50
|
+
in context rather than changed solely to silence a generic rule.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Secrets Management
|
|
2
|
+
|
|
3
|
+
Covers both how ssh-mcp-pro handles secrets at runtime, and how this repository's own
|
|
4
|
+
CI/CD handles secrets. No secrets, tokens, or credentials were added to the repository
|
|
5
|
+
by this audit — this document only records what already exists.
|
|
6
|
+
|
|
7
|
+
## Runtime (the deployed server)
|
|
8
|
+
|
|
9
|
+
- **Bearer tokens are read from a file** (`SSH_MCP_HTTP_BEARER_TOKEN_FILE`), not passed
|
|
10
|
+
directly as an environment variable value, reducing exposure via process listings and
|
|
11
|
+
environment dumps.
|
|
12
|
+
- **Bearer token comparison uses `timingSafeEqual`** (documented in
|
|
13
|
+
`SECURITY_DECISIONS.md`), avoiding timing side-channels.
|
|
14
|
+
- **Connector credential providers** (`SSH_MCP_CONNECTOR_CREDENTIAL_PROVIDER=command`)
|
|
15
|
+
resolve credentials via an external command rather than storing them in configuration,
|
|
16
|
+
and reject command output containing forbidden secret-shaped fields (see
|
|
17
|
+
`test/unit/connector-credentials.test.ts`).
|
|
18
|
+
- **Audit logging redacts sensitive fields** per `SECURITY_DECISIONS.md`, within a
|
|
19
|
+
bounded 500-event buffer.
|
|
20
|
+
- **Resolved (was: known open gap):** CodeQL alert #1 (High) flagged clear-text logging
|
|
21
|
+
of sensitive environment data in `scripts/start-chatgpt-http.mjs` — a genuine secrets
|
|
22
|
+
handling defect. Fixed 2026-07-03 by deriving the logged values from already-validated
|
|
23
|
+
enum checks instead of interpolating environment-sourced strings directly; see
|
|
24
|
+
[docs/repo-maturity-report.md](../repo-maturity-report.md) for the audit trail.
|
|
25
|
+
|
|
26
|
+
## CI/CD
|
|
27
|
+
|
|
28
|
+
- **No long-lived npm token.** The release workflow explicitly `unset`s
|
|
29
|
+
`NODE_AUTH_TOKEN`/`NPM_CONFIG_USERCONFIG` before publishing and relies on
|
|
30
|
+
`id-token: write` + `npm publish --provenance` — npm's OIDC trusted-publishing flow,
|
|
31
|
+
not a stored secret. See [docs/security/release-integrity.md](release-integrity.md).
|
|
32
|
+
- **No Docker registry password stored** — GHCR login uses `${{ github.token }}`
|
|
33
|
+
(the automatically-provisioned, workflow-scoped token), not a personal access token.
|
|
34
|
+
- **This audit's own `gitleaks.yml` addition uses `${{ secrets.GITHUB_TOKEN }}`** —
|
|
35
|
+
the same automatic token, required by `gitleaks-action` v3 to scan pull requests. No
|
|
36
|
+
new secret was created or requested.
|
|
37
|
+
- **GitHub secret scanning + push protection are enabled** at the repository level
|
|
38
|
+
(confirmed via API), catching accidental secret commits before they're even pushed.
|
|
39
|
+
- **`.env.example` exists** and should be the only `.env*`-shaped file ever committed;
|
|
40
|
+
`.gitignore` is expected to exclude real `.env` files (verify locally if adding new
|
|
41
|
+
env-derived tooling).
|
|
42
|
+
|
|
43
|
+
## If you're adding a new CI step that needs credentials
|
|
44
|
+
|
|
45
|
+
Before adding any token: check whether OIDC/trusted-publishing is available for the
|
|
46
|
+
target platform first (npm and PyPI both support it; GHCR uses the automatic
|
|
47
|
+
`GITHUB_TOKEN`). Long-lived tokens should be a last resort, not a default — see the
|
|
48
|
+
constraints this audit operated under in
|
|
49
|
+
[docs/repo-maturity-report.md](../repo-maturity-report.md).
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Threat Model
|
|
2
|
+
|
|
3
|
+
This document states the threat model implied by the defaults already documented in
|
|
4
|
+
[SECURITY_DECISIONS.md](../../SECURITY_DECISIONS.md) and the README's
|
|
5
|
+
[Security Defaults](../../README.md#security-defaults) section, gathered into one place.
|
|
6
|
+
It does not introduce new claims about the implementation beyond what those documents
|
|
7
|
+
already assert.
|
|
8
|
+
|
|
9
|
+
## What ssh-mcp-pro is
|
|
10
|
+
|
|
11
|
+
An MCP server that gives an LLM-driven client a curated set of tools for opening SSH
|
|
12
|
+
sessions and running commands, transferring files, managing services, and creating
|
|
13
|
+
tunnels against remote hosts, mediated by a policy layer.
|
|
14
|
+
|
|
15
|
+
## Primary actors
|
|
16
|
+
|
|
17
|
+
| Actor | Trust level | Notes |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| The MCP client (e.g. an LLM agent) | Partially trusted | Can issue any tool call the active [tool profile](../../README.md#tool-profiles) exposes; instructions reaching it may be ambiguous or, in the worst case, adversarial (prompt injection via tool output, a compromised upstream, etc.) |
|
|
20
|
+
| The operator/deployer | Trusted | Configures policy, environment variables, and which hosts are reachable |
|
|
21
|
+
| The remote SSH host | Partially trusted | Assumed to be a host the operator intends to manage, but output from it (command results, file contents) is untrusted data flowing back into the MCP session |
|
|
22
|
+
| A remote connector caller (HTTP transport) | Least trusted | Reaches the server over a network boundary; see the non-loopback HTTP restrictions below |
|
|
23
|
+
|
|
24
|
+
## What the defaults are actually defending against
|
|
25
|
+
|
|
26
|
+
1. **An LLM client instructed (by a user, a compromised prompt, or a malicious tool
|
|
27
|
+
response) to do something destructive.** This is why destructive commands and
|
|
28
|
+
filesystem operations (`fs_rmrf`, etc.) are denied by default
|
|
29
|
+
(`SSH_MCP_ALLOW_DESTRUCTIVE_COMMANDS`, `SSH_MCP_ALLOW_DESTRUCTIVE_FS`), and why root
|
|
30
|
+
login and raw `sudo` are denied by default.
|
|
31
|
+
2. **Host impersonation / MITM against a managed host.** This is why
|
|
32
|
+
`SSH_MCP_HOST_KEY_POLICY` defaults to `strict` against a known-hosts file rather than
|
|
33
|
+
trusting on first use.
|
|
34
|
+
3. **Accidental exposure of the server itself to the network.** This is why non-loopback
|
|
35
|
+
HTTP startup requires an explicit combination of bearer/OAuth auth, an allowed
|
|
36
|
+
origins list, a public HTTPS URL, strict host-key verification, a remote-safe tool
|
|
37
|
+
profile, and a host allowlist — the server refuses to start non-loopback without all
|
|
38
|
+
of these, rather than silently binding wide open.
|
|
39
|
+
4. **Overexposure to untrusted/broad connector audiences.** This is why tool profiles
|
|
40
|
+
(`remote-safe`, `chatgpt`, `claude`, `remote-readonly`, `remote-broker`) are
|
|
41
|
+
allowlists of a small tool subset, not the full `full` profile, for anything meant to
|
|
42
|
+
be reachable by a broader audience than a trusted local stdio client.
|
|
43
|
+
5. **Credential/secret leakage through logs or audit trails.** `SECURITY_DECISIONS.md`
|
|
44
|
+
documents audit redaction patterns and a bounded (500-event) audit buffer, and
|
|
45
|
+
constant-time (`timingSafeEqual`) comparison for bearer tokens.
|
|
46
|
+
|
|
47
|
+
## Resolved gap (was: known open gap)
|
|
48
|
+
|
|
49
|
+
CodeQL previously had 7 open alerts, including one High severity finding
|
|
50
|
+
(`js/clear-text-logging` in `scripts/start-chatgpt-http.mjs`) that was exactly the kind
|
|
51
|
+
of secret-leakage-through-logs risk this threat model calls out. All 8 were resolved
|
|
52
|
+
2026-07-03 (1 fixed in code, 7 dismissed with re-verified rationale) — see
|
|
53
|
+
[docs/repo-maturity-report.md](../repo-maturity-report.md) for the audit trail. Separately,
|
|
54
|
+
adding Trivy container-image scanning the same day surfaced 50+ new findings against the
|
|
55
|
+
built Docker image (mostly the base image's bundled tooling, not this project's own
|
|
56
|
+
code) — see "Package publishing maturity" in that same report. That backlog is
|
|
57
|
+
untriaged as of this update and is the current live example of "detection isn't the
|
|
58
|
+
same as resolution."
|
|
59
|
+
|
|
60
|
+
## Out of scope (matches SECURITY.md)
|
|
61
|
+
|
|
62
|
+
- Vulnerabilities in dependencies that aren't reachable through this project's own
|
|
63
|
+
attack surface.
|
|
64
|
+
- Findings that require the operator to have already disabled a secure default.
|
|
65
|
+
- Denial-of-service against a fully trusted local development environment.
|
package/docs/testing.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Testing
|
|
2
2
|
|
|
3
|
+
## HTTP boundary testing
|
|
4
|
+
|
|
5
|
+
`test/integration/http-server-boundary.integration.test.ts` starts the real HTTP
|
|
6
|
+
MCP runtime in-process on an ephemeral loopback port. It uses temporary bearer
|
|
7
|
+
files, an injected clock, and deterministic remote-control-plane doubles; it
|
|
8
|
+
does not require external OAuth, JWKS, SSH, or public-network services.
|
|
9
|
+
|
|
10
|
+
The suite exercises the production request boundary rather than only helper
|
|
11
|
+
functions. Coverage includes bearer and OAuth challenges, origin and CORS
|
|
12
|
+
handling, request-size limits, rate-limit headers, protected-resource metadata,
|
|
13
|
+
MCP session initialization, capacity eviction, idle expiry, legacy SSE,
|
|
14
|
+
remote HTTP and WebSocket delegation, startup refusal, and idempotent shutdown.
|
|
15
|
+
`test/unit/http-server-lifecycle.test.ts` separately locks lifecycle concurrency,
|
|
16
|
+
bind failures, signal cleanup, and one-shot close behavior.
|
|
17
|
+
|
|
18
|
+
Run the boundary suite with:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm run test:integration -- test/integration/http-server-boundary.integration.test.ts
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The HTTP runtime is included in the normal coverage denominator. Do not replace
|
|
25
|
+
these tests with a coverage exclusion when adding routes or lifecycle branches.
|
|
26
|
+
|
|
3
27
|
## Mutation testing
|
|
4
28
|
|
|
5
29
|
Mutation testing is configured for policy-critical security surfaces only. The
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Common failure modes and where to look. For option-by-option config, see
|
|
4
|
+
[docs/reference/configuration.md](reference/configuration.md).
|
|
5
|
+
|
|
6
|
+
## The server starts but no tools show up in my MCP client
|
|
7
|
+
|
|
8
|
+
Check `SSH_MCP_TOOL_PROFILE` (or `--tool-profile`). Every profile except `full` is an
|
|
9
|
+
allowlist — see [Tool Profiles](../README.md#tool-profiles). If you expected the full
|
|
10
|
+
tool set and see only a handful, you're likely on `remote-safe` or another restricted
|
|
11
|
+
profile.
|
|
12
|
+
|
|
13
|
+
## `EHOSTKEY` / host key verification failures
|
|
14
|
+
|
|
15
|
+
This is `SSH_MCP_HOST_KEY_POLICY=strict` (the default) working as intended: the host
|
|
16
|
+
isn't in `SSH_MCP_KNOWN_HOSTS_PATH` yet, or its key changed. Add the host's key to your
|
|
17
|
+
known_hosts file first (e.g. `ssh-keyscan` then verify out-of-band), or see
|
|
18
|
+
[docs/how-to/configure-ssh-policy.md](how-to/configure-ssh-policy.md) for
|
|
19
|
+
lab-environment alternatives. Do not switch to `insecure` against a host you don't fully
|
|
20
|
+
trust.
|
|
21
|
+
|
|
22
|
+
## A tool call is denied by policy
|
|
23
|
+
|
|
24
|
+
Run `ssh_policy_explain` (or ask your MCP client to "explain the active SSH policy")
|
|
25
|
+
before assuming something is broken — most denials are the deny-by-default security
|
|
26
|
+
posture described in [SECURITY_DECISIONS.md](../SECURITY_DECISIONS.md), not a bug. See
|
|
27
|
+
[docs/how-to/configure-ssh-policy.md](how-to/configure-ssh-policy.md) to loosen a
|
|
28
|
+
specific restriction deliberately.
|
|
29
|
+
|
|
30
|
+
## Non-loopback HTTP transport won't start
|
|
31
|
+
|
|
32
|
+
By design — see [Security Defaults](../README.md#security-defaults). Non-loopback
|
|
33
|
+
startup requires bearer/OAuth auth, an allowed origins list, a public HTTPS URL, strict
|
|
34
|
+
host-key verification, a remote-safe tool profile, and a host allowlist, all configured
|
|
35
|
+
together. Check the startup error message; it names which of these is missing.
|
|
36
|
+
|
|
37
|
+
## Debugging a session
|
|
38
|
+
|
|
39
|
+
Set `SSH_MCP_DEBUG=true` for more verbose configuration-time diagnostics. For
|
|
40
|
+
request/response-level detail, check whether OpenTelemetry export is configured (see the
|
|
41
|
+
`@opentelemetry/*` dependencies and the telemetry-related environment variables) — this
|
|
42
|
+
project ships OTLP trace export support, not just console logging.
|
|
43
|
+
|
|
44
|
+
## Windows-specific SSH integration issues
|
|
45
|
+
|
|
46
|
+
There's a dedicated Windows SSH integration test project
|
|
47
|
+
(`pnpm run test:integration:windows`) — if something works on Linux but not Windows,
|
|
48
|
+
check that test file first; it's the closest thing to a regression harness for
|
|
49
|
+
Windows-specific SSH behavior.
|
|
50
|
+
|
|
51
|
+
## Filing a bug
|
|
52
|
+
|
|
53
|
+
If none of the above resolves it, open an issue using the bug report template — see
|
|
54
|
+
[SUPPORT.md](../SUPPORT.md) for response expectations. Include the output of
|
|
55
|
+
`ssh_policy_explain` and the exact `SSH_MCP_*` environment variables you've set
|
|
56
|
+
(redacting any secrets).
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Tutorial: Getting Started
|
|
2
|
+
|
|
3
|
+
This is a learning-oriented walkthrough: follow it top to bottom and you'll end with a
|
|
4
|
+
working local ssh-mcp-pro connected to an MCP client and one successful remote command.
|
|
5
|
+
Per [Diátaxis](https://diataxis.fr/tutorials/), it favors one guaranteed-to-work path
|
|
6
|
+
over covering every option — see [How-to guides](../how-to/README.md) for other tasks
|
|
7
|
+
and [Reference](../reference/README.md) for the full option set.
|
|
8
|
+
|
|
9
|
+
## 1. Prerequisites
|
|
10
|
+
|
|
11
|
+
You need:
|
|
12
|
+
|
|
13
|
+
- Node.js `>=22.22.2` (or `>=24.15.0` / `>=26.3.0`) and pnpm `>=11.0.9`.
|
|
14
|
+
- At least one host you can already reach with plain `ssh`, with its key already in
|
|
15
|
+
your `~/.ssh/known_hosts` (this tutorial uses the default `strict` host-key policy —
|
|
16
|
+
see [SECURITY_DECISIONS.md](../../SECURITY_DECISIONS.md) for why).
|
|
17
|
+
|
|
18
|
+
## 2. Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add --global ssh-mcp-pro
|
|
22
|
+
ssh-mcp-pro --version
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If that prints a version number, installation worked.
|
|
26
|
+
|
|
27
|
+
## 3. Register it with an MCP client
|
|
28
|
+
|
|
29
|
+
Pick the block matching your client and add it to that client's MCP config (see
|
|
30
|
+
[INSTALL.md](../../INSTALL.md) for exact file locations per client):
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"ssh-mcp-pro": {
|
|
36
|
+
"command": "ssh-mcp-pro",
|
|
37
|
+
"args": []
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Restart or reload your MCP client so it picks up the new server.
|
|
44
|
+
|
|
45
|
+
## 4. Confirm the server is visible
|
|
46
|
+
|
|
47
|
+
In your MCP client, ask it to list available tools, or run:
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
List configured SSH hosts.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
You should see a response describing zero or more configured hosts — an empty list is
|
|
54
|
+
expected if you haven't pointed `ssh-mcp-pro` at any host config yet; it means the
|
|
55
|
+
server started and responded, which is the thing this step is actually checking.
|
|
56
|
+
|
|
57
|
+
## 5. Inspect the active policy
|
|
58
|
+
|
|
59
|
+
Before running anything against a real host, see what's allowed:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
Explain the active SSH policy.
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This reflects the deny-by-default settings described in the
|
|
66
|
+
[Security Defaults](../../README.md#security-defaults) section of the README: strict
|
|
67
|
+
host-key checking, no root login, no raw `sudo`, no destructive operations.
|
|
68
|
+
|
|
69
|
+
## 6. Connect to a host and run a safe, read-only command
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
Connect to <your-host> as <your-user> with hostKeyPolicy=strict, then run os_detect.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
If this succeeds, you have a working end-to-end setup: MCP client → ssh-mcp-pro →
|
|
76
|
+
your host.
|
|
77
|
+
|
|
78
|
+
## Next steps
|
|
79
|
+
|
|
80
|
+
- [How to configure the SSH policy](../how-to/configure-ssh-policy.md) if you need to
|
|
81
|
+
change any default.
|
|
82
|
+
- [examples/README.md](../../examples/README.md) for more workflow examples.
|
|
83
|
+
- [docs/explanation/architecture.md](../explanation/architecture.md) to understand why
|
|
84
|
+
the server is structured the way it is.
|
package/mcp.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "ssh-mcp-pro",
|
|
3
3
|
"display_name": "ssh-mcp-pro",
|
|
4
4
|
"description": "Secure MCP SSH automation server with policy controls, resources, prompts, stdio, and HTTP.",
|
|
5
|
-
"version": "1.1
|
|
5
|
+
"version": "1.2.1",
|
|
6
6
|
"author": "Osman Aslan",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"runtime": "node",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ssh-mcp-pro",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"mcpName": "io.github.oaslananka/ssh-mcp-pro",
|
|
5
5
|
"description": "Model Context Protocol (MCP) SSH client server for remote automation",
|
|
6
6
|
"type": "module",
|
|
@@ -58,17 +58,18 @@
|
|
|
58
58
|
},
|
|
59
59
|
"engines": {
|
|
60
60
|
"node": ">=22.22.2",
|
|
61
|
-
"pnpm": "^11.5
|
|
61
|
+
"pnpm": "^11.28.5"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
64
|
+
"@modelcontextprotocol/sdk": "^1.32.0",
|
|
65
65
|
"@opentelemetry/api": "^1.9.1",
|
|
66
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.
|
|
67
|
-
"@opentelemetry/resources": "^2.
|
|
68
|
-
"@opentelemetry/sdk-node": "^0.
|
|
69
|
-
"@opentelemetry/semantic-conventions": "^1.
|
|
66
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.222.0",
|
|
67
|
+
"@opentelemetry/resources": "^2.11.0",
|
|
68
|
+
"@opentelemetry/sdk-node": "^0.222.0",
|
|
69
|
+
"@opentelemetry/semantic-conventions": "^1.43.0",
|
|
70
70
|
"jose": "6.2.3",
|
|
71
71
|
"node-ssh": "^13.2.1",
|
|
72
|
+
"ws": "^8.21.1",
|
|
72
73
|
"zod": "^4.4.3"
|
|
73
74
|
},
|
|
74
75
|
"devDependencies": {
|
|
@@ -76,21 +77,33 @@
|
|
|
76
77
|
"@stryker-mutator/typescript-checker": "9.6.1",
|
|
77
78
|
"@stryker-mutator/vitest-runner": "9.6.1",
|
|
78
79
|
"@types/node": "^24.13.1",
|
|
79
|
-
"@types/ssh2": "^1.15.
|
|
80
|
-
"@
|
|
81
|
-
"@typescript-eslint/
|
|
82
|
-
"@
|
|
80
|
+
"@types/ssh2": "^1.15.6",
|
|
81
|
+
"@types/ws": "^8.18.2",
|
|
82
|
+
"@typescript-eslint/eslint-plugin": "^8.71.0",
|
|
83
|
+
"@typescript-eslint/parser": "^8.71.0",
|
|
84
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
83
85
|
"ajv": "^8.20.0",
|
|
84
86
|
"autocannon": "^7.15.0",
|
|
85
87
|
"dependency-cruiser": "^17.4.3",
|
|
86
|
-
"eslint": "^10.
|
|
87
|
-
"fast-check": "^4.
|
|
88
|
-
"knip": "^6.
|
|
89
|
-
"prettier": "^3.
|
|
90
|
-
"
|
|
88
|
+
"eslint": "^10.12.0",
|
|
89
|
+
"fast-check": "^4.10.2",
|
|
90
|
+
"knip": "^6.39.0",
|
|
91
|
+
"prettier": "^3.9.9",
|
|
92
|
+
"publint": "^0.3.25",
|
|
93
|
+
"typedoc": "0.28.20",
|
|
91
94
|
"typescript": "^6.0.3",
|
|
92
95
|
"vite": "^7.3.5",
|
|
93
|
-
"vitest": "^4.1.
|
|
96
|
+
"vitest": "^4.1.11"
|
|
97
|
+
},
|
|
98
|
+
"overrides": {
|
|
99
|
+
"brace-expansion": "^5.0.12",
|
|
100
|
+
"fast-uri": "^3.1.8",
|
|
101
|
+
"ip-address": "^10.7.1",
|
|
102
|
+
"nanoid": "^3.3.18",
|
|
103
|
+
"browserslist": "^4.28.7",
|
|
104
|
+
"@hono/node-server": "^2.0.5",
|
|
105
|
+
"markdown-it": "^14.3.2",
|
|
106
|
+
"vitest": "^4.1.11"
|
|
94
107
|
},
|
|
95
108
|
"scripts": {
|
|
96
109
|
"build": "tsc -p tsconfig.json",
|
|
@@ -112,12 +125,16 @@
|
|
|
112
125
|
"format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\" \"scripts/**/*.{mjs,cjs}\" \"docs/**/*.md\" \".github/workflows/*.{yml,yaml}\" \"stryker.conf.mjs\" \"vitest.config.ts\" \"vitest.mutation.config.ts\"",
|
|
113
126
|
"format:staged": "node scripts/run-staged-checks.mjs",
|
|
114
127
|
"docker:ssh-fixture:up": "node scripts/docker-ssh-fixture.mjs up",
|
|
128
|
+
"docker:ssh-fixture:verify": "node scripts/docker-ssh-fixture.mjs verify",
|
|
129
|
+
"docker:ssh-fixture:diagnostics": "node scripts/docker-ssh-fixture.mjs diagnostics",
|
|
115
130
|
"docker:ssh-fixture:down": "node scripts/docker-ssh-fixture.mjs down",
|
|
131
|
+
"check:fixture-results": "node scripts/check-fixture-test-results.mjs",
|
|
116
132
|
"e2e:docker": "node scripts/docker-ssh-fixture.mjs run e2e",
|
|
117
133
|
"integration:docker": "node scripts/docker-ssh-fixture.mjs run integration",
|
|
118
134
|
"docs": "pnpm exec typedoc --options typedoc.json",
|
|
119
135
|
"docs:check": "pnpm exec typedoc --options typedoc.json --treatWarningsAsErrors",
|
|
120
136
|
"start:http": "node dist/render-http.js",
|
|
137
|
+
"start:chatgpt": "node scripts/start-chatgpt-http.mjs",
|
|
121
138
|
"sync-version": "node scripts/sync-version.mjs",
|
|
122
139
|
"validate:mcp-metadata": "node scripts/validate-mcp-metadata.mjs",
|
|
123
140
|
"validate:mcp-registry": "node scripts/check-mcp-registry-record.mjs",
|
|
@@ -136,16 +153,18 @@
|
|
|
136
153
|
"release:state": "node scripts/release-state.mjs",
|
|
137
154
|
"check:npm-name": "node scripts/check-npm-name.mjs ssh-mcp-pro",
|
|
138
155
|
"audit": "pnpm audit --audit-level moderate",
|
|
156
|
+
"audit:packed": "node scripts/check-packed-consumer-audit.mjs",
|
|
139
157
|
"licenses:check": "node scripts/check-licenses.mjs",
|
|
140
158
|
"reuse:lint": "reuse lint",
|
|
141
159
|
"pack:check": "node scripts/check-package-contents.mjs",
|
|
142
160
|
"pack:install-smoke": "node scripts/check-package-install-smoke.mjs",
|
|
161
|
+
"pack:lint": "publint --strict=false",
|
|
143
162
|
"check:knip": "knip -c knip.jsonc --reporter compact || true",
|
|
144
163
|
"check:circular": "depcruise src --config .dependency-cruiser.mjs || true",
|
|
145
164
|
"check:module-size": "node scripts/check-module-size.mjs",
|
|
146
165
|
"check:maintainability": "pnpm run check:module-size && pnpm run check:circular && pnpm run check:knip",
|
|
147
166
|
"check:quality": "pnpm run format:check && pnpm run check:doc-language && pnpm run check:package-scripts && pnpm run check:rulesets && pnpm run verify:actions-runtime && pnpm run lint && pnpm run typecheck && pnpm run audit && pnpm run licenses:check",
|
|
148
|
-
"check:package": "pnpm run build && pnpm run sync-version -- --check && pnpm run validate:mcp-metadata && pnpm run validate:chatgpt-app && pnpm run validate:claude-connector && pnpm run docs:check && pnpm run pack:check && pnpm run pack:install-smoke",
|
|
167
|
+
"check:package": "pnpm run build && pnpm run sync-version -- --check && pnpm run validate:mcp-metadata && pnpm run validate:chatgpt-app && pnpm run validate:claude-connector && pnpm run docs:check && pnpm run pack:check && pnpm run pack:install-smoke && pnpm run audit:packed",
|
|
149
168
|
"check:push": "pnpm run format:check && pnpm run lint && pnpm run typecheck && pnpm test",
|
|
150
169
|
"check": "pnpm run check:quality && pnpm run test:coverage && pnpm run check:package",
|
|
151
170
|
"hook:pre-commit": "pnpm run format:staged",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "ssh-mcp-pro",
|
|
3
3
|
"display_name": "ssh-mcp-pro",
|
|
4
4
|
"description": "Secure MCP SSH automation server with policy controls, resources, prompts, stdio, and HTTP.",
|
|
5
|
-
"version": "1.1
|
|
5
|
+
"version": "1.2.1",
|
|
6
6
|
"author": "Osman Aslan",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"runtime": "node",
|
package/server.json
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
"url": "https://github.com/oaslananka/ssh-mcp-pro",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "1.1
|
|
10
|
+
"version": "1.2.1",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
15
15
|
"identifier": "ssh-mcp-pro",
|
|
16
|
-
"version": "1.1
|
|
16
|
+
"version": "1.2.1",
|
|
17
17
|
"transport": {
|
|
18
18
|
"type": "stdio"
|
|
19
19
|
}
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"registryType": "npm",
|
|
23
23
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
24
24
|
"identifier": "ssh-mcp-pro",
|
|
25
|
-
"version": "1.1
|
|
25
|
+
"version": "1.2.1",
|
|
26
26
|
"runtimeHint": "npx",
|
|
27
27
|
"transport": {
|
|
28
28
|
"type": "streamable-http",
|