Skip to content

Commit 7b014fa

Browse files
committed
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.
1 parent 25dfb37 commit 7b014fa

9 files changed

Lines changed: 154 additions & 270 deletions

File tree

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

Lines changed: 74 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -988,46 +988,18 @@ from autogen_ext.tools.mcp import (
988988
logger = logging.getLogger(__name__)
989989
990990
{{#if hasGateway}}
991-
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
992-
import boto3
993-
import httpx
994-
from botocore.auth import SigV4Auth
995-
from botocore.awsrequest import AWSRequest
996-
997-
998-
class SigV4HTTPXAuth(httpx.Auth):
999-
"""Signs HTTP requests with AWS SigV4 for Lambda function URL authentication."""
1000-
1001-
def __init__(self):
1002-
session = boto3.Session()
1003-
credentials = session.get_credentials().get_frozen_credentials()
1004-
region = session.region_name or os.environ.get("AWS_REGION", "us-east-1")
1005-
self.signer = SigV4Auth(credentials, "lambda", region)
1006-
1007-
def auth_flow(self, request):
1008-
headers = dict(request.headers)
1009-
headers.pop("connection", None)
1010-
aws_request = AWSRequest(
1011-
method=request.method,
1012-
url=str(request.url),
1013-
data=request.content,
1014-
headers=headers,
1015-
)
1016-
self.signer.add_auth(aws_request)
1017-
request.headers.update(dict(aws_request.headers))
1018-
yield request
1019-
{{/if}}
1020-
1021-
1022-
async def get_streamable_http_mcp_tools() -> List[StreamableHttpMcpToolAdapter]:
1023-
"""Returns MCP Tools from the {{gatewayProviders.[0].name}} gateway."""
1024-
url = os.environ.get("{{gatewayProviders.[0].envVarName}}")
1025-
if not url:
1026-
logger.warning("{{gatewayProviders.[0].envVarName}} not set — gateway tools unavailable")
1027-
return []
1028-
1029-
server_params = StreamableHttpServerParams(url=url)
1030-
return await mcp_server_tools(server_params)
991+
async def get_all_gateway_mcp_tools() -> List[StreamableHttpMcpToolAdapter]:
992+
"""Returns MCP Tools from all configured gateways."""
993+
tools = []
994+
{{#each gatewayProviders}}
995+
url = os.environ.get("{{envVarName}}")
996+
if url:
997+
server_params = StreamableHttpServerParams(url=url)
998+
tools.extend(await mcp_server_tools(server_params))
999+
else:
1000+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
1001+
{{/each}}
1002+
return tools
10311003
{{else}}
10321004
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
10331005
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
@@ -1747,47 +1719,17 @@ from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnecti
17471719
logger = logging.getLogger(__name__)
17481720
17491721
{{#if hasGateway}}
1750-
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
1751-
import boto3
1752-
import httpx
1753-
from botocore.auth import SigV4Auth
1754-
from botocore.awsrequest import AWSRequest
1755-
1756-
1757-
class SigV4HTTPXAuth(httpx.Auth):
1758-
"""Signs HTTP requests with AWS SigV4 for Lambda function URL authentication."""
1759-
1760-
def __init__(self):
1761-
session = boto3.Session()
1762-
credentials = session.get_credentials().get_frozen_credentials()
1763-
region = session.region_name or os.environ.get("AWS_REGION", "us-east-1")
1764-
self.signer = SigV4Auth(credentials, "lambda", region)
1765-
1766-
def auth_flow(self, request):
1767-
headers = dict(request.headers)
1768-
headers.pop("connection", None)
1769-
aws_request = AWSRequest(
1770-
method=request.method,
1771-
url=str(request.url),
1772-
data=request.content,
1773-
headers=headers,
1774-
)
1775-
self.signer.add_auth(aws_request)
1776-
request.headers.update(dict(aws_request.headers))
1777-
yield request
1778-
{{/if}}
1779-
1780-
1781-
def get_streamable_http_mcp_client() -> MCPToolset | None:
1782-
"""Returns an MCP Toolset connected to the {{gatewayProviders.[0].name}} gateway."""
1783-
url = os.environ.get("{{gatewayProviders.[0].envVarName}}")
1784-
if not url:
1785-
logger.warning("{{gatewayProviders.[0].envVarName}} not set — gateway tools unavailable")
1786-
return None
1787-
1788-
return MCPToolset(
1789-
connection_params=StreamableHTTPConnectionParams(url=url)
1790-
)
1722+
def get_all_gateway_mcp_toolsets() -> list[MCPToolset]:
1723+
"""Returns MCP Toolsets for all configured gateways."""
1724+
toolsets = []
1725+
{{#each gatewayProviders}}
1726+
url = os.environ.get("{{envVarName}}")
1727+
if url:
1728+
toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(url=url)))
1729+
else:
1730+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
1731+
{{/each}}
1732+
return toolsets
17911733
{{else}}
17921734
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
17931735
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
@@ -2040,7 +1982,7 @@ from langchain_mcp_adapters.client import MultiServerMCPClient
20401982
logger = logging.getLogger(__name__)
20411983
20421984
{{#if hasGateway}}
2043-
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
1985+
{{#if (includes gatewayAuthTypes "AWS_IAM")}}
20441986
import boto3
20451987
import httpx
20461988
from botocore.auth import SigV4Auth
@@ -2071,34 +2013,23 @@ class SigV4HTTPXAuth(httpx.Auth):
20712013
{{/if}}
20722014
20732015
2074-
def get_streamable_http_mcp_client() -> MultiServerMCPClient | None:
2075-
"""Returns an MCP Client connected to the {{gatewayProviders.[0].name}} gateway."""
2076-
url = os.environ.get("{{gatewayProviders.[0].envVarName}}")
2077-
if not url:
2078-
logger.warning("{{gatewayProviders.[0].envVarName}} not set — gateway tools unavailable")
2016+
def get_all_gateway_mcp_client() -> MultiServerMCPClient | None:
2017+
"""Returns an MCP Client connected to all configured gateways."""
2018+
servers = {}
2019+
{{#each gatewayProviders}}
2020+
url = os.environ.get("{{envVarName}}")
2021+
if url:
2022+
{{#if (eq authType "AWS_IAM")}}
2023+
servers["{{name}}"] = {"transport": "streamable_http", "url": url, "http_client": httpx.AsyncClient(auth=SigV4HTTPXAuth())}
2024+
{{else}}
2025+
servers["{{name}}"] = {"transport": "streamable_http", "url": url}
2026+
{{/if}}
2027+
else:
2028+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
2029+
{{/each}}
2030+
if not servers:
20792031
return None
2080-
2081-
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
2082-
http_client = httpx.AsyncClient(auth=SigV4HTTPXAuth())
2083-
return MultiServerMCPClient(
2084-
{
2085-
"{{gatewayProviders.[0].name}}": {
2086-
"transport": "streamable_http",
2087-
"url": url,
2088-
"http_client": http_client,
2089-
}
2090-
}
2091-
)
2092-
{{else}}
2093-
return MultiServerMCPClient(
2094-
{
2095-
"{{gatewayProviders.[0].name}}": {
2096-
"transport": "streamable_http",
2097-
"url": url,
2098-
}
2099-
}
2100-
)
2101-
{{/if}}
2032+
return MultiServerMCPClient(servers)
21022033
{{else}}
21032034
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
21042035
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
@@ -2469,7 +2400,7 @@ from agents.mcp import MCPServerStreamableHttp
24692400
logger = logging.getLogger(__name__)
24702401
24712402
{{#if hasGateway}}
2472-
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
2403+
{{#if (includes gatewayAuthTypes "AWS_IAM")}}
24732404
import boto3
24742405
import httpx
24752406
from botocore.auth import SigV4Auth
@@ -2500,23 +2431,21 @@ class SigV4HTTPXAuth(httpx.Auth):
25002431
{{/if}}
25012432
25022433
2503-
def get_streamable_http_mcp_client() -> MCPServerStreamableHttp | None:
2504-
"""Returns an MCP Client connected to the {{gatewayProviders.[0].name}} gateway."""
2505-
url = os.environ.get("{{gatewayProviders.[0].envVarName}}")
2506-
if not url:
2507-
logger.warning("{{gatewayProviders.[0].envVarName}} not set — gateway tools unavailable")
2508-
return None
2509-
2510-
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
2511-
http_client = httpx.AsyncClient(auth=SigV4HTTPXAuth())
2512-
return MCPServerStreamableHttp(
2513-
name="{{gatewayProviders.[0].name}}", params={"url": url, "http_client": http_client}
2514-
)
2515-
{{else}}
2516-
return MCPServerStreamableHttp(
2517-
name="{{gatewayProviders.[0].name}}", params={"url": url}
2518-
)
2519-
{{/if}}
2434+
def get_all_gateway_mcp_servers() -> list[MCPServerStreamableHttp]:
2435+
"""Returns MCP servers for all configured gateways."""
2436+
servers = []
2437+
{{#each gatewayProviders}}
2438+
url = os.environ.get("{{envVarName}}")
2439+
if url:
2440+
{{#if (eq authType "AWS_IAM")}}
2441+
servers.append(MCPServerStreamableHttp(name="{{name}}", params={"url": url, "http_client": httpx.AsyncClient(auth=SigV4HTTPXAuth())}))
2442+
{{else}}
2443+
servers.append(MCPServerStreamableHttp(name="{{name}}", params={"url": url}))
2444+
{{/if}}
2445+
else:
2446+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
2447+
{{/each}}
2448+
return servers
25202449
{{else}}
25212450
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
25222451
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"
@@ -2793,7 +2722,7 @@ from strands.tools.mcp.mcp_client import MCPClient
27932722
logger = logging.getLogger(__name__)
27942723
27952724
{{#if hasGateway}}
2796-
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
2725+
{{#if (includes gatewayAuthTypes "AWS_IAM")}}
27972726
import boto3
27982727
import httpx
27992728
from botocore.auth import SigV4Auth
@@ -2823,20 +2752,30 @@ class SigV4HTTPXAuth(httpx.Auth):
28232752
yield request
28242753
{{/if}}
28252754
2826-
2827-
def get_streamable_http_mcp_client() -> MCPClient | None:
2828-
"""Returns an MCP Client connected to the {{gatewayProviders.[0].name}} gateway."""
2829-
url = os.environ.get("{{gatewayProviders.[0].envVarName}}")
2755+
{{#each gatewayProviders}}
2756+
def get_{{snakeCase name}}_mcp_client() -> MCPClient | None:
2757+
"""Returns an MCP Client connected to the {{name}} gateway."""
2758+
url = os.environ.get("{{envVarName}}")
28302759
if not url:
2831-
logger.warning("{{gatewayProviders.[0].envVarName}} not set — gateway tools unavailable")
2760+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
28322761
return None
2833-
2834-
{{#if (eq gatewayProviders.[0].authType "AWS_IAM")}}
2762+
{{#if (eq authType "AWS_IAM")}}
28352763
http_client = httpx.AsyncClient(auth=SigV4HTTPXAuth())
28362764
return MCPClient(lambda: streamablehttp_client(url, http_client=http_client))
28372765
{{else}}
28382766
return MCPClient(lambda: streamablehttp_client(url))
28392767
{{/if}}
2768+
2769+
{{/each}}
2770+
def get_all_gateway_mcp_clients() -> list[MCPClient]:
2771+
"""Returns MCP clients for all configured gateways."""
2772+
clients = []
2773+
{{#each gatewayProviders}}
2774+
client = get_{{snakeCase name}}_mcp_client()
2775+
if client:
2776+
clients.append(client)
2777+
{{/each}}
2778+
return clients
28402779
{{else}}
28412780
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
28422781
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"

src/assets/python/autogen/base/mcp_client/client.py

Lines changed: 12 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,46 +10,18 @@
1010
logger = logging.getLogger(__name__)
1111

1212
{{#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)
13+
async def get_all_gateway_mcp_tools() -> List[StreamableHttpMcpToolAdapter]:
14+
"""Returns MCP Tools from all configured gateways."""
15+
tools = []
16+
{{#each gatewayProviders}}
17+
url = os.environ.get("{{envVarName}}")
18+
if url:
19+
server_params = StreamableHttpServerParams(url=url)
20+
tools.extend(await mcp_server_tools(server_params))
21+
else:
22+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
23+
{{/each}}
24+
return tools
5325
{{else}}
5426
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
5527
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"

src/assets/python/googleadk/base/mcp_client/client.py

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,17 @@
66
logger = logging.getLogger(__name__)
77

88
{{#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-
)
9+
def get_all_gateway_mcp_toolsets() -> list[MCPToolset]:
10+
"""Returns MCP Toolsets for all configured gateways."""
11+
toolsets = []
12+
{{#each gatewayProviders}}
13+
url = os.environ.get("{{envVarName}}")
14+
if url:
15+
toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(url=url)))
16+
else:
17+
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
18+
{{/each}}
19+
return toolsets
5020
{{else}}
5121
# ExaAI provides information about code through web searches, crawling and code context searches through their platform. Requires no authentication
5222
EXAMPLE_MCP_ENDPOINT = "https://mcp.exa.ai/mcp"

0 commit comments

Comments
 (0)