wiki/appdoc/mcp_outlook_sharepoint_analysis.md
2025-12-03 23:02:58 +01:00

11 KiB

MCP for Outlook/SharePoint: Can MCP Servers Replace Your Custom Actions?

Your Question

Can you use MCP server functionality to access Outlook emails and SharePoint data, eliminating the need for custom methodOutlook and methodSharepoint actions?

Answer: Yes, but with important considerations


How MCP Accesses Outlook/SharePoint

MCP Server Architecture

Your System
  ↓ (MCP Client)
MCP Server (OutlookMCPServer / Microsoft 365 MCP Server)
  ↓ (Microsoft Graph API + OAuth)
Microsoft 365 (Outlook, SharePoint, OneDrive, Teams)

Authentication Flow

MCP servers use the same authentication as your current methods:

  1. OAuth 2.0 Flow:

    • User grants permissions via Azure AD
    • Access token obtained (same as your connectionReference)
    • Token used for Microsoft Graph API calls
  2. Permissions Required:

    • Outlook: Mail.ReadWrite, Mail.Send, Mail.ReadWrite.Shared
    • SharePoint: Sites.ReadWrite.All, Files.ReadWrite.All

Key Point: MCP servers need the same OAuth setup as your current methods.


Current Implementation vs MCP Server

Your Current Implementation

methodOutlook.py:

class MethodOutlook(MethodBase):
    def _getMicrosoftConnection(self, connectionReference: str):
        # Get connection from your system
        userConnection = self.services.chat.getUserConnectionFromConnectionReference(connectionReference)
        
        # Get fresh token
        token = self.services.chat.getFreshConnectionToken(userConnection.id)
        
        return {
            "accessToken": token.tokenAccess,
            "refreshToken": token.tokenRefresh,
            "scopes": ["Mail.ReadWrite", "Mail.Send", ...]
        }
    
    @action
    async def readEmails(self, parameters: Dict) -> ActionResult:
        connection = self._getMicrosoftConnection(parameters["connectionReference"])
        # Direct Microsoft Graph API call
        response = requests.get(
            f"https://graph.microsoft.com/v1.0/me/messages",
            headers={"Authorization": f"Bearer {connection['accessToken']}"}
        )
        # Process and return ActionResult

Characteristics:

  • Uses your existing connectionReference system
  • Integrates with your UserConnection management
  • Returns ActionResult (compatible with your workflow)
  • Custom actions tailored to your needs

MCP Server Implementation

OutlookMCPServer (external MCP server):

# MCP Server exposes tools like:
tools = [
    {
        "name": "outlook.readEmails",
        "description": "Read emails from Outlook",
        "inputSchema": {
            "type": "object",
            "properties": {
                "folder": {"type": "string"},
                "limit": {"type": "integer"}
            }
        }
    },
    {
        "name": "outlook.sendEmail",
        "description": "Send email via Outlook",
        "inputSchema": {...}
    }
]

# MCP Server handles authentication internally
# Uses Microsoft Graph API (same as your methods)

Characteristics:

  • Standardized MCP protocol
  • Pre-built tools (no custom code needed)
  • ⚠️ Needs separate OAuth setup (not integrated with your connectionReference)
  • ⚠️ Returns MCP format (needs conversion to ActionResult)

Comparison: Custom Actions vs MCP Servers

Scenario: Read Outlook Emails

Option A: Your Custom Action (Current)

# In your workflow
result = await executeAction("outlook.readEmails", {
    "connectionReference": "conn_msft_123",  # Your connection system
    "folder": "Inbox",
    "limit": 10
})

# Returns: ActionResult with ActionDocument[]
# Integrated with your connection management
# Works seamlessly with your workflow

Pros:

  • Integrated with your connectionReference system
  • Uses your existing UserConnection management
  • Returns ActionResult (native format)
  • Customizable to your specific needs
  • Token refresh handled by your system

Cons:

  • You maintain the code
  • Need to implement all actions yourself

Option B: MCP Server (Alternative)

# Connect to external MCP server
outlookMcpClient = ExternalMcpClient("http://outlook-mcp-server:8080")

# Call MCP tool
mcpResult = await outlookMcpClient.callTool("outlook.readEmails", {
    "folder": "Inbox",
    "limit": 10
    # Note: No connectionReference - MCP server handles auth internally
})

# Convert MCP result to ActionResult
result = mcpResultToActionResult(mcpResult)

Pros:

  • No custom code to maintain
  • Pre-built tools (readEmails, sendEmail, etc.)
  • Standardized protocol
  • Can use multiple MCP servers (Outlook, SharePoint, etc.)

Cons:

  • Separate OAuth setup (not integrated with your connectionReference)
  • Different authentication flow (MCP server manages tokens)
  • Needs conversion from MCP format to ActionResult
  • Less control over implementation
  • May not match your exact requirements

Critical Question: Authentication

How Does MCP Server Access Your Data?

MCP servers need authentication, just like your current methods:

  1. Option 1: MCP Server Manages OAuth

    • User authenticates with MCP server
    • MCP server stores tokens
    • Problem: Separate from your connectionReference system
    • Problem: User needs to authenticate twice (your system + MCP server)
  2. Option 2: Pass Tokens to MCP Server

    • Your system gets token (via connectionReference)
    • Pass token to MCP server
    • Problem: MCP protocol doesn't standardize token passing
    • Problem: Security concern (passing tokens)
  3. Option 3: Custom MCP Server Using Your Connection System

    • Create MCP server wrapper around your methods
    • Uses your connectionReference system
    • This is what the original proposal suggested (but adds overhead)

Practical Assessment

Can You Replace Your Actions with MCP Servers?

Short Answer: Technically yes, but not recommended for these reasons:

Problem 1: Authentication Duplication

Your System:

# User authenticates once
userConnection = createUserConnection("msft", oauthFlow)
# Stored in your system, reusable across all actions

MCP Server:

# User needs to authenticate again
# MCP server manages its own tokens
# Not integrated with your connectionReference system

Impact: Users authenticate twice, tokens managed separately


Problem 2: Integration Complexity

Your Current Flow:

Workflow → ActionExecutor → methodOutlook.readEmails()
  ↓
Uses connectionReference → Gets token → Calls Graph API
  ↓
Returns ActionResult (native format)

MCP Flow:

Workflow → ActionExecutor → MCP Client → MCP Server
  ↓
MCP Server manages auth → Calls Graph API
  ↓
Returns MCP format → Convert to ActionResult

Impact: More layers, more complexity, more points of failure


Problem 3: Loss of Control

Your Custom Actions:

  • Full control over implementation
  • Customize to your exact needs
  • Integrate with your workflow seamlessly
  • Use your connection management

MCP Servers:

  • Limited to what MCP server provides
  • Can't customize easily
  • Need to adapt to MCP format
  • Separate authentication system

When MCP Servers Make Sense

Use Case 1: External Tools You Don't Want to Maintain

Example: Slack, GitHub, Postgres MCP servers

# Use external MCP server for Slack (you don't have Slack actions)
slackMcpClient = ExternalMcpClient("http://slack-mcp-server:8080")
result = await slackMcpClient.callTool("slack.sendMessage", {...})

Value: No need to build/maintain Slack integration


Use Case 2: Standard Tools with Standard Authentication

Example: Public APIs with API keys (not OAuth)

# Use MCP server for public API (simple API key auth)
weatherMcpClient = ExternalMcpClient("http://weather-mcp-server:8080")
result = await weatherMcpClient.callTool("weather.getForecast", {...})

Value: Simple integration, no complex auth


Don't Use MCP Servers When:

  1. You already have working custom actions (like Outlook/SharePoint)
  2. Authentication is complex (OAuth with your connection system)
  3. You need tight integration with your workflow
  4. You need customization beyond what MCP server provides

Recommendation

For Outlook/SharePoint: Keep Your Custom Actions

Why:

  1. Already working: Your methodOutlook and methodSharepoint work well
  2. Integrated authentication: Uses your connectionReference system
  3. Native format: Returns ActionResult directly
  4. Customizable: Tailored to your specific needs
  5. No duplication: Single authentication flow

Don't replace with MCP servers because:

  • Would require separate OAuth setup
  • Would need format conversion
  • Would lose integration with your connection system
  • Adds complexity without clear benefit

Use MCP Servers For:

  1. New external tools you don't want to build (Slack, GitHub, etc.)
  2. Simple integrations with standard APIs
  3. Tools with simple authentication (API keys, not OAuth)

Alternative: Hybrid Approach

Use MCP Servers for New Tools, Keep Custom Actions for Existing

class ActionExecutor:
    async def executeAction(self, methodName: str, actionName: str, parameters: Dict):
        # Check if it's a custom action (Outlook, SharePoint, AI)
        if methodName in ["outlook", "sharepoint", "ai"]:
            # Use your custom actions (existing code)
            return await self._executeCustomAction(methodName, actionName, parameters)
        
        # Check if it's an external MCP tool
        elif methodName in self.mcpClients:
            # Use MCP server
            mcpClient = self.mcpClients[methodName]
            toolName = f"{methodName}.{actionName}"
            mcpResult = await mcpClient.callTool(toolName, parameters)
            return self._mcpResultToActionResult(mcpResult)
        
        else:
            raise ValueError(f"Unknown method: {methodName}")

Benefits:

  • Keep existing Outlook/SharePoint actions (working, integrated)
  • Use MCP servers for new external tools (Slack, GitHub, etc.)
  • Best of both worlds

Conclusion

Can you use MCP servers for Outlook/SharePoint?

  • Technically yes - MCP servers exist and can access Outlook/SharePoint
  • Practically no - Your custom actions are better integrated

How does MCP access your data?

  • MCP servers use Microsoft Graph API + OAuth (same as your methods)
  • But they need separate OAuth setup (not integrated with your connectionReference)

Recommendation:

  • Keep your custom Outlook/SharePoint actions (they're better integrated)
  • Use MCP servers for new external tools (Slack, GitHub, etc.)
  • Hybrid approach: Custom actions for existing, MCP for new

The real value of MCP: Easy integration of external tools you don't want to build, not replacing working custom actions.