Skip to main content
Glama
kunwarmahen

SSH Read-Only MCP Server

by kunwarmahen

SSH Read-Only MCP Server

A secure Model Context Protocol (MCP) server that enables remote SSH command execution with strict read-only enforcement. Perfect for safely delegating SSH access to Claude while preventing accidental or malicious write operations.

Features

Read-Only Command Enforcement – Only allows safe, read-only commands
SSH Connection Pooling – Support multiple simultaneous connections
Command Validation – Blocks dangerous patterns and write operations
Multicast Discovery – Auto-announces on network for easy discovery
Flexible Transport – Stdio, HTTP, or Streamable-HTTP modes
Comprehensive Logging – Full audit trail in ssh_mcp.log
Environment Configuration – Fully configurable via .env

Related MCP server: SSH Remote MCP Server

Installation

Prerequisites

  • Python 3.8+

  • uv package manager

Setup

# Clone or create project directory
mkdir ssh-mcp-server
cd ssh-mcp-server

# Initialize uv project (if needed)
uv init

# Install dependencies
uv pip install fastmcp paramiko python-dotenv

Or use pyproject.toml:

[project]
name = "ssh-mcp-server"
version = "0.1.0"
dependencies = [
    "fastmcp>=0.1.0",
    "paramiko>=3.0.0",
    "python-dotenv>=1.0.0",
]

Then install:

uv sync

Configuration

Create a .env file in the project root:

# Transport mode: stdio (default), http, or streamable-http
MCP_TRANSPORT=stdio

# Server identification
MCP_SERVER_NAME=SSH Read-Only MCP Server

# HTTP mode settings (if using http/streamable-http)
MCP_HOST=0.0.0.0
MCP_PORT=3000

# Multicast discovery
MCP_ENABLE_BROADCAST=true
MCP_BROADCAST_INTERVAL=30

Environment Variables

Variable

Default

Description

MCP_TRANSPORT

stdio

Communication transport: stdio, http, or streamable-http

MCP_SERVER_NAME

SSH Read-Only MCP Server

Display name for the server

MCP_HOST

0.0.0.0

Bind address for HTTP mode

MCP_PORT

3000

Port for HTTP mode

MCP_ENABLE_BROADCAST

true

Enable multicast discovery announcements

MCP_BROADCAST_INTERVAL

30

Seconds between broadcast announcements

Usage

Start the Server

Stdio mode (default):

uv run ssh_readonly_fastmcp_mcast.py

HTTP mode with multicast discovery:

MCP_TRANSPORT=http MCP_PORT=3000 uv run ssh_readonly_fastmcp_mcast.py

HTTP mode without broadcasting:

MCP_ENABLE_BROADCAST=false MCP_TRANSPORT=http MCP_PORT=3000 uv run ssh_readonly_fastmcp_mcast.py

Available Tools

1. ssh_connect

Establish an SSH connection to a remote machine.

Parameters:

  • host (required) – Remote host IP or hostname

  • username (required) – SSH username

  • port (optional, default: 22) – SSH port

  • key_filename (optional) – Path to private key file (recommended)

  • password (optional) – SSH password (fallback)

Example:

Connect to 192.168.1.100 as user 'admin' with private key
host: 192.168.1.100
username: admin
key_filename: /home/user/.ssh/id_rsa

2. ssh_execute

Execute a read-only command on the connected remote machine.

Parameters:

  • host (required) – Remote host (must be connected first)

  • username (required) – SSH username

  • command (required) – Read-only command to execute

  • port (optional, default: 22) – SSH port

Example:

Run 'ls -la /home' on connected server
host: 192.168.1.100
username: admin
command: ls -la /home

3. ssh_disconnect

Close an SSH connection.

Parameters:

  • host (required) – Remote host

  • username (required) – SSH username

  • port (optional, default: 22) – SSH port

4. ssh_list_connections

View all active SSH connections.

Parameters: None

5. ssh_get_allowed_commands

Retrieve the list of allowed read-only commands.

Parameters: None

Allowed Commands

The server permits the following read-only operations:

  • File operations: cat, ls, file, head, tail, find, locate

  • System info: ps, top, df, du, free, uname, hostname, uptime

  • Network: netstat, ss, ifconfig, ip, curl, wget, dig, nslookup, ping, traceroute

  • Process management: lsof, systemctl, service

  • Text processing: grep, awk, sed, wc

  • And many more read-only utilities

Blocked operations: rm, mv, cp, chmod, chown, mkdir, touch, kill, shutdown, reboot, sudo, and any write/modify commands.

Multicast Discovery

When running in HTTP mode with broadcasting enabled, the server announces itself on the multicast group:

  • Address: 239.255.255.250

  • Port: 5353

  • Interval: Configurable (default: 30 seconds)

Discovery announcement includes:

  • Server UUID

  • Server name

  • Local IP and port

  • Transport type

  • Protocol version

Logging

All activity is logged to ssh_mcp.log:

2025-10-17 10:30:45,123 [INFO] ssh_mcp - Starting MCP server with transport=http
2025-10-17 10:30:46,456 [INFO] ssh_mcp - Starting multicast broadcaster on 239.255.255.250:5353
2025-10-17 10:30:47,789 [INFO] ssh_mcp - Successfully connected to admin@192.168.1.100:22

Security Considerations

🔒 Read-Only Enforcement:

  • Only whitelisted commands are allowed

  • Dangerous patterns (pipes, redirects, subshells) are blocked

  • Write operations are prevented at the command level

⏱️ Timeouts:

  • 30-second execution timeout per command

  • Prevents hanging commands from blocking the server

🔐 Authentication:

  • SSH key authentication recommended over passwords

  • Passwords stored in memory only, never persisted

📋 Audit Trail:

  • All connections and commands are logged

  • Review ssh_mcp.log for security audits

Troubleshooting

Connection Refused

Error: Connection failed: [Errno 111] Connection refused
  • Verify the remote host is reachable: ping <host>

  • Check SSH is running on the remote machine

  • Verify port number (default 22)

Authentication Failed

Error: Connection failed: Authentication failed
  • Verify username is correct

  • For key auth: check key file path and permissions (chmod 600)

  • For password auth: verify credentials

  • Ensure SSH public key is authorized on remote (~/.ssh/authorized_keys)

Command Not Allowed

Error: Command not allowed for security reasons
  • The command contains a blocked pattern or is not in the allowed list

  • Use ssh_get_allowed_commands to see permitted commands

  • For write operations, use SSH directly instead

Broadcast Not Working

  • Verify MCP_ENABLE_BROADCAST=true

  • Check network supports multicast (most corporate networks block it)

  • Verify firewall allows UDP on port 5353

  • Check ssh_mcp.log for broadcast errors

Development

Running in Debug Mode

DEBUG=true uv run ssh_readonly_fastmcp_mcast.py

Testing

# Test connection
uv run -c "from ssh_readonly_fastmcp_mcast import is_command_safe; print(is_command_safe('ls -la'))"

# Should print: True

# Test blocked command
uv run -c "from ssh_readonly_fastmcp_mcast import is_command_safe; print(is_command_safe('rm -rf /'))"

# Should print: False

Project Structure

ssh-mcp-server/
├── ssh_readonly_fastmcp_mcast.py    # Main server implementation
├── .env                        # Configuration file
├── .env.example               # Configuration template
├── ssh_mcp.log                # Server logs (auto-generated)
├── pyproject.toml             # Project metadata
└── README.md                  # This file

API Response Format

All tools return consistent JSON responses:

Success:

{
  "status": "success",
  "host": "192.168.1.100",
  "command": "ls -la /home",
  "exit_code": 0,
  "output": "total 24\ndrwxr-xr-x 3 root root 4096...",
  "error": null
}

Error:

{
  "status": "error",
  "message": "Command not allowed for security reasons",
  "reason": "Only read-only commands are permitted"
}

License

MIT

Contributing

Contributions welcome! Please ensure:

  • All changes maintain read-only enforcement

  • Code is logged appropriately

  • Tests pass for security validations

Support

For issues or questions:

  1. Check ssh_mcp.log for error details

  2. Review the Troubleshooting section

  3. Verify environment configuration

  4. Check network connectivity to remote hosts

Available Tools

5 tools
ssh_connectA

Establish SSH connection to a remote machine (read-only access only).

ParametersJSON Schema
NameRequiredDescriptionDefault
hostYesRemote host IP address or hostname
usernameYesSSH username
portNoSSH port (default: 22)
key_filenameNoPath to private key file (recommended)
passwordNoSSH password (fallback if no key)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden. It adds the behavioral trait 'read-only access only', but lacks detail on failure modes, authentication behavior, or state changes. This is a minimal addition beyond the parameter schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, front-loaded sentence of 11 words. Every word is informative, no redundancy. Perfectly concise for a simple connection tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has 5 parameters, no annotations, and an output schema (not shown), the description is adequate but sparse. It covers the basic action and access level but omits details like connection lifecycle or output structure. Sufficient for simple scenarios.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description does not add any parameter-specific meaning beyond what the schema already provides, maintaining the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: establishing an SSH connection to a remote machine. It also notes 'read-only access only', which distinguishes it from ssh_execute (for executing commands) and other siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage ('establish SSH connection') but does not explicitly compare to alternatives like ssh_execute or provide when-not-to-use guidance. No direct mention of prerequisites or context for selection among siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_disconnectC

Disconnect from the remote machine.

ParametersJSON Schema
NameRequiredDescriptionDefault
hostYesRemote host
usernameYesSSH username
portNoSSH port (default: 22)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

C2.8/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, and the description doesn't disclose side effects (e.g., closing a terminal session), error conditions, or security implications. The behavioral burden is not met.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Very concise (one sentence) but lacks essential context. Could be improved by front-loading usage context without being verbose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Does not mention output schema return value, error scenarios, or how the host/username map to an existing connection. Incomplete given the presence of an output schema and sibling tools.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so parameters are already explained. Description adds no additional meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the action (disconnect) and target (remote machine), distinguishing from siblings like ssh_connect. However, it doesn't specify which connection is being disconnected (e.g., by host/username).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool vs alternatives. Does not mention prerequisites (e.g., active connection) or when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_executeA

Execute a read-only command on the connected remote machine.

ParametersJSON Schema
NameRequiredDescriptionDefault
hostYesRemote host (must be connected first)
usernameYesSSH username
commandYesThe read-only command to execute (e.g., 'ls -la', 'cat /etc/hostname')
portNoSSH port (default: 22)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It correctly marks the tool as read-only, which is a critical behavioral trait. However, it does not disclose other traits like authentication requirements or error handling, but the read-only aspect is well conveyed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence, no wasted words, front-loads the purpose. Excellent conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only command execution tool, the description covers purpose and safety. The output schema likely handles return values, so no further explanation needed. Complete given the complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description does not add any additional meaning beyond the schema's parameter descriptions. No extra semantics provided.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states 'Execute a read-only command on the connected remote machine,' specifying the verb (execute), resource (command on remote machine), and a distinguishing trait (read-only). This differentiates from sibling tools like ssh_connect and ssh_disconnect.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says 'read-only command,' guiding the agent to use this tool for read operations. While it doesn't name alternatives, the context of sibling tools and the schema's command description imply when to use versus write operations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_get_allowed_commandsA

Get the list of allowed read-only commands.

Returns: List of allowed commands

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must disclose behavioral traits. It only mentions 'read-only,' implying non-destructiveness, but lacks details like whether a connection is required or if results are cached.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is short with two sentences, but the second sentence ('Returns: List of allowed commands') is redundant. The key information is front-loaded in the first sentence.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no parameters and an output schema, the description is fairly complete. However, it lacks context about prerequisites (e.g., whether an SSH session must exist) and does not describe the output format beyond 'list.'

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters, so no explanation is needed. The description adds value by specifying the return type ('list of allowed commands'), which is clear and sufficient.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Get' and the resource 'list of allowed read-only commands,' which distinguishes it from sibling tools like ssh_connect, ssh_execute, etc.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives (e.g., before executing commands to check allowed commands). The description only states what it does, not when it's appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_list_connectionsA

List all active SSH connections.

Returns: List of active connections

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description only states 'List all active SSH connections', lacking detail on permissions, side effects, or performance.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short, direct sentences with no extraneous information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless tool with an output schema, the description is sufficient but minimal; it could optionally mention output details.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

No parameters exist; per guidelines, baseline is 4. Description adds nothing about parameters because there are none.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'List' and the resource 'active SSH connections', distinguishing it from siblings like ssh_connect or ssh_disconnect.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use or alternatives, but the simple name and context imply its use for listing active connections.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

TDQS

A3.8/5.0
Disambiguation5/5

Each tool has a distinct purpose: connecting, disconnecting, executing commands, listing allowed commands, and listing connections. No overlap, clear differentiation.

Naming Consistency5/5

All tools follow the ssh_verb_noun pattern consistently, with verbs like connect, disconnect, execute, get_allowed_commands, and list_connections. Minor variation between get and list is acceptable as both are retrieval verbs.

Tool Count5/5

5 tools is well-scoped for a read-only SSH server. Each tool covers a necessary operation without redundancy or missing essentials.

Completeness5/5

The tool surface covers the full lifecycle of a read-only SSH session: connect, execute (read-only commands), disconnect, and utilities like listing allowed commands and connections. No obvious gaps.

Maintenance

ActivityInactive
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    B
    quality
    D
    maintenance
    Enables secure SSH command execution on remote servers and local PowerShell automation through Claude Desktop. Features enterprise-grade security with SSH key authentication, network scanning, and comprehensive logging for Windows and Linux system administration.
    4
  • A
    license
    A
    quality
    C
    maintenance
    Enables SSH remote access to servers through Claude, allowing users to execute commands, transfer files via SFTP, and manage multiple remote connections using natural language.
    12
    8
    MIT
  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    Enables Claude Code to control remote servers via SSH for automated deployment, testing, and operations, including command execution and file transfer.
    4
  • A
    license
    Not graded
    quality
    F
    maintenance
    Enables Claude to execute commands on remote servers via SSH, with support for SSH config, private keys, password auth, and agent forwarding.
    84
    ISC

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kunwarmahen/ssh-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server