Skip to content

Commit add47b2

Browse files
authored
feat: add gateway auth and multi-gateway support to agent templates (#427)
* 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. * feat: add multi-gateway support and fix template rendering Replace single-gateway [0] indexing with {{#each gatewayProviders}} loops. Each gateway gets its own client function (Strands) or entry in the servers dict (LangChain/OpenAI/AutoGen/ADK). Add snakeCase Handlebars helper for gateway function names. Add gatewayAuthTypes array for conditional SigV4 imports. Fix @index parse error by using plain variable names. * fix: update main.py files with gateway conditional imports All 5 framework main.py files now use Handlebars conditionals to import the correct MCP client function based on hasGateway flag. Fix snakeCase helper to handle all special characters. * style: fix formatting * refactor: use mcp-proxy-for-aws for gateway auth, remove AutoGen gateway support Replace custom SigV4HTTPXAuth class with official mcp-proxy-for-aws package: - Strands: aws_iam_streamablehttp_client factory pattern - LangChain: SigV4HTTPXAuth via auth param in MultiServerMCPClient config - OpenAI Agents: SigV4HTTPXAuth via httpx_client_factory param - Google ADK: SigV4HTTPXAuth via httpx_client_factory in StreamableHTTPConnectionParams Revert AutoGen to original upstream — SDK doesn't support custom httpx auth (no httpx_client_factory param). * fix: pass AWS region to aws_iam_streamablehttp_client in Strands template
1 parent 4f277e7 commit add47b2

22 files changed

Lines changed: 511 additions & 64 deletions

File tree

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

Lines changed: 226 additions & 25 deletions
Large diffs are not rendered by default.

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
from google.genai import types
66
from bedrock_agentcore.runtime import BedrockAgentCoreApp
77
from model.load import load_model
8+
{{#if hasGateway}}
9+
from mcp_client.client import get_all_gateway_mcp_toolsets
10+
{{else}}
811
from mcp_client.client import get_streamable_http_mcp_client
12+
{{/if}}
913

1014
app = BedrockAgentCoreApp()
1115
log = app.logger
@@ -23,7 +27,12 @@ def add_numbers(a: int, b: int) -> int:
2327

2428

2529
# Get MCP Toolset
26-
mcp_toolset = [get_streamable_http_mcp_client()]
30+
{{#if hasGateway}}
31+
mcp_toolset = get_all_gateway_mcp_toolsets()
32+
{{else}}
33+
mcp_client = get_streamable_http_mcp_client()
34+
mcp_toolset = [mcp_client] if mcp_client else []
35+
{{/if}}
2736

2837
_credentials_loaded = False
2938

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,45 @@
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 (includes gatewayAuthTypes "AWS_IAM")}}
10+
import httpx
11+
from mcp_proxy_for_aws.sigv4_helper import SigV4HTTPXAuth, create_aws_session
12+
{{/if}}
13+
14+
def get_all_gateway_mcp_toolsets() -> list[MCPToolset]:
15+
"""Returns MCP Toolsets for all configured gateways."""
16+
toolsets = []
17+
{{#each gatewayProviders}}
18+
url = os.environ.get("{{envVarName}}")
19+
if url:
20+
{{#if (eq authType "AWS_IAM")}}
21+
session = create_aws_session()
22+
auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
23+
toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(
24+
url=url,
25+
httpx_client_factory=lambda **kwargs: httpx.AsyncClient(auth=auth, **kwargs)
26+
)))
27+
{{else}}
28+
toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(url=url)))
29+
{{/if}}
30+
else:
31+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
32+
{{/each}}
33+
return toolsets
34+
{{else}}
435
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
536
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
637

738

839
def get_streamable_http_mcp_client() -> MCPToolset:
9-
"""
10-
Returns an MCP Toolset compatible with Google ADK.
11-
"""
40+
"""Returns an MCP Toolset compatible with Google ADK."""
1241
# to use an MCP server that supports bearer authentication, add headers={"Authorization": f"Bearer {access_token}"}
1342
return MCPToolset(
1443
connection_params=StreamableHTTPConnectionParams(url=EXAMPLE_MCP_ENDPOINT)
1544
)
45+
{{/if}}

src/assets/python/googleadk/base/pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ dependencies = [
1414
"google-adk >= 1.17.0",
1515
"bedrock-agentcore >= 1.0.3",
1616
"botocore[crt] >= 1.35.0",
17+
{{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0",
18+
{{/if}}{{/if}}
1719
]
1820

1921
[tool.hatch.build.targets.wheel]

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
from langchain.tools import tool
55
from bedrock_agentcore.runtime import BedrockAgentCoreApp
66
from model.load import load_model
7+
{{#if hasGateway}}
8+
from mcp_client.client import get_all_gateway_mcp_client
9+
{{else}}
710
from mcp_client.client import get_streamable_http_mcp_client
11+
{{/if}}
812

913
app = BedrockAgentCoreApp()
1014
log = app.logger
@@ -34,10 +38,16 @@ async def invoke(payload, context):
3438
log.info("Invoking Agent.....")
3539

3640
# Get MCP Client
41+
{{#if hasGateway}}
42+
mcp_client = get_all_gateway_mcp_client()
43+
{{else}}
3744
mcp_client = get_streamable_http_mcp_client()
45+
{{/if}}
3846

3947
# Load MCP Tools
40-
mcp_tools = await mcp_client.get_tools()
48+
mcp_tools = []
49+
if mcp_client:
50+
mcp_tools = await mcp_client.get_tools()
4151

4252
# Define the agent using create_react_agent
4353
graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools)
Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,40 @@
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 (includes gatewayAuthTypes "AWS_IAM")}}
9+
from mcp_proxy_for_aws.sigv4_helper import SigV4HTTPXAuth, create_aws_session
10+
{{/if}}
11+
12+
def get_all_gateway_mcp_client() -> MultiServerMCPClient | None:
13+
"""Returns an MCP Client connected to all configured gateways."""
14+
servers = {}
15+
{{#each gatewayProviders}}
16+
url = os.environ.get("{{envVarName}}")
17+
if url:
18+
{{#if (eq authType "AWS_IAM")}}
19+
session = create_aws_session()
20+
auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
21+
servers["{{name}}"] = {"transport": "streamable_http", "url": url, "auth": auth}
22+
{{else}}
23+
servers["{{name}}"] = {"transport": "streamable_http", "url": url}
24+
{{/if}}
25+
else:
26+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
27+
{{/each}}
28+
if not servers:
29+
return None
30+
return MultiServerMCPClient(servers)
31+
{{else}}
332
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
433
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
534

635

736
def get_streamable_http_mcp_client() -> MultiServerMCPClient:
8-
"""
9-
Returns an MCP Client compatible with LangChain/LangGraph.
10-
"""
37+
"""Returns an MCP Client compatible with LangChain/LangGraph."""
1138
# to use an MCP server that supports bearer authentication, add headers={"Authorization": f"Bearer {access_token}"}
1239
return MultiServerMCPClient(
1340
{
@@ -17,3 +44,4 @@ def get_streamable_http_mcp_client() -> MultiServerMCPClient:
1744
}
1845
}
1946
)
47+
{{/if}}

src/assets/python/langchain_langgraph/base/pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ dependencies = [
3030
{{#if (eq modelProvider "Gemini")}}
3131
"langchain-google-genai >= 3.0.3",
3232
{{/if}}
33+
{{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0",
34+
{{/if}}{{/if}}
3335
]
3436

3537
[tool.hatch.build.targets.wheel]

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

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,22 @@
22
from agents import Agent, Runner, function_tool
33
from bedrock_agentcore.runtime import BedrockAgentCoreApp
44
from model.load import load_model
5+
{{#if hasGateway}}
6+
from mcp_client.client import get_all_gateway_mcp_servers
7+
{{else}}
58
from mcp_client.client import get_streamable_http_mcp_client
9+
{{/if}}
610

711
app = BedrockAgentCoreApp()
812
log = app.logger
913

1014
# Get MCP Server
15+
{{#if hasGateway}}
16+
mcp_servers = get_all_gateway_mcp_servers()
17+
{{else}}
1118
mcp_server = get_streamable_http_mcp_client()
19+
mcp_servers = [mcp_server] if mcp_server else []
20+
{{/if}}
1221

1322
_credentials_loaded = False
1423

@@ -30,16 +39,47 @@ def add_numbers(a: int, b: int) -> int:
3039
async def main(query):
3140
ensure_credentials_loaded()
3241
try:
33-
async with mcp_server as server:
34-
active_servers = [server] if server else []
42+
{{#if hasGateway}}
43+
if mcp_servers:
3544
agent = Agent(
3645
name="{{ name }}",
3746
model="gpt-4.1",
38-
mcp_servers=active_servers,
47+
mcp_servers=mcp_servers,
3948
tools=[add_numbers]
4049
)
4150
result = await Runner.run(agent, query)
4251
return result
52+
else:
53+
agent = Agent(
54+
name="{{ name }}",
55+
model="gpt-4.1",
56+
mcp_servers=[],
57+
tools=[add_numbers]
58+
)
59+
result = await Runner.run(agent, query)
60+
return result
61+
{{else}}
62+
if mcp_servers:
63+
async with mcp_servers[0] as server:
64+
active_servers = [server]
65+
agent = Agent(
66+
name="{{ name }}",
67+
model="gpt-4.1",
68+
mcp_servers=active_servers,
69+
tools=[add_numbers]
70+
)
71+
result = await Runner.run(agent, query)
72+
return result
73+
else:
74+
agent = Agent(
75+
name="{{ name }}",
76+
model="gpt-4.1",
77+
mcp_servers=[],
78+
tools=[add_numbers]
79+
)
80+
result = await Runner.run(agent, query)
81+
return result
82+
{{/if}}
4383
except Exception as e:
4484
log.error(f"Error during agent execution: {e}", exc_info=True)
4585
raise e
Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,44 @@
1+
import os
2+
import logging
13
from agents.mcp import MCPServerStreamableHttp
24

5+
logger = logging.getLogger(__name__)
6+
7+
{{#if hasGateway}}
8+
{{#if (includes gatewayAuthTypes "AWS_IAM")}}
9+
import httpx
10+
from mcp_proxy_for_aws.sigv4_helper import SigV4HTTPXAuth, create_aws_session
11+
{{/if}}
12+
13+
def get_all_gateway_mcp_servers() -> list[MCPServerStreamableHttp]:
14+
"""Returns MCP servers for all configured gateways."""
15+
servers = []
16+
{{#each gatewayProviders}}
17+
url = os.environ.get("{{envVarName}}")
18+
if url:
19+
{{#if (eq authType "AWS_IAM")}}
20+
session = create_aws_session()
21+
auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
22+
servers.append(MCPServerStreamableHttp(
23+
name="{{name}}",
24+
params={"url": url, "httpx_client_factory": lambda **kwargs: httpx.AsyncClient(auth=auth, **kwargs)}
25+
))
26+
{{else}}
27+
servers.append(MCPServerStreamableHttp(name="{{name}}", params={"url": url}))
28+
{{/if}}
29+
else:
30+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
31+
{{/each}}
32+
return servers
33+
{{else}}
334
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
435
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
536

637

738
def get_streamable_http_mcp_client() -> MCPServerStreamableHttp:
8-
"""
9-
Returns an MCP Client compatible with OpenAI Agents SDK.
10-
"""
39+
"""Returns an MCP Client compatible with OpenAI Agents SDK."""
1140
# to use an MCP server that supports bearer authentication, add headers={"Authorization": f"Bearer {access_token}"}
1241
return MCPServerStreamableHttp(
1342
name="AgentCore Gateway MCP", params={"url": EXAMPLE_MCP_ENDPOINT}
1443
)
44+
{{/if}}

src/assets/python/openaiagents/base/pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ dependencies = [
1313
"openai-agents >= 0.4.2",
1414
"bedrock-agentcore >= 1.0.3",
1515
"botocore[crt] >= 1.35.0",
16+
{{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0",
17+
{{/if}}{{/if}}
1618
]
1719

1820
[tool.hatch.build.targets.wheel]

0 commit comments

Comments
 (0)