Skip to main content
Glama
larksuite

Feishu/Lark OpenAPI MCP

Official
by larksuite
init.test.ts8.07 kB
import { initMcpServerWithTransport, initOAPIMcpServer, initRecallMcpServer, } from '../../../src/mcp-server/shared/init'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; // 模拟依赖项 jest.mock('@modelcontextprotocol/sdk/server/mcp.js', () => ({ McpServer: jest.fn().mockImplementation(() => ({ connect: jest.fn().mockResolvedValue(undefined), tool: jest.fn().mockImplementation((name, description, schema, handler) => { handler(); }), })), })); // 模拟mcp-tool模块 jest.mock('../../../src/mcp-tool', () => { return { LarkMcpTool: jest.fn().mockImplementation(() => ({ updateUserAccessToken: jest.fn(), registerMcpServer: jest.fn(), })), defaultToolNames: ['default-tool-1', 'default-tool-2'], presetTools: { 'preset.default': ['default-tool-1', 'default-tool-2'], }, RecallTool: { name: 'RecallTool', description: 'RecallTool description', schema: jest.fn(), handler: jest.fn(), }, }; }); jest.mock('../../../src/mcp-server/transport', () => ({ initSSEServer: jest.fn().mockImplementation((getNewServer) => { getNewServer?.(); }), initStreamableServer: jest.fn().mockImplementation((getNewServer) => { getNewServer?.(); }), initStdioServer: jest.fn().mockImplementation((getNewServer) => { getNewServer?.(); }), })); // 保存原始的环境变量和console.error const originalEnv = process.env; const originalConsoleError = console.error; const originalProcessExit = process.exit; describe('initOAPIMcpServer', () => { beforeEach(() => { // 重置模拟 jest.clearAllMocks(); // 模拟环境变量 process.env = { ...originalEnv }; // 模拟 console.error console.error = jest.fn(); // 模拟 process.exit process.exit = jest.fn() as any; }); afterEach(() => { // 恢复原始环境变量和函数 process.env = originalEnv; console.error = originalConsoleError; process.exit = originalProcessExit; }); it('应该使用提供的凭证初始化服务器', () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', host: 'localhost', port: 3000, }; initOAPIMcpServer(options); expect(McpServer).toHaveBeenCalled(); // 从mcp-tool模块导入LarkMcpTool const { LarkMcpTool } = require('../../../src/mcp-tool'); expect(LarkMcpTool).toHaveBeenCalledWith( expect.objectContaining({ appId: 'test-app-id', appSecret: 'test-app-secret', }), undefined, ); }); it('如果提供了userAccessToken,应该调用updateUserAccessToken', () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', userAccessToken: 'test-user-access-token', host: 'localhost', port: 3000, }; const { larkClient } = initOAPIMcpServer(options); expect(larkClient.updateUserAccessToken).toHaveBeenCalledWith('test-user-access-token'); }); it('应该处理数组形式的tools参数', () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', tools: ['tool1', 'tool2'], host: 'localhost', port: 3000, }; initOAPIMcpServer(options); // 从mcp-tool模块导入LarkMcpTool const { LarkMcpTool } = require('../../../src/mcp-tool'); expect(LarkMcpTool).toHaveBeenCalledWith( expect.objectContaining({ toolsOptions: expect.objectContaining({ allowTools: ['tool1', 'tool2'], }), }), undefined, ); }); it('应该处理字符串形式的tools参数', () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', tools: ['tool1', 'tool2'], host: 'localhost', port: 3000, }; initOAPIMcpServer(options); // 从mcp-tool模块导入LarkMcpTool const { LarkMcpTool } = require('../../../src/mcp-tool'); expect(LarkMcpTool).toHaveBeenCalledWith( expect.objectContaining({ toolsOptions: expect.objectContaining({ allowTools: ['tool1', 'tool2'], }), }), undefined, ); }); it('如果凭证缺失,应该退出程序', () => { const options = { host: 'localhost', port: 3000, }; try { initOAPIMcpServer(options); } catch (error) { expect(error).toBeInstanceOf(Error); } expect(console.error).toHaveBeenCalled(); }); it('应该处理preset.default工具集', () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', tools: ['preset.default', 'extra-tool'], host: 'localhost', port: 3000, }; initOAPIMcpServer(options); // 从mcp-tool模块导入LarkMcpTool const { LarkMcpTool } = require('../../../src/mcp-tool'); // 验证LarkMcpTool被调用且包含toolsOptions expect(LarkMcpTool).toHaveBeenCalledWith( expect.objectContaining({ toolsOptions: expect.objectContaining({ allowTools: expect.any(Array), }), }), undefined, ); // 验证tools被正确传递 const calls = LarkMcpTool.mock.calls; const toolsOptions = calls[calls.length - 1][0].toolsOptions; expect(toolsOptions.allowTools).toEqual(expect.arrayContaining(['preset.default', 'extra-tool'])); }); }); describe('initRecallMcpServer', () => { it('应该正确初始化Recall MCP服务器', () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', host: 'localhost', port: 3000, mode: 'stdio' as const, }; initRecallMcpServer(options); expect(McpServer).toHaveBeenCalled(); }); }); describe('initMcpServerWithTransport', () => { it('应该正确初始化OAPI MCP服务器', () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', host: 'localhost', port: 3000, mode: 'stdio' as const, }; initMcpServerWithTransport('oapi', options); }); it('应该正确初始化OAPI SSE MCP服务器', () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', host: 'localhost', port: 3000, mode: 'sse' as const, }; initMcpServerWithTransport('oapi', options); }); it('应该正确初始化OAPI streamable MCP服务器', () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', host: 'localhost', port: 3000, mode: 'streamable' as const, }; initMcpServerWithTransport('oapi', options); }); it('应该正确初始化Recall MCP服务器', () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', host: 'localhost', port: 3000, mode: 'stdio' as const, }; initMcpServerWithTransport('recall', options); }); it('应该在userAccessToken和oauth同时存在时抛出错误', async () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', host: 'localhost', port: 3000, mode: 'stdio' as const, userAccessToken: 'test-token', oauth: true, }; await expect(initMcpServerWithTransport('oapi', options)).rejects.toThrow( 'userAccessToken and oauth cannot be used together', ); }); it('应该在无效的服务器类型时抛出错误', async () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', host: 'localhost', port: 3000, mode: 'stdio' as const, }; await expect(initMcpServerWithTransport('invalid' as any, options)).rejects.toThrow('Invalid server type'); }); it('应该在无效的模式时抛出错误', async () => { const options = { appId: 'test-app-id', appSecret: 'test-app-secret', host: 'localhost', port: 3000, mode: 'invalid' as any, }; await expect(initMcpServerWithTransport('oapi', options)).rejects.toThrow('Invalid mode:invalid'); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/larksuite/lark-openapi-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server