Session State
Implementing Session State Using FastMCP
To implement session state in our server, we will add a new parameter to the tool called name. This parameter will allow users to specify a name for their dog, and we will store that name in the session state so that it can be retrieved in future calls.
The parameter is optional, so users can still call the tool without providing a name. If a name is provided, we store it in session state under the key "dog_name". On subsequent calls where no name is given, we read it back from state — so the user only needs to introduce their dog once per session. We also modify the response to include the dog's name when it is available.
Here is the full updated server code with session state implemented:
cat > $HOME/workspace/puppy_guide/server/main.py << EOF
import os
from difflib import get_close_matches
from typing import Annotated
from dotenv import load_dotenv
from pydantic import Field
from fastmcp import Context
from fastmcp import FastMCP
from fastmcp.exceptions import ToolError
load_dotenv()
mcp = FastMCP(
name=os.getenv("MCP_NAME"),
instructions=os.getenv("MCP_INSTRUCTIONS"),
)
BREED_MULTIPLIERS = {
"labrador": 7,
"chihuahua": 5,
"german shepherd": 8,
"bulldog": 6,
}
def get_breed_multiplier(breed: str) -> int | None:
"""Fetch the age multiplier for a given dog breed."""
return BREED_MULTIPLIERS.get(breed.lower())
@mcp.tool
async def dog_to_human_age(
age: Annotated[int, Field(ge=0, le=30, description="The dog's age in years")],
breed: Annotated[str, Field(description="The dog's breed")],
ctx: Context,
# New optional parameter for the dog's name
name: Annotated[str | None, Field(description="The dog's name")] = None,
) -> str:
"""Calculate the real age of a dog in human years based on its breed."""
total_steps = 4
# If a name is provided, store it in session state for future calls
if name:
await ctx.set_state("dog_name", name)
else:
# No name provided — check if we stored one in a previous call
name = await ctx.get_state("dog_name")
# Progress: breed lookup
await ctx.report_progress(
progress=0,
total=total_steps,
message=f"Looking up breed multiplier for '{breed}'",
)
await ctx.info(f"Looking up breed multiplier for '{breed}'")
multiplier = get_breed_multiplier(breed)
if multiplier is None:
# Look for 1 similar breed name
suggestions = get_close_matches(
breed.lower(), BREED_MULTIPLIERS.keys(), n=1, cutoff=0.6
)
if suggestions:
await ctx.info(
f"Breed '{breed}' not found, but found similar: {suggestions}"
)
resultPractical MCP with FastMCP & LangChain
Engineering the Agentic ExperienceEnroll now to unlock current content and receive all future updates for free. Your purchase supports the author and fuels the creation of more exciting content. Act fast, as the price will rise as the course nears completion!
