blog-zero-secrets-mcp
Demonstrates deploying an MCP server on AgentCore in standalone or gateway mode, using Cognito public client with PKCE for zero-secret user authentication.
README
AgentCore + Cognito Public Client MCP PoC
End-to-end proof of concept demonstrating two deployment modes for an MCP server on AgentCore:
- Standalone — Runtime with Cognito JWT auth directly (no gateway)
- 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)
Mode B: Gateway (recommended)
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
Quick Start: Gateway Mode (recommended)
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_JWTinbound 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_idis 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 bydeploy-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.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。