mcp-shell-server-example
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-shell-server-examplerun 'ls' to list files"
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-shell-server-example
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.
Related MCP server: Vulnerable MCP Server
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 |
| Tool | Runs a command via PowerShell on the host. Meant for local/Windows use. |
| Tool | Runs a command via |
| Tool | Downloads content from a fixed URL with |
| Resource | Returns the contents of |
⚠️
terminal/terminal_linuxrun 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.pyThe 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-appInside 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.pyAgainst the Docker image:
npx @modelcontextprotocol/inspector docker run -i --rm shell-server-appEither 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 configReferences
Available Tools
3 toolsbenign_toolD
Download content from a specified URL using curl.
Returns:
A dictionary containing the downloaded content and status
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must bear full burden. It mentions using curl but lacks details on behavioral traits like error handling, timeouts, or side effects. The core issue is the mismatch between the described action and the lack of a URL parameter.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short but fails to include essential information. It is not well-structured as it omits the critical detail of how the URL is provided, making it inadequate despite its brevity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool claims to download content but provides no mechanism for specifying the URL. The description does not explain how the tool operates without parameters. The presence of an output schema is mentioned but not provided, leaving the tool functionally incomplete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% because there are no parameters, but the description references a 'specified URL' which implies a parameter that does not exist. This contradicts the input schema, adding no value and causing confusion.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the tool downloads content from a URL using curl, which is a specific verb+resource. However, it claims a 'specified URL' but the input schema has no parameters, making the purpose unclear and potentially misleading. It does not distinguish itself from sibling tools terminal and terminal_linux.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided on when to use this tool versus alternatives. The description simply states what it does without any context about prerequisites, limitations, or when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
terminalC
Run a shell command on the local machine and return its output.
Args:
command: The shell command to execute.
| Name | Required | Description | Default |
|---|---|---|---|
| command | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, and the description fails to disclose the destructive potential, security risks, or side effects of executing arbitrary shell commands. The description merely states the obvious functionality.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Very concise but at the expense of missing critical information. The description is efficient but incomplete.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's dangerous nature (running shell commands), the description lacks necessary warnings, return value details, and behavioral context. Completely inadequate for a high-risk tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, and the description adds minimal value by explaining that 'command' is a shell command, which is already implied by the parameter name.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states it runs a shell command on the local machine, but does not differentiate from sibling tool 'terminal_linux' which may have a different scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this tool vs alternatives, no prerequisites or caveats provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
terminal_linuxC
Run a shell command inside the container (Linux sh) and return its output.
Args:
command: The shell command to execute.
| Name | Required | Description | Default |
|---|---|---|---|
| command | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided; the description does not disclose potential side effects, error handling, timeouts, or destructive capabilities of commands. For a command execution tool, this is minimal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is very short (one sentence plus an Args line) and concise, but lacks structure such as front-loading critical context or separating usage notes.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple schema (one required parameter, no output schema, no annotations), the description covers the basic purpose and environment. However, it misses safety warnings and error behavior, which are important for command execution.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% (no descriptions in schema); the description only says 'The shell command to execute', adding little beyond the schema title 'Command'. No format, constraints, or examples provided.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it runs a shell command inside a container using Linux sh, with a specific verb 'Run' and resource 'shell command inside the container'. It distinguishes from sibling 'terminal' by specifying the shell type.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this tool versus the sibling 'terminal' or other alternatives. No context on prerequisites, security considerations, or when not to use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
3 tool updates
v0.1.0- First observed
benign_tool - First observed
terminal - First observed
terminal_linux
TDQS
Tools have distinct functions: benign_tool downloads via curl, terminal runs local commands, terminal_linux runs containerized commands. However, the two terminal tools share the same core purpose (shell execution) and could be confused without careful reading.
Names use snake_case, but 'benign_tool' does not follow a verb_noun pattern like the others. 'terminal' and 'terminal_linux' are similar but 'terminal' is generic, breaking consistency.
Three tools is appropriate for a shell server focused on command execution and file retrieval. No unnecessary bloat or insufficiency.
Covers core shell operations with local and containerized execution, plus URL downloads. Minor gap: no file management or process control tools, but essential workflows are supported.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Security scanner for MCP servers. Detect vulnerabilities, prompt injection, and tool poisoning.
Scan any MCP server for tool-poisoning, security, auth & license. Trust score before install.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA simple MCP Server with shell execution capabilities that can be run locally with Ngrok tunneling or hosted in an Ubuntu 24 Docker container.4MIT
- FlicenseNot gradedqualityDmaintenanceAn educational MCP server demonstrating common security vulnerabilities like command injection, path traversal, SQL injection, and XXE attacks. Designed for security training purposes only, not for production use.-
- AlicenseNot gradedqualityDmaintenanceAn educational MCP server that exposes system tools (like IP, hostname, file operations, ping) for AI agents to execute via HTTP.225MIT
- FlicenseNot gradedqualityDmaintenanceA deliberately insecure MCP server designed as a pentest lab to demonstrate common vulnerabilities in MCP deployments.-
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/mohamedelamraoui1/mcp-shell-server-example'
If you have feedback or need assistance with the MCP directory API, please join our Discord server