| marp | true |
|---|---|
| theme | default |
| paginate | true |
| backgroundColor | |
| color | |
| header | 🤖 AI Agent Workshop - Model Context Protocol |
| footer | Lars Søraas | September 2025 |
| style | section { font-size: 24px; line-height: 1.3; padding: 40px; } h1 { font-size: 42px; margin-bottom: 0.4em; margin-top: 0.2em; } h2 { font-size: 32px; margin-bottom: 0.3em; margin-top: 0.2em; } h3 { font-size: 28px; margin-bottom: 0.2em; margin-top: 0.2em; } li { margin-bottom: 0.2em; } code { font-size: 18px; } pre { font-size: 16px; line-height: 1.2; margin: 0.5em 0; } ul, ol { margin: 0.5em 0; } |
Lars Søraas
15 Oktober 2025
- Forstå MCP arkitektur og konsepter
- Bygge din egen AI agent med verktøy
- Utvide systemet med nye funksjoner
- Deploye ved hjelp av Docker containere
- Lære beste praksis for produksjon
- Introduksjon til MCP (15 min)
- Arkitektur Oversikt (15 min)
- Hands-on: Utforske Koden (20 min)
- Bygging av Verktøy (30 min)
- Deployment & Testing (20 min)
- Avanserte Funksjoner (20 min)
- Spørsmål & Neste Steg (10 min)
- AI modeller er kraftige men isolerte
- Trenger tilgang til sanntidsdata
- Ønsker å utføre handlinger i verden
- Sikkerhet og standardisering utfordringer
- Standardisert protokoll for AI-verktøy integrasjon
- Sikker og strukturert kommunikasjon
- Utvidbar arkitektur for alle verktøy
https://modelcontextprotocol.io/specification/2025-06-18 + https://modelcontextprotocol.io/docs/getting-started/intro
- 🔧 Standardisert verktøy-grensesnitt
- 🛡️ Innebygde sikkerhetsmønstre
- 📈 Skalerbar arkitektur
- 🔄 Gjenbrukbare komponenter
- 🌐 Tilgang til eksterne APIer
- 💾 Sanntids data-henting
- ⚡ Utføre handlinger
- 🧠 Forbedret resonnering med kontekst
┌─────────────────┐ HTTP ┌─────────────────┐ HTTP ┌─────────────────┐
│ Web Frontend │◄────────► │ AI Agent │◄────────►│ MCP Server │
│ │ │ │ │ │
│ (HTML/JS) │ │ (OpenAI) │ │ (Verktøy) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Samtale │ │ Eksterne APIer │
│ Minne (SQLite) │ │ (OpenWeather) │
└─────────────────┘ └─────────────────┘
- Eksponerer verktøy via HTTP API
- Håndterer ekstern API integrasjon
- Prosesserer brukerforespørsler med OpenAI
- Kaller MCP verktøy når nødvendig
- Enkelt HTML frontend for testing
- Sanntids interaksjon med agent
Oppstart (én gang):
0. Agent → MCP Server: GET /tools (hent tilgjengelige verktøy)
Per forespørsel:
- Web → Agent: Brukerforespørsel
- Agent → OpenAI: "Bruker vil ha vær for Oslo"
- OpenAI → Agent: "Bruk get_weather_forecast verktøy"
- Agent → MCP Server:
POST /weathermed parametere - MCP Server → OpenWeather API: Hent værdata
- MCP Server → Agent: Vær respons
- Agent → OpenAI: "Formater denne værdataen"
- Agent → Web: Formatert svar til bruker
2. Lag en fork av https://github.com/zral/mcp-ws
1. Gå til https://github.com/marketplace/models
5. Register deg gratis på https://openweathermap.org/api og hent ut API Key
agent/
├── docker-compose.yml # 🐳 Container orkestrering
├── .env.example # 🔐 Miljøvariabler
├── services/
│ ├── mcp-server/ # 🔧 Verktøy server
│ │ └── app.py # ⭐ Hoved server logikk
│ ├── agent/ # 🤖 AI agent
│ │ ├── app.py # ⭐ Agent implementasjon
│ │ └── conversation_memory.py
│ └── web/ # 🌐 Frontend
# Tools endpoint - eksponerer tilgjengelige verktøy til agent
@app.get("/tools")
async def list_tools():
"""List available tools according to MCP specification."""
tools = [
{
"name": "get_weather_forecast",
"description": "Hent værprognose for en destinasjon",
"inputSchema": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "Navn på by"}
},
"required": ["location"]
}
}
]
return {"tools": tools}
# Værverktøy implementasjon
@app.post("/weather")
async def get_weather(request: WeatherRequest):
"""Hent værvarsel for en lokasjon."""
coords = await geocode_location(request.location)
weather_data = await fetch_weather_data(coords)
return {"success": True, "data": weather_data}# services/agent/app.py
# Tools hentes dynamisk fra MCP server ved oppstart
async def load_tools_from_mcp_server(self):
"""Hent tilgjengelige tools fra MCP server."""
response = await self.http_client.get(f"{self.mcp_server_url}/tools")
mcp_tools = response.json()
# Konverter fra MCP format til OpenAI function calling format
for tool in mcp_tools.get("tools", []):
openai_tool = {
"type": "function",
"function": {
"name": tool["name"],
"description": tool["description"],
"parameters": tool["inputSchema"]
}
}
self.tools.append(openai_tool)- Agent henter tools automatisk fra MCP server ved oppstart
- Ingen hardkoding av verktøydefinisjon i agent-kode
- MCP standard for tools exchange
- Kun endre MCP server for å legge til nye verktøy
- Agent restarter automatisk med nye tools
- Løs kobling mellom komponenter
- Flere MCP servere kan eksponere forskjellige verktøy
- Plugin arkitektur for nye funksjonaliteter
https://modelcontextprotocol.io/specification/2025-06-18/server/tools
# Når OpenAI vil bruke et verktøy
if response_message.tool_calls:
for tool_call in response_message.tool_calls:
tool_name = tool_call.function.name
tool_args = json.loads(tool_call.function.arguments)
# Kall MCP server
tool_result = await self.call_mcp_tool(tool_name, tool_args)
# Legg til resultat i samtalen
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(tool_result)
})# Start systemet
docker-compose up -d
# Test tools endpoint - se tilgjengelige verktøy
curl -s "http://localhost:8000/tools" | python3 -m json.tool
# Test MCP server direkte
curl -X POST "http://localhost:8000/weather" \
-H "Content-Type: application/json" \
-d '{"location": "Oslo"}'
# Test via agent
curl -X POST "http://localhost:8001/query" \
-H "Content-Type: application/json" \
-d '{"query": "Hva er været i Bergen?"}'# I services/mcp-server/app.py
class FactRequest(BaseModel):
category: str = "general"
@app.post("/fact")
async def get_random_fact(request: FactRequest):
"""Få et tilfeldig interessant faktum."""
facts = {
"general": ["Honningbien produserer mat spist av mennesker.",
"Bananer er bær, men jordbær er ikke det."],
"space": ["En dag på Venus er lengre enn året sitt.",
"Saturn ville flyte i vann."]
}
import random
fact = random.choice(facts.get(request.category, facts["general"]))
return MCPResponse(
success=True,
data={"category": request.category, "fact": fact},
timestamp=datetime.now().isoformat()
)# I services/mcp-server/app.py, oppdater list_tools():
@app.get("/tools")
async def list_tools():
tools = [
{
"name": "get_weather_forecast",
"description": "Hent værprognose for en destinasjon",
"inputSchema": { /* ... */ }
},
{
"name": "get_random_fact",
"description": "Få et tilfeldig interessant faktum",
"inputSchema": {
"type": "object",
"properties": {
"category": {
"type": "string",
"description": "Faktakategori (general, space)",
"default": "general"
}
}
}
}
]
return {"tools": tools}# Bygg på nytt og restart (agent henter tools ved oppstart)
docker-compose build mcp-server travel-agent
docker-compose up -d
# Test at tools er oppdatert
curl -s "http://localhost:8000/tools" | python3 -m json.tool
# Test det nye verktøyet
curl -X POST "http://localhost:8001/query" \
-H "Content-Type: application/json" \
-d '{"query": "Fortell meg et interessant faktum om verdensrommet"}'# I services/mcp-server/app.py
import httpx
class NewsRequest(BaseModel):
topic: str
language: str = "no"
@app.post("/tools/get_news")
async def get_news(request: NewsRequest):
"""Få nylige nyheter om et emne."""
api_key = os.getenv("NEWS_API_KEY")
async with httpx.AsyncClient() as client:
response = await client.get(
"https://newsapi.org/v2/everything",
params={
"q": request.topic,
"language": request.language,
"apiKey": api_key
}
)
news_data = response.json()
articles = [
{"title": article["title"], "url": article["url"]}
for article in news_data.get("articles", [])[:3]
]
return {"success": True, "topic": request.topic, "articles": articles}# Start fra bunnen av
docker-compose up --build
# Stopp alt
docker-compose down
# Bygg spesifikk tjeneste på nytt
docker-compose build mcp-server
# Se logger
docker-compose logs -f travel-agent
# Sjekk helse
curl http://localhost:8000/healthcp .env.example .env# .env
OPENAI_API_KEY=your-openai-api-key-here
OPENWEATHER_API_KEY=your-openweather-api-key-here
NEWS_API_KEY=your-news-api-key-here # Hvis du bruker news verktøydocker-compose up --build# Test MCP server endepunkter direkte
curl -X POST "http://localhost:8000/tools/get_weather_forecast" \
-H "Content-Type: application/json" \
-d '{"location": "Oslo"}'# Test gjennom agent
curl -X POST "http://localhost:8001/query" \
-H "Content-Type: application/json" \
-d '{"query": "Hva er været i dag?"}'Åpne http://localhost:8080 i nettleser
docker-compose logs service-namedocker-compose exec travel-agent env | grep APIcurl http://localhost:8001/health- Oppretthold kontekst mellom kall
- Brukerpreferanser og historie
- Sesjonshåndtering
- Langvarige oppgaver
- Bakgrunnsprosessering
- Fremdriftssporing
- Verktøy-kjeding
- Betinget logikk
- Feilhåndtering og retry
from pydantic import BaseModel, validator
class SecureRequest(BaseModel):
location: str
@validator('location')
def validate_location(cls, v):
if len(v) > 100:
raise ValueError('Lokasjon for lang')
# Legg til mer validering...
return vimport os
def get_api_key(service: str) -> str:
key = os.getenv(f"{service.upper()}_API_KEY")
if not key:
raise ValueError(f"Mangler {service} API nøkkel")
return key- Lastbalansering med flere agent instanser
- Database clustering for samtale minne
- Caching for ofte brukte verktøy-resultater
- Helsesjekk og oppetid overvåkning
- Logging aggregering (ELK stack)
- Metrics innsamling (Prometheus/Grafana)
- Feilsporing (Sentry)
- API rate limiting
- Input sanitisering
- HTTPS terminering
- Håndtering av hemmeligheter
- Vektordatabaser for semantisk søk
- Kunnskaps grafer for relasjoner
- Langsiktig læring og tilpasning
- Webhook endepunkter for sanntid oppdateringer
- Meldingskøer for asynkron prosessering
- Hendelsesdrevet arkitektur
- Bildeanalyse verktøy
- Lydprosessering
- Tolking av video
Vanskelighet: Nybegynner
Forbedre værverktøyet til å inkludere:
- UV-indeks informasjon
- Luftkvalitet data
- Soloppgang/solnedgang tider
Tips: OpenWeatherMap API gir all denne dataen i responsen!
Vanskelighet: Nybegynner
Lag et kalkulator verktøy som kan:
- Utføre grunnleggende matematiske operasjoner
- Håndtere komplekse uttrykk
- Vise steg-for-steg løsninger
# Verktøy idé
@app.post("/tools/calculate")
async def calculate(request: CalculationRequest):
# Din implementasjon her
passVanskelighet: Mellomnivå
Utvid agenten til å huske:
- Brukerpreferanser (favoritt byer, enheter)
- Tidligere samtaler
- Personaliserte anbefalinger
Filer å modifisere:
conversation_memory.py- Logikk for samtale med agent
Vanskelighet: Avansert
Lag en reiseplanlegging arbeidsflyt:
- Få vær for destinasjon
- Finn nærliggende attraksjoner
- Sjekk kalender tilgjengelighet
- Send e-post sammendrag
Krever: Flere API integrasjoner + logikk for arbeidsflyt
- Model Context Protocol grunnleggende
- AI agent arkitektur mønstre
- Verktøy-basert AI system design
- Bygge MCP-kompatible verktøy
- Integrere eksterne APIer sikkert
- Docker containerisering for AI systemer
- Strukturert feilhåndtering
- Sikkerhetsbetraktninger
- Testing strategier
- Utforsk MCP spesifikasjonen i dybden
- Studer avanserte AI agent mønstre
- Lær om vektor databaser og RAG
- Lag industri-spesifikke verktøy
- Implementer produksjon overvåkning
- Skaler til multi-tenant arkitektur
- Bli med i MCP utvikler community
- Bidra til open source verktøy
- Del implementasjoner
- Workshop repository:
github.com/your-repo/agent-workshop - Eksempel implementasjoner
- Utvidet verktøy bibliotek
Lars Søraas
📧 lsoraas@gmail.com
🐙 github.com/zral
- Start enkelt, iterer raskt
- Sikkerhet først, alltid
- Dokumentasjon er din venn
- Community er her for å hjelpe