From 75f74f2b2bccd0de4aba996699f788aa0cbbc35d Mon Sep 17 00:00:00 2001 From: Nithin Chandran Rajashankar Date: Thu, 18 Jun 2026 18:26:20 +0000 Subject: [PATCH] feat(agentcore-web-search): Add AgentCore Gateway Web Search pattern Deploy an Amazon Bedrock AgentCore Gateway with the managed Web Search Tool connector. An AWS Lambda function demonstrates querying the gateway via MCP protocol to ground AI agents in current web knowledge. First serverless pattern using AgentCore Web Search (launched June 17 at AWS Summit NYC). Zero infrastructure to provision -- the connector provides fully managed web search backed by Amazon's web index. --- agentcore-web-search-cdk/.gitignore | 6 ++ agentcore-web-search-cdk/README.md | 72 ++++++++++++++++ agentcore-web-search-cdk/bin/app.ts | 8 ++ agentcore-web-search-cdk/cdk.json | 3 + agentcore-web-search-cdk/example-pattern.json | 85 +++++++++++++++++++ .../lib/agentcore-web-search-stack.ts | 71 ++++++++++++++++ agentcore-web-search-cdk/package.json | 17 ++++ agentcore-web-search-cdk/src/handler/index.py | 75 ++++++++++++++++ agentcore-web-search-cdk/tsconfig.json | 26 ++++++ 9 files changed, 363 insertions(+) create mode 100644 agentcore-web-search-cdk/.gitignore create mode 100644 agentcore-web-search-cdk/README.md create mode 100644 agentcore-web-search-cdk/bin/app.ts create mode 100644 agentcore-web-search-cdk/cdk.json create mode 100644 agentcore-web-search-cdk/example-pattern.json create mode 100644 agentcore-web-search-cdk/lib/agentcore-web-search-stack.ts create mode 100644 agentcore-web-search-cdk/package.json create mode 100644 agentcore-web-search-cdk/src/handler/index.py create mode 100644 agentcore-web-search-cdk/tsconfig.json diff --git a/agentcore-web-search-cdk/.gitignore b/agentcore-web-search-cdk/.gitignore new file mode 100644 index 0000000000..576a01fe73 --- /dev/null +++ b/agentcore-web-search-cdk/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +cdk.out/ +*.js +*.d.ts +build/ +cdk.context.json diff --git a/agentcore-web-search-cdk/README.md b/agentcore-web-search-cdk/README.md new file mode 100644 index 0000000000..64ba186872 --- /dev/null +++ b/agentcore-web-search-cdk/README.md @@ -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 \ + --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 diff --git a/agentcore-web-search-cdk/bin/app.ts b/agentcore-web-search-cdk/bin/app.ts new file mode 100644 index 0000000000..d891dfc179 --- /dev/null +++ b/agentcore-web-search-cdk/bin/app.ts @@ -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' }, +}); diff --git a/agentcore-web-search-cdk/cdk.json b/agentcore-web-search-cdk/cdk.json new file mode 100644 index 0000000000..debd1380e0 --- /dev/null +++ b/agentcore-web-search-cdk/cdk.json @@ -0,0 +1,3 @@ +{ + "app": "node build/bin/app.js" +} diff --git a/agentcore-web-search-cdk/example-pattern.json b/agentcore-web-search-cdk/example-pattern.json new file mode 100644 index 0000000000..724c72f172 --- /dev/null +++ b/agentcore-web-search-cdk/example-pattern.json @@ -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": [ + "npx cdk deploy" + ] + }, + "testing": { + "text": [ + "After deployment, invoke the AWS Lambda function with a query:", + "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" + ] + }, + "cleanup": { + "text": [ + "npx cdk destroy" + ] + }, + "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" + } + } +} diff --git a/agentcore-web-search-cdk/lib/agentcore-web-search-stack.ts b/agentcore-web-search-cdk/lib/agentcore-web-search-stack.ts new file mode 100644 index 0000000000..6276b1c166 --- /dev/null +++ b/agentcore-web-search-cdk/lib/agentcore-web-search-stack.ts @@ -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 }); + } +} diff --git a/agentcore-web-search-cdk/package.json b/agentcore-web-search-cdk/package.json new file mode 100644 index 0000000000..2b203f7eec --- /dev/null +++ b/agentcore-web-search-cdk/package.json @@ -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" + } +} diff --git a/agentcore-web-search-cdk/src/handler/index.py b/agentcore-web-search-cdk/src/handler/index.py new file mode 100644 index 0000000000..1ac23386bb --- /dev/null +++ b/agentcore-web-search-cdk/src/handler/index.py @@ -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)}), + } diff --git a/agentcore-web-search-cdk/tsconfig.json b/agentcore-web-search-cdk/tsconfig.json new file mode 100644 index 0000000000..e7b20346a0 --- /dev/null +++ b/agentcore-web-search-cdk/tsconfig.json @@ -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"] +}