Skip to content

TypeScript MCP Server

Generate a TypeScript Model Context Protocol (MCP) server for providing context to Large Language Models (LLMs), and optionally deploy it to Amazon Bedrock AgentCore.

The Model Context Protocol (MCP) is an open standard that allows AI assistants to interact with external tools and resources. It provides a consistent way for LLMs to:

  • Execute tools (functions) that perform actions or retrieve information
  • Access resources that provide context or data

You can generate a TypeScript MCP server in two ways:

Run this generator@aws/nx-plugin:ts#mcp-server

pnpm nx g @aws/nx-plugin:ts#mcp-server
Build your command6

Required

infra = agentcore | agentcore-ecr

Generator Options6 options
projectRequiredstring

The project to add an MCP server to

authenuminfra = agentcore | agentcore-ecrDefault: iam

The method used to authenticate with your MCP server. Only applicable when infra is set (ignored when infra is none).

iamcognito
iacenumDefault: inherit

The preferred IaC provider. By default this is inherited from your initial selection.

inheritcdkterraform
infraenumDefault: agentcore

The type of infrastructure to host your MCP server. agentcore deploys your code as a zip to an AgentCore managed runtime for the fastest build and deploy cycle. agentcore-ecr builds and hosts a container image instead, for OS-level control or an established container pipeline. Select none for no hosting.

agentcoreagentcore-ecrnone
namestring

The name of your MCP server (default: mcp-server)

preferInstallDependenciesbooleanDefault: true

Whether to prefer installing dependencies after the generator runs. Set to false to defer installing when batching multiple generators (an install still runs if needed so subsequent generators can compute the Nx project graph); install once at the end.

The generator will add the following files to your existing TypeScript project:

  • Directoryyour-project/
    • Directorysrc/
      • Directorymcp-server/ (or custom name if specified)
        • index.ts Exports your server
        • server.ts Main server definition
        • stdio.ts Entry point for STDIO transport, useful for simple local MCP servers
        • http.ts Entry point for Streamable HTTP transport, useful for hosting your MCP server
        • Directorytools/
          • divide.ts Sample tool
        • Directoryresources/
          • sample-guidance.ts Sample resource
        • Dockerfile Container image definition (only when infra is agentcore-ecr)
    • project.json Updated with MCP server serve target

The infra option selects how your code is packaged and hosted on Amazon Bedrock AgentCore Runtime:

  • agentcore (default) uses direct code deployment: your built code is packaged as a .zip, uploaded to S3, and run on an AgentCore managed language runtime. There is no container image to build, no ECR repository to manage, and no image to push, which makes for a substantially faster build and deploy cycle.
  • agentcore-ecr builds an arm64 container image from a vended Dockerfile and hosts it from the shared core/asset-ecr registry, alongside every other container in the workspace. Choose this when you need control over the operating system image — for example to install native system libraries — or when you have an established container pipeline. This option additionally vends a Trivy image scan target (see Image Scanning below).
  • none generates no infrastructure at all, so the project can only be run locally.
infra = agentcore | agentcore-ecr

Since this generator vends infrastructure as code based on your chosen iac, it will create a project in packages/common which includes the relevant CDK constructs or Terraform modules.

The common infrastructure as code project is structured as follows:

  • Directorypackages/common/constructs
    • Directorysrc
      • Directoryapp/ Constructs for infrastructure specific to a project/generator
      • Directorycore/ Generic constructs which are reused by constructs in app
      • index.ts Entry point exporting constructs from app
    • project.json Project build targets and configuration

For deploying your MCP Server, the following files are generated:

  • Directorypackages/common/constructs/src
    • Directoryapp
      • Directorymcp-servers
        • Directory<mcp-server-name>
          • <mcp-server-name>.ts CDK construct for deploying your MCP Server
infra = none

If you selected none for infra, no CDK constructs or Terraform modules are generated — the MCP server is configured for local STDIO / HTTP use only. The auth option is ignored in this mode since there is no hosted endpoint to authenticate.

When deployed to Bedrock AgentCore Runtime, your server’s code is packaged as a zip and run in the AgentCore managed runtime. AI assistants invoke the AgentCore Runtime data plane endpoint, which forwards tools/* and resources/* calls to your server over the streamable HTTP transport.

Loading the diagram…

Tools are functions that the AI assistant can call to perform actions. Each tool lives in its own file under tools/ that exports a register<Name>Tool function, which you then call from server.ts. For example, add tools/my-tool.ts:

tools/my-tool.ts
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
export const registerMyTool = (server: McpServer) => {
server.registerTool(
'toolName',
{
description: 'tool description',
// Input schema using Zod
inputSchema: { param1: z.string(), param2: z.number() },
},
async ({ param1, param2 }) => {
// Tool implementation
const result = `${param1} ${param2}`;
return {
content: [{ type: 'text' as const, text: result }],
};
},
);
};

Then register it inside createServer in server.ts:

server.ts
import { registerMyTool } from './tools/my-tool.js';
export const createServer = async () => {
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
registerMyTool(server);
return server;
};

Resources provide context to the AI assistant. Like tools, each resource lives in its own file under resources/ that exports a register<Name>Resource function called from server.ts. You can add static resources from files or dynamic resources:

resources/my-resource.ts
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
const fetchSomeData = async (): Promise<string> => 'some dynamic context';
export const registerMyResource = (server: McpServer) => {
const exampleContext = 'some context to return';
server.registerResource(
'resource-name',
'example://resource',
{},
async (uri) => ({
contents: [{ uri: uri.href, text: exampleContext }],
}),
);
// Dynamic resource
server.registerResource(
'dynamic-resource',
'dynamic://resource',
{},
async (uri) => {
const data = await fetchSomeData();
return {
contents: [{ uri: uri.href, text: data }],
};
},
);
};

Register it inside createServer in server.ts the same way as a tool:

server.ts
import { registerMyResource } from './resources/my-resource.js';
export const createServer = async () => {
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
registerMyResource(server);
return server;
};

Most AI assistants that support MCP use a similar configuration approach. You’ll need to create or update a configuration file with your MCP server details:

{
"mcpServers": {
"your-mcp-server": {
"command": "npx",
"args": ["tsx", "/path/to/your-mcp-server/stdio.ts"]
}
}
}

While developing your MCP server, you may wish to configure the --watch flag so that the AI assistant always sees the latest versions of tools/resources:

{
"mcpServers": {
"your-mcp-server": {
"command": "npx",
"args": ["tsx", "--watch", "/path/to/your-mcp-server/stdio.ts"]
}
}
}

Please refer to the following documentation for configuring MCP with specific AI Assistants:

To run your MCP server (and everything connected to it, such as a local database) locally, use the project’s dev target:

Terminal window
pnpm nx dev your-project

If you have added multiple components to your project (MCP servers, agents, etc.), this starts them all. To run just this MCP server, target its <your-server-name>-dev target:

Terminal window
pnpm nx your-server-name-dev your-project

The generator configures a target named <your-server-name>-inspect, which starts your MCP server locally (via the <your-server-name>-dev target, including any connected dependencies such as a local database) and launches the MCP Inspector pre-configured to connect to it over Streamable HTTP transport.

Terminal window
pnpm nx your-server-name-inspect your-project

This will start the inspector at http://localhost:6274. Get started by clicking on the “Connect” button.

The easiest way to test and use an MCP server is by using the inspector or configuring it with an AI assistant (as above).

You can however run your server with STDIO transport directly using the <your-server-name>-serve-stdio target.

Terminal window
pnpm nx your-server-name-serve-stdio your-project

This command uses tsx --watch to automatically restart the server when files change.

If you would like to run your MCP server locally using Streamable HTTP transport, you can use the <your-server-name>-serve target.

Terminal window
pnpm nx your-server-name-serve your-project

This command uses tsx --watch to automatically restart the server when files change.

infra = agentcore | agentcore-ecr

Deploying Your MCP Server to Bedrock AgentCore Runtime

Section titled “Deploying Your MCP Server to Bedrock AgentCore Runtime”

If you selected agentcore or agentcore-ecr for infra, the relevant CDK or Terraform infrastructure is generated which you can use to deploy your MCP server to Amazon Bedrock AgentCore Runtime.

A CDK construct is generated for your MCP Server, named based on the name you chose when running the generator, or <ProjectName>McpServer by default.

You can use this CDK construct in a CDK application:

import { MyProjectMcpServer } from '@my-scope/common-constructs';
export class ExampleStack extends Stack {
constructor(scope: Construct, id: string) {
// Add the MCP server to your stack
new MyProjectMcpServer(this, 'MyProjectMcpServer');
}
}

The generator provides an auth option to configure authentication for your MCP server. You can choose between IAM (default) or Cognito authentication when generating your MCP server.

By default, your MCP server will be secured using IAM authentication, simply deploy it without any arguments:

import { MyProjectMcpServer } from '@my-scope/common-constructs';
export class ExampleStack extends Stack {
constructor(scope: Construct, id: string) {
new MyProjectMcpServer(this, 'MyProjectMcpServer');
}
}

You can grant access to invoke your MCP server on Bedrock AgentCore Runtime using the grantInvokeAccess method. For example you may wish for an agent generated with the py#agent generator to call your MCP server:

import { MyProjectAgent, MyProjectMcpServer } from '@my-scope/common-constructs';
export class ExampleStack extends Stack {
constructor(scope: Construct, id: string) {
const agent = new MyProjectAgent(this, 'MyProjectAgent');
const mcpServer = new MyProjectMcpServer(this, 'MyProjectMcpServer');
mcpServer.grantInvokeAccess(agent);
}
}

When you select Cognito authentication, the generator configures the MCP server to use Cognito for authentication.

The generated construct accepts an identity prop which configures Cognito authentication:

import { MyProjectMcpServer, UserIdentity } from '@my-scope/common-constructs';
export class ExampleStack extends Stack {
constructor(scope: Construct, id: string) {
const identity = new UserIdentity(this, 'Identity');
new MyProjectMcpServer(this, 'MyProjectMcpServer', {
identity,
});
}
}

The UserIdentity construct can be generated using the ts#website#auth generator, or you can create your own CDK UserPool and UserPoolClient.

The generator automatically configures a bundle target which uses Rolldown to create a deployment package:

Terminal window
pnpm nx bundle <project-name>

Rolldown configuration can be found in rolldown.config.ts, with an entry per bundle to generate. Rolldown manages creating multiple bundles in parallel if defined.

The bundle target uses http.ts as the entrypoint for the Streamable HTTP MCP server to host on Bedrock AgentCore Runtime.

infra = agentcore

The generator configures a <your-server-name>-package target which assembles the deployable code package: the bundled index.js plus a vendored install of the AWS Distro for OpenTelemetry, which AgentCore requires to be present in the package. The generated infrastructure uploads this directory as a .zip — via AgentRuntimeArtifact.fromCodeAsset under CDK, or archived into the shared asset bucket under Terraform.

infra = agentcore-ecr

The generator configures a <your-server-name>-docker target which copies the Dockerfile from your MCP server source directory into the bundle output directory. This co-locates the Dockerfile with the bundled artifacts, allowing CDK to build the Docker image directly using AgentRuntimeArtifact.fromAsset.

A docker target is also generated which prepares the docker context for all MCP servers if you have multiple defined.

The Docker image built for this project can be scanned for vulnerabilities using Trivy, running from the ECR-hosted Trivy image.

A trivy target is added to your project which scans the built image and exits non-zero if any HIGH or CRITICAL severity vulnerability is found. The generated Dockerfile uses a base image with no known fixable vulnerabilities of these severities at time of generation, and upgrades bundled tooling (such as npm) to keep it that way.

The scan uses the same container engine as your image build (docker or finch), so no additional tooling is required. The scan is not cached, since the image it reads lives in the container engine rather than on disk — so it always scans the real image, and fails loudly rather than reporting a cached pass for an image that is no longer there. Each run therefore takes tens of seconds per image and refreshes Trivy’s vulnerability database, so it needs network access. The vended trivy root script scans every image in the workspace:

Terminal window
pnpm trivy

There may be instances where you want to suppress a specific vulnerability, for example when no fix is yet available and you have assessed the risk as acceptable.

Add the vulnerability ID (one per line) to the .trivyignore file in the root of your project (i.e. next to your project.json):

.trivyignore
# node-tar arbitrary file write - not exploitable in our usage
CVE-2024-XXXXX

For more details on filtering findings, refer to the Trivy filtering documentation.

Your MCP server is automatically configured with observability using the AWS Distro for Open Telemetry (ADOT), by configuring auto-instrumentation in your Dockerfile.

You can find traces in the CloudWatch AWS Console, by selecting “GenAI Observability” in the menu. Note that for traces to be populated you will need to enable Transaction Search.

For more details, refer to the AgentCore documentation on observability.

Use the connection generator to integrate this project with others in your workspace. The following connections involve this project:

Strands AgentsTypeScriptModel Context Protocol
TypeScript Agent to MCPConnect a TypeScript Agent to an MCP server
Strands AgentsPythonModel Context Protocol
Python Agent to MCPConnect a Python Agent to an MCP server
Model Context ProtocolAmazon Aurora
MCP Server to Relational DatabaseConnect a TypeScript MCP Server to an Aurora relational database
Model Context ProtocolAmazon DynamoDB
MCP Server to TypeScript DynamoDBConnect a TypeScript MCP Server to a DynamoDB table
Amazon Bedrock AgentCore GatewayModel Context Protocol
AgentCore Gateway to MCP ServerAggregate an MCP server behind an AgentCore Gateway