Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion ai/gen-ai-agents/custom-rag-agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ This repository contains the code for the development of a **custom RAG Agent**,

**Author**: L. Saetta

**Last updated**: 11/09/2025
**Reviewed**: 23.09.2025

![UI](images/ui_image.png)

## Design and implementation
* The agent is implemented using **LangGraph**
Expand Down
2 changes: 1 addition & 1 deletion ai/gen-ai-agents/custom-rag-agent/llm_with_mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ async def _list_tools(self):
Fetch tools from the MCP server using FastMCP. Must be async.
"""
jwt = self.jwt_supplier()

logger.info("Listing tools from %s ...", self.mcp_url)

# FastMCP requires async context + await for client ops.
Expand Down
88 changes: 88 additions & 0 deletions ai/gen-ai-agents/custom-rag-agent/minimal_mcp_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""
Minimal-but-solid MCP server with JWT hardening and sane defaults.

- Safe defaults for transports
"""

from fastmcp import FastMCP

# to verify the JWT token
# if you don't need to add security, you can remove this
# in newer version of FastMCP should be replaced with
# from fastmcp.server.auth.providers.jwt import JWTVerifier
from fastmcp.server.auth import BearerAuthProvider

from config import (
# first four needed only to manage JWT
ENABLE_JWT_TOKEN,
IAM_BASE_URL,
ISSUER,
AUDIENCE,
TRANSPORT,
# needed only if transport is stremable-http
HOST,
PORT,
)


#
# if you don't need to add security, you can remove this part and set
# AUTH = None, simply set ENABLE_JWT_TOKEN = False
#
AUTH = None

if ENABLE_JWT_TOKEN:
# check that a valid JWT token is provided
AUTH = BearerAuthProvider(
# this is the url to get the public key from IAM
# the PK is used to check the JWT
jwks_uri=f"{IAM_BASE_URL}/admin/v1/SigningCert/jwk",
issuer=ISSUER,
audience=AUDIENCE,
)

#
# define the MCP server
#
mcp = FastMCP("MCP server with few lines of code, but secure", auth=AUTH)


#
# MCP tools definition
# add and write the code for the tools here
#
@mcp.tool
def say_the_truth(user: str) -> str:
"""
This tool, given the name of the user return one of the secret truths.

Args:
user: The caller's display name or identifier.

Returns:
A short truth string.
"""
# here you'll put the code that reads and return the info requested
# mark each tool with the annotation
return f"{user}: Less is more!"


#
# Run the MCP server
#
if __name__ == "__main__":
# Validate transport
if TRANSPORT not in {"stdio", "streamable-http"}:
# don't use sse! it is deprecated!
raise RuntimeError(f"Unsupported TRANSPORT: {TRANSPORT}")

if TRANSPORT == "stdio":
# stdio doesn’t support host/port args
mcp.run(transport=TRANSPORT)
else:
# For http/streamable-http transport, host/port are valid
mcp.run(
transport=TRANSPORT,
host=HOST,
port=PORT,
)
7 changes: 7 additions & 0 deletions ai/gen-ai-agents/custom-rag-agent/ui_mcp_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
"""

import asyncio
import traceback
import streamlit as st
from mcp_servers_config import MCP_SERVERS_CONFIG

# this one contains the backend and the test code only for console
from llm_with_mcp import AgentWithMCP, default_jwt_supplier
from utils import get_console_logger

logger = get_console_logger()

# ---------- Page setup ----------
st.set_page_config(page_title="MCP UI", page_icon="🛠️", layout="wide")
Expand Down Expand Up @@ -50,6 +54,9 @@
except Exception as e:
st.session_state.agent = None
st.error(f"Failed to connect: {e}")
logger.error(e)
stack_str = traceback.format_exc()
logger.error(stack_str)

# ---------- Chat history (display) ----------
for msg in st.session_state.chat:
Expand Down