Skip to main content

Microsoft Teams MCP server with reusable OAuth2 authentication

Project description

Teams MCP Python

A Python implementation of Microsoft Teams MCP (Model Context Protocol) server with a reusable OAuth2 authentication library that can be used for building MCP servers for any OAuth2-based service.

Features

Reusable OAuth2 Library (mcp_oauth2)

  • Generic OAuth2 implementation that works with any OAuth2 provider
  • Built-in providers for Microsoft, Google, and generic OAuth2 services
  • Standardized MCP tools (is_authenticated and authorize) for OAuth2 flow
  • PKCE support for public clients (no client secret required)
  • Automatic token refresh handling
  • Easy to extend for new OAuth2 providers

Teams MCP Server

  • Full Microsoft Teams integration via Graph API
  • Chat management: List, create, and manage Teams chats
  • Messaging: Send and retrieve messages
  • Rate limiting with exponential backoff
  • Async/await throughout for performance

Installation

Using uvx (Recommended)

The easiest way to use this MCP server is with uvx, which allows you to run Python applications without manual installation:

# Run the Teams MCP server directly
uvx teams-mcp-python

# Or specify with full package name
uvx --from teams-mcp-python teams-mcp

Using pip

pip install teams-mcp-python

Quick Start

1. Azure AD Setup

First, register an app in Azure Portal:

  1. Go to Azure Portal > Azure Active Directory > App registrations
  2. Click "New registration"
  3. Set redirect URI to http://localhost:3000/auth/callback (Web platform)
  4. Grant these API permissions (Delegated):
    • Chat.ReadWrite
    • ChatMessage.Send
    • User.Read
    • offline_access

2. Configuration

Create a .env file in your project:

AZURE_CLIENT_ID=your-client-id
AZURE_TENANT_ID=your-tenant-id
AZURE_CLIENT_SECRET=your-client-secret  # Optional for public clients
AZURE_REDIRECT_URI=http://localhost:3000/auth/callback
DEBUG=true

3. Using with Claude Desktop

Add to your Claude Desktop configuration file:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json

Option 1: Using uvx (Recommended)

{
  "mcpServers": {
    "teams": {
      "command": "uvx",
      "args": ["teams-mcp-python"],
      "env": {
        "AZURE_CLIENT_ID": "your-client-id",
        "AZURE_TENANT_ID": "your-tenant-id",
        "AZURE_REDIRECT_URI": "http://localhost:3000/auth/callback"
      }
    }
  }
}

Option 2: Using Python

{
  "mcpServers": {
    "teams": {
      "command": "python",
      "args": ["-m", "teams_mcp"],
      "env": {
        "AZURE_CLIENT_ID": "your-client-id",
        "AZURE_TENANT_ID": "your-tenant-id",
        "AZURE_REDIRECT_URI": "http://localhost:3000/auth/callback"
      }
    }
  }
}

Option 3: If installed globally

{
  "mcpServers": {
    "teams": {
      "command": "teams-mcp",
      "env": {
        "AZURE_CLIENT_ID": "your-client-id",
        "AZURE_TENANT_ID": "your-tenant-id",
        "AZURE_REDIRECT_URI": "http://localhost:3000/auth/callback"
      }
    }
  }
}

4. Authentication Flow

When using the Teams MCP server in Claude:

  1. First use - Claude will provide an authentication URL
  2. Open the URL in your browser and sign in with your Microsoft account
  3. Copy the authorization code from the redirect URL
  4. Provide the code to Claude to complete authentication

Example conversation:

You: List my Teams chats

Claude: I'll help you list your Teams chats. First, I need to check your authentication status.

[Calls teams_is_authenticated]

You need to authenticate. Please visit this URL:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?...

After signing in, you'll be redirected to a URL with a code parameter. Please provide that code.

You: The URL shows: http://localhost:3000/auth/callback?code=ABC123...

Claude: [Calls teams_authorize with the code]

Great! I've successfully authenticated. Now let me list your chats.

[Calls teams_list_chats]

Here are your Teams chats:
1. Project Team - Group chat with 5 members
2. John Doe - One-on-one chat
...

Available Tools

The Teams MCP server provides these tools:

Authentication Tools

  • teams_is_authenticated - Check authentication status or get auth URL
  • teams_authorize - Complete OAuth2 flow with authorization code

Teams Tools

  • teams_list_chats - List all chats with optional filtering
  • teams_create_chat - Create new one-on-one or group chats
  • teams_send_message - Send messages to a chat
  • teams_get_messages - Retrieve messages from a chat

Creating Your Own OAuth2 MCP Server

The mcp_oauth2 library makes it easy to create MCP servers for any OAuth2 service:

from mcp_oauth2 import OAuth2Config, GenericOAuth2Provider, create_oauth2_tools
from mcp.server import Server

# Configure your OAuth2 provider
oauth_config = OAuth2Config(
    client_id="your-client-id",
    client_secret="your-client-secret",  # Optional for PKCE
    redirect_uri="http://localhost:3000/auth/callback",
    scopes=["scope1", "scope2"],
    authorization_endpoint="https://provider.com/oauth/authorize",
    token_endpoint="https://provider.com/oauth/token"
)

# Create provider instance
provider = GenericOAuth2Provider("myprovider", oauth_config)

# Get OAuth2 MCP tools
oauth_tools = create_oauth2_tools(provider)  # Creates is_authenticated and authorize tools

# Add to your MCP server
server = Server("my-mcp-server")

@server.list_tools()
async def list_tools():
    return oauth_tools + your_custom_tools

OAuth2 Authentication Flow

The library implements a standard OAuth2 flow with two MCP tools:

1. {provider}_is_authenticated

Check if tokens are valid or generate an auth URL:

// Request without tokens - generates auth URL
{
  "callback_url": "http://localhost:3000/auth/callback",
  "callback_state": { "custom": "data" }
}

// Response
{
  "authenticated": false,
  "auth_url": "https://provider.com/oauth/authorize?...",
  "state": "random-state-string"
}

// Request with tokens - validates them
{
  "tokens": {
    "access_token": "...",
    "refresh_token": "..."
  }
}

// Response
{
  "authenticated": true,
  "tokens": { /* refreshed tokens if needed */ }
}

2. {provider}_authorize

Exchange authorization code for tokens:

// Request
{
  "code": "auth-code-from-callback",
  "callback_url": "http://localhost:3000/auth/callback?code=...&state=...",
  "callback_state": { "custom": "data" }
}

// Response
{
  "success": true,
  "tokens": {
    "access_token": "...",
    "refresh_token": "...",
    "expires_in": 3600
  }
}

Built-in OAuth2 Providers

Microsoft Provider

from mcp_oauth2 import MicrosoftProvider, OAuth2Config

config = OAuth2Config(
    client_id="your-client-id",
    client_secret="your-secret",  # Optional
    scopes=["User.Read", "Mail.Read"]
)

provider = MicrosoftProvider(config, tenant_id="common")

Google Provider

from mcp_oauth2 import GoogleProvider, OAuth2Config

config = OAuth2Config(
    client_id="your-client-id",
    client_secret="your-secret",
    scopes=["https://www.googleapis.com/auth/drive.readonly"]
)

provider = GoogleProvider(config)

Generic Provider

from mcp_oauth2 import GenericOAuth2Provider, OAuth2Config

config = OAuth2Config(
    client_id="your-client-id",
    client_secret="your-secret",
    authorization_endpoint="https://example.com/oauth/authorize",
    token_endpoint="https://example.com/oauth/token",
    scopes=["read", "write"]
)

provider = GenericOAuth2Provider("custom", config)

Creating a Custom OAuth2 Provider

Extend the base OAuth2Provider class:

from mcp_oauth2 import OAuth2Provider, OAuth2Config, TokenResponse

class MyCustomProvider(OAuth2Provider):
    @property
    def name(self) -> str:
        return "mycustom"
    
    async def exchange_code(self, code: str, code_verifier: Optional[str] = None) -> TokenResponse:
        # Custom implementation
        pass
    
    async def refresh_token(self, refresh_token: str) -> TokenResponse:
        # Custom implementation
        pass

Examples

See the examples/ directory for complete implementations:

  • google_drive_mcp.py - Google Drive MCP server
  • github_mcp.py - GitHub MCP server

Using Example Servers with Claude Desktop

You can run the example servers using uvx as well:

For the Google Drive example:

{
  "mcpServers": {
    "google-drive": {
      "command": "uvx",
      "args": ["--from", "teams-mcp-python", "python", "-m", "examples.google_drive_mcp"],
      "env": {
        "GOOGLE_CLIENT_ID": "your-client-id",
        "GOOGLE_CLIENT_SECRET": "your-client-secret"
      }
    }
  }
}

Or with a local installation:

{
  "mcpServers": {
    "google-drive": {
      "command": "python",
      "args": ["/path/to/examples/google_drive_mcp.py"],
      "env": {
        "GOOGLE_CLIENT_ID": "your-client-id",
        "GOOGLE_CLIENT_SECRET": "your-client-secret"
      }
    }
  }
}

For the GitHub example:

{
  "mcpServers": {
    "github": {
      "command": "uvx",
      "args": ["--from", "teams-mcp-python", "python", "-m", "examples.github_mcp"],
      "env": {
        "GITHUB_CLIENT_ID": "your-client-id",
        "GITHUB_CLIENT_SECRET": "your-client-secret"
      }
    }
  }
}

Architecture

OAuth2 Library Structure

mcp_oauth2/
├── base.py          # Base classes and interfaces
├── tools.py         # MCP tool creation
└── providers/       # OAuth2 provider implementations
    ├── generic.py   # Generic OAuth2 provider
    ├── microsoft.py # Microsoft-specific provider
    └── google.py    # Google-specific provider

Teams MCP Structure

teams_mcp/
├── server.py        # Main MCP server
├── config.py        # Configuration
├── api/            # Teams API client
│   ├── client.py   # Graph API wrapper
│   └── rate_limiter.py
└── tools/          # Teams-specific MCP tools
    ├── list_chats.py
    ├── create_chat.py
    ├── send_message.py
    └── get_messages.py

Development

Setup

# Clone the repository
git clone https://github.com/shmaxi/teams-mcp-python.git
cd teams-mcp-python

# Install in development mode
pip install -e ".[dev]"

Testing

# Run tests
pytest

# With coverage
pytest --cov=src

# Type checking
mypy src

Code Quality

# Format code
black src tests

# Lint
ruff src tests

Publishing

To publish a new version to PyPI:

# Build the package
python -m build

# Upload to PyPI (requires PyPI credentials)
python -m twine upload dist/*

After publishing, the package will be available via:

  • pip install teams-mcp-python
  • uvx teams-mcp-python (for direct execution without installation)

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

teams_mcp_python-0.2.1.tar.gz (21.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

teams_mcp_python-0.2.1-py3-none-any.whl (25.3 kB view details)

Uploaded Python 3

File details

Details for the file teams_mcp_python-0.2.1.tar.gz.

File metadata

  • Download URL: teams_mcp_python-0.2.1.tar.gz
  • Upload date:
  • Size: 21.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.5

File hashes

Hashes for teams_mcp_python-0.2.1.tar.gz
Algorithm Hash digest
SHA256 0bca70ca559649d1ae0f0c4babcdf1799184d7d61a0a78013baf9974bd8b99a3
MD5 7db010f792de88fda56d307322bfd693
BLAKE2b-256 80e11ed607e297fb72d5a1014f892d45531158fa723458fd4ea132a9c1e35c1c

See more details on using hashes here.

File details

Details for the file teams_mcp_python-0.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for teams_mcp_python-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 426b7ec26be5aae5d009a762f995a507deb6a6f8eb4ec5e01255fe374dce405f
MD5 a433faf22eb0ed12c2a9c2914ab936fc
BLAKE2b-256 53f3ef29bbfe5a0d78580fb6a6486144689fa5b960720f6ae381fe2c48834f3c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page