diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..17f96ce --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +# Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile +FROM registry.fly.io/sidecar:deployment-01JQZ4GJ1RN49TFQ5X8921CTMR as sidecar_image + +# User's Dockerfile +FROM node:lts-alpine + +# Create app directory +WORKDIR /usr/src/app + +# Copy dependencies and source +COPY package.json package-lock.json tsconfig.json ./ +COPY src ./src + +# Install app dependencies +RUN npm ci --ignore-scripts + +# Build project +RUN npm run build +# End user Dockerfile + +COPY --from=sidecar_image /app/gateway-app-glibc /tmp/smithery-gateway-glibc +COPY --from=sidecar_image /app/gateway-app-musl /tmp/smithery-gateway-musl + +USER root + +# Install required dependencies for Alpine +RUN /bin/sh -c 'set -eux && if grep -q "Alpine" /etc/os-release 2>/dev/null; then echo "Alpine Linux detected, installing required libraries" && apk add --no-cache libstdc++ libgcc && echo "musl" > /tmp/os-family; exit 0; fi' + +# Fallback detection script if not Alpine +RUN /bin/sh -c 'set -eux && if [ -f /tmp/os-family ]; then echo "OS family already detected, skipping detection"; exit 0; fi && if [ ! -x /bin/sh ] && [ ! -x /usr/bin/env ]; then echo "ERROR: No shell found in the user image. Can not detect OS family." >&2 && exit 1; fi && shell_to_check="/bin/sh" && if [ ! -x "$shell_to_check" ]; then shell_to_check="/usr/bin/env"; fi && if ! command -v ldd >/dev/null 2>&1; then echo "ERROR: ldd not found in the user image. Can not detect OS family." >&2 && exit 1; fi && if ldd "$shell_to_check" 2>&1 | grep -qi musl; then echo "musl detected" && echo "musl" > /tmp/os-family; else echo "glibc detected" && echo "glibc" > /tmp/os-family; fi' + +# Pick the correct binary based on /tmp/os-family +RUN /bin/sh -c 'set -eux && os_family="$(cat /tmp/os-family)" && case "$os_family" in musl) mv /tmp/smithery-gateway-musl /usr/local/bin/smithery-gateway ;; glibc) mv /tmp/smithery-gateway-glibc /usr/local/bin/smithery-gateway ;; *) echo "Unknown OS family: $os_family" >&2 && exit 1 ;; esac && chmod +x /usr/local/bin/smithery-gateway && rm -f /tmp/smithery-gateway-*' + +# Expose port for gateway +EXPOSE 8080 + +# Use Smithery Gateway as the entrypoint +ENTRYPOINT ["/usr/local/bin/smithery-gateway"] +CMD ["--port", "8080", "--configb64", "${CONFIG_BASE64}"] diff --git a/README.md b/README.md index 32aab3e..419f3bd 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Shell MCP Server +[![smithery badge](https://smithery.ai/badge/@hdresearch/mcp-shell)](https://smithery.ai/server/@hdresearch/mcp-shell) + A Node.js implementation of the Model Context Protocol (MCP) that provides secure shell command execution capabilities. This server allows AI models to execute shell commands in a controlled environment with built-in security measures. Easily integrates with [Claude Desktop](https://claude.ai/download) for connecting Claude with your shell. ## Features @@ -12,6 +14,15 @@ A Node.js implementation of the Model Context Protocol (MCP) that provides secur ## Installation +### Installing via Smithery + +To install Shell MCP Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@hdresearch/mcp-shell): + +```bash +npx -y @smithery/cli install @hdresearch/mcp-shell --client claude +``` + +### Manual Installation Run `npx mcp-shell`. To add it to Claude Desktop, run `npx mcp-shell config`. Or add `npx -y mcp-shell` to your config manually. diff --git a/smithery.yaml b/smithery.yaml new file mode 100644 index 0000000..043baad --- /dev/null +++ b/smithery.yaml @@ -0,0 +1,13 @@ +# Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml + +startCommand: + type: stdio + configSchema: + # JSON Schema defining the configuration options for the MCP. + type: object + description: No configuration required + commandFunction: + # A JS function that produces the CLI command based on the given config to start the MCP on stdio. + |- + (config) => ({command: 'node', args: ['build/index.js']}) + exampleConfig: {}