raw request propagation in tools - implementation, unit tests, types
This commit is contained in:
parent
df0d9c4ffc
commit
db9ba7b419
1 changed files with 641 additions and 226 deletions
|
|
@ -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) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue