Skip to main content
Glama
pcolazurdo

blog-zero-secrets-mcp

by pcolazurdo

AgentCore + Cognito Public Client MCP PoC

End-to-end proof of concept demonstrating two deployment modes for an MCP server on AgentCore:

  1. Standalone — Runtime with Cognito JWT auth directly (no gateway)

  2. Gateway — Runtime behind an AgentCore Gateway with Cognito PKCE inbound auth and IAM outbound auth

Both modes use a public Cognito client (no client_secret) with PKCE for user authentication.

Architecture

Mode A: Standalone (Runtime with direct JWT auth)

Claude Code / Kiro
    │ PKCE → Cognito Hosted UI → browser
    │ Bearer JWT
    ▼
AgentCore Runtime (CUSTOM_JWT validates token)
    │
    ▼
MCP Server (FastMCP, Python)
Claude Code / Kiro
    │ PKCE → Cognito Hosted UI → browser
    │ Bearer JWT
    ▼
AgentCore Gateway (CUSTOM_JWT validates token)
    │ SigV4 (gateway IAM role)
    ▼
AgentCore Runtime (AWS_IAM auth)
    │
    ▼
MCP Server (FastMCP, Python)

The Gateway mode provides:

  • Centralized authentication (gateway handles all JWT validation)

  • Tool discovery and semantic search across multiple targets

  • Protocol-level MCP routing

  • Separation of concerns (runtime doesn't need to know about user auth)

Project Structure

.
├── server/
│   ├── cognitopocmcp/              # Runtime deployed via agentcore CLI
│   │   ├── app/cognito_poc_mcp/
│   │   │   └── main.py            # FastMCP server with sample tools
│   │   └── agentcore/             # agentcore CLI config
│   ├── mcp_server.py              # MCP server source (standalone mode)
│   └── requirements.txt
├── src/
│   ├── config.mjs                 # Shared config (project name, region, helpers)
│   ├── auth.mjs                   # PKCE auth module (no secrets!)
│   ├── mcp-server.mjs             # Stdio MCP server (proxy mode)
│   └── test-auth.mjs              # Standalone auth flow test
├── scripts/
│   ├── setup-cognito.mjs          # Creates Cognito pool + public client + user
│   ├── deploy.sh                  # Deploys runtime (standalone mode, with JWT auth)
│   ├── deploy-infrastructure.mjs  # Creates gateway + IAM role + target (gateway mode)
│   ├── test-gateway.mjs           # Tests gateway end-to-end
│   ├── test-deployed.mjs          # Tests standalone runtime end-to-end
│   └── teardown-cognito.mjs       # Deletes all infrastructure
├── .env                           # Generated by setup (Cognito config)
├── .mcp.json                      # Generated by deploy-infra (gateway URL + OAuth)
├── claude-mcp-config.json         # Same as .mcp.json (for copying to Claude/Kiro)
└── package.json

Prerequisites

# AWS CLI + credentials configured
aws sts get-caller-identity

# Node.js 20+
node --version

# AgentCore CLI
npm install -g @aws/agentcore

# Python 3.10+ (for the MCP server)
python3 --version

Step 1: Install dependencies

npm install

Step 2: Create Cognito infrastructure

npm run setup

Creates a Cognito User Pool with a public app client (no secret), a hosted UI domain, and a test user (testuser / TestPass123!). Config is saved to .env.

Step 3: Deploy the runtime

npm run deploy-runtime

Deploys the MCP server to AgentCore Runtime using the agentcore CLI. The runtime uses default IAM auth (the gateway will authenticate users).

Step 4: Deploy the gateway

npm run deploy-infra

Creates:

  • An IAM role for the gateway (with permission to invoke the runtime)

  • An AgentCore Gateway with CUSTOM_JWT inbound auth (Cognito PKCE)

  • A gateway target pointing at the runtime via GATEWAY_IAM_ROLE (SigV4)

Updates .mcp.json and claude-mcp-config.json with the gateway URL.

Step 5: Test

npm run test-gateway

Authenticates via Cognito (non-interactive using test user), then:

  • Verifies unauthenticated requests are rejected (401)

  • Initializes MCP session

  • Lists discovered tools

  • Calls tools (greet_user, add_numbers, get_server_info)

Step 6: Connect Claude Code / Kiro

Copy the generated config:

# For Kiro — .mcp.json is already in the project root
# For Claude Code
cp claude-mcp-config.json ~/.claude/mcp.json

The config looks like:

{
  "mcpServers": {
    "cognito-poc": {
      "type": "http",
      "url": "https://<gateway-id>.gateway.bedrock-agentcore.<region>.amazonaws.com/mcp",
      "oauth": {
        "clientId": "<public-client-id>",
        "callbackPort": 8976
      }
    }
  }
}

On first tool invocation, Claude/Kiro opens your browser for Cognito login. After that, tokens are cached and refreshed automatically.

Quick Start: Standalone Mode

If you don't need a gateway and want the runtime to handle JWT auth directly:

npm run setup         # Create Cognito pool
npm run deploy        # Deploy runtime with CUSTOM_JWT auth
npm run test-deployed # Test via PKCE (opens browser)

npm Scripts

Script

Description

npm run setup

Create Cognito User Pool + public client + test user

npm run deploy-runtime

Deploy MCP runtime via agentcore CLI (IAM auth, for gateway)

npm run deploy-infra

Create gateway + IAM role + target via Control Plane API

npm run deploy

Deploy runtime with direct JWT auth (standalone, no gateway)

npm run test-gateway

Test gateway end-to-end (non-interactive)

npm run test-gateway -- --pkce

Test gateway with browser-based PKCE login

npm run test-deployed

Test standalone runtime via PKCE

npm run test-auth

Test PKCE auth flow only (opens browser)

npm run test-local

Run MCP server locally for development

npm run teardown

Delete all infrastructure (gateway, IAM role, Cognito pools)

MCP Tools Available

The sample MCP server exposes:

Tool

Description

add_numbers

Add two numbers together

multiply_numbers

Multiply two numbers together

greet_user

Greet a user by name

get_server_info

Return deployment and version info

analyze_text

Analyze text and return basic statistics

When accessed through the gateway, tool names are prefixed with the target name: mcp-runtime___add_numbers.

Cleanup

npm run teardown

This deletes:

  • AgentCore Gateway (targets + gateway)

  • Gateway IAM role

  • Cognito User Pool(s)

  • Local files (.env, .mcp.json, claude-mcp-config.json)

The AgentCore Runtime is NOT deleted (managed separately by agentcore CLI). To remove it:

cd server/cognitopocmcp && agentcore destroy

Key Concepts

Zero-secrets authentication

  • Cognito public client: GenerateSecret: false — no client secret exists

  • PKCE (code_challenge + code_verifier) proves the requester without a shared secret

  • Only the client_id is stored locally (a public identifier, not a credential)

  • Tokens are in-memory with 1-hour expiry + auto-refresh

Gateway outbound auth

The gateway authenticates to the runtime using its own IAM role (SigV4). This avoids the complexity of OAuth machine-to-machine flows between the gateway and runtime. The IAM role has bedrock-agentcore:* permission scoped to the runtime ARN.

Portability

All environment-specific values are derived at runtime:

  • AWS Account ID: resolved via STS.GetCallerIdentity

  • Gateway URL: read from .mcp.json (generated by deploy-infra)

  • Runtime ARN: read from agentcore deployed state

  • Project constants: centralized in src/config.mjs

To deploy in a different account/region, just configure AWS credentials and re-run the setup steps.

Security

See CONTRIBUTING for information on reporting security issues.

License

This library is licensed under the MIT-0 License. See the LICENSE file.

-
license - not tested
-
quality - not tested
C
maintenance

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Self-hosted federated MCP gateway: one OAuth 2.1 MCP server in front of N apps, user-level scopes.

  • Hosted AgentLux MCP server for marketplace, identity, creator, services, and social flows.

  • MCP server for Argo RPG Platform — connects AI assistants to campaign data via OAuth2

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pcolazurdo/blog-zero-secrets-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server