mcp-server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-serverhealth check myapp on 10.0.1.25 port 9080"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-server
An MCP server for inspecting IBM Liberty / WebSphere-style application servers over SSH — reading config with secrets redacted, checking whether an app is actually up, and searching its logs.
Tools
read_config
Connects to a remote server over SSH and returns its application config as sanitized text.
Arguments
Name | Type | Description |
| string | Hostname or IP address of the server to connect to over SSH. |
| string | SSH username to authenticate as. |
| string | Path to the private key file (on the machine running this MCP server) used for authentication. |
| string | Base deployment directory containing the application folder. |
| string | Name of the application subfolder to read config from. |
What it does
Opens an SFTP session to
server_ipasos_user, authenticating withssh_key. Strict host key checking is disabled (StrictHostKeyChecking=noequivalent) — unknown hosts are auto-accepted rather than requiring aknown_hostsentry. This trades off protection against man-in-the-middle attacks for not having to pre-seedknown_hostsfor every target server.Looks in
<deployment_directory>/<application>/on that server.Reads
server.xml.Scans
server.xmlfor<include location="...">references and any*.propertiesfile references, and reads those too.Always also reads (if present):
jvm.options,server.env,bootstrap.properties.Redacts values associated with sensitive keys —
password,secret,token,apikey,credential, etc. — in bothkey=valuestyle (properties files,.env,-DJVM options) and XML attribute style, including Liberty's<variable name="db.password" value="..."/>pattern where the keyword and the secret live in separate attributes.Returns a single JSON object with the sanitized content of every file found (and a not-found/error note for anything missing).
References that would resolve outside the application directory (e.g. path
traversal via ../../) or that depend on an unresolved ${variable} are
skipped rather than followed.
Note: only the SSH key path is ever passed to the tool — key material itself never flows through the LLM or tool-call history.
Example result shape
{
"server": "10.0.1.25",
"application_directory": "/opt/liberty/deployments/myapp",
"files": [
{ "path": "server.xml", "found": true, "content": "..." },
{ "path": "jvm.options", "found": true, "content": "..." },
{ "path": "server.env", "found": true, "content": "..." },
{ "path": "bootstrap.properties", "found": true, "content": "..." },
{ "path": "vars/extra.properties", "found": true, "content": "..." }
]
}health_check
Connects to a remote server over SSH and reports whether an IBM Liberty app
is healthy: an HTTP probe plus a process check. Built for locked-down
targets — assumes a non-root SSH user with no access to root-owned
paths, and no JDK installed, so it never shells out to jps, jcmd,
or bin/server status.
Arguments
Name | Type | Description |
| string | Hostname or IP address of the server to connect to over SSH. |
| string | SSH username to authenticate as. |
| string | Path to the private key file (on the machine running this MCP server) used for authentication. |
| integer | Local port the application listens on. |
| string | URI path to request for the HTTP health check (e.g. |
| string | Application/server name to look for among running processes. |
What it does
Opens one SSH session to
server_ipasos_userand runs two small shell scripts on the remote host (no local files needed, nosudo):HTTP check: requests
http://127.0.0.1:<port><uri>using whichever ofcurl,wget, orpython3is present on the target, in that order. If none are available it reports that rather than guessing.Process check: greps
ps -effor a line containing bothjavaandapplication, since Liberty runs as a plain JVM process and there's no JDK on the box to ask it directly.
Returns HTTP reachability + status code + a healthy/unhealthy verdict (2xx/3xx counts as healthy), and process running/not-running + PID.
Example result shape
{
"server": "10.0.1.25",
"application": "myapp",
"http": { "reachable": true, "status_code": 200, "healthy": true, "detail": "HTTP 200" },
"process": { "running": true, "pid": "25579", "detail": "501 25579 ... java ... myapp ..." }
}list_logs
Connects over SSH and enumerates every file under
<deployment_directory>/<application>/logs/ — Liberty's own messages.log,
console.log, trace.log, ffdc/*, plus whatever an application itself
writes into subdirectories there. Meant to be called before analyze_logs
so an LLM can pick which files are actually relevant instead of blindly
grepping everything (trace.log especially can be huge).
Arguments
Name | Type | Description |
| string | Hostname or IP address of the server to connect to over SSH. |
| string | SSH username to authenticate as. |
| string | Path to the private key file (on the machine running this MCP server) used for authentication. |
| string | Base deployment directory containing the application folder. |
| string | Name of the application subfolder whose |
Example result shape
{
"server": "10.0.1.25",
"logs_directory": "/opt/liberty/deployments/myapp/logs",
"files": [
{ "path": "messages.log", "size_bytes": 827, "modified": "2026-07-28T00:45:10+00:00", "category": "liberty_core" },
{ "path": "trace.log", "size_bytes": 111, "modified": "2026-07-28T00:10:00+00:00", "category": "liberty_core" },
{ "path": "ffdc/com.ibm.ws.webcontainer_exception_...txt", "size_bytes": 178, "modified": "2026-07-28T00:15:32+00:00", "category": "ffdc" },
{ "path": "myapplogs/app-2026-07-28.log", "size_bytes": 174, "modified": "2026-07-28T00:50:00+00:00", "category": "app_or_other" }
]
}analyze_logs
Connects over SSH and greps the app's logs for given strings/exception names, returning matches with surrounding context.
Arguments
Name | Type | Description |
| string | Hostname or IP address of the server to connect to over SSH. |
| string | SSH username to authenticate as. |
| string | Path to the private key file (on the machine running this MCP server) used for authentication. |
| string | Base deployment directory containing the application folder. |
| string | Name of the application subfolder whose |
| list of strings | Strings or exception names to search for (case-insensitive, literal match). |
| string, optional | ISO-8601 timestamp; matches before this are excluded when a timestamp is detected. |
| string, optional | ISO-8601 timestamp; matches after this are excluded when a timestamp is detected. |
| list of strings, optional | Paths relative to |
What it does
If
log_filesisn't given, discovers every file underlogs/(capped at 300 files) and skips any over ~25MB — those get reported back underskipped_filesrather than silently ignored, so the LLM knows to pass them explicitly vialog_filesif they're actually needed.If
start_timeis given, skips whole files whose last-modified time predates it (log files are append-only, so an untouched-since-start_timefile can't contain anything newer).Runs
grep -n -i -a -F -C 2per file for the given terms and groups matches into context blocks.For each block, tries to find a timestamp — Liberty's basic format (
[7/28/26 0:15:32:123 UTC]), Liberty's JSON format ("ibm_datetime"), or generic ISO-8601 for arbitrary app logs — anchored on the actually matched line (not just the first line of the context block). If found and outside[start_time, end_time], the block is dropped; if no timestamp can be parsed, the block is kept rather than silently discarded — stack traces and multi-line messages don't repeat their header's timestamp, and hiding potentially-relevant lines is worse than including a few extra ones.
Example result shape
{
"server": "10.0.1.25",
"logs_directory": "/opt/liberty/deployments/myapp/logs",
"search": ["NullPointerException"],
"results": [
{
"file": "messages.log",
"timestamp": "2026-07-28T00:15:32.123000",
"lines": [
"2-[7/28/26 0:15:32:123 UTC] ... E SRVE0777E: Exception thrown by application class",
"3:java.lang.NullPointerException: Cannot invoke method on null object",
"4-\tat com.example.myapp.Service.process(Service.java:42)"
]
}
],
"truncated": false,
"skipped_files": []
}Related MCP server: MCP SSH Manager
Setup
Requires Python 3.11+ and uv.
git clone https://github.com/Murtaza1211/mcp-server.git
cd mcp-server
uv syncThat installs the mcp SDK and registers the mcp-server console script
(uv run mcp-server), which starts the server over stdio.
Connecting to an MCP client
Any MCP client that supports stdio servers can run this directly. The general pattern is:
command:
uvargs:
["--directory", "/absolute/path/to/mcp-server", "run", "mcp-server"]
Hermes Agent
Add to ~/.hermes/config.yaml:
mcp_servers:
server-config-reader:
command: /absolute/path/to/uv
args: ["--directory", "/absolute/path/to/mcp-server", "run", "mcp-server"]Then verify:
hermes mcp list
hermes mcp test server-config-readerhermes mcp test should report a successful connection and list
read_config, health_check, list_logs, and analyze_logs as discovered
tools.
Claude Desktop / other MCP clients
Add an equivalent entry to the client's MCP server config, e.g. for Claude
Desktop's claude_desktop_config.json:
{
"mcpServers": {
"server-config-reader": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/mcp-server", "run", "mcp-server"]
}
}
}Project layout
src/mcp_server/
server.py MCP tool registration (FastMCP)
ssh.py Shared SSH connection helper (used by every tool)
config_reader.py read_config: file discovery over SFTP, path-traversal guard
health_check.py health_check: HTTP probe + process check over SSH exec
logs.py list_logs / analyze_logs: log discovery + grep with time filtering
sanitize.py Regex-based secret redactionDevelopment
uv run python -c "
from mcp_server.config_reader import read_config
import json
print(json.dumps(read_config('10.0.1.25', 'appuser', '~/.ssh/id_rsa', '/opt/liberty/deployments', 'myapp'), indent=2))
"
uv run python -c "
from mcp_server.health_check import check_health
import json
print(json.dumps(check_health('10.0.1.25', 'appuser', '~/.ssh/id_rsa', 9080, '/health', 'myapp'), indent=2))
"
uv run python -c "
from mcp_server.logs import list_logs, analyze_logs
import json
print(json.dumps(list_logs('10.0.1.25', 'appuser', '~/.ssh/id_rsa', '/opt/liberty/deployments', 'myapp'), indent=2))
print(json.dumps(analyze_logs('10.0.1.25', 'appuser', '~/.ssh/id_rsa', '/opt/liberty/deployments', 'myapp', ['NullPointerException']), indent=2))
"This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/Murtaza1211/mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server