Skip to content

Commit 70608b5

Browse files
committed
Add more test clients
1 parent 3ef9023 commit 70608b5

File tree

3 files changed

+608
-0
lines changed

3 files changed

+608
-0
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import { Client } from '../../client/index.js';
2+
import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js';
3+
import {
4+
CallToolRequest,
5+
CallToolResultSchema,
6+
LoggingMessageNotificationSchema,
7+
} from '../../types.js';
8+
9+
/**
10+
* Multiple Clients MCP Example
11+
*
12+
* This client demonstrates how to:
13+
* 1. Create multiple MCP clients in parallel
14+
* 2. Each client calls a single tool
15+
* 3. Track notifications from each client independently
16+
*/
17+
18+
// Command line args processing
19+
const args = process.argv.slice(2);
20+
const serverUrl = args[0] || 'http://localhost:3000/mcp';
21+
22+
interface ClientConfig {
23+
id: string;
24+
name: string;
25+
toolName: string;
26+
toolArguments: Record<string, any>;
27+
}
28+
29+
async function createAndRunClient(config: ClientConfig): Promise<{ id: string; result: any }> {
30+
console.log(`[${config.id}] Creating client: ${config.name}`);
31+
32+
const client = new Client({
33+
name: config.name,
34+
version: '1.0.0'
35+
});
36+
37+
const transport = new StreamableHTTPClientTransport(new URL(serverUrl));
38+
39+
// Set up client-specific error handler
40+
client.onerror = (error) => {
41+
console.error(`[${config.id}] Client error:`, error);
42+
};
43+
44+
// Set up client-specific notification handler
45+
client.setNotificationHandler(LoggingMessageNotificationSchema, (notification) => {
46+
console.log(`[${config.id}] Notification: ${notification.params.data}`);
47+
});
48+
49+
try {
50+
// Connect to the server
51+
await client.connect(transport);
52+
console.log(`[${config.id}] Connected to MCP server`);
53+
54+
// Call the specified tool
55+
console.log(`[${config.id}] Calling tool: ${config.toolName}`);
56+
const toolRequest: CallToolRequest = {
57+
method: 'tools/call',
58+
params: {
59+
name: config.toolName,
60+
arguments: {
61+
...config.toolArguments,
62+
// Add client ID to arguments for identification in notifications
63+
caller: config.id
64+
}
65+
}
66+
};
67+
68+
const result = await client.request(toolRequest, CallToolResultSchema);
69+
console.log(`[${config.id}] Tool call completed`);
70+
71+
// Keep the connection open for a bit to receive notifications
72+
await new Promise(resolve => setTimeout(resolve, 5000));
73+
74+
// Disconnect
75+
await transport.close();
76+
console.log(`[${config.id}] Disconnected from MCP server`);
77+
78+
return { id: config.id, result };
79+
} catch (error) {
80+
console.error(`[${config.id}] Error:`, error);
81+
throw error;
82+
}
83+
}
84+
85+
async function main(): Promise<void> {
86+
console.log('MCP Multiple Clients Example');
87+
console.log('============================');
88+
console.log(`Server URL: ${serverUrl}`);
89+
console.log('');
90+
91+
try {
92+
// Define client configurations
93+
const clientConfigs: ClientConfig[] = [
94+
{
95+
id: 'client1',
96+
name: 'basic-client-1',
97+
toolName: 'start-notification-stream',
98+
toolArguments: {
99+
interval: 3, // 1 second between notifications
100+
count: 5 // Send 5 notifications
101+
}
102+
},
103+
{
104+
id: 'client2',
105+
name: 'basic-client-2',
106+
toolName: 'start-notification-stream',
107+
toolArguments: {
108+
interval: 2, // 2 seconds between notifications
109+
count: 3 // Send 3 notifications
110+
}
111+
},
112+
{
113+
id: 'client3',
114+
name: 'basic-client-3',
115+
toolName: 'start-notification-stream',
116+
toolArguments: {
117+
interval: 1, // 0.5 second between notifications
118+
count: 8 // Send 8 notifications
119+
}
120+
}
121+
];
122+
123+
// Start all clients in parallel
124+
console.log(`Starting ${clientConfigs.length} clients in parallel...`);
125+
console.log('');
126+
127+
const clientPromises = clientConfigs.map(config => createAndRunClient(config));
128+
const results = await Promise.all(clientPromises);
129+
130+
// Display results from all clients
131+
console.log('\n=== Final Results ===');
132+
results.forEach(({ id, result }) => {
133+
console.log(`\n[${id}] Tool result:`);
134+
if (Array.isArray(result.content)) {
135+
result.content.forEach((item: { type: string; text?: string }) => {
136+
if (item.type === 'text' && item.text) {
137+
console.log(` ${item.text}`);
138+
} else {
139+
console.log(` ${item.type} content:`, item);
140+
}
141+
});
142+
} else {
143+
console.log(` Unexpected result format:`, result);
144+
}
145+
});
146+
147+
console.log('\n=== All clients completed successfully ===');
148+
149+
} catch (error) {
150+
console.error('Error running multiple clients:', error);
151+
process.exit(1);
152+
}
153+
}
154+
155+
// Start the example
156+
main().catch((error: unknown) => {
157+
console.error('Error running MCP multiple clients example:', error);
158+
process.exit(1);
159+
});
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
import { Client } from '../../client/index.js';
2+
import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js';
3+
import {
4+
ListToolsRequest,
5+
ListToolsResultSchema,
6+
CallToolRequest,
7+
CallToolResultSchema,
8+
LoggingMessageNotificationSchema,
9+
} from '../../types.js';
10+
11+
/**
12+
* Parallel Tool Calls MCP Client
13+
*
14+
* This client demonstrates how to:
15+
* 1. Start multiple tool calls in parallel
16+
* 2. Track notifications from each tool call using a caller parameter
17+
*/
18+
19+
// Command line args processing
20+
const args = process.argv.slice(2);
21+
const serverUrl = args[0] || 'http://localhost:3000/mcp';
22+
23+
async function main(): Promise<void> {
24+
console.log('MCP Parallel Tool Calls Client');
25+
console.log('==============================');
26+
console.log(`Connecting to server at: ${serverUrl}`);
27+
28+
let client: Client;
29+
let transport: StreamableHTTPClientTransport;
30+
31+
try {
32+
// Create client with streamable HTTP transport
33+
client = new Client({
34+
name: 'parallel-tool-calls-client',
35+
version: '1.0.0'
36+
});
37+
38+
client.onerror = (error) => {
39+
console.error('Client error:', error);
40+
};
41+
42+
// Connect to the server
43+
transport = new StreamableHTTPClientTransport(new URL(serverUrl));
44+
await client.connect(transport);
45+
console.log('Successfully connected to MCP server');
46+
47+
// Set up notification handler with caller identification
48+
client.setNotificationHandler(LoggingMessageNotificationSchema, (notification) => {
49+
console.log(`Notification: ${notification.params.data}`);
50+
});
51+
52+
console.log("List tools")
53+
const toolsRequest = await listTools(client);
54+
console.log("Tools: ", toolsRequest)
55+
56+
57+
// 2. Start multiple notification tools in parallel
58+
console.log('\n=== Starting Multiple Notification Streams in Parallel ===');
59+
const toolResults = await startParallelNotificationTools(client);
60+
61+
// Log the results from each tool call
62+
for (const [caller, result] of Object.entries(toolResults)) {
63+
console.log(`\n=== Tool result for ${caller} ===`);
64+
result.content.forEach((item: { type: string; text: any; }) => {
65+
if (item.type === 'text') {
66+
console.log(` ${item.text}`);
67+
} else {
68+
console.log(` ${item.type} content:`, item);
69+
}
70+
});
71+
}
72+
73+
// 3. Wait for all notifications (10 seconds)
74+
console.log('\n=== Waiting for all notifications ===');
75+
await new Promise(resolve => setTimeout(resolve, 10000));
76+
77+
// 4. Disconnect
78+
console.log('\n=== Disconnecting ===');
79+
await transport.close();
80+
console.log('Disconnected from MCP server');
81+
82+
} catch (error) {
83+
console.error('Error running client:', error);
84+
process.exit(1);
85+
}
86+
}
87+
88+
/**
89+
* List available tools on the server
90+
*/
91+
async function listTools(client: Client): Promise<void> {
92+
try {
93+
const toolsRequest: ListToolsRequest = {
94+
method: 'tools/list',
95+
params: {}
96+
};
97+
const toolsResult = await client.request(toolsRequest, ListToolsResultSchema);
98+
99+
console.log('Available tools:');
100+
if (toolsResult.tools.length === 0) {
101+
console.log(' No tools available');
102+
} else {
103+
for (const tool of toolsResult.tools) {
104+
console.log(` - ${tool.name}: ${tool.description}`);
105+
}
106+
}
107+
} catch (error) {
108+
console.log(`Tools not supported by this server: ${error}`);
109+
}
110+
}
111+
112+
/**
113+
* Start multiple notification tools in parallel with different configurations
114+
* Each tool call includes a caller parameter to identify its notifications
115+
*/
116+
async function startParallelNotificationTools(client: Client): Promise<Record<string, any>> {
117+
try {
118+
// Define multiple tool calls with different configurations
119+
const toolCalls = [
120+
{
121+
caller: 'fast-notifier',
122+
request: {
123+
method: 'tools/call',
124+
params: {
125+
name: 'start-notification-stream',
126+
arguments: {
127+
interval: 2, // 0.5 second between notifications
128+
count: 10, // Send 10 notifications
129+
caller: 'fast-notifier' // Identify this tool call
130+
}
131+
}
132+
}
133+
},
134+
{
135+
caller: 'slow-notifier',
136+
request: {
137+
method: 'tools/call',
138+
params: {
139+
name: 'start-notification-stream',
140+
arguments: {
141+
interval: 5, // 2 seconds between notifications
142+
count: 5, // Send 5 notifications
143+
caller: 'slow-notifier' // Identify this tool call
144+
}
145+
}
146+
}
147+
},
148+
{
149+
caller: 'burst-notifier',
150+
request: {
151+
method: 'tools/call',
152+
params: {
153+
name: 'start-notification-stream',
154+
arguments: {
155+
interval: 1, // 0.1 second between notifications
156+
count: 3, // Send just 3 notifications
157+
caller: 'burst-notifier' // Identify this tool call
158+
}
159+
}
160+
}
161+
}
162+
];
163+
164+
console.log(`Starting ${toolCalls.length} notification tools in parallel...`);
165+
166+
// Start all tool calls in parallel
167+
const toolPromises = toolCalls.map(({ caller, request }) => {
168+
console.log(`Starting tool call for ${caller}...`);
169+
return client.request(request, CallToolResultSchema)
170+
.then(result => ({ caller, result }))
171+
.catch(error => {
172+
console.error(`Error in tool call for ${caller}:`, error);
173+
throw error;
174+
});
175+
});
176+
177+
// Wait for all tool calls to complete
178+
const results = await Promise.all(toolPromises);
179+
180+
// Organize results by caller
181+
const resultsByTool: Record<string, any> = {};
182+
results.forEach(({ caller, result }) => {
183+
resultsByTool[caller] = result;
184+
});
185+
186+
return resultsByTool;
187+
} catch (error) {
188+
console.error(`Error starting parallel notification tools:`, error);
189+
throw error;
190+
}
191+
}
192+
193+
// Start the client
194+
main().catch((error: unknown) => {
195+
console.error('Error running MCP client:', error);
196+
process.exit(1);
197+
});

0 commit comments

Comments
 (0)