Skip to content

MCP API Key Authentication

LMA’s MCP server supports two authentication methods, both deployed automatically when MCP is enabled:

  1. 3LO (OAuth) via Cognito + BedrockAgentCore Gateway — for interactive clients like Amazon Quick Suite and Claude Desktop
  2. API Key via REST API Gateway + Lambda authorizer — for headless/programmatic MCP clients, or Quick Suite via bearer token

Users generate personal API keys from the LMA UI (MCP Servers Configuration page). The API key endpoint speaks the full MCP JSON-RPC 2.0 protocol (streamable HTTP), so standard MCP clients can connect directly.

┌─────────────────────────────────────────────────────────────┐
│ MCP Clients │
│ (Quick Suite, Claude Desktop, curl, custom clients) │
└──────────┬──────────────────────────┬───────────────────────┘
│ OAuth (3LO) │ API Key (Bearer / x-api-key)
▼ ▼
┌─────────────────────┐ ┌──────────────────────────────┐
│ BedrockAgentCore │ │ REST API Gateway │
│ Gateway (CUSTOM_JWT)│ │ (REQUEST authorizer) │
└─────────┬───────────┘ └──────────┬───────────────────┘
│ │
│ ┌─────────▼──────────────┐
│ │ MCPApiKeyAuthorizer │
│ │ Lambda │
│ │ - Checks Authorization: │
│ │ Bearer or x-api-key │
│ │ - SHA-256 hash → DynamoDB│
│ │ - Returns user context │
│ └─────────┬───────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ MCPServerAnalyticsFunction │
│ - BedrockAgentCore path: raw tool input from gateway │
│ - API Gateway path: full MCP JSON-RPC 2.0 protocol │
│ (initialize, tools/list, tools/call, ping) │
│ - UBAC enforced on both paths │
└─────────────────────────────────────────────────────────────┘

Every tool the MCP server exposes is scoped to the calling user: a request returns that user’s meetings, and the scope widens to all meetings in the account only for a member of the Admin group. MCPServerAnalyticsFunction therefore resolves a caller from each request and refuses the request when it cannot. What it reads from the event:

  • API key path — requestContext.authorizer.userId, username and isAdmin, which the REQUEST authorizer put there after resolving the API key.
  • OAuth (3LO) path — requestContext.authorizer.claims, taking the user from sub, the display name from cognito:username (or email) and group membership from cognito:groups.

A request on either path that does not resolve to a user is answered with 403 and a message naming the API key endpoint. A client that receives that response should connect to the MCPServerApiKeyEndpoint REST endpoint with a personal API key, which supplies a caller on every request. See Key Generation Flow and Connecting from Quick Suite.

To confirm on a deployed stack: whether the BedrockAgentCore Gateway (CUSTOM_JWT authorizer, GATEWAY_IAM_ROLE credential provider) includes the caller’s Cognito claims in the event it sends to its Lambda target has not been verified against a live deployment. Where it does not, the OAuth path returns the 403 described above and the API key endpoint is the route that works for those clients. Worth confirming before a release.

Group membership is read from the cognito:groups claim, which Cognito supplies either as a list or as a comma-separated string; both are accepted, and the comparison is an exact match on a whole group name (a group called Administrators, for instance, is not the Admin group).

MCP client connects to REST API Gateway endpoint
→ POST with Authorization: Bearer <key> (or x-api-key: <key>)
→ REQUEST authorizer Lambda invoked (no IdentitySource — always invoked)
→ Extracts token from Authorization header (strips "Bearer ") or x-api-key header
→ SHA-256 hashes the token
→ Looks up hash in MCPApiKeysTable (DynamoDB)
→ Returns IAM Allow policy + { userId, username, isAdmin } in context
→ MCPServerAnalyticsFunction receives API Gateway proxy event
→ Detects JSON-RPC 2.0 message (jsonrpc + method fields in body)
→ Routes to MCP protocol handler:
- initialize → returns server capabilities + protocolVersion
- notifications/initialized → empty 200 acknowledgment
- tools/list → returns 6 tool definitions with inputSchema
- tools/call → routes to tool implementation, returns MCP result
- ping → returns empty result
→ User context from authorizer enforces UBAC on tool calls
User clicks "Generate API Key" on MCP Servers Configuration page
→ AppSync mutation: generateMCPApiKey
→ MCPApiKeyManagerFunction Lambda
→ Verifies user doesn't already have a key (queries UserIdIndex GSI)
→ Generates key: "lma_" + uuid4
→ SHA-256 hashes the key
→ Stores in DynamoDB: { KeyHash (PK), UserId, Username, IsAdmin, CreatedAt, KeyPrefix, Enabled }
→ Returns plaintext key to user (shown once in modal with copy-to-clipboard)
FilePurpose
lma-ai-stack/deployment/lma-ai-stack.yamlAll CF resources: MCPApiKeysTable, MCPApiKeyAuthorizerFunction, MCPApiKeyManagerFunction, MCPApiKeyRestApi (REQUEST authorizer, no IdentitySource), AppSync data source + 3 resolvers, MCPServerApiKeyEndpoint output
lma-main.yamlMCPServerApiKeyEndpoint output (pass-through from nested stack)
lma-ai-stack/source/appsync/schema.graphqlMCPApiKey type, GenerateMCPApiKeyOutput type, generateMCPApiKey/revokeMCPApiKey mutations, listMCPApiKeys query
lma-ai-stack/source/lambda_functions/mcp_api_key_authorizer/index.pyREQUEST authorizer — accepts both Authorization: Bearer and x-api-key headers, hashes token, DynamoDB lookup, returns IAM policy + user context
lma-ai-stack/source/lambda_functions/mcp_api_key_manager/index.pyAppSync resolver — generate/list/revoke per-user API keys, one key per user enforced
lma-ai-stack/source/lambda_functions/mcp_analytics/index.pyMCP JSON-RPC 2.0 protocol handler (initialize, tools/list, tools/call, ping) for the API Gateway path; on the BedrockAgentCore path, resolves the caller from the forwarded claims (see Connecting with a User Identity)
lma-ai-stack/source/ui/src/graphql/mutations.jsgenerateMCPApiKey, revokeMCPApiKey, listMCPApiKeys GraphQL operations
lma-ai-stack/source/ui/src/components/mcp-servers-page/MCPApiKeySection.jsxCloudscape UI component for key management
lma-ai-stack/source/ui/src/components/mcp-servers-page/MCPServersPage.jsxIntegrated MCPApiKeySection at top of page
utilities/test-mcp-api-key.shEnd-to-end test script for the API key endpoint
docs/mcp-api-key-auth.mdThis document

The API key endpoint implements the MCP streamable HTTP transport (JSON-RPC 2.0 over HTTP POST). Supported methods:

MethodDescription
initializeReturns server info (name: lma-mcp-server) and capabilities
notifications/initializedClient acknowledgment, returns empty 200
tools/listReturns all 6 tool definitions with inputSchema
tools/callExecutes a tool by name with arguments, returns MCP content result
pingHealth check, returns empty result
ToolDescription
search_lma_meetingsSearch transcripts/summaries with natural language
get_meeting_transcriptGet full transcript (json, text, or srt format)
get_meeting_summaryGet AI summary with action items and topics
list_meetingsList meetings with date/participant/status filters
schedule_meetingSchedule a future meeting with virtual participant
start_meeting_nowStart a meeting immediately with virtual participant

Table: ${LMAStackName}-MCPApiKeys

AttributeTypeDescription
KeyHashS (PK)SHA-256 hash of the API key
UserIdSCognito username
UsernameSCognito username/email
IsAdminS"true" or "false"
KeyPrefixSFirst 12 chars of key (e.g. lma_a1b2c3d4) for UI display
CreatedAtSISO 8601 timestamp
EnabledS"true" or "false"

GSI: UserIdIndex — Partition key: UserId, projects all attributes. Used for listing a user’s keys and enforcing one-key-per-user.

  • Type: REQUEST (not TOKEN) — receives all headers, no IdentitySource filter
  • TTL: 0 (no caching — since the identity source varies between headers)
  • Token extraction order: authorizationToken (TOKEN mode compat) → headers.x-api-key → headers.Authorization (strips Bearer prefix)
  • On success: returns IAM Allow policy with context: { userId, username, isAdmin }
  • On failure: returns IAM Deny policy

Located on the MCP Servers Configuration page (/configuration/mcp-servers):

  • MCP API Key container at the top of the page
  • Shows key prefix with masked suffix + creation date if a key exists
  • “Generate API Key” button (disabled when a key already exists)
  • Generated key shown in a modal with CopyToClipboard and warning it won’t be shown again
  • “Revoke” button with confirmation modal
  • The Hosted MCP Access tab, including this API key container, is available to every signed-in user; the External MCP Servers tab on the same page is read-only for users outside the Admin group (see MCP Servers › Admin UI)
  • The left navigation still lists Configuration › MCP Servers for Admin users only, so a non-admin user needs the direct link (/#/configuration/mcp-servers) to reach their API key. Surfacing the link for all users is a follow-up.
  • API keys are less secure than 3LO — no token expiration, no refresh rotation
  • Keys are SHA-256 hashed at rest — DynamoDB compromise doesn’t expose usable keys
  • Users can only manage their own keys (enforced by AppSync identity context)
  • API Gateway throttling: 50 burst, 100 sustained requests/sec
  • Keys can be revoked immediately by the user
  • lma_ prefix makes keys identifiable if leaked in logs
  • REQUEST authorizer with no IdentitySource means every request invokes the authorizer Lambda (no bypass via missing headers)
Terminal window
# Run the end-to-end test
./utilities/test-mcp-api-key.sh <your-api-key> [api-gateway-url]
# Tests: initialize (Bearer), initialize (x-api-key), tools/list,
# tools/call (list_meetings), ping, bad key rejection

Add as a remote MCP server in Quick Suite:

  • Transport: SSE/HTTP
  • URL: The MCPServerApiKeyEndpoint stack output (e.g. https://xxx.execute-api.us-west-2.amazonaws.com/mcp)
  • Token: Your LMA API key (e.g. lma_a1b2c3d4-e5f6-7890-abcd-ef1234567890)

Quick Suite sends Authorization: Bearer <key> on all requests via streamablehttp_client.

To confirm on a deployed stack: this has not been verified against a live Quick Suite tenant, and the Quick Suite setup guide documents only user-authentication (OAuth) for a remote MCP server. If your Quick Suite version has no bearer-token or API-key field, use Quick Desktop, Claude Desktop or another MCP client for the API key route. LMA’s endpoint accepts the key over Authorization: Bearer or x-api-key regardless of the client.