$ workshop --start mcp-agents

AI Agent Workshop
Mastering MCP

Bygg, utvid og deploy intelligente agenter med Model Context Protocol

Lars Søraas & Leif Terje Fonnes | Januar 2026

// Arkitektur

MCP gir agenter tilgang til den virkelige verden gjennom standardisert verktøyoppdagelse

Web Grensesnitt :8080 AI Agent :8001 MCP Server :8000 HTTP JSON-RPC 2.0 tools/list • tools/call get_weather • get_news • ...
Agent (OpenAI)
MCP Protokoll
Verktøy

$ Hurtigstart

Sett opp utviklingsmiljøet ditt på under 5 minutter

1

Installer uv

uv er en rask Python-pakkehåndterer som gir deg Python og avhengigheter i ett verktøy.

installer uv
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
2

Opprett prosjekt

Lag et nytt Python-prosjekt og installer FastMCP med avhengigheter:

prosjektoppsett
mkdir weather-mcp && cd weather-mcp
uv init
uv add fastmcp httpx python-dotenv
3

Konfigurer API-nøkkel

Opprett en .env fil i prosjektmappen:

.env
OPENWEATHER_API_KEY=din-api-nøkkel-her

Hvor får du API-nøkkel?

Registrer en gratis konto på openweathermap.org/api og generer en API-nøkkel under "Current Weather Data" (gratis tier).

Klar til å kode!

Miljøet er klart. Neste steg: bygg din første MCP-server med FastMCP.

# Værtjeneste med FastMCP

En komplett MCP-server for vær — klar på under 50 linjer Python

Opprett weather_server.py

weather_server.py
import os
import httpx
from dotenv import load_dotenv
from fastmcp import FastMCP

load_dotenv()

mcp = FastMCP("Værtjeneste")

API_KEY = os.environ["OPENWEATHER_API_KEY"]
BASE_URL = "https://api.openweathermap.org/data/2.5"


@mcp.tool()
async def get_weather(city: str) -> str:
    """Hent gjeldende vær for en by.

    Args:
        city: Navnet på byen, f.eks. 'Oslo', 'Bergen', 'Tromsø'
    """
    async with httpx.AsyncClient() as client:
        resp = await client.get(
            f"{BASE_URL}/weather",
            params={
                "q": city,
                "appid": API_KEY,
                "units": "metric",
                "lang": "no",
            },
        )
        resp.raise_for_status()
        data = resp.json()

    return (
        f"Vær i {data['name']}:\n"
        f"  Temperatur: {data['main']['temp']}°C "
        f"(føles som {data['main']['feels_like']}°C)\n"
        f"  Beskrivelse: {data['weather'][0]['description']}\n"
        f"  Fuktighet: {data['main']['humidity']}%\n"
        f"  Vind: {data['wind']['speed']} m/s"
    )


@mcp.tool()
async def get_forecast(city: str, hours: int = 24) -> str:
    """Hent værvarsel for en by.

    Args:
        city: Navnet på byen
        hours: Timer fremover (3-120, steg på 3)
    """
    async with httpx.AsyncClient() as client:
        resp = await client.get(
            f"{BASE_URL}/forecast",
            params={
                "q": city,
                "appid": API_KEY,
                "units": "metric",
                "lang": "no",
            },
        )
        resp.raise_for_status()
        data = resp.json()

    entries = data["list"][: max(1, hours // 3)]
    lines = [f"Værvarsel for {data['city']['name']}:\n"]
    for e in entries:
        lines.append(
            f"  {e['dt_txt']}  {e['main']['temp']:+.0f}°C  "
            f"{e['weather'][0]['description']}"
        )
    return "\n".join(lines)

Kjør og test

terminal
# Start MCP Inspector (åpner nettleser med testgrensesnitt)
uv run fastmcp dev weather_server.py

# Eller installer direkte i Claude Desktop
uv run fastmcp install weather_server.py

// MCP Inspector

  1. 1. Kjør fastmcp dev
  2. 2. Åpne nettleseren på adressen som vises
  3. 3. Klikk "List Tools" for å se verktøyene
  4. 4. Test get_weather med en by

// Claude Desktop

  1. 1. Kjør fastmcp install
  2. 2. Start Claude Desktop på nytt
  3. 3. Se etter hammer-ikonet i chat
  4. 4. Spør: "Hva er været i Oslo?"

Hva er FastMCP?

FastMCP er et Python-rammeverk som gjør det enkelt å bygge MCP-servere. Med dekoratorer som @mcp.tool(), @mcp.resource() og @mcp.prompt() kan du eksponere Python-funksjoner som MCP-verktøy med minimal kode.

Når MCP Inspector viser verktøyene og du kan hente værdata, er du klar for oppgavene!

> Oppgaver

To hands-on oppgaver som bygger videre på værserveren (~30 min hver)

Utvid weather_server.py med smarte verktøy som bruker værdata til noe nyttig. Du lærer å bruke @mcp.tool(), @mcp.resource() og @mcp.prompt().

A Legg til klesanbefaling

Lag et verktøy suggest_clothing som henter været for en by og anbefaler klær basert på temperatur, vind og nedbør.

weather_server.py - nytt verktøy
@mcp.tool()
async def suggest_clothing(city: str) -> str:
    """Anbefal klær basert på gjeldende vær i en by.

    Args:
        city: Navnet på byen
    """
    # 1. Hent værdata (gjenbruk logikk fra get_weather)
    async with httpx.AsyncClient() as client:
        resp = await client.get(
            f"{BASE_URL}/weather",
            params={
                "q": city,
                "appid": API_KEY,
                "units": "metric",
                "lang": "no",
            },
        )
        resp.raise_for_status()
        data = resp.json()

    temp = data["main"]["temp"]
    wind = data["wind"]["speed"]
    description = data["weather"][0]["description"]

    # 2. Bygg anbefalinger basert på forholdene
    clothes = []
    if temp < 0:
        clothes.extend(["Vinterjakke", "Lue", "Hansker", "Skjerf"])
    elif temp < 10:
        clothes.extend(["Varm jakke", "Genser", "Lange bukser"])
    elif temp < 20:
        clothes.extend(["Lett jakke", "Langermet skjorte"])
    else:
        clothes.extend(["T-skjorte", "Shorts eller lett bukse"])

    if wind > 10:
        clothes.append("Vindtett ytterlag")
    if "regn" in description or "rain" in description:
        clothes.extend(["Regntett jakke", "Vanntette sko"])

    return (
        f"Klesanbefaling for {data['name']} "
        f"({temp:.0f}°C, {description}):\n\n"
        + "\n".join(f"  - {item}" for item in clothes)
    )

B Legg til bysammenligning

Lag et verktøy compare_weather som sammenligner været i to byer side om side.

din oppgave
@mcp.tool()
async def compare_weather(city_a: str, city_b: str) -> str:
    """Sammenlign været mellom to byer.

    Args:
        city_a: Første by
        city_b: Andre by
    """
    # Din implementasjon her!
    # Tips:
    #   - Hent værdata for begge byer (bruk httpx)
    #   - Sammenlign temperatur, vind, fuktighet
    #   - Returner en formatert sammenligning
    ...

C Legg til en ressurs

MCP-ressurser gir AI-modellen tilgang til data den kan referere til. Legg til en liste over populære norske byer:

weather_server.py - ressurs
@mcp.resource("weather://cities")
def get_cities() -> str:
    """Liste over støttede norske byer."""
    cities = [
        "Oslo", "Bergen", "Trondheim", "Stavanger",
        "Tromsø", "Kristiansand", "Drammen", "Bodø",
        "Fredrikstad", "Ålesund",
    ]
    return "\n".join(cities)

D Legg til en prompt-mal

MCP-prompts er maler som AI-klienten kan bruke. Lag en "daglig oppdatering"-prompt:

weather_server.py - prompt
@mcp.prompt()
def daily_briefing(city: str) -> str:
    """Generer en morgenrapport for været."""
    return (
        f"Gi meg en kort og hyggelig morgenrapport for {city}. "
        f"Bruk get_weather og get_forecast for å hente data. "
        f"Inkluder: gjeldende vær, varsel for resten av dagen, "
        f"og et forslag til klær (bruk suggest_clothing). "
        f"Skriv på norsk og hold det kort."
    )

Test alt

terminal
# Start MCP Inspector
uv run fastmcp dev weather_server.py

# Sjekk at alle 4 verktøy vises under "Tools"
# Sjekk at ressursen vises under "Resources"
# Sjekk at prompten vises under "Prompts"
# Test hvert verktøy med ulike byer

Når alle verktøy, ressursen og prompten fungerer i Inspector, er oppgave 1 fullført!

Bonus: Installer i Claude Desktop og spør "Bruk daily_briefing for Oslo"

Bygg en ny MCP-server fra bunnen av! Turplanleggeren skal hjelpe brukere med å planlegge turer ved å kombinere stedsinformasjon med værdata.

Tips

Bruk gjerne Claude, Copilot eller lignende verktøy til å hjelpe deg med implementasjonen. Del opp i små steg og test underveis!

A Opprett ny server

Lag en ny fil trip_planner.py i samme prosjekt:

trip_planner.py - grunnstruktur
import os
import httpx
from dotenv import load_dotenv
from fastmcp import FastMCP

load_dotenv()

mcp = FastMCP("Turplanlegger")

API_KEY = os.environ["OPENWEATHER_API_KEY"]

# Enkel database over norske reisemål
DESTINATIONS = {
    "Oslo": {
        "type": "storby",
        "highlights": ["Operaen", "Vigelandsparken", "Munchmuseet"],
        "activities": ["museum", "shopping", "mat", "arkitektur"],
    },
    "Bergen": {
        "type": "kystby",
        "highlights": ["Bryggen", "Fløibanen", "Fisketorget"],
        "activities": ["fjordcruise", "vandring", "mat", "historie"],
    },
    "Lofoten": {
        "type": "natur",
        "highlights": ["Reine", "Haukland strand", "Trollfjorden"],
        "activities": ["vandring", "fiske", "kajakk", "nordlys"],
    },
    "Tromsø": {
        "type": "nordnorsk",
        "highlights": ["Ishavskatedralen", "Fjellheisen", "Polaria"],
        "activities": ["nordlys", "hundekjøring", "hvalsafari", "vandring"],
    },
    "Trondheim": {
        "type": "historisk",
        "highlights": ["Nidarosdomen", "Bakklandet", "Festung Kristiansten"],
        "activities": ["historie", "sykkel", "mat", "kultur"],
    },
}

B Implementer reisemål-anbefaling

Lag et verktøy som anbefaler reisemål basert på brukerens interesser:

din oppgave
@mcp.tool()
async def suggest_destination(interests: list[str]) -> str:
    """Anbefal et norsk reisemål basert på interesser.

    Args:
        interests: Liste med interesser, f.eks. ['vandring', 'mat', 'historie']
    """
    # Din implementasjon her!
    # Tips:
    #   - Gå gjennom DESTINATIONS
    #   - Tell treff på aktiviteter vs. interesser
    #   - Hent været for de beste forslagene
    #   - Returner en rangert liste med begrunnelse
    ...

C Lag en pakkeliste-generator

Lag et verktøy som genererer en pakkeliste basert på reisemål, varighet og værvarsel:

din oppgave
@mcp.tool()
async def packing_list(destination: str, days: int = 3) -> str:
    """Generer en pakkeliste basert på reisemål og værvarsel.

    Args:
        destination: Reisemål (by eller sted)
        days: Antall dager (1-14)
    """
    # Din implementasjon her!
    # Tips:
    #   - Hent værvarsel for destinasjonen
    #   - Sjekk temp-spenn, nedbør, vind
    #   - Baseklær + vær-spesifikke ting + aktivitetsutstyr
    #   - Returner en ryddig, kategorisert liste
    ...

D Lag en dagsplan

Lag et verktøy som planlegger en dag på et reisemål:

din oppgave
@mcp.tool()
async def day_plan(destination: str, interests: list[str]) -> str:
    """Lag en dagsplan for et reisemål.

    Args:
        destination: Reisemål
        interests: Hva brukeren er interessert i
    """
    # Din implementasjon her!
    # Tips:
    #   - Bruk DESTINATIONS for å finne highlights
    #   - Hent været for å tilpasse planen
    #   - Lag en tidsplan (morgen, formiddag, lunsj, ettermiddag, kveld)
    #   - Gi konkrete forslag basert på interesser og vær
    ...

E Legg til ressurs og prompt

Fullfør serveren med en ressurs og en prompt:

din oppgave
@mcp.resource("trips://destinations")
def list_destinations() -> str:
    """Oversikt over tilgjengelige reisemål."""
    # Returner en formatert liste over DESTINATIONS
    # med type og aktiviteter for hvert sted
    ...

@mcp.prompt()
def plan_trip(destination: str, days: int) -> str:
    """Planlegg en komplett tur."""
    return (
        f"Hjelp meg å planlegge en {days}-dagers tur til {destination}. "
        f"Bruk suggest_destination for å bekrefte valget, "
        f"packing_list for pakkeliste, og day_plan for "
        f"hver dag. Presenter alt ryddig på norsk."
    )

Test serveren

terminal
# Test turplanleggeren
uv run fastmcp dev trip_planner.py

# Test i Inspector:
#   - suggest_destination med interests=["vandring", "natur"]
#   - packing_list med destination="Bergen", days=3
#   - day_plan med destination="Oslo", interests=["mat", "kultur"]

Når alle verktøy fungerer og gir fornuftige svar, er oppgave 2 fullført!

Bonus: Installer begge servere i Claude Desktop!

installer begge
uv run fastmcp install weather_server.py
uv run fastmcp install trip_planner.py

# Spør Claude: "Planlegg en 3-dagers tur til Bergen.
# Sjekk været og lag en pakkeliste."

{} Teknisk Referanse

FastMCP-dekoratorer, MCP-konsepter og nyttige kommandoer

// FastMCP Dekoratorer

Dekorator Beskrivelse
@mcp.tool() Eksponer en funksjon som MCP-verktøy
@mcp.resource(uri) Eksponer data som en lesbar ressurs
@mcp.prompt() Definer en gjenbrukbar prompt-mal

// MCP Konsepter

Konsept Forklaring
Tools Funksjoner AI-en kan kalle (handlinger)
Resources Data AI-en kan lese (kontekst)
Prompts Maler for vanlige oppgaver (arbeidsflyter)

// Nyttige kommandoer

Utvikling og testing

# Start MCP Inspector
uv run fastmcp dev server.py

# Kjør server direkte
uv run python server.py

# Installer i Claude Desktop
uv run fastmcp install server.py

# Installer med navn
uv run fastmcp install server.py \
  --name "Min Server"

Prosjektoppsett

# Nytt prosjekt med uv
uv init && uv add fastmcp httpx

# Claude Desktop config (macOS)
cat ~/Library/Application\ Support/\
  Claude/claude_desktop_config.json

# Claude Desktop config (Windows)
cat %APPDATA%\Claude\
  claude_desktop_config.json

@ Ta kontakt

Spørsmål om workshopen eller ønsker en gjennomkjøring for teamet ditt? Send oss en melding.

Om workshopen

  • Hands-on med MCP, FastMCP og AI-agenter
  • Ettermiddag/kveld 2-3 timer
  • Hos dere, hos oss eller remote
  • Tilpasses nivå og behov

E-post

Lokasjon

Bergen, Norge

Svartid: Vi svarer normalt innen 24 timer på virkedager.