Run Model Context Protocol Servers with AWS Lambda

repository·main·Indexed 18 days ago

https://github.com/awslabs/run-model-context-protocol-servers-with-aws-lambda

A project providing a method to run Model Context Protocol (MCP) servers inside AWS Lambda functions, transforming local stdio-based servers into cloud-accessible services via HTTPS. It includes examples for deploying various remote MCP servers (such as Book Search, Cat Facts, Dad Jokes, and Dictionary) using AWS CDK, supporting multiple languages (Python, TypeScript), authentication methods (OAuth, AWS IAM), and transports including Bedrock AgentCore Gateway and Lambda Function URLs.

Tokens
23.8K
Snippets
67
Records
98
Agent score
61%

What's inside run-model-context-protocol-servers-with-aws-lambda

  1. Overview of the Dog Breeds Facts Remote MCP Server

    main

    The Dog Breeds Facts Remote MCP Server is a remote Model Context Protocol (MCP) server that wraps the @ivotoby/openapi-mcp-server (a stdio-based server) inside an AWS Lambda function. It uses a simplified OpenAPI specification to interface with the thedogapi.com API.

    Key Specifications:

    • Language: TypeScript
    • Transport: Streamable HTTP transport
    • Authentication: OAuth
    • Endpoint: API Gateway
  2. Dictionary Remote MCP Server Overview

    main

    The Dictionary Remote MCP Server is a specialized implementation of an MCP server designed to run on AWS Lambda.

    Technical Specifications:

    • Language: TypeScript
    • Transport: Streamable HTTP transport
    • Authentication: OAuth
    • Endpoint: Bedrock AgentCore Gateway
    • Underlying Engine: Wraps @ivotoby/openapi-mcp-server using a simplified OpenAPI spec for the Free Dictionary API.
  3. Run MCP servers in AWS Lambda

    main

    This project allows you to wrap existing Model Context Protocol (MCP) stdio-based servers into AWS Lambda functions. This enables you to invoke MCP servers over HTTPS instead of local stdio streams, making them accessible to distributed systems or cloud-based applications.

    When a Lambda function is invoked, the library manages the lifecycle of the MCP server by:

    1. Starting the stdio MCP server as a child process.
    2. Initializing the MCP server.
    3. Forwarding the incoming request to the local server.
    4. Returning the server's response to the caller.
    5. Shutting down the MCP server child process.
  4. Supported MCP connection transports for Lambda

    main

    You can connect to Lambda-based MCP servers using one of the following four methods:

    1. MCP Streamable HTTP (Amazon API Gateway): Typically authenticated using OAuth.
    2. MCP Streamable HTTP (Amazon Bedrock AgentCore Gateway): Authenticated using OAuth.
    3. Custom Streamable HTTP (Lambda Function URL): Supports SigV4 and is authenticated with AWS IAM.
    4. Custom Lambda Invocation Transport: Uses the Lambda Invoke API directly and is authenticated with AWS IAM.
  5. Important considerations for running MCP on Lambda

    main

    When using this library to run MCP servers on AWS Lambda, keep the following constraints in mind:

    • Language Support: Currently supports MCP servers and clients written in Python and TypeScript. Other languages (e.g., Kotlin) are not supported.
    • Protocol Support: This library only adapts stdio MCP servers. It does not support servers written for other protocols like SSE.
    • Statelessness Requirement: The library does not maintain state or sessions across Lambda invocations. You must use stateless MCP servers.
      • Suitable: Servers that perform stateless tasks like time or fetch.
      • Unsuitable: Servers that manage local data/state such as sqlite, filesystem, or git servers, as they will lose state on every request.
  6. Pass AWS credentials to MCP subprocesses

    main

    The MCP server child process does not automatically inherit the Lambda execution role's credentials. To allow an MCP server to call AWS APIs, you must manually retrieve the credentials from the Lambda environment and pass them as environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, and AWS_REGION).

    import os
    import sys
    import boto3
    from mcp.client.stdio import StdioServerParameters
    
    session = boto3.Session()
    credentials = session.get_credentials()
    if credentials is None:
        raise RuntimeError("Unable to retrieve AWS credentials from the execution environment")
    resolved = credentials.get_frozen_credentials()
    
    server_params = StdioServerParameters(
        command=sys.executable,
        args=["-m", "my_mcp_server"],
        env={
            "AWS_REGION": os.environ.get("AWS_REGION", "us-west-2"),
            "AWS_DEFAULT_REGION": os.environ.get("AWS_REGION", "us-west-2"),
            "AWS_ACCESS_KEY_ID": resolved.access_key,
            "AWS_SECRET_ACCESS_KEY": resolved.secret_key,
            "AWS_SESSION_TOKEN": resolved.token or "",
        },
    )
  7. Deploy an MCP server using Bedrock AgentCore Gateway

    main

    Using Bedrock AgentCore Gateway in front of a stdio-based MCP server allows the gateway to advertise the tool schema to HTTP clients and validate request inputs/outputs.

    Requirement: You must retrieve the MCP server's tool schema and provide it in the AgentCore Gateway Lambda target configuration.

    Schema Retrieval

    Use the MCP Inspector to extract the tool schema to a JSON file:

    npx @modelcontextprotocol/inspector --cli --method tools/list <your MCP server command and arguments> > tool-schema.json

    Schema Cleaning

    If the schema contains incompatible types (like "items": {}, "default": null, or anyOf with {"type": "null"}), you may need to clean it using the provided script:

    python3 scripts/clean-tool-schema.py tool-schema.json

    Implementation

    Use BedrockAgentCoreGatewayTargetHandler instead of the standard API Gateway handler.

    import { Handler, Context } from "aws-lambda";
    import {
      BedrockAgentCoreGatewayTargetHandler,
      StdioServerAdapterRequestHandler,
    } from "@aws/run-mcp-servers-with-aws-lambda";
    
    const serverParams = {
      command: "npx",
      args: [
        "--offline",
        "my-mcp-server-typescript-module",
        "--my-server-command-line-parameter",
        "some_value",
      ],
    };
    
    const requestHandler = new BedrockAgentCoreGatewayTargetHandler(
      new StdioServerAdapterRequestHandler(serverParams)
    );
    
    export const handler: Handler = async (
      event: Record<string, unknown>,
      context: Context
    ): Promise<Record<string, unknown>> => {
      return requestHandler.handle(event, context);
    };
  8. Setup the development environment for MCP Lambda examples

    main

    To deploy and run the example MCP servers, follow these prerequisite steps:

    1. Install AWS CDK CLI: Ensure the AWS CDK CLI is installed.
    2. Request Bedrock Model Access: Request access to Anthropic Claude 3.7 Sonnet in the us-west-2 region via the AWS Console.
    3. Configure IAM Roles: Create the necessary IAM roles for Lambda functions and Bedrock AgentCore gateways using the provided policy files in the repository.
    4. Bootstrap CDK: Bootstrap your AWS account for the target region.

    Note: The examples default to us-west-2. If using a different region, you must perform a search-and-replace for us-west-2 in the configuration files.

    aws iam create-role \
      --role-name mcp-lambda-example-servers \
      --assume-role-policy-document file://examples/servers/lambda-assume-role-policy.json
    
    aws iam attach-role-policy \
      --role-name mcp-lambda-example-servers \
      --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
    
    aws iam put-role-policy \
      --role-name mcp-lambda-example-servers \
      --policy-name secret-access \
      --policy-document file://examples/servers/lambda-function-role-policy.json
    
    aws iam put-role-policy \
      --role-name mcp-lambda-example-servers \
      --policy-name sns-sqs-access \
      --policy-document file://examples/servers/lambda-function-sns-sqs-policy.json
    
    aws iam create-role \
      --role-name mcp-lambda-example-agentcore-gateways \
      --assume-role-policy-document file://examples/servers/bedrock-agentcore-gateway-assume-role-policy.json
    
    aws iam put-role-policy \
      --role-name mcp-lambda-example-agentcore-gateways \
      --policy-name bedrock-agentcore-full-access \
      --policy-document file://examples/servers/bedrock-agentcore-gateway-role-policy.json
    
    cdk bootstrap aws://<aws account id>/us-west-2
  9. Deploy an MCP server using API Gateway

    main

    You can deploy MCP servers to AWS Lambda and expose them via API Gateway using the MCP Streamable HTTP Transport. This architecture is compatible with off-the-shelf MCP clients like Cursor, Cline, and Claude Desktop. You can use Amazon Cognito, Okta, or Auth0 as your OAuth provider for authorization via API Gateway custom authorization.

    Python Server Implementation

    Use APIGatewayProxyEventHandler and StdioServerAdapterRequestHandler to wrap your MCP server parameters.

    TypeScript Server Implementation

    Use @aws/run-mcp-servers-with-aws-lambda to import APIGatewayProxyEventHandler and StdioServerAdapterRequestHandler to handle Lambda events.

    import sys
    from mcp.client.stdio import StdioServerParameters
    from mcp_lambda import APIGatewayProxyEventHandler, StdioServerAdapterRequestHandler
    
    server_params = StdioServerParameters(
        command=sys.executable,
        args=[
            "-m",
            "my_mcp_server_python_module",
            "--my-server-command-line-parameter",
            "some_value",
        ],
    )
    
    request_handler = StdioServerAdapterRequestHandler(server_params)
    event_handler = APIGatewayProxyEventHandler(request_handler)
    
    def handler(event, context):
        return event_handler.handle(event, context)