Nms Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Nms Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Production-grade MCP server for persistent SSH PTY sessions and cached Oracle DB diagnostic sessions, with strict server-side review, confirmation, and audit logging.
ssh2 directly so the server can keep a real PTY shell alive across MCP callssrc/
|-- index.ts
|-- session.ts
|-- ssh.ts
|-- executor.ts
|-- nms-docs.ts
|-- sudo.ts
|-- db.ts
|-- db-session.ts
|-- policy.ts
|-- sql-policy.ts
|-- policy-config.ts
|-- oracledb.d.ts
`-- utils.ts
ssh-mcp-policy.json
ssh-mcp-policy.example.json
mcp-audit.ndjson
scripts/mcp_smoke_test.mjsShell and transport:
MCP_SSH_IDLE_TIMEOUT_MS default 1800000MCP_SSH_DEFAULT_TIMEOUT_MS default 30000MCP_SSH_APPROVAL_TTL_MS default 600000MCP_SSH_MAX_SESSIONS default 10MCP_SSH_ALGORITHM_PROFILE default compat; use default to fall back to the raw ssh2 algorithm orderMCP_SSH_POLICY_FILE optional path to a custom JSON policy fileMCP_TRANSPORT stdio or sse, default stdioMCP_SSE_PORT default 3000Oracle DB:
MCP_DB_IDLE_TIMEOUT_MS default 1800000MCP_DB_DEFAULT_TIMEOUT_MS default 30000MCP_DB_MAX_SESSIONS default 5MCP_DB_MAX_ROWS default 200MCP_DB_CONFIG_DIR optional Oracle Net config directory for wallet or TNS-based connections; if unset, MCP also falls back to TNS_ADMIN when presentMCP_DB_WALLET_LOCATION optional wallet directoryMCP_DB_WALLET_PASSWORD optional wallet passwordMCP_DB_HTTPS_PROXY optional HTTPS proxy for secure Oracle DB connectionsMCP_DB_HTTPS_PROXY_PORT optional proxy portAudit:
MCP_AUDIT_LOG_FILE default C:\ProjectNMS\NMS_MCP\mcp-audit.ndjson when running from this repoOracle NMS documentation:
MCP_NMS_DOCS_BOOKS_URL default https://docs.oracle.com/en/industries/energy-water/network-management-system/books.htmlMCP_NMS_DOCS_CACHE_DIR default %USERPROFILE%\Documents\nms-docsShell tools:
ssh_connectssh_connect_target_sessionreview_commandreview_command_batchexecute_commandexecute_command_batchstart_interactive_commandwrite_stdinsend_interaction_inputread_outputread_interaction_stateresize_terminallist_sessionsclose_sessioninterrupt_sessionOracle DB tools:
oracle_connectreview_sqlexecute_sqllist_db_sessionslist_nms_guidesget_nms_guide_pdfclose_db_sessioninterrupt_db_sessionShared visibility:
read_usage_guideread_policyread_audit_logOracle NMS documentation tools:
list_nms_guidesget_nms_guide_pdfThe server does not trust user intent or agent intent. It reviews the exact command or SQL text first, decides whether it is on the explicit safe list, and otherwise requires confirmation before running it.
For simple commands, use execute_command.
When you already know the target project or admin account you need, prefer ssh_connect_target_session so MCP logs in once, adopts that target shell once, and then lets the rest of the session run without repeating sudo.
For a related sequence of standalone checks on the same host, use execute_command_batch so MCP can review the whole set together and, when needed, ask for one shared confirmation instead of one prompt per command.
For anything that may prompt, stream, or open a REPL, use the guided interactive flow:
start_interactive_commandread_interaction_statesend_interaction_inputinterrupt_session or wait for the command to completeThe server keeps the PTY stateful, classifies common prompt types, and returns structured interaction metadata such as:
promptTypepromptTextexpectsInputsafeToAutoRespondsuggestedInputsforegroundCommandPrompt types currently include shell prompts, sudo/password prompts, yes/no prompts, press-enter prompts, Python REPL prompts, SQL prompts, pagers, and fallback unknown interactive prompts.
These commands can auto-run when MCP can clearly recognize them and does not detect extra unsafe behavior:
lspwdcdgrepfindlocatecatpstailheadsortuniqwcechoprintfhostnamewhoamiiddateunameenvprintenvcommandtypessnetstatlsofreadlinkrealpathsmsReportISQL read-only SELECT commands onlyISQL -admin read-only SELECT commands onlyNotes:
cd is treated as low-impact and allowed because it only changes the active shell directoryhostname, whoami, id, getent, grep -n ... | head, ps -ef | grep ... | grep -v grep, find ... | sort | tail, ss -ltn, and exact .nmsrc validation bundles can auto-run when they match the built-in diagnostics profilesudo su - <target-user> or sudo -iu <target-user> can auto-run so MCP can adopt the target shell without an extra confirmation stepsudo -u <target-user> whoami, ps, grep, find, log-path discovery pipelines, or smsReport 2>&1 | head -n ... can auto-run when the underlying command already matches the safe diagnostics rulessudo usage is still higher scrutiny and can require confirmation or be blocked by policyssh_connect_target_session instead of repeating sudo -u <target-user> on every command.nmsrc wrappers over privilege-changing bundles whenever possible.bashrc, .profile, or similar login files unless the command truly depends on extra environment setuppython, sqlplus, ISQL, tail -f, less, top, or ssh are not treated as safe auto-run commandssudo, or other risky patterns, it will stop auto-running and ask firstThese statements can auto-run when MCP can clearly recognize them as read-only:
SELECT ...WITH ... SELECT ...Notes:
SELECT are not auto-run if MCP is not confident about side effectsSELECT ... FOR UPDATE is not auto-runAnything outside the safe auto-run lists requires explicit user confirmation.
What MCP returns:
decision: "allow" for explicit safe commands or queriesdecision: "allow" for safe read-only command batches whose individual commands are all recognized as low riskdecision: "approval_required" for unknown, custom, mutating, or higher-risk actionsdecision: "blocked" only when a deny rule or explicit blocked category in your policy file says MCP must refuse it entirelyConfirmation rule:
execute_command_batch, MCP can ask once for the whole related command setCONFIRMapprovalId and userConfirmation: "CONFIRM"Every reviewed or executed operation is appended to the audit file:
The default audit file is mcp-audit.ndjson. Each line is one JSON object so it is easy to search or archive.
Use list_nms_guides to scrape the live Oracle NMS docs library and discover available versions plus guide titles.
Use get_nms_guide_pdf with a version and guide query to resolve one PDF to a local cached file path. If the file is already cached, MCP returns that local path immediately. Otherwise MCP downloads the PDF into the configured cache directory first and then returns the absolute path.
Examples:
list_nms_guides to inspect all currently published versions and guideslist_nms_guides with {"version":"25.12"}get_nms_guide_pdf with {"version":"25.12","guide":"installation guide"}get_nms_guide_pdf with {"version":"25.12","guide":"nms-installation-guide","refresh":true}The server loads ssh-mcp-policy.json by default. You can point to a different file with MCP_SSH_POLICY_FILE.
Current policy file model:
sqlPolicy fields apply to Oracle SQL policydenyRules always win over allowRulesblockedCategories are for commands or SQL you want MCP to hard-refuseapprovalCategories are for categories that should always require confirmationapprovedScratchPaths define the only scratch paths MCP will treat as explicitly approved write targetsdiagnosticsProfiles enable exact built-in read-only command bundles such as the Oracle NMS diagnostics profileallowRules are for narrow exceptions you want MCP to recognize explicitlyDefault files:
{
"blockedCategories": [
"privilege-escalation",
"password-change"
],
"approvalCategories": [
"session-state",
"privileged-command"
],
"approvedScratchPaths": [
"/tmp",
"/var/tmp"
],
"diagnosticsProfiles": [
"oracle-nms-readonly"
],
"allowRules": [],
"denyRules": [
{
"name": "block-service-restarts",
"regex": "\\b(systemctl|service)\\b.*\\b(start|stop|restart|reload)\\b",
"reason": "Hard-block service interruption through MCP."
}
],
"sqlPolicy": {
"blockedCategories": [
"ddl-destructive",
"lock-control"
],
"approvalCategories": ["session-state"],
"allowRules": [],
"denyRules": [
{
"name": "block-delete",
"regex": "^delete\\b",
"reason": "Hard-block row deletion through MCP."
}
]
}
}Use these tools anytime they would help NMS development, debugging, runtime validation, issue analysis, or environment checks.
Good uses:
.nmsrc setup, and NMS utility checksreview_command for custom project commands when MCP is not fully certainreview_command_batch and execute_command_batch for a human-style sequence of related standalone checks on the same hostreview_sql for any SQL beyond a plain safe SELECTRequired behavior:
CONFIRM.POLICY_BLOCKED as final unless a human intentionally changes the policy file.smsReport, then grep, then find, instead of one giant quoted shell command that has to be mentally unpacked later.On Windows PowerShell, use npm.cmd and codex.cmd. The .ps1 shims may be blocked by execution policy on locked-down machines.
Install dependencies:
npm.cmd installBuild:
npm.cmd run buildStart over stdio:
npm.cmd startStart over SSE:
$env:MCP_TRANSPORT = "sse"
$env:MCP_SSE_PORT = "3000"
npm.cmd startBuild the project first:
cd C:\ProjectNMS\NMS_MCP
npm.cmd install
npm.cmd run buildRegister the server with Codex:
codex.cmd mcp add nms-mcp `
--env MCP_SSH_DEFAULT_TIMEOUT_MS=120000 `
--env MCP_SSH_IDLE_TIMEOUT_MS=3600000 `
--env MCP_SSH_APPROVAL_TTL_MS=600000 `
--env MCP_SSH_POLICY_FILE=C:\ProjectNMS\NMS_MCP\ssh-mcp-policy.json `
--env MCP_SSH_MAX_SESSIONS=10 `
--env MCP_DB_DEFAULT_TIMEOUT_MS=60000 `
--env MCP_DB_IDLE_TIMEOUT_MS=3600000 `
--env MCP_DB_MAX_SESSIONS=5 `
--env MCP_DB_MAX_ROWS=200 `
--env MCP_AUDIT_LOG_FILE=C:\ProjectNMS\NMS_MCP\mcp-audit.ndjson `
-- node C:\ProjectNMS\NMS_MCP\dist\index.jsVerify it is registered:
codex.cmd mcp listNotes:
C:\ProjectNMS\NMS_MCP with your actual checkout path if it is differentssh_connect or oracle_connectCONFIRMBuild the project first if you have not already:
cd C:\ProjectNMS\NMS_MCP
npm.cmd install
npm.cmd run buildOpen Cline and add a local stdio MCP server using this shape:
{
"mcpServers": {
"nms-mcp": {
"command": "node",
"args": ["C:\\ProjectNMS\\NMS_MCP\\dist\\index.js"],
"env": {
"MCP_SSH_DEFAULT_TIMEOUT_MS": "120000",
"MCP_SSH_IDLE_TIMEOUT_MS": "3600000",
"MCP_SSH_APPROVAL_TTL_MS": "600000",
"MCP_SSH_POLICY_FILE": "C:\\ProjectNMS\\NMS_MCP\\ssh-mcp-policy.json",
"MCP_SSH_MAX_SESSIONS": "10",
"MCP_DB_DEFAULT_TIMEOUT_MS": "60000",
"MCP_DB_IDLE_TIMEOUT_MS": "3600000",
"MCP_DB_MAX_SESSIONS": "5",
"MCP_DB_MAX_ROWS": "200",
"MCP_AUDIT_LOG_FILE": "C:\\ProjectNMS\\NMS_MCP\\mcp-audit.ndjson"
},
"disabled": false
}
}
}Notes:
ssh_connect or oracle_connectSSH:
ssh_connect.review_command for anything outside the obvious safe list or when you want MCP to explain the risk before asking the user.execute_command for one-shot commands, execute_command_batch for a related set of standalone checks, or start_interactive_command for prompt-driven commands.CONFIRMATION_REQUIRED, show the exact command or command set plus the summary, then retry with the same approvalId and userConfirmation: "CONFIRM".read_interaction_state and continue with send_interaction_input.Oracle DB:
oracle_connect with DB credentials and either connectString or host plus serviceName or sid.review_sql for anything beyond a plain safe SELECT.execute_sql.CONFIRMATION_REQUIRED, show the exact SQL and the summary, then retry with the same approvalId and userConfirmation: "CONFIRM".Safe shell command:
{
"sessionId": "abc123",
"command": "ps -ef | grep -i nms_1 | grep -v grep"
}Custom project command that requires confirmation:
{
"sessionId": "abc123",
"command": "smsReport"
}Interactive prompt-driven command:
{
"sessionId": "abc123",
"command": "python3 -q",
"waitForOutputMs": 1500
}Follow-up interactive input:
{
"sessionId": "abc123",
"input": "print(2 + 2)\\n",
"waitForOutputMs": 1000
}Safe SQL query:
{
"dbSessionId": "db123",
"sql": "select count(*) as class_count from classes"
}SQL that requires confirmation:
{
"dbSessionId": "db123",
"sql": "alter session set current_schema = NMS"
}If a long-running command times out or an interactive program appears stuck, the PTY session stays attached on purpose so the agent can recover it instead of losing shell state.
Recommended recovery steps:
read_output to inspect the latest PTY output.read_interaction_state when you want prompt classification instead of raw output alone.interrupt_session with ctrlC to bring the shell back to a prompt.read_output again if you want to capture the interrupt output.pwd to confirm the shell is ready again.This is safer than blindly starting a new session because the existing working directory, sourced environment, and any confirmed elevation state remain visible and auditable.
The smoke harness verifies the SSH path end-to-end, exercises the review flow for shell and SQL, and checks PTY recovery with interrupt_session. It auto-confirms inside the local harness only so the test can complete; production agents must not do that.
SSH smoke test:
$env:SSH_TEST_HOST = "your-ssh-host"
$env:SSH_TEST_PORT = "2222"
$env:SSH_TEST_USER = "your_ssh_user"
$env:SSH_TEST_PASSWORD = "your_ssh_password"
node scripts\mcp_smoke_test.mjsOptional direct Oracle DB smoke test:
$env:DB_TEST_USER = "your_db_user"
$env:DB_TEST_PASSWORD = "your_db_password"
$env:DB_TEST_CONNECT_STRING = "db-host:1521/your_service"
node scripts\mcp_smoke_test.mjsAudit file example:
Get-Content C:\ProjectNMS\NMS_MCP\mcp-audit.ndjson -Tail 20~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.