Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
"updateInternalDependencies": "patch",
"ignore": [
"@modelcontextprotocol/examples",
"@modelcontextprotocol/examples-client-quickstart",
"@modelcontextprotocol/examples-server-quickstart",
"@mcp-examples/*"
]
}
2 changes: 0 additions & 2 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
"@modelcontextprotocol/tsconfig": "2.0.0",
"@modelcontextprotocol/vitest-config": "2.0.0",
"@modelcontextprotocol/examples": "2.0.0-alpha.0",
"@modelcontextprotocol/examples-client-quickstart": "2.0.0-alpha.0",
"@modelcontextprotocol/examples-server-quickstart": "2.0.0-alpha.0",
"@modelcontextprotocol/client": "2.0.0-alpha.0",
"@modelcontextprotocol/core-internal": "2.0.0-alpha.0",
"@modelcontextprotocol/express": "2.0.0-alpha.0",
Expand Down
1 change: 1 addition & 0 deletions docs/behavior-surface-pins.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ CI pass — that reopens the silent-drift hole the pin exists to close.
| Schema strict/strip/loose boundaries, key existence | `packages/core-internal/test/types/schemaBoundaryPins.test.ts` |
| Published package set, export maps, ESM-only topology | `packages/core-internal/test/packageTopologyPins.test.ts` |
| stdio environment-inheritance safelist | `packages/client/test/client/stdioEnvPins.test.ts` |
| 2025-11-25 wire method-registry membership, schema identity | `packages/core-internal/test/types/registryPins.test.ts` |

## Writing a new pin

Expand Down
94 changes: 55 additions & 39 deletions docs/client-quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,11 @@ import { Client } from '@modelcontextprotocol/client';
import { StdioClientTransport } from '@modelcontextprotocol/client/stdio';
import readline from 'readline/promises';

const ANTHROPIC_MODEL = 'claude-sonnet-4-5';
const ANTHROPIC_MODEL = 'claude-sonnet-4-6';

class MCPClient {
private mcp: Client;
private _anthropic: Anthropic | null = null;
private transport: StdioClientTransport | null = null;
private tools: Anthropic.Tool[] = [];

constructor() {
Expand Down Expand Up @@ -153,8 +152,8 @@ Next, we'll implement the method to connect to an MCP server:
: process.execPath;

// Initialize transport and connect to server
this.transport = new StdioClientTransport({ command, args: [serverScriptPath] });
await this.mcp.connect(this.transport);
const transport = new StdioClientTransport({ command, args: [serverScriptPath] });
await this.mcp.connect(transport);

// List available tools
const toolsResult = await this.mcp.listTools();
Expand Down Expand Up @@ -185,60 +184,74 @@ Now let's add the core functionality for processing queries and handling tool ca
];

// Initial Claude API call
const response = await this.anthropic.messages.create({
let response = await this.anthropic.messages.create({
model: ANTHROPIC_MODEL,
max_tokens: 1000,
messages,
tools: this.tools,
});

// Process response and handle tool calls
// Process responses, executing tool calls until Claude stops requesting them
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;
while (true) {
const toolUses: Anthropic.ToolUseBlock[] = [];
for (const content of response.content) {
if (content.type === 'text') {
finalText.push(content.text);
} else if (content.type === 'tool_use') {
toolUses.push(content);
}
}

if (toolUses.length === 0) {
break;
}

// Execute every requested tool call and collect the results
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const toolUse of toolUses) {
const toolArgs = toolUse.input as Record<string, unknown>;
const result = await this.mcp.callTool({
name: toolName,
name: toolUse.name,
arguments: toolArgs,
});

finalText.push(`[Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}]`);
finalText.push(`[Calling tool ${toolUse.name} 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,
toolResults.push({
type: 'tool_result',
tool_use_id: toolUse.id,
content: toolResultText,
// Tell Claude when the tool call failed
...(result.isError ? { is_error: true } : {}),
});

const firstBlock = followUp.content[0];
finalText.push(firstBlock?.type === 'text' ? firstBlock.text : '');
}

// Continue the conversation: the assistant turn, then ALL tool
// results together in a single user turn
messages.push({
role: 'assistant',
content: response.content,
});
messages.push({
role: 'user',
content: toolResults,
});

// Get next response from Claude
response = await this.anthropic.messages.create({
model: ANTHROPIC_MODEL,
max_tokens: 1000,
messages,
tools: this.tools,
});
}

return finalText.join('\n');
Expand Down Expand Up @@ -364,13 +377,16 @@ When you submit a query:
5. Claude provides a natural language response
6. The response is displayed to you

> [!NOTE]
> By default, the client uses the legacy 2025-era `initialize` handshake, so it works with any 2025-era server, including the weather server from the server quickstart. To opt into the 2026-07-28 draft revision, see [Protocol version negotiation](./client.md#protocol-version-negotiation-2026-07-28-revision).

## 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
- On Windows, both backslashes (`\`) and forward slashes (`/`) work as path separators
- Verify the server file has the correct extension (`.js` for Node.js or `.py` for Python)

Example of correct path usage:
Expand Down Expand Up @@ -411,7 +427,7 @@ node build/index.js C:/projects/mcp-server/build/index.js
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
- `Error: spawn ... ENOENT` or an immediate exit: check the server script path and that `node` / `python3` can run it (the client spawns the server, so don't start it yourself)
- `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
Expand Down
Loading
Loading