Skip to main content
Glama
theddnc

Duck MCP Server

by theddnc
README.md
# Duck MCP Server šŸ¦†

A simple MCP (Model Context Protocol) server built with [FastMCP](https://gofastmcp.com/).

## Features

This server provides the following tools:
- **select_option**: Ask user to select one option from provided choices (uses elicitation)
- **provide_information**: Request additional information from user in natural language (uses elicitation)
- **request_manual_test**: Request the user to perform manual testing and report results (uses elicitation)

## Installation

### Prerequisites

- Python 3.10 or higher
- [uv](https://docs.astral.sh/uv/getting-started/installation/) (recommended) or pip

### Install Dependencies

Using uv (recommended):
```bash
uv sync
```

Using pip:
```bash
pip install -e .
```

## Usage

### Running the Server

#### Using the FastMCP CLI (recommended):
```bash
# Run with default configuration from fastmcp.json
fastmcp run

# Or specify the config file explicitly
fastmcp run fastmcp.json

# Run with HTTP transport for testing
fastmcp run --transport http --port 8000
```

#### Using Python directly:
```bash
python server.py
```

### Running with uv:
```bash
uv run fastmcp run server.py
```

### Development Mode

Run with the FastMCP Inspector UI:
```bash
fastmcp dev
```

### Inspect Server Capabilities

View all available tools, resources, and prompts:
```bash
fastmcp inspect
```

## Installing to MCP Clients

### Claude Desktop

```bash
fastmcp install claude-desktop
```

### Cursor

```bash
fastmcp install cursor
```

### Claude Code (VS Code Extension)

```bash
fastmcp install claude-code
```

## Testing

You can test the server using a FastMCP client:

```python
import asyncio
from fastmcp import Client

async def test_server():
    async with Client("http://localhost:8000/mcp") as client:
        # Ping the server to check connectivity
        await client.ping()
        print("Server is running!")

if __name__ == "__main__":
    asyncio.run(test_server())
```

### Testing Elicitation Tools

The `select_option`, `provide_information`, and `request_manual_test` tools use FastMCP's elicitation feature to interactively request information from users:

```python
import asyncio
from fastmcp import Client

async def elicitation_handler(message: str, response_type: type, params, context):
    """Handler that responds to server's elicitation requests"""
    print(f"Server asks: {message}")
    user_input = input("Your response: ")
    return response_type(selected_option=user_input) if hasattr(response_type, '__annotations__') and 'selected_option' in response_type.__annotations__ else response_type(information=user_input)

async def test_elicitation():
    async with Client("http://localhost:8000/mcp", elicitation_handler=elicitation_handler) as client:
        # Test select_option tool
        result = await client.call_tool("select_option", {
            "question": "What's your favorite programming language?",
            "options": ["Python", "JavaScript", "Rust", "Go"]
        })
        print(result.data)
        
        # Test provide_information tool
        result = await client.call_tool("provide_information", {
            "question": "What would you like to build today?"
        })
        print(result.data)
        
        # Test request_manual_test tool
        result = await client.call_tool("request_manual_test", {
            "test_description": "Navigate to the login page and verify the form renders correctly",
            "expected_outcome": "Login form should display username/password fields and submit button"
        })
        print(result.data)

if __name__ == "__main__":
    asyncio.run(test_elicitation())
```

## Project Structure

```
duck-mcp/
ā”œā”€ā”€ server.py          # Main server implementation
ā”œā”€ā”€ fastmcp.json       # FastMCP configuration
ā”œā”€ā”€ pyproject.toml     # Project metadata and dependencies
ā”œā”€ā”€ README.md          # This file
└── tests/            # Test files (optional)
```

## Development

### Adding New Tools

To add a new tool to the server, simply decorate a function with `@mcp.tool`:

```python
@mcp.tool
def my_new_tool(arg1: str, arg2: int) -> str:
    """Description of what this tool does"""
    # Your implementation here
    return "result"
```

### Running Tests

```bash
pytest
```

## Deployment

### Local Deployment

The server runs with stdio transport by default, making it compatible with local MCP clients like Claude Desktop.

### HTTP Deployment

For remote access, run with HTTP transport:

```bash
fastmcp run --transport http --host 0.0.0.0 --port 8000
```

### FastMCP Cloud

Deploy to FastMCP Cloud for managed hosting (requires account):

```bash
fastmcp cloud deploy
```

## Configuration

The `fastmcp.json` file contains the server configuration:

- **source**: Location and entrypoint of the server code
- **environment**: Python version and dependencies
- **deployment**: Runtime configuration (transport, logging, etc.)

You can override any configuration via CLI arguments:

```bash
fastmcp run --port 8080 --log-level DEBUG
```

### MCP Client Configuration

To use this MCP server with MCP-compatible clients (like Claude Desktop), add the following configuration to your client's `mcp.json` file:

#### Using uv (recommended):
```json
{
  "mcpServers": {
    "duck-mcp": {
      "command": "uv",
      "args": ["run", "fastmcp", "run", "server.py"],
      "cwd": "/path/to/duck-mcp"
    }
  }
}
```

#### Using Python directly:
```json
{
  "mcpServers": {
    "duck-mcp": {
      "command": "python",
      "args": ["server.py"],
      "cwd": "/path/to/duck-mcp"
    }
  }
}
```

Replace `/path/to/duck-mcp` with the actual path to your duck-mcp directory. The `cwd` (current working directory) ensures the server runs from the correct location.

## Learn More

- [FastMCP Documentation](https://gofastmcp.com/)
- [Model Context Protocol](https://modelcontextprotocol.io/)
- [FastMCP GitHub](https://github.com/jlowin/fastmcp)

## License

MIT

TDQS

B3.4/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a distinct purpose: providing information, requesting manual tests, and selecting options. There is no overlap or ambiguity between them.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern (provide_information, request_manual_test, select_option), with clear and descriptive naming.

Tool Count4/5

With 3 tools, the set is minimal but well-scoped for a server focused on user interaction requests. It is slightly thin but appropriate for its apparent purpose.

Completeness3/5

The tools cover key user elicitation tasks (info, manual test, option selection), but lack general action requests or confirmations, leaving some gaps in the interaction surface.

Maintenance

ActivityInactive
ResponsivenessNo issues