Nasuni AI Activate via AgentCore Gateway

Connect Nasuni's MCP server to AWS Bedrock AgentCore with OAuth 2.0 SSO.

Introduction

30 Second Summary

Organizations store millions of files across their infrastructure, but AI agents cannot access that data without a secure, permission-aware pipeline in place. Proving this connection works is the first step toward production AI integration.

In this project, you will connect AWS Bedrock AgentCore Gateway to Nasuni AI Activate's hosted MCP server. You will validate that AI tools can discover and query governed enterprise file data through a secure OAuth 2.0 Authorization Code flow.

What You'll Build

A working AgentCore Gateway that authenticates to Nasuni via SSO, discovers file data tools automatically, and returns real query results from your Nasuni volumes.

By the end of this project, you'll have:

  • A Gateway that accepts MCP requests and routes them to Nasuni with automatic OAuth token management, so your AI tools never handle raw credentials.
  • A tool discovery response proving Nasuni's file data capabilities are synchronized and queryable through the Gateway.
  • A validation script you can re-run at any time to confirm the integration still works, ready to inform production architecture decisions.
  • Secret Mission: Build a Strands Agent that answers natural language questions about your enterprise file data via the Gateway.

Are there any prerequisites?

This project requires an AWS account with Bedrock access enabled, the AWS CLI configured on your machine, and Python 3.9+ installed.

You also need Nasuni AI Activate preview access with your SSO credentials (OAuth discovery URL, client ID, and client secret) from your Nasuni onboarding materials.

Before We Start

Before any infrastructure goes up, take a moment to articulate what you are validating and why this integration matters for your organization.

Set Up IAM, Cognito, and Python Environment

Before the Gateway can manage connections and broker tokens on your behalf, it needs three foundations in place.

First, an IAM role grants the Gateway permission to perform AgentCore operations and read credentials from Secrets Manager. Second, a Cognito User Pool issues JWT tokens that authenticate inbound agent requests to the Gateway. Third, a Python environment with boto3 lets you script the entire validation programmatically.

In this step, get ready to:
  • Create an IAM role with AgentCore Gateway permissions.
  • Set up a Cognito User Pool with an App Client for JWT issuance.
  • Install boto3 and verify connectivity to the AgentCore control plane.
Create the IAM role for AgentCore Gateway

The Gateway needs an IAM service role that the bedrock-agentcore.amazonaws.com service can assume. This role authorizes the Gateway to create targets, manage OAuth tokens, and read secrets on your behalf.

  • Open the IAM console by navigating to https://console.aws.amazon.com/iam/ in your browser.
  • Select Roles in the left sidebar.
  • Click Create role.
  • Select Custom trust policy as the trusted entity type.
  • Paste the following trust policy JSON into the editor:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "bedrock-agentcore.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Why no Condition block?

The official docs recommend adding aws:SourceAccount and aws:SourceArn conditions after the Gateway is created, since you do not know the Gateway ARN yet. For this validation, the simplified trust policy is sufficient.

  • Click Next.
  • On the Add permissions page, click Create policy (this opens a new tab).
  • In the policy editor, select the JSON tab and paste the following permissions policy:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "GatewayAndTargetOperations",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:CreateGateway",
        "bedrock-agentcore:GetGateway",
        "bedrock-agentcore:DeleteGateway",
        "bedrock-agentcore:UpdateGateway",
        "bedrock-agentcore:CreateGatewayTarget",
        "bedrock-agentcore:GetGatewayTarget",
        "bedrock-agentcore:DeleteGatewayTarget",
        "bedrock-agentcore:UpdateGatewayTarget",
        "bedrock-agentcore:SynchronizeGatewayTargets"
      ],
      "Resource": "arn:aws:bedrock-agentcore:*:*:*gateway*"
    },
    {
      "Sid": "IdentityAndTokenOperations",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:CreateWorkloadIdentity",
        "bedrock-agentcore:GetWorkloadAccessToken",
        "bedrock-agentcore:GetWorkloadAccessTokenForUserId",
        "bedrock-agentcore:GetResourceOauth2Token",
        "bedrock-agentcore:GetResourceApiKey",
        "bedrock-agentcore:CompleteResourceTokenAuth",
        "secretsmanager:GetSecretValue"
      ],
      "Resource": "*"
    }
  ]
}

What does this policy allow?

The first statement covers Gateway CRUD operations. The second covers workload identity, OAuth token retrieval, and reading stored credentials from Secrets Manager.

  • Click Next.
  • Name the policy AgentCoreGatewayPolicy and click Create policy.
  • Return to the Create role tab, click the refresh icon, then search for and select AgentCoreGatewayPolicy.
  • Click Next.
  • Name the role AgentCoreGatewayRole and click Create role.

You should see a success banner confirming the role was created. Copy the Role ARN from the role summary page. It looks like arn:aws:iam::123456789012:role/AgentCoreGatewayRole.

Don't see the policy in the list?

Make sure you clicked the refresh icon after creating the policy. If it still does not appear, verify you are in the same AWS account where you created the policy.

Help me troubleshoot my IAM role setup for AgentCore Gateway.

Create a Cognito User Pool and App Client

The Gateway uses CUSTOM_JWT authorization for inbound requests. Amazon Cognito issues these JWTs via its OAuth 2.0 token endpoint.

  • Open the Amazon Cognito console at https://console.aws.amazon.com/cognito/.
  • Make sure your region is set to us-east-1 in the top-right corner.
  • Click Create user pool.
  • For Application type, select Machine-to-machine application.
  • Name your application agentcore-gateway-client.
  • For the Return URL, enter http://localhost:8080/callback.
  • Click Create app client.

Why machine-to-machine?

The machine-to-machine application type automatically configures client_credentials as the OAuth grant type and generates a client secret. This is exactly what we need for service-to-service authentication against the Gateway.

After creation, Cognito shows you the User Pool ID and App Client details. Collect the following four values from the console:

  • Navigate to your new User Pool and note the User pool ID (format: us-east-1_xxxxxxxxx).
  • Click App clients under Applications in the left sidebar.
  • Select your agentcore-gateway-client and note the Client ID.
  • Click Show client secret and copy the Client secret value.

The OpenID Connect discovery URL follows this pattern:

https://cognito-idp.us-east-1.amazonaws.com/YOUR_USER_POOL_ID/.well-known/openid-configuration

You now have all four Cognito values needed for the Gateway configuration.

Can't find the client secret?

If no secret is shown, the app client was created without one. Delete the app client and recreate it, ensuring you select Machine-to-machine application which automatically generates a secret.

Help me find my Cognito client secret for the AgentCore Gateway setup.

Install boto3 and verify AWS configuration

With the AWS resources in place, set up a local Python environment to drive the validation script.

  • Open your terminal by pressing Cmd+Space (macOS) and typing Terminal.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir nasuni-agentcore-validation
cd nasuni-agentcore-validation
  • Create a Python virtual environment and activate it by running:
python3 -m venv venv
source venv/bin/activate
  • Install boto3 by running:
pip install boto3 requests
  • Confirm the files exist by running:
ls

You should see the venv folder in the output.

Before you run the next command, do you expect it to succeed or fail? Think about whether your AWS CLI credentials can reach the AgentCore control plane in us-east-1.

  • Verify boto3 can connect to the AgentCore control plane by running:
python3 -c "import boto3; client = boto3.client('bedrock-agentcore-control', region_name='us-east-1'); print('AgentCore client ready')"

You should see AgentCore client ready printed without errors.

Seeing a credentials or region error?

Make sure your AWS CLI is configured with valid credentials. Run aws sts get-caller-identity to confirm. If you see a service not available error, verify you are targeting us-east-1 or us-west-2 where AgentCore is available.

Help me fix my boto3 connection to the AgentCore control plane.

Now create the configuration file that the validation script will import. This file centralizes all the resource identifiers you just collected.

  • Create a file named config.py in your nasuni-agentcore-validation folder by running:
touch config.py
  • Open config.py in your preferred text editor and paste the following configuration:
# Configuration for Nasuni AI Activate + AgentCore Gateway validation
# Replace all placeholder values with your actual configuration

# AWS Configuration
AWS_REGION = "us-east-1"
IAM_ROLE_ARN = "arn:aws:iam::your-account-id:role/AgentCoreGatewayRole"

# Cognito Configuration (inbound auth)
COGNITO_USER_POOL_ID = "your-user-pool-id"
COGNITO_CLIENT_ID = "your-cognito-client-id"
COGNITO_CLIENT_SECRET = "your-cognito-client-secret"
COGNITO_DISCOVERY_URL = f"https://cognito-idp.{AWS_REGION}.amazonaws.com/{COGNITO_USER_POOL_ID}/.well-known/openid-configuration"

# Nasuni AI Activate Configuration (outbound auth)
NASUNI_MCP_ENDPOINT = "https://preview.mcp.nasuni.com"
NASUNI_OAUTH_DISCOVERY_URL = "your-nasuni-sso-discovery-url"
NASUNI_CLIENT_ID = "your-nasuni-client-id"
NASUNI_CLIENT_SECRET = "your-nasuni-client-secret"
NASUNI_OAUTH_SCOPES = []

# Gateway Configuration
GATEWAY_NAME = "nasuni-ai-activate-gateway"
GATEWAY_TARGET_NAME = "nasuni-mcp-target"
RETURN_URL = "http://localhost:8080/callback"

What does each section do?

  • AWS Configuration: Your region and the IAM role ARN you just created.
  • Cognito Configuration: The User Pool and App Client values for inbound JWT authentication.
  • Nasuni Configuration: Your Nasuni AI Activate preview credentials from your onboarding materials.
  • Gateway Configuration: Names for the Gateway and target resources the script will create.
  • Replace each placeholder value with your actual credentials and identifiers.
  • For IAM_ROLE_ARN, paste the ARN you copied from the IAM console.
  • For the Cognito values, paste the User Pool ID, Client ID, and Client Secret from the Cognito console.
  • For the Nasuni values, use the SSO discovery URL, client ID, and client secret from your Nasuni AI Activate onboarding materials.
  • Save config.py.
  • Verify the config file loads without errors by running:
python3 -c "from config import *; print(f'Region: {AWS_REGION}, Gateway: {GATEWAY_NAME}')"

You should see Region: us-east-1, Gateway: nasuni-ai-activate-gateway printed.

✔️ Awesome, I've got everything!

Great. Double check you have saved config.py with all your real values filled in.

ⓧ I'd like to double check the full code

Your config.py should look like this (with your actual values replacing the placeholders):

# Configuration for Nasuni AI Activate + AgentCore Gateway validation
# Replace all placeholder values with your actual configuration

# AWS Configuration
AWS_REGION = "us-east-1"
IAM_ROLE_ARN = "arn:aws:iam::your-account-id:role/AgentCoreGatewayRole"

# Cognito Configuration (inbound auth)
COGNITO_USER_POOL_ID = "your-user-pool-id"
COGNITO_CLIENT_ID = "your-cognito-client-id"
COGNITO_CLIENT_SECRET = "your-cognito-client-secret"
COGNITO_DISCOVERY_URL = f"https://cognito-idp.{AWS_REGION}.amazonaws.com/{COGNITO_USER_POOL_ID}/.well-known/openid-configuration"

# Nasuni AI Activate Configuration (outbound auth)
NASUNI_MCP_ENDPOINT = "https://preview.mcp.nasuni.com"
NASUNI_OAUTH_DISCOVERY_URL = "your-nasuni-sso-discovery-url"
NASUNI_CLIENT_ID = "your-nasuni-client-id"
NASUNI_CLIENT_SECRET = "your-nasuni-client-secret"
NASUNI_OAUTH_SCOPES = []

# Gateway Configuration
GATEWAY_NAME = "nasuni-ai-activate-gateway"
GATEWAY_TARGET_NAME = "nasuni-mcp-target"
RETURN_URL = "http://localhost:8080/callback"

Your environment is fully wired. Next up, you will use these credentials to create the AgentCore Gateway itself and watch it come online.

Create the AgentCore Gateway

Your IAM role and Cognito setup give you the building blocks. Now you need the actual entry point that AI agents will talk to.

The AgentCore Gateway is the secure front door that routes incoming MCP requests to backend tool servers. In this step, you will create the Gateway with MCP protocol and CUSTOM_JWT authorization, then confirm it reaches READY status before moving on.

In this step, get ready to:
  • Create the validation script with boto3 clients for AgentCore and Cognito.
  • Call the create_gateway API with MCP protocol and CUSTOM_JWT authorization.
  • Poll until the Gateway reaches READY status and capture your Gateway URL.
Define the Gateway configuration and create it

The validation script will grow across several steps as you add each integration piece. You will start by creating the file with the shared client setup, then add the Gateway creation function.

  • Install the requests library (used later for MCP HTTP calls to the Gateway) by running:
pip install requests
  • Create a new file called validate_nasuni_agentcore.py in the same folder as config.py and paste the following imports and client helper:
import time
import json
import boto3
import requests
from config import (
    AWS_REGION, IAM_ROLE_ARN,
    COGNITO_CLIENT_ID, COGNITO_DISCOVERY_URL,
    NASUNI_MCP_ENDPOINT, NASUNI_OAUTH_DISCOVERY_URL,
    NASUNI_CLIENT_ID, NASUNI_CLIENT_SECRET, NASUNI_OAUTH_SCOPES,
    GATEWAY_NAME, GATEWAY_TARGET_NAME, RETURN_URL,
    COGNITO_USER_POOL_ID, COGNITO_CLIENT_SECRET,
)


def get_clients():
    """Initialize boto3 clients."""
    control_client = boto3.client("bedrock-agentcore-control", region_name=AWS_REGION)
    cognito_client = boto3.client("cognito-idp", region_name=AWS_REGION)
    return control_client, cognito_client

What does this code do?

  • The imports pull in all the configuration values you defined in config.py so nothing is hardcoded in the script itself.
  • get_clients() creates two boto3 clients. The bedrock-agentcore-control client handles all Gateway control plane operations. The cognito-idp client will be used later for token management.
  • Confirm the imports resolve correctly by running:
python3 -c "from validate_nasuni_agentcore import get_clients; c, _ = get_clients(); print('AgentCore control client ready')"

You should see AgentCore control client ready printed with no errors.

Seeing a ModuleNotFoundError?

  • Make sure your virtual environment is still active. You should see its name in your terminal prompt.
  • Verify config.py is in the same directory as validate_nasuni_agentcore.py. Run ls to confirm both files appear.

help me fix a ModuleNotFoundError when importing my validate_nasuni_agentcore script

Now add the function that creates the Gateway. This calls the create_gateway API with your Cognito authorizer configuration and MCP protocol.

  • In validate_nasuni_agentcore.py, add the following function below get_clients():
def create_gateway(control_client):
    """Step 2: Create the AgentCore Gateway with MCP protocol."""
    auth_config = {
        "customJWTAuthorizer": {
            "allowedClients": [COGNITO_CLIENT_ID],
            "discoveryUrl": COGNITO_DISCOVERY_URL,
        }
    }

    print("Creating AgentCore Gateway...")
    response = control_client.create_gateway(
        name=GATEWAY_NAME,
        roleArn=IAM_ROLE_ARN,
        protocolType="MCP",
        authorizerType="CUSTOM_JWT",
        authorizerConfiguration=auth_config,
        description="AgentCore Gateway for Nasuni AI Activate validation",
    )

    gateway_id = response["gatewayId"]
    gateway_url = response["gatewayUrl"]
    print(f"Gateway created: {gateway_id}")
    print(f"Gateway URL: {gateway_url}")

What does this code do?

  • auth_config defines the CUSTOM_JWT authorizer. It tells the Gateway to accept JWTs issued by your Cognito User Pool (via discoveryUrl) and only from the specific client ID you created.
  • protocolType="MCP" puts the Gateway into aggregation mode. It will only accept MCP targets (not HTTP APIs).
  • The response includes gatewayId (for subsequent API calls) and gatewayUrl (the endpoint agents will connect to).
Poll until the Gateway is READY

Gateway provisioning is asynchronous. After the create_gateway call returns, the infrastructure takes a few seconds to spin up. A polling loop lets your script wait until the Gateway is actually accepting connections.

  • In validate_nasuni_agentcore.py, add the polling loop to the end of the create_gateway function, directly below the print(f"Gateway URL: {gateway_url}") line:
    # Poll until READY
    print("Waiting for Gateway to be READY...")
    while True:
        status_response = control_client.get_gateway(gatewayIdentifier=gateway_id)
        status = status_response["status"]
        if status == "READY":
            print(f"Gateway is READY!")
            break
        elif status == "FAILED":
            raise Exception(f"Gateway deployment failed: {status_response}")
        print(f"  Status: {status} - waiting...")
        time.sleep(5)

    return gateway_id, gateway_url

What does get_gateway polling do?

  • get_gateway fetches the current state of the Gateway by its ID.
  • The loop checks every 5 seconds until the status is READY (infrastructure provisioned) or FAILED (something went wrong with the role or configuration).
  • Once READY, the function returns both IDs so subsequent steps can reference them.
  • Save validate_nasuni_agentcore.py.

Before you run this, what do you expect to happen? The script should create the Gateway, then print status updates every 5 seconds until it reaches READY.

  • Run the Gateway creation by executing:
python3 -c "
from validate_nasuni_agentcore import get_clients, create_gateway
c, _ = get_clients()
gw_id, gw_url = create_gateway(c)
print(f'\nSave these values:')
print(f'  Gateway ID: {gw_id}')
print(f'  Gateway URL: {gw_url}')
"

You should see output showing the Gateway being created, followed by status polling messages, and finally a confirmation that the Gateway is READY with your gatewayId and gatewayUrl printed.

Save your Gateway values

Copy the gatewayId and gatewayUrl from the output. You will need these in the next steps when adding the Nasuni target and making tool invocations.

Seeing an AccessDeniedException?

  • Verify your IAM role ARN in config.py matches the role you created in Step 1. Check for typos in the account ID or role name.
  • Confirm the role's trust policy allows the bedrock-agentcore service to assume it.
  • Make sure you are running in a region where AgentCore is available (us-east-1 or us-west-2).

help me fix an AccessDeniedException when creating an AgentCore Gateway

✔️ Awesome, I've got everything!

Great. Double check you have saved validate_nasuni_agentcore.py and confirmed your Gateway is in READY status.

ⓧ I'd like to double check the full code

Your validate_nasuni_agentcore.py should contain these sections in order. Scroll up and confirm each is present:

  • Import block (time, json, boto3, requests, and all config values).
  • get_clients() function returning the bedrock-agentcore-control and cognito-idp clients.
  • create_gateway() function that builds the auth_config dict, calls create_gateway, captures gatewayId and gatewayUrl, polls until READY, and returns both values.

Your Gateway is live and waiting for connections. Next up, you will register Nasuni's OAuth provider in AgentCore Identity so the Gateway can authenticate to Nasuni's MCP server on your behalf.

Configure AgentCore Identity for Nasuni SSO

Your Gateway is live and accepting inbound connections. Now it needs a way to authenticate outbound to Nasuni's MCP server when it forwards tool requests.

Nasuni AI Activate requires OAuth 2.0 authorization via SSO. Rather than hardcoding credentials into the Gateway configuration, AgentCore Identity acts as a credential broker. It registers Nasuni's OAuth provider once, then handles token acquisition and refresh automatically on every tool call.

In this step, get ready to:
  • Register Nasuni's SSO as an OAuth2 credential provider in AgentCore Identity.
  • Verify the credential provider is active and ready to issue tokens.
Register Nasuni's OAuth provider in AgentCore Identity

AgentCore Identity stores OAuth credentials in a credential provider resource. When the Gateway needs to call Nasuni, it asks Identity for a fresh token instead of managing secrets itself.

  • In validate_nasuni_agentcore.py, find the closing return gateway_id, gateway_url line at the end of the create_gateway function.
  • Add the following new function below it:
def create_nasuni_oauth_provider(control_client):
    """Step 3: Register Nasuni's OAuth provider in AgentCore Identity."""
    print("\nRegistering Nasuni OAuth provider in AgentCore Identity...")
    response = control_client.create_oauth2_credential_provider(
        name="nasuni-ai-activate-oauth",
        credentialProviderVendor="CustomOauth2",
        oauth2ProviderConfigInput={
            "customOauth2ProviderConfig": {
                "oauthDiscovery": {
                    "discoveryUrl": NASUNI_OAUTH_DISCOVERY_URL,
                },
                "clientId": NASUNI_CLIENT_ID,
                "clientSecret": NASUNI_CLIENT_SECRET,
            }
        },
    )

    provider_arn = response["credentialProviderArn"]
    print(f"OAuth provider registered: {provider_arn}")

    # Verify provider status
    verify_response = control_client.get_oauth2_credential_provider(
        credentialProviderArn=provider_arn
    )
    print(f"Provider status: {verify_response.get('status', 'ACTIVE')}")

    return provider_arn

What does this code do?

This function registers Nasuni's SSO as a credential source and then immediately verifies it.

  • create_oauth2_credential_provider tells AgentCore Identity about Nasuni's OAuth discovery URL, client ID, and client secret. The CustomOauth2 vendor type means this is a standard OAuth provider (not a pre-built integration like GitHub or Slack).
  • get_oauth2_credential_provider confirms the provider registered successfully. Identity validates the discovery URL is reachable and returns an active status.
  • The returned credentialProviderArn is what you'll pass to the Gateway target in the next step, linking the target to this credential source.
  • Save validate_nasuni_agentcore.py.
Verify the credential provider is active

Before you run, think about what you expect to see. The function calls two APIs in sequence. What output should confirm both succeeded?

  • Run the new function by executing this command in your terminal:
python3 -c "from validate_nasuni_agentcore import get_clients, create_nasuni_oauth_provider; c, _ = get_clients(); create_nasuni_oauth_provider(c)"

You should see two lines printed: the provider ARN confirming registration, and the provider status showing it is active and ready to issue tokens.

What should I see?

The output shows the credential provider ARN (a long resource identifier starting with arn:aws:bedrock-agentcore:) and a status line reading ACTIVE. This confirms AgentCore Identity accepted Nasuni's OAuth configuration and can broker tokens.

Seeing a validation error or timeout?

  • Check that NASUNI_OAUTH_DISCOVERY_URL in config.py points to a reachable URL. AgentCore Identity fetches this URL during registration to validate the OAuth endpoints.
  • Confirm NASUNI_CLIENT_ID and NASUNI_CLIENT_SECRET match the values from your Nasuni AI Activate onboarding materials exactly.
  • Verify your IAM role has the secretsmanager:GetSecretValue permission. AgentCore Identity uses Secrets Manager to store the OAuth client secret.

Help me debug why my OAuth2 credential provider registration is failing in AgentCore Identity.

✔️ Awesome, I've got everything!

Great. Make sure you've saved validate_nasuni_agentcore.py and note the provider ARN printed in your terminal. You'll need it in the next step.

ⓧ I'd like to double check the full code

Here is the full validate_nasuni_agentcore.py so far. Confirm your file matches:

Your file has three functions in this order:

  • get_clients() at the top (initializes boto3 clients).
  • create_gateway(control_client) in the middle (creates and polls the Gateway).
  • create_nasuni_oauth_provider(control_client) at the bottom (registers and verifies the OAuth provider).

Scroll up and confirm each function is present in that order. The import block at the top should remain unchanged from the previous step.

Your Gateway now has a credential broker that can obtain tokens from Nasuni's SSO on demand. Next up, you'll wire the two together by adding Nasuni AI Activate as an MCP target and completing the authorization handshake.

Add Nasuni AI Activate as MCP Target and Complete Authorization

Your Gateway is running and your OAuth credential provider is registered. Now it is time to connect them to Nasuni AI Activate's hosted MCP server.

Adding the MCP target triggers the Gateway to reach out to Nasuni, but the target enters a CREATE_PENDING_AUTH state until you complete the SSO authorization flow. Without that handshake, no tools are discovered. This step proves the full OAuth connection works.

In this step, get ready to:
  • Create a Gateway target pointing to Nasuni's MCP endpoint with Authorization Code grant.
  • Complete the SSO authorization flow in your browser.
  • Confirm the target reaches READY status with tools synchronized from Nasuni.
Create the gateway target pointing to Nasuni

The create_gateway_target API tells the Gateway which MCP server to connect to and which credential provider to use for obtaining OAuth tokens. You will point it at https://preview.mcp.nasuni.com and reference the OAuth provider ARN from the previous step.

  • In validate_nasuni_agentcore.py, add the following function below the create_nasuni_oauth_provider function. This is the first half of the target creation logic:
def create_nasuni_target(control_client, gateway_id, provider_arn):
    """Step 4: Add Nasuni AI Activate as MCP target."""
    print("\nCreating Gateway target for Nasuni AI Activate...")
    response = control_client.create_gateway_target(
        name=GATEWAY_TARGET_NAME,
        gatewayIdentifier=gateway_id,
        targetConfiguration={
            "mcp": {
                "mcpServer": {
                    "endpoint": NASUNI_MCP_ENDPOINT,
                }
            }
        },
        credentialProviderConfigurations=[
            {
                "credentialProviderType": "OAUTH",
                "credentialProvider": {
                    "oauthCredentialProvider": {
                        "providerArn": provider_arn,
                        "grantType": "AUTHORIZATION_CODE",
                        "defaultReturnUrl": RETURN_URL,
                        "scopes": NASUNI_OAUTH_SCOPES,
                    }
                },
            }
        ],
    )

    target_id = response["targetId"]
    print(f"Target created: {target_id}")

What does this code do?

  • create_gateway_target registers Nasuni's MCP endpoint as a target on your Gateway.
  • The targetConfiguration specifies the MCP protocol and points at Nasuni's preview server URL.
  • credentialProviderConfigurations tells the Gateway to use your OAuth provider with the AUTHORIZATION_CODE grant type, which requires you to complete an SSO login before tools can sync.
  • The defaultReturnUrl is where your browser redirects after you grant consent during the SSO flow.
Add authorization handling and poll until tools sync

Because you are using Authorization Code grant (three-legged OAuth), the target enters CREATE_PENDING_AUTH status after creation. The API response includes an authorization URL that you must open in your browser to complete Nasuni SSO.

  • Still in validate_nasuni_agentcore.py, add the following code directly below the print(f"Target created: {target_id}") line, inside the same function:
    # Check for authorization requirement
    if "authorizationData" in response:
        auth_url = response["authorizationData"].get("authorizationUrl", "")
        print(f"\n{'='*60}")
        print("AUTHORIZATION REQUIRED")
        print(f"{'='*60}")
        print(f"Open this URL in your browser to complete SSO login:")
        print(f"\n  {auth_url}\n")
        print("Complete the Nasuni SSO login, then press Enter to continue...")
        print(f"{'='*60}")
        input()

    # Poll until READY
    print("Waiting for target to sync tools from Nasuni...")
    while True:
        status_response = control_client.get_gateway_target(
            gatewayIdentifier=gateway_id,
            targetIdentifier=target_id,
        )
        status = status_response["status"]
        if status == "READY":
            print(f"Target is READY! Tools synchronized successfully.")
            break
        elif status in ["FAILED", "CREATE_FAILED"]:
            raise Exception(f"Target creation failed: {status_response}")
        elif "PENDING_AUTH" in status:
            print(f"  Status: {status} - waiting for authorization...")
        else:
            print(f"  Status: {status} - syncing tools...")
        time.sleep(5)

    return target_id

What does this code do?

The authorization block checks if the response contains an authorizationUrl. If it does, the script prints the URL and pauses with input() so you can open it, complete SSO, and return.

After you press Enter, the polling loop calls get_gateway_target every 5 seconds. Once SSO completes, the Gateway initiates an MCP session with Nasuni, performs the tools/list handshake, and caches all available tool definitions. The target then transitions to READY.

  • Save validate_nasuni_agentcore.py.
Run the target creation and complete SSO

Before you run this, think about what you expect to happen. The script will call Nasuni's endpoint with OAuth. Do you think tools will sync immediately, or will something else happen first?

  • Run the create_nasuni_target function by executing this command in your terminal (replace the placeholder values with the gateway ID and provider ARN you captured in previous steps):
python3 -c "
from validate_nasuni_agentcore import get_clients, create_nasuni_target
control_client, _ = get_clients()
target_id = create_nasuni_target(control_client, 'your-gateway-id', 'your-provider-arn')
print(f'Target ID: {target_id}')
"

What will happen when you run this?

  • The script prints "AUTHORIZATION REQUIRED" and displays a URL.
  • Copy the URL and open it in your browser.
  • Complete your Nasuni SSO login and grant consent when prompted.
  • Return to your terminal and press Enter.
  • The polling loop begins. You will see status updates as the Gateway syncs tools from Nasuni.

After the SSO flow completes and you press Enter, the script polls until the target reaches READY. You should see output similar to:

Creating Gateway target for Nasuni AI Activate...
Target created: aBcDeFgHiJ

============================================================
AUTHORIZATION REQUIRED
============================================================
Open this URL in your browser to complete SSO login:

  https://your-nasuni-sso-url/authorize?...

Complete the Nasuni SSO login, then press Enter to continue...
============================================================

Waiting for target to sync tools from Nasuni...
  Status: CREATE_PENDING_AUTH - waiting for authorization...
  Status: SYNCHRONIZING - syncing tools...
Target is READY! Tools synchronized successfully.
Target ID: aBcDeFgHiJ

What just happened behind the scenes?

When you granted consent, Nasuni's authorization server sent an authorization code back to AgentCore Identity. Identity exchanged that code for an access token. The Gateway then used the token to open an MCP session with Nasuni, called tools/list, and cached all the tool definitions that Nasuni exposes.

The target is now READY, which means the Gateway can accept tool invocation requests and route them to Nasuni on your behalf.

Target stuck in CREATE_PENDING_AUTH?

  • Make sure you completed the full SSO login in your browser and granted consent. If you closed the tab early, you will need to re-run the function.
  • Check that the NASUNI_OAUTH_DISCOVERY_URL, NASUNI_CLIENT_ID, and NASUNI_CLIENT_SECRET in config.py match the values from your Nasuni onboarding materials exactly.
  • If you see FAILED instead, the credential provider may have an incorrect discovery URL. Verify it resolves to a valid OpenID Connect configuration document.

Still stuck? Help me troubleshoot my Nasuni MCP target creation. The target is stuck in CREATE_PENDING_AUTH and I've already completed the SSO login.

  • Save the target_id value that was printed. You will use it in the next step to validate tool invocation.

✔️ Awesome, I've got everything!

Great. Double check you have saved validate_nasuni_agentcore.py with the complete create_nasuni_target function.

ⓧ I'd like to double check the full code

Here is the full validate_nasuni_agentcore.py as it should look at this point. Scroll through and confirm each function is present in order: get_clients, create_gateway, create_nasuni_oauth_provider, create_nasuni_target.

import time
import json
import boto3
import requests
from config import (
    AWS_REGION, IAM_ROLE_ARN,
    COGNITO_CLIENT_ID, COGNITO_DISCOVERY_URL,
    NASUNI_MCP_ENDPOINT, NASUNI_OAUTH_DISCOVERY_URL,
    NASUNI_CLIENT_ID, NASUNI_CLIENT_SECRET, NASUNI_OAUTH_SCOPES,
    GATEWAY_NAME, GATEWAY_TARGET_NAME, RETURN_URL,
    COGNITO_USER_POOL_ID, COGNITO_CLIENT_SECRET,
)
def get_clients():
    """Initialize boto3 clients."""
    control_client = boto3.client("bedrock-agentcore-control", region_name=AWS_REGION)
    cognito_client = boto3.client("cognito-idp", region_name=AWS_REGION)
    return control_client, cognito_client
def create_gateway(control_client):
    """Step 2: Create the AgentCore Gateway with MCP protocol."""
    auth_config = {
        "customJWTAuthorizer": {
            "allowedClients": [COGNITO_CLIENT_ID],
            "discoveryUrl": COGNITO_DISCOVERY_URL,
        }
    }

    print("Creating AgentCore Gateway...")
    response = control_client.create_gateway(
        name=GATEWAY_NAME,
        roleArn=IAM_ROLE_ARN,
        protocolType="MCP",
        authorizerType="CUSTOM_JWT",
        authorizerConfiguration=auth_config,
        description="AgentCore Gateway for Nasuni AI Activate validation",
    )

    gateway_id = response["gatewayId"]
    gateway_url = response["gatewayUrl"]
    print(f"Gateway created: {gateway_id}")
    print(f"Gateway URL: {gateway_url}")
    # Poll until READY
    print("Waiting for Gateway to be READY...")
    while True:
        status_response = control_client.get_gateway(gatewayIdentifier=gateway_id)
        status = status_response["status"]
        if status == "READY":
            print(f"Gateway is READY!")
            break
        elif status == "FAILED":
            raise Exception(f"Gateway deployment failed: {status_response}")
        print(f"  Status: {status} - waiting...")
        time.sleep(5)

    return gateway_id, gateway_url
def create_nasuni_oauth_provider(control_client):
    """Step 3: Register Nasuni's OAuth provider in AgentCore Identity."""
    print("\nRegistering Nasuni OAuth provider in AgentCore Identity...")
    response = control_client.create_oauth2_credential_provider(
        name="nasuni-ai-activate-oauth",
        credentialProviderVendor="CustomOauth2",
        oauth2ProviderConfigInput={
            "customOauth2ProviderConfig": {
                "oauthDiscovery": {
                    "discoveryUrl": NASUNI_OAUTH_DISCOVERY_URL,
                },
                "clientId": NASUNI_CLIENT_ID,
                "clientSecret": NASUNI_CLIENT_SECRET,
            }
        },
    )

    provider_arn = response["credentialProviderArn"]
    print(f"OAuth provider registered: {provider_arn}")

    # Verify provider status
    verify_response = control_client.get_oauth2_credential_provider(
        credentialProviderArn=provider_arn
    )
    print(f"Provider status: {verify_response.get('status', 'ACTIVE')}")

    return provider_arn
def create_nasuni_target(control_client, gateway_id, provider_arn):
    """Step 4: Add Nasuni AI Activate as MCP target."""
    print("\nCreating Gateway target for Nasuni AI Activate...")
    response = control_client.create_gateway_target(
        name=GATEWAY_TARGET_NAME,
        gatewayIdentifier=gateway_id,
        targetConfiguration={
            "mcp": {
                "mcpServer": {
                    "endpoint": NASUNI_MCP_ENDPOINT,
                }
            }
        },
        credentialProviderConfigurations=[
            {
                "credentialProviderType": "OAUTH",
                "credentialProvider": {
                    "oauthCredentialProvider": {
                        "providerArn": provider_arn,
                        "grantType": "AUTHORIZATION_CODE",
                        "defaultReturnUrl": RETURN_URL,
                        "scopes": NASUNI_OAUTH_SCOPES,
                    }
                },
            }
        ],
    )

    target_id = response["targetId"]
    print(f"Target created: {target_id}")
    # Check for authorization requirement
    if "authorizationData" in response:
        auth_url = response["authorizationData"].get("authorizationUrl", "")
        print(f"\n{'='*60}")
        print("AUTHORIZATION REQUIRED")
        print(f"{'='*60}")
        print(f"Open this URL in your browser to complete SSO login:")
        print(f"\n  {auth_url}\n")
        print("Complete the Nasuni SSO login, then press Enter to continue...")
        print(f"{'='*60}")
        input()

    # Poll until READY
    print("Waiting for target to sync tools from Nasuni...")
    while True:
        status_response = control_client.get_gateway_target(
            gatewayIdentifier=gateway_id,
            targetIdentifier=target_id,
        )
        status = status_response["status"]
        if status == "READY":
            print(f"Target is READY! Tools synchronized successfully.")
            break
        elif status in ["FAILED", "CREATE_FAILED"]:
            raise Exception(f"Target creation failed: {status_response}")
        elif "PENDING_AUTH" in status:
            print(f"  Status: {status} - waiting for authorization...")
        else:
            print(f"  Status: {status} - syncing tools...")
        time.sleep(5)

    return target_id

Your Gateway target is READY with Nasuni's file data tools synchronized. Next up, you will validate the full chain by listing those tools and invoking one to retrieve governed file data.

Validate End-to-End Tool Discovery and Invocation

A READY target proves that your Gateway can reach Nasuni's MCP server. However, connectivity alone does not confirm the full integration chain works.

The real validation is proving that an agent request can flow through the Gateway, trigger an OAuth token refresh, execute an MCP call against Nasuni, and return permission-scoped file data. This step closes that loop.

In this step, get ready to:
  • Obtain a Cognito bearer token for inbound Gateway authentication.
  • Discover Nasuni's file data tools via the MCP tools/list protocol.
  • Invoke a tool to retrieve governed file data through the Gateway.
Install requests and add the token acquisition function

The Gateway exposes a standard HTTPS endpoint. You will use the requests library to make MCP protocol calls directly to that endpoint with a bearer token for authentication.

  • Install the requests library by running this command:
pip install requests
  • Confirm the install succeeded. You should see a version number printed.
python3 -c "import requests; print(requests.__version__)"

Seeing ModuleNotFoundError?

Make sure your virtual environment is still active. You should see the environment name in your terminal prompt. If not, reactivate it with source venv/bin/activate before retrying the install.

help me troubleshoot why requests isn't installing in my Python virtual environment

The Gateway uses CUSTOM_JWT authorization, which means inbound requests must carry a valid JWT from your Cognito User Pool. You need a function that authenticates against Cognito and returns an access token.

  • In validate_nasuni_agentcore.py, find the end of the create_nasuni_target function.
  • Add the following get_cognito_token function below it:
def get_cognito_token():
    """Get a bearer token from Cognito for Gateway inbound auth."""
    cognito_client = boto3.client("cognito-idp", region_name=AWS_REGION)
    idp_client = boto3.client("cognito-idp", region_name=AWS_REGION)

    # Use InitiateAuth with client credentials
    response = boto3.client("cognito-idp", region_name=AWS_REGION).initiate_auth(
        AuthFlow="USER_PASSWORD_AUTH",
        ClientId=COGNITO_CLIENT_ID,
        AuthParameters={
            "USERNAME": "your-test-username",
            "PASSWORD": "your-test-password",
        },
    )
    return response["AuthenticationResult"]["AccessToken"]

What does this function do?

  • It calls Cognito's initiate_auth API with the USER_PASSWORD_AUTH flow, sending a username and password to your User Pool.
  • On success, Cognito returns an AuthenticationResult containing an access token that the Gateway will accept as a valid JWT.
  • Replace your-test-username and your-test-password with the credentials of the test user you created in your Cognito User Pool during Step 1.
  • Save validate_nasuni_agentcore.py.
  • Verify that token acquisition works by running:
python3 -c "from validate_nasuni_agentcore import get_cognito_token; token = get_cognito_token(); print(f'Token obtained: {len(token)} characters')"

You should see output like Token obtained: 1347 characters (the exact number will vary). This confirms your Cognito credentials are valid and the Gateway will accept your requests.

Getting NotAuthorizedException?

This means your username or password is incorrect, or the USER_PASSWORD_AUTH flow is not enabled on your App Client. Check that ALLOW_USER_PASSWORD_AUTH is listed in your App Client's authentication flows in the Cognito console.

help me fix a NotAuthorizedException when calling Cognito initiate_auth with USER_PASSWORD_AUTH flow

List available tools from Nasuni via the Gateway

With a valid token in hand, you can now open an MCP session against the Gateway and ask it for available tools. The Gateway will proxy this request through to Nasuni's MCP server and return the synchronized tool definitions.

  • In validate_nasuni_agentcore.py, add the beginning of the validate_tools function below get_cognito_token:
def validate_tools(gateway_url, token):
    """Step 5: List tools and invoke a file data query."""
    print(f"\nValidating tool discovery via Gateway...")
    print(f"Gateway URL: {gateway_url}")

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
        "Accept": "application/json, text/event-stream",
    }

    # Initialize MCP session
    init_payload = {
        "jsonrpc": "2.0",
        "method": "initialize",
        "params": {
            "protocolVersion": "2025-11-25",
            "capabilities": {},
            "clientInfo": {"name": "nasuni-validator", "version": "1.0.0"},
        },
        "id": 1,
    }

    print("\nInitializing MCP session...")
    init_response = requests.post(gateway_url, headers=headers, json=init_payload)
    print(f"  Init response status: {init_response.status_code}")

    # Capture session ID from response headers if present
    session_id = init_response.headers.get("Mcp-Session-Id", "")
    if session_id:
        headers["Mcp-Session-Id"] = session_id

What does this code do?

  • It sets up HTTP headers with your Cognito bearer token so the Gateway authorizes each request.
  • The initialize payload opens an MCP session, declaring protocol version 2025-11-25 (required for Authorization Code flow support).
  • The Mcp-Session-Id header returned by the Gateway binds subsequent requests to the same authenticated session.
  • Continuing inside the same validate_tools function, add the tools/list call directly below the session ID capture:
    # List tools
    list_payload = {
        "jsonrpc": "2.0",
        "method": "tools/list",
        "id": 2,
    }

    print("\nCalling tools/list...")
    list_response = requests.post(gateway_url, headers=headers, json=list_payload)
    tools_data = list_response.json()

    if "result" in tools_data and "tools" in tools_data["result"]:
        tools = tools_data["result"]["tools"]
        print(f"\n{'='*60}")
        print(f"VALIDATION SUCCESS: {len(tools)} tools discovered from Nasuni")
        print(f"{'='*60}")
        for tool in tools:
            print(f"  - {tool['name']}: {tool.get('description', 'No description')[:80]}")
    else:
        print(f"Tools response: {json.dumps(tools_data, indent=2)}")

What does this code do?

  • It sends a tools/list JSON-RPC request to the Gateway, which proxies it to Nasuni's MCP server.
  • The response contains all tool definitions that Nasuni has published, including tool names, descriptions, and input schemas.
  • Each tool represents a governed file data capability that any AI agent can invoke through the Gateway.
  • Save validate_nasuni_agentcore.py.
Invoke a file data query tool

Listing tools proves the MCP handshake works. The final proof is calling one of those tools and receiving actual governed file data back from your Nasuni platform.

  • Still inside the validate_tools function, add the tool invocation code below the tools/list block:
    # Invoke a tool (example: search for files)
    if tools:
        first_tool = tools[0]
        print(f"\nInvoking tool: {first_tool['name']}...")
        call_payload = {
            "jsonrpc": "2.0",
            "method": "tools/call",
            "params": {
                "name": first_tool["name"],
                "arguments": {"query": "recent documents"},
            },
            "id": 3,
        }

        call_response = requests.post(gateway_url, headers=headers, json=call_payload)
        call_data = call_response.json()
        print(f"\n{'='*60}")
        print("TOOL INVOCATION RESULT:")
        print(f"{'='*60}")
        print(json.dumps(call_data, indent=2)[:500])

    return tools_data

What does this code do?

  • It picks the first discovered tool and sends a tools/call request with a sample query of recent documents.
  • The Gateway forwards this to Nasuni, which evaluates permissions based on your SSO identity and returns only the file data you are authorized to see.
  • The return tools_data passes the discovery results back to the caller for summary reporting.
  • Now add the main function and entry point at the bottom of the file:
def main():
    """Run the full validation."""
    print("=" * 60)
    print("Nasuni AI Activate + AgentCore Gateway Validation")
    print("=" * 60)

    control_client, _ = get_clients()

    # Step 2: Create Gateway
    gateway_id, gateway_url = create_gateway(control_client)

    # Step 3: Configure OAuth for Nasuni
    provider_arn = create_nasuni_oauth_provider(control_client)

    # Step 4: Add Nasuni as MCP target
    target_id = create_nasuni_target(control_client, gateway_id, provider_arn)

    # Step 5: Validate end-to-end
    print("\nObtaining Cognito token for Gateway access...")
    token = get_cognito_token()
    validate_tools(gateway_url, token)

    print(f"\n{'='*60}")
    print("VALIDATION COMPLETE")
    print(f"{'='*60}")
    print(f"Gateway ID: {gateway_id}")
    print(f"Gateway URL: {gateway_url}")
    print(f"Target ID: {target_id}")
    print(f"Provider ARN: {provider_arn}")


if __name__ == "__main__":
    main()

What does main() do?

This orchestrator function runs the entire validation end-to-end: it creates a fresh Gateway, registers the OAuth provider, adds the Nasuni target (including the SSO flow), and then validates tool discovery and invocation. It prints a final summary with all resource IDs.

The if __name__ == "__main__" guard ensures main() only runs when you execute the script directly, not when importing functions individually.

  • Save validate_nasuni_agentcore.py.

Before you run the full validation, what do you expect to see printed for the tools/list call? Do you think it will show Nasuni tool names, or will something go wrong?

  • Run the complete validation script:
python3 validate_nasuni_agentcore.py

The script will walk through the full sequence. When it reaches the authorization step, it will print a URL. Open that URL in your browser, complete the Nasuni SSO login, then return to your terminal and press Enter to continue.

You should see output ending with a VALIDATION SUCCESS line showing the number of tools discovered, followed by each tool name and description. Then TOOL INVOCATION RESULT shows the governed file data returned from your Nasuni volumes.

Getting a 401 or 403 from the Gateway?

A 401 means your Cognito token is invalid or expired. Confirm your Cognito App Client has ALLOW_USER_PASSWORD_AUTH enabled and that the COGNITO_DISCOVERY_URL in config.py matches the URL you configured in the Gateway's authorizer.

A 403 means the token is valid but the client ID is not in the Gateway's allowedClients list. Check that COGNITO_CLIENT_ID matches what you passed to create_gateway.

help me debug a 401 or 403 error when calling my AgentCore Gateway with a Cognito JWT bearer token

Now create a cleanup script so you can tear down all resources when you are done.

  • Create a new file called cleanup.py in the same directory and add the cleanup function:
import boto3
from config import AWS_REGION, GATEWAY_NAME

def cleanup(gateway_id, target_id, provider_arn):
    """Delete all resources created during validation."""
    control_client = boto3.client("bedrock-agentcore-control", region_name=AWS_REGION)

    print("Cleaning up resources...")

    # Delete target first
    if target_id:
        print(f"  Deleting gateway target: {target_id}")
        control_client.delete_gateway_target(
            gatewayIdentifier=gateway_id,
            targetIdentifier=target_id,
        )

    # Delete gateway
    if gateway_id:
        print(f"  Deleting gateway: {gateway_id}")
        control_client.delete_gateway(gatewayIdentifier=gateway_id)

    # Delete OAuth provider
    if provider_arn:
        print(f"  Deleting OAuth provider: {provider_arn}")
        control_client.delete_oauth2_credential_provider(
            credentialProviderArn=provider_arn
        )

    print("Cleanup complete.")

What does cleanup do?

It deletes resources in reverse dependency order: target first (since it depends on the gateway), then the gateway, then the OAuth credential provider. Each deletion is guarded by an ID check so you can call it with partial state if needed.

  • Add the entry point below the cleanup function in cleanup.py:
if __name__ == "__main__":
    # Replace with your actual resource IDs from the validation run
    cleanup(
        gateway_id="your-gateway-id",
        target_id="your-target-id",
        provider_arn="your-provider-arn",
    )
  • Save cleanup.py.
  • Confirm both files exist by running:
ls

You should see config.py, validate_nasuni_agentcore.py, and cleanup.py listed.

When to use cleanup.py

You do not need to run cleanup.py now. Save it for the Before You Go step when you decide whether to keep or remove your resources. Replace the placeholder IDs with the actual values printed in the VALIDATION COMPLETE summary.

✔️ Awesome, I've got everything!

Great. Double check you have saved both validate_nasuni_agentcore.py and cleanup.py.

ⓧ I'd like to double check the full code

Your validate_nasuni_agentcore.py should contain these sections in order (scroll up to confirm each is present):

  • Imports and config imports at the top.
  • get_clients() function.
  • create_gateway() function.
  • create_nasuni_oauth_provider() function.
  • create_nasuni_target() function.
  • get_cognito_token() function.
  • validate_tools() function (session init, tools/list, tools/call, return).
  • main() function with the if __name__ == "__main__" guard.

Your cleanup.py should contain the cleanup() function with three deletion calls (target, gateway, provider) followed by the if __name__ == "__main__" entry point.

You have validated the complete integration chain: agent request through the Gateway, OAuth token negotiation, MCP protocol call to Nasuni, and permission-aware file data response. Next up, put this integration to work with an autonomous AI agent.

Secret mission

Build a Strands Agent That Queries Your File Data

Your Gateway is validated and tools are flowing. But right now, querying Nasuni requires raw MCP requests. What if an AI agent could use those tools autonomously to answer natural language questions about your file data?

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. The AgentCore Gateway charges only on invocation ($0.005 per 1,000 calls), so an idle Gateway costs nothing.

Resources you used:

  • AgentCore Gateway nasuni-ai-activate-gateway (consumption-based pricing).
  • Gateway target nasuni-mcp-target (included in Gateway pricing).
  • AgentCore Identity OAuth2 credential provider nasuni-ai-activate-oauth (no charge when used through Gateway).
  • Amazon Cognito User Pool and App Client (free tier covers 50,000 MAU).
  • IAM role AgentCoreGatewayRole (no cost).
  • Local project files (config.py, validate_nasuni_agentcore.py, cleanup.py, strands_agent_nasuni.py) and Python virtual environment.

Keep everything running

No action needed. Choose this if you plan to continue developing against the Gateway or want to re-run your validation scripts later.

  • The Gateway only charges per invocation, so an idle Gateway incurs zero cost.
  • The Cognito User Pool stays well within its free tier unless you add thousands of users.
  • Your local Python files and virtual environment remain on disk ready to use.

Pause - I'll come back to this later

No pause mechanism is needed for these resources. The Gateway only charges on invocation, so leaving it idle is functionally the same as pausing.

  • Deactivate your Python virtual environment by running deactivate in your terminal to free up the shell session.
  • Your Gateway, target, credential provider, Cognito pool, and IAM role all remain in place at no cost while idle.

Delete - I don't want to use this again

Remove all project resources and start fresh. Follow these steps in order to avoid dependency errors.

  • Open cleanup.py and replace the placeholder values at the bottom with your actual gateway_id, target_id, and provider_arn from your validation run output.
  • Run the cleanup script to delete the Gateway target, Gateway, and OAuth provider:
python3 cleanup.py
  • You should see confirmation messages for each resource deletion ending with "Cleanup complete."
  • Delete your Cognito User Pool by running this command (replace the pool ID with yours from config.py):
aws cognito-idp delete-user-pool --user-pool-id your-user-pool-id
  • Detach any managed policies from the IAM role, then delete it:
aws iam detach-role-policy --role-name AgentCoreGatewayRole --policy-arn arn:aws:iam::your-account-id:policy/your-policy-name
aws iam delete-role --role-name AgentCoreGatewayRole
  • Remove your local project files and virtual environment:
cd ~/Desktop
rm -rf nasuni-agentcore-validation

Check the IAM console if delete-role fails

If the delete-role command returns an error, the role may still have inline policies attached. Run aws iam list-role-policies --role-name AgentCoreGatewayRole to find them, then delete each with aws iam delete-role-policy before retrying.

Well Done!

Well Done!

Nice work! You have validated a complete enterprise integration between AWS Bedrock AgentCore and Nasuni AI Activate, proving that AI agents can securely discover and query governed file data through the MCP protocol.

You learned how to:

  • Created an AgentCore Gateway with MCP protocol and CUSTOM_JWT inbound authentication, then configured AgentCore Identity as an OAuth 2.0 credential broker for Nasuni's SSO.
  • Connected Nasuni AI Activate as a Gateway target using the Authorization Code flow, completing SSO login and validating that tool synchronization discovers Nasuni's file data capabilities.
  • Invoked a Nasuni file data tool through the Gateway end-to-end, confirming governed, permission-aware data access works across the full chain: agent request, OAuth token refresh, MCP call, and scoped response.
  • Secret Mission: Built a Strands Agent that autonomously queries enterprise file data through the validated Gateway integration using natural language.

Ready to quiz yourself?