From b0de5ad4646c057b97790abc21a3fd124e3abdd2 Mon Sep 17 00:00:00 2001 From: petterlindstrom79 Date: Wed, 1 Apr 2026 15:35:13 +0200 Subject: [PATCH] =?UTF-8?q?Add=20Strale=20integration=20=E2=80=94=20trust?= =?UTF-8?q?=20&=20compliance=20via=20AgentCore=20Gateway?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03-integrations/gateway/strale/README.md | 225 ++++++++++++++++ .../gateway/strale/agent-example.py | 245 ++++++++++++++++++ .../gateway/strale/gateway-config.json | 35 +++ 3 files changed, 505 insertions(+) create mode 100644 03-integrations/gateway/strale/README.md create mode 100644 03-integrations/gateway/strale/agent-example.py create mode 100644 03-integrations/gateway/strale/gateway-config.json diff --git a/03-integrations/gateway/strale/README.md b/03-integrations/gateway/strale/README.md new file mode 100644 index 000000000..3c30d42f8 --- /dev/null +++ b/03-integrations/gateway/strale/README.md @@ -0,0 +1,225 @@ +# Connecting External MCP Servers to AgentCore: Strale Trust & Compliance + +> [!IMPORTANT] +> This is an educational example. Review the code and understand the resources created before running in your AWS account. + +## Overview + +This example connects [Strale](https://strale.dev) — a trust and quality infrastructure platform with 250+ verified data capabilities — to Amazon Bedrock AgentCore Gateway as a remote MCP server. Once connected, any agent using the gateway can validate IBANs, look up companies across 27 country registries, screen against sanctions lists, extract structured data from URLs, and more. + +Strale's MCP server uses Streamable HTTP transport at `https://api.strale.io/mcp`. AgentCore's semantic tool search makes all 250+ capabilities discoverable by description, not just by name. + +| Information | Details | +|:---------------------|:-------------------------------------------| +| Use case type | Integration — External MCP Server | +| Agent type | Strands Agent with remote MCP tools | +| Use case components | Gateway, Identity, Tools | +| Use case vertical | Financial Services / Compliance | +| Example complexity | Easy | +| SDK used | boto3 + strands-agents + mcp | + +## Architecture + +``` +┌──────────────┐ ┌─────────────────────┐ ┌──────────────────┐ +│ │ │ AgentCore Gateway │ │ Strale MCP │ +│ Your Agent │────▶│ (Semantic Search) │────▶│ api.strale.io │ +│ (Strands) │ │ │ │ 250+ tools │ +└──────────────┘ └─────────────────────┘ └──────────────────┘ + │ │ │ + │ Claude Sonnet │ JWT Auth │ Bearer Token + │ │ Tool Discovery │ Quality Scores + ▼ ▼ ▼ + Natural language Auto-discovers 8 Validated data with + compliance queries Strale meta-tools provenance + audit trail +``` + +The agent asks questions in natural language. AgentCore's semantic search finds the right Strale tool. Strale executes the capability and returns structured JSON with a quality score, data provenance, and an audit trail. + +## Prerequisites + +- AWS account with Bedrock AgentCore access (us-east-1) +- Python 3.10+ +- Strale API key — sign up at [strale.dev/signup](https://strale.dev/signup) (free EUR 2.00 trial credits, no card required) + +## Quick Start + +### 1. Install dependencies + +```bash +pip install boto3 strands-agents mcp +``` + +### 2. Set environment variables + +```bash +export AWS_REGION=us-east-1 +export STRALE_API_KEY=sk_live_your_key_here +``` + +### 3. Run the example + +```bash +python agent-example.py +``` + +This creates an AgentCore Gateway, registers Strale's MCP server as a target, and provides a gateway URL for connecting agents. + +## Step-by-Step + +### Create the Gateway + +```python +import boto3 + +client = boto3.client('bedrock-agentcore-control', region_name='us-east-1') + +response = client.create_gateway( + name='strale-compliance-gateway', + roleArn=role_arn, + protocolType='MCP', + protocolConfiguration={ + 'mcp': { + 'supportedVersions': ['2025-03-26'], + 'searchType': 'SEMANTIC' + } + }, + description='Gateway with Strale trust & compliance capabilities' +) + +gateway_id = response['gatewayId'] +gateway_url = response['gatewayUrl'] +``` + +### Register Strale as a Remote Target + +```python +# Store your Strale API key as a credential provider +provider = client.create_api_key_credential_provider( + name='strale-api-key', + apiKey=os.environ['STRALE_API_KEY'], +) + +# Register the MCP server +client.create_gateway_target( + gatewayIdentifier=gateway_id, + name='strale-mcp-target', + targetConfiguration={ + 'mcp': { + 'mcpServer': { + 'endpoint': 'https://api.strale.io/mcp' + } + } + }, + credentialProviderConfigurations=[{ + 'credentialProviderType': 'API_KEY', + 'credentialProvider': { + 'apiKeyCredentialProvider': { + 'providerArn': provider['credentialProviderArn'], + 'credentialParameterName': 'Authorization', + 'credentialPrefix': 'Bearer ', + 'credentialLocation': 'HEADER', + } + } + }] +) +``` + +After registration, AgentCore automatically discovers Strale's 8 meta-tools: + +| Tool | Description | +|------|-------------| +| `strale_search` | Search 250+ capabilities by keyword | +| `strale_execute` | Run any capability by slug | +| `strale_trust_profile` | Check quality score before calling | +| `strale_balance` | Check wallet balance | +| `strale_ping` | Health check | +| `strale_getting_started` | Free capabilities with examples | +| `strale_methodology` | Quality scoring methodology | +| `strale_transaction` | Retrieve past execution records | + +### Connect an Agent + +```python +from mcp.client.streamable_http import streamablehttp_client +from strands import Agent +from strands.models import BedrockModel +from strands.tools.mcp.mcp_client import MCPClient + +def create_transport(): + return streamablehttp_client( + gateway_url, + headers={"Authorization": f"Bearer {access_token}"} + ) + +mcp_client = MCPClient(create_transport) +model = BedrockModel(model_id="us.anthropic.claude-sonnet-4-20250514-v1:0") + +with mcp_client: + tools = mcp_client.list_tools_sync() + agent = Agent(model=model, tools=tools) + + # The agent can now use any Strale capability + agent("Validate IBAN DE89370400440532013000") + agent("Look up the Swedish company with org number 5591674668") + agent("Is the pep-check capability reliable enough for production?") +``` + +### Use Semantic Search + +AgentCore's gateway supports semantic tool search. Agents can discover the right Strale capability without knowing the exact slug: + +```bash +curl -X POST $GATEWAY_URL \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -d '{ + "jsonrpc": "2.0", + "method": "tools/call", + "params": { + "name": "x_amz_bedrock_agentcore_search", + "arguments": {"query": "validate a European bank account number"} + }, + "id": 1 + }' +``` + +This returns `strale_execute` as a match, with `iban-validate` as the suggested slug. + +## Free Tier + +Five Strale capabilities work without an API key (10 calls/day): + +- `email-validate` — verify email deliverability +- `iban-validate` — validate international bank account numbers +- `dns-lookup` — DNS records for any domain +- `url-to-markdown` — convert any URL to markdown +- `json-repair` — fix malformed JSON + +## Cleanup + +```bash +python agent-example.py +# Follow the prompts to delete the gateway and target +``` + +Or manually: + +```python +client.delete_gateway_target( + gatewayIdentifier=gateway_id, + targetIdentifier=target_id +) +client.delete_gateway(gatewayIdentifier=gateway_id) +``` + +## Links + +- [Strale Documentation](https://strale.dev/docs) +- [Capability Catalog](https://api.strale.io/v1/capabilities) +- [AgentCore Gateway Documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/agentcore-gateway.html) +- [Strale MCP Server on npm](https://www.npmjs.com/package/strale-mcp) + +## License + +Apache-2.0 diff --git a/03-integrations/gateway/strale/agent-example.py b/03-integrations/gateway/strale/agent-example.py new file mode 100644 index 000000000..d109501df --- /dev/null +++ b/03-integrations/gateway/strale/agent-example.py @@ -0,0 +1,245 @@ +""" +Strale Compliance Agent — AgentCore + Strale MCP Integration + +Demonstrates connecting Strale's MCP server to Amazon Bedrock AgentCore +Gateway for trust-sensitive data operations: IBAN validation, company +lookups, and sanctions screening. + +Prerequisites: + - AWS account with Bedrock AgentCore access (us-east-1) + - Strale API key (free at https://strale.dev/signup) + - Python 3.10+ + +Install: + pip install boto3 strands-agents mcp + +Usage: + export AWS_REGION=us-east-1 + export STRALE_API_KEY=sk_live_your_key_here + python agent-example.py +""" + +import json +import os +import sys + +import boto3 + + +# ── Configuration ────────────────────────────────────────────────────────────── + +REGION = os.environ.get("AWS_REGION", "us-east-1") +STRALE_API_KEY = os.environ.get("STRALE_API_KEY", "") +GATEWAY_NAME = "strale-compliance-gateway" +TARGET_NAME = "strale-mcp-target" + + +# ── Step 1: Create Gateway ───────────────────────────────────────────────────── + +def create_gateway(client: "boto3.client") -> tuple[str, str]: + """Create an AgentCore MCP Gateway with semantic search enabled.""" + print("Creating AgentCore Gateway...") + + # Get or create IAM role for the gateway + iam = boto3.client("iam", region_name=REGION) + role_name = f"agentcore-{GATEWAY_NAME}-role" + + try: + role = iam.get_role(RoleName=role_name) + role_arn = role["Role"]["Arn"] + except iam.exceptions.NoSuchEntityException: + trust_policy = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"Service": "bedrock-agentcore.amazonaws.com"}, + "Action": "sts:AssumeRole", + } + ], + } + role = iam.create_role( + RoleName=role_name, + AssumeRolePolicyDocument=json.dumps(trust_policy), + Description="AgentCore Gateway role for Strale integration", + ) + role_arn = role["Role"]["Arn"] + print(f" Created IAM role: {role_arn}") + + response = client.create_gateway( + name=GATEWAY_NAME, + roleArn=role_arn, + protocolType="MCP", + protocolConfiguration={ + "mcp": { + "supportedVersions": ["2025-03-26"], + "searchType": "SEMANTIC", + } + }, + description="Gateway with Strale trust & compliance capabilities", + ) + + gateway_id = response["gatewayId"] + gateway_url = response["gatewayUrl"] + print(f" Gateway created: {gateway_id}") + print(f" Gateway URL: {gateway_url}") + return gateway_id, gateway_url + + +# ── Step 2: Register Strale MCP Server ───────────────────────────────────────── + +def register_strale_target( + client: "boto3.client", gateway_id: str +) -> str: + """Register Strale as a remote MCP server target.""" + print("Registering Strale MCP server...") + + # Create API key credential provider for Strale auth + provider_response = client.create_api_key_credential_provider( + name="strale-api-key", + apiKey=STRALE_API_KEY, + ) + provider_arn = provider_response["credentialProviderArn"] + print(f" Credential provider: {provider_arn}") + + # Register the MCP server target + target_response = client.create_gateway_target( + gatewayIdentifier=gateway_id, + name=TARGET_NAME, + targetConfiguration={ + "mcp": { + "mcpServer": { + "endpoint": "https://api.strale.io/mcp", + } + } + }, + credentialProviderConfigurations=[ + { + "credentialProviderType": "API_KEY", + "credentialProvider": { + "apiKeyCredentialProvider": { + "providerArn": provider_arn, + "credentialParameterName": "Authorization", + "credentialPrefix": "Bearer ", + "credentialLocation": "HEADER", + } + }, + } + ], + ) + + target_id = target_response["targetId"] + print(f" Target registered: {target_id}") + print(" Strale tools are now discoverable via the gateway.") + return target_id + + +# ── Step 3: Use the Agent ────────────────────────────────────────────────────── + +def run_agent(gateway_url: str, access_token: str) -> None: + """Run a compliance agent that uses Strale tools via the gateway.""" + try: + from mcp.client.streamable_http import streamablehttp_client + from strands import Agent + from strands.models import BedrockModel + from strands.tools.mcp.mcp_client import MCPClient + except ImportError: + print("\nInstall agent dependencies: pip install strands-agents mcp") + print("Then re-run this script.") + return + + print("\nConnecting to gateway and discovering tools...") + + def create_transport(): + return streamablehttp_client( + gateway_url, + headers={"Authorization": f"Bearer {access_token}"}, + ) + + mcp_client = MCPClient(create_transport) + + model = BedrockModel( + model_id="us.anthropic.claude-sonnet-4-20250514-v1:0", + temperature=0.3, + max_tokens=2000, + ) + + with mcp_client: + tools = mcp_client.list_tools_sync() + tool_names = [t.name for t in tools] + strale_tools = [n for n in tool_names if n.startswith("strale_")] + print(f" Discovered {len(tools)} tools, {len(strale_tools)} from Strale") + + agent = Agent(model=model, tools=tools) + + # Example 1: Validate an IBAN (free, no credits used) + print("\n--- Example 1: IBAN Validation (free) ---") + result = agent( + "Validate this IBAN: DE89370400440532013000. " + "Use the strale_execute tool with slug 'iban-validate'." + ) + print(result) + + # Example 2: Look up a Swedish company + print("\n--- Example 2: Company Lookup ---") + result = agent( + "Look up the Swedish company with org number 5591674668 using Strale. " + "First search for the right capability, then execute it." + ) + print(result) + + # Example 3: Check quality before calling + print("\n--- Example 3: Quality Check ---") + result = agent( + "Before running a sanctions check, use strale_trust_profile " + "to check the quality score for 'pep-check'. " + "Is it reliable enough for production use?" + ) + print(result) + + +# ── Step 4: Cleanup ──────────────────────────────────────────────────────────── + +def cleanup(client: "boto3.client", gateway_id: str, target_id: str) -> None: + """Remove the gateway and target.""" + print("\nCleaning up...") + try: + client.delete_gateway_target( + gatewayIdentifier=gateway_id, targetIdentifier=target_id + ) + print(f" Deleted target: {target_id}") + except Exception as e: + print(f" Target deletion: {e}") + + try: + client.delete_gateway(gatewayIdentifier=gateway_id) + print(f" Deleted gateway: {gateway_id}") + except Exception as e: + print(f" Gateway deletion: {e}") + + +# ── Main ─────────────────────────────────────────────────────────────────────── + +def main() -> None: + if not STRALE_API_KEY: + print("Set STRALE_API_KEY environment variable.") + print("Get a free key at https://strale.dev/signup") + sys.exit(1) + + client = boto3.client("bedrock-agentcore-control", region_name=REGION) + + gateway_id, gateway_url = create_gateway(client) + target_id = register_strale_target(client, gateway_id) + + # In production, you'd get the access token from Cognito/OIDC. + # For this example, we use a placeholder. + print("\nTo run the agent, obtain an access token from your gateway's") + print("OIDC provider and call run_agent(gateway_url, access_token).") + print(f"\nGateway URL: {gateway_url}") + + input("\nPress Enter to clean up resources...") + cleanup(client, gateway_id, target_id) + + +if __name__ == "__main__": + main() diff --git a/03-integrations/gateway/strale/gateway-config.json b/03-integrations/gateway/strale/gateway-config.json new file mode 100644 index 000000000..b30bb370f --- /dev/null +++ b/03-integrations/gateway/strale/gateway-config.json @@ -0,0 +1,35 @@ +{ + "gateway": { + "name": "strale-compliance-gateway", + "protocolType": "MCP", + "protocolConfiguration": { + "mcp": { + "supportedVersions": ["2025-03-26"], + "searchType": "SEMANTIC" + } + }, + "description": "AgentCore Gateway with Strale trust & compliance capabilities" + }, + "target": { + "name": "strale-mcp-server", + "targetConfiguration": { + "mcp": { + "mcpServer": { + "endpoint": "https://api.strale.io/mcp" + } + } + }, + "credentialProviderConfigurations": [ + { + "credentialProviderType": "API_KEY", + "credentialProvider": { + "apiKeyCredentialProvider": { + "credentialParameterName": "Authorization", + "credentialPrefix": "Bearer ", + "credentialLocation": "HEADER" + } + } + } + ] + } +}