From 46f98671ea2749340c1dd7b640e9b3d1d34ec687 Mon Sep 17 00:00:00 2001 From: Steve White Date: Tue, 8 Apr 2025 21:06:58 -0500 Subject: [PATCH] Fixed descriptions --- .gitignore | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 215 -> 216 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 309 -> 310 bytes src/mcpssh/__pycache__/server.cpython-312.pyc | Bin 9695 -> 10567 bytes src/mcpssh/server.py | 55 ++++++++++++------ 5 files changed, 37 insertions(+), 19 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d17dae --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.venv diff --git a/src/mcpssh/__pycache__/__init__.cpython-312.pyc b/src/mcpssh/__pycache__/__init__.cpython-312.pyc index e8ba3714001ca846d654ea92de20898431c2226b..34080a25ccda8e44247bd34f98300864190ad77e 100644 GIT binary patch delta 46 zcmcc4c!QDaG%qg~0}!k_H<2q(!c;%BIJKx)zqq74BeNt`-`U^ARo^$jd1Ai@07)MX AvH$=8 delta 45 zcmcb?c%6~!G%qg~0}%M;PUOlHH_;Ev&neAKE!Gcq^fl6V_IGjB_jL}KIKcw|7xWC* diff --git a/src/mcpssh/__pycache__/__main__.cpython-312.pyc b/src/mcpssh/__pycache__/__main__.cpython-312.pyc index 211e0e8720efe2167b3375a49961a1e9bb7d3f34..50ed50549e0e260c1bf6c6e52394d36c92a4fa0a 100644 GIT binary patch delta 46 zcmdnWw2g`DG%qg~0}!k_H<4?PgsFaLacWVqesM{8MrKK>zO%oJtG;i5^TfLm07nH6 A8~^|S delta 45 zcmdnSw3UhLG%qg~0}!<2PUPAnZlWKSpHrHfTC5-J=xe0!?C;{L@9P{e@m>S~9Ig#` diff --git a/src/mcpssh/__pycache__/server.cpython-312.pyc b/src/mcpssh/__pycache__/server.cpython-312.pyc index 1576b0fbe84167f01e2754cbaa04afff10aa8504..259a0f9ad096efc6e13826a68e97a9d706fbd527 100644 GIT binary patch delta 2292 zcmZ`)>r)d~6yKX{UL+wv-U)#Pc?Egcs?efswFnBzL%_Esrr8ApAz|(=2y_|HwlndA zQ<&Qh?KpmL+8MPlqm~cFFV#=2GfvwL>VO$%>L1WLnTj)h?7f=@p!H1h+k4OX-E;2i zocq_o-@39N7>!vJmLLCk*?)?;ot>+4Y_C1SbC9p)g>z?v0$1DEv9GDNt+R2lPSu(X zH0Zq9;`~@iQQv?$N>q&jo&l6Vd=NpiMsFJnSjD^|shCs=>ST+eE@p|;rCbV+T2Rh| zq!v&tEmA&Jnj-@2vG6sI=pUUPaf+B@rayi z0}`xem#AS)qUthrMX``GkN2Ahpa>V`sIBN0p=jCMw^M2hl7lv)sAKcq95GIN&HlvV z6Kf-wVzA)zALXDg>>uJ9n8p!ahzv2L!}LWUBb?<@1SS~f1%EieF%`rxG!hbm!=bd5 z_hu1aX%QlkkZ%}reZjE?rc?eV-C@1#oM$Syn*QdRDyBRc{~ces%*b?k{;V$$35U6W zP`>UwZf zrqE5G2ZL7+UHF4$Xlu8A!x_R}tc@E|OOlT@Zb&US*)y%LIH}P2e1VXk=Y2k&B!GN~ zDCVfz9>RJ1YMM$oD0}g;?f4H}*G^tNd9C+que77({_cmR$D{hETH{4cOzZe|P|`Xc zX)BS`w$@M|h^h|5`%6QQ@!>-uMVz#pDr=^xNl0PJ!8Ityg zqsB+t$SPrcw3#v>4US3!=cN5(gfcEuk_>Om=DlT-ItHcCIcacAY8#IlA8RMjGiQb3 zK0rBzF2$q*%@}R2NhQuj8gI^PGD)LemrVf;!m~?Dn%MSciGVe zof$dYMwOD!71ijx&VoL~Jv!54-DY4yWA5^;xNs&#RER1venC5*3XjW_E@Pzz^3Y+W z8CcO>oeRBk7lOy=lHGx}+1ahpLSUkS+Fer>y2QUT${t(j_>r9uwr7CP0Ui= z-CcKfMd`);1qBLiKlbFM;R!UvxbjGBp1eB@1Ks!oyU}-y2mG}7GgAjZKYCtN;+7{| zPmJ#oHhG0oZ8eL+2;_q?PT)n_2F4{TBO0I7Iqf+CHjk|q9Lojniq0E(Ta9&X+@nT+Cqx^ zi(fFzZGK3tEJ#0FlbbF0l4LQHK+xbpvWS!j@S~c3bQPjvK!iY@_b{)1`ry+% z%j>E&HI?mJwG`stno60io^DPU(B6_i!6?ct^?(bgw)FGrPXRatX6n}{x$$qS(g=zZ Z3`HBF6U$2H6I%Oab3#ecF6hC*{{ybQRbBu9 delta 1585 zcmZ`(O-vhC5Pr{Iuh))$F#cI%uvv_8*wENX)Rst83XvN?B%%DZ>R&L%yCOzrm+meR z0Y{*w2T)ao=qVz%R;ntc0!6C0&`ZUwm3jz9si3|j$DS&yNu(S*&j!n-?MOR2Z{~Y5 zZ+E^oKaW1U>iX5`v?Gwa3$Lb|T7GbOEc}J!2WozPR@Ream#<$)rrvw^O7ePYc)Qy& z==#(`!AHWv+YHZ(cT5O9z#GUoj-WM50euBn32&J;an+5HWGX&2&~(6gg`w22)i-FjOI<2xDUdf-Y;fWKA?_gHTvYfhtwD$P03I-jEmD$@yq| zW64F+NICsDQ-oM!k+Y(^WYOp6WKC&C6G9&U?-^=el$dh!+F#M>qBcrdFL#x$Gh5I2o9w0i`Y=76anmx!%1Y zW!3o`r;@K*I-?vAX9E@R3{*WS&}IilOa-Q3A+uo~dnrfAwYbd=)L?W^ft{(kehNFRmfE@l z`+-tkVvqQ`__{P^nrMsLWU4-(ZS5d%<{%j{dvP=IM7?A#6336pMr4AJXcy^k{Wk8> z+^|dgkg5i%KB9^qQu~;yMyfs`SZMK&Q?m_}Xst9;n*f`3blEza15zl{x)nS^RkUUb zrz}_u0uje5JcPTSs3Yv>5Y~&JlQ&JdO!?n>>kK!3^O$ z-i%jh-bb-Du9uug1kcL(d^#;+?FRX*BYb`mP_Ms0zcanB7{6r>mlJK4al99OtBk0z z6Wh^uQ#%VkCSFw5fosR_!2Xl$tju&pj~)$ z+F!V_EOLduoLDjUm09xr=_gnvw>!gliEMP<4ZM%>HN4*a5><@9=1eS(mK(`Ak^dXg CuXzLj diff --git a/src/mcpssh/server.py b/src/mcpssh/server.py index 6e09bb3..b59bd00 100644 --- a/src/mcpssh/server.py +++ b/src/mcpssh/server.py @@ -1,4 +1,15 @@ -"""MCP SSH Server implementation.""" +"""MCP SSH Server implementation. + +This module implements an Anthropic Model Context Protocol (MCP) server that provides +secure SSH access to remote systems. It allows LLMs to connect to and execute commands +on remote systems via SSH, while enforcing security by requiring hostname, username, +and key file to be set in configuration rather than allowing the LLM to specify them directly. + +The server provides three main tools: +1. ssh_connect: Connect to an SSH server using credentials from configuration +2. ssh_execute: Execute a command on the connected SSH server +3. ssh_disconnect: Disconnect from the SSH server +""" import json import logging @@ -89,20 +100,25 @@ class SSHSession: class SSHConnectionParams(BaseModel): """Parameters for SSH connection.""" - hostname: Optional[str] = Field(None, description="SSH server hostname or IP address") - port: Optional[int] = Field(None, description="SSH server port") - username: Optional[str] = Field(None, description="SSH username") - key_filename: Optional[str] = Field(None, description="Path to SSH private key file") + hostname: Optional[str] = Field(None, description="SSH server hostname or IP address (ignored - set from configuration)") + port: Optional[int] = Field(None, description="SSH server port (optional)") + username: Optional[str] = Field(None, description="SSH username (ignored - set from configuration)") + key_filename: Optional[str] = Field(None, description="Path to SSH private key file (ignored - set from configuration)") class CommandParams(BaseModel): - """Parameters for executing a command.""" + """Parameters for executing a command on the remote SSH server.""" - command: str = Field(..., description="Command to execute on remote server") + command: str = Field(..., description="Command to execute on the remote SSH server (requires an active SSH connection)") class SSHServerMCP(FastMCP): - """MCP server that provides SSH access to remote systems.""" + """MCP server that provides secure SSH access to remote systems. + + This server allows LLMs to connect to and execute commands on remote systems via SSH, + while enforcing security by requiring hostname, username, and key file to be set + in configuration rather than allowing the LLM to specify them directly. + """ def __init__(self, hostname=None, port=None, username=None, key_filename=None, server_name=None, tool_prefix=None): """Initialize SSH server. @@ -134,15 +150,16 @@ class SSHServerMCP(FastMCP): execute_name = f"{self.tool_prefix}ssh_execute" disconnect_name = f"{self.tool_prefix}ssh_disconnect" - self.add_tool(self.ssh_connect, name=connect_name, description=f"Connect to SSH server: {server_name}") - self.add_tool(self.ssh_execute, name=execute_name, description=f"Execute a command on SSH server: {server_name}") - self.add_tool(self.ssh_disconnect, name=disconnect_name, description=f"Disconnect from SSH server: {server_name}") + self.add_tool(self.ssh_connect, name=connect_name, description=f"Connect to SSH server: {server_name} (hostname and username are set in configuration and cannot be altered)") + self.add_tool(self.ssh_execute, name=execute_name, description=f"Execute a command on SSH server: {server_name} using the established SSH connection") + self.add_tool(self.ssh_disconnect, name=disconnect_name, description=f"Disconnect from SSH server: {server_name} and close the SSH connection") def ssh_connect(self, params: SSHConnectionParams) -> Dict[str, Any]: - """Connect to an SSH server. + """Connect to an SSH server using SSH protocol. Args: - params: SSH connection parameters (ignored for security-critical fields) + params: SSH connection parameters (hostname, username, and key_filename are ignored + and set from configuration for security reasons; only port can be optionally specified) Returns: Result of connection attempt @@ -176,13 +193,13 @@ class SSHServerMCP(FastMCP): return {"success": False, "message": "Failed to connect to SSH server"} def ssh_execute(self, params: CommandParams) -> Dict[str, Any]: - """Execute a command on the SSH server. + """Execute a command on the SSH server using the established SSH connection. Args: - params: Command parameters + params: Command parameters (requires an active SSH connection established via ssh_connect) Returns: - Command execution result + Command execution result with stdout, stderr, and exit_code """ if not self.ssh_session or not self.ssh_session.connected: return {"success": False, "message": "Not connected to SSH server"} @@ -190,10 +207,10 @@ class SSHServerMCP(FastMCP): return self.ssh_session.execute_command(params.command) def ssh_disconnect(self) -> Dict[str, Any]: - """Disconnect from the SSH server. + """Disconnect from the SSH server and close the SSH connection. Returns: - Disconnect result + Disconnect result indicating success or failure """ if not self.ssh_session: return {"success": True, "message": "Not connected to SSH server"} @@ -219,4 +236,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main()