Skip to main content
Glama
script-decoder-mcp

script-decoder-mcp

Script Decoder MCP

A defensive, static-analysis MCP server that explains what a script does — in plain English and with technical evidence — without ever executing it.

Paste a Python, PowerShell, shell, JavaScript, batch, or VBScript script (or a single command line) and get back: a behavior breakdown (network, file, process, persistence, credential-access, discovery, defense-evasion, execution), safely decoded obfuscated content, extracted indicators of compromise, a transparent risk score, and a contextual MITRE ATT&CK mapping — all with source-line evidence and explicit observed/inferred/ possible classifications.

Defensive-use statement: this project performs static analysis only. It never executes, imports, compiles-for-execution, or otherwise runs submitted content. It never sends submitted scripts or decoded content to any third-party service. It is intended for SOC analysts, incident responders, and anyone who needs to understand an unfamiliar or suspicious script before deciding what to do with it — not to enable offensive use.

Features

  • Five MCP tools: analyze_script, decode_blob, extract_indicators, explain_command, compare_scripts.

  • A local browser GUI (see Browser GUI) for the same five analyses, with no MCP client required.

  • Six language analyzers: Python (AST-based), PowerShell, shell (bash/sh/zsh), JavaScript, batch, and VBScript (rule-based).

  • Bounded recursive decoding: Base64, Base32, hex, URL encoding, Unicode escapes, HTML entities, gzip/zlib/bz2, ROT13, reversed strings, PowerShell -EncodedCommand, integer/char-code arrays, simple string concatenation, and explicit-key XOR — chained safely up to a configurable depth, with decompression-bomb protection.

  • IOC extraction: URLs, domains, IPv4/IPv6, emails, file paths, registry keys, hashes, mutex-like strings, user agents, named pipes, scheduled-task/service names, and common cloud resource identifiers — including defanged-notation recognition (hxxp, example[.]com, 10[.]0[.]0[.]1).

  • Transparent, documented risk scoring (0-100) with contributing factors listed in every response — never a black box, never a malware verdict.

  • Conservative, local, offline MITRE ATT&CK mapping.

  • Prompt-injection safe: all submitted and decoded content is treated as inert data, never as instructions, and is explicitly labeled as untrusted in evidence excerpts.

  • Optional, local, disabled-by-default CyberChef-style adapter for a small set of additional decode operations, with no network access and an operation allowlist.

  • No outbound network access is required or performed during analysis.

Related MCP server: retriage

Architecture

See docs/architecture.md for the full breakdown. In short:

MCP client (e.g. Claude Desktop)
        │  stdio (default) or localhost HTTP
        ▼
 server.py (5 MCP tools)
        │
        ├─ analyzers/        language detection + per-language static analysis (AST for
        │                    Python, regex/rule-based for the rest)
        ├─ decoding/         bounded recursive decoding engine, native decoders, optional
        │                    local CyberChef-style adapter
        ├─ extraction/       IOC extraction
        ├─ classification/   risk scoring + ATT&CK mapping
        ├─ reporting/        assembles the final structured response + summaries
        └─ security/         sanitization and trust-boundary helpers

Nothing in this pipeline executes, imports, or evaluates submitted content. See docs/threat-model.md for the full threat model and SECURITY.md for the security policy.

Installation

Requires Python 3.12+.

python -m venv .venv
# Windows: .venv\Scripts\activate    macOS/Linux: source .venv/bin/activate
pip install -e ".[dev]"

Optional: Node.js 18+ if you want to enable the local CyberChef-style adapter (disabled by default; not required for any core functionality).

Local development

pip install -e ".[dev]"
python -m pytest
ruff check .
ruff format --check .
mypy src

Running the server

Default transport is stdio, which is what MCP clients like Claude Desktop expect:

python -m script_decoder_mcp
# or, after `pip install -e .`:
script-decoder-mcp

Set SDMCP_TRANSPORT=http (see .env.example) to run over localhost HTTP instead; it binds 127.0.0.1 by default and is never exposed remotely without explicit additional configuration, which this project does not provide.

Browser GUI

Prefer a browser over an MCP client? There's a local web GUI that calls the exact same analyzer/decoder code as the MCP tools -- it's a thin FastAPI wrapper around reporting/formatter.py, not a separate implementation, so results never drift from the MCP server.

pip install -e ".[web]"
python -m script_decoder_mcp.web.app
# or: make web

Then open http://127.0.0.1:8787. It has one tab per tool (Analyze Script, Decode Blob, Extract Indicators, Explain Command, Compare Scripts), plus "Load good/bad example" buttons that load examples/good_script_benign.py and examples/bad_script_suspicious.py for a quick before/after. Like the MCP server, it binds to 127.0.0.1 only by default (SDMCP_WEB_HOST/SDMCP_WEB_PORT to change), has no authentication, is not meant to be exposed beyond localhost, and never sends anything you paste anywhere beyond your own machine.

Claude Desktop / MCP client configuration

Add to your MCP client config (see examples/claude-desktop-config.example.json and examples/mcp-client-config.example.json):

{
  "mcpServers": {
    "script-decoder": {
      "command": "script-decoder-mcp",
      "args": []
    }
  }
}

If you haven't installed the console script, point command at the venv's Python and args at ["-m", "script_decoder_mcp"] instead.

Tools

analyze_script

Statically analyzes a full script. Input: content (required), language (default auto), filename, decode_embedded_content (default true), include_line_references (default true), analysis_depth (quick/standard/deep, default standard), map_to_attack (default true).

Returns a schema_version-stamped response with summary, plain_language_summary, analyst_summary, verdict, risk_score, risk_factors, behaviors (each with category, title, description, evidence, source_lines, confidence, classification — observed/inferred/possible — and severity), decoded_artifacts, indicators, imports/functions/commands, suspicious_constructs, attack_techniques, limitations, errors, and analysis_metadata. execution_performed is always false.

decode_blob

Decodes a single encoded/obfuscated value. Input: content (required), encoding_hint, max_depth, use_cyberchef (default false). Returns the detected encodings, every attempted decode chain, the successful chain (if any), decoded text/size/hashes, any indicators found in the decoded text, and warnings. Never claims to decode arbitrary encryption and never brute-forces a password or key.

extract_indicators

Extracts IOCs from arbitrary text or source. Input: content (required). Returns a dictionary of indicator categories, each entry carrying value, normalized_value, type, source_lines, context, confidence, and defanged_value.

explain_command

Explains a single command line. Input: command (required), shell (auto/cmd/powershell/bash/zsh/python, default auto), include_tokens. Returns executable, arguments, pipelines, redirections, environment changes, possible side effects, and suspicious features — never runs the command.

compare_scripts

Diffs two versions of a script. Input: original_content, new_content, language (default auto), decode_embedded_content (default true). Returns added/removed behaviors, changed indicators, newly decoded artifacts, the risk-score delta, and line-level change summary.

Example requests

See examples/sample_requests.md.

CyberChef integration

Disabled by default (SDMCP_CYBERCHEF_ENABLED=false). When enabled, decode_blob (with use_cyberchef: true) can fall back to a small local Node.js worker (cyberchef-worker/index.mjs) for a fixed, allowlisted set of operations: From Base64, From Base32, From Hex, URL Decode, HTML Entity Decode, Gunzip, Zlib Inflate, ROT13, Reverse.

Deviation from the original design: rather than depending on the cyberchef npm package (a large dependency tree), the worker reimplements these named operations using only Node.js built-ins, in a single auditable file. It performs no network access, no filesystem access beyond stdin, and no dynamic code loading. See cyberchef-worker/README.md for details and how to extend it. It is never called against a public CyberChef instance, and native Python decoders remain fully functional with or without it.

Docker

docker compose build
docker compose run --rm script-decoder-mcp

The image runs as a non-root user, uses a multistage build, and does not require network access at runtime. See Dockerfile and docker-compose.yml.

Security model

  • Static analysis only: no eval/exec/compile-for-execution of submitted content, no os.system/shell=True on submitted content, no importing of submitted scripts, no outbound network requests, no DNS resolution, no reputation-service calls.

  • Every resource limit (input size, decode output size, decompression size, recursion depth, candidate branches, analysis duration, indicators per category, evidence excerpt length) is documented in .env.example and enforced in src/script_decoder_mcp/limits.py; a threshold being hit is always reported as a limitation, never silently ignored.

  • All submitted and decoded content is treated as untrusted data, never as instructions — see src/script_decoder_mcp/security/.

  • No secrets are read, stored, or logged. Logging is JSON-structured and never emits full submitted content (see src/script_decoder_mcp/logging_config.py).

  • Full details: docs/threat-model.md, SECURITY.md.

Limitations

  • Static analysis cannot always determine runtime behavior. What a downloaded payload or a dynamically constructed command will actually do when run is not knowable from source alone, and responses/results of any network call are never fetched.

  • Dynamically constructed values (string building, indirect calls) lower analysis confidence and are flagged as inferred or possible, not observed.

  • Risk scoring is a heuristic, not a malware verdict; ATT&CK mapping is contextual evidence, not proof of malicious intent.

  • Batch and VBScript analysis is rule-based (no safe parser exists for either), so it is less thorough than the Python AST analyzer.

  • Encoding/administrative-tool use alone is never enough to mark something malicious.

Supported languages

Python, PowerShell, Bash/sh/zsh, JavaScript, Batch, VBScript, and single command lines (auto, or specify explicitly).

Extending

See docs/adding-an-analyzer.md and docs/adding-a-decoder.md.

Testing

python -m pytest -v

Test fixtures under tests/fixtures/ are inert text — no functional malware, credential-stealing code, persistence payloads, destructive scripts, or live malicious URLs. They use reserved example domains/IPs (example.com, example.invalid, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24).

Two ready-to-use manual test scripts are also included: examples/good_script_benign.py (should score low/no risk) and examples/bad_script_suspicious.py (an inert, non-functional script that exhibits several suspicious static patterns — encoded payload, exec, outbound request construction — and should score meaningfully higher). Neither script does anything if actually run; bad_script_suspicious.py is deliberately written so it does not function even if a reader ignored this warning and executed it.

Troubleshooting

  • "No dedicated analyzer is available for language..." — the language could not be detected or was not one of the six supported languages; indicator extraction and decoding still run.

  • CyberChef warnings in decode_blob — expected when SDMCP_CYBERCHEF_ENABLED=false (the default) and use_cyberchef: true was requested anyway; native decoders already cover the same operations.

  • errors populated in analyze_script — usually a Python SyntaxError; the response still includes a best-effort text-based fallback analysis.

Privacy

No submitted script, decoded artifact, or any derived content is ever sent to a third-party service. The optional CyberChef worker runs locally with no network access. No telemetry is collected by default.

Deployment

Intended for local, single-user use via stdio (the MCP-recommended local transport) or containerized via Docker for isolation. The optional HTTP transport binds 127.0.0.1 by default; exposing it beyond localhost is out of scope for this project and would require adding authentication, which is not currently implemented — see docs/threat-model.md for the residual risk this leaves if you choose to do so anyway.

Available Tools

5 tools
analyze_scriptA

Statically analyze a script (Python, PowerShell, shell, JavaScript, batch, or VBScript) without executing it. Returns behaviors, decoded artifacts, indicators, a risk score, and plain-language and analyst summaries. Never runs the submitted content.

Inputs: content (required), filename, language, map_to_attack, +3 more. Returns: errors, hashes, imports, summary, +23 more

compare_scriptsA

Compare two versions of a script and report added/removed behaviors, changed indicators, newly decoded artifacts, and the risk score delta. Neither script is executed.

Inputs: new_content (required), original_content (required), language, decode_embedded_content. Returns: summary, limitations, schema_version, added_behaviors, +6 more

decode_blobA

Safely decode an encoded or obfuscated value (Base64, hex, URL encoding, Base32, Unicode escapes, HTML entities, gzip/zlib/bz2, explicit-key XOR, ROT13, reversed strings, PowerShell -EncodedCommand, integer/char arrays, simple string concatenation) without executing the result.

Inputs: content (required), max_depth, encoding_hint, use_cyberchef. Returns: hashes, warnings, indicators, decoded_size, +8 more

explain_commandA

Explain a single command line in plain English without executing it: executable, arguments, pipelines, redirections, environment changes, and suspicious features.

Inputs: command (required), shell, include_tokens. Returns: shell, tokens, summary, arguments, +11 more

extract_indicatorsA

Extract potential security indicators (URLs, domains, IPs, emails, file paths, registry keys, hashes, and more) from text or source code, including defanged notations. Never resolves domains or makes network requests.

Inputs: content (required). Returns: indicators, total_count, schema_version, truncated_categories

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.1/5.0

    Scored across 5 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose: analyzing a full script, decoding a single blob, extracting indicators, explaining a command line, and comparing script versions. Although analyze_script returns decoded artifacts and indicators, the dedicated tools serve standalone use cases without ambiguity.

    Naming Consistency5/5

    All tool names follow a consistent verb_noun pattern: analyze_script, decode_blob, extract_indicators, explain_command, compare_scripts. The naming convention is uniform and predictable.

    Tool Count5/5

    Five tools is well-scoped for a static script decoding and analysis server. Each tool covers a distinct capability without redundancy or bloat.

    Completeness5/5

    The tool surface covers the full static analysis workflow: analyzing scripts, decoding blobs, extracting indicators, explaining commands, and comparing versions. There are no obvious missing operations for the stated purpose of safely decoding and analyzing scripts without execution.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      D
      maintenance
      Enables secure static analysis of Microsoft Office documents and related file types for malicious content, integrating with systems that support the MCP protocol.
      4
      -
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables MCP clients to run hardened, read-only radare2-based static binary triage tools, including disassembly, cross-reference following, string decoding, function renaming, and evidence-checked report generation without executing the sample.
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables agents to inspect and reverse engineer native binaries, JavaScript/Electron applications, .NET assemblies, websites, and runtime behavior, returning evidence-backed findings that can be explained, implemented, or tested.
      351,882 npm
      4
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Enables agents like Claude Code and Codex to statically scan .zip, .exe, .dll files and GitHub repositories for malware without executing them, explaining likely false positives and letting users dig into reports through natural language.
      5
      MIT