Skip to content

Commit 5296fa8

Browse files
authored
Merge pull request #195 from esnible/deployment-for-weather-svc-and-tool
Feature: Deployment descriptor and README for weather agent and weather tool
2 parents 87da6df + 6a1c3d2 commit 5296fa8

7 files changed

Lines changed: 363 additions & 4 deletions

File tree

a2a/a2a_currency_converter/deployment/k8s.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ spec:
8383
- name: LLM_API_KEY
8484
value: dummy
8585
# For production, use a Secret:
86-
# - name: OPENAI_API_KEY
86+
# - name: LLM_API_KEY
8787
# valueFrom:
8888
# secretKeyRef:
8989
# name: llm-credentials

a2a/weather_service/.dockerignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
.venv
1+
.venv
2+
3+
deployment
4+

a2a/weather_service/README.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
11
# Agents
22

3-
Weather Service Agent
3+
The Weather Service Agent is an example of an [A2A](https://a2a-protocol.org/latest/) agent.
4+
5+
This agent depends on the Kagenti [Weather Tool](https://github.com/kagenti/agent-examples/tree/main/mcp/weather_tool). The weather tool should be running before chatting with the weather service agent.
6+
7+
## Run the agent on Kubernetes with Kagenti
8+
9+
You may deploy using Kagenti's UI or through a Kubernetes manifest.
10+
11+
### Deploy using Kagenti's UI
12+
13+
Kagenti's UI is aware of this example agent. To deploy through the UI
14+
15+
- Browse to http://kagenti-ui.localtest.me:8080/agents/
16+
- Build from source
17+
- Weather service agent
18+
- Expand Environment Variables
19+
- Import from File/URL, URL, https://raw.githubusercontent.com/kagenti/agent-examples/refs/heads/main/a2a/weather_service/.env.openai
20+
- If using [Ollama](https://ollama.com/), instead of the default use https://raw.githubusercontent.com/kagenti/agent-examples/refs/heads/main/a2a/weather_service/.env.ollama
21+
- Fetch and parse
22+
- Import
23+
- Build and deploy agent
24+
- Chat
25+
- `What is the weather in New York?`
26+
27+
### Deploy using a Kubernetes deployment manifest
28+
29+
Deploy the sample manifest:
30+
31+
```bash
32+
kubectl apply -f deployment/k8s.yaml
33+
```
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Best practice to create a ServiceAccount for each agent to allow for more granular permissions if needed.
2+
apiVersion: v1
3+
kind: ServiceAccount
4+
metadata:
5+
name: weather-service
6+
namespace: team1
7+
---
8+
# Expose the A2A endpoint and Agent Card.
9+
apiVersion: v1
10+
kind: Service
11+
metadata:
12+
labels:
13+
app.kubernetes.io/name: weather-service
14+
# kagenti.io/type=agent is required for the Agent to be discovered by Kagenti and show up in the UI
15+
kagenti.io/type: agent
16+
protocol.kagenti.io/a2a: ""
17+
name: weather-service
18+
namespace: team1
19+
spec:
20+
ports:
21+
- name: http
22+
port: 8080
23+
protocol: TCP
24+
targetPort: 8000
25+
selector:
26+
app.kubernetes.io/name: weather-service
27+
kagenti.io/type: agent
28+
type: ClusterIP
29+
---
30+
# Deploy a test build of the Agent
31+
apiVersion: apps/v1
32+
kind: Deployment
33+
metadata:
34+
labels:
35+
app.kubernetes.io/component: agent
36+
app.kubernetes.io/name: weather-service
37+
kagenti.io/framework: LangGraph
38+
kagenti.io/type: agent
39+
kagenti.io/workload-type: deployment
40+
protocol.kagenti.io/a2a: ""
41+
name: weather-service
42+
namespace: team1
43+
spec:
44+
progressDeadlineSeconds: 600
45+
replicas: 1
46+
revisionHistoryLimit: 10
47+
selector:
48+
matchLabels:
49+
app.kubernetes.io/name: weather-service
50+
kagenti.io/type: agent
51+
template:
52+
metadata:
53+
labels:
54+
app.kubernetes.io/name: weather-service
55+
kagenti.io/framework: LangGraph
56+
kagenti.io/type: agent
57+
protocol.kagenti.io/a2a: ""
58+
spec:
59+
containers:
60+
- env:
61+
# Port to bind A2A server
62+
- name: PORT
63+
value: "8000"
64+
# Host to bind A2A server (0.0.0.0 means bind to all interfaces)
65+
- name: HOST
66+
value: 0.0.0.0
67+
# AGENT_ENDPOINT is the endpoint that appears on the Agent Card
68+
- name: AGENT_ENDPOINT
69+
value: http://weather-service.team1.svc.cluster.local:8080/
70+
- name: OTEL_EXPORTER_OTLP_ENDPOINT
71+
value: http://otel-collector.kagenti-system.svc.cluster.local:8335
72+
- name: KEYCLOAK_URL
73+
value: http://keycloak.keycloak.svc.cluster.local:8080
74+
- name: UV_CACHE_DIR
75+
value: /app/.cache/uv
76+
# Make direct call to tool.
77+
- name: MCP_URL
78+
value: http://weather-tool-mcp.team1.svc.cluster.local:8000/mcp
79+
# Use this value to make call through MCP Gateway
80+
# value: http://mcp-gateway-istio.gateway-system.svc.cluster.local:8080/mcp
81+
# This is the LLM_API_BASE for ollama running on the host machine. In production, this would point to a real LLM API.
82+
- name: LLM_API_BASE
83+
value: http://host.docker.internal:11434/v1
84+
# This is a dummy key; if using a real LLM API use a real key
85+
- name: LLM_API_KEY
86+
value: dummy
87+
# For production, use a Secret:
88+
# - name: LLM_API_KEY
89+
# valueFrom:
90+
# secretKeyRef:
91+
# name: llm-credentials
92+
# key: openai-api-key
93+
# This is a dummy key; if using OpenAI use a real key
94+
- name: OPENAI_API_KEY
95+
value: dummy
96+
# For production, use a Secret:
97+
# - name: OPENAI_API_KEY
98+
# valueFrom:
99+
# secretKeyRef:
100+
# name: llm-credentials
101+
# key: openai-api-key
102+
- name: LLM_MODEL
103+
value: llama3.2:3b-instruct-fp16
104+
# Kagenti will supply a GITHUB_SECRET_NAME, but the weather service does not need it.
105+
# - name: GITHUB_SECRET_NAME
106+
# value: github-token-secret
107+
# Pin to a specific version
108+
image: ghcr.io/kagenti/agent-examples/weather_service:v0.1.0-alpha.1
109+
# Or use the latest version
110+
# image: ghcr.io/kagenti/agent-examples/weather_service:latest
111+
imagePullPolicy: Always
112+
name: agent
113+
ports:
114+
- containerPort: 8000
115+
name: http
116+
protocol: TCP
117+
readinessProbe:
118+
failureThreshold: 12
119+
initialDelaySeconds: 5
120+
periodSeconds: 5
121+
successThreshold: 1
122+
tcpSocket:
123+
port: 8000
124+
timeoutSeconds: 1
125+
resources:
126+
limits:
127+
cpu: 500m
128+
memory: 1Gi
129+
requests:
130+
cpu: 100m
131+
memory: 256Mi
132+
# Note that Kagenti's UI doesn't create security contexts for agents, but it's a good practice to set them for defense in depth. This is a fairly restrictive security context that should work for most agents, but you may need to adjust it based on your Agent's needs.
133+
securityContext:
134+
allowPrivilegeEscalation: false
135+
capabilities:
136+
drop:
137+
- ALL
138+
runAsUser: 1000
139+
terminationMessagePath: /dev/termination-log
140+
terminationMessagePolicy: File
141+
volumeMounts:
142+
# This is for agents that use uv and its dependency cache
143+
- mountPath: /app/.cache
144+
name: cache
145+
# Something like this is needed if the Agent has a Marvin dependency
146+
# - mountPath: /.marvin
147+
# name: marvin
148+
dnsPolicy: ClusterFirst
149+
restartPolicy: Always
150+
schedulerName: default-scheduler
151+
securityContext:
152+
runAsNonRoot: true
153+
seccompProfile:
154+
type: RuntimeDefault
155+
serviceAccountName: weather-service
156+
terminationGracePeriodSeconds: 30
157+
# This is for agents that use uv and its dependency cache
158+
volumes:
159+
- emptyDir: {}
160+
name: cache
161+
# Something like this is needed if the Agent has a Marvin dependency
162+
# - emptyDir: {}
163+
# name: marvin

mcp/weather_tool/.dockerignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
.venv
1+
.venv
2+
3+
deployment
4+

mcp/weather_tool/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# MCP Weather tool
2+
3+
This tool demonstrates a small MCP server. The server implements a `get_weather` tool that returns the current weather for a city using https://open-meteo.com/en/docs/geocoding-api .
4+
5+
## Test the MCP server locally
6+
7+
Run locally
8+
9+
```bash
10+
cd mcp/weather_tool
11+
uv run --no-sync weather_tool.py
12+
```
13+
14+
## Deploy the MCP server to Kagenti
15+
16+
### Deploy using the Kagenti UI
17+
18+
- Browse to http://kagenti-ui.localtest.me:8080/tools
19+
- Import Tool
20+
- Deploy from Source
21+
- Select weather tool
22+
23+
### Deploy using a Kubernetes deployment descriptor
24+
25+
Alternately, you can deploy a pre-built image using Kubernetes
26+
27+
- `kubectl apply -f mcp/weather_tool/deployment/k8s.yaml`
28+
29+
## Test the MCP server using Kagenti
30+
31+
- Visit http://kagenti-ui.localtest.me:8080/tools/team1/weather-tool
32+
- Click "Connect & list tools"
33+
- Expand "get_weather"
34+
- Click "invoke tool"
35+
- Enter the name of a city
36+
- Click "invoke"
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Best practice to create a ServiceAccount for each agent to allow for more granular permissions if needed.
2+
apiVersion: v1
3+
kind: ServiceAccount
4+
metadata:
5+
name: weather-tool
6+
namespace: team1
7+
---
8+
# Expose the MCP endpoint
9+
apiVersion: v1
10+
kind: Service
11+
metadata:
12+
labels:
13+
app.kubernetes.io/name: weather-tool
14+
# kagenti.io/type=tool is required for the MCP Server that provides tool to be discovered by Kagenti and show up in the UI
15+
kagenti.io/type: tool
16+
protocol.kagenti.io/mcp: ""
17+
name: weather-tool-mcp
18+
namespace: team1
19+
spec:
20+
ports:
21+
- name: http
22+
port: 8000
23+
protocol: TCP
24+
targetPort: 8000
25+
selector:
26+
app.kubernetes.io/name: weather-tool
27+
kagenti.io/type: tool
28+
type: ClusterIP
29+
---
30+
# Deploy a test build of the Tool
31+
apiVersion: apps/v1
32+
kind: Deployment
33+
metadata:
34+
labels:
35+
app.kubernetes.io/name: weather-tool
36+
kagenti.io/framework: Python
37+
# Set inject to true for [AuthBridge](https://github.com/kagenti/kagenti-extensions/tree/main/AuthBridge)
38+
kagenti.io/inject: disabled
39+
kagenti.io/type: tool
40+
kagenti.io/workload-type: deployment
41+
protocol.kagenti.io/mcp: ""
42+
name: weather-tool
43+
namespace: team1
44+
spec:
45+
progressDeadlineSeconds: 600
46+
replicas: 1
47+
revisionHistoryLimit: 10
48+
selector:
49+
matchLabels:
50+
app.kubernetes.io/name: weather-tool
51+
kagenti.io/type: tool
52+
template:
53+
metadata:
54+
labels:
55+
app.kubernetes.io/name: weather-tool
56+
kagenti.io/framework: Python
57+
# Set inject to true for [AuthBridge](https://github.com/kagenti/kagenti-extensions/tree/main/AuthBridge)
58+
kagenti.io/inject: disabled
59+
kagenti.io/transport: streamable_http
60+
kagenti.io/type: tool
61+
protocol.kagenti.io/mcp: ""
62+
spec:
63+
containers:
64+
- env:
65+
# Port to bind MCP server
66+
- name: PORT
67+
value: "8000"
68+
# Host to bind MCP server (0.0.0.0 means bind to all interfaces)
69+
- name: HOST
70+
value: 0.0.0.0
71+
- name: OTEL_EXPORTER_OTLP_ENDPOINT
72+
value: http://otel-collector.kagenti-system.svc.cluster.local:8335
73+
- name: KEYCLOAK_URL
74+
value: http://keycloak.keycloak.svc.cluster.local:8080
75+
- name: UV_CACHE_DIR
76+
value: /app/.cache/uv
77+
# Pin to a specific version
78+
image: ghcr.io/kagenti/agent-examples/weather_tool:v0.1.0-alpha.1
79+
# Or use the latest version
80+
# image: ghcr.io/kagenti/agent-examples/weather_tool:latest
81+
imagePullPolicy: Always
82+
name: mcp
83+
ports:
84+
- containerPort: 8000
85+
name: http
86+
protocol: TCP
87+
# Note that a readinessProbe is recommended. Kagenti doesn't generate one for UI
88+
# deployments, and we follow that pattern in this example, but you may want to add one for your own tools.
89+
resources:
90+
limits:
91+
cpu: 500m
92+
memory: 1Gi
93+
requests:
94+
cpu: 100m
95+
memory: 256Mi
96+
securityContext:
97+
allowPrivilegeEscalation: false
98+
capabilities:
99+
drop:
100+
- ALL
101+
runAsUser: 1000
102+
terminationMessagePath: /dev/termination-log
103+
terminationMessagePolicy: File
104+
volumeMounts:
105+
# This is for agents that use uv and its dependency cache
106+
- mountPath: /app/.cache
107+
name: cache
108+
- mountPath: /tmp
109+
name: tmp
110+
dnsPolicy: ClusterFirst
111+
restartPolicy: Always
112+
schedulerName: default-scheduler
113+
securityContext:
114+
runAsNonRoot: true
115+
seccompProfile:
116+
type: RuntimeDefault
117+
serviceAccountName: weather-tool
118+
terminationGracePeriodSeconds: 30
119+
volumes:
120+
# This is for tools that use uv and its dependency cache
121+
- emptyDir: {}
122+
name: cache
123+
- emptyDir: {}
124+
name: tmp

0 commit comments

Comments
 (0)