mcp-server-tools-assignment
README.md
# Assignment 2: MCP Server with 5 Tools
This project implements a small Model Context Protocol (MCP) server with five tools and a client that calls them over stdio.
## What this project does
The server exposes five tools, each of which makes one GET request to a public API and returns only the relevant fields.
| Tool | Input | Public API | Returned data |
| --- | --- | --- | --- |
| `weather` | `city` | `https://wttr.in/{city}?format=j1` | `city`, `temp_c`, `condition`, `humidity` |
| `country_info` | `name` | `https://restcountries.com/v3.1/name/{name}` | `name`, `capital`, `region`, `population`, `currencies`, `languages` |
| `exchange_rates` | `base` | `https://open.er-api.com/v6/latest/{base}` | base currency + selected rates |
| `public_holidays` | `year`, `country_code` | `https://date.nager.at/api/v3/PublicHolidays/{year}/{country_code}` | list of holiday objects with `date`, `localName`, `name` |
| `define_word` | `word` | `https://api.dictionaryapi.dev/api/v2/entries/en/{word}` | `word` and one or more short definitions |
The client starts the server as a subprocess, lists the available tools, and calls each tool with sample input.
## Project structure
```text
mcp-server-tools-assignment/
├── client/
│ └── client.py
├── server/
│ ├── http.py
│ ├── server.py
│ └── tools/
│ ├── country.py
│ ├── dictionary.py
│ ├── exchange.py
│ ├── holidays.py
│ └── weather.py
├── config.py
├── README.md
├── requirements.txt
└── .venv/
```
## Setup
```bash
cd mcp-server-tools-assignment
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -r requirements.txt
```
## Run the server directly
```bash
cd mcp-server-tools-assignment
. .venv/bin/activate
python -m server.server
```
This starts the MCP server over stdio.
## Run the client
```bash
cd mcp-server-tools-assignment
. .venv/bin/activate
python client/client.py
```
This launches the server, lists the available tools, and calls each tool with sample data.
## Notes on behavior
- The project uses the `mcp` Python package and communicates over `stdio` transport.
- The server and client are separate Python programs.
- Each tool function makes one GET request to a public API and returns only the relevant fields.
- Error handling is included so that invalid input or API failures do not crash the server.
## Section 7 test cases and output
The following are the actual validation calls and representative outputs from the working project.
### 1) Weather
```python
{'city': 'Mumbai'}
```
Output:
```text
CASE:weather
{'meta': None, 'content': [{'type': 'text', 'text': '{\n "city": "Mumbai",\n "temp_c": 28.0,\n "condition": "Light rain shower",\n "humidity": 78\n}', 'annotations': None, 'meta': None}], 'structuredContent': None, 'isError': False}
```
### 2) Country info
```python
{'name': 'India'}
```
Output:
```text
CASE:country_info
{'meta': None, 'content': [{'type': 'text', 'text': '{\n "name": "India",\n "capital": "New Delhi",\n "region": "Asia",\n "population": 1380004385,\n "currencies": [\n "INR"\n ],\n "languages": [\n "Hindi",\n "English"\n ]\n}', 'annotations': None, 'meta': None}], 'structuredContent': None, 'isError': False}
```
### 3) Exchange rates
```python
{'base': 'USD'}
```
Output:
```text
CASE:exchange_rates
{'meta': None, 'content': [{'type': 'text', 'text': '{\n "base": null,\n "rates": {\n "USD": 1,\n "EUR": 0.862295,\n "INR": 95.581563,\n "GBP": 0.738249,\n "JPY": 160.045067,\n "AUD": 1.395915,\n "CAD": 1.389176,\n "SGD": 1.273831\n }\n}', 'annotations': None, 'meta': None}], 'structuredContent': None, 'isError': False}
```
### 4) Public holidays
```python
{'year': 2025, 'country_code': 'US'}
```
Output:
```text
CASE:public_holidays
{'meta': None, 'content': [{'type': 'text', 'text': '{\n "date": "2025-01-01",\n "localName": "New Year\'s Day",\n "name": "New Year\'s Day"\n}', ... ], 'structuredContent': None, 'isError': False}
```
The output contains multiple holiday records, which confirms the tool is returning a non-empty list.
### 5) Dictionary lookup
```python
{'word': 'example'}
```
Output:
```text
CASE:define_word
{'meta': None, 'content': [{'type': 'text', 'text': '{\n "word": "example",\n "definitions": [\n {\n "partOfSpeech": "noun",\n "meaning": "A thing characteristic of its kind or illustrating a general rule."\n },\n {\n "partOfSpeech": "verb",\n "meaning": "To serve as a pattern or model for others."\n }\n ]\n}', 'annotations': None, 'meta': None}], 'structuredContent': None, 'isError': False}
```
### 6) Failure path test
```python
{'word': 'asdfghjkl'}
```
Output:
```text
CASE:define_word
{'meta': None, 'content': [{'type': 'text', 'text': '{\n "word": "asdfghjkl",\n "definitions": [],\n "error": "not found"\n}', 'annotations': None, 'meta': None}], 'structuredContent': None, 'isError': False}
```
This confirms the tool does not crash on a nonsense word; it returns a clean `not found` response, while valid words return real definitions.
## Requirements
```text
mcp<2
requests>=2.31.0
```
## Purpose of the assignment
This assignment demonstrates how an MCP server exposes tools, how a client discovers them, and how the client calls them over stdio. It is a beginner-friendly example of how external APIs can be wrapped as tools that an AI or application can call in a structured and repeatable way.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues