lint
This commit is contained in:
parent
eeda5d630a
commit
6050aa9f05
4 changed files with 13 additions and 264 deletions
|
|
@ -4,6 +4,7 @@ import {
|
|||
CallToolRequest,
|
||||
CallToolResultSchema,
|
||||
LoggingMessageNotificationSchema,
|
||||
CallToolResult,
|
||||
} from '../../types.js';
|
||||
|
||||
/**
|
||||
|
|
@ -23,12 +24,12 @@ interface ClientConfig {
|
|||
id: string;
|
||||
name: string;
|
||||
toolName: string;
|
||||
toolArguments: Record<string, any>;
|
||||
toolArguments: Record<string, string | number | boolean>;
|
||||
}
|
||||
|
||||
async function createAndRunClient(config: ClientConfig): Promise<{ id: string; result: any }> {
|
||||
async function createAndRunClient(config: ClientConfig): Promise<{ id: string; result: CallToolResult }> {
|
||||
console.log(`[${config.id}] Creating client: ${config.name}`);
|
||||
|
||||
|
||||
const client = new Client({
|
||||
name: config.name,
|
||||
version: '1.0.0'
|
||||
|
|
@ -101,7 +102,7 @@ async function main(): Promise<void> {
|
|||
}
|
||||
},
|
||||
{
|
||||
id: 'client2',
|
||||
id: 'client2',
|
||||
name: 'basic-client-2',
|
||||
toolName: 'start-notification-stream',
|
||||
toolArguments: {
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js';
|
|||
import {
|
||||
ListToolsRequest,
|
||||
ListToolsResultSchema,
|
||||
CallToolRequest,
|
||||
CallToolResultSchema,
|
||||
LoggingMessageNotificationSchema,
|
||||
CallToolResult,
|
||||
} from '../../types.js';
|
||||
|
||||
/**
|
||||
|
|
@ -57,11 +57,11 @@ async function main(): Promise<void> {
|
|||
// 2. Start multiple notification tools in parallel
|
||||
console.log('\n=== Starting Multiple Notification Streams in Parallel ===');
|
||||
const toolResults = await startParallelNotificationTools(client);
|
||||
|
||||
|
||||
// Log the results from each tool call
|
||||
for (const [caller, result] of Object.entries(toolResults)) {
|
||||
console.log(`\n=== Tool result for ${caller} ===`);
|
||||
result.content.forEach((item: { type: string; text: any; }) => {
|
||||
result.content.forEach((item: { type: string; text?: string; }) => {
|
||||
if (item.type === 'text') {
|
||||
console.log(` ${item.text}`);
|
||||
} else {
|
||||
|
|
@ -113,7 +113,7 @@ async function listTools(client: Client): Promise<void> {
|
|||
* Start multiple notification tools in parallel with different configurations
|
||||
* Each tool call includes a caller parameter to identify its notifications
|
||||
*/
|
||||
async function startParallelNotificationTools(client: Client): Promise<Record<string, any>> {
|
||||
async function startParallelNotificationTools(client: Client): Promise<Record<string, CallToolResult>> {
|
||||
try {
|
||||
// Define multiple tool calls with different configurations
|
||||
const toolCalls = [
|
||||
|
|
@ -162,7 +162,7 @@ async function startParallelNotificationTools(client: Client): Promise<Record<st
|
|||
];
|
||||
|
||||
console.log(`Starting ${toolCalls.length} notification tools in parallel...`);
|
||||
|
||||
|
||||
// Start all tool calls in parallel
|
||||
const toolPromises = toolCalls.map(({ caller, request }) => {
|
||||
console.log(`Starting tool call for ${caller}...`);
|
||||
|
|
@ -176,9 +176,9 @@ async function startParallelNotificationTools(client: Client): Promise<Record<st
|
|||
|
||||
// Wait for all tool calls to complete
|
||||
const results = await Promise.all(toolPromises);
|
||||
|
||||
|
||||
// Organize results by caller
|
||||
const resultsByTool: Record<string, any> = {};
|
||||
const resultsByTool: Record<string, CallToolResult> = {};
|
||||
results.forEach(({ caller, result }) => {
|
||||
resultsByTool[caller] = result;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,252 +0,0 @@
|
|||
/**
|
||||
* Integration tests for batch messaging in StreamableHttp transport
|
||||
*
|
||||
* This test suite focuses specifically on the requirement from the spec:
|
||||
* "The body of the POST request MUST be one of the following:
|
||||
* - A single JSON-RPC request, notification, or response
|
||||
* - An array batching one or more requests and/or notifications
|
||||
* - An array batching one or more responses"
|
||||
*/
|
||||
|
||||
import { createServer, type Server } from "node:http";
|
||||
import { AddressInfo } from "node:net";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { StreamableHTTPServerTransport } from "../server/streamableHttp.js";
|
||||
import { McpServer } from "../server/mcp.js";
|
||||
import { Client } from "../client/index.js";
|
||||
import { CallToolResult, CallToolResultSchema, JSONRPCMessage } from "../types.js";
|
||||
import { z } from "zod";
|
||||
import { StreamableHTTPClientTransport } from '../client/streamableHttp.js';
|
||||
describe("StreamableHttp Batch Messaging - SSE", () => {
|
||||
let server: Server;
|
||||
let client: Client;
|
||||
|
||||
// Just a basic server and client for testing
|
||||
beforeEach(async () => {
|
||||
// Create MCP server with test tools
|
||||
const mcpServer = new McpServer(
|
||||
{ name: "batch-test-server", version: "1.0.0" },
|
||||
{ capabilities: { logging: {} } }
|
||||
);
|
||||
|
||||
// Simple greeting tool
|
||||
mcpServer.tool(
|
||||
"greet",
|
||||
"A simple greeting tool",
|
||||
{ name: z.string().describe("Name to greet") },
|
||||
async ({ name }): Promise<CallToolResult> => {
|
||||
return { content: [{ type: "text", text: `Hello, ${name}!` }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Server transport with session management
|
||||
const serverTransport = new StreamableHTTPServerTransport({
|
||||
sessionIdGenerator: () => randomUUID(),
|
||||
});
|
||||
|
||||
// Connect transport to server
|
||||
await mcpServer.connect(serverTransport);
|
||||
|
||||
// Create HTTP server
|
||||
server = createServer(async (req, res) => {
|
||||
await serverTransport.handleRequest(req, res);
|
||||
});
|
||||
|
||||
// Start server on random port
|
||||
const baseUrl = await new Promise<URL>((resolve) => {
|
||||
server.listen(0, '127.0.0.1', () => {
|
||||
const addr = server.address() as AddressInfo;
|
||||
resolve(new URL(`http://127.0.0.1:${addr.port}`));
|
||||
});
|
||||
});
|
||||
|
||||
// Create client that connects to the server
|
||||
const transport = new StreamableHTTPClientTransport(baseUrl);
|
||||
client = new Client({ name: "test-client", version: "1.0.0" });
|
||||
await client.connect(transport);
|
||||
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await client.close();
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
});
|
||||
|
||||
/**
|
||||
* 1. Test sending a single JSON-RPC request
|
||||
*/
|
||||
it("handles a single request", async () => {
|
||||
const result = await client.callTool({
|
||||
name: "greet",
|
||||
arguments: {
|
||||
name: "user"
|
||||
}
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty("content");
|
||||
expect(Array.isArray(result.content)).toBe(true);
|
||||
expect(result.content).toHaveLength(1);
|
||||
|
||||
// Type assertion to handle the unknown type
|
||||
const content = result.content as Array<{ type: string, text: string }>;
|
||||
expect(content[0]).toHaveProperty("type", "text");
|
||||
expect(content[0]).toHaveProperty("text", "Hello, user!");
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* 1. Test sending a single JSON-RPC request
|
||||
*/
|
||||
it("handles a single request with request", async () => {
|
||||
const result = await client.request(
|
||||
{
|
||||
method: "tools/call",
|
||||
params: {
|
||||
name: "greet",
|
||||
arguments: {
|
||||
name: "user"
|
||||
}
|
||||
},
|
||||
},
|
||||
CallToolResultSchema,
|
||||
);
|
||||
|
||||
|
||||
expect(result).toHaveProperty("content");
|
||||
expect(Array.isArray(result.content)).toBe(true);
|
||||
expect(result.content).toHaveLength(1);
|
||||
|
||||
// Type assertion to handle the unknown type
|
||||
const content = result.content as Array<{ type: string, text: string }>;
|
||||
expect(content[0]).toHaveProperty("type", "text");
|
||||
expect(content[0]).toHaveProperty("text", "Hello, user!");
|
||||
|
||||
});
|
||||
|
||||
// it("handles an array batching one or more requests and/or notifications", async () => {
|
||||
// const result = await client.request({
|
||||
|
||||
// });
|
||||
|
||||
// });
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe("StreamableHttp Batch Messaging - JSON response", () => {
|
||||
let server: Server;
|
||||
let client: Client;
|
||||
|
||||
// Just a basic server and client for testing
|
||||
beforeEach(async () => {
|
||||
// Create MCP server with test tools
|
||||
const mcpServer = new McpServer(
|
||||
{ name: "batch-test-server", version: "1.0.0" },
|
||||
{ capabilities: { logging: {} } }
|
||||
);
|
||||
|
||||
// Simple greeting tool
|
||||
mcpServer.tool(
|
||||
"greet",
|
||||
"A simple greeting tool",
|
||||
{ name: z.string().describe("Name to greet") },
|
||||
async ({ name }): Promise<CallToolResult> => {
|
||||
return { content: [{ type: "text", text: `Hello, ${name}!` }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Server transport with session management
|
||||
const serverTransport = new StreamableHTTPServerTransport({
|
||||
sessionIdGenerator: () => randomUUID(),
|
||||
enableJsonResponse: true,
|
||||
|
||||
});
|
||||
|
||||
// Connect transport to server
|
||||
await mcpServer.connect(serverTransport);
|
||||
|
||||
// Create HTTP server
|
||||
server = createServer(async (req, res) => {
|
||||
await serverTransport.handleRequest(req, res);
|
||||
});
|
||||
|
||||
// Start server on random port
|
||||
const baseUrl = await new Promise<URL>((resolve) => {
|
||||
server.listen(0, '127.0.0.1', () => {
|
||||
const addr = server.address() as AddressInfo;
|
||||
resolve(new URL(`http://127.0.0.1:${addr.port}`));
|
||||
});
|
||||
});
|
||||
|
||||
// Create client that connects to the server
|
||||
const transport = new StreamableHTTPClientTransport(baseUrl);
|
||||
client = new Client({ name: "test-client", version: "1.0.0" });
|
||||
await client.connect(transport);
|
||||
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await client.close();
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
});
|
||||
|
||||
/**
|
||||
* 1. Test sending a single JSON-RPC request
|
||||
*/
|
||||
it("handles a single request", async () => {
|
||||
const result = await client.callTool({
|
||||
name: "greet",
|
||||
arguments: {
|
||||
name: "user"
|
||||
}
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty("content");
|
||||
expect(Array.isArray(result.content)).toBe(true);
|
||||
expect(result.content).toHaveLength(1);
|
||||
|
||||
// Type assertion to handle the unknown type
|
||||
const content = result.content as Array<{ type: string, text: string }>;
|
||||
expect(content[0]).toHaveProperty("type", "text");
|
||||
expect(content[0]).toHaveProperty("text", "Hello, user!");
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* 1. Test sending a single JSON-RPC request
|
||||
*/
|
||||
it("handles a single request with request", async () => {
|
||||
const result = await client.request(
|
||||
{
|
||||
method: "tools/call",
|
||||
params: {
|
||||
name: "greet",
|
||||
arguments: {
|
||||
name: "user"
|
||||
}
|
||||
},
|
||||
},
|
||||
CallToolResultSchema,
|
||||
);
|
||||
|
||||
|
||||
expect(result).toHaveProperty("content");
|
||||
expect(Array.isArray(result.content)).toBe(true);
|
||||
expect(result.content).toHaveLength(1);
|
||||
|
||||
// Type assertion to handle the unknown type
|
||||
const content = result.content as Array<{ type: string, text: string }>;
|
||||
expect(content[0]).toHaveProperty("type", "text");
|
||||
expect(content[0]).toHaveProperty("text", "Hello, user!");
|
||||
|
||||
});
|
||||
|
||||
// it("handles an array batching one or more requests and/or notifications", async () => {
|
||||
// const result = await client.request({
|
||||
|
||||
// });
|
||||
|
||||
// });
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -288,7 +288,7 @@ describe("StreamableHTTPServerTransport", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it.only("should reject requests without a valid session ID", async () => {
|
||||
it("should reject requests without a valid session ID", async () => {
|
||||
const response = await sendPostRequest(baseUrl, TEST_MESSAGES.toolsList);
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
|
|
|
|||
Loading…
Reference in a new issue