Difference between revisions of "Module6-New2"

From CSE330 Wiki
Jump to navigationJump to search
Line 262: Line 262:
 
#* README includes 3 different example prompts used in Claude (2 points)
 
#* README includes 3 different example prompts used in Claude (2 points)
 
#*: ''Each example should show the prompt you asked and the MCP’s response.''
 
#*: ''Each example should show the prompt you asked and the MCP’s response.''
 +
 +
 +
--- NEW -----
 +
 +
 +
==== Verify Your MCP Server Works ====
 +
 +
Before connecting Claude Desktop, verify that your MCP server runs correctly.
 +
 +
Run your container manually:
 +
 +
<source lang="bash">
 +
docker run --rm -it cardinals-mcp-server:latest
 +
</source>
 +
 +
If everything is working correctly, you should see a startup message similar to:
 +
 +
<source lang="text">
 +
Starting Cardinals Historical Data MCP server...
 +
</source>
 +
 +
If the container exits with an error, fix the issue before continuing.
 +
 +
You can stop the container with:
 +
 +
<source lang="bash">
 +
Ctrl+C
 +
</source>
 +
 +
Do not attempt to connect Claude until the container runs successfully.
 +
 +
 +
==== Common Setup Mistakes ====
 +
 +
If Claude cannot see your MCP server, check the following:
 +
 +
'''Docker image was not built'''
 +
 +
You must run:
 +
 +
<source lang="bash">
 +
docker build -t cardinals-mcp-server:latest .
 +
</source>
 +
 +
before attempting to run the container.
 +
 +
'''Container name mismatch'''
 +
 +
The Docker image name in your Claude configuration must match the image name used during the build step.
 +
 +
Example:
 +
 +
<source lang="bash">
 +
docker build -t cardinals-mcp-server:latest .
 +
</source>
 +
 +
must match:
 +
 +
<source lang="json">
 +
"args": [
 +
  "run",
 +
  "--rm",
 +
  "-i",
 +
  "cardinals-mcp-server:latest"
 +
]
 +
</source>
 +
 +
'''Claude Desktop was not restarted'''
 +
 +
After editing the MCP configuration file, completely quit and reopen Claude Desktop.
 +
 +
'''The container exits immediately'''
 +
 +
This usually means your Python script crashed. Run the container manually to view the error:
 +
 +
<source lang="bash">
 +
docker run --rm -it cardinals-mcp-server:latest
 +
</source>
 +
 +
 +
==== What Claude Is Actually Doing ====
 +
 +
When you ask Claude a question such as:
 +
 +
<pre>
 +
Use CardinalsMCP to list the top 10 hitters from 1940.
 +
</pre>
 +
 +
the following process occurs:
 +
 +
<pre>
 +
User Prompt
 +
      ↓
 +
Claude reads the prompt
 +
      ↓
 +
Claude decides which tool to use
 +
      ↓
 +
Claude calls the MCP server
 +
      ↓
 +
Docker launches your container
 +
      ↓
 +
Your Python tool runs
 +
      ↓
 +
The results are returned to Claude
 +
</pre>
 +
 +
Claude never directly runs your Python code.
 +
 +
Your MCP server runs the code and sends the results back to Claude.
 +
 +
 +
==== Debugging Your MCP Server ====
 +
 +
If Claude does not return results, try the following:
 +
 +
'''Step 1: Verify the container runs'''
 +
 +
<source lang="bash">
 +
docker run --rm -it cardinals-mcp-server:latest
 +
</source>
 +
 +
'''Step 2: Verify your Python script loads'''
 +
 +
Your container should print a startup message when it launches.
 +
 +
'''Step 3: Verify tools exist'''
 +
 +
Claude should display available tools in the MCP indicator inside the chat interface.
 +
 +
'''Step 4: Check Claude configuration'''
 +
 +
Ensure the file:
 +
 +
<code>claude_desktop_config.json</code>
 +
 +
contains your MCP server configuration.
 +
 +
If necessary, restart Claude Desktop.
 +
  
 
[[Category:Module 6]]
 
[[Category:Module 6]]
 
[[Category:Modules]]
 
[[Category:Modules]]

Revision as of 18:21, 15 March 2026

In Module 6, you will learn the fundamentals of Python, a popular scripting language, and Regular Expressions, which give you power in text processing.

This article contains your assignments for Module 6.

Learning Goals

  • Regular Expressions
  • Python
  • MCP Fundamentals

Using the Wiki

Text enclosed by < and > should be replaced by content unique to you.

Example

$ sudo useradd -r -m -c "<My Full Name>" <usernameHere>

becomes

$ sudo useradd -r -m -c "Zach Cohn" zcohn

Reading

The following articles on the online class wiki textbook contain information that will help you complete the assignments.

Individual Assignments

Learn Python and Regular Expressions

Up to this point in CSE 3300, you have used two programming languages: PHP and JavaScript. In Module 6, you will learn a new language: Python.

Before starting this assignment review:

You should use Python version 3 or greater.

Write some Regular Expressions

Please write regular expressions that do each of the following:

  1. Match the substring "hello world"
  2. Match strings containing three or more consecutive vowels
  3. Match a flight code of format AA####

Save them as:

regex1.txt regex2.txt regex3.txt

Baseball Stats Counter

The St. Louis Cardinals are the most legendary baseball team in the national league.

In this exercise you will create a Python script that reads box scores from a file and computes the Cardinals' players' batting averages.

Input

Sample input files may be found here:

http://classes.engineering.wustl.edu/cse330/content/cardinals/

Output

Each line in the output should have the format:

XXX: #.###

Players should be sorted by batting average.

Baseball Stats MCP Extension

This project builds a custom MCP server that lets Claude Desktop explore St. Louis Cardinals batting data.

Goal

You will build a Python MCP server that:

  • reads Cardinals batting averages
  • lists team rosters
  • returns top hitters
  • allows player search
  • runs inside Docker
  • connects to Claude Desktop

Project Structure

cardinals-mcp/
├── Dockerfile
├── cardinals_server.py
├── requirements.txt
└── data/
    ├── cardinals-1930.txt
    └── cardinals-1940.txt

Step 1: Prerequisites

Install:

  • Docker Desktop
  • Claude Desktop

Step 2: Create the Files

cardinals_server.py
import os
import sys
import re
from datetime import datetime
from mcp.server.fastmcp import FastMCP

# Initialize MCP server
mcp = FastMCP("CardinalsMCP")

# Data file paths
DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
CARDINALS_1930_FILE = os.path.join(DATA_DIR, "cardinals-1930.txt")
CARDINALS_1940_FILE = os.path.join(DATA_DIR, "cardinals-1940.txt")

# ==== Helper Functions (You DO NOT need to use these) ====

def load_cardinals_data():
    """Load Cardinals player data from both 1930 and 1940 files."""
    data = {"1930": [], "1940": []}
    
    for year, file_path in [("1930", CARDINALS_1930_FILE), ("1940", CARDINALS_1940_FILE)]:
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
                data[year] = parse_player_data(content)
        except FileNotFoundError:
            logger.warning(f"Data file not found: {file_path}")
        except Exception as e:
            logger.error(f"Error loading {year} data: {e}")
    
    return data

def parse_player_data(content):
    """Parse player data from the simplified Cardinals text files."""
    players = []
    
    for line in content.split('\n'):
        line = line.strip()
        if not line or line.startswith('#'):
            continue
            
        if ':' in line:
            parts = line.split(':')
            if len(parts) == 2:
                name = parts[0].strip()
                try:
                    batting_avg = float(parts[1].strip())
                    players.append({
                        'name': name,
                        'batting_average': batting_avg
                    })
                except ValueError:
                    continue
    
    return players

def get_all_players(data):
    players=set()
    for year_data in data.values():
        for player in year_data:
            players.add(player['name'])
    return sorted(list(players))

def get_player_by_name(data, player_name):
    player_data=[]
    for year,year_data in data.items():
        for player in year_data:
            if player['name'].lower()==player_name.lower():
                player_data.append({
                    'year':year,
                    'name':player['name'],
                    'batting_average':player['batting_average']
                })
    return player_data

# ==== MCP Tools ====

@mcp.tool()
async def hello(name: str = "world") -> str:
    return f"Hello CSE 3300 Student, {name}!"

@mcp.tool()
async def get_player_stats(player: str = "") -> str:
    # TODO
  

@mcp.tool()
async def get_team_roster(year: str = "1930") -> str:
    # TODO
  

@mcp.tool()
async def get_top_players(year: str = "1930", limit: int = 10) -> str:
    # TODO


@mcp.tool()
async def search_players(search_term: str = "") -> str:
    # TODO

if __name__=="__main__":
    logger.info("Starting Cardinals Historical Data MCP server...")
    try:
        mcp.run(transport="stdio")
    except Exception as e:
        logger.error(f"Server error: {e}", exc_info=True)
        sys.exit(1)

Grading

We will be grading the following aspects of your work. There are 50 points total.

Assignments (including code) must be committed to Github by the end of class on the due date (commit early and often). Failing to commit by the end of class on the due date will result in a 0.

Upload your baseball code and a file with your Regular expressions.

  1. Regular Expressions (15 Points):
    • Your regex files should contain your regex (with no delimiters or flags) and nothing else.
    • Regular Expression 1 Correct and saved in a file named regex1.txt (5 points)
    • Regular Expression 2 Correct and saved in a file named regex2.txt (5 points)
    • Regular Expression 3 Correct and saved in a file named regex3.txt (5 points)
  1. Baseball Stats Counter (25 Points):
    • Solution is written entirely in Python and saved in a file named baseball.py (5 points)
      Note: Failing to write your code in Python 3 will result in losing, at a minimum, points for this category.
    • Correct usage of one or more regular expressions to parse and extract data from each line of the input file (5 points)
      Note: You should not be using str.split to extract data.
    • Script prints a usage message if a command line argument is not present (3 points)
      Note: For an example of a usage message, see https://en.wikipedia.org/wiki/Usage_message#Examples
    • Output is correct for all test cases (12 points)
      This includes sorting and rounding.
  1. Baseball Stats MCP Extension (10 Points):
    • Docker image builds successfully without errors (5 points)
      MCP server (`cardinals_server.py`) loads player data and returns correct results.
    • Includes at least 2 MCP tools (3 points)
      Each tool must function correctly and return expected output through Claude Desktop.
    • README includes 3 different example prompts used in Claude (2 points)
      Each example should show the prompt you asked and the MCP’s response.


--- NEW -----


Verify Your MCP Server Works

Before connecting Claude Desktop, verify that your MCP server runs correctly.

Run your container manually:

docker run --rm -it cardinals-mcp-server:latest

If everything is working correctly, you should see a startup message similar to:

Starting Cardinals Historical Data MCP server...

If the container exits with an error, fix the issue before continuing.

You can stop the container with:

Ctrl+C

Do not attempt to connect Claude until the container runs successfully.


Common Setup Mistakes

If Claude cannot see your MCP server, check the following:

Docker image was not built

You must run:

docker build -t cardinals-mcp-server:latest .

before attempting to run the container.

Container name mismatch

The Docker image name in your Claude configuration must match the image name used during the build step.

Example:

docker build -t cardinals-mcp-server:latest .

must match:

"args": [
  "run",
  "--rm",
  "-i",
  "cardinals-mcp-server:latest"
]

Claude Desktop was not restarted

After editing the MCP configuration file, completely quit and reopen Claude Desktop.

The container exits immediately

This usually means your Python script crashed. Run the container manually to view the error:

docker run --rm -it cardinals-mcp-server:latest


What Claude Is Actually Doing

When you ask Claude a question such as:

Use CardinalsMCP to list the top 10 hitters from 1940.

the following process occurs:

User Prompt
      ↓
Claude reads the prompt
      ↓
Claude decides which tool to use
      ↓
Claude calls the MCP server
      ↓
Docker launches your container
      ↓
Your Python tool runs
      ↓
The results are returned to Claude

Claude never directly runs your Python code.

Your MCP server runs the code and sends the results back to Claude.


Debugging Your MCP Server

If Claude does not return results, try the following:

Step 1: Verify the container runs

docker run --rm -it cardinals-mcp-server:latest

Step 2: Verify your Python script loads

Your container should print a startup message when it launches.

Step 3: Verify tools exist

Claude should display available tools in the MCP indicator inside the chat interface.

Step 4: Check Claude configuration

Ensure the file:

claude_desktop_config.json

contains your MCP server configuration.

If necessary, restart Claude Desktop.