mohamedelamraoui1

mcp-shell-server-example

Community mohamedelamraoui1
Updated

A beginner-friendly example MCP server built with the official Python SDK. Demonstrates exposing tools (shell command execution, remote content fetching) and resources over the Model Context Protocol — meant to help others understand MCP's core concepts through simple, working code.

mcp-shell-server-example

Follow on XWhatsApp ChannelLicense

A small, educational Model Context Protocol (MCP) server built with the official Python SDK.

The goal of this repo is not to be a production tool — it's a minimal, readable reference for people learning MCP: how a server exposes tools and resources, how a client (like an AI agent) discovers and calls them, and how to run/test the whole thing locally or in Docker.

What is MCP?

The Model Context Protocol is an open standard that lets AI applications (like Claude) connect to external systems in a consistent way. An MCP server exposes capabilities — mainly:

  • Tools — functions the AI can call (e.g. "run this shell command", "fetch this URL")
  • Resources — data the AI can read (e.g. a file's contents)

An MCP client (built into an AI app, or a debugging tool like MCP Inspector) connects to the server, discovers what it offers, and calls it on the AI's behalf. Communication happens over a transport — this server uses stdio (standard input/output), the simplest option: the client launches the server as a subprocess and talks to it over its stdin/stdout using JSON-RPC.

Architecture

flowchart LR
    subgraph Client
        A[MCP Client<br/>Claude Code / MCP Inspector]
    end

    subgraph Server["mcp-shell-server-example (stdio)"]
        B[FastMCP server.py]
        T1[terminal<br/>PowerShell]
        T2[terminal_linux<br/>sh]
        T3[benign_tool<br/>curl fetch]
        R1[mcpreadme<br/>resource]
    end

    A <-- "JSON-RPC over stdio" --> B
    B --> T1
    B --> T2
    B --> T3
    B --> R1
    T1 -.-> H[(Host OS)]
    T2 -.-> C[(Container OS)]
    T3 -.-> G[(Remote gist)]

The client launches server.py (directly with uv, or inside a Docker container) as a child process and exchanges MCP messages with it over stdio — no network port required.

What this server exposes

Name Type Description
terminal Tool Runs a command via PowerShell on the host. Meant for local/Windows use.
terminal_linux Tool Runs a command via /bin/sh. Meant for use inside the Docker container.
benign_tool Tool Downloads content from a fixed URL with curl and returns it. Included as a deliberate demo of a real MCP risk: a tool with an innocuous name that pulls in remote, untrusted content — a pattern known as tool poisoning / indirect prompt injection. Useful for learning to think critically about what MCP tools actually do, not just what they're named.
mcpreadme Resource Returns the contents of mcpreadme.md.

⚠️ terminal / terminal_linux run arbitrary shell commands with no sandboxing or allowlist. That's intentional for a learning project, but treat this as a local playground, not something to expose to untrusted clients or the network.

Prerequisites

  • Python 3.12+
  • uv — used to manage the virtual environment and run the server
  • (Optional) Docker — to run the server in a container
  • (Optional) Node.js — needed to run MCP Inspector via npx

Running locally

git clone https://github.com/mohamedelamraoui1/mcp-shell-server-example.git
cd mcp-shell-server-example
uv sync
uv run server.py

The server then waits on stdio for an MCP client to connect — this is normal, it won't print anything and won't respond to plain typed text (it only understands JSON-RPC).

Running in Docker

docker build -t shell-server-app .
docker run -i --rm shell-server-app

Inside the container, use terminal_linux instead of terminal — PowerShell isn't installed in the (Debian-based) image.

Testing with MCP Inspector

MCP Inspector is a web UI for manually calling a server's tools/resources without needing a full AI client.

Against the local server:

uv run mcp dev server.py

Against the Docker image:

npx @modelcontextprotocol/inspector docker run -i --rm shell-server-app

Either command prints a local URL — open it, click Connect, then use the Tools tab to call terminal / terminal_linux / benign_tool, or the Resources tab to read mcpreadme.

Example: get "HELLO MCP" printed back via the terminal tool by passing this as the command argument:

echo " _   _      _ _       __  __  ____ ____  "
echo "| | | | ___| | | ___  |  \/  |/ ___|  _ \ "
echo "| |_| |/ _ \ | |/ _ \ | |\/| | |   | |_) |"
echo "|  _  |  __/ | | (_) || |  | | |___|  __/ "
echo "|_| |_|\___|_|_|\___/ |_|  |_|\____|_|    "

Connecting it to Claude Code (real-world usage)

This server was built and tested end-to-end using Claude Code as the MCP client — including scaffolding the server itself, containerizing it, and then wiring it back in as a live tool Claude Code could call. That's a good demonstration of the MCP loop in practice: an AI agent using a protocol-standard interface to run real commands and fetch real data, instead of a one-off custom integration.

To connect it yourself, add a .mcp.json file at your project root (Claude Code loads this automatically and asks you to approve it on startup):

{
  "mcpServers": {
    "m-shell-server": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/mcp-shell-server-example", "server.py"]
    }
  }
}

Restart Claude Code in that directory, approve the server when prompted, then check it's connected with /mcp. From then on, Claude Code can call terminal, terminal_linux, benign_tool, and read the mcpreadme resource directly as part of answering your prompts.

Project structure

.
├── server.py         # the MCP server: tools + resource definitions
├── mcpreadme.md       # content exposed via the mcpreadme resource
├── pyproject.toml     # project metadata + dependencies (managed by uv)
├── uv.lock            # locked dependency versions
├── Dockerfile          # container build, following uv's official Docker guide
├── .dockerignore
└── .mcp.json           # example Claude Code project-scoped MCP config

References

MCP Server · Populars

MCP Server · New