Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
782ed12
initial commit
naga-gaddamu May 30, 2026
943136d
Add AgentCore Web Search Tool samples and workshop content
naga-gaddamu Jun 3, 2026
cf286d2
feat: add deep-research-agent with auto-provisioning and search priva…
naga-gaddamu Jun 5, 2026
d07fea8
Adding nagagaddamu to the contributors.md
naga-gaddamu Jun 9, 2026
5d543cf
Merge pull request #1 from nagagaddamu/web-search-feature
nagagaddamu Jun 9, 2026
0366359
security: remove hardcoded Cognito credentials from setup README
naga-gaddamu Jun 9, 2026
e9d8fee
Merge pull request #2 from nagagaddamu/web-search-feature-v2
nagagaddamu Jun 9, 2026
f51901a
chore: remove 03-Agent-Core-web-search workshop (to be added in separ…
naga-gaddamu Jun 9, 2026
2cb91d3
workshop read me clean up
naga-gaddamu Jun 9, 2026
0707d3f
Merge pull request #3 from nagagaddamu/web-search-feature-v2
nagagaddamu Jun 9, 2026
32c52ec
docs: remove web-search workshop references and add deep-research-age…
naga-gaddamu Jun 9, 2026
4f3434b
Merge pull request #4 from nagagaddamu/web-search-feature-v2
nagagaddamu Jun 9, 2026
7ea8c5b
security: write credentials to .env file instead of logging to stdout
naga-gaddamu Jun 12, 2026
7243495
Merge pull request #5 from nagagaddamu/web-search-feature-v2
nagagaddamu Jun 12, 2026
7a5431f
fix: add request timeout and update search privacy wording
naga-gaddamu Jun 12, 2026
c872593
Merge pull request #6 from nagagaddamu/web-search-feature-v2
nagagaddamu Jun 12, 2026
9475ce9
Fixed recommendations from vedashreevinay
naga-gaddamu Jun 12, 2026
ffb6f94
Merge pull request #7 from nagagaddamu/web-search-feature-v2
nagagaddamu Jun 12, 2026
f530248
Merge branch 'main' into main
nagagaddamu Jun 12, 2026
27da737
deep research agent use cases restructure + updated ascii workflow to…
naga-gaddamu Jun 15, 2026
a6fb30f
refactor: restructure web-search by key learning and add self-contain…
naga-gaddamu Jun 15, 2026
23cba12
Testing post NY Summit boto3 sdk release
naga-gaddamu Jun 18, 2026
f48b0dc
Merge pull request #1 from nagagaddamu/usecase-restructure
nagagaddamu Jun 18, 2026
f7bb899
Changes to follow naming convention 'AgentCore gateway ' AgentCore we…
naga-gaddamu Jun 22, 2026
a2bf6e0
Merge pull request #2 from nagagaddamu/usecase-restructure
nagagaddamu Jun 23, 2026
f1f3fb8
Update README.md
nagagaddamu Jun 23, 2026
a4defde
Update README.md
nagagaddamu Jun 23, 2026
0209197
Update web_search_strands.py
nagagaddamu Jun 23, 2026
5bda933
Update web_search_langchain.py
nagagaddamu Jun 23, 2026
472f705
Fixing linting issues and CodeQL alerts
naga-gaddamu Jun 23, 2026
0931733
Merge pull request #3 from nagagaddamu/usecase-restructure
nagagaddamu Jun 23, 2026
008bc4b
Fixed Ruff issues
naga-gaddamu Jun 23, 2026
442ccac
Merge pull request #4 from nagagaddamu/usecase-restructure
nagagaddamu Jun 23, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ celerybeat.pid

# Environments
.env
.env.*
.venv
env/
venv/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Raw MCP Tool Discovery and Invocation

## Overview

This example calls the AgentCore gateway directly over the MCP protocol — no agent framework involved. It's the simplest way to verify your Gateway and Web Search Tool target are working correctly.

> 🔒 **Search Privacy**: The Web Search Tool queries an AWS-maintained search index. Queries do not route to any third-party search engines or external providers.

![Raw MCP Client web search Architecture](images/raw-mcp-call-architecture.png)

## Prerequisites

- Python 3.10+
- AWS account with Amazon Bedrock enabled in **us-east-1**
- AWS credentials with IAM, Cognito, and AgentCore gateway permissions

## How It Works

The script performs three operations against the Gateway:

### Step 1: Authenticate

An OAuth token is obtained from Cognito using the `client_credentials` flow. The token is attached as a `Bearer` header on the MCP Streamable HTTP transport. This is handled internally by `create_streamable_http_transport()`.

```python
from utils.gateway_auth import create_streamable_http_transport

transport = create_streamable_http_transport()
```

### Step 2: Discover Tools (`tools/list`)

The MCP `tools/list` call returns all tools available on the Gateway. For a Gateway with the Web Search connector target, you'll see:

```json
{
"name": "WebSearch",
"description": "Search the web for current information",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search query (max 200 characters)"
}
},
"required": ["query"]
}
}
```

### Step 3: Invoke the Tool (`tools/call`)

Calling the tool with a query returns structured results:

```json
{
"results": [
{
"text": "Snippet from the web page...",
"url": "https://example.com/article",
"title": "Article Title",
"publishedDate": "2026-05-28"
}
]
}
```

## Files

| File | Description |
|:-----|:------------|
| `raw_mcp_call.py` | Main example script — tool discovery and invocation |

## Quick Start

```bash
# Install dependencies
pip install -r ../requirements.txt
#python3 -m pip install --upgrade --force-reinstall boto3

# Set up the Gateway (creates IAM role, Cognito, Gateway, Web Search target)
python setup_gateway.py
#python setup_gateway.py --gateway-name my-web-search-gw

# Load credentials into your shell
source .env.web-search

# Run the example — discovers WebSearch tool and invokes it
python raw_mcp_call.py

# Try a custom query
python raw_mcp_call.py --query "Latest Python release"
python raw_mcp_call.py --query "AWS re:Invent 2026 announcements"
```

| Parameter | Required | Description |
|:----------|:---------|:------------|
| `--query` | No | Search query (default: built-in example query) |

## Cleanup (Optional)

When you're done remove all provisioned AWS resources:

**1. Retrieve resource IDs** from the setup output (printed when you ran `setup_gateway.py`):

```
Gateway ID: <printed during setup>
IAM Role: agentcore-web-search-gateway-role
Cognito Pool: <printed during setup>
```

> **Tip:** If you no longer have the terminal output, the gateway ID is the subdomain prefix in your `AGENTCORE_GATEWAY_URL` (e.g., `gw-abc123` from `https://gw-abc123.gateway.bedrock-agentcore...`). The IAM role follows the pattern `agentcore-<gateway-name>-role`.

**2. Run cleanup:**

```bash
python cleanup.py --gateway-id <id> --user-pool-id <id> --role-name <name>
```

| Parameter | Required | Description |
|:----------|:---------|:------------|
| `--gateway-id` | Yes | Gateway ID |
| `--user-pool-id` | Yes | Cognito User Pool ID |
| `--role-name` | Yes | IAM role name |
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"""
Clean up all resources created by the Web Search Tool setup.

Deletes in order:
1. Gateway targets and Gateway
2. Cognito User Pool (domain, clients, pool)
3. IAM Role and inline policies

Prerequisites:
pip install -r ../requirements.txt
AWS credentials with permissions to delete the resources.

Usage:
python cleanup.py --gateway-id <id> --user-pool-id <id> --role-name <name>
python cleanup.py --gateway-id gw-abc123 --user-pool-id us-east-1_AbCdEf --role-name agentcore-web-search-gateway-role
"""

import argparse
import os
import time

import boto3

REGION = os.getenv("AWS_DEFAULT_REGION", "us-east-1")


def delete_gateway(gateway_client, gateway_id):
"""Delete all targets and the gateway itself."""
print("\n[1/3] Deleting Gateway resources...")
try:
targets = gateway_client.list_gateway_targets(gatewayIdentifier=gateway_id, maxResults=100)
for item in targets["items"]:
gateway_client.delete_gateway_target(gatewayIdentifier=gateway_id, targetId=item["targetId"])
print(f" Deleted target: {item['name']}")

time.sleep(10)
gateway_client.delete_gateway(gatewayIdentifier=gateway_id)
print(f" Deleted gateway: {gateway_id}")
except Exception as e:
print(f" Error deleting gateway: {e}")


def delete_cognito(cognito_client, user_pool_id):
"""Delete the Cognito User Pool and its domain."""
print("\n[2/3] Deleting Cognito resources...")
try:
domain = user_pool_id.replace("_", "").lower()
cognito_client.delete_user_pool_domain(Domain=domain, UserPoolId=user_pool_id)
cognito_client.delete_user_pool(UserPoolId=user_pool_id)
print(f" Deleted user pool: {user_pool_id}")
except Exception as e:
print(f" Error deleting Cognito: {e}")


def delete_iam_role(iam_client, role_name):
"""Delete the IAM role and its inline policies."""
print("\n[3/3] Deleting IAM resources...")
try:
policies = iam_client.list_role_policies(RoleName=role_name)
for policy_name in policies["PolicyNames"]:
iam_client.delete_role_policy(RoleName=role_name, PolicyName=policy_name)
print(f" Deleted policy: {policy_name}")

iam_client.delete_role(RoleName=role_name)
print(f" Deleted role: {role_name}")
except Exception as e:
print(f" Error deleting IAM role: {e}")


def parse_args():
parser = argparse.ArgumentParser(description="Clean up Web Search Tool Gateway resources")
parser.add_argument("--gateway-id", required=True, help="Gateway ID to delete")
parser.add_argument("--user-pool-id", required=True, help="Cognito User Pool ID to delete")
parser.add_argument("--role-name", required=True, help="IAM role name to delete")
parser.add_argument("--region", default=REGION, help="AWS region (default: us-east-1)")
return parser.parse_args()


def main():
args = parse_args()
region = args.region

print("=" * 60)
print("AgentCore web search tool — Resource Cleanup")
print("=" * 60)
print(f"\nRegion: {region}")
print(f"Gateway ID: {args.gateway_id}")
print(f"User Pool ID: {args.user_pool_id}")
print(f"Role Name: {args.role_name}")

gateway_client = boto3.client("bedrock-agentcore-control", region_name=region)
cognito_client = boto3.client("cognito-idp", region_name=region)
iam_client = boto3.client("iam")

delete_gateway(gateway_client, args.gateway_id)
delete_cognito(cognito_client, args.user_pool_id)
delete_iam_role(iam_client, args.role_name)

# Remove local credentials file
env_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env.web-search")
if os.path.exists(env_file):
os.remove(env_file)
print(f"\n Deleted local credentials file: {env_file}")

print("\n" + "=" * 60)
print("✅ All resources cleaned up successfully!")
print("=" * 60)


if __name__ == "__main__":
main()
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"""
Raw MCP Tool Discovery and Invocation against AgentCore gateway.

Demonstrates direct MCP protocol calls without an agent framework:
1. Connect to the Gateway using MCP Streamable HTTP transport
2. Call tools/list to discover the WebSearch tool and its schema
3. Call tools/call to invoke WebSearch with a test query
4. Display the structured results

This is useful for verifying your Gateway setup before integrating
with an agent framework.

Prerequisites:
pip install -r ../requirements.txt
Export environment variables from 01-setup-gateway/setup_gateway.py

Environment variables required:
AGENTCORE_GATEWAY_URL — Gateway MCP endpoint
COGNITO_DOMAIN — Cognito domain prefix
COGNITO_CLIENT_ID — Cognito app client ID
COGNITO_CLIENT_SECRET — Cognito app client secret
COGNITO_SCOPE — OAuth scope string

IAM permissions required:
bedrock-agentcore:InvokeGateway (via OAuth token)

Usage:
python raw_mcp_call.py
python raw_mcp_call.py --query "Latest Python release"
"""

import argparse
import json
import os
import sys

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from utils.gateway_auth import create_streamable_http_transport

from strands.tools.mcp.mcp_client import MCPClient

# ── Configuration ─────────────────────────────────────────────────────────────

DEFAULT_QUERY = "Tesla stock price right now?"


# ── Main ──────────────────────────────────────────────────────────────────────


def parse_args():
parser = argparse.ArgumentParser(description="Raw MCP tool discovery and invocation against AgentCore gateway")
parser.add_argument(
"--query",
default=DEFAULT_QUERY,
help=f"Search query (default: '{DEFAULT_QUERY}')",
)
return parser.parse_args()


def main():
args = parse_args()

print("=" * 60)
print("AgentCore web search tool — Raw MCP Calls")
print("=" * 60)

# Create MCP client
transport_factory = create_streamable_http_transport()
mcp_client = MCPClient(transport_factory)

with mcp_client:
# Step 1: Discover tools
print("\n[1] Discovering tools (tools/list)...\n")
tools = mcp_client.list_tools_sync()
print(f" Found {len(tools)} tool(s):\n")

for tool in tools:
spec = tool.tool_spec
print(f" Name: {spec['name']}")
print(f" Description: {spec.get('description', 'N/A')}")
schema_str = json.dumps(spec.get("inputSchema", {}), indent=2)
# Truncate long schemas for readability
if len(schema_str) > 200:
schema_str = schema_str[:200] + "..."
print(f" Input: {schema_str}")
print()

# Step 2: Invoke WebSearch
print("=" * 60)
print(f"[2] Calling WebSearch: '{args.query}'")
print("=" * 60 + "\n")

# Find the WebSearch tool
ws_tools = [t for t in tools if "WebSearch" in t.tool_name]
if not ws_tools:
print(" ERROR: WebSearch tool not found. Check your Gateway target.")
return

ws_tool_name = ws_tools[0].tool_name
result = mcp_client.call_tool_sync("raw-mcp-demo", ws_tool_name, {"query": args.query})

# Step 3: Display results
print("[3] Results:\n")
for content in result.get("content", result if isinstance(result, list) else [result]):
if isinstance(content, dict) and "text" in content:
try:
parsed = json.loads(content["text"])
print(json.dumps(parsed, indent=2))
except (ValueError, TypeError):
print(content["text"][:2000])
else:
print(content)

print("\n" + "=" * 60)
print("Demo complete!")
print("=" * 60)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Set up AgentCore gateway with Web Search Tool — delegates to shared utility.
After running this script, load credentials with `source .env.web-search` to use
with the other web search examples.

Usage:
python setup_gateway.py
python setup_gateway.py --gateway-name my-gateway
python setup_gateway.py --region us-east-1
"""

import sys
import os

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from utils.gateway_setup import main

if __name__ == "__main__":
main()
Loading
Loading