DCR Proxy
Trình tạo DCR Proxy tạo một proxy OAuth Dynamic Client Registration (DCR) đặt trước Amazon Cognito User Pool.
Các client MCP (như Claude Code, Kiro CLI hoặc MCP Inspector) mong đợi xác thực với một máy chủ ủy quyền OAuth hỗ trợ Dynamic Client Registration và khám phá metadata. Amazon Cognito không hỗ trợ DCR nguyên bản, và App Client secret của nó không bao giờ được phép lộ ra cho một public client. Proxy này bắc cầu khoảng trống đó: nó giữ nguyên luồng Cognito Hosted UI, triển khai DCR, chèn App Client secret ở phía máy chủ trong quá trình trao đổi token, và chuyển tiếp lưu lượng MCP đến máy chủ MCP upstream của bạn.
Cách sử dụng
Phần tiêu đề “Cách sử dụng”Tạo một DCR proxy
Phần tiêu đề “Tạo một DCR proxy”pnpm nx g @aws/nx-plugin:ts#dcr-proxyyarn nx g @aws/nx-plugin:ts#dcr-proxynpx nx g @aws/nx-plugin:ts#dcr-proxybunx nx g @aws/nx-plugin:ts#dcr-proxyBạn cũng có thể thực hiện chạy thử để xem những tệp nào sẽ bị thay đổi
pnpm nx g @aws/nx-plugin:ts#dcr-proxy --dry-runyarn nx g @aws/nx-plugin:ts#dcr-proxy --dry-runnpx nx g @aws/nx-plugin:ts#dcr-proxy --dry-runbunx nx g @aws/nx-plugin:ts#dcr-proxy --dry-run- Cài đặt Nx Console VSCode Plugin nếu bạn chưa cài đặt
- Mở Nx Console trong VSCode
- Nhấp
Generate (UI)trong phần "Common Nx Commands" - Tìm kiếm
@aws/nx-plugin - ts#dcr-proxy - Điền các tham số bắt buộc
- Nhấp
Generate
Tùy chọn
Phần tiêu đề “Tùy chọn”| Tham số | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| name | string | dcr-proxy | Tên của DCR proxy của bạn, được sử dụng cho dự án TypeScript handler, tên class construct/module, và thư mục của nó trong common/constructs hoặc common/terraform |
| directory | string | packages | Thư mục để lưu trữ dự án DCR proxy handler. |
| subDirectory | string | - | Thư mục con mà dự án handler được đặt trong đó. Mặc định là tên dự án. |
| iac | inherit | cdk | terraform | inherit | Nhà cung cấp IaC ưu tiên (cdk hoặc terraform). Mặc định được kế thừa từ lựa chọn ban đầu của bạn. |
| preferInstallDependencies | boolean | true | Có nên cài đặt dependencies sau khi generator chạy hay không. Đặt thành false để hoãn việc cài đặt khi chạy nhiều generator cùng lúc (việc cài đặt vẫn chạy nếu cần thiết để các generator tiếp theo có thể tính toán Nx project graph); cài đặt một lần vào cuối. |
Đầu ra của Trình tạo
Phần tiêu đề “Đầu ra của Trình tạo”Trình tạo tạo một dự án TypeScript độc lập chứa các Lambda handler, và cơ sở hạ tầng để triển khai chúng dựa trên iac bạn đã chọn.
Thư mục<dcr-proxy-name>
Thư mụcsrc/
Thư mụchandlers/
- authorization-server-metadata.ts Phục vụ
/.well-known/oauth-authorization-servervà/.well-known/openid-configuration - protected-resource-metadata.ts Phục vụ
/.well-known/oauth-protected-resource - register.ts RFC 7591 Dynamic Client Registration
- authorize.ts Chuyển hướng đến Cognito Hosted UI
- token.ts Chèn App Client secret và trao đổi token
- mcp-proxy.ts Proxy các yêu cầu
/mcpđến máy chủ MCP upstream
- authorization-server-metadata.ts Phục vụ
Các handler được đóng gói độc lập với Rolldown, và cả hai nhà cung cấp IaC đều tham chiếu đến đầu ra bundle kết quả.
Cơ sở hạ tầng
Phần tiêu đề “Cơ sở hạ tầng”Vì generator này cung cấp infrastructure as code dựa trên iac bạn đã chọn, nó sẽ tạo một dự án trong packages/common bao gồm các CDK constructs hoặc Terraform modules liên quan.
Dự án infrastructure as code chung được cấu trúc như sau:
Thư mụcpackages/common/constructs
Thư mụcsrc
Thư mụcapp/ Constructs for infrastructure specific to a project/generator
- …
Thư mụccore/ Generic constructs which are reused by constructs in
app- …
- index.ts Entry point exporting constructs from
app
- project.json Project build targets and configuration
Thư mụcpackages/common/terraform
Thư mụcsrc
Thư mụcapp/ Terraform modules for infrastructure specific to a project/generator
- …
Thư mụccore/ Generic modules which are reused by modules in
app- …
- project.json Project build targets and configuration
Để triển khai proxy, các tệp sau được tạo:
Thư mụcpackages/common/constructs/src
Thư mụcapp
Thư mụcdcr-proxies
Thư mục<dcr-proxy-name>
- <dcr-proxy-name>.ts CDK construct triển khai proxy
Thư mụcpackages/common/terraform/src
Thư mụcapp
Thư mụcdcr-proxies
Thư mục<dcr-proxy-name>
- <dcr-proxy-name>.tf Terraform module triển khai proxy
Cơ sở hạ tầng cung cấp một API Gateway HTTP API với các route sau:
| Route | Mô tả |
|---|---|
GET /.well-known/oauth-protected-resource | Metadata tài nguyên được bảo vệ |
GET /.well-known/oauth-authorization-server | Metadata máy chủ ủy quyền |
GET /.well-known/openid-configuration | Cấu hình OpenID (được phục vụ bởi handler metadata máy chủ ủy quyền) |
POST /register | Dynamic Client Registration |
GET /authorize | Ủy quyền (chuyển hướng đến Cognito Hosted UI) |
POST /oauth/token | Trao đổi token (chèn App Client secret) |
ANY /mcp | Proxy đến máy chủ MCP upstream |
Chỉ có token handler được cấp quyền truy cập đọc vào Cognito App Client secret trong Secrets Manager.
Triển khai DCR Proxy
Phần tiêu đề “Triển khai DCR Proxy”Proxy không tạo các tài nguyên Cognito hoặc máy chủ MCP của bạn. Thay vào đó, bạn chèn các định danh của các tài nguyên được quản lý ở nơi khác (dù được tạo bởi plugin này hay được cung cấp riêng biệt), giữ cho proxy tách rời khỏi cách các tài nguyên đó được cung cấp.
Bạn cung cấp:
- Id của Cognito User Pool và id của App Client
- ARN của một secret Secrets Manager chứa App Client secret. Token handler đọc điều này tại runtime; giá trị không bao giờ được lộ ra cho client.
- URL cơ sở của domain Cognito Hosted UI
- URL đầy đủ của máy chủ MCP upstream của bạn
Khởi tạo construct được tạo trong stack của bạn, truyền các thuộc tính bắt buộc:
import { DcrProxy } from ':my-scope/common-constructs';
new DcrProxy(this, 'DcrProxy', { userPoolId: userPool.userPoolId, userPoolClientId: userPoolClient.userPoolClientId, cognitoClientSecretArn: clientSecret.secretArn, cognitoHostedUiBase: userPoolDomain.baseUrl(), upstreamUrl: 'https://my-agentcore-runtime-url/mcp',});Construct hiển thị các endpoint proxy (proxyUrl, mcpUrl, metadataUrl, tokenEndpoint, registrationEndpoint) dưới dạng các thuộc tính readonly.
Tham chiếu module được tạo từ cấu hình Terraform của bạn, truyền các biến bắt buộc:
module "dcr_proxy" { source = "../../common/terraform/src/app/dcr-proxies/dcr-proxy"
user_pool_id = aws_cognito_user_pool.main.id user_pool_client_id = aws_cognito_user_pool_client.main.id cognito_client_secret_arn = aws_secretsmanager_secret.client_secret.arn cognito_hosted_ui_base = "https://${aws_cognito_user_pool_domain.main.domain}.auth.${data.aws_region.current.region}.amazoncognito.com" upstream_url = "https://my-agentcore-runtime-url/mcp" asset_bucket_name = module.asset_bucket.bucket_name}Module hiển thị các endpoint proxy (proxy_url, mcp_url, metadata_url, token_endpoint, registration_endpoint) dưới dạng output.
Đặt trước một Máy chủ MCP
Phần tiêu đề “Đặt trước một Máy chủ MCP”Để đặt trước một máy chủ MCP được tạo bằng trình tạo ts#mcp-server (hoặc py#mcp-server) sử dụng --auth cognito, truyền cùng User Pool và App Client cho cả máy chủ MCP và proxy, và sử dụng invocationUrl của construct máy chủ MCP làm upstreamUrl của proxy.
import { DcrProxy, MyProjectMcpServer, UserIdentity,} from ':my-scope/common-constructs';import { OAuthScope } from 'aws-cdk-lib/aws-cognito';import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
const identity = new UserIdentity(this, 'Identity');
// A confidential App Client the proxy uses for the token exchange. Register the// callback URLs your clients use (see below).const proxyClient = identity.userPool.addClient('DcrProxyClient', { generateSecret: true, oAuth: { flows: { authorizationCodeGrant: true }, scopes: [OAuthScope.OPENID, OAuthScope.EMAIL, OAuthScope.PROFILE], callbackUrls: [ 'http://localhost:41100/callback', // Callback used by Claude Desktop 'https://claude.ai/api/mcp/auth_callback', ], },});
// Store the App Client secret in Secrets Manager for the token handler to readconst clientSecret = new secretsmanager.Secret(this, 'ClientSecret', { secretStringValue: proxyClient.userPoolClientSecret,});
// The MCP server, authorizing JWTs issued for the same App Clientconst mcpServer = new MyProjectMcpServer(this, 'MyProjectMcpServer', { identity: { userPool: identity.userPool, userPoolClient: proxyClient, },});
new DcrProxy(this, 'DcrProxy', { userPoolId: identity.userPool.userPoolId, userPoolClientId: proxyClient.userPoolClientId, cognitoClientSecretArn: clientSecret.secretArn, cognitoHostedUiBase: identity.userPoolDomain.baseUrl(), // Use the MCP server construct's invocation URL rather than hardcoding it upstreamUrl: mcpServer.invocationUrl,});# A confidential App Client the proxy uses for the token exchange. Register the# callback URLs your clients use (see below).resource "aws_cognito_user_pool_client" "dcr_proxy" { name = "dcr-proxy-client" user_pool_id = module.user_identity.user_pool_id generate_secret = true allowed_oauth_flows = ["code"] allowed_oauth_flows_user_pool_client = true allowed_oauth_scopes = ["openid", "email", "profile"] callback_urls = [ "http://localhost:41100/callback", # Callback used by Claude Desktop "https://claude.ai/api/mcp/auth_callback", ]}
# Store the App Client secret in Secrets Manager for the token handler to readresource "aws_secretsmanager_secret" "client_secret" { name = "my-dcr-proxy-client-secret"}
resource "aws_secretsmanager_secret_version" "client_secret" { secret_id = aws_secretsmanager_secret.client_secret.id secret_string = aws_cognito_user_pool_client.dcr_proxy.client_secret}
# The MCP server, authorizing JWTs issued for the same App Clientmodule "my_project_mcp_server" { source = "../../common/terraform/src/app/mcp-servers/my-project-mcp-server"
user_pool_id = module.user_identity.user_pool_id user_pool_client_ids = [aws_cognito_user_pool_client.dcr_proxy.id] appconfig_application_id = module.runtime_config.application_id appconfig_application_arn = module.runtime_config.application_arn}
module "dcr_proxy" { source = "../../common/terraform/src/app/dcr-proxies/dcr-proxy"
user_pool_id = module.user_identity.user_pool_id user_pool_client_id = aws_cognito_user_pool_client.dcr_proxy.id cognito_client_secret_arn = aws_secretsmanager_secret.client_secret.arn cognito_hosted_ui_base = "https://${module.user_identity.user_pool_domain}.auth.${data.aws_region.current.region}.amazoncognito.com" # Use the MCP server module's invocation URL rather than hardcoding it upstream_url = module.my_project_mcp_server.invocation_url asset_bucket_name = module.asset_bucket.bucket_name}Đặt trước một AgentCore Gateway
Phần tiêu đề “Đặt trước một AgentCore Gateway”Để đặt trước một AgentCore Gateway được tạo bằng trình tạo agentcore-gateway sử dụng --auth cognito, truyền cùng User Pool và App Client cho cả gateway và proxy, và sử dụng gatewayUrl của construct gateway làm upstreamUrl của proxy.
import { DcrProxy, MyGateway, UserIdentity,} from ':my-scope/common-constructs';import { OAuthScope } from 'aws-cdk-lib/aws-cognito';import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
const identity = new UserIdentity(this, 'Identity');
// A confidential App Client the proxy uses for the token exchange. Register the// callback URLs your clients use (see below).const proxyClient = identity.userPool.addClient('DcrProxyClient', { generateSecret: true, oAuth: { flows: { authorizationCodeGrant: true }, scopes: [OAuthScope.OPENID, OAuthScope.EMAIL, OAuthScope.PROFILE], callbackUrls: [ 'http://localhost:41100/callback', // Callback used by Claude Desktop 'https://claude.ai/api/mcp/auth_callback', ], },});
// Store the App Client secret in Secrets Manager for the token handler to readconst clientSecret = new secretsmanager.Secret(this, 'ClientSecret', { secretStringValue: proxyClient.userPoolClientSecret,});
// The gateway, authorizing JWTs issued for the same App Clientconst gateway = new MyGateway(this, 'MyGateway', { identity: { userPool: identity.userPool, userPoolClient: proxyClient, },});
new DcrProxy(this, 'DcrProxy', { userPoolId: identity.userPool.userPoolId, userPoolClientId: proxyClient.userPoolClientId, cognitoClientSecretArn: clientSecret.secretArn, cognitoHostedUiBase: identity.userPoolDomain.baseUrl(), // Use the gateway construct's URL rather than hardcoding it upstreamUrl: gateway.gateway.gatewayUrl,});# A confidential App Client the proxy uses for the token exchange. Register the# callback URLs your clients use (see below).resource "aws_cognito_user_pool_client" "dcr_proxy" { name = "dcr-proxy-client" user_pool_id = module.user_identity.user_pool_id generate_secret = true allowed_oauth_flows = ["code"] allowed_oauth_flows_user_pool_client = true allowed_oauth_scopes = ["openid", "email", "profile"] callback_urls = [ "http://localhost:41100/callback", # Callback used by Claude Desktop "https://claude.ai/api/mcp/auth_callback", ]}
# Store the App Client secret in Secrets Manager for the token handler to readresource "aws_secretsmanager_secret" "client_secret" { name = "my-dcr-proxy-client-secret"}
resource "aws_secretsmanager_secret_version" "client_secret" { secret_id = aws_secretsmanager_secret.client_secret.id secret_string = aws_cognito_user_pool_client.dcr_proxy.client_secret}
# The gateway, authorizing JWTs issued for the same App Clientmodule "my_gateway" { source = "../../common/terraform/src/app/agentcore-gateway/my-gateway"
user_pool_id = module.user_identity.user_pool_id user_pool_client_ids = [aws_cognito_user_pool_client.dcr_proxy.id]}
module "dcr_proxy" { source = "../../common/terraform/src/app/dcr-proxies/dcr-proxy"
user_pool_id = module.user_identity.user_pool_id user_pool_client_id = aws_cognito_user_pool_client.dcr_proxy.id cognito_client_secret_arn = aws_secretsmanager_secret.client_secret.arn cognito_hosted_ui_base = "https://${module.user_identity.user_pool_domain}.auth.${data.aws_region.current.region}.amazoncognito.com" # Use the gateway module's URL rather than hardcoding it upstream_url = module.my_gateway.gateway_url asset_bucket_name = module.asset_bucket.bucket_name}Cho phép URI Chuyển hướng của Client
Phần tiêu đề “Cho phép URI Chuyển hướng của Client”Bởi vì proxy triển khai Dynamic Client Registration một cách ảo — không có Cognito App Client riêng cho từng client — mọi client MCP đều xác thực thông qua App Client duy nhất mà bạn truyền cho proxy. Trong quá trình luồng OAuth, proxy chuyển tiếp redirect_uri của client đến Cognito Hosted UI không thay đổi, vì vậy Cognito thực hiện kiểm tra có thẩm quyền: callback phải được đăng ký là một URL callback trên App Client đó, nếu không Cognito sẽ từ chối đăng nhập.
Đây là một tác dụng phụ của thiết kế DCR ảo. Một client có thể đăng ký bất kỳ redirect_uri nào với proxy, nhưng đăng nhập chỉ thành công nếu URL chính xác đó là một trong các URL callback của App Client. Cognito khớp các URL callback chính xác, bao gồm cả cổng, vì vậy các client lắng nghe trên một cổng tạm thời ngẫu nhiên không thể được bao phủ bởi một ký tự đại diện — bạn phải ghim mỗi client vào một URL callback cố định và đăng ký URL chính xác đó trên App Client.
Thêm các URL callback mà client của bạn sử dụng khi bạn tạo App Client:
const userPoolClient = userPool.addClient('DcrProxyClient', { generateSecret: true, oAuth: { flows: { authorizationCodeGrant: true }, callbackUrls: [ // Local clients: pin to a fixed, uncommon port rather than a default one 'http://localhost:41100/callback', // Callback used by Claude Desktop 'https://claude.ai/api/mcp/auth_callback', ], },});resource "aws_cognito_user_pool_client" "dcr_proxy" { # ... generate_secret = true allowed_oauth_flows = ["code"] allowed_oauth_flows_user_pool_client = true callback_urls = [ # Local clients: pin to a fixed, uncommon port rather than a default one "http://localhost:41100/callback", # Callback used by Claude Desktop "https://claude.ai/api/mcp/auth_callback", ]}Sử dụng một Máy chủ MCP được Proxy
Phần tiêu đề “Sử dụng một Máy chủ MCP được Proxy”Proxy cho phép các client MCP xác thực với Cognito User Pool của bạn mà không cần bất kỳ cấu hình cụ thể nào cho client ngoài URL proxy. Khi một client kết nối đến endpoint /mcp, nó khám phá metadata OAuth (thông qua /.well-known/oauth-protected-resource và /.well-known/oauth-authorization-server), tự động đăng ký chính nó, và dẫn người dùng qua đăng nhập Cognito Hosted UI. Proxy chèn App Client secret trong quá trình trao đổi token, vì vậy client không bao giờ cần nó.
Để kết nối một client, hướng nó đến mcpUrl của proxy (tức là <proxyUrl>/mcp). Các ví dụ dưới đây giả định proxy của bạn được triển khai tại https://my-proxy.example.com.
Claude Code
Phần tiêu đề “Claude Code”Thêm máy chủ được proxy bằng lệnh claude mcp add, sử dụng giao thức HTTP. Theo mặc định Claude Code lắng nghe trên một cổng callback ngẫu nhiên; truyền --callback-port để ghim nó vào cổng được đăng ký trên App Client của bạn (41100 trong các ví dụ trên). Claude Code luôn sử dụng đường dẫn /callback, vì vậy URI chuyển hướng kết quả là http://localhost:41100/callback:
claude mcp add --transport http --callback-port 41100 my-proxied-server https://my-proxy.example.com/mcpKhi bạn lần đầu tiên gọi một công cụ từ máy chủ, Claude Code mở Cognito Hosted UI để xác thực trước khi yêu cầu được proxy upstream.
Kiro CLI
Phần tiêu đề “Kiro CLI”Thêm máy chủ vào cấu hình MCP Kiro CLI của bạn, sử dụng giao thức HTTP. Không có oauth.redirectUri rõ ràng, Kiro chọn một cổng callback ngẫu nhiên; đặt nó thành URL được đăng ký trên App Client của bạn để cổng và đường dẫn khớp chính xác:
{ "mcpServers": { "my-proxied-server": { "type": "http", "url": "https://my-proxy.example.com/mcp", "oauth": { "redirectUri": "http://localhost:41100/callback" } } }}Kiro CLI kích hoạt đăng nhập Cognito Hosted UI khi sử dụng lần đầu và quản lý các token kết quả cho các yêu cầu tiếp theo.
Tái sử dụng một UserIdentity User Pool
Phần tiêu đề “Tái sử dụng một UserIdentity User Pool”Nếu bạn đã có một User Pool từ trình tạo ts#website#auth (construct UserIdentity), bạn có thể đặt trước một máy chủ MCP cho cùng những người dùng đăng nhập vào website của bạn. Tái sử dụng userPool của nó, nhưng thêm một App Client riêng biệt cho proxy: client của website là một public client không có secret, trong khi DCR proxy yêu cầu một confidential client (generateSecret: true) mà secret của nó được token handler chèn trong quá trình trao đổi token.
UserIdentity cấu hình domain User Pool với Managed Login (phiên bản 2). Managed Login yêu cầu một branding style cho mỗi App Client, vì vậy bạn phải tạo một cho client proxy mới — nếu không trang đăng nhập hosted của nó trả về 403.
import { DcrProxy, MyProjectMcpServer, UserIdentity,} from ':my-scope/common-constructs';import { OAuthScope, CfnManagedLoginBranding } from 'aws-cdk-lib/aws-cognito';import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
// The user pool created by ts#website#auth for your website usersconst identity = new UserIdentity(this, 'Identity');
// A confidential App Client on the SAME user pool for the DCR proxyconst proxyClient = identity.userPool.addClient('DcrProxyClient', { generateSecret: true, oAuth: { flows: { authorizationCodeGrant: true }, scopes: [OAuthScope.OPENID, OAuthScope.EMAIL, OAuthScope.PROFILE], callbackUrls: ['http://localhost:41100/callback'], },});
// Managed Login needs a branding style for the new clientnew CfnManagedLoginBranding(this, 'DcrProxyClientBranding', { userPoolId: identity.userPool.userPoolId, clientId: proxyClient.userPoolClientId, useCognitoProvidedValues: true,});
const clientSecret = new secretsmanager.Secret(this, 'ClientSecret', { secretStringValue: proxyClient.userPoolClientSecret,});
const mcpServer = new MyProjectMcpServer(this, 'MyProjectMcpServer', { identity: { userPool: identity.userPool, userPoolClient: proxyClient, },});
new DcrProxy(this, 'DcrProxy', { userPoolId: identity.userPool.userPoolId, userPoolClientId: proxyClient.userPoolClientId, cognitoClientSecretArn: clientSecret.secretArn, // The UserIdentity construct always creates a domain cognitoHostedUiBase: identity.userPoolDomain.baseUrl(), upstreamUrl: mcpServer.invocationUrl,});# The user pool module created by ts#website#auth for your website usersmodule "user_identity" { source = "../../common/terraform/src/core/user-identity"}
# A confidential App Client on the SAME user pool for the DCR proxyresource "aws_cognito_user_pool_client" "dcr_proxy" { name = "dcr-proxy-client" user_pool_id = module.user_identity.user_pool_id generate_secret = true allowed_oauth_flows = ["code"] allowed_oauth_flows_user_pool_client = true allowed_oauth_scopes = ["openid", "email", "profile"] callback_urls = ["http://localhost:41100/callback"]}
# Managed Login needs a branding style for the new clientresource "aws_cognito_managed_login_branding" "dcr_proxy" { user_pool_id = module.user_identity.user_pool_id client_id = aws_cognito_user_pool_client.dcr_proxy.id use_cognito_provided_values = true}
resource "aws_secretsmanager_secret" "client_secret" { name = "my-dcr-proxy-client-secret"}
resource "aws_secretsmanager_secret_version" "client_secret" { secret_id = aws_secretsmanager_secret.client_secret.id secret_string = aws_cognito_user_pool_client.dcr_proxy.client_secret}
module "my_project_mcp_server" { source = "../../common/terraform/src/app/mcp-servers/my-project-mcp-server"
user_pool_id = module.user_identity.user_pool_id user_pool_client_ids = [aws_cognito_user_pool_client.dcr_proxy.id] appconfig_application_id = module.runtime_config.application_id appconfig_application_arn = module.runtime_config.application_arn}
module "dcr_proxy" { source = "../../common/terraform/src/app/dcr-proxies/dcr-proxy"
user_pool_id = module.user_identity.user_pool_id user_pool_client_id = aws_cognito_user_pool_client.dcr_proxy.id cognito_client_secret_arn = aws_secretsmanager_secret.client_secret.arn cognito_hosted_ui_base = "https://${module.user_identity.user_pool_domain}.auth.${data.aws_region.current.region}.amazoncognito.com" upstream_url = module.my_project_mcp_server.invocation_url asset_bucket_name = module.asset_bucket.bucket_name}