Import "Build an LLM-powered chatbot" quickstart guide (#1550)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6cd75c67ed
commit
d6dc0abde9
10 changed files with 703 additions and 2 deletions
|
|
@ -9,6 +9,7 @@
|
|||
"updateInternalDependencies": "patch",
|
||||
"ignore": [
|
||||
"@modelcontextprotocol/examples-client",
|
||||
"@modelcontextprotocol/examples-client-quickstart",
|
||||
"@modelcontextprotocol/examples-server",
|
||||
"@modelcontextprotocol/examples-server-quickstart",
|
||||
"@modelcontextprotocol/examples-shared"
|
||||
|
|
|
|||
|
|
@ -12,5 +12,6 @@ pnpm-lock.yaml
|
|||
# Ignore generated files
|
||||
src/spec.types.ts
|
||||
|
||||
# Quickstart example uses 2-space indent to match ecosystem conventions
|
||||
# Quickstart examples uses 2-space indent to match ecosystem conventions
|
||||
examples/client-quickstart/
|
||||
examples/server-quickstart/
|
||||
|
|
|
|||
420
docs/client-quickstart.md
Normal file
420
docs/client-quickstart.md
Normal file
|
|
@ -0,0 +1,420 @@
|
|||
---
|
||||
title: Client Quickstart
|
||||
---
|
||||
|
||||
# Quickstart: Build an LLM-powered chatbot
|
||||
|
||||
In this tutorial, we'll build an LLM-powered chatbot that connects to an MCP server, discovers its tools, and uses Claude to call them.
|
||||
|
||||
Before you begin, it helps to have gone through the [server quickstart](./server-quickstart.md) so you understand how clients and servers communicate.
|
||||
|
||||
[You can find the complete code for this tutorial here.](https://github.com/modelcontextprotocol/typescript-sdk/tree/main/examples/client-quickstart)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This quickstart assumes you have familiarity with:
|
||||
|
||||
- TypeScript
|
||||
- LLMs like Claude
|
||||
|
||||
Before starting, ensure your system meets these requirements:
|
||||
|
||||
- Node.js 20 or higher installed
|
||||
- Latest version of `npm` installed
|
||||
- An Anthropic API key from the [Anthropic Console](https://console.anthropic.com/settings/keys)
|
||||
|
||||
## Set up your environment
|
||||
|
||||
First, let's create and set up our project:
|
||||
|
||||
**macOS/Linux:**
|
||||
|
||||
```bash
|
||||
# Create project directory
|
||||
mkdir mcp-client
|
||||
cd mcp-client
|
||||
|
||||
# Initialize npm project
|
||||
npm init -y
|
||||
|
||||
# Install dependencies
|
||||
npm install @anthropic-ai/sdk @modelcontextprotocol/client
|
||||
|
||||
# Install dev dependencies
|
||||
npm install -D @types/node typescript
|
||||
|
||||
# Create source file
|
||||
mkdir src
|
||||
touch src/index.ts
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
|
||||
```powershell
|
||||
# Create project directory
|
||||
md mcp-client
|
||||
cd mcp-client
|
||||
|
||||
# Initialize npm project
|
||||
npm init -y
|
||||
|
||||
# Install dependencies
|
||||
npm install @anthropic-ai/sdk @modelcontextprotocol/client
|
||||
|
||||
# Install dev dependencies
|
||||
npm install -D @types/node typescript
|
||||
|
||||
# Create source file
|
||||
md src
|
||||
new-item src\index.ts
|
||||
```
|
||||
|
||||
Update your `package.json` to set `type: "module"` and a build script:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Create a `tsconfig.json` in the root of your project:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2023",
|
||||
"lib": ["ES2023"],
|
||||
"module": "Node16",
|
||||
"moduleResolution": "Node16",
|
||||
"outDir": "./build",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
```
|
||||
|
||||
## Creating the client
|
||||
|
||||
### Basic client structure
|
||||
|
||||
First, let's set up our imports and create the basic client class in `src/index.ts`:
|
||||
|
||||
```ts source="../examples/client-quickstart/src/index.ts#prelude"
|
||||
import Anthropic from '@anthropic-ai/sdk';
|
||||
import { Client, StdioClientTransport, type CallToolResult } from '@modelcontextprotocol/client';
|
||||
import readline from 'readline/promises';
|
||||
|
||||
const ANTHROPIC_MODEL = 'claude-sonnet-4-5';
|
||||
|
||||
class MCPClient {
|
||||
private mcp: Client;
|
||||
private _anthropic: Anthropic | null = null;
|
||||
private transport: StdioClientTransport | null = null;
|
||||
private tools: Anthropic.Tool[] = [];
|
||||
|
||||
constructor() {
|
||||
// Initialize MCP client
|
||||
this.mcp = new Client({ name: 'mcp-client-cli', version: '1.0.0' });
|
||||
}
|
||||
|
||||
private get anthropic(): Anthropic {
|
||||
// Lazy-initialize Anthropic client when needed
|
||||
return this._anthropic ??= new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
||||
}
|
||||
```
|
||||
|
||||
### Server connection management
|
||||
|
||||
Next, we'll implement the method to connect to an MCP server:
|
||||
|
||||
```ts source="../examples/client-quickstart/src/index.ts#connectToServer"
|
||||
async connectToServer(serverScriptPath: string) {
|
||||
try {
|
||||
// Determine script type and appropriate command
|
||||
const isJs = serverScriptPath.endsWith('.js');
|
||||
const isPy = serverScriptPath.endsWith('.py');
|
||||
if (!isJs && !isPy) {
|
||||
throw new Error('Server script must be a .js or .py file');
|
||||
}
|
||||
const command = isPy
|
||||
? (process.platform === 'win32' ? 'python' : 'python3')
|
||||
: process.execPath;
|
||||
|
||||
// Initialize transport and connect to server
|
||||
this.transport = new StdioClientTransport({ command, args: [serverScriptPath] });
|
||||
await this.mcp.connect(this.transport);
|
||||
|
||||
// List available tools
|
||||
const toolsResult = await this.mcp.listTools();
|
||||
this.tools = toolsResult.tools.map((tool) => ({
|
||||
name: tool.name,
|
||||
description: tool.description ?? '',
|
||||
input_schema: tool.inputSchema as Anthropic.Tool.InputSchema,
|
||||
}));
|
||||
console.log('Connected to server with tools:', this.tools.map(({ name }) => name));
|
||||
} catch (e) {
|
||||
console.log('Failed to connect to MCP server: ', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Query processing logic
|
||||
|
||||
Now let's add the core functionality for processing queries and handling tool calls:
|
||||
|
||||
```ts source="../examples/client-quickstart/src/index.ts#processQuery"
|
||||
async processQuery(query: string) {
|
||||
const messages: Anthropic.MessageParam[] = [
|
||||
{
|
||||
role: 'user',
|
||||
content: query,
|
||||
},
|
||||
];
|
||||
|
||||
// Initial Claude API call
|
||||
const response = await this.anthropic.messages.create({
|
||||
model: ANTHROPIC_MODEL,
|
||||
max_tokens: 1000,
|
||||
messages,
|
||||
tools: this.tools,
|
||||
});
|
||||
|
||||
// Process response and handle tool calls
|
||||
const finalText = [];
|
||||
|
||||
for (const content of response.content) {
|
||||
if (content.type === 'text') {
|
||||
finalText.push(content.text);
|
||||
} else if (content.type === 'tool_use') {
|
||||
// Execute tool call
|
||||
const toolName = content.name;
|
||||
const toolArgs = content.input as Record<string, unknown> | undefined;
|
||||
const result = await this.mcp.callTool({
|
||||
name: toolName,
|
||||
arguments: toolArgs,
|
||||
}) as CallToolResult;
|
||||
|
||||
finalText.push(`[Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}]`);
|
||||
|
||||
// Extract text from tool result content blocks
|
||||
const toolResultText = result.content
|
||||
.filter((block) => block.type === 'text')
|
||||
.map((block) => block.text)
|
||||
.join('\n');
|
||||
|
||||
// Continue conversation with tool results
|
||||
messages.push({
|
||||
role: 'assistant',
|
||||
content: response.content,
|
||||
});
|
||||
messages.push({
|
||||
role: 'user',
|
||||
content: [{
|
||||
type: 'tool_result',
|
||||
tool_use_id: content.id,
|
||||
content: toolResultText,
|
||||
}],
|
||||
});
|
||||
|
||||
// Get next response from Claude
|
||||
const followUp = await this.anthropic.messages.create({
|
||||
model: ANTHROPIC_MODEL,
|
||||
max_tokens: 1000,
|
||||
messages,
|
||||
});
|
||||
|
||||
finalText.push(followUp.content[0].type === 'text' ? followUp.content[0].text : '');
|
||||
}
|
||||
}
|
||||
|
||||
return finalText.join('\n');
|
||||
}
|
||||
```
|
||||
|
||||
### Interactive chat interface
|
||||
|
||||
Now we'll add the chat loop and cleanup functionality:
|
||||
|
||||
```ts source="../examples/client-quickstart/src/index.ts#chatLoop"
|
||||
async chatLoop() {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
try {
|
||||
console.log('\nMCP Client Started!');
|
||||
console.log('Type your queries or "quit" to exit.');
|
||||
|
||||
while (true) {
|
||||
const message = await rl.question('\nQuery: ');
|
||||
if (message.toLowerCase() === 'quit') {
|
||||
break;
|
||||
}
|
||||
const response = await this.processQuery(message);
|
||||
console.log('\n' + response);
|
||||
}
|
||||
} finally {
|
||||
rl.close();
|
||||
}
|
||||
}
|
||||
|
||||
async cleanup() {
|
||||
await this.mcp.close();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Main entry point
|
||||
|
||||
Finally, we'll add the main execution logic:
|
||||
|
||||
```ts source="../examples/client-quickstart/src/index.ts#main"
|
||||
async function main() {
|
||||
if (process.argv.length < 3) {
|
||||
console.log('Usage: node build/index.js <path_to_server_script>');
|
||||
return;
|
||||
}
|
||||
const mcpClient = new MCPClient();
|
||||
try {
|
||||
await mcpClient.connectToServer(process.argv[2]);
|
||||
|
||||
// Check if we have a valid API key to continue
|
||||
const apiKey = process.env.ANTHROPIC_API_KEY;
|
||||
if (!apiKey) {
|
||||
console.log(
|
||||
'\nNo ANTHROPIC_API_KEY found. To query these tools with Claude, set your API key:'
|
||||
+ '\n export ANTHROPIC_API_KEY=your-api-key-here'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await mcpClient.chatLoop();
|
||||
} catch (e) {
|
||||
console.error('Error:', e);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await mcpClient.cleanup();
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
## Running the client
|
||||
|
||||
To run your client with any MCP server:
|
||||
|
||||
**macOS/Linux:**
|
||||
|
||||
```bash
|
||||
# Build TypeScript
|
||||
npm run build
|
||||
|
||||
# Run the client with a Node.js MCP server
|
||||
ANTHROPIC_API_KEY=your-key-here node build/index.js path/to/server/build/index.js
|
||||
|
||||
# Example: connect to the weather server from the server quickstart
|
||||
ANTHROPIC_API_KEY=your-key-here node build/index.js /absolute/path/to/weather/build/index.js
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
|
||||
```powershell
|
||||
# Build TypeScript
|
||||
npm run build
|
||||
|
||||
# Run the client with a Node.js MCP server
|
||||
$env:ANTHROPIC_API_KEY="your-key-here"; node build/index.js path\to\server\build\index.js
|
||||
```
|
||||
|
||||
**The client will:**
|
||||
|
||||
1. Connect to the specified server
|
||||
2. List available tools
|
||||
3. Start an interactive chat session where you can:
|
||||
- Enter queries
|
||||
- See tool executions
|
||||
- Get responses from Claude
|
||||
|
||||
## What's happening under the hood
|
||||
|
||||
When you submit a query:
|
||||
|
||||
1. Your query is sent to Claude along with the tool descriptions discovered during connection
|
||||
2. Claude decides which tools (if any) to use
|
||||
3. The client executes any requested tool calls through the server
|
||||
4. Results are sent back to Claude
|
||||
5. Claude provides a natural language response
|
||||
6. The response is displayed to you
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Server Path Issues
|
||||
|
||||
- Double-check the path to your server script is correct
|
||||
- Use the absolute path if the relative path isn't working
|
||||
- For Windows users, make sure to use forward slashes (`/`) or escaped backslashes (`\\`) in the path
|
||||
- Verify the server file has the correct extension (`.js` for Node.js or `.py` for Python)
|
||||
|
||||
Example of correct path usage:
|
||||
|
||||
**macOS/Linux:**
|
||||
|
||||
```bash
|
||||
# Relative path
|
||||
node build/index.js ./server/build/index.js
|
||||
|
||||
# Absolute path
|
||||
node build/index.js /Users/username/projects/mcp-server/build/index.js
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
|
||||
```powershell
|
||||
# Relative path
|
||||
node build/index.js .\server\build\index.js
|
||||
|
||||
# Absolute path (either format works)
|
||||
node build/index.js C:\projects\mcp-server\build\index.js
|
||||
node build/index.js C:/projects/mcp-server/build/index.js
|
||||
```
|
||||
|
||||
### Response Timing
|
||||
|
||||
- The first response might take up to 30 seconds to return
|
||||
- This is normal and happens while:
|
||||
- The server initializes
|
||||
- Claude processes the query
|
||||
- Tools are being executed
|
||||
- Subsequent responses are typically faster
|
||||
- Don't interrupt the process during this initial waiting period
|
||||
|
||||
### Common Error Messages
|
||||
|
||||
If you see:
|
||||
|
||||
- `Error: Cannot find module`: Check your build folder and ensure TypeScript compilation succeeded
|
||||
- `Connection refused`: Ensure the server is running and the path is correct
|
||||
- `Tool execution failed`: Verify the tool's required environment variables are set
|
||||
- `ANTHROPIC_API_KEY is not set`: Check your environment variables (e.g., `export ANTHROPIC_API_KEY=...`)
|
||||
- `TypeError`: Ensure you're using the correct types for tool arguments
|
||||
- `BadRequestError`: Ensure you have enough credits to access the Anthropic API
|
||||
|
||||
## Next steps
|
||||
|
||||
Now that you have a working client, here are some ways to go further:
|
||||
|
||||
- [**Client guide**](./client.md) — Add OAuth, middleware, sampling, and more to your client.
|
||||
- [**Example clients**](https://github.com/modelcontextprotocol/typescript-sdk/tree/main/examples/client) — Browse runnable client examples.
|
||||
- [**FAQ**](./faq.md) — Troubleshoot common errors.
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: Client
|
||||
title: Client Guide
|
||||
---
|
||||
|
||||
# Client overview
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ title: Documents
|
|||
children:
|
||||
- ./server-quickstart.md
|
||||
- ./server.md
|
||||
- ./client-quickstart.md
|
||||
- ./client.md
|
||||
- ./faq.md
|
||||
---
|
||||
|
|
@ -11,5 +12,6 @@ children:
|
|||
|
||||
- [Server Quickstart](./server-quickstart.md) – build a weather server from scratch and connect it to Claude for Desktop
|
||||
- [Server](./server.md) – building MCP servers, transports, tools/resources/prompts, sampling, elicitation, tasks, and deployment patterns
|
||||
- [Client Quickstart](./client-quickstart.md) – build an LLM-powered chatbot that connects to an MCP server and calls its tools
|
||||
- [Client](./client.md) – using the high-level client, transports, OAuth helpers, handling server‑initiated requests, and tasks
|
||||
- [FAQ](./faq.md) – frequently asked questions and troubleshooting
|
||||
|
|
|
|||
1
examples/client-quickstart/.gitignore
vendored
Normal file
1
examples/client-quickstart/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
build/
|
||||
21
examples/client-quickstart/package.json
Normal file
21
examples/client-quickstart/package.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "@modelcontextprotocol/examples-client-quickstart",
|
||||
"private": true,
|
||||
"version": "2.0.0-alpha.0",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"mcp-client-cli": "./build/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.74.0",
|
||||
"@modelcontextprotocol/client": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.10.1",
|
||||
"typescript": "catalog:devTools"
|
||||
}
|
||||
}
|
||||
187
examples/client-quickstart/src/index.ts
Normal file
187
examples/client-quickstart/src/index.ts
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
//#region prelude
|
||||
import Anthropic from '@anthropic-ai/sdk';
|
||||
import { Client, StdioClientTransport, type CallToolResult } from '@modelcontextprotocol/client';
|
||||
import readline from 'readline/promises';
|
||||
|
||||
const ANTHROPIC_MODEL = 'claude-sonnet-4-5';
|
||||
|
||||
class MCPClient {
|
||||
private mcp: Client;
|
||||
private _anthropic: Anthropic | null = null;
|
||||
private transport: StdioClientTransport | null = null;
|
||||
private tools: Anthropic.Tool[] = [];
|
||||
|
||||
constructor() {
|
||||
// Initialize MCP client
|
||||
this.mcp = new Client({ name: 'mcp-client-cli', version: '1.0.0' });
|
||||
}
|
||||
|
||||
private get anthropic(): Anthropic {
|
||||
// Lazy-initialize Anthropic client when needed
|
||||
return this._anthropic ??= new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
||||
}
|
||||
//#endregion prelude
|
||||
|
||||
//#region connectToServer
|
||||
async connectToServer(serverScriptPath: string) {
|
||||
try {
|
||||
// Determine script type and appropriate command
|
||||
const isJs = serverScriptPath.endsWith('.js');
|
||||
const isPy = serverScriptPath.endsWith('.py');
|
||||
if (!isJs && !isPy) {
|
||||
throw new Error('Server script must be a .js or .py file');
|
||||
}
|
||||
const command = isPy
|
||||
? (process.platform === 'win32' ? 'python' : 'python3')
|
||||
: process.execPath;
|
||||
|
||||
// Initialize transport and connect to server
|
||||
this.transport = new StdioClientTransport({ command, args: [serverScriptPath] });
|
||||
await this.mcp.connect(this.transport);
|
||||
|
||||
// List available tools
|
||||
const toolsResult = await this.mcp.listTools();
|
||||
this.tools = toolsResult.tools.map((tool) => ({
|
||||
name: tool.name,
|
||||
description: tool.description ?? '',
|
||||
input_schema: tool.inputSchema as Anthropic.Tool.InputSchema,
|
||||
}));
|
||||
console.log('Connected to server with tools:', this.tools.map(({ name }) => name));
|
||||
} catch (e) {
|
||||
console.log('Failed to connect to MCP server: ', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
//#endregion connectToServer
|
||||
|
||||
//#region processQuery
|
||||
async processQuery(query: string) {
|
||||
const messages: Anthropic.MessageParam[] = [
|
||||
{
|
||||
role: 'user',
|
||||
content: query,
|
||||
},
|
||||
];
|
||||
|
||||
// Initial Claude API call
|
||||
const response = await this.anthropic.messages.create({
|
||||
model: ANTHROPIC_MODEL,
|
||||
max_tokens: 1000,
|
||||
messages,
|
||||
tools: this.tools,
|
||||
});
|
||||
|
||||
// Process response and handle tool calls
|
||||
const finalText = [];
|
||||
|
||||
for (const content of response.content) {
|
||||
if (content.type === 'text') {
|
||||
finalText.push(content.text);
|
||||
} else if (content.type === 'tool_use') {
|
||||
// Execute tool call
|
||||
const toolName = content.name;
|
||||
const toolArgs = content.input as Record<string, unknown> | undefined;
|
||||
const result = await this.mcp.callTool({
|
||||
name: toolName,
|
||||
arguments: toolArgs,
|
||||
}) as CallToolResult;
|
||||
|
||||
finalText.push(`[Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}]`);
|
||||
|
||||
// Extract text from tool result content blocks
|
||||
const toolResultText = result.content
|
||||
.filter((block) => block.type === 'text')
|
||||
.map((block) => block.text)
|
||||
.join('\n');
|
||||
|
||||
// Continue conversation with tool results
|
||||
messages.push({
|
||||
role: 'assistant',
|
||||
content: response.content,
|
||||
});
|
||||
messages.push({
|
||||
role: 'user',
|
||||
content: [{
|
||||
type: 'tool_result',
|
||||
tool_use_id: content.id,
|
||||
content: toolResultText,
|
||||
}],
|
||||
});
|
||||
|
||||
// Get next response from Claude
|
||||
const followUp = await this.anthropic.messages.create({
|
||||
model: ANTHROPIC_MODEL,
|
||||
max_tokens: 1000,
|
||||
messages,
|
||||
});
|
||||
|
||||
finalText.push(followUp.content[0].type === 'text' ? followUp.content[0].text : '');
|
||||
}
|
||||
}
|
||||
|
||||
return finalText.join('\n');
|
||||
}
|
||||
//#endregion processQuery
|
||||
|
||||
//#region chatLoop
|
||||
async chatLoop() {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
try {
|
||||
console.log('\nMCP Client Started!');
|
||||
console.log('Type your queries or "quit" to exit.');
|
||||
|
||||
while (true) {
|
||||
const message = await rl.question('\nQuery: ');
|
||||
if (message.toLowerCase() === 'quit') {
|
||||
break;
|
||||
}
|
||||
const response = await this.processQuery(message);
|
||||
console.log('\n' + response);
|
||||
}
|
||||
} finally {
|
||||
rl.close();
|
||||
}
|
||||
}
|
||||
|
||||
async cleanup() {
|
||||
await this.mcp.close();
|
||||
}
|
||||
}
|
||||
//#endregion chatLoop
|
||||
|
||||
//#region main
|
||||
async function main() {
|
||||
if (process.argv.length < 3) {
|
||||
console.log('Usage: node build/index.js <path_to_server_script>');
|
||||
return;
|
||||
}
|
||||
const mcpClient = new MCPClient();
|
||||
try {
|
||||
await mcpClient.connectToServer(process.argv[2]);
|
||||
|
||||
// Check if we have a valid API key to continue
|
||||
const apiKey = process.env.ANTHROPIC_API_KEY;
|
||||
if (!apiKey) {
|
||||
console.log(
|
||||
'\nNo ANTHROPIC_API_KEY found. To query these tools with Claude, set your API key:'
|
||||
+ '\n export ANTHROPIC_API_KEY=your-api-key-here'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await mcpClient.chatLoop();
|
||||
} catch (e) {
|
||||
console.error('Error:', e);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await mcpClient.cleanup();
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
//#endregion main
|
||||
23
examples/client-quickstart/tsconfig.json
Normal file
23
examples/client-quickstart/tsconfig.json
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2023",
|
||||
"lib": ["ES2023"],
|
||||
"module": "Node16",
|
||||
"moduleResolution": "Node16",
|
||||
"outDir": "./build",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"paths": {
|
||||
"@modelcontextprotocol/client": ["./node_modules/@modelcontextprotocol/client/src/index.ts"],
|
||||
"@modelcontextprotocol/client/_shims": ["./node_modules/@modelcontextprotocol/client/src/shimsNode.ts"],
|
||||
"@modelcontextprotocol/core": [
|
||||
"./node_modules/@modelcontextprotocol/client/node_modules/@modelcontextprotocol/core/src/index.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
45
pnpm-lock.yaml
generated
45
pnpm-lock.yaml
generated
|
|
@ -312,6 +312,22 @@ importers:
|
|||
specifier: catalog:devTools
|
||||
version: 0.18.4(@typescript/native-preview@7.0.0-dev.20260105.1)(typescript@5.9.3)
|
||||
|
||||
examples/client-quickstart:
|
||||
dependencies:
|
||||
'@anthropic-ai/sdk':
|
||||
specifier: ^0.74.0
|
||||
version: 0.74.0(zod@4.3.5)
|
||||
'@modelcontextprotocol/client':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/client
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^24.10.1
|
||||
version: 24.10.4
|
||||
typescript:
|
||||
specifier: catalog:devTools
|
||||
version: 5.9.3
|
||||
|
||||
examples/server:
|
||||
dependencies:
|
||||
'@hono/node-server':
|
||||
|
|
@ -959,6 +975,15 @@ importers:
|
|||
|
||||
packages:
|
||||
|
||||
'@anthropic-ai/sdk@0.74.0':
|
||||
resolution: {integrity: sha512-srbJV7JKsc5cQ6eVuFzjZO7UR3xEPJqPamHFIe29bs38Ij2IripoAhC0S5NslNbaFUYqBKypmmpzMTpqfHEUDw==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
zod: ^3.25.0 || ^4.0.0
|
||||
peerDependenciesMeta:
|
||||
zod:
|
||||
optional: true
|
||||
|
||||
'@babel/generator@7.28.5':
|
||||
resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
|
@ -3505,6 +3530,10 @@ packages:
|
|||
json-buffer@3.0.1:
|
||||
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
|
||||
|
||||
json-schema-to-ts@3.1.1:
|
||||
resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
json-schema-traverse@0.4.1:
|
||||
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
||||
|
||||
|
|
@ -4203,6 +4232,9 @@ packages:
|
|||
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
||||
hasBin: true
|
||||
|
||||
ts-algebra@2.0.0:
|
||||
resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==}
|
||||
|
||||
ts-api-utils@2.4.0:
|
||||
resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==}
|
||||
engines: {node: '>=18.12'}
|
||||
|
|
@ -4551,6 +4583,12 @@ packages:
|
|||
|
||||
snapshots:
|
||||
|
||||
'@anthropic-ai/sdk@0.74.0(zod@4.3.5)':
|
||||
dependencies:
|
||||
json-schema-to-ts: 3.1.1
|
||||
optionalDependencies:
|
||||
zod: 4.3.5
|
||||
|
||||
'@babel/generator@7.28.5':
|
||||
dependencies:
|
||||
'@babel/parser': 7.28.5
|
||||
|
|
@ -6981,6 +7019,11 @@ snapshots:
|
|||
|
||||
json-buffer@3.0.1: {}
|
||||
|
||||
json-schema-to-ts@3.1.1:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.4
|
||||
ts-algebra: 2.0.0
|
||||
|
||||
json-schema-traverse@0.4.1: {}
|
||||
|
||||
json-schema-traverse@1.0.0: {}
|
||||
|
|
@ -7762,6 +7805,8 @@ snapshots:
|
|||
|
||||
tree-kill@1.2.2: {}
|
||||
|
||||
ts-algebra@2.0.0: {}
|
||||
|
||||
ts-api-utils@2.4.0(typescript@5.9.3):
|
||||
dependencies:
|
||||
typescript: 5.9.3
|
||||
|
|
|
|||
Loading…
Reference in a new issue