raw request propagation in tools - implementation, unit tests, types

This commit is contained in:
Konstantin Konstantinov 2025-06-14 01:08:02 +03:00
commit db9ba7b419
No known key found for this signature in database

View file

@ -18,6 +18,14 @@ import {
import { ResourceTemplate } from "./mcp.js";
import { completable } from "./completable.js";
import { UriTemplate } from "../shared/uriTemplate.js";
import { RequestInfo } from "./types/types.js";
const mockRequestInfo: RequestInfo = {
headers: {
'content-type': 'application/json',
'accept': 'application/json',
},
};
describe("McpServer", () => {
/***
@ -212,7 +220,8 @@ describe("ResourceTemplate", () => {
signal: abortController.signal,
requestId: 'not-implemented',
sendRequest: () => { throw new Error("Not implemented") },
sendNotification: () => { throw new Error("Not implemented") }
sendNotification: () => { throw new Error("Not implemented") },
requestInfo: mockRequestInfo
});
expect(result?.resources).toHaveLength(1);
expect(list).toHaveBeenCalled();
@ -913,18 +922,10 @@ describe("tool()", () => {
name: "test server",
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
tools: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
mcpServer.tool(
"test",
@ -1056,17 +1057,10 @@ describe("tool()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
tools: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
// Register a tool with outputSchema
mcpServer.registerTool(
@ -1169,17 +1163,10 @@ describe("tool()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
tools: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
// Register a tool with outputSchema that returns only content without structuredContent
mcpServer.registerTool(
@ -1233,17 +1220,10 @@ describe("tool()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
tools: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
// Register a tool with outputSchema that returns invalid data
mcpServer.registerTool(
@ -1308,17 +1288,10 @@ describe("tool()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
tools: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
let receivedSessionId: string | undefined;
mcpServer.tool("test-tool", async (extra) => {
@ -1364,17 +1337,10 @@ describe("tool()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
tools: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
let receivedRequestId: string | number | undefined;
mcpServer.tool("request-id-test", async (extra) => {
@ -1423,17 +1389,10 @@ describe("tool()", () => {
{ capabilities: { logging: {} } },
);
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
tools: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
let receivedLogMessage: string | undefined;
const loggingMessage = "hello here is log message 1";
@ -1480,17 +1439,10 @@ describe("tool()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
tools: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
mcpServer.tool(
"test",
@ -1546,17 +1498,10 @@ describe("tool()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
tools: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
mcpServer.tool("error-test", async () => {
throw new Error("Tool execution failed");
@ -1598,17 +1543,10 @@ describe("tool()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
tools: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
mcpServer.tool("test-tool", async () => ({
content: [
@ -2392,6 +2330,48 @@ describe("resource()", () => {
).rejects.toThrow(/Resource test:\/\/nonexistent not found/);
});
/***
* Test: Registering a resource template with a complete callback should update server capabilities to advertise support for completion
*/
test("should advertise support for completion when a resource template with a complete callback is defined", async () => {
const mcpServer = new McpServer({
name: "test server",
version: "1.0",
});
const client = new Client({
name: "test client",
version: "1.0",
});
mcpServer.resource(
"test",
new ResourceTemplate("test://resource/{category}", {
list: undefined,
complete: {
category: () => ["books", "movies", "music"],
},
}),
async () => ({
contents: [
{
uri: "test://resource/test",
text: "Test content",
},
],
}),
);
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
await Promise.all([
client.connect(clientTransport),
mcpServer.server.connect(serverTransport),
]);
expect(client.getServerCapabilities()).toMatchObject({ completions: {} })
})
/***
* Test: Resource Template Parameter Completion
*/
@ -2401,17 +2381,10 @@ describe("resource()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
resources: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
mcpServer.resource(
"test",
@ -2469,17 +2442,10 @@ describe("resource()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
resources: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
mcpServer.resource(
"test",
@ -2540,17 +2506,10 @@ describe("resource()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
resources: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
let receivedRequestId: string | number | undefined;
mcpServer.resource("request-id-test", "test://resource", async (_uri, extra) => {
@ -3052,17 +3011,10 @@ describe("prompt()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
prompts: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
mcpServer.prompt(
"test",
@ -3258,17 +3210,10 @@ describe("prompt()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
prompts: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
mcpServer.prompt("test-prompt", async () => ({
messages: [
@ -3303,6 +3248,49 @@ describe("prompt()", () => {
).rejects.toThrow(/Prompt nonexistent-prompt not found/);
});
/***
* Test: Registering a prompt with a completable argument should update server capabilities to advertise support for completion
*/
test("should advertise support for completion when a prompt with a completable argument is defined", async () => {
const mcpServer = new McpServer({
name: "test server",
version: "1.0",
});
const client = new Client({
name: "test client",
version: "1.0",
});
mcpServer.prompt(
"test-prompt",
{
name: completable(z.string(), () => ["Alice", "Bob", "Charlie"]),
},
async ({ name }) => ({
messages: [
{
role: "assistant",
content: {
type: "text",
text: `Hello ${name}`,
},
},
],
}),
);
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
await Promise.all([
client.connect(clientTransport),
mcpServer.server.connect(serverTransport),
]);
expect(client.getServerCapabilities()).toMatchObject({ completions: {} })
})
/***
* Test: Prompt Argument Completion
*/
@ -3312,17 +3300,10 @@ describe("prompt()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
prompts: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
mcpServer.prompt(
"test-prompt",
@ -3380,17 +3361,10 @@ describe("prompt()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
prompts: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
mcpServer.prompt(
"test-prompt",
@ -3450,17 +3424,10 @@ describe("prompt()", () => {
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
prompts: {},
},
},
);
const client = new Client({
name: "test client",
version: "1.0",
});
let receivedRequestId: string | number | undefined;
mcpServer.prompt("request-id-test", async (extra) => {