diff --git a/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/04-litellm-gateway.ipynb b/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/04-litellm-gateway.ipynb new file mode 100644 index 000000000..620995ddb --- /dev/null +++ b/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/04-litellm-gateway.ipynb @@ -0,0 +1,541 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4ba51a29-a566-4b5a-97f0-10e634567e40", + "metadata": { + "collapsed": true, + "jupyter": { + "outputs_hidden": true + } + }, + "source": [ + "# LiteLLM connecting to Bedrock AgentCore Gateway\n", + "\n", + "## Overview\n", + "\n", + "[LiteLLM](https://docs.litellm.ai/) is a proxy server and an open-source Python library that acts as a universal API gateway for accessing 100+ large language models from different providers (Bedrock, OpenAI, Anthropic, Azure, Cohere, Mistral, Gemini, Ollama, etc.). It eliminates the need to learn multiple APIs by translating inputs to match each provider's specific requirements. Beyond API unification, LiteLLM provides production-ready features including cost tracking, guardrails, load balancing, failover, rate limiting, caching, logging, and real-time monitoring. This makes it ideal for maintaining provider-agnostic infrastructure while implementing enterprise-grade operational controls in AI applications.\n", + "\n", + "LiteLLM proxy also serves as a centralized [MCP gateway](https://docs.litellm.ai/docs/mcp) offering unified management of 100+ AI providers through a single interface. Key benefits include enhanced security by addressing MCP's decentralized vulnerabilities, simplified authentication/authorization eliminating duplicate OAuth/RBAC setups, improved scalability preventing configuration drift, and multi-server aggregation for easy administration. Technical advantages include LLM-agnostic support, seamless function calling integration, and protocol bridging capabilities. This creates a robust, secure, and scalable solution that standardizes MCP connections while providing enterprise-grade operational controls for AI integration across multiple servers and clients.\n", + "\n", + "Bedrock AgentCore Gateway provides customers a way to turn their existing AWS Lambda functions into fully-managed MCP servers without needing to manage infra or hosting. Gateway will provide a uniform Model Context Protocol (MCP) interface across all these tools.\n", + "\n", + "In this example, we will demonstrate how to connect LiteLLM proxy with Bedrock AgentCore Gateway using Python SDK. This will use OAuth for Inbound Authentication to connect with Gateway. This tutorial will show MCP List Tools and Call Tool.\n", + "\n", + "![How does it work](images/litellm-oauth-gateway.png)\n", + "\n", + "### Tutorial Details\n", + "\n", + "| Information | Details |\n", + "|:---------------------|:----------------------------------------------------------|\n", + "| Tutorial type | Interactive |\n", + "| AgentCore components | AgentCore Gateway, AgentCore Identity |\n", + "| MCP components | LiteLLM |\n", + "| Gateway Target type | AWS Lambda |\n", + "| Inbound Auth IdP | Amazon Cognito |\n", + "| Outbound Auth | AWS IAM |\n", + "| LLM model | Anthropic Claude Sonnet 3.7, Amazon Nova Pro |\n", + "| Tutorial components | Creating AgentCore Gateway and Connecting with LiteLLM |\n", + "| Tutorial vertical | Cross-vertical |\n", + "| Example complexity | Easy |\n", + "| SDK used | boto3, LiteLLM Python SDK |\n", + "\n", + "### Tutorial Architecture\n", + "\n", + "In this tutorial we will transform operations defined in an AWS Lambda function into MCP tools and host them in Bedrock AgentCore Gateway. For demonstration purposes, we will use LiteLLM proxy to connect to AgentCore Gateway. In our example LiteLLM will call two tools: `get_order` and `update_order`." + ] + }, + { + "cell_type": "markdown", + "id": "5362e1ad-f027-4452-a8d9-0b861c0115c2", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "To execute this tutorial you will need:\n", + "\n", + "- Jupyter notebook (Python kernel)\n", + "- uv\n", + "- AWS credentials\n", + "- Amazon Cognito\n", + "- LiteLLM Python SDK" + ] + }, + { + "cell_type": "markdown", + "id": "e93da982-0d11-427c-9958-fff3c80b32f1", + "metadata": {}, + "source": [ + "## Configuring Authentication for Incoming AgentCore Gateway Requests\n", + "\n", + "AgentCore Gateway provides secure connections via inbound and outbound authentication. For the inbound authentication, the AgentCore Gateway analyzes the OAuth token passed during invocation to decide allow or deny the access to a tool in the gateway. If a tool needs access to external resources, the AgentCore Gateway can use outbound authentication via API Key, IAM or OAuth Token to allow or deny the access to the external resource.\n", + "\n", + "During the inbound authorization flow, an agent or the MCP client calls an MCP tool in the AgentCore Gateway adding an OAuth access token (generated from the user’s IdP). AgentCore Gateway then validates the OAuth access token and performs inbound authorization.\n", + "\n", + "If the tool running in AgentCore Gateway needs to access external resources, OAuth will retrieve credentials of downstream resources using the resource credential provider for the Gateway target. AgentCore Gateway passes the authorization credentials to the caller to get access to the downstream API. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e326677b-11b5-4488-b01b-573ad275a764", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install --force-reinstall -U -r requirements.txt --quiet" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a4e6248d-b740-418b-ae0d-c0a9623e43e1", + "metadata": {}, + "outputs": [], + "source": [ + "# Set AWS credentials if not using Amazon SageMaker notebook\n", + "import os\n", + "\n", + "# os.environ['AWS_ACCESS_KEY_ID'] = '' # Set the access key\n", + "# os.environ['AWS_SECRET_ACCESS_KEY'] = '' # Set the secret key\n", + "os.environ['AWS_DEFAULT_REGION'] = os.environ.get('AWS_REGION', 'us-east-1') # set the AWS region" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd5f3851-d0ca-484f-bb41-68f66ddbea44", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "\n", + "# Get the directory of the current script\n", + "if '__file__' in globals():\n", + " current_dir = os.path.dirname(os.path.abspath(__file__))\n", + "else:\n", + " current_dir = os.getcwd() # Fallback if __file__ is not defined (e.g., Jupyter)\n", + "\n", + "# Navigate to the directory containing utils.py (one level up)\n", + "utils_dir = os.path.abspath(os.path.join(current_dir, '../..'))\n", + "\n", + "# Add to sys.path\n", + "sys.path.insert(0, utils_dir)\n", + "\n", + "# Now you can import utils\n", + "import utils" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ddf8bfe9-8435-44cc-9e8a-ed8ece48f6a6", + "metadata": {}, + "outputs": [], + "source": [ + "#### Create a sample AWS Lambda function that you want to convert into MCP tools\n", + "lambda_resp = utils.create_gateway_lambda(\"lambda_function_code.zip\")\n", + "\n", + "if lambda_resp is not None:\n", + " if lambda_resp['exit_code'] == 0:\n", + " print(\"Lambda function created with ARN: \", lambda_resp['lambda_function_arn'])\n", + " else:\n", + " print(\"Lambda function creation failed with message: \", lambda_resp['lambda_function_arn'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ef17018-d2be-40e3-a892-55dd420297f9", + "metadata": {}, + "outputs": [], + "source": [ + "#### Create an IAM role for the Gateway to assume\n", + "import utils\n", + "agentcore_gateway_iam_role = utils.create_agentcore_gateway_role(\"sample-lambdagateway\")\n", + "print(\"Agentcore gateway role ARN: \", agentcore_gateway_iam_role['Role']['Arn'])" + ] + }, + { + "cell_type": "markdown", + "id": "65120594-c3ec-4d51-810b-8d478851d8d2", + "metadata": {}, + "source": [ + "## Create Amazon Cognito Pool for Inbound authorization to Gateway" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0bbbc736-6f5e-4a60-a598-ead43a0c1f90", + "metadata": {}, + "outputs": [], + "source": [ + "# Creating Cognito User Pool \n", + "import os\n", + "import boto3\n", + "import requests\n", + "import time\n", + "from botocore.exceptions import ClientError\n", + "\n", + "REGION = os.environ['AWS_DEFAULT_REGION']\n", + "USER_POOL_NAME = \"sample-agentcore-gateway-pool\"\n", + "RESOURCE_SERVER_ID = \"sample-agentcore-gateway-id\"\n", + "RESOURCE_SERVER_NAME = \"sample-agentcore-gateway-name\"\n", + "CLIENT_NAME = \"sample-agentcore-gateway-client\"\n", + "SCOPES = [\n", + " {\"ScopeName\": \"gateway:read\", \"ScopeDescription\": \"Read access\"},\n", + " {\"ScopeName\": \"gateway:write\", \"ScopeDescription\": \"Write access\"}\n", + "]\n", + "scopeString = f\"{RESOURCE_SERVER_ID}/gateway:read {RESOURCE_SERVER_ID}/gateway:write\"\n", + "\n", + "cognito = boto3.client(\"cognito-idp\", region_name=REGION)\n", + "\n", + "print(\"Creating or retrieving Cognito resources...\")\n", + "user_pool_id = utils.get_or_create_user_pool(cognito, USER_POOL_NAME)\n", + "print(f\"User Pool ID: {user_pool_id}\")\n", + "\n", + "utils.get_or_create_resource_server(cognito, user_pool_id, RESOURCE_SERVER_ID, RESOURCE_SERVER_NAME, SCOPES)\n", + "print(\"Resource server ensured.\")\n", + "\n", + "client_id, client_secret = utils.get_or_create_m2m_client(cognito, user_pool_id, CLIENT_NAME, RESOURCE_SERVER_ID)\n", + "print(f\"Client ID: {client_id}\")\n", + "\n", + "# Get discovery URL \n", + "cognito_discovery_url = f'https://cognito-idp.{REGION}.amazonaws.com/{user_pool_id}/.well-known/openid-configuration'\n", + "print(cognito_discovery_url)" + ] + }, + { + "cell_type": "markdown", + "id": "f1a63450-7fb9-42fc-ab4f-3d86c27bb2f8", + "metadata": {}, + "source": [ + "## Create the Gateway with Amazon Cognito Authorizer for inbound authorization" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72f2cd57-7777-42d3-b6f3-c45ed0a935c4", + "metadata": {}, + "outputs": [], + "source": [ + "# CreateGateway with Cognito authorizer without CMK. Use the Cognito user pool created in the previous step\n", + "gateway_client = boto3.client('bedrock-agentcore-control', region_name = os.environ['AWS_DEFAULT_REGION'])\n", + "auth_config = {\n", + " \"customJWTAuthorizer\": { \n", + " \"allowedClients\": [client_id], # Client MUST match with the ClientId configured in Cognito. Example: 7rfbikfsm51j2fpaggacgng84g\n", + " \"discoveryUrl\": cognito_discovery_url\n", + " }\n", + "}\n", + "create_response = gateway_client.create_gateway(name='2TestGWforLambda',\n", + " roleArn = agentcore_gateway_iam_role['Role']['Arn'], # The IAM Role must have permissions to create/list/get/delete Gateway \n", + " protocolType='MCP',\n", + " authorizerType='CUSTOM_JWT',\n", + " authorizerConfiguration=auth_config, \n", + " description='AgentCore Gateway with AWS Lambda target type'\n", + ")\n", + "print(create_response)\n", + "# Retrieve the GatewayID used for GatewayTarget creation\n", + "gatewayID = create_response[\"gatewayId\"]\n", + "gatewayURL = create_response[\"gatewayUrl\"]\n", + "print(gatewayID)\n", + "time.sleep(10)" + ] + }, + { + "cell_type": "markdown", + "id": "94dc57be-e50e-4997-a440-3bcf582d09bc", + "metadata": {}, + "source": [ + "## Create an AWS Lambda target and transform into MCP tools" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c1474da-cdd6-4dbd-84e7-3fdad018647d", + "metadata": {}, + "outputs": [], + "source": [ + "# Replace the AWS Lambda function ARN below\n", + "lambda_target_config = {\n", + " \"mcp\": {\n", + " \"lambda\": {\n", + " \"lambdaArn\": lambda_resp['lambda_function_arn'], # Replace this with your AWS Lambda function ARN\n", + " \"toolSchema\": {\n", + " \"inlinePayload\": [\n", + " {\n", + " \"name\": \"get_order_tool\",\n", + " \"description\": \"tool to get the order\",\n", + " \"inputSchema\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"orderId\": {\n", + " \"type\": \"string\"\n", + " }\n", + " },\n", + " \"required\": [\"orderId\"]\n", + " }\n", + " }, \n", + " {\n", + " \"name\": \"update_order_tool\",\n", + " \"description\": \"tool to update the orderId\",\n", + " \"inputSchema\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"orderId\": {\n", + " \"type\": \"string\"\n", + " }\n", + " },\n", + " \"required\": [\"orderId\"]\n", + " }\n", + " }\n", + " ]\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "credential_config = [ \n", + " {\n", + " \"credentialProviderType\" : \"GATEWAY_IAM_ROLE\"\n", + " }\n", + "]\n", + "targetname='LambdaUsingSDK'\n", + "response = gateway_client.create_gateway_target(\n", + " gatewayIdentifier=gatewayID,\n", + " name=targetname,\n", + " description='Lambda Target using SDK',\n", + " targetConfiguration=lambda_target_config,\n", + " credentialProviderConfigurations=credential_config)" + ] + }, + { + "cell_type": "markdown", + "id": "d3ac6532-5299-4024-917d-bcd60caea6ed", + "metadata": {}, + "source": [ + "## Calling Bedrock AgentCore Gateway from LiteLLM \n", + "\n", + "The LiteLLM proxy seamlessly integrates with AWS tools through the Bedrock AgentCore Gateway, which implements the Model Context Protocol (MCP) specification. This integration enables secure, standardized communication between LiteLLM (MCP Client) and Bedrock AgentCore Gateway (MCP Server)\n", + "\n", + "At its core, the Bedrock AgentCore Gateway serves as a protocol-compliant Gateway that exposes fundamental MCP APIs: list_tools and InvokeTool. These APIs allow any MCP-compliant client or SDK to discover and interact with available tools in a secure, standardized way. When the LiteLLM MCP gateway needs to access AWS services, it communicates with the Gateway using these MCP-standardized endpoints.\n", + "\n", + "The Gateway's implementation adheres strictly to the [MCP Authorization specification](https://modelcontextprotocol.org/specification/draft/basic/authorization), ensuring robust security and access control. This means that every tool invocation by the LiteLLM goes through authorization step, maintaining security while enabling powerful functionality.\n", + "\n", + "For example, when the LiteLLM needs to access MCP tools, it first calls ListTools to discover available tools, then uses CallTool to execute specific actions. The Gateway handles all the necessary security validations, protocol translations, and service interactions, making the entire process seamless and secure.\n", + "\n", + "This architectural approach means that any client or SDK that implements the MCP specification can interact with AWS services through the Gateway, making it a versatile and future-proof solution for AI agent integrations.\n", + "\n", + "![Strands agent calling Gateway](images/litellm-lambda-gateway.png)" + ] + }, + { + "cell_type": "markdown", + "id": "873031fe-62b5-4196-91be-500c1f87dfd4", + "metadata": {}, + "source": [ + "## Request the access token from Amazon Cognito for inbound authorization" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efbc389b", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "time.sleep(10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ed1d1d6-e84c-4286-bf25-3ad6a49723b9", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Requesting the access token from Amazon Cognito authorizer...May fail for some time till the domain name propogation completes\")\n", + "token_response = utils.get_token(user_pool_id, client_id, client_secret,scopeString,REGION)\n", + "token = token_response[\"access_token\"]\n", + "print(\"Token response:\", token)" + ] + }, + { + "cell_type": "markdown", + "id": "6fd0379d-9576-43cb-aa9b-72b86c43b472", + "metadata": {}, + "source": [ + "## LiteLLM calling MCP tools of AWS Lambda using Bedrock AgentCore Gateway\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "be4b39c4-7387-4ce8-b728-f2347fbdaa36", + "metadata": {}, + "outputs": [], + "source": [ + "from litellm.experimental_mcp_client.client import MCPClient\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e64794e7-4e5f-4fc5-824a-61c901e356c4", + "metadata": {}, + "outputs": [], + "source": [ + "# Initialize LiteLLM MCP client with HTTP transport and Bearer token auth\n", + "client = MCPClient(\n", + " server_url=gatewayURL,\n", + " transport_type=\"http\",\n", + " auth_type=\"bearer_token\",\n", + " auth_value=token,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90133bfd", + "metadata": {}, + "outputs": [], + "source": [ + "#Connecting to AgentCore Gateway (MCP Server)\n", + "async def mcp_operations(session):\n", + " print(\"\\n✓ Connected successfully!\")\n", + " print(\"\\nAvailable Tools:\")\n", + " print(\"-\" * 50)\n", + "\n", + " # List all available tools\n", + " tools = await session.list_tools()\n", + " tools = tools.tools\n", + "\n", + " if tools:\n", + " for i, tool in enumerate(tools, 1):\n", + " print(f\"\\n{i}. {tool.name}\")\n", + " print(f\" Description: {tool.description}\")\n", + " if hasattr(tool, 'inputSchema'):\n", + " print(f\" Input Schema: {tool.inputSchema}\")\n", + " else:\n", + " print(\"No tools available.\")\n", + "\n", + " print(\"\\n\" + \"-\" * 50)\n", + " print(f\"Total tools: {len(tools)}\")\n", + "\n", + " # Call the __get_order_tool with orderId argument\n", + " tool_name = targetname + \"___get_order_tool\"\n", + "\n", + " print(\"\\n\" + \"=\" * 50)\n", + " print(f\"Calling {tool_name} with orderId=123...\")\n", + " print(\"=\" * 50)\n", + "\n", + " tool_result = await session.call_tool(tool_name, arguments={\"orderId\": \"123\"})\n", + "\n", + " if tool_result.content and len(tool_result.content) > 0:\n", + " print(f\"Tool Call result: {tool_result.content[0].text}\")\n", + " else:\n", + " print(\"No content in tool result\")\n", + "\n", + "await client.run_with_session(mcp_operations)" + ] + }, + { + "cell_type": "markdown", + "id": "73169486-2fa0-42b5-8a8f-d6bdcc532159", + "metadata": {}, + "source": [ + "**Issue: if you get below error while executing below cell, it indicates incompatibily between pydantic and pydantic-core versions.**\n", + "\n", + "```\n", + "TypeError: model_schema() got an unexpected keyword argument 'generic_origin'\n", + "```\n", + "**How to resolve?**\n", + "\n", + "You will need to make sure you have pydantic==2.7.2 and pydantic-core 2.27.2 that are both compatible. Restart the kernel once done." + ] + }, + { + "cell_type": "markdown", + "id": "fa8dd91d-15a6-45b2-b539-bb3eaf0e0e08", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "Run the cell below to delete all resources created by this notebook: AgentCore Gateway (and its targets), Lambda function, IAM roles, and Cognito user pool." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3edc5b6-e5f0-47b9-994f-378415bad50d", + "metadata": {}, + "outputs": [], + "source": [ + "import utils\n", + "\n", + "# ── Delete AgentCore Gateway (deletes targets automatically) ──────────\n", + "try:\n", + " utils.delete_gateway(gateway_client, gatewayID)\n", + " print(f\"✓ Deleted gateway: {gatewayID}\")\n", + "except Exception as e:\n", + " print(f\" Gateway cleanup: {e}\")\n", + "\n", + "# ── Delete Lambda function ───────────────────────────────────────────\n", + "try:\n", + " utils.delete_lambda_functions(['gateway_lambda'])\n", + " print(\"✓ Deleted Lambda function: gateway_lambda\")\n", + "except Exception as e:\n", + " print(f\" Lambda cleanup: {e}\")\n", + "\n", + "# ── Delete Lambda IAM role ──────────────────────────────────────────\n", + "try:\n", + " utils.delete_iam_role('gateway_lambda_iamrole')\n", + " print(\"✓ Deleted IAM role: gateway_lambda_iamrole\")\n", + "except Exception as e:\n", + " print(f\" Lambda IAM role cleanup: {e}\")\n", + "\n", + "# ── Delete Gateway IAM role ─────────────────────────────────────────\n", + "try:\n", + " utils.delete_iam_role('sample-lambdagateway-agentcore-gateway-role')\n", + " print(\"✓ Deleted IAM role: sample-lambdagateway-agentcore-gateway-role\")\n", + "except Exception as e:\n", + " print(f\" Gateway IAM role cleanup: {e}\")\n", + "\n", + "# ── Delete Cognito User Pool ────────────────────────────────────────\n", + "try:\n", + " utils.delete_cognito_user_pool(user_pool_id, REGION)\n", + " print(f\"✓ Deleted Cognito user pool: {user_pool_id}\")\n", + "except Exception as e:\n", + " print(f\" Cognito cleanup: {e}\")\n", + "\n", + "print(\"\\n✓ Cleanup complete!\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "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.12.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/images/litellm-lambda-gateway.png b/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/images/litellm-lambda-gateway.png new file mode 100644 index 000000000..baac6f28a Binary files /dev/null and b/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/images/litellm-lambda-gateway.png differ diff --git a/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/images/litellm-oauth-gateway.png b/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/images/litellm-oauth-gateway.png new file mode 100644 index 000000000..3d86f99d5 Binary files /dev/null and b/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/images/litellm-oauth-gateway.png differ diff --git a/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/lambda_function_code.zip b/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/lambda_function_code.zip new file mode 100644 index 000000000..26ac9a2b8 Binary files /dev/null and b/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/lambda_function_code.zip differ diff --git a/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/requirements.txt b/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/requirements.txt index cf48f7d57..043d67238 100644 --- a/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/requirements.txt +++ b/01-tutorials/02-AgentCore-gateway/04-integration/01-runtime-gateway/requirements.txt @@ -4,4 +4,5 @@ uv boto3 bedrock-agentcore bedrock-agentcore-starter-toolkit -mcp \ No newline at end of file +mcp +litellm \ No newline at end of file