Vendor_Risk_Assessment_MCP_LangGraph.ipynb•74.3 kB
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Complete Vendor Risk Assessment with MCP, Amazon Titan, and LangGraph\n",
"## Google Colab Notebook\n",
"\n",
"This notebook provides a complete vendor risk assessment system using:\n",
"- MCP (Model Context Protocol) for client-server architecture\n",
"- Amazon Titan for AI-powered risk analysis\n",
"- LangGraph for workflow orchestration\n",
"- Real data sources (yfinance, NewsAPI, OpenWeather)\n",
"- Function-based modular design"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. Installation and Setup"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: yfinance in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (0.2.66)\n",
"Requirement already satisfied: requests in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (2.31.0)\n",
"Requirement already satisfied: boto3 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (1.40.35)\n",
"Requirement already satisfied: httpx in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (0.28.1)\n",
"Requirement already satisfied: pandas in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (2.1.4)\n",
"Requirement already satisfied: numpy in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (1.26.4)\n",
"Collecting langchain-aws\n",
" Downloading langchain_aws-0.2.33-py3-none-any.whl.metadata (4.5 kB)\n",
"Collecting langgraph\n",
" Downloading langgraph-0.6.7-py3-none-any.whl.metadata (6.8 kB)\n",
"Requirement already satisfied: mcp in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (1.14.1)\n",
"Requirement already satisfied: fastmcp in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (2.12.3)\n",
"Collecting langchain-mcp-adapters\n",
" Downloading langchain_mcp_adapters-0.1.10-py3-none-any.whl.metadata (10 kB)\n",
"Requirement already satisfied: multitasking>=0.0.7 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from yfinance) (0.0.12)\n",
"Requirement already satisfied: platformdirs>=2.0.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from yfinance) (4.2.0)\n",
"Requirement already satisfied: pytz>=2022.5 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from yfinance) (2023.3.post1)\n",
"Requirement already satisfied: frozendict>=2.3.4 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from yfinance) (2.4.6)\n",
"Requirement already satisfied: peewee>=3.16.2 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from yfinance) (3.18.2)\n",
"Requirement already satisfied: beautifulsoup4>=4.11.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from yfinance) (4.13.5)\n",
"Requirement already satisfied: curl_cffi>=0.7 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from yfinance) (0.13.0)\n",
"Requirement already satisfied: protobuf>=3.19.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from yfinance) (3.20.3)\n",
"Requirement already satisfied: websockets>=13.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from yfinance) (15.0.1)\n",
"Requirement already satisfied: charset-normalizer<4,>=2 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from requests) (2.0.4)\n",
"Requirement already satisfied: idna<4,>=2.5 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from requests) (3.4)\n",
"Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from requests) (2.1.0)\n",
"Requirement already satisfied: certifi>=2017.4.17 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from requests) (2024.2.2)\n",
"Requirement already satisfied: botocore<1.41.0,>=1.40.35 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from boto3) (1.40.35)\n",
"Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from boto3) (1.0.1)\n",
"Requirement already satisfied: s3transfer<0.15.0,>=0.14.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from boto3) (0.14.0)\n",
"Requirement already satisfied: anyio in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from httpx) (4.10.0)\n",
"Requirement already satisfied: httpcore==1.* in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from httpx) (1.0.9)\n",
"Requirement already satisfied: h11>=0.16 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from httpcore==1.*->httpx) (0.16.0)\n",
"Requirement already satisfied: python-dateutil>=2.8.2 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from pandas) (2.8.2)\n",
"Requirement already satisfied: tzdata>=2022.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from pandas) (2023.3)\n",
"Collecting langchain-core<0.4.0,>=0.3.76 (from langchain-aws)\n",
" Downloading langchain_core-0.3.76-py3-none-any.whl.metadata (3.7 kB)\n",
"Requirement already satisfied: pydantic<3,>=2.10.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from langchain-aws) (2.11.9)\n",
"Collecting langgraph-checkpoint<3.0.0,>=2.1.0 (from langgraph)\n",
" Downloading langgraph_checkpoint-2.1.1-py3-none-any.whl.metadata (4.2 kB)\n",
"Collecting langgraph-prebuilt<0.7.0,>=0.6.0 (from langgraph)\n",
" Downloading langgraph_prebuilt-0.6.4-py3-none-any.whl.metadata (4.5 kB)\n",
"Collecting langgraph-sdk<0.3.0,>=0.2.2 (from langgraph)\n",
" Downloading langgraph_sdk-0.2.9-py3-none-any.whl.metadata (1.5 kB)\n",
"Collecting xxhash>=3.5.0 (from langgraph)\n",
" Downloading xxhash-3.5.0-cp311-cp311-macosx_11_0_arm64.whl.metadata (12 kB)\n",
"Requirement already satisfied: httpx-sse>=0.4 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from mcp) (0.4.1)\n",
"Requirement already satisfied: jsonschema>=4.20.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from mcp) (4.21.1)\n",
"Requirement already satisfied: pydantic-settings>=2.5.2 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from mcp) (2.10.1)\n",
"Requirement already satisfied: python-multipart>=0.0.9 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from mcp) (0.0.20)\n",
"Requirement already satisfied: sse-starlette>=1.6.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from mcp) (3.0.2)\n",
"Requirement already satisfied: starlette>=0.27 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from mcp) (0.48.0)\n",
"Requirement already satisfied: uvicorn>=0.31.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from mcp) (0.36.0)\n",
"Requirement already satisfied: authlib>=1.5.2 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from fastmcp) (1.6.4)\n",
"Requirement already satisfied: cyclopts>=3.0.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from fastmcp) (3.24.0)\n",
"Requirement already satisfied: exceptiongroup>=1.2.2 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from fastmcp) (1.3.0)\n",
"Requirement already satisfied: openapi-core>=0.19.5 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from fastmcp) (0.19.5)\n",
"Requirement already satisfied: openapi-pydantic>=0.5.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from fastmcp) (0.5.1)\n",
"Requirement already satisfied: pyperclip>=1.9.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from fastmcp) (1.10.0)\n",
"Requirement already satisfied: python-dotenv>=1.1.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from fastmcp) (1.1.1)\n",
"Requirement already satisfied: rich>=13.9.4 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from fastmcp) (14.1.0)\n",
"Requirement already satisfied: typing-extensions>=4.14.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from langchain-mcp-adapters) (4.15.0)\n",
"Requirement already satisfied: sniffio>=1.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from anyio->httpx) (1.3.1)\n",
"Requirement already satisfied: cryptography in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from authlib>=1.5.2->fastmcp) (46.0.1)\n",
"Requirement already satisfied: soupsieve>1.2 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.8)\n",
"Requirement already satisfied: cffi>=1.12.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from curl_cffi>=0.7->yfinance) (2.0.0)\n",
"Requirement already satisfied: attrs>=23.1.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from cyclopts>=3.0.0->fastmcp) (23.2.0)\n",
"Requirement already satisfied: docstring-parser>=0.15 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from cyclopts>=3.0.0->fastmcp) (0.17.0)\n",
"Requirement already satisfied: rich-rst<2.0.0,>=1.3.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from cyclopts>=3.0.0->fastmcp) (1.3.1)\n",
"Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from jsonschema>=4.20.0->mcp) (2023.12.1)\n",
"Requirement already satisfied: referencing>=0.28.4 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from jsonschema>=4.20.0->mcp) (0.33.0)\n",
"Requirement already satisfied: rpds-py>=0.7.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from jsonschema>=4.20.0->mcp) (0.10.6)\n",
"Collecting langsmith>=0.3.45 (from langchain-core<0.4.0,>=0.3.76->langchain-aws)\n",
" Downloading langsmith-0.4.29-py3-none-any.whl.metadata (14 kB)\n",
"Requirement already satisfied: tenacity!=8.4.0,<10.0.0,>=8.1.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from langchain-core<0.4.0,>=0.3.76->langchain-aws) (8.2.2)\n",
"Collecting jsonpatch<2.0,>=1.33 (from langchain-core<0.4.0,>=0.3.76->langchain-aws)\n",
" Downloading jsonpatch-1.33-py2.py3-none-any.whl.metadata (3.0 kB)\n",
"Requirement already satisfied: PyYAML>=5.3 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from langchain-core<0.4.0,>=0.3.76->langchain-aws) (6.0.1)\n",
"Collecting packaging>=23.2 (from langchain-core<0.4.0,>=0.3.76->langchain-aws)\n",
" Downloading packaging-25.0-py3-none-any.whl.metadata (3.3 kB)\n",
"Collecting ormsgpack>=1.10.0 (from langgraph-checkpoint<3.0.0,>=2.1.0->langgraph)\n",
" Downloading ormsgpack-1.10.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.metadata (43 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m43.7/43.7 kB\u001b[0m \u001b[31m2.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hCollecting orjson>=3.10.1 (from langgraph-sdk<0.3.0,>=0.2.2->langgraph)\n",
" Downloading orjson-3.11.3-cp311-cp311-macosx_15_0_arm64.whl.metadata (41 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m41.9/41.9 kB\u001b[0m \u001b[31m4.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hRequirement already satisfied: isodate in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from openapi-core>=0.19.5->fastmcp) (0.7.2)\n",
"Requirement already satisfied: jsonschema-path<0.4.0,>=0.3.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from openapi-core>=0.19.5->fastmcp) (0.3.4)\n",
"Requirement already satisfied: more-itertools in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from openapi-core>=0.19.5->fastmcp) (10.8.0)\n",
"Requirement already satisfied: openapi-schema-validator<0.7.0,>=0.6.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from openapi-core>=0.19.5->fastmcp) (0.6.3)\n",
"Requirement already satisfied: openapi-spec-validator<0.8.0,>=0.7.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from openapi-core>=0.19.5->fastmcp) (0.7.2)\n",
"Requirement already satisfied: parse in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from openapi-core>=0.19.5->fastmcp) (1.20.2)\n",
"Requirement already satisfied: werkzeug<3.1.2 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from openapi-core>=0.19.5->fastmcp) (3.1.1)\n",
"Requirement already satisfied: annotated-types>=0.6.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from pydantic<3,>=2.10.0->langchain-aws) (0.7.0)\n",
"Requirement already satisfied: pydantic-core==2.33.2 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from pydantic<3,>=2.10.0->langchain-aws) (2.33.2)\n",
"Requirement already satisfied: typing-inspection>=0.4.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from pydantic<3,>=2.10.0->langchain-aws) (0.4.1)\n",
"Requirement already satisfied: email-validator>=2.0.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from pydantic[email]>=2.11.7->fastmcp) (2.3.0)\n",
"Requirement already satisfied: six>=1.5 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from python-dateutil>=2.8.2->pandas) (1.16.0)\n",
"Requirement already satisfied: markdown-it-py>=2.2.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from rich>=13.9.4->fastmcp) (3.0.0)\n",
"Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from rich>=13.9.4->fastmcp) (2.17.2)\n",
"Requirement already satisfied: click>=7.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from uvicorn>=0.31.1->mcp) (8.1.7)\n",
"Requirement already satisfied: pycparser in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from cffi>=1.12.0->curl_cffi>=0.7->yfinance) (2.23)\n",
"Requirement already satisfied: dnspython>=2.0.0 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from email-validator>=2.0.0->pydantic[email]>=2.11.7->fastmcp) (2.8.0)\n",
"Collecting jsonpointer>=1.9 (from jsonpatch<2.0,>=1.33->langchain-core<0.4.0,>=0.3.76->langchain-aws)\n",
" Downloading jsonpointer-3.0.0-py2.py3-none-any.whl.metadata (2.3 kB)\n",
"Requirement already satisfied: pathable<0.5.0,>=0.4.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from jsonschema-path<0.4.0,>=0.3.1->openapi-core>=0.19.5->fastmcp) (0.4.4)\n",
"Collecting requests-toolbelt>=1.0.0 (from langsmith>=0.3.45->langchain-core<0.4.0,>=0.3.76->langchain-aws)\n",
" Downloading requests_toolbelt-1.0.0-py2.py3-none-any.whl.metadata (14 kB)\n",
"Collecting zstandard>=0.23.0 (from langsmith>=0.3.45->langchain-core<0.4.0,>=0.3.76->langchain-aws)\n",
" Downloading zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl.metadata (3.3 kB)\n",
"Requirement already satisfied: mdurl~=0.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from markdown-it-py>=2.2.0->rich>=13.9.4->fastmcp) (0.1.2)\n",
"Requirement already satisfied: rfc3339-validator in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from openapi-schema-validator<0.7.0,>=0.6.0->openapi-core>=0.19.5->fastmcp) (0.1.4)\n",
"Requirement already satisfied: lazy-object-proxy<2.0.0,>=1.7.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from openapi-spec-validator<0.8.0,>=0.7.1->openapi-core>=0.19.5->fastmcp) (1.12.0)\n",
"Requirement already satisfied: docutils in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from rich-rst<2.0.0,>=1.3.1->cyclopts>=3.0.0->fastmcp) (0.22.2)\n",
"Requirement already satisfied: MarkupSafe>=2.1.1 in /Users/shikharamar/anaconda3/envs/myenv/lib/python3.11/site-packages (from werkzeug<3.1.2->openapi-core>=0.19.5->fastmcp) (2.1.3)\n",
"Downloading langchain_aws-0.2.33-py3-none-any.whl (143 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m143.6/143.6 kB\u001b[0m \u001b[31m6.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hDownloading langgraph-0.6.7-py3-none-any.whl (153 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m153.3/153.3 kB\u001b[0m \u001b[31m17.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hDownloading langchain_mcp_adapters-0.1.10-py3-none-any.whl (15 kB)\n",
"Downloading langchain_core-0.3.76-py3-none-any.whl (447 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m447.5/447.5 kB\u001b[0m \u001b[31m23.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hDownloading langgraph_checkpoint-2.1.1-py3-none-any.whl (43 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m43.9/43.9 kB\u001b[0m \u001b[31m7.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hDownloading langgraph_prebuilt-0.6.4-py3-none-any.whl (28 kB)\n",
"Downloading langgraph_sdk-0.2.9-py3-none-any.whl (56 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m56.8/56.8 kB\u001b[0m \u001b[31m11.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hDownloading xxhash-3.5.0-cp311-cp311-macosx_11_0_arm64.whl (30 kB)\n",
"Downloading jsonpatch-1.33-py2.py3-none-any.whl (12 kB)\n",
"Downloading langsmith-0.4.29-py3-none-any.whl (386 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m386.2/386.2 kB\u001b[0m \u001b[31m29.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hDownloading orjson-3.11.3-cp311-cp311-macosx_15_0_arm64.whl (127 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m127.7/127.7 kB\u001b[0m \u001b[31m13.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hDownloading ormsgpack-1.10.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (376 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m376.3/376.3 kB\u001b[0m \u001b[31m29.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hDownloading packaging-25.0-py3-none-any.whl (66 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m66.5/66.5 kB\u001b[0m \u001b[31m8.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hDownloading jsonpointer-3.0.0-py2.py3-none-any.whl (7.6 kB)\n",
"Downloading requests_toolbelt-1.0.0-py2.py3-none-any.whl (54 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m54.5/54.5 kB\u001b[0m \u001b[31m7.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hDownloading zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl (640 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m640.6/640.6 kB\u001b[0m \u001b[31m32.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m\n",
"\u001b[?25hInstalling collected packages: zstandard, xxhash, packaging, ormsgpack, orjson, jsonpointer, requests-toolbelt, jsonpatch, langsmith, langgraph-sdk, langchain-core, langgraph-checkpoint, langchain-mcp-adapters, langchain-aws, langgraph-prebuilt, langgraph\n",
" Attempting uninstall: packaging\n",
" Found existing installation: packaging 23.1\n",
" Uninstalling packaging-23.1:\n",
" Successfully uninstalled packaging-23.1\n",
"\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
"streamlit 1.31.1 requires packaging<24,>=16.8, but you have packaging 25.0 which is incompatible.\n",
"streamlit 1.31.1 requires rich<14,>=10.14.0, but you have rich 14.1.0 which is incompatible.\u001b[0m\u001b[31m\n",
"\u001b[0mSuccessfully installed jsonpatch-1.33 jsonpointer-3.0.0 langchain-aws-0.2.33 langchain-core-0.3.76 langchain-mcp-adapters-0.1.10 langgraph-0.6.7 langgraph-checkpoint-2.1.1 langgraph-prebuilt-0.6.4 langgraph-sdk-0.2.9 langsmith-0.4.29 orjson-3.11.3 ormsgpack-1.10.0 packaging-25.0 requests-toolbelt-1.0.0 xxhash-3.5.0 zstandard-0.25.0\n",
"✅ All packages installed successfully!\n"
]
}
],
"source": [
"# Install required packages\n",
"!pip install yfinance requests boto3 httpx pandas numpy langchain-aws langgraph mcp fastmcp langchain-mcp-adapters\n",
"\n",
"print(\"✅ All packages installed successfully!\")"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ Environment variables set!\n",
"⚠️ Make sure to replace placeholder values with your actual API keys\n"
]
}
],
"source": [
"# Set environment variables - REPLACE WITH YOUR API KEYS\n",
"import os\n",
"\n",
"\n",
"\n",
"print(\"✅ Environment variables set!\")\n",
"print(\"⚠️ Make sure to replace placeholder values with your actual API keys\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Import Required Libraries"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ All libraries imported successfully!\n"
]
}
],
"source": [
"# Import all required libraries\n",
"import asyncio\n",
"import json\n",
"import logging\n",
"import requests\n",
"import yfinance as yf\n",
"import boto3\n",
"from datetime import datetime, timedelta\n",
"from typing import Dict, Any, Optional\n",
"from langgraph.graph import StateGraph, START, END\n",
"from typing_extensions import TypedDict\n",
"from langchain_aws import ChatBedrock\n",
"from langchain_core.messages import HumanMessage, SystemMessage\n",
"\n",
"# Configure logging\n",
"logging.basicConfig(level=logging.INFO)\n",
"logger = logging.getLogger(__name__)\n",
"\n",
"print(\"✅ All libraries imported successfully!\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. MCP Server Functions - Data Collection"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ AWS Bedrock and Titan integration setup complete!\n"
]
}
],
"source": [
"# AWS Configuration and Bedrock Client Setup\n",
"AWS_REGION = os.getenv('AWS_REGION', 'us-east-1')\n",
"BEDROCK_MODEL_ID = 'amazon.titan-text-express-v1'\n",
"\n",
"# API Keys\n",
"ALPHA_VANTAGE_API_KEY = os.getenv('ALPHA_VANTAGE_API_KEY')\n",
"OPENWEATHER_API_KEY = os.getenv('OPENWEATHER_API_KEY') \n",
"NEWS_API_KEY = os.getenv('NEWS_API_KEY')\n",
"\n",
"def get_bedrock_client():\n",
" \"\"\"Initialize AWS Bedrock client for Amazon Titan\"\"\"\n",
" try:\n",
" return boto3.client(\n",
" 'bedrock-runtime',\n",
" region_name=AWS_REGION,\n",
" aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),\n",
" aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY')\n",
" )\n",
" except Exception as e:\n",
" logger.error(f\"Failed to create Bedrock client: {e}\")\n",
" return None\n",
"\n",
"async def call_titan_model(prompt: str, max_tokens: int = 1000) -> str:\n",
" \"\"\"Call Amazon Titan model for AI analysis\"\"\"\n",
" try:\n",
" bedrock_client = get_bedrock_client()\n",
" if not bedrock_client:\n",
" return \"Error: Could not connect to AWS Bedrock\"\n",
" \n",
" body = {\n",
" \"inputText\": prompt,\n",
" \"textGenerationConfig\": {\n",
" \"maxTokenCount\": max_tokens,\n",
" \"temperature\": 0.1,\n",
" \"topP\": 0.9\n",
" }\n",
" }\n",
" \n",
" response = bedrock_client.invoke_model(\n",
" modelId=BEDROCK_MODEL_ID,\n",
" body=json.dumps(body),\n",
" contentType=\"application/json\",\n",
" accept=\"application/json\"\n",
" )\n",
" \n",
" response_body = json.loads(response['body'].read())\n",
" return response_body.get('results', [{}])[0].get('outputText', 'No response')\n",
" except Exception as e:\n",
" logger.error(f\"Titan API error: {e}\")\n",
" return f\"Error calling Titan: {str(e)}\"\n",
"\n",
"print(\"✅ AWS Bedrock and Titan integration setup complete!\")"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ Financial data collection function ready!\n"
]
},
{
"data": {
"text/plain": [
"{'symbol': 'META',\n",
" 'current_price': 778.38,\n",
" 'market_cap': 1955400777728,\n",
" 'volatility': 2.29,\n",
" 'pe_ratio': 28.253359,\n",
" 'debt_equity': 25.406,\n",
" 'sector': 'Communication Services',\n",
" 'beta': 1.242}"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Financial Data Collection Function\n",
"def get_financial_data(symbol: str) -> Dict[str, Any]:\n",
" \"\"\"Get financial metrics from yfinance\"\"\"\n",
" try:\n",
" stock = yf.Ticker(symbol)\n",
" info = stock.info\n",
" hist = stock.history(period=\"1y\")\n",
" \n",
" if hist.empty:\n",
" return {\"error\": f\"No data for {symbol}\"}\n",
" \n",
" current_price = hist['Close'].iloc[-1]\n",
" volatility = hist['Close'].pct_change().std() * 100\n",
" \n",
" return {\n",
" \"symbol\": symbol,\n",
" \"current_price\": round(current_price, 2),\n",
" \"market_cap\": info.get('marketCap'),\n",
" \"volatility\": round(volatility, 2),\n",
" \"pe_ratio\": info.get('trailingPE'),\n",
" \"debt_equity\": info.get('debtToEquity'),\n",
" \"sector\": info.get('sector'),\n",
" \"beta\": info.get('beta')\n",
" }\n",
" except Exception as e:\n",
" return {\"error\": f\"Financial data error: {str(e)}\"}\n",
"\n",
"print(\"✅ Financial data collection function ready!\")\n",
"get_financial_data(\"META\")"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ Weather data collection function ready!\n"
]
},
{
"data": {
"text/plain": [
"{'location': 'Mumbai',\n",
" 'temperature': 25.99,\n",
" 'humidity': 89,\n",
" 'condition': 'mist',\n",
" 'weather_risk_score': 10}"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Weather Data Collection Function\n",
"def get_weather_data(location: str) -> Dict[str, Any]:\n",
" \"\"\"Get weather risk data from OpenWeather\"\"\"\n",
" if not OPENWEATHER_API_KEY:\n",
" return {\"error\": \"Weather API key not configured\"}\n",
" \n",
" try:\n",
" url = \"http://api.openweathermap.org/data/2.5/weather\"\n",
" params = {\n",
" 'q': location,\n",
" 'appid': OPENWEATHER_API_KEY,\n",
" 'units': 'metric'\n",
" }\n",
" \n",
" response = requests.get(url, params=params, timeout=10)\n",
" data = response.json()\n",
" \n",
" if response.status_code != 200:\n",
" return {\"error\": f\"Weather API error: {data.get('message')}\"}\n",
" \n",
" # Simple weather risk calculation\n",
" humidity = data['main']['humidity']\n",
" temp = data['main']['temp']\n",
" weather_risk = min(10, (humidity / 10) + abs(temp - 20) / 5)\n",
" \n",
" return {\n",
" \"location\": location,\n",
" \"temperature\": temp,\n",
" \"humidity\": humidity,\n",
" \"condition\": data['weather'][0]['description'],\n",
" \"weather_risk_score\": round(weather_risk, 1)\n",
" }\n",
" except Exception as e:\n",
" return {\"error\": f\"Weather data error: {str(e)}\"}\n",
"\n",
"print(\"✅ Weather data collection function ready!\")\n",
"get_weather_data(\"Mumbai\")"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ News sentiment analysis function ready!\n",
"{'sentiment_score': 10, 'articles_count': 10, 'risk_level': 'Low', 'recent_headlines': ['The Apple Watch SE 3 is the one to buy', 'Apple Watch Series 11 review: stuck in the middle', 'Apple’s new iPhone charger is a first of its kind']}\n"
]
}
],
"source": [
"# News Sentiment Analysis Function\n",
"async def get_news_sentiment(company: str) -> Dict[str, Any]:\n",
" \"\"\"Get news sentiment using NewsAPI and Titan analysis\"\"\"\n",
" if not NEWS_API_KEY:\n",
" return {\"error\": \"News API key not configured\"}\n",
" \n",
" try:\n",
" url = \"https://newsapi.org/v2/everything\"\n",
" params = {\n",
" 'q': company,\n",
" 'language': 'en',\n",
" 'from': (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d'),\n",
" 'apiKey': NEWS_API_KEY,\n",
" 'pageSize': 10\n",
" }\n",
" \n",
" response = requests.get(url, params=params, timeout=10)\n",
" data = response.json()\n",
" \n",
" if response.status_code != 200:\n",
" return {\"error\": f\"News API error: {data.get('message')}\"}\n",
" \n",
" articles = data.get('articles', [])\n",
" if not articles:\n",
" return {\"sentiment_score\": 0, \"articles_count\": 0, \"risk_level\": \"Low\"}\n",
" \n",
" # Prepare headlines for Titan sentiment analysis\n",
" headlines = [article.get('title', '') for article in articles[:5]]\n",
" text_for_analysis = \"\\n\".join(headlines)\n",
" \n",
" prompt = f\"\"\"Analyze sentiment of these news headlines about {company}:\n",
"{text_for_analysis}\n",
"\n",
"Rate sentiment from -10 (very negative) to +10 (very positive). \n",
"Respond with just a number.\"\"\"\n",
" \n",
" ai_response = await call_titan_model(prompt, max_tokens=50)\n",
" \n",
" try:\n",
" sentiment_score = int(float(ai_response.strip()))\n",
" sentiment_score = max(-10, min(10, sentiment_score))\n",
" except:\n",
" sentiment_score = 0\n",
" \n",
" risk_level = \"High\" if sentiment_score < -3 else \"Medium\" if sentiment_score < 0 else \"Low\"\n",
" \n",
" return {\n",
" \"sentiment_score\": sentiment_score,\n",
" \"articles_count\": len(articles),\n",
" \"risk_level\": risk_level,\n",
" \"recent_headlines\": headlines[:3]\n",
" }\n",
" except Exception as e:\n",
" return {\"error\": f\"News sentiment error: {str(e)}\"}\n",
"\n",
"print(\"✅ News sentiment analysis function ready!\")\n",
"result = await get_news_sentiment(\"apple\")\n",
"print(result)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ Geopolitical risk assessment function ready!\n",
"✅ All MCP Server functions loaded!\n"
]
},
{
"data": {
"text/plain": [
"{'country': 'germany', 'geopolitical_risk_score': 5, 'risk_level': 'Medium'}"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Geopolitical Risk Assessment Function\n",
"def calculate_geopolitical_risk(country: str) -> Dict[str, Any]:\n",
" \"\"\"Simple geopolitical risk scoring based on country\"\"\"\n",
" # Simplified risk scoring - in production, use real geopolitical data sources\n",
" risk_mapping = {\n",
" 'United States': 3, 'Canada': 2, 'Germany': 2, 'Japan': 3,\n",
" 'China': 6, 'Russia': 8, 'Brazil': 5, 'India': 4,\n",
" 'United Kingdom': 2, 'France': 3, 'Australia': 2\n",
" }\n",
" \n",
" risk_score = risk_mapping.get(country, 5) # Default medium risk\n",
" \n",
" return {\n",
" \"country\": country,\n",
" \"geopolitical_risk_score\": risk_score,\n",
" \"risk_level\": \"High\" if risk_score >= 7 else \"Medium\" if risk_score >= 4 else \"Low\"\n",
" }\n",
"\n",
"print(\"✅ Geopolitical risk assessment function ready!\")\n",
"print(\"✅ All MCP Server functions loaded!\")\n",
"calculate_geopolitical_risk(\"germany\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. Risk Scoring Functions"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ Category risk scoring functions loaded!\n"
]
}
],
"source": [
"# Category-specific Risk Scoring Functions\n",
"def calculate_financial_risk_score(financial_data: Dict[str, Any]) -> float:\n",
" \"\"\"Calculate financial risk score (0-10 scale)\"\"\"\n",
" if \"error\" in financial_data:\n",
" return 5.0 # Default medium risk\n",
" \n",
" risk_score = 2.0 # Base score\n",
" \n",
" # Volatility risk\n",
" volatility = financial_data.get('volatility', 0)\n",
" if volatility > 10:\n",
" risk_score += 3\n",
" elif volatility > 5:\n",
" risk_score += 1.5\n",
" \n",
" # PE ratio risk\n",
" pe_ratio = financial_data.get('pe_ratio')\n",
" if pe_ratio and (pe_ratio > 50 or pe_ratio < 5):\n",
" risk_score += 1\n",
" \n",
" # Debt to equity risk\n",
" debt_equity = financial_data.get('debt_equity')\n",
" if debt_equity and debt_equity > 100:\n",
" risk_score += 1.5\n",
" \n",
" return min(10.0, risk_score)\n",
"\n",
"def calculate_weather_risk_score(weather_data: Dict[str, Any]) -> float:\n",
" \"\"\"Calculate weather-based operational risk score\"\"\"\n",
" if \"error\" in weather_data:\n",
" return 3.0 # Default low-medium risk\n",
" \n",
" return weather_data.get('weather_risk_score', 3.0)\n",
"\n",
"def calculate_news_risk_score(news_data: Dict[str, Any]) -> float:\n",
" \"\"\"Convert news sentiment to risk score\"\"\"\n",
" if \"error\" in news_data:\n",
" return 5.0 # Default medium risk\n",
" \n",
" sentiment = news_data.get('sentiment_score', 0)\n",
" # Convert sentiment (-10 to +10) to risk (0 to 10)\n",
" # Negative sentiment = higher risk\n",
" risk_score = 5 - (sentiment * 0.4) # Scale and invert\n",
" return max(0, min(10, risk_score))\n",
"\n",
"print(\"✅ Category risk scoring functions loaded!\")"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ Combined risk scoring with Titan integration ready!\n"
]
}
],
"source": [
"# Combined Risk Score Calculation with Amazon Titan\n",
"async def calculate_combined_risk_score(\n",
" financial_data: Dict[str, Any],\n",
" weather_data: Dict[str, Any], \n",
" news_data: Dict[str, Any],\n",
" geo_data: Dict[str, Any]\n",
") -> Dict[str, Any]:\n",
" \"\"\"Calculate combined risk score using Amazon Titan\"\"\"\n",
" \n",
" # Calculate individual category scores\n",
" financial_risk = calculate_financial_risk_score(financial_data)\n",
" weather_risk = calculate_weather_risk_score(weather_data)\n",
" news_risk = calculate_news_risk_score(news_data)\n",
" geo_risk = geo_data.get('geopolitical_risk_score', 5.0)\n",
" \n",
" # Weight the different risk categories\n",
" weights = {\n",
" 'financial': 0.4,\n",
" 'geopolitical': 0.3,\n",
" 'news': 0.2,\n",
" 'weather': 0.1\n",
" }\n",
" \n",
" weighted_score = (\n",
" financial_risk * weights['financial'] +\n",
" geo_risk * weights['geopolitical'] +\n",
" news_risk * weights['news'] +\n",
" weather_risk * weights['weather']\n",
" )\n",
" \n",
" # Use Amazon Titan for intelligent risk analysis\n",
" titan_prompt = f\"\"\"\n",
" Analyze this vendor risk assessment:\n",
" \n",
" Financial Risk: {financial_risk}/10 (Volatility: {financial_data.get('volatility', 'N/A')}%, PE: {financial_data.get('pe_ratio', 'N/A')})\n",
" Geopolitical Risk: {geo_risk}/10 (Country: {geo_data.get('country', 'Unknown')})\n",
" News Sentiment Risk: {news_risk}/10 (Score: {news_data.get('sentiment_score', 'N/A')})\n",
" Weather Risk: {weather_risk}/10 (Location risk)\n",
" \n",
" Weighted Combined Score: {weighted_score:.1f}/10\n",
" \n",
" Provide a final risk rating (Low/Medium/High/Critical) and brief justification:\n",
" \"\"\"\n",
" \n",
" ai_analysis = await call_titan_model(titan_prompt, max_tokens=200)\n",
" \n",
" return {\n",
" \"category_scores\": {\n",
" \"financial\": round(financial_risk, 1),\n",
" \"geopolitical\": round(geo_risk, 1), \n",
" \"news\": round(news_risk, 1),\n",
" \"weather\": round(weather_risk, 1)\n",
" },\n",
" \"weighted_combined_score\": round(weighted_score, 1),\n",
" \"titan_analysis\": ai_analysis\n",
" }\n",
"\n",
"print(\"✅ Combined risk scoring with Titan integration ready!\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. LangGraph Workflow Setup"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ LangGraph state and LangChain Titan LLM setup complete!\n"
]
}
],
"source": [
"# Define State for LangGraph Workflow\n",
"class VendorAssessmentState(TypedDict):\n",
" vendor_name: str\n",
" stock_symbol: str\n",
" location: str\n",
" financial_data: Dict[str, Any]\n",
" weather_data: Dict[str, Any]\n",
" news_data: Dict[str, Any]\n",
" geo_data: Dict[str, Any]\n",
" risk_scores: Dict[str, Any]\n",
" final_assessment: str\n",
"\n",
"# Initialize Amazon Titan via LangChain\n",
"def get_titan_llm():\n",
" \"\"\"Get Titan LLM via LangChain\"\"\"\n",
" return ChatBedrock(\n",
" model_id=BEDROCK_MODEL_ID,\n",
" region_name=AWS_REGION,\n",
" model_kwargs={\"temperature\": 0.1, \"max_tokens\": 1000}\n",
" )\n",
"\n",
"print(\"✅ LangGraph state and LangChain Titan LLM setup complete!\")"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ All LangGraph workflow nodes defined!\n"
]
}
],
"source": [
"# LangGraph Workflow Nodes\n",
"async def collect_financial_data_node(state: VendorAssessmentState) -> VendorAssessmentState:\n",
" \"\"\"LangGraph node: Collect financial data\"\"\"\n",
" print(f\"📊 Collecting financial data for {state['stock_symbol']}\")\n",
" financial_data = get_financial_data(state['stock_symbol'])\n",
" state['financial_data'] = financial_data\n",
" return state\n",
"\n",
"async def collect_weather_data_node(state: VendorAssessmentState) -> VendorAssessmentState:\n",
" \"\"\"LangGraph node: Collect weather data\"\"\"\n",
" print(f\"🌤️ Collecting weather data for {state['location']}\")\n",
" weather_data = get_weather_data(state['location'])\n",
" state['weather_data'] = weather_data\n",
" return state\n",
"\n",
"async def collect_news_data_node(state: VendorAssessmentState) -> VendorAssessmentState:\n",
" \"\"\"LangGraph node: Collect news sentiment data\"\"\"\n",
" print(f\"📰 Collecting news sentiment for {state['vendor_name']}\")\n",
" news_data = await get_news_sentiment(state['vendor_name'])\n",
" state['news_data'] = news_data\n",
" return state\n",
"\n",
"async def collect_geo_data_node(state: VendorAssessmentState) -> VendorAssessmentState:\n",
" \"\"\"LangGraph node: Collect geopolitical data\"\"\"\n",
" print(f\"🌍 Assessing geopolitical risk for {state['location']}\")\n",
" # Extract country from location (simplified)\n",
" country = state['location'] if state['location'] in ['United States', 'China', 'Germany', 'Japan', 'India'] else 'United States'\n",
" geo_data = calculate_geopolitical_risk(country)\n",
" state['geo_data'] = geo_data\n",
" return state\n",
"\n",
"async def calculate_risks_node(state: VendorAssessmentState) -> VendorAssessmentState:\n",
" \"\"\"LangGraph node: Calculate risk scores\"\"\"\n",
" print(\"🎯 Calculating risk scores...\")\n",
" risk_scores = await calculate_combined_risk_score(\n",
" state['financial_data'],\n",
" state['weather_data'],\n",
" state['news_data'], \n",
" state['geo_data']\n",
" )\n",
" state['risk_scores'] = risk_scores\n",
" return state\n",
"\n",
"async def generate_assessment_node(state: VendorAssessmentState) -> VendorAssessmentState:\n",
" \"\"\"LangGraph node: Generate final assessment using Titan\"\"\"\n",
" print(\"📋 Generating final assessment...\")\n",
" \n",
" llm = get_titan_llm()\n",
" \n",
" assessment_prompt = f\"\"\"\n",
" Generate a comprehensive vendor risk assessment report for {state['vendor_name']}:\n",
" \n",
" COMPANY: {state['vendor_name']} ({state['stock_symbol']})\n",
" LOCATION: {state['location']}\n",
" \n",
" RISK SCORES:\n",
" - Financial Risk: {state['risk_scores']['category_scores']['financial']}/10\n",
" - Geopolitical Risk: {state['risk_scores']['category_scores']['geopolitical']}/10 \n",
" - News Sentiment Risk: {state['risk_scores']['category_scores']['news']}/10\n",
" - Weather/Operational Risk: {state['risk_scores']['category_scores']['weather']}/10\n",
" - Combined Weighted Score: {state['risk_scores']['weighted_combined_score']}/10\n",
" \n",
" DATA SUMMARY:\n",
" Financial: {json.dumps(state['financial_data'], indent=2)}\n",
" News: {json.dumps(state['news_data'], indent=2)}\n",
" \n",
" Provide a structured assessment with:\n",
" 1. Executive Summary\n",
" 2. Key Risk Factors\n",
" 3. Risk Mitigation Recommendations\n",
" 4. Overall Risk Rating\n",
" \"\"\"\n",
" \n",
" messages = [\n",
" SystemMessage(content=\"You are a professional risk analyst. Provide detailed, actionable risk assessments.\"),\n",
" HumanMessage(content=assessment_prompt)\n",
" ]\n",
" \n",
" response = llm.invoke(messages)\n",
" state['final_assessment'] = response.content\n",
" return state\n",
"\n",
"print(\"✅ All LangGraph workflow nodes defined!\")"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ LangGraph workflow builder ready!\n"
]
}
],
"source": [
"# Build the LangGraph workflow\n",
"def create_vendor_assessment_workflow():\n",
" \"\"\"Create LangGraph workflow for vendor risk assessment\"\"\"\n",
" \n",
" workflow = StateGraph(VendorAssessmentState)\n",
" \n",
" # Add nodes\n",
" workflow.add_node(\"collect_financial\", collect_financial_data_node)\n",
" workflow.add_node(\"collect_weather\", collect_weather_data_node) \n",
" workflow.add_node(\"collect_news\", collect_news_data_node)\n",
" workflow.add_node(\"collect_geo\", collect_geo_data_node)\n",
" workflow.add_node(\"calculate_risks\", calculate_risks_node)\n",
" workflow.add_node(\"generate_assessment\", generate_assessment_node)\n",
" \n",
" # Define workflow edges\n",
" workflow.add_edge(START, \"collect_financial\")\n",
" workflow.add_edge(\"collect_financial\", \"collect_weather\")\n",
" workflow.add_edge(\"collect_weather\", \"collect_news\") \n",
" workflow.add_edge(\"collect_news\", \"collect_geo\")\n",
" workflow.add_edge(\"collect_geo\", \"calculate_risks\")\n",
" workflow.add_edge(\"calculate_risks\", \"generate_assessment\")\n",
" workflow.add_edge(\"generate_assessment\", END)\n",
" \n",
" return workflow.compile()\n",
"\n",
"print(\"✅ LangGraph workflow builder ready!\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6. MCP Client - Main Assessment Function"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ Main assessment function ready!\n"
]
}
],
"source": [
"# Main Assessment Function using LangGraph\n",
"async def assess_vendor_risk_with_langgraph(vendor_name: str, stock_symbol: str, location: str) -> Dict[str, Any]:\n",
" \"\"\"Main function to assess vendor risk using LangGraph workflow\"\"\"\n",
" \n",
" print(f\"🚀 Starting vendor risk assessment for {vendor_name}\")\n",
" print(\"=\" * 50)\n",
" \n",
" # Create workflow\n",
" workflow = create_vendor_assessment_workflow()\n",
" \n",
" # Initial state\n",
" initial_state = VendorAssessmentState(\n",
" vendor_name=vendor_name,\n",
" stock_symbol=stock_symbol,\n",
" location=location,\n",
" financial_data={},\n",
" weather_data={},\n",
" news_data={},\n",
" geo_data={},\n",
" risk_scores={},\n",
" final_assessment=\"\"\n",
" )\n",
" \n",
" # Execute workflow\n",
" final_state = await workflow.ainvoke(initial_state)\n",
" \n",
" return {\n",
" \"vendor_name\": vendor_name,\n",
" \"assessment_date\": datetime.now().isoformat(),\n",
" \"risk_scores\": final_state[\"risk_scores\"],\n",
" \"data_sources\": {\n",
" \"financial\": final_state[\"financial_data\"],\n",
" \"weather\": final_state[\"weather_data\"], \n",
" \"news\": final_state[\"news_data\"],\n",
" \"geopolitical\": final_state[\"geo_data\"]\n",
" },\n",
" \"final_assessment\": final_state[\"final_assessment\"]\n",
" }\n",
"\n",
"print(\"✅ Main assessment function ready!\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7. Test the Complete System"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"🚀 Starting vendor risk assessment for Microsoft\n",
"==================================================\n",
"📊 Collecting financial data for MSFT\n",
"🌤️ Collecting weather data for Seattle\n",
"📰 Collecting news sentiment for Microsoft\n",
"🌍 Assessing geopolitical risk for Seattle\n",
"Fallback\n",
"🎯 Calculating risk scores...\n",
"📋 Generating final assessment...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO:langchain_aws.llms.bedrock:Using Bedrock Invoke API to generate response\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"============================================================\n",
"VENDOR RISK ASSESSMENT RESULTS\n",
"============================================================\n",
"Vendor: Microsoft\n",
"Assessment Date: 2025-09-21T23:55:18.311278\n",
"\n",
"RISK SCORES:\n",
" Financial: 2.0/10\n",
" Geopolitical: 3/10\n",
" News: 5.0/10\n",
" Weather: 10/10\n",
"\n",
"Combined Score: 3.7/10\n",
"\n",
"FINAL ASSESSMENT:\n",
" \n",
"Executive Summary:\n",
"\n",
"Microsoft Corporation, headquartered in Seattle, Washington, is a multinational technology corporation that develops, manufactures, licenses, and supports a wide range of software products and services related to computing. Microsoft's products and services include operating systems, productivity software, enterprise software, cloud services, and gaming consoles.\n",
"\n",
"Key Risk Factors:\n",
"\n",
"Financial Risk: Microsoft's financial risk is moderate. The company has a strong balance sheet with a market capitalization of over $3.8 trillion as of January 2023. However, the company's revenue has been declining in recent years, and it faces competition from other technology companies such as Apple, Google, and Amazon.\n",
"\n",
"Geopolitical Risk: Microsoft operates in a global market, and geopolitical risks can impact its business. For example, changes in trade policies, tariffs, and political instability in certain regions can affect the company's supply chain and sales.\n",
"\n",
"News Sentiment Risk: Microsoft's news sentiment risk is moderate. The company has been the subject of negative news coverage in the past, particularly related to privacy and security issues. However, the company has taken steps to address these issues and has a strong reputation for transparency and ethical behavior.\n",
"\n",
"Weather/Operational Risk: Microsoft's weather/operational risk is low. The company's data centers are located in multiple regions around the world, and it has implemented robust disaster recovery and business continuity plans to ensure that its operations are not disrupted by natural disasters or other events.\n",
"\n",
"Risk Mitigation Recommendations:\n",
"\n",
"Financial Risk: Microsoft should continue to focus on growing its revenue and profitability. This can be done by expanding its product offerings, entering new markets, and improving its customer service. The company should also be careful with its spending and avoid taking on too much debt.\n",
"\n",
"Geopolitical Risk: Microsoft should continue to monitor geopolitical risks and take steps to mitigate them. This can include diversifying its supply chain, implementing trade policies that benefit the company, and engaging in political advocacy.\n",
"\n",
"News Sentiment Risk: Microsoft should continue to focus on transparency and ethical behavior. This can include providing clear and accurate information to its customers, responding to customer feedback, and investing in privacy and security technologies.\n",
"\n",
"Weather/Operational Risk: Microsoft should continue to invest in its data centers and disaster recovery and business continuity plans. This can include building new data centers in different regions, improving the reliability of its data centers, and training its employees on disaster recovery procedures.\n",
"\n",
"Overall Risk Rating:\n",
"\n",
"Based on the analysis of the key risk factors, Microsoft's overall risk rating is moderate. While the company faces some risks, it has taken steps to mitigate them and has a strong reputation for transparency and ethical behavior. Investors should consider Microsoft's financial performance, geopolitical risks, news sentiment risk, and weather/operational risk when making investment decisions.\n",
"\n",
"Risk Mitigation Recommendations:\n",
"\n",
"Financial Risk: Microsoft should continue to focus on growing its revenue and profitability. This can be done by expanding its product offerings, entering new markets, and improving its customer service. The company should also be careful with its spending and avoid taking on too much debt.\n",
"\n",
"Geopolitical Risk: Microsoft should continue to monitor geopolitical risks and take steps to mitigate them. This can include diversifying its supply chain, implementing trade policies that benefit the company, and engaging in political advocacy.\n",
"\n",
"News Sentiment Risk: Microsoft should continue to focus on transparency and ethical behavior. This can include providing clear and accurate information to its customers, responding to customer feedback, and investing in privacy and security technologies.\n",
"\n",
"Weather/Operational Risk: Microsoft should continue to invest in its data centers and disaster recovery and business continuity plans. This can include building new data centers in different regions, improving the reliability of its data centers, and training its employees on disaster recovery procedures.\n",
"\n",
"Overall Risk Rating:\n",
"\n",
"Based on the analysis of the key risk factors, Microsoft's overall risk rating is moderate. While the company faces some risks, it has taken steps to mitigate them and has a strong reputation for transparency and ethical behavior. Investors should consider Microsoft's financial performance, geopolitical risks, news sentiment risk, and weather/operational risk when making investment decisions.\n",
"\n",
"In conclusion, Microsoft Corporation is a multinational technology corporation that faces a variety of risks. However, the company has taken steps to mitigate these risks and has a strong reputation for transparency and ethical behavior. Investors should consider Microsoft's financial performance, geopolitical risks, news sentiment risk, and weather/operational risk when making investment decisions.\n"
]
}
],
"source": [
"# Test the vendor risk assessment system\n",
"async def test_vendor_assessment():\n",
" \"\"\"Test the vendor risk assessment system\"\"\"\n",
" \n",
" try:\n",
" # Test with Microsoft\n",
" result = await assess_vendor_risk_with_langgraph(\n",
" vendor_name=\"Microsoft\",\n",
" stock_symbol=\"MSFT\", \n",
" location=\"Seattle\"\n",
" )\n",
" \n",
" print(\"\\n\" + \"=\"*60)\n",
" print(\"VENDOR RISK ASSESSMENT RESULTS\")\n",
" print(\"=\"*60)\n",
" print(f\"Vendor: {result['vendor_name']}\")\n",
" print(f\"Assessment Date: {result['assessment_date']}\")\n",
" print(\"\\nRISK SCORES:\")\n",
" for category, score in result['risk_scores']['category_scores'].items():\n",
" print(f\" {category.title()}: {score}/10\")\n",
" print(f\"\\nCombined Score: {result['risk_scores']['weighted_combined_score']}/10\")\n",
" \n",
" print(\"\\nFINAL ASSESSMENT:\")\n",
" print(result['final_assessment'])\n",
" \n",
" return result\n",
" \n",
" except Exception as e:\n",
" print(f\"❌ Error during assessment: {e}\")\n",
" return None\n",
"\n",
"# Run the test\n",
"# Note: In Jupyter/Colab, you may need to use different syntax based on your environment\n",
"# If you get \"asyncio.run() cannot be called from a running event loop\", use: await test_vendor_assessment()\n",
"result = await test_vendor_assessment()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8. Additional Utility Functions"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ All utility functions loaded!\n",
"\n",
"🎯 Usage Examples:\n",
"1. Single assessment: await assess_vendor_risk_with_langgraph('Apple', 'AAPL', 'Cupertino')\n",
"2. Multiple vendors: await compare_multiple_vendors([{'vendor_name': 'Apple', 'stock_symbol': 'AAPL', 'location': 'Cupertino'}, ...])\n",
"3. Dashboard data: create_risk_dashboard_data(result)\n"
]
}
],
"source": [
"# Compare Multiple Vendors\n",
"async def compare_multiple_vendors(vendors_list):\n",
" \"\"\"Compare multiple vendors side by side\"\"\"\n",
" results = []\n",
" for vendor in vendors_list:\n",
" result = await assess_vendor_risk_with_langgraph(**vendor)\n",
" results.append(result)\n",
" \n",
" # Create comparison summary\n",
" print(\"\\n\" + \"=\"*80)\n",
" print(\"VENDOR COMPARISON SUMMARY\")\n",
" print(\"=\"*80)\n",
" \n",
" for result in results:\n",
" scores = result['risk_scores']['category_scores']\n",
" combined = result['risk_scores']['weighted_combined_score']\n",
" print(f\"\\n{result['vendor_name']} (Combined: {combined}/10):\")\n",
" print(f\" Financial: {scores['financial']}/10 | Geo: {scores['geopolitical']}/10\")\n",
" print(f\" News: {scores['news']}/10 | Weather: {scores['weather']}/10\")\n",
" \n",
" return results\n",
"\n",
"def create_risk_dashboard_data(assessment_result):\n",
" \"\"\"Create data structure for risk dashboard visualization\"\"\"\n",
" if not assessment_result:\n",
" return None\n",
" \n",
" scores = assessment_result['risk_scores']['category_scores']\n",
" \n",
" dashboard_data = {\n",
" \"vendor\": assessment_result['vendor_name'],\n",
" \"overall_risk\": assessment_result['risk_scores']['weighted_combined_score'],\n",
" \"risk_breakdown\": [\n",
" {\"category\": \"Financial\", \"score\": scores['financial'], \"max\": 10},\n",
" {\"category\": \"Geopolitical\", \"score\": scores['geopolitical'], \"max\": 10},\n",
" {\"category\": \"News Sentiment\", \"score\": scores['news'], \"max\": 10},\n",
" {\"category\": \"Weather/Ops\", \"score\": scores['weather'], \"max\": 10}\n",
" ],\n",
" \"data_quality\": {\n",
" \"financial\": \"error\" not in assessment_result['data_sources']['financial'],\n",
" \"weather\": \"error\" not in assessment_result['data_sources']['weather'],\n",
" \"news\": \"error\" not in assessment_result['data_sources']['news'],\n",
" \"geo\": True # Always available\n",
" }\n",
" }\n",
" \n",
" return dashboard_data\n",
"\n",
"print(\"✅ All utility functions loaded!\")\n",
"print(\"\\n🎯 Usage Examples:\")\n",
"print(\"1. Single assessment: await assess_vendor_risk_with_langgraph('Apple', 'AAPL', 'Cupertino')\")\n",
"print(\"2. Multiple vendors: await compare_multiple_vendors([{'vendor_name': 'Apple', 'stock_symbol': 'AAPL', 'location': 'Cupertino'}, ...])\")\n",
"print(\"3. Dashboard data: create_risk_dashboard_data(result)\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 9. Example Usage - Multiple Vendor Comparison"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"📊 Multiple vendor comparison example ready!\n",
"Uncomment the line above to run the comparison.\n"
]
}
],
"source": [
"# Example: Compare multiple major vendors\n",
"vendors_to_compare = [\n",
" {\"vendor_name\": \"Apple\", \"stock_symbol\": \"AAPL\", \"location\": \"Cupertino\"},\n",
" {\"vendor_name\": \"Amazon\", \"stock_symbol\": \"AMZN\", \"location\": \"Seattle\"},\n",
" {\"vendor_name\": \"Google\", \"stock_symbol\": \"GOOGL\", \"location\": \"Mountain View\"}\n",
"]\n",
"\n",
"# Uncomment to run comparison\n",
"# comparison_results = await compare_multiple_vendors(vendors_to_compare)\n",
"\n",
"print(\"📊 Multiple vendor comparison example ready!\")\n",
"print(\"Uncomment the line above to run the comparison.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 10. System Summary and Next Steps"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"🎉 COMPLETE VENDOR RISK ASSESSMENT SYSTEM READY!\n",
"============================================================\n",
"\n",
"✅ Key Features Implemented:\n",
" • MCP Server-Client Architecture\n",
" • Function-based modular design (no classes)\n",
" • LangGraph workflow orchestration\n",
" • Amazon Titan LLM integration\n",
" • Real data sources (yfinance, NewsAPI, OpenWeather)\n",
" • Category-based risk scoring\n",
" • Comprehensive risk assessment reports\n",
"\n",
"📋 Risk Categories Covered:\n",
" • Financial Risk (volatility, P/E, debt-equity)\n",
" • Geopolitical Risk (country-based assessment)\n",
" • News Sentiment Risk (AI-powered analysis)\n",
" • Weather/Operational Risk (location-based)\n",
"\n",
"🔧 Next Steps:\n",
" 1. Add your actual API keys to environment variables\n",
" 2. Test with different vendors and locations\n",
" 3. Customize risk weights based on your requirements\n",
" 4. Add additional data sources as needed\n",
" 5. Implement automated scheduling for regular assessments\n",
"\n",
"⚡ Ready to assess vendor risks with AI-powered insights!\n"
]
}
],
"source": [
"print(\"🎉 COMPLETE VENDOR RISK ASSESSMENT SYSTEM READY!\")\n",
"print(\"=\" * 60)\n",
"print(\"\\n✅ Key Features Implemented:\")\n",
"print(\" • MCP Server-Client Architecture\")\n",
"print(\" • Function-based modular design (no classes)\")\n",
"print(\" • LangGraph workflow orchestration\")\n",
"print(\" • Amazon Titan LLM integration\")\n",
"print(\" • Real data sources (yfinance, NewsAPI, OpenWeather)\")\n",
"print(\" • Category-based risk scoring\")\n",
"print(\" • Comprehensive risk assessment reports\")\n",
"print(\"\\n📋 Risk Categories Covered:\")\n",
"print(\" • Financial Risk (volatility, P/E, debt-equity)\")\n",
"print(\" • Geopolitical Risk (country-based assessment)\")\n",
"print(\" • News Sentiment Risk (AI-powered analysis)\")\n",
"print(\" • Weather/Operational Risk (location-based)\")\n",
"print(\"\\n🔧 Next Steps:\")\n",
"print(\" 1. Add your actual API keys to environment variables\")\n",
"print(\" 2. Test with different vendors and locations\")\n",
"print(\" 3. Customize risk weights based on your requirements\")\n",
"print(\" 4. Add additional data sources as needed\")\n",
"print(\" 5. Implement automated scheduling for regular assessments\")\n",
"print(\"\\n⚡ Ready to assess vendor risks with AI-powered insights!\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.8"
}
},
"nbformat": 4,
"nbformat_minor": 0
}