DEV Community

Cover image for MCPfying Tools Securely at Scale with Bedrock AgentCore Gateway

MCPfying Tools Securely at Scale with Bedrock AgentCore Gateway

As organizations move from single-agent experiments to production-grade agentic systems, the bottleneck is rarely the model. It’s the tool layer: how teams expose capabilities, how agents discover the right tools, how invocation is standardized across heterogeneous backends, and how governance is enforced consistently as usage scales.

In this article, I describe an enterprise pattern for “MCP-fying” internal tools using Amazon Bedrock AgentCore Gateway—treating it as a centralized MCP front door for tool discovery and invocation. The goal is not to wrap one function, but to establish a repeatable approach that reduces duplicated integrations, supports multi-team ownership, and creates a foundation for secure, scalable tool access across the organization.

AgentCore Gateway as an enterprise tool layer

Amazon Bedrock AgentCore Gateway AgentCore Gateway is a managed tool front door that exposes organizational capabilities as discoverable, invokable tools through an MCP-compatible interface. Instead of every agent framework integrating separately with every backend service, you register backends behind the gateway as targets, define tool schemas (contracts) once, and let clients interact through one consistent surface.

Clients typically use three MCP-style operations:

  • Tool discovery (what tools exist).
  • Tool search/filtering (find the right tool at scale).
  • Tool invocation (run a tool with inputs).

AgentCore Gateway as the MCP tool front door with identity, IAM execution, and observability

Key capabilities of AgentCore Gateway

AgentCore Gateway provides a set of capabilities designed to standardize and simplify tool integration across teams and agent frameworks:

  • Unified MCP endpoint – A stable entry point that exposes tools through a consistent contract for discovery, search, and invocation.
  • Protocol translation & request routing – Converts MCP tool calls into the appropriate backend action and routes requests to the correct target/tool implementation.
  • Composition (many tools, one front door) – Aggregates tools from multiple backends so agents integrate once with the gateway instead of many services directly.
  • Targets for enterprise backends – Connect common enterprise surfaces as tool targets, such as:

  • AWS Lambda

  • OpenAPI-defined APIs

  • Smithy models

In this article we focus on MCPfying tools with AWS Lambda.

  • Managed operations – Centralizes telemetry and operational visibility (for example via Amazon CloudWatch) for troubleshooting and governance.
  • Scalable discovery – Supports narrowing the toolset at runtime (semantic search / filtered discovery) to reduce tool overload and improve tool selection in large catalogs.

OK, enough theory. Let’s build!

What we’ll build

  1. Configure identity (inbound) and Create the Gateway
  2. Add a Lambda target + IAM execution role (outbound)
  3. Connect a Strands agent to the Gateway (MCP client)
  4. Invoke tools through the agent

The full notebook (end-to-end) is available in my repo:

1. Configure identity (inbound) and Create the Gateway

For this implementation I use bedrock_agentcore_starter_toolkit which is AWS’s CLI-based starter toolkit for deploying Python agents to Amazon Bedrock AgentCore Runtime with “zero infrastructure” to manage—so you can go from local code to a running agent quickly.

import logging
from bedrock_agentcore_starter_toolkit.operations.gateway.client import GatewayClient

client = GatewayClient(region_name=os.environ["AWS_DEFAULT_REGION"])

cognito_authorizer = client.create_oauth_authorizer_with_cognito("agentcore-gateway-test")

# Create Gateway (MCP) and capture identifiers
gateway = client.create_mcp_gateway(authorizer_config=cognito_authorizer["authorizer_config"])
gateway_id = gateway["gatewayId"]
gateway_url = gateway["gatewayUrl"]
Enter fullscreen mode Exit fullscreen mode

We need gateway_id and gateway_url later.

2. Add a Lambda target + IAM execution role (outbound)

When you use bedrock_agentcore_starter_toolkit with create_mcp_gateway_target, the SDK automatically provisions an AWS Lambda function that includes two example tools: a helper-created AWS Lambda target exposing get_weather and get_time. You can see that lambda in your console.

lambda_target_1 = client.create_mcp_gateway_target(
    gateway=gateway,
    target_type="lambda"  # helper creates/uses a default lambda + tool schema
)
Enter fullscreen mode Exit fullscreen mode

In this tutorial, we’ll go a step further by creating a custom Lambda-backed target with a simple tool that returns a random number (Option B). In order to do that we need to :

  1. Create an AWS Lambda function and copy its function ARN.
  2. Create a Gateway target for that Lambda using create_mcp_gateway_target.
  3. Define the tool schema (contract) so the Gateway knows the tool name, inputs, and what output to expect.

explicit target payload (more realistic)
This is the part that matters most for enterprise usage: you’re defining the tool contract (schema) explicitly.

lambda_target_configuration = {
    "lambdaArn": "arn:aws:lambda:REGION:ACCOUNT_ID:function:agentCoreGatewayCustomLambda",
    "toolSchema": {
        "inlinePayload": [
            {
                "name": "get_random_number",
                "description": "Return a random number",
                "inputSchema": {"type": "object", "properties": {}, "required": []},
                "outputSchema": {"type": "integer"},
            }
        ]
    },
}

lambda_target_2 = client.create_mcp_gateway_target(
    gateway=gateway,
    target_type="lambda",
    target_payload=lambda_target_configuration,
)
Enter fullscreen mode Exit fullscreen mode

3) Connect a Strands agent to the Gateway (MCP client)
Cool! Now let’s create an agent with Strands and connect it to the AgentCore Gateway as an MCP client. Two important details from the working flow: refresh the access token before connecting (Cognito tokens expire), and keep the MCP client running while the agent is operating (start it once—don’t recreate it per call).
After connecting, your first sanity check is to list the tools exposed by the Gateway—if ListTools doesn’t return what you expect, the issue is usually the Authorization header, the /mcp suffix, or the Gateway target/tool configuration, not the agent itself.

from strands import Agent
from strands.models import BedrockModel
from strands.tools.mcp.mcp_client import MCPClient
from mcp.client.streamable_http import streamablehttp_client

# refresh token
access_token = client.get_access_token_for_cognito(cognito_authorizer["client_info"])

# ensure /mcp suffix
mcp_url = gateway_url if gateway_url.endswith("/mcp") else f"{gateway_url}/mcp"

mcp_client = MCPClient(
    lambda: streamablehttp_client(
        url=mcp_url,
        headers={"Authorization": f"Bearer {access_token}"},
    )
)

mcp_client.start()
tools = mcp_client.list_tools_sync()

# Bedrock model for the agent
model = BedrockModel(model_id="eu.amazon.nova-pro-v1:0")  # choose your model
agent = Agent(model=model, tools=tools)

print("Loaded tools:", agent.tool_names)
Enter fullscreen mode Exit fullscreen mode

You’ll see tools like:

  • \<TargetName\>___get_weather
  • \<TargetName\>___get_time
  • \<TargetName\>___get_random_number

4) Invoke tools through the agent

response = agent("Get the time for ECT")
print(response)
Enter fullscreen mode Exit fullscreen mode

You should be able to see this in the output:

The user has requested the time for ECT, which stands for Eastern Caribbean Time. I need to use the TestGatewayTargetc7c8080f___get_time tool to get the current time for this timezone. Tool #1: TestGatewayTargetc7c8080f___get_time
The current time in Eastern Caribbean Time (ECT) is 2:30 PM.Response: The current time in Eastern Caribbean Time (ECT) is 2:30 PM.

This validates the full chain:
Agent **→ **MCP clientAgentCore GatewayLambda targettool response

Cleanup (important)

# Stop MCP client
try:
    if mcp_client.is_running():
        mcp_client.stop()
except Exception:
    pass

# Delete targets (repeat for every created targetId)
# Example: delete both targets you created
client.delete_gateway_target(gateway_id, lambda_target_1["targetId"])
client.delete_gateway_target(gateway_id, lambda_target_2["targetId"])

# Now delete gateway
client.delete_gateway(gateway_id)
Enter fullscreen mode Exit fullscreen mode

Practical notes from this implementation

  • Tool schema is the real product surface. Treat it like an API contract (names, descriptions, input schema quality).
  • Target naming matters. The final tool name includes the target name prefix; keep it stable and readable.
  • Keep the MCP client session alive while the agent is running, otherwise tool calls will fail.
  • You get enterprise-friendly operational behavior because the tool access surface is centralized (and can be governed consistently later).

Summary

This article shows how Amazon Bedrock AgentCore Gateway acts as an enterprise “tool front door”: agents don’t integrate with every backend directly—instead they connect once over Model Context Protocol to discover, search, and invoke tools through a single stable endpoint.

You then walk through a practical build: creating a gateway, wiring identity (inbound auth via AgentCore Identity and an IdP like Amazon Cognito), connecting an AWS Lambda target with an IAM execution role (outbound auth), defining tool schemas (contracts), and validating everything end-to-end by connecting a Strands Agents MCP client to list tools and run invocations.

Resources

My GitHub (full notebook + code)

Top comments (0)