Skip to main content
Glama

Notion MCP Server V2

by ankitmalik84
HOW_MCP_TOOLS_WORK.md9.21 kB
# How MCP Tools Work: Complete Explanation ## 🎯 **Understanding the Magic** MCP (Model Context Protocol) tools work through a sophisticated flow that connects your chatbot to external services. Here's the complete breakdown: ## 🔧 **1. Tool Definition (MCP Server Side)** ### The Decorators Explained ```python # In src/utils/notion_mcp_server.py @self.server.list_tools() # ← This is the REGISTRATION decorator async def list_tools() -> List[Tool]: """ This function is called when a client asks: "What tools are available on this MCP server?" """ return [ Tool( name="search_notion_pages", # ← Tool identifier description="Search for pages...", # ← What the tool does inputSchema={ # ← Parameters it accepts "type": "object", "properties": { "query": {"type": "string", "description": "Search query"} }, "required": ["query"] } ) ] @self.server.call_tool() # ← This is the EXECUTION decorator async def call_tool(name: str, arguments: dict) -> List[TextContent]: """ This function is called when a client says: "Execute tool X with arguments Y" """ if name == "search_notion_pages": return await self.search_pages(arguments) # ← Route to implementation # ... handle other tools ``` ### What the Decorators Do 1. **`@self.server.list_tools()`** - Registers the function as a "tool discovery" handler - When MCP client asks "what tools are available?", this function is called - Returns a list of available tools with their schemas 2. **`@self.server.call_tool()`** - Registers the function as a "tool execution" handler - When MCP client says "execute tool X", this function is called - Routes the call to the appropriate implementation method ## 🔄 **2. Tool Registration (Chatbot Side)** ### Making Tools Available to the LLM ```python # In src/utils/chatbot_agentic_v3.py # The chatbot creates function schemas for OpenAI API self.agent_functions = [ # ... existing functions { "name": "search_notion_pages", # ← Must match MCP server tool name "description": "Search for pages in Notion workspace", "parameters": { # ← OpenAI function calling schema "type": "object", "properties": { "query": {"type": "string", "description": "Search query text"} }, "required": ["query"] } } ] ``` ### Why This Duplication? - **MCP Server**: Defines what tools exist and how they work - **Chatbot**: Tells the LLM what functions it can call - **Two different protocols**: MCP for tool execution, OpenAI for function calling ## 🎬 **3. Real-World Execution Flow** ### Example: User asks "Search for pages about 'project planning'" ```python # Step 1: User message user_message = "Search for pages about 'project planning' in my Notion workspace" # Step 2: LLM sees available functions response = self.client.chat.completions.create( model=self.chat_model, messages=[{"role": "user", "content": user_message}], functions=self.agent_functions, # ← LLM sees search_notion_pages function_call="auto" ) # Step 3: LLM decides to call search_notion_pages if response.choices[0].message.function_call: function_name = "search_notion_pages" function_args = {"query": "project planning", "page_size": 10} # Step 4: Route to MCP client self.execute_function_call(function_name, function_args) ``` ## 📡 **4. MCP Client-Server Communication** ### The Communication Bridge ```python # In src/utils/mcp_client_manager.py def call_tool_sync(self, server_name: str, tool_name: str, arguments: dict): """ This is the bridge between your chatbot and MCP server """ # Convert sync call to async for MCP future = self.executor.submit( self._run_async_call, server_name, tool_name, arguments ) return future.result(timeout=30) async def _call_tool_async(self, server_name: str, tool_name: str, arguments: dict): """ This actually calls the MCP server """ client = self.clients[server_name] # ← MCP client connected to server # This triggers the MCP server's @call_tool() decorated function result = await client.call_tool(tool_name, arguments) return result ``` ## 🔍 **5. MCP Server Execution** ### What Happens on the Server ```python # When client.call_tool() is called, this function is triggered: @self.server.call_tool() # ← This decorator caught the call async def call_tool(name: str, arguments: dict) -> List[TextContent]: if name == "search_notion_pages": return await self.search_pages(arguments) # ← Route to implementation # The actual implementation async def search_pages(self, arguments: dict) -> List[TextContent]: query = arguments.get("query", "") # Make actual Notion API call results = self.notion.search(query=query, page_size=10) # Format results for MCP return [TextContent( type="text", text=f"Found {len(results['results'])} pages matching '{query}'" )] ``` ## 🎯 **Complete Flow Diagram** ``` 1. User: "Search for pages about 'project planning'" ↓ 2. Chatbot.chat() → OpenAI API with functions=agent_functions ↓ 3. LLM: "I'll call search_notion_pages with query='project planning'" ↓ 4. execute_function_call("search_notion_pages", {"query": "project planning"}) ↓ 5. mcp_client_manager.call_tool_sync("notion", "search_notion_pages", {...}) ↓ 6. MCP Client → MCP Server (stdio/network communication) ↓ 7. MCP Server @call_tool() decorator catches the call ↓ 8. Routes to search_pages({"query": "project planning"}) ↓ 9. search_pages() → Notion API call ↓ 10. Notion API → Returns search results ↓ 11. search_pages() → Formats as TextContent ↓ 12. MCP Server → Returns TextContent to MCP Client ↓ 13. MCP Client → Returns result to chatbot ↓ 14. Chatbot → Returns result to LLM ↓ 15. LLM → Formats friendly response for user ↓ 16. User sees: "I found 5 pages about project planning: ..." ``` ## 🧠 **Key Insights** ### Why This Architecture? 1. **Separation of Concerns** - MCP Server: Handles external API integration - Chatbot: Handles conversation flow - LLM: Handles natural language understanding 2. **Reusability** - One MCP server can serve multiple chatbots - One chatbot can connect to multiple MCP servers - Tools are standardized across the ecosystem 3. **Scalability** - MCP servers can run locally or remotely - Multiple instances can be deployed - Load balancing is possible ### Why Not Direct Integration? ```python # You COULD do this (direct integration): def search_notion_pages(self, query: str): return self.notion.search(query=query) # But MCP provides: # ✅ Standardized protocol # ✅ Language-agnostic servers # ✅ Remote deployment capability # ✅ Tool discovery # ✅ Better error handling # ✅ Ecosystem compatibility ``` ## 🔧 **Tool Definition Best Practices** ### 1. Clear Tool Names ```python # Good "search_notion_pages" "create_notion_page" "get_user_profile" # Bad "search" "create" "get" ``` ### 2. Detailed Descriptions ```python # Good "Search for pages in Notion workspace using text query" # Bad "Search pages" ``` ### 3. Comprehensive Schemas ```python # Good { "type": "object", "properties": { "query": { "type": "string", "description": "Text to search for in page titles and content" }, "page_size": { "type": "integer", "description": "Number of results to return (1-100)", "minimum": 1, "maximum": 100, "default": 10 } }, "required": ["query"] } # Bad { "type": "object", "properties": { "query": {"type": "string"} } } ``` ## 🚀 **Testing Your Understanding** Run the explanation example: ```bash python mcp_tools_explanation.py ``` This will show you exactly how the decorators and flow work with a simple example. ## 📋 **Summary** MCP tools work through: 1. **Definition**: `@server.list_tools()` and `@server.call_tool()` decorators 2. **Registration**: Adding function schemas to `agent_functions` 3. **Discovery**: LLM sees available functions 4. **Selection**: LLM chooses appropriate function 5. **Routing**: Chatbot routes to MCP client 6. **Communication**: MCP client calls MCP server 7. **Execution**: MCP server executes the tool 8. **Response**: Results flow back to user The "magic" is in the decorators - they create the bridge between the MCP protocol and your actual tool implementations! ## 🎯 **Next Steps** 1. **Try the test**: `python test_notion_mcp.py` 2. **Examine the logs**: See the flow in action 3. **Add new tools**: Follow the same pattern 4. **Scale up**: Deploy MCP servers remotely The MCP architecture enables powerful, scalable AI integrations while maintaining clean separation of concerns!

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/ankitmalik84/Agentic_Longterm_Memory'

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