Skip to content

TypeScript Quickstart

This quickstart takes you to a first running agent in TypeScript: install the SDK, pick a model provider, run the agent, then give it a tool. Everything past that (streaming, memory, observability, deployment) has its own guide, linked from next steps.

Using a coding agent? Copy this prompt into Codex, Claude Code, Kiro, or any coding assistant and it will walk you through this page, ask which model provider you want, and offer to set up the Strands MCP server.

Make sure you have Node.js 22+ and npm installed. See the npm docs if you need to set them up. Then, in a new project directory, initialize it and install the SDK:

Terminal window
npm init -y
npm pkg set type=module
npm install @strands-agents/sdk zod
npm install --save-dev @types/node typescript

Strands works with any major model provider. The model is one object you hand to the agent, and the rest of your code is the same no matter which provider is behind it. The tabs below cover the most common providers; pick the one you already have access to, then create src/agent.ts with the snippet from that tab:

Amazon Bedrock is the default provider, using Claude Sonnet 4.6, so no extra install or model object is needed.

import { Agent } from '@strands-agents/sdk'
// Bedrock is the default, so no model object is needed.
const agent = new Agent()
const result = await agent.invoke('What is an agent harness, in one sentence?')
console.log(result.lastMessage)

Give the SDK AWS credentials with permission to invoke the model, using one of:

  • Bedrock API key: set the AWS_BEARER_TOKEN_BEDROCK environment variable to a Bedrock API key. Quickest for local development.
  • AWS credentials: aws configure, or the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and optionally AWS_SESSION_TOKEN environment variables
  • IAM roles: on AWS services like EC2, ECS, or Lambda

Enable access to the models you use in the Amazon Bedrock console, following the AWS documentation.

Run it with tsx:

Terminal window
npx tsx src/agent.ts

Don’t see your provider? Strands also supports the OpenAI Responses API, any provider in the Vercel AI SDK ecosystem, and any model behind a custom provider you write. Local models through Ollama are available in the Python SDK. See all supported model providers.

You now have a working agent loop, but the agent has nothing to act with. It can only answer from what the model already knows. Tools are what let an agent do things: read a file, call an API, run a command, or look something up.

A tool is a function the model can decide to call. Tools come from two places: Strands ships vended tools for common jobs like editing files, running shell commands, and making HTTP requests, and you can turn any function of your own into a tool with tool(). You’ll use one of each.

Add this to the top of src/agent.ts. It imports the fileEditor vended tool and defines a custom letterCounter tool. The description and the Zod schema are what the model reads to decide when to call the tool and what to pass it:

import { Agent, tool } from '@strands-agents/sdk'
import { fileEditor } from '@strands-agents/sdk/vended-tools/file-editor'
import z from 'zod'
// Define a custom tool as a TypeScript function
const letterCounter = tool({
name: 'letter_counter',
description:
'Count occurrences of a specific letter in a word. Performs case-insensitive matching.',
// Zod schema for letter counter input validation
inputSchema: z
.object({
word: z.string().describe('The input word to search in'),
letter: z.string().describe('The specific letter to count'),
})
.refine((data) => data.letter.length === 1, {
message: "The 'letter' parameter must be a single character",
}),
callback: (input) => {
const { word, letter } = input
// Convert both to lowercase for case-insensitive comparison
const lowerWord = word.toLowerCase()
const lowerLetter = letter.toLowerCase()
// Count occurrences
let count = 0
for (const char of lowerWord) {
if (char === lowerLetter) {
count++
}
}
return `The letter '${letter}' appears ${count} time(s) in '${word}'`
},
})

Then replace the agent creation with this. Both tools go in the tools array, and the prompt asks for something that needs each of them (keep your model line if you set one):

const agent = new Agent({ tools: [letterCounter, fileEditor] })
const result = await agent.invoke(
`How many letter R's are in the word "strawberry"? Write the answer to answer.txt.`
)
console.log(result.lastMessage)

Run it again. The model works out that counting letters is what letter_counter is for and that writing a file is what fileEditor is for, calls both, and you end up with an answer.txt in your working directory. You wrote one of those tools; the other came with the SDK.

The agent decides when to call a tool based on the request, loops until it has an answer, and streams the response to your console.

flowchart LR
A[Input & Context] --> Loop
subgraph Loop[" "]
direction TB
B["Reasoning (LLM)"] --> C["Tool Selection"]
C --> D["Tool Execution"]
D --> B
end
Loop --> E[Response]

Every invocation returns an AgentResult carrying the run’s messages, metrics, and traces. The Agent Loop explains the cycle above, and Observability covers reading traces and metrics. To silence the streamed console output, pass printer: false when creating the agent.

Strands ships an MCP server that gives AI coding assistants in your IDE live access to the Strands documentation — search, section browsing, and on-demand fetching — so the code they generate follows current APIs. It helps you build, but it isn’t required to run an agent.

The server requires uv. Once uv is installed, add the server to your AI coding tool:

Add the following to ~/.kiro/settings/mcp.json:

{
"mcpServers": {
"strands-agents": {
"command": "uvx",
"args": ["strands-agents-mcp-server"],
"disabled": false,
"autoApprove": ["search_docs", "fetch_doc"]
}
}
}

See the Kiro MCP documentation for more details.

Verify the connection with the MCP Inspector:

Terminal window
npx @modelcontextprotocol/inspector uvx strands-agents-mcp-server

You have a running agent with a tool. From here: