Serverless Framework v4.41.0 can now deploy an MCP server to AWS Lambda with four lines of YAML.
mcp:
servers:
crm:
server: index.ts
That gets you a real HTTPS endpoint, response streaming, and AWS Lambda's pay-per-request pricing. Here is why this just became possible, and how it works.
MCP went stateless
On July 28, the Model Context Protocol shipped a revision that removed the two things tying MCP servers to always-on compute: the initialization handshake and protocol-level sessions (SEP-2575 and SEP-2567). Every request now carries its own protocol version, client identity, and capabilities, so any request can land on any instance. No shared storage. No sticky routing. MCP is now plain request/response over ordinary HTTP.
Remote MCP servers are already everywhere, but they have all run on always-on servers, because a session ID pinned each client to whichever replica answered its handshake. That constraint is gone.
Lambda is the natural home
MCP traffic is bursty. An agent calls a tool, then nothing happens for a while. A container billed by the hour is the wrong shape for that. Lambda bills per invocation and costs nothing when idle.
Just as important, your tools are the code that touches your actual systems, and they belong next to them: same AWS account, same VPC, same IAM roles, same DynamoDB tables and secrets you already use. A tool that queries your orders table is an IAM policy, not an outbound integration through someone else's platform.
Your code stays plain
The file you point at is an ordinary MCP server written with the official MCP TypeScript SDK. No Lambda concepts, no Framework APIs, no handler signature to learn.
The Framework owns everything around it:
- An HTTPS endpoint on the same REST API as your
httpfunctions - Response streaming wired end to end, with timeouts kept in sync
- Packaging that bundles your code with a prebuilt entry bridging Lambda's streaming runtime to the SDK
- When you opt into auth: your access control wired to the MCP route while the OAuth discovery route stays open - the part that is easy to get wrong by hand, because a client has to read that document before it has anything to present
The whole protocol works
Tools, resources including URI templates, and prompts all work, for every client. Responses stream, so a long tool sends progress notifications as it goes instead of going quiet and timing out.
The hardest part works too, the one where the server asks the client for something mid-call: elicitation, which sounds impossible without a session.
A tool stops halfway and asks the user a question - which of these three orders did you mean? The answer arrives in a new HTTP request that can land on any instance, and nothing on the server remembers the first call. So the server seals everything it needs to resume into a blob, hands it over with the question, and the client returns it alongside the answer. Whichever instance picks up the retry unseals it and continues where the first one stopped. The state travels through the client instead of living on the server.
That blob passes through the caller's hands, so it has to be signed - otherwise a client could edit its own resume state and the server would trust it. state: true provisions that signing key in your stack: a single generated secret, no database, because the state itself never lands on the server. One line, and your tools can hold a conversation.
The whole configuration surface
server - Points at your MCP server code. That one path is all it takes to get a deployed server on an HTTPS endpoint. The only required key.
authorizer - Locks the server down before it runs. Access control enforced by API Gateway in front of the function, in the same shapes an http event accepts: point it at a Cognito user pool and API Gateway validates tokens itself - no code to write, and a rejected request never invokes anything you pay for. Or bring your own Lambda authorizer for any identity provider, or require IAM-signed callers.
oauthDiscovery - Tells clients where to log in. One line - your issuer URL - becomes the discovery document MCP clients read to find your authorization server (RFC 9728), served as a static API Gateway response with no Lambda behind it.
The two are independent, and any combination is coherent: an authorizer with no discovery for machine-to-machine callers that already hold tokens, discovery with no authorizer when your module verifies tokens itself, both for interactive clients, neither for a public server. And when you want the specification's own semantics - scope-aware 403s, the caller's verified identity inside your tools - the MCP SDK's requireBearerAuth runs inside your module, and the layers compose.
state - Lets tools pause and ask the user for input. Provisions the signing key that makes resume state tamper-proof, created and destroyed with your stack. Or point it at your own SSM or Secrets Manager ARN.
timeout - Sets how long a tool may run, up to 15 minutes. One value moves the function timeout and the streaming integration timeout together, so a long tool cannot be cut off by a limit you forgot about.
memorySize - Gives heavy tools more room, up to 10 GB. CPU scales with it.
environment - Connects the server to the resources it uses. Ordinary environment variables, CloudFormation intrinsics included, so !Ref OrdersTable hands your tools a real table name.
Here is the Cognito shape end to end - the user pool lives in the same service's resources, and one deploy wires all of it, discovery document included:
mcp:
servers:
crm:
server: index.ts
authorizer:
name: crmPool
type: COGNITO_USER_POOLS
arn: !GetAtt UserPool.Arn
scopes:
- mcp/invoke
oauthDiscovery:
issuer: !Sub https://cognito-idp.${AWS::Region}.amazonaws.com/${UserPool}
state: true
Everything else comes from settings you already use. provider.vpc, provider.architecture, provider.layers, and provider.iam apply to an MCP server exactly as they do to your functions, down to perFunction roles. provider.domain puts a custom domain in front. There is no parallel configuration language to learn, because there is no parallel resource.
It's just a function
Day to day, an MCP server is a function in your service. serverless logs -f crm and serverless invoke -f crm work by bare server name. Metrics, versions, and rollback work. Two servers in one service share one API, one stage, and one custom domain, and serverless deploy prints each endpoint. Nothing is a special case.
We verified this against real clients, not a demo harness: 664 unit tests, a live integration suite that deploys one server per way of enforcing access - including proof from CloudWatch that a rejected request never invokes the function, and a full Cognito auth chain with real access tokens - and end-to-end runs with the official MCP client, MCP Inspector, and Claude Code through a real OAuth browser login and an elicitation round trip.
Two things before you ship
Interactive login needs a custom domain mapped at the root. On the default execute-api URL, the discovery document sits under the stage prefix, where clients never look - so browser login cannot start there. Machine-to-machine callers that already hold tokens are unaffected, and the Framework warns you at packaging time whenever the document would land on the stage URL. One more provider note: Cognito has no dynamic client registration, so it fits pre-registered clients and machine-to-machine callers; the full discover-then-register flow needs a provider that supports registration, such as Auth0, Okta, or Entra ID.
Elicitation needs a client on the 2026-07-28 revision. Official-SDK clients reach it by opting in.
Docs: serverless.com/framework/docs/providers/aws/guide/mcp
Where to go next
- The MCP guide - the full reference: every configuration key, the three ways to enforce access and how they compose, elicitation state, permissions, and troubleshooting.
- The examples hub - deployable examples for each tier, from a public server to the full OAuth walkthrough with a real client, plus a custom/ family for when you want to own the hosting glue yourself.
- The serverless-mcp Agent Skill - if you build with an AI coding agent, this skill teaches it the whole surface: configuration shapes, server code patterns, testing, and troubleshooting. It ships inside the CLI - run
serverless agent skills installin your service directory and the Framework installs it for your agent and keeps it current from then on.
The Serverless Framework is free for individuals and organizations under $2M in annual revenue. For larger teams, learn about our Subscription plans or schedule a meeting with us.
