Skip to content

Commit f82d4cc

Browse files
committed
feat: add gateway auth support to agent templates
Add SigV4 authentication to MCP client templates so agents can authenticate with AWS_IAM gateways. Each framework's client.py uses Handlebars conditionals to include auth when gateways exist. SigV4HTTPXAuth class signs HTTP requests using botocore SigV4Auth, passed to the MCP client via httpx.AsyncClient. Templates read gateway URLs from AGENTCORE_GATEWAY_{NAME}_URL env vars and handle missing vars gracefully (warn, don't crash). Updated all 5 frameworks: Strands, LangChain, OpenAI Agents, Google ADK, AutoGen. Schema mapper reads mcp.json to populate gateway config for template rendering. All gateways are auto- included when creating an agent.
1 parent 10f6cbe commit f82d4cc

19 files changed

Lines changed: 662 additions & 69 deletions

File tree

src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap

Lines changed: 305 additions & 28 deletions
Large diffs are not rendered by default.

src/assets/python/autogen/base/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ async def invoke(payload, context):
2929

3030
# Get MCP Tools
3131
mcp_tools = await get_streamable_http_mcp_tools()
32+
if mcp_tools is None:
33+
mcp_tools = []
3234

3335
# Define an AssistantAgent with the model and tools
3436
agent = AssistantAgent(
Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,63 @@
1+
import os
2+
import logging
13
from typing import List
24
from autogen_ext.tools.mcp import (
35
StreamableHttpMcpToolAdapter,
46
StreamableHttpServerParams,
57
mcp_server_tools,
68
)
79

10+
logger = logging.getLogger(__name__)
11+
12+
{{#if hasGateway}}
13+
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
14+
import boto3
15+
import httpx
16+
from botocore.auth import SigV4Auth
17+
from botocore.awsrequest import AWSRequest
18+
19+
20+
class SigV4HTTPXAuth(httpx.Auth):
21+
"""Signs HTTP requests with AWS SigV4 for Lambda function URL authentication."""
22+
23+
def __init__(self):
24+
session = boto3.Session()
25+
credentials = session.get_credentials().get_frozen_credentials()
26+
region = session.region_name or os.environ.get("AWS_REGION", "us-east-1")
27+
self.signer = SigV4Auth(credentials, "lambda", region)
28+
29+
def auth_flow(self, request):
30+
headers = dict(request.headers)
31+
headers.pop("connection", None)
32+
aws_request = AWSRequest(
33+
method=request.method,
34+
url=str(request.url),
35+
data=request.content,
36+
headers=headers,
37+
)
38+
self.signer.add_auth(aws_request)
39+
request.headers.update(dict(aws_request.headers))
40+
yield request
41+
{{/if}}
42+
43+
44+
async def get_streamable_http_mcp_tools() -> List[StreamableHttpMcpToolAdapter]:
45+
"""Returns MCP Tools from the {{gatewayProviders.[0].name}} gateway."""
46+
url = os.environ.get("{{gatewayProviders.[0].envVarName}}")
47+
if not url:
48+
logger.warning("{{gatewayProviders.[0].envVarName}} not set — gateway tools unavailable")
49+
return []
50+
51+
server_params = StreamableHttpServerParams(url=url)
52+
return await mcp_server_tools(server_params)
53+
{{else}}
854
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
955
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
1056

1157

1258
async def get_streamable_http_mcp_tools() -> List[StreamableHttpMcpToolAdapter]:
13-
"""
14-
Returns MCP Tools compatible with AutoGen.
15-
"""
59+
"""Returns MCP Tools compatible with AutoGen."""
1660
# to use an MCP server that supports bearer authentication, add headers={"Authorization": f"Bearer {access_token}"}
1761
server_params = StreamableHttpServerParams(url=EXAMPLE_MCP_ENDPOINT)
1862
return await mcp_server_tools(server_params)
63+
{{/if}}

src/assets/python/googleadk/base/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ def add_numbers(a: int, b: int) -> int:
2323

2424

2525
# Get MCP Toolset
26-
mcp_toolset = [get_streamable_http_mcp_client()]
26+
mcp_client = get_streamable_http_mcp_client()
27+
mcp_toolset = [mcp_client] if mcp_client else []
2728

2829
_credentials_loaded = False
2930

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,61 @@
1+
import os
2+
import logging
13
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
24
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
35

6+
logger = logging.getLogger(__name__)
7+
8+
{{#if hasGateway}}
9+
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
10+
import boto3
11+
import httpx
12+
from botocore.auth import SigV4Auth
13+
from botocore.awsrequest import AWSRequest
14+
15+
16+
class SigV4HTTPXAuth(httpx.Auth):
17+
"""Signs HTTP requests with AWS SigV4 for Lambda function URL authentication."""
18+
19+
def __init__(self):
20+
session = boto3.Session()
21+
credentials = session.get_credentials().get_frozen_credentials()
22+
region = session.region_name or os.environ.get("AWS_REGION", "us-east-1")
23+
self.signer = SigV4Auth(credentials, "lambda", region)
24+
25+
def auth_flow(self, request):
26+
headers = dict(request.headers)
27+
headers.pop("connection", None)
28+
aws_request = AWSRequest(
29+
method=request.method,
30+
url=str(request.url),
31+
data=request.content,
32+
headers=headers,
33+
)
34+
self.signer.add_auth(aws_request)
35+
request.headers.update(dict(aws_request.headers))
36+
yield request
37+
{{/if}}
38+
39+
40+
def get_streamable_http_mcp_client() -> MCPToolset | None:
41+
"""Returns an MCP Toolset connected to the {{gatewayProviders.[0].name}} gateway."""
42+
url = os.environ.get("{{gatewayProviders.[0].envVarName}}")
43+
if not url:
44+
logger.warning("{{gatewayProviders.[0].envVarName}} not set — gateway tools unavailable")
45+
return None
46+
47+
return MCPToolset(
48+
connection_params=StreamableHTTPConnectionParams(url=url)
49+
)
50+
{{else}}
451
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
552
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
653

754

855
def get_streamable_http_mcp_client() -> MCPToolset:
9-
"""
10-
Returns an MCP Toolset compatible with Google ADK.
11-
"""
56+
"""Returns an MCP Toolset compatible with Google ADK."""
1257
# to use an MCP server that supports bearer authentication, add headers={"Authorization": f"Bearer {access_token}"}
1358
return MCPToolset(
1459
connection_params=StreamableHTTPConnectionParams(url=EXAMPLE_MCP_ENDPOINT)
1560
)
61+
{{/if}}

src/assets/python/langchain_langgraph/base/main.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ async def invoke(payload, context):
3737
mcp_client = get_streamable_http_mcp_client()
3838

3939
# Load MCP Tools
40-
mcp_tools = await mcp_client.get_tools()
40+
mcp_tools = []
41+
if mcp_client:
42+
mcp_tools = await mcp_client.get_tools()
4143

4244
# Define the agent using create_react_agent
4345
graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools)
Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,76 @@
1+
import os
2+
import logging
13
from langchain_mcp_adapters.client import MultiServerMCPClient
24

5+
logger = logging.getLogger(__name__)
6+
7+
{{#if hasGateway}}
8+
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
9+
import boto3
10+
import httpx
11+
from botocore.auth import SigV4Auth
12+
from botocore.awsrequest import AWSRequest
13+
14+
15+
class SigV4HTTPXAuth(httpx.Auth):
16+
"""Signs HTTP requests with AWS SigV4 for Lambda function URL authentication."""
17+
18+
def __init__(self):
19+
session = boto3.Session()
20+
credentials = session.get_credentials().get_frozen_credentials()
21+
region = session.region_name or os.environ.get("AWS_REGION", "us-east-1")
22+
self.signer = SigV4Auth(credentials, "lambda", region)
23+
24+
def auth_flow(self, request):
25+
headers = dict(request.headers)
26+
headers.pop("connection", None)
27+
aws_request = AWSRequest(
28+
method=request.method,
29+
url=str(request.url),
30+
data=request.content,
31+
headers=headers,
32+
)
33+
self.signer.add_auth(aws_request)
34+
request.headers.update(dict(aws_request.headers))
35+
yield request
36+
{{/if}}
37+
38+
39+
def get_streamable_http_mcp_client() -> MultiServerMCPClient | None:
40+
"""Returns an MCP Client connected to the {{gatewayProviders.[0].name}} gateway."""
41+
url = os.environ.get("{{gatewayProviders.[0].envVarName}}")
42+
if not url:
43+
logger.warning("{{gatewayProviders.[0].envVarName}} not set — gateway tools unavailable")
44+
return None
45+
46+
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
47+
http_client = httpx.AsyncClient(auth=SigV4HTTPXAuth())
48+
return MultiServerMCPClient(
49+
{
50+
"{{gatewayProviders.[0].name}}": {
51+
"transport": "streamable_http",
52+
"url": url,
53+
"http_client": http_client,
54+
}
55+
}
56+
)
57+
{{else}}
58+
return MultiServerMCPClient(
59+
{
60+
"{{gatewayProviders.[0].name}}": {
61+
"transport": "streamable_http",
62+
"url": url,
63+
}
64+
}
65+
)
66+
{{/if}}
67+
{{else}}
368
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
469
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
570

671

772
def get_streamable_http_mcp_client() -> MultiServerMCPClient:
8-
"""
9-
Returns an MCP Client compatible with LangChain/LangGraph.
10-
"""
73+
"""Returns an MCP Client compatible with LangChain/LangGraph."""
1174
# to use an MCP server that supports bearer authentication, add headers={"Authorization": f"Bearer {access_token}"}
1275
return MultiServerMCPClient(
1376
{
@@ -17,3 +80,4 @@ def get_streamable_http_mcp_client() -> MultiServerMCPClient:
1780
}
1881
}
1982
)
83+
{{/if}}

src/assets/python/openaiagents/base/main.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,22 @@ def add_numbers(a: int, b: int) -> int:
3030
async def main(query):
3131
ensure_credentials_loaded()
3232
try:
33-
async with mcp_server as server:
34-
active_servers = [server] if server else []
33+
if mcp_server:
34+
async with mcp_server as server:
35+
active_servers = [server]
36+
agent = Agent(
37+
name="{{ name }}",
38+
model="gpt-4.1",
39+
mcp_servers=active_servers,
40+
tools=[add_numbers]
41+
)
42+
result = await Runner.run(agent, query)
43+
return result
44+
else:
3545
agent = Agent(
3646
name="{{ name }}",
3747
model="gpt-4.1",
38-
mcp_servers=active_servers,
48+
mcp_servers=[],
3949
tools=[add_numbers]
4050
)
4151
result = await Runner.run(agent, query)
Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,67 @@
1+
import os
2+
import logging
13
from agents.mcp import MCPServerStreamableHttp
24

5+
logger = logging.getLogger(__name__)
6+
7+
{{#if hasGateway}}
8+
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
9+
import boto3
10+
import httpx
11+
from botocore.auth import SigV4Auth
12+
from botocore.awsrequest import AWSRequest
13+
14+
15+
class SigV4HTTPXAuth(httpx.Auth):
16+
"""Signs HTTP requests with AWS SigV4 for Lambda function URL authentication."""
17+
18+
def __init__(self):
19+
session = boto3.Session()
20+
credentials = session.get_credentials().get_frozen_credentials()
21+
region = session.region_name or os.environ.get("AWS_REGION", "us-east-1")
22+
self.signer = SigV4Auth(credentials, "lambda", region)
23+
24+
def auth_flow(self, request):
25+
headers = dict(request.headers)
26+
headers.pop("connection", None)
27+
aws_request = AWSRequest(
28+
method=request.method,
29+
url=str(request.url),
30+
data=request.content,
31+
headers=headers,
32+
)
33+
self.signer.add_auth(aws_request)
34+
request.headers.update(dict(aws_request.headers))
35+
yield request
36+
{{/if}}
37+
38+
39+
def get_streamable_http_mcp_client() -> MCPServerStreamableHttp | None:
40+
"""Returns an MCP Client connected to the {{gatewayProviders.[0].name}} gateway."""
41+
url = os.environ.get("{{gatewayProviders.[0].envVarName}}")
42+
if not url:
43+
logger.warning("{{gatewayProviders.[0].envVarName}} not set — gateway tools unavailable")
44+
return None
45+
46+
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
47+
http_client = httpx.AsyncClient(auth=SigV4HTTPXAuth())
48+
return MCPServerStreamableHttp(
49+
name="{{gatewayProviders.[0].name}}", params={"url": url, "http_client": http_client}
50+
)
51+
{{else}}
52+
return MCPServerStreamableHttp(
53+
name="{{gatewayProviders.[0].name}}", params={"url": url}
54+
)
55+
{{/if}}
56+
{{else}}
357
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
458
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
559

660

761
def get_streamable_http_mcp_client() -> MCPServerStreamableHttp:
8-
"""
9-
Returns an MCP Client compatible with OpenAI Agents SDK.
10-
"""
62+
"""Returns an MCP Client compatible with OpenAI Agents SDK."""
1163
# to use an MCP server that supports bearer authentication, add headers={"Authorization": f"Bearer {access_token}"}
1264
return MCPServerStreamableHttp(
1365
name="AgentCore Gateway MCP", params={"url": EXAMPLE_MCP_ENDPOINT}
1466
)
67+
{{/if}}

src/assets/python/strands/base/main.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ def add_numbers(a: int, b: int) -> int:
2222
return a+b
2323
tools.append(add_numbers)
2424

25+
# Add MCP client to tools if available
26+
if mcp_client:
27+
tools.append(mcp_client)
28+
2529

2630
{{#if hasMemory}}
2731
def agent_factory():
@@ -36,7 +40,7 @@ def get_or_create_agent(session_id, user_id):
3640
system_prompt="""
3741
You are a helpful assistant. Use tools when appropriate.
3842
""",
39-
tools=tools+[mcp_client]
43+
tools=tools
4044
)
4145
return cache[key]
4246
return get_or_create_agent
@@ -52,7 +56,7 @@ def get_or_create_agent():
5256
system_prompt="""
5357
You are a helpful assistant. Use tools when appropriate.
5458
""",
55-
tools=tools+[mcp_client]
59+
tools=tools
5660
)
5761
return _agent
5862
{{/if}}

0 commit comments

Comments
 (0)