Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions agentcore-web-search-cdk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
cdk.out/
*.js
*.d.ts
build/
cdk.context.json
72 changes: 72 additions & 0 deletions agentcore-web-search-cdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Amazon Bedrock AgentCore Gateway with Web Search Tool

This pattern deploys an Amazon Bedrock AgentCore Gateway with a managed Web Search Tool connector target and an AWS Lambda function that invokes the gateway to answer questions using live web data.

Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/agentcore-web-search-cdk

Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.

## Requirements

* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
* [Node.js 18+](https://nodejs.org/en/download/) installed
* [AWS CDK v2](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html) installed

## Architecture

1. **Amazon Bedrock AgentCore Gateway** - Hosts the Web Search Tool as a connector target with IAM authorization
2. **Web Search Tool Connector** - A managed connector that provides live web search capabilities without external API keys
3. **AWS Lambda Function** - Invokes the gateway to perform web searches and return results

## Deployment Instructions

1. Install dependencies:
```bash
npm install
```

2. Build the project:
```bash
npx tsc
```

3. Deploy the stack (us-east-1 only):
```bash
npx cdk deploy
```

## How it works

The Amazon Bedrock AgentCore Gateway provides a unified connectivity layer between agents and tools. The Web Search Tool is a managed connector (`web-search`) that lets agents retrieve information from the live web without any external search service API keys or infrastructure.

The AWS Lambda function demonstrates invoking the gateway's web search tool by calling the `invoke_tool` API with a query string (max 200 characters) and optional `maxResults` parameter (1-25).

## Testing

After deployment, invoke the AWS Lambda function:

```bash
aws lambda invoke \
--function-name <FunctionName from stack output> \
--payload '{"query": "What is Amazon Bedrock AgentCore?"}' \
--cli-binary-format raw-in-base64-out \
output.json && cat output.json
```

You can also pass `maxResults` (1-25) in the event payload to control the number of search results returned.

## Cleanup

```bash
npx cdk destroy
```

## Author

* **Nithin Chandran R** - [LinkedIn](https://www.linkedin.com/in/nithin-chandran-r/)

----
Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

SPDX-License-Identifier: MIT-0
8 changes: 8 additions & 0 deletions agentcore-web-search-cdk/bin/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { AgentcoreWebSearchStack } from '../lib/agentcore-web-search-stack';

const app = new cdk.App();
new AgentcoreWebSearchStack(app, 'AgentcoreWebSearchStack', {
env: { region: 'us-east-1' },
});
3 changes: 3 additions & 0 deletions agentcore-web-search-cdk/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "node build/bin/app.js"
}
85 changes: 85 additions & 0 deletions agentcore-web-search-cdk/example-pattern.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"title": "Amazon Bedrock AgentCore Gateway with Web Search Tool",
"description": "This pattern deploys an Amazon Bedrock AgentCore Gateway with a Web Search Tool connector target and an AWS Lambda function that invokes the gateway to perform live web searches.",
"language": "Python",
"level": "200",
"framework": "AWS CDK",
"introBox": {
"headline": "How it works",
"text": [
"This pattern demonstrates how to use Amazon Bedrock AgentCore Gateway with the managed Web Search Tool connector.",
"The Amazon Bedrock AgentCore Gateway hosts the web search tool as a target, enabling agents to retrieve live web data.",
"An AWS Lambda function invokes the gateway to perform web searches and return results."
]
},
"gitHub": {
"template": {
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/agentcore-web-search-cdk",
"templateURL": "serverless-patterns/agentcore-web-search-cdk",
"projectFolder": "agentcore-web-search-cdk"
}
},
"resources": {
"bullets": [
{
"text": "Amazon Bedrock AgentCore Gateway Documentation",
"link": "https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway.html"
},
{
"text": "Web Search Tool as Connector Target",
"link": "https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-target-connector-web-search-tool.html"
}
]
},
"deploy": {
"text": [
"<code>npx cdk deploy</code>"
]
},
"testing": {
"text": [
"After deployment, invoke the AWS Lambda function with a query:",
"<code>aws lambda invoke --function-name FUNCTION_NAME --payload '{\"query\": \"What is Amazon Bedrock AgentCore?\"}' --cli-binary-format raw-in-base64-out output.json && cat output.json</code>"
]
},
"cleanup": {
"text": [
"<code>npx cdk destroy</code>"
]
},
"authors": [
{
"name": "Nithin Chandran R",
"bio": "Cloud Engineer",
"linkedin": "nithin-chandran-r"
}
],
"patternArch": {
"icon1": {
"x": 20,
"y": 50,
"service": "bedrock",
"label": "AgentCore Gateway"
},
"icon2": {
"x": 50,
"y": 50,
"service": "bedrock",
"label": "Web Search Tool"
},
"icon3": {
"x": 80,
"y": 50,
"service": "lambda",
"label": "AWS Lambda"
},
"line1": {
"from": "icon1",
"to": "icon2"
},
"line2": {
"from": "icon3",
"to": "icon1"
}
}
}
71 changes: 71 additions & 0 deletions agentcore-web-search-cdk/lib/agentcore-web-search-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import * as cdk from 'aws-cdk-lib';
import * as agentcore from 'aws-cdk-lib/aws-bedrockagentcore';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import path = require('path');
import { Construct } from 'constructs';

export class AgentcoreWebSearchStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

// Amazon Bedrock AgentCore Gateway with IAM authorization
const gateway = new agentcore.Gateway(this, 'WebSearchGateway', {
gatewayName: 'web-search-gateway',
description: 'Amazon Bedrock AgentCore Gateway with Web Search Tool connector',
authorizerConfiguration: agentcore.GatewayAuthorizer.usingAwsIam(),
});

// Web Search connector target using CfnResource (L1)
const webSearchTarget = new cdk.CfnResource(this, 'WebSearchTarget', {
type: 'AWS::BedrockAgentCore::GatewayTarget',
properties: {
GatewayIdentifier: gateway.gatewayId,
Name: 'web-search-target',
TargetConfiguration: {
Mcp: {
Connector: {
Source: { ConnectorId: 'web-search' },
Configurations: [
{
Name: 'WebSearch',
ParameterValues: {},
},
],
},
},
},
CredentialProviderConfigurations: [
{ CredentialProviderType: 'GATEWAY_IAM_ROLE' },
],
},
});

// Grant the gateway role permission to invoke web search
gateway.role.addToPrincipalPolicy(new iam.PolicyStatement({
actions: ['bedrock-agentcore:InvokeWebSearch'],
resources: [
`arn:aws:bedrock-agentcore:${this.region}:aws:tool/web-search.v1`,
],
}));

// AWS Lambda function to invoke the gateway
const fn = new lambda.Function(this, 'WebSearchFunction', {
runtime: lambda.Runtime.PYTHON_3_12,
handler: 'index.handler',
code: lambda.Code.fromAsset(path.join(__dirname, '..', '..', 'src', 'handler')),
timeout: cdk.Duration.seconds(30),
environment: {
GATEWAY_ID: gateway.gatewayId,
GATEWAY_URL: gateway.gatewayUrl ?? '',
},
});

// Grant the AWS Lambda function permission to invoke the gateway
gateway.grantInvoke(fn);

// Outputs
new cdk.CfnOutput(this, 'GatewayId', { value: gateway.gatewayId });
new cdk.CfnOutput(this, 'FunctionName', { value: fn.functionName });
}
}
17 changes: 17 additions & 0 deletions agentcore-web-search-cdk/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "agentcore-web-search-cdk",
"version": "1.0.0",
"scripts": {
"build": "tsc",
"cdk": "cdk"
},
"dependencies": {
"aws-cdk-lib": "2.260.0",
"constructs": "^10.4.2"
},
"devDependencies": {
"@types/node": "^22.0.0",
"typescript": "~5.7.0",
"aws-cdk": "2.1128.0"
}
}
75 changes: 75 additions & 0 deletions agentcore-web-search-cdk/src/handler/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""
AWS Lambda function that invokes an Amazon Bedrock AgentCore Gateway
with the Web Search Tool to answer questions using live web data.
"""

import json
import os
import urllib.request


def handler(event, context):
"""Invoke the Amazon Bedrock AgentCore Gateway web search tool via MCP protocol."""
try:
gateway_id = os.environ["GATEWAY_ID"]
region = os.environ.get("AWS_REGION", "us-east-1")
endpoint = os.environ.get(
"GATEWAY_URL",
f"https://{gateway_id}.gateway.bedrock-agentcore.{region}.amazonaws.com/mcp",
)

import botocore.session
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest

session = botocore.session.get_session()
credentials = session.get_credentials().get_frozen_credentials()

action = event.get("action", "search")

if action == "list_tools":
mcp_request = {"jsonrpc": "2.0", "id": "1", "method": "tools/list", "params": {}}
else:
query = event.get("query", "What is Amazon Bedrock AgentCore?")
max_results = event.get("maxResults", 5)
tool_name = event.get("toolName", "web-search-target___WebSearch")
mcp_request = {
"jsonrpc": "2.0",
"id": "1",
"method": "tools/call",
"params": {
"name": tool_name,
"arguments": {
"query": query[:200],
"maxResults": min(max(int(max_results), 1), 25),
},
},
}

payload = json.dumps(mcp_request).encode("utf-8")

request = AWSRequest(
method="POST",
url=endpoint,
data=payload,
headers={"Content-Type": "application/json", "Accept": "application/json"},
)
SigV4Auth(credentials, "bedrock-agentcore", region).add_auth(request)

req = urllib.request.Request(
endpoint, data=payload, headers=dict(request.headers), method="POST",
)

with urllib.request.urlopen(req, timeout=25) as resp:
response_body = json.loads(resp.read().decode("utf-8"))

return {
"statusCode": 200,
"body": json.dumps({"results": response_body}),
}

except Exception as e:
return {
"statusCode": 500,
"body": json.dumps({"error": str(e)}),
}
26 changes: 26 additions & 0 deletions agentcore-web-search-cdk/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"lib": ["es2022", "esnext.disposable"],
"declaration": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noImplicitThis": true,
"alwaysStrict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": false,
"inlineSourceMap": true,
"inlineSources": true,
"experimentalDecorators": true,
"strictPropertyInitialization": false,
"outDir": "./build",
"rootDir": ".",
"types": ["node"],
"skipLibCheck": true
},
"exclude": ["node_modules", "cdk.out"]
}