Skip to main content
Glama
MCP_TOOL_BEST_PRACTICES.md5.75 kB
# MCP Tool Handling Best Practices Analysis ## Current Implementation vs. Best Practices ### 🔍 **Your Current Approach** ```typescript // Your current method (older pattern) this.server.tool( "manage_distribution_lists", distributionListSchema, wrapToolHandler(async (args: DistributionListArgs) => { // Tool logic here }) ); ``` ### ✅ **Modern MCP Best Practice** ```typescript // Modern MCP pattern (from official servers) server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "manage_distribution_lists", description: "Manage distribution lists in M365", inputSchema: zodToJsonSchema(distributionListSchema) as ToolInput, }, // ... other tools ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; switch (name) { case "manage_distribution_lists": return await handleDistributionList(args); case "manage_security_groups": return await handleSecurityGroup(args); // ... other tools default: throw new Error(`Unknown tool: ${name}`); } }); ``` ## 📊 **Comparison with Official MCP Servers** ### **1. Filesystem Server Pattern** ```typescript server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: "read_file", description: "Read the complete contents of a file", inputSchema: zodToJsonSchema(ReadFileArgsSchema) as ToolInput, } ], })); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; // Handle tools in switch statement }); ``` ### **2. Git Server Pattern** ```python @server.list_tools() async def list_tools() -> list[Tool]: return [ Tool( name="git_status", description="Shows the working tree status", inputSchema=GitStatus.schema(), ) ] @server.call_tool() async def call_tool(name: str, arguments: dict) -> list[TextContent]: match name: case "git_status": return [TextContent(type="text", text=git_status(repo))] ``` ### **3. Time Server Pattern** ```python @server.list_tools() async def list_tools() -> list[Tool]: return [ Tool( name="get_current_time", description="Get current time in a specific timezone", inputSchema={ "type": "object", "properties": { "timezone": {"type": "string"} }, "required": ["timezone"], }, ) ] ``` ## 🚀 **Recommended Migration Strategy** ### **Step 1: Update Tool Registration** Replace your current `setupTools()` method with modern request handlers: ```typescript private setupTools(): void { // List all available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "manage_distribution_lists", description: "Manage distribution lists in Microsoft 365", inputSchema: zodToJsonSchema(distributionListSchema) as ToolInput, }, { name: "manage_security_groups", description: "Manage security groups in Microsoft 365", inputSchema: zodToJsonSchema(securityGroupSchema) as ToolInput, }, // ... all your other tools ], }; }); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case "manage_distribution_lists": return { content: [{ type: "text", text: await this.handleDistributionList(args) }] }; case "manage_security_groups": return { content: [{ type: "text", text: await this.handleSecurityGroup(args) }] }; // ... all your other tools default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true, }; } }); } ``` ### **Step 2: Update Response Format** Ensure your handlers return proper MCP response format: ```typescript // Current format (needs updating) return "Success message"; // Correct MCP format return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; ``` ### **Step 3: Add Proper Error Handling** ```typescript catch (error) { return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true, }; } ``` ## 🎯 **Key Benefits of Modern Approach** 1. **Better Error Handling** - Standardized error responses 2. **Improved Type Safety** - Better TypeScript integration 3. **Future Compatibility** - Aligns with latest MCP specifications 4. **Easier Debugging** - Clearer request/response flow 5. **Better Testing** - Request handlers are easier to unit test ## 📝 **Migration Checklist** - [ ] Replace `this.server.tool()` with `setRequestHandler()` - [ ] Update tool schemas to use `zodToJsonSchema()` - [ ] Modify response format to include `content` array - [ ] Add proper error handling with `isError: true` - [ ] Test all tools with MCP inspector - [ ] Update any tool wrapper functions ## 🔧 **Next Steps** 1. Start with one tool as a proof of concept 2. Test thoroughly with MCP inspector 3. Gradually migrate all tools 4. Update documentation and examples 5. Consider adding progress indicators for long-running operations This migration will make your M365 Core MCP server more maintainable, debuggable, and aligned with modern MCP best practices!

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/DynamicEndpoints/m365-core-mcp'

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