Skip to content
Open
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
153 changes: 105 additions & 48 deletions src/everything/__tests__/registrations.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, it, expect, vi } from 'vitest';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { describe, it, expect, vi } from "vitest";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

// Create mock server
function createMockServer() {
Expand All @@ -16,10 +16,21 @@ function createMockServer() {
} as unknown as McpServer;
}

describe('Registration Index Files', () => {
describe('tools/index.ts', () => {
it('should register all standard tools', async () => {
const { registerTools } = await import('../tools/index.js');
function expectToolAnnotations(config: any) {
expect(config.annotations).toEqual(
expect.objectContaining({
readOnlyHint: expect.any(Boolean),
destructiveHint: expect.any(Boolean),
idempotentHint: expect.any(Boolean),
openWorldHint: expect.any(Boolean),
})
);
}

describe("Registration Index Files", () => {
describe("tools/index.ts", () => {
it("should register all standard tools", async () => {
const { registerTools } = await import("../tools/index.js");
const mockServer = createMockServer();

registerTools(mockServer);
Expand All @@ -31,22 +42,33 @@ describe('Registration Index Files', () => {
const registeredTools = (mockServer.registerTool as any).mock.calls.map(
(call: any[]) => call[0]
);
expect(registeredTools).toContain('echo');
expect(registeredTools).toContain('get-sum');
expect(registeredTools).toContain('get-env');
expect(registeredTools).toContain('get-tiny-image');
expect(registeredTools).toContain('get-structured-content');
expect(registeredTools).toContain('get-annotated-message');
expect(registeredTools).toContain('trigger-long-running-operation');
expect(registeredTools).toContain('get-resource-links');
expect(registeredTools).toContain('get-resource-reference');
expect(registeredTools).toContain('gzip-file-as-resource');
expect(registeredTools).toContain('toggle-simulated-logging');
expect(registeredTools).toContain('toggle-subscriber-updates');
expect(registeredTools).toContain("echo");
expect(registeredTools).toContain("get-sum");
expect(registeredTools).toContain("get-env");
expect(registeredTools).toContain("get-tiny-image");
expect(registeredTools).toContain("get-structured-content");
expect(registeredTools).toContain("get-annotated-message");
expect(registeredTools).toContain("trigger-long-running-operation");
expect(registeredTools).toContain("get-resource-links");
expect(registeredTools).toContain("get-resource-reference");
expect(registeredTools).toContain("gzip-file-as-resource");
expect(registeredTools).toContain("toggle-simulated-logging");
expect(registeredTools).toContain("toggle-subscriber-updates");
});

it('should register conditional tools based on capabilities', async () => {
const { registerConditionalTools } = await import('../tools/index.js');
it("should register annotations for all standard tools", async () => {
const { registerTools } = await import("../tools/index.js");
const mockServer = createMockServer();

registerTools(mockServer);

for (const [, config] of (mockServer.registerTool as any).mock.calls) {
expectToolAnnotations(config);
}
});

it("should register conditional tools based on capabilities", async () => {
const { registerConditionalTools } = await import("../tools/index.js");

// Server with all capabilities including experimental tasks API
const mockServerWithCapabilities = {
Expand Down Expand Up @@ -75,17 +97,52 @@ describe('Registration Index Files', () => {
const registeredTools = (
mockServerWithCapabilities.registerTool as any
).mock.calls.map((call: any[]) => call[0]);
expect(registeredTools).toContain('get-roots-list');
expect(registeredTools).toContain('trigger-elicitation-request');
expect(registeredTools).toContain('trigger-url-elicitation');
expect(registeredTools).toContain('trigger-sampling-request');
expect(registeredTools).toContain("get-roots-list");
expect(registeredTools).toContain("trigger-elicitation-request");
expect(registeredTools).toContain("trigger-url-elicitation");
expect(registeredTools).toContain("trigger-sampling-request");

// Task-based tools are registered via experimental.tasks.registerToolTask
expect(mockServerWithCapabilities.experimental.tasks.registerToolTask).toHaveBeenCalled();
expect(
mockServerWithCapabilities.experimental.tasks.registerToolTask
).toHaveBeenCalled();
});

it("should register annotations for all conditional tools", async () => {
const { registerConditionalTools } = await import("../tools/index.js");

const mockServerWithCapabilities = {
registerTool: vi.fn(),
server: {
getClientCapabilities: vi.fn(() => ({
roots: {},
elicitation: { url: {} },
sampling: {},
})),
},
experimental: {
tasks: {
registerToolTask: vi.fn(),
},
},
} as unknown as McpServer;

registerConditionalTools(mockServerWithCapabilities);

for (const [, config] of (mockServerWithCapabilities.registerTool as any)
.mock.calls) {
expectToolAnnotations(config);
}

for (const [, config] of (
mockServerWithCapabilities.experimental.tasks.registerToolTask as any
).mock.calls) {
expectToolAnnotations(config);
}
});

it('should not register conditional tools when capabilities missing', async () => {
const { registerConditionalTools } = await import('../tools/index.js');
it("should not register conditional tools when capabilities missing", async () => {
const { registerConditionalTools } = await import("../tools/index.js");

const mockServerNoCapabilities = {
registerTool: vi.fn(),
Expand All @@ -106,49 +163,49 @@ describe('Registration Index Files', () => {
});
});

describe('prompts/index.ts', () => {
it('should register all prompts', async () => {
const { registerPrompts } = await import('../prompts/index.js');
describe("prompts/index.ts", () => {
it("should register all prompts", async () => {
const { registerPrompts } = await import("../prompts/index.js");
const mockServer = createMockServer();

registerPrompts(mockServer);

// Should register 4 prompts
expect(mockServer.registerPrompt).toHaveBeenCalledTimes(4);

const registeredPrompts = (mockServer.registerPrompt as any).mock.calls.map(
(call: any[]) => call[0]
);
expect(registeredPrompts).toContain('simple-prompt');
expect(registeredPrompts).toContain('args-prompt');
expect(registeredPrompts).toContain('completable-prompt');
expect(registeredPrompts).toContain('resource-prompt');
const registeredPrompts = (
mockServer.registerPrompt as any
).mock.calls.map((call: any[]) => call[0]);
expect(registeredPrompts).toContain("simple-prompt");
expect(registeredPrompts).toContain("args-prompt");
expect(registeredPrompts).toContain("completable-prompt");
expect(registeredPrompts).toContain("resource-prompt");
});
});

describe('resources/index.ts', () => {
it('should register resource templates', async () => {
const { registerResources } = await import('../resources/index.js');
describe("resources/index.ts", () => {
it("should register resource templates", async () => {
const { registerResources } = await import("../resources/index.js");
const mockServer = createMockServer();

registerResources(mockServer);

// Should register at least the 2 resource templates (text and blob) plus file resources
expect(mockServer.registerResource).toHaveBeenCalled();
const registeredResources = (mockServer.registerResource as any).mock.calls.map(
(call: any[]) => call[0]
);
expect(registeredResources).toContain('Dynamic Text Resource');
expect(registeredResources).toContain('Dynamic Blob Resource');
const registeredResources = (
mockServer.registerResource as any
).mock.calls.map((call: any[]) => call[0]);
expect(registeredResources).toContain("Dynamic Text Resource");
expect(registeredResources).toContain("Dynamic Blob Resource");
});

it('should read instructions from file', async () => {
const { readInstructions } = await import('../resources/index.js');
it("should read instructions from file", async () => {
const { readInstructions } = await import("../resources/index.js");

const instructions = readInstructions();

// Should return a string (either content or error message)
expect(typeof instructions).toBe('string');
expect(typeof instructions).toBe("string");
expect(instructions.length).toBeGreaterThan(0);
});
});
Expand Down
Loading