Google Workspace MCP Response Format Improvements - model-agnostic json envelope format for better compatibility across platforms
This commit is contained in:
338
README.md
338
README.md
@@ -2,172 +2,202 @@
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
A Model Context Protocol (MCP) server designed to integrate Google Workspace services (like Google Calendar) with AI assistants and other applications.
|
||||
A Model Context Protocol (MCP) server that integrates Google Workspace services with AI assistants and other applications.
|
||||
|
||||
## Overview
|
||||
## Quick Start
|
||||
|
||||
This server acts as a bridge, allowing applications that speak MCP to securely interact with your Google Workspace data via Google's APIs. It handles authentication using OAuth 2.0 and provides tools for accessing services like Google Calendar.
|
||||
1. **Prerequisites:**
|
||||
- Python 3.12+
|
||||
- [uv](https://github.com/astral-sh/uv) package installer
|
||||
- [Node.js & npm](https://nodejs.org/) (for MCP Inspector)
|
||||
- Google Cloud Project with OAuth 2.0 credentials
|
||||
|
||||
2. **Installation:**
|
||||
```bash
|
||||
git clone https://github.com/your-username/google_workspace_mcp.git
|
||||
cd google_workspace_mcp
|
||||
uv pip install -e .
|
||||
```
|
||||
|
||||
3. **Configuration:**
|
||||
- Create OAuth 2.0 credentials in [Google Cloud Console](https://console.cloud.google.com/)
|
||||
- Download credentials as `client_secret.json` to project root
|
||||
- Add the following redirect URIs to your OAuth client in Google Cloud Console:
|
||||
```
|
||||
http://localhost:8080/callback
|
||||
http://localhost:8081/callback
|
||||
http://localhost:8082/callback
|
||||
http://localhost:8083/callback
|
||||
http://localhost:8084/callback
|
||||
http://localhost:8085/callback
|
||||
http://localhost:8086/callback
|
||||
http://localhost:8087/callback
|
||||
http://localhost:8088/callback
|
||||
http://localhost:8089/callback
|
||||
http://localhost:8090/callback
|
||||
```
|
||||
This allows the server to use alternate ports if 8080 is unavailable.
|
||||
|
||||
4. **Environment Setup:**
|
||||
The server uses HTTP for localhost OAuth callbacks in development. Set this environment variable:
|
||||
```bash
|
||||
# Allow HTTP for localhost OAuth callbacks (development only)
|
||||
export OAUTHLIB_INSECURE_TRANSPORT=1
|
||||
```
|
||||
Without this, you'll get an "OAuth 2 MUST utilize HTTPS" error.
|
||||
|
||||
5. **Start the Server:**
|
||||
|
||||
Choose one of these methods to run the server:
|
||||
|
||||
```bash
|
||||
# Development mode with Inspector UI
|
||||
./with_inspector.sh
|
||||
|
||||
# OR Production mode (stdin/stdout)
|
||||
python main.py
|
||||
|
||||
# OR HTTP mode
|
||||
python -c "from core.server import server; server.run(transport='http', port=8000)"
|
||||
|
||||
# OR Using mcpo (recommended for API access)
|
||||
mcpo --config config.json
|
||||
```
|
||||
|
||||
**Important Ports:**
|
||||
- OAuth Callback: `8080-8090` (automatically selects first available)
|
||||
- HTTP Mode: `8000` (when running in HTTP mode)
|
||||
- mcpo API: `8000` (default when using mcpo)
|
||||
|
||||
6. **Connecting to the Server:**
|
||||
|
||||
The server supports multiple connection methods:
|
||||
|
||||
- **Using mcpo (Recommended for API Access)**:
|
||||
- Install mcpo: `pip install mcpo` or `uvx mcpo`
|
||||
- Run with provided config: `mcpo --config config.json`
|
||||
- Access API at: `http://localhost:8000/gworkspace`
|
||||
- OpenAPI docs at: `http://localhost:8000/gworkspace/docs`
|
||||
|
||||
- **Direct stdio (for MCP-compatible applications)**:
|
||||
- Start server with `python main.py`
|
||||
- Application manages server process and communicates via stdin/stdout
|
||||
- No network port needed - uses process I/O streams
|
||||
|
||||
- **HTTP Mode**:
|
||||
- Start server in HTTP mode
|
||||
- Send requests to `http://localhost:8000`
|
||||
- Useful for direct HTTP client access
|
||||
|
||||
7. **Integration with Open WebUI:**
|
||||
|
||||
To use this server with Open WebUI:
|
||||
|
||||
1. **Create mcpo Configuration:**
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"gworkspace": {
|
||||
"command": "uv",
|
||||
"args": [
|
||||
"--directory",
|
||||
"/path/to/google_workspace_mcp",
|
||||
"run",
|
||||
"main.py"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Save this as `config.json` in your project directory.
|
||||
|
||||
2. **Start the mcpo Server:**
|
||||
```bash
|
||||
mcpo --port 8000 --api-key "your-secret-key" --config config.json
|
||||
```
|
||||
This exposes your MCP server as an OpenAPI-compatible endpoint.
|
||||
|
||||
3. **Configure Open WebUI:**
|
||||
- Go to Open WebUI settings
|
||||
- Add a new API endpoint
|
||||
- Use URL: `http://localhost:8000/gworkspace`
|
||||
- Add your API key if configured
|
||||
- The Google Workspace tools will now be available in Open WebUI
|
||||
|
||||
8. **First-time Setup:**
|
||||
- Start the server using one of the methods above
|
||||
- First API call will trigger OAuth flow
|
||||
- Browser will open to Google login
|
||||
- The server will automatically select an available port (8080-8090) for the OAuth callback
|
||||
- After authorization, server stores credentials for future use
|
||||
|
||||
## Features
|
||||
|
||||
* **OAuth 2.0 Authentication:** Securely connects to Google APIs using user-authorized credentials.
|
||||
* **Google Calendar Integration:** Provides tools to list calendars and fetch events.
|
||||
* **MCP Standard Compliance:** Implements the Model Context Protocol for seamless integration.
|
||||
* **Stdio & HTTP Transport:** Supports both standard I/O (for direct integration) and HTTP (for development/testing).
|
||||
* **Extensible:** Designed to easily add support for more Google Workspace APIs.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you begin, ensure you have the following installed:
|
||||
|
||||
* **Python:** Version 3.12 or higher.
|
||||
* **uv:** A fast Python package installer and resolver. ([Installation Guide](https://github.com/astral-sh/uv))
|
||||
* **Node.js & npm/npx:** Required for using the MCP Inspector tool. ([Download Node.js](https://nodejs.org/))
|
||||
* **Google Cloud Project:** You'll need a project set up in the Google Cloud Console with the necessary APIs enabled and OAuth 2.0 credentials configured.
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
1. **Clone the Repository:**
|
||||
```bash
|
||||
git clone https://github.com/your-username/google_workspace_mcp.git # Replace with the actual repo URL if different
|
||||
cd google_workspace_mcp
|
||||
```
|
||||
|
||||
2. **Install Dependencies:**
|
||||
Use `uv` to install the project and its dependencies in editable mode. This allows you to make changes to the code and have them reflected immediately without reinstalling.
|
||||
```bash
|
||||
uv pip install -e .
|
||||
```
|
||||
*Note: Ensure your shell is configured to use the Python version managed by `uv` if you use a version manager like `pyenv`.*
|
||||
|
||||
3. **Configure Google Cloud & OAuth 2.0:**
|
||||
* Go to the [Google Cloud Console](https://console.cloud.google.com/).
|
||||
* Create a new project or select an existing one.
|
||||
* **Enable APIs:** Navigate to "APIs & Services" > "Library" and enable the "Google Calendar API" (and any other Google Workspace APIs you intend to use).
|
||||
* **Configure OAuth Consent Screen:** Go to "APIs & Services" > "OAuth consent screen". Configure it for your application type (likely "External" unless restricted to an organization). Add necessary scopes (e.g., `https://www.googleapis.com/auth/calendar.readonly`).
|
||||
* **Create OAuth Client ID:** Go to "APIs & Services" > "Credentials". Click "Create Credentials" > "OAuth client ID".
|
||||
* Select "Desktop app" as the Application type.
|
||||
* Give it a name (e.g., "MCP Desktop Client").
|
||||
* **Download Credentials:** After creation, download the client secrets JSON file. Rename it to `client_secret.json` and place it in the **root directory** of this project (`google_workspace_mcp/`).
|
||||
* **Important:** This file contains sensitive application credentials. **Do not commit `client_secret.json` to version control.** Add it to your `.gitignore` file if it's not already there.
|
||||
|
||||
4. **Understanding Token Storage:**
|
||||
* `client_secret.json`: Contains your *application's* credentials (client ID and secret) used to identify your application to Google.
|
||||
* `credentials.json` (or similar): When a *user* successfully authenticates via the OAuth flow, the server obtains access and refresh tokens specific to that user. These user tokens are typically stored locally (e.g., in a file named `credentials-<user_id_hash>.json` or similar within the project directory, managed by `auth/oauth_manager.py`).
|
||||
* **Security:** These user credential files are also sensitive and **must not be committed to version control.** Ensure patterns like `credentials-*.json` are included in your `.gitignore`.
|
||||
|
||||
## Running the Server
|
||||
|
||||
You can run the MCP server in several ways:
|
||||
|
||||
### 1. With MCP Inspector (Recommended for Development & Debugging)
|
||||
|
||||
The `with_inspector.sh` script simplifies running the server with the MCP Inspector, a graphical tool for testing MCP servers.
|
||||
|
||||
Set `OAUTHLIB_INSECURE_TRANSPORT=1` if testing on localhost without https for OAuth to work.
|
||||
|
||||
```bash
|
||||
./with_inspector.sh
|
||||
```
|
||||
|
||||
This script handles dependency checks and starts the server process, instructing the MCP Inspector (run via `npx`) to connect to it using `uv` for execution within the correct environment.
|
||||
|
||||
The Inspector UI allows you to:
|
||||
* Discover available tools and resources.
|
||||
* Execute tools with specific arguments.
|
||||
* View results and logs.
|
||||
* Test the authentication flow interactively.
|
||||
|
||||
### 2. Manual Start with Stdio (Production/Direct Integration)
|
||||
|
||||
To run the server using standard input/output, which is how most MCP client applications will connect:
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
The server will listen for MCP messages on stdin and send responses to stdout.
|
||||
|
||||
### 3. Manual Start with HTTP (Development/Testing)
|
||||
|
||||
To run the server with an HTTP transport layer, useful for testing with tools like `curl` or other HTTP clients:
|
||||
|
||||
```bash
|
||||
python -c "from core.server import server; server.run(transport='http', port=8000)"
|
||||
```
|
||||
|
||||
The server will be accessible at `http://localhost:8000`.
|
||||
|
||||
## Authentication Flow & Handling Localhost Redirects
|
||||
|
||||
This server uses OAuth 2.0's "Authorization Code Grant" flow for desktop applications.
|
||||
|
||||
1. **Initiation:** When a tool requiring authentication is called (e.g., `list_calendars`) or the `start_auth` tool is explicitly used, the server generates a unique Google authorization URL.
|
||||
2. **User Authorization:**
|
||||
* If using `start_auth` or running interactively where possible, the server attempts to automatically open this URL in the user's default web browser.
|
||||
* If automatic opening fails or isn't supported, the URL is provided to the client/user to open manually.
|
||||
3. **Google Consent:** The user logs into their Google account (if necessary) and grants the requested permissions (scopes) defined in your Google Cloud Console consent screen.
|
||||
4. **Redirection with Code:** After authorization, Google redirects the user's browser back to a specific `redirect_uri`.
|
||||
* **Handling `http://localhost`:** Google requires HTTPS for redirect URIs in production, but allows `http://localhost:<port>` for testing and desktop apps. This server handles this by:
|
||||
* Starting a temporary local HTTP server (see `auth/callback_server.py`) on a predefined port (e.g., 8080).
|
||||
* Constructing the authorization URL with `redirect_uri` set to `http://localhost:<port>/callback` (e.g., `http://localhost:8080/callback`).
|
||||
* **Crucial:** You **must** add this exact `http://localhost:<port>/callback` URI to the "Authorized redirect URIs" list in your OAuth client ID settings within the Google Cloud Console.
|
||||
* The temporary server listens for the callback, extracts the `authorization_code` and `state` parameters from the redirect request.
|
||||
5. **Token Exchange:** The server securely exchanges this `authorization_code` (along with the `client_secret.json` credentials) with Google for an `access_token` and a `refresh_token`.
|
||||
6. **Token Storage:** The obtained user tokens are stored locally (e.g., `credentials-<user_id_hash>.json`) for future use, managed by the `OAuthManager`. The refresh token allows the server to obtain new access tokens when the current one expires without requiring the user to re-authenticate constantly.
|
||||
7. **Completion:** The authentication process is complete, and the original tool request can now proceed using the stored credentials.
|
||||
|
||||
### Authentication Tools
|
||||
|
||||
* `start_auth(user_id)`: Initiates the automatic browser-based flow.
|
||||
* `auth_status(user_id)`: Checks if valid credentials exist for the user.
|
||||
* `complete_auth(user_id, authorization_code)`: Used for manual code entry if the automatic callback fails (requires manually copying the code from the browser's address bar after authorization).
|
||||
|
||||
## Debugging
|
||||
|
||||
* **MCP Inspector:** The primary tool for debugging. It shows request/response payloads, tool execution results, and errors. Use `./with_inspector.sh`.
|
||||
* **Python Logging:** Increase logging verbosity by adding the following near the start of `main.py` (or configure logging as needed):
|
||||
```python
|
||||
import logging
|
||||
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
|
||||
# You might want to specifically set levels for libraries like google-auth
|
||||
logging.getLogger('google_auth_oauthlib').setLevel(logging.INFO)
|
||||
logging.getLogger('googleapiclient').setLevel(logging.INFO)
|
||||
```
|
||||
* **Check `client_secret.json`:** Ensure it's present in the project root and correctly configured in Google Cloud Console.
|
||||
* **Check Redirect URIs:** Double-check that `http://localhost:<port>/callback` (e.g., `http://localhost:8080/callback`) is listed in your Google Cloud OAuth Client's authorized redirect URIs.
|
||||
* **Check Enabled APIs:** Verify the Google Calendar API (and others) are enabled in your Google Cloud project.
|
||||
- OAuth 2.0 authentication with Google APIs
|
||||
- Google Calendar integration (list calendars, fetch events)
|
||||
- Both stdio and HTTP transport support
|
||||
- Extensible design for adding more Google Workspace APIs
|
||||
- Dynamic port selection for OAuth callback
|
||||
|
||||
## Available Tools
|
||||
|
||||
### Authentication
|
||||
* `start_auth`: Starts automatic OAuth flow. Requires `user_id`.
|
||||
* `auth_status`: Checks current auth status. Requires `user_id`.
|
||||
* `complete_auth`: Completes flow with manual code. Requires `user_id`, `authorization_code`.
|
||||
* `oauth2callback` (Advanced): Low-level handler. Requires `code`, `state`. Optional `redirect_uri`.
|
||||
|
||||
### Calendar
|
||||
* `list_calendars`: Lists user's calendars. No parameters.
|
||||
* `get_events`: Gets events from a calendar. Requires `calendar_id`. Optional `time_min`, `time_max`, `max_results`.
|
||||
- `list_calendars`: Lists user's calendars
|
||||
- `get_events`: Gets calendar events (requires `calendar_id`, optional `time_min`, `time_max`, `max_results`)
|
||||
|
||||
### Authentication
|
||||
- `start_auth`: Starts OAuth flow (requires `user_id`)
|
||||
- `auth_status`: Checks auth status (requires `user_id`)
|
||||
- `complete_auth`: Manual code entry (requires `user_id`, `authorization_code`)
|
||||
|
||||
## Development
|
||||
|
||||
* **Project Structure:**
|
||||
* `core/`: Core MCP server logic.
|
||||
* `auth/`: Authentication handling (OAuth flow, token management, callback server).
|
||||
* `gcalendar/`: Google Calendar specific tools.
|
||||
* `main.py`: Main entry point for running the server.
|
||||
* `pyproject.toml`: Project metadata and dependencies.
|
||||
* `with_inspector.sh`: Helper script for running with MCP Inspector.
|
||||
* **Adding New Tools:**
|
||||
1. Create the tool function within an appropriate module (e.g., a new `gmail/gmail_tools.py`).
|
||||
2. Decorate it with `@server.tool("your_tool_name")` from `core.server`.
|
||||
3. Define parameters using type hints.
|
||||
4. Implement the logic, potentially using helper functions for API calls and authentication checks.
|
||||
5. Ensure the function is imported so the decorator registers it (e.g., in the module's `__init__.py` or `main.py`).
|
||||
6. Return results as a dictionary.
|
||||
### Project Structure
|
||||
```
|
||||
google_workspace_mcp/
|
||||
├── core/ # Core MCP server logic
|
||||
├── auth/ # OAuth handling
|
||||
├── gcalendar/ # Calendar tools
|
||||
├── main.py # Entry point
|
||||
├── config.json # mcpo configuration
|
||||
├── pyproject.toml # Dependencies
|
||||
└── with_inspector.sh
|
||||
```
|
||||
|
||||
### Port Handling
|
||||
The server implements intelligent port selection for OAuth callbacks:
|
||||
- Starts with port 8080 (default)
|
||||
- If port is in use, tries next port up to 8090
|
||||
- Logs port reassignment for transparency
|
||||
- Returns port information in authentication response
|
||||
- Automatically updates redirect URI for selected port
|
||||
- Requires OAUTHLIB_INSECURE_TRANSPORT=1 for HTTP callbacks
|
||||
|
||||
### Debugging
|
||||
- Use MCP Inspector UI (`./with_inspector.sh`)
|
||||
- Check `mcp_server_debug.log` for detailed logs
|
||||
- Monitor port assignment in logs when OAuth flow starts
|
||||
- Verify OAuth setup in Google Cloud Console
|
||||
- Ensure APIs are enabled in Google Cloud project
|
||||
- Check OAUTHLIB_INSECURE_TRANSPORT is set if you get HTTPS errors
|
||||
|
||||
### Adding New Tools
|
||||
1. Create tool function in appropriate module
|
||||
2. Decorate with `@server.tool("tool_name")`
|
||||
3. Define parameters using type hints
|
||||
4. Implement logic
|
||||
5. Import in `main.py`
|
||||
6. Return results as dictionary
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Store `client_secret.json` securely (never commit to VCS)
|
||||
- User tokens stored as `credentials-<user_id_hash>.json`
|
||||
- Add both files to `.gitignore`
|
||||
- OAuth callback uses HTTP on localhost only (requires OAUTHLIB_INSECURE_TRANSPORT=1)
|
||||
- Production deployments should use HTTPS
|
||||
- When using mcpo, secure your API key and use HTTPS in production
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
MIT License - see [LICENSE](LICENSE) file
|
||||
Reference in New Issue
Block a user