Google Chat Webhook MCP Server
---
# Google Chat Webhook MCP Server
[](https://github.com/ice3x2/google-chat-webhook-mcp/actions)
[](https://www.npmjs.com/package/google-chat-webhook-mcp)
[](https://opensource.org/licenses/MIT)
An MCP (Model Context Protocol) server that sends messages to Google Chat via webhooks. Automatically converts Markdown to Google Chat Cards V2 format with image validation, structured logging, and fallback handling.
## Features
- π **MCP Protocol Support**: Integrates with Claude Code, GitHub Copilot, and other MCP clients
- οΏ½ **MCP Protocol Support**: Integrates with Claude Code, GitHub Copilot, and other MCP clients
- οΏ½π **Markdown β Cards V2 Auto-conversion**: Supports headers, lists, code blocks, tables, images, and more
- πΌοΈ **Image URL Validation**: Validates with HEAD requests (HTTP status, Content-Type, size)
- π **Auto Fallback**: Automatically falls back to text when Cards V2 fails
- π **Structured Logging**: JSON format with 30-day retention
- β
**Test Automation**: Snapshot tests, integration tests, CI/CD pipeline
## Installation
### npm (Recommended)
```bash
npm install -g google-chat-webhook-mcp
```
### From Source (Development)
```bash
git clone https://github.com/ice3x2/google-chat-webhook-mcp.git
cd google-chat-webhook-mcp
npm install
npm run build
```
## Google Chat Webhook Setup
Before configuring the MCP server, create a Google Chat Webhook URL:
1. Open your Google Chat space
2. Menu β "Apps & integrations" β "Manage webhooks"
3. Click "Add webhook"
4. Enter a name and **copy the URL**
5. Use it in the configuration below
## MCP Client Configuration
### 1. Claude Code
#### Config File Location
- **Windows**: `%USERPROFILE%\.claude.json`
- **macOS/Linux**: `~/.claude.json`
**Note**: Claude Desktop uses different paths:
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Linux: `~/.config/Claude/claude_desktop_config.json`
#### npm Installation
```json
{
"mcpServers": {
"google-chat": {
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx"
}
}
}
}
```
#### Source Installation
```json
{
"mcpServers": {
"google-chat": {
"command": "node",
"args": ["C:\\path\\to\\google-chat-webhook-mcp\\dist\\index.js"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx"
}
}
}
}
```
**β οΈ Note**: Use `\\` or `/` for Windows paths (e.g., `C:/path/to/...`)
#### Configuration Scopes
Claude Code supports three configuration scopes:
1. **User Scope** (Global): `~/.claude.json` - Available across all projects
2. **Project Scope** (Shared): `.mcp.json` in project root - Version-controlled, team-shared
3. **Local Scope** (Private): Project-specific, personal settings
**Priority**: Local > Project > User
#### Project-Scoped Configuration (.mcp.json)
For team-shared MCP servers, create `.mcp.json` in your project root:
```json
{
"mcpServers": {
"google-chat": {
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "${GOOGLE_CHAT_WEBHOOK_URL}"
}
}
}
}
```
**Benefits**:
- β
Version-controlled with Git
- β
Team-shared configuration
- β
Environment variable support: `${VAR}` or `${VAR:-default}`
- β
Project-specific MCP servers
**Environment Variables**: Each team member can set their own webhook URL:
```bash
# Linux/macOS
export GOOGLE_CHAT_WEBHOOK_URL="https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx"
# Windows (PowerShell)
$env:GOOGLE_CHAT_WEBHOOK_URL="https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx"
```
#### How to Apply
**User-scoped configuration** (~/.claude.json):
1. Edit `~/.claude.json` (or `%USERPROFILE%\.claude.json` on Windows)
2. Save the file
3. Restart Claude Code if already running
**Project-scoped configuration** (.mcp.json):
1. Create `.mcp.json` in project root
2. Set environment variables for sensitive data
3. Commit `.mcp.json` to version control
4. Use commands like "Send a message to Google Chat"
### 2. GitHub Copilot (VS Code)
[VS Code GitHub Copilot](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode) supports MCP through **agent mode**. Configure MCP servers in workspace or user settings.
#### Configuration File Locations
Choose one of the following:
- **User Settings**: `~/.vscode/settings.json` or `%APPDATA%\Code\User\settings.json` (Windows)
- **Workspace Settings**: `.vscode/settings.json` in your project root
- **Claude Code Config** (Auto-import): Copy from `~/.claude.json`
#### Configuration (mcp.json format)
Add to `settings.json`:
```json
{
"github.copilot.chat.mcp.servers": {
"google-chat": {
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx"
}
}
}
}
```
#### Features
- **Agent Mode Integration**: MCP tools available in agent workflow
- **Per-Session Tool Selection**: Choose which tools to enable per session
- **STDIO & SSE Support**: Both transport types supported
- **Debugging**: Restart commands and output logging built-in
#### Using with Agent Mode
1. Open GitHub Copilot Chat in VS Code
2. Enable agent mode (if not already enabled)
3. Start a conversation - Copilot will automatically access MCP tools
4. Tools require approval before execution
**Example:**
```
@workspace Send a deployment summary to Google Chat
```
**π Note**: GitHub Copilot's MCP support includes agent mode, allowing sophisticated workflows. Make sure you're using the latest VS Code and GitHub Copilot extension.
### 3. Other MCP Clients
Works with any MCP-compatible client:
```json
{
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "your-webhook-url"
}
}
```
## Usage
### MCP Tools (3 Tools)
Available tools in Claude Code or other MCP clients:
#### 1. `send_google_chat_text`
Send simple text messages
**Example (Claude Code):**
```
Send "Hello from Claude!" to Google Chat
```
**Parameters:**
```json
{
"text": "Hello, Google Chat!"
}
```
#### 2. `send_google_chat_cards_v2`
Send Cards V2 format directly (advanced users)
**Parameters:**
```json
{
"text": "Card Message",
"cardsV2": [
{
"cardId": "unique-card",
"card": {
"header": { "title": "Card Title" },
"sections": [
{
"widgets": [
{ "textParagraph": { "text": "Card content" } }
]
}
]
}
}
]
}
```
#### 3. `send_google_chat_markdown` β **Recommended**
Convert Markdown to Cards V2 and send
**Example (Claude Code):**
```
Send this markdown to Google Chat:
# Project Update
- Task 1: β
Completed
- Task 2: π§ In Progress
**Deadline**: Tomorrow
```
**Parameters:**
```json
{
"markdown": "# Title\n\n**Bold** and *italic*\n\n- List item 1\n- List item 2\n\n```python\nprint('Hello')\n```",
"cardTitle": "Markdown Message",
"fallbackToText": true
}
```
**Options:**
- `cardTitle`: Title shown at the top of the card (optional)
- `fallbackToText`: Auto-send as text on conversion failure (default: false)
### Claude Code Usage Example
After setup, Claude will automatically use MCP tools when you chat naturally:
**π€ User:**
> "Send a project status update to Google Chat. Show 3 completed tasks and 2 in-progress tasks as a markdown list."
**π€ Claude:**
> (Automatically calls `send_google_chat_markdown` tool)
>
> I've sent the message to Google Chat. The project status has been updated.
### Supported Markdown Syntax
Markdown written in Claude or MCP clients is automatically converted to Google Chat Cards V2.
| Syntax | Markdown Example | Google Chat Rendering |
|--------|------------------|----------------------|
| **Headers** | `# H1`, `## H2`, `### H3` | Bold with size differences |
| **Bold** | `**bold**` or `__bold__` | **bold** |
| **Italic** | `*italic*` or `_italic_` | *italic* |
| **Inline Code** | `` `code` `` | `code` (monospace) |
| **Code Block** | ` ```python\ncode\n``` ` | Syntax-highlighted box |
| **Ordered List** | `1. First\n2. Second` | 1. First<br>2. Second |
| **Unordered List** | `- Item` or `* Item` | β’ Item |
| **Nested List** | ` - nested` (2-space indent) | γβ’ nested (Em space) |
| **Table** | `\| A \| B \|\n\|--\|--\|` | Monospace table |
| **Image** | `` | Image widget (after validation) |
| **Link** | `[text](https://...)` | Clickable link |
| **Horizontal Rule** | `---` or `***` | Divider |
| **Blockquote** | `> quote` | Indented + gray text |
**Example Markdown:**
```markdown
# Project Deployment Complete π
## Key Changes
- **Performance**: API response 30% faster
- **Bug Fix**: Login error resolved
- New feature added
## Deployment Status
| Environment | Status | Version |
|-------------|--------|---------|
| Production | β
| v2.1.0 |
| Staging | β
| v2.1.0 |
## Next Steps
1. Monitor for 24 hours
2. Collect user feedback
3. Plan next sprint
Code example:
```python
def deploy():
print("Deploying v2.1.0...")
return True
```
See [documentation](https://docs.example.com) for details.
```
**Result:** Headers, lists, tables, and code blocks are all visually distinguished in Google Chat.
## Environment Variables
### Required
| Variable | Description | Example |
|----------|-------------|---------|
| `GOOGLE_CHAT_WEBHOOK_URL` | Google Chat Webhook URL | `https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx` |
### Optional (Logging)
| Variable | Description | Default | Values |
|----------|-------------|---------|--------|
| `LOG_LEVEL` | Log level | `INFO` | `DEBUG`, `INFO`, `WARN`, `ERROR` |
| `LOG_DIR` | Log directory path | `./logs` | Absolute/relative path |
| `LOG_RETENTION_DAYS` | Days to keep logs | `30` | Number (days) |
| `LOG_ENABLE_CONSOLE` | Enable console output | `true` | `true`, `false` |
### Configuration Methods
#### Claude Code (~/.claude.json)
```json
{
"mcpServers": {
"google-chat": {
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx",
"LOG_LEVEL": "INFO",
"LOG_RETENTION_DAYS": "30"
}
}
}
}
```
#### .env File (Development)
Create `.env` in project root:
```env
GOOGLE_CHAT_WEBHOOK_URL=https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx
LOG_LEVEL=INFO
LOG_DIR=./logs
LOG_RETENTION_DAYS=30
LOG_ENABLE_CONSOLE=true
```
## Limitations
### Google Chat API Constraints
| Item | Limit | Workaround |
|------|-------|------------|
| **Image Protocol** | HTTPS only | HTTP URLs replaced with text links |
| **Image Size** | Max 5MB | Show as link on validation failure |
| **Image Auth** | Public URLs only | No access if auth required |
| **Content-Type** | `image/*` only | HTML pages rejected |
| **Markdown Support** | Limited | Unsupported syntax approximated |
### Markdown Conversion Limitations
**β
Fully Supported:**
- Headers (H1~H6)
- Bold, italic, inline code
- Ordered/unordered lists (up to 3 levels)
- Code blocks (syntax highlighting)
- Tables (monospace)
- Links, images
**β οΈ Partial Support:**
- Complex nesting β Simplified
- HTML tags β Converted to text
- Blockquotes β Shown as indents
**β Not Supported:**
- Footnotes
- Definition lists
- Math formulas (LaTeX)
- Task checkboxes (`- [ ]`, `- [x]`)
- Emoji shortcodes (`:smile:`, Unicode emojis work)
## FAQ
### Q: Images not displaying
**A**: Image validation failure causes:
1. **HTTPS only** (HTTP not supported)
2. **File size**: Must be under 5MB
3. **Public access**: Must be accessible without auth
4. **Content-Type**: Response header must be `image/*`
**Debug:**
```bash
cat logs/app-YYYY-MM-DD.log | grep "image_validation_failed"
```
### Q: Cards V2 conversion fails
**A**: Use `fallbackToText` option:
```json
{
"markdown": "...",
"fallbackToText": true
}
```
Check logs for details:
```bash
cat logs/errors-YYYY-MM-DD.log
```
### Q: Too many log files
**A**: Adjust with environment variables:
```json
{
"env": {
"LOG_LEVEL": "WARN",
"LOG_RETENTION_DAYS": "7"
}
}
```
### Q: Multiple Google Chat spaces
**A**: Register separate MCP server instances:
```json
{
"mcpServers": {
"google-chat-team-a": {
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "https://chat.googleapis.com/.../team-a/..."
}
},
"google-chat-team-b": {
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "https://chat.googleapis.com/.../team-b/..."
}
}
}
}
```
## License
MIT License - [LICENSE](LICENSE)
## Links
- [Model Context Protocol](https://github.com/modelcontextprotocol)
- [Claude Code](https://claude.ai/desktop)
- [Google Chat API](https://developers.google.com/chat)
---
Korean:
[](https://github.com/ice3x2/google-chat-webhook-mcp/actions)
[](https://www.npmjs.com/package/google-chat-webhook-mcp)
[](https://opensource.org/licenses/MIT)
MCP (Model Context Protocol) μλ²λ‘ Google Chat μΉν
μ ν΅ν΄ λ©μμ§λ₯Ό μ μ‘ν©λλ€. Markdownμ Google Chat Cards V2 νμμΌλ‘ μλ λ³ννλ©°, μ΄λ―Έμ§ κ²μ¦, μλ λ‘κΉ
, ν΄λ°± μ²λ¦¬λ₯Ό μ§μν©λλ€.
## μ£Όμ κΈ°λ₯
- π **MCP νλ‘ν μ½ μ§μ**: Claude Code, GitHub Copilot λ±κ³Ό ν΅ν©
- π **Markdown β Cards V2 μλ λ³ν**: ν€λ, 리μ€νΈ, μ½λλΈλ‘, ν, μ΄λ―Έμ§ λ± μ§μ
- πΌοΈ **μ΄λ―Έμ§ URL κ²μ¦**: HEAD μμ²μΌλ‘ μ ν¨μ± νμΈ (HTTP μν, Content-Type, ν¬κΈ°)
- π **μλ ν΄λ°±**: Cards V2 μ€ν¨ μ ν
μ€νΈλ‘ μλ μ ν
- π **ꡬ쑰νλ λ‘κΉ
**: JSON νμ, 30μΌ μλ 보κ΄
- β
**ν
μ€νΈ μλν**: μ€λ
μ· ν
μ€νΈ, ν΅ν© ν
μ€νΈ, CI/CD νμ΄νλΌμΈ
## μ€μΉ
### npm μ€μΉ (κΆμ₯)
```bash
npm install -g google-chat-webhook-mcp
```
### μμ€ μ€μΉ (κ°λ°μ©)
```bash
git clone https://github.com/ice3x2/google-chat-webhook-mcp.git
cd google-chat-webhook-mcp
npm install
npm run build
```
## Google Chat Webhook URL μμ±
MCP μλ² μ€μ μ μ λ¨Όμ Google Chat Webhook URLμ μμ±ν΄μΌ ν©λλ€:
1. Google Chat μ€νμ΄μ€ μ΄κΈ°
2. μλ¨ λ©λ΄ β "μ± λ° ν΅ν©" β "Webhook κ΄λ¦¬"
3. "Webhook μΆκ°" ν΄λ¦
4. μ΄λ¦ μ
λ ₯ ν **URL 볡μ¬**
5. μλ μ€μ μμ μ¬μ©
## MCP ν΄λΌμ΄μΈνΈ μ€μ
### 1. Claude Code
#### μ€μ νμΌ μμΉ
- **Windows**: `%USERPROFILE%\.claude.json`
- **macOS/Linux**: `~/.claude.json`
**μ°Έκ³ **: Claude Desktopμ λ€λ₯Έ κ²½λ‘λ₯Ό μ¬μ©ν©λλ€:
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Linux: `~/.config/Claude/claude_desktop_config.json`
#### npm μ€μΉ μ
```json
{
"mcpServers": {
"google-chat": {
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx"
}
}
}
}
```
#### μμ€ μ€μΉ μ
```json
{
"mcpServers": {
"google-chat": {
"command": "node",
"args": ["C:\\path\\to\\google-chat-webhook-mcp\\dist\\index.js"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx"
}
}
}
}
```
**β οΈ μ£Όμ**: Windows κ²½λ‘λ `\\` λλ `/` μ¬μ© (μ: `C:/path/to/...`)
#### μ€μ μ€μ½ν
Claude Codeλ 3κ°μ§ μ€μ μ€μ½νλ₯Ό μ§μν©λλ€:
1. **User Scope** (μ μ): `~/.claude.json` - λͺ¨λ νλ‘μ νΈμμ μ¬μ© κ°λ₯
2. **Project Scope** (곡μ ): νλ‘μ νΈ λ£¨νΈμ `.mcp.json` - λ²μ κ΄λ¦¬, ν 곡μ κ°λ₯
3. **Local Scope** (κ°μΈ): νλ‘μ νΈλ³ κ°μΈ μ€μ
**μ°μ μμ**: Local > Project > User
#### νλ‘μ νΈ μμ€ μ€μ (.mcp.json)
νκ³Ό 곡μ ν MCP μλ² μ€μ μ νλ‘μ νΈ λ£¨νΈμ `.mcp.json` νμΌμ μμ±νμΈμ:
```json
{
"mcpServers": {
"google-chat": {
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "${GOOGLE_CHAT_WEBHOOK_URL}"
}
}
}
}
```
**μ₯μ **:
- β
GitμΌλ‘ λ²μ κ΄λ¦¬ κ°λ₯
- β
νκ³Ό μ€μ 곡μ
- β
νκ²½ λ³μ μ§μ: `${VAR}` λλ `${VAR:-κΈ°λ³Έκ°}`
- β
νλ‘μ νΈλ³ MCP μλ² μ€μ
**νκ²½ λ³μ μ€μ **: κ° νμμ΄ μμ μ Webhook URLμ μ€μ ν μ μμ΅λλ€:
```bash
# Linux/macOS
export GOOGLE_CHAT_WEBHOOK_URL="https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx"
# Windows (PowerShell)
$env:GOOGLE_CHAT_WEBHOOK_URL="https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx"
```
#### μ μ© λ°©λ²
**User μμ€ μ€μ ** (~/.claude.json):
1. `~/.claude.json` νΈμ§ (Windowsλ `%USERPROFILE%\.claude.json`)
2. νμΌ μ μ₯
3. Claude Codeκ° μ€ν μ€μ΄λ©΄ μ¬μμ
**Project μμ€ μ€μ ** (.mcp.json):
1. νλ‘μ νΈ λ£¨νΈμ `.mcp.json` μμ±
2. λ―Όκ°ν λ°μ΄ν°λ νκ²½ λ³μλ‘ μ€μ
3. `.mcp.json`μ λ²μ κ΄λ¦¬ μμ€ν
μ 컀λ°
4. "Send a message to Google Chat" κ°μ λͺ
λ Ή μ¬μ©
### 2. GitHub Copilot (VS Code)
[VS Code GitHub Copilot](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode)μ **μμ΄μ νΈ λͺ¨λ**λ₯Ό ν΅ν΄ MCPλ₯Ό μ§μν©λλ€. μν¬μ€νμ΄μ€ λλ μ¬μ©μ μ€μ μμ MCP μλ²λ₯Ό ꡬμ±ν μ μμ΅λλ€.
#### μ€μ νμΌ μμΉ
λ€μ μ€ νλλ₯Ό μ ν:
- **μ¬μ©μ μ€μ **: `~/.vscode/settings.json` λλ `%APPDATA%\Code\User\settings.json` (Windows)
- **μν¬μ€νμ΄μ€ μ€μ **: νλ‘μ νΈ λ£¨νΈμ `.vscode/settings.json`
- **Claude Code μ€μ ** (μλ κ°μ Έμ€κΈ°): `~/.claude.json`μμ 볡μ¬
#### μ€μ λ°©λ² (mcp.json νμ)
`settings.json`μ μΆκ°:
```json
{
"github.copilot.chat.mcp.servers": {
"google-chat": {
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx"
}
}
}
}
```
#### κΈ°λ₯
- **μμ΄μ νΈ λͺ¨λ ν΅ν©**: μμ΄μ νΈ μν¬νλ‘μ°μμ MCP λꡬ μ¬μ© κ°λ₯
- **μΈμ
λ³ λꡬ μ ν**: μΈμ
λ§λ€ νμ±νν λꡬ μ ν κ°λ₯
- **STDIO & SSE μ§μ**: λ μ μ‘ λ°©μ λͺ¨λ μ§μ
- **λλ²κΉ
**: μ¬μμ λͺ
λ Ή λ° μΆλ ₯ λ‘κΉ
λ΄μ₯
#### μμ΄μ νΈ λͺ¨λμμ μ¬μ©νκΈ°
1. VS Codeμμ GitHub Copilot μ±ν
μ΄κΈ°
2. μμ΄μ νΈ λͺ¨λ νμ±ν (κΈ°λ³Έ νμ±νλ κ²½μ°λ μμ)
3. λν μμ - Copilotμ΄ μλμΌλ‘ MCP λꡬμ μ κ·Ό
4. λꡬ μ€ν μ μΉμΈ νμ
**μμ:**
```
@workspace λ°°ν¬ μμ½μ Google Chatμ μ μ‘ν΄μ€
```
**π μ°Έκ³ **: GitHub Copilotμ MCP μ§μμ μμ΄μ νΈ λͺ¨λλ₯Ό ν¬ν¨νμ¬ μ κ΅ν μν¬νλ‘μ°λ₯Ό μ§μν©λλ€. μ΅μ λ²μ μ VS Codeμ GitHub Copilot νμ₯μ μ¬μ©νμΈμ.
### 3. κΈ°ν MCP ν΄λΌμ΄μΈνΈ
MCP νλ‘ν μ½μ μ§μνλ λͺ¨λ ν΄λΌμ΄μΈνΈμμ μ¬μ© κ°λ₯ν©λλ€:
```json
{
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "your-webhook-url"
}
}
1. Google Chat μ€νμ΄μ€ μ΄κΈ°
2. μλ¨ λ©λ΄ β "μ± λ° ν΅ν©" β "Webhook κ΄λ¦¬"
3. "Webhook μΆκ°" ν΄λ¦
4. μ΄λ¦ μ
λ ₯ ν URL 볡μ¬
5. νκ²½ λ³μμ μ€μ
## μ¬μ©λ²
### MCP λꡬ (3κ°μ§)
Claude Codeμ΄λ λ€λ₯Έ MCP ν΄λΌμ΄μΈνΈμμ λ€μ λꡬλ€μ μ¬μ©ν μ μμ΅λλ€:
#### 1. `send_google_chat_text`
κ°λ¨ν ν
μ€νΈ λ©μμ§ μ μ‘
**μμ (Claude Code):**
```
Send "Hello from Claude!" to Google Chat
```
**νλΌλ―Έν°:**
```json
{
"text": "μλ
νμΈμ, Google Chat!"
}
```
#### 2. `send_google_chat_cards_v2`
Cards V2 νμμΌλ‘ μ§μ μ μ‘ (κ³ κΈ μ¬μ©μμ©)
**νλΌλ―Έν°:**
```json
{
"text": "Card Message",
"cardsV2": [
{
"cardId": "unique-card",
"card": {
"header": { "title": "Card Title" },
"sections": [
{
"widgets": [
{ "textParagraph": { "text": "Card content" } }
]
}
]
}
}
]
}
```
#### 3. `send_google_chat_markdown` β **μΆμ²**
Markdownμ Cards V2λ‘ μλ λ³ννμ¬ μ μ‘
**μμ (Claude Code):**
```
Send this markdown to Google Chat:
# Project Update
- Task 1: β
Completed
- Task 2: π§ In Progress
**Deadline**: Tomorrow
```
**νλΌλ―Έν°:**
```json
{
"markdown": "# μ λͺ©\n\n**κ΅΅μ κΈμ¨**μ *κΈ°μΈμ*\n\n- 리μ€νΈ νλͺ© 1\n- 리μ€νΈ νλͺ© 2\n\n```python\nprint('Hello')\n```",
"cardTitle": "λ§ν¬λ€μ΄ λ©μμ§",
"fallbackToText": true
}
```
**μ΅μ
:**
- `cardTitle`: μΉ΄λ μλ¨μ νμλ μ λͺ© (μ ν)
- `fallbackToText`: λ³ν μ€ν¨ μ ν
μ€νΈλ‘ μλ μ μ‘ (κΈ°λ³Έκ°: false)
### Claude Code μ¬μ© μμ
μ€μ μλ£ ν Claudeμ μμ°μ΄λ‘ λννλ©΄ μλμΌλ‘ MCP λꡬλ₯Ό μ¬μ©ν©λλ€:
**π€ μ¬μ©μ:**
> "Google Chatμ νλ‘μ νΈ μν μ
λ°μ΄νΈλ₯Ό 보λ΄μ€. μλ£λ μμ
3κ°, μ§ν μ€μΈ μμ
2κ°λ₯Ό λ§ν¬λ€μ΄ 리μ€νΈλ‘ μμ±ν΄μ."
**π€ Claude:**
> (μλμΌλ‘ `send_google_chat_markdown` λꡬ νΈμΆ)
>
> Google Chatμ λ©μμ§λ₯Ό μ μ‘νμ΅λλ€. νλ‘μ νΈ μνκ° μ
λ°μ΄νΈλμμ΅λλ€.
**π€ μ¬μ©μ:**
> "λ°©κΈ λ³΄λΈ λ©μμ§μ μ½λ μμ λ μΆκ°ν΄μ€."
**π€ Claude:**
> (λ€μ MarkdownμΌλ‘ λ©μμ§ μμ± λ° μ μ‘)
### μ§μνλ Markdown λ¬Έλ²
Claudeλ MCP ν΄λΌμ΄μΈνΈμμ MarkdownμΌλ‘ λ©μμ§λ₯Ό μμ±νλ©΄ μλμΌλ‘ Google Chat Cards V2λ‘ λ³νλ©λλ€.
| λ¬Έλ² | Markdown μμ | Google Chat λ λλ§ |
|------|---------------|-------------------|
| **ν€λ** | `# H1`, `## H2`, `### H3` | κ΅΅μ κΈμ¨ + ν¬κΈ° μ°¨λ± |
| **κ΅΅κ²** | `**bold**` λλ `__bold__` | **bold** |
| **κΈ°μΈμ** | `*italic*` λλ `_italic_` | *italic* |
| **μΈλΌμΈ μ½λ** | `` `code` `` | `code` (κ³ μ ν ν°νΈ) |
| **μ½λλΈλ‘** | ` ```python\ncode\n``` ` | ꡬ문 κ°μ‘° λ°μ€ |
| **μμ 리μ€νΈ** | `1. First\n2. Second` | 1. First<br>2. Second |
| **λΉμμ 리μ€νΈ** | `- Item` λλ `* Item` | β’ Item |
| **μ€μ²© 리μ€νΈ** | ` - nested` (2μΉΈ λ€μ¬μ°κΈ°) | γβ’ nested (Em space) |
| **ν** | `\| A \| B \|\n\|--\|--\|` | κ³ μ ν ν°νΈ ν |
| **μ΄λ―Έμ§** | `` | μ΄λ―Έμ§ μμ ― (URL κ²μ¦ ν) |
| **λ§ν¬** | `[ν
μ€νΈ](https://...)` | ν΄λ¦ κ°λ₯ν λ§ν¬ |
| **μνμ ** | `---` λλ `***` | ꡬλΆμ |
| **μΈμ©λ¬Έ** | `> quote` | λ€μ¬μ°κΈ° + νμ ν
μ€νΈ |
**μμ Markdown:**
```markdown
# νλ‘μ νΈ λ°°ν¬ μλ£ π
## μ£Όμ λ³κ²½μ¬ν
- **μ±λ₯ κ°μ **: API μλ΅ μλ 30% ν₯μ
- **λ²κ·Έ μμ **: λ‘κ·ΈμΈ μ€λ₯ ν΄κ²°
- μ κΈ°λ₯ μΆκ°
## λ°°ν¬ μν
| νκ²½ | μν | λ²μ |
|------|------|------|
| Production | β
| v2.1.0 |
| Staging | β
| v2.1.0 |
## λ€μ λ¨κ³
1. λͺ¨λν°λ§ 24μκ°
2. μ¬μ©μ νΌλλ°± μμ§
3. λ€μ μ€νλ¦°νΈ κ³ν
μ½λ μμ :
```python
def deploy():
print("Deploying v2.1.0...")
return True
```
μμΈν λ΄μ©μ [λ¬Έμ](https://docs.example.com)λ₯Ό μ°Έμ‘°νμΈμ.
```
**λ³ν κ²°κ³Ό:** Google Chatμμ ν€λ, 리μ€νΈ, ν, μ½λλΈλ‘μ΄ λͺ¨λ μκ°μ μΌλ‘ ꡬλΆλμ΄ νμλ©λλ€.
## νκ²½ λ³μ
### νμ νκ²½ λ³μ
| λ³μλͺ
| μ€λͺ
| μμ |
|--------|------|------|
| `GOOGLE_CHAT_WEBHOOK_URL` | Google Chat Webhook URL | `https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx` |
### μ ν νκ²½ λ³μ (λ‘κΉ
)
| λ³μλͺ
| μ€λͺ
| κΈ°λ³Έκ° | νμ©κ° |
|--------|------|--------|--------|
| `LOG_LEVEL` | λ‘κ·Έ λ 벨 | `INFO` | `DEBUG`, `INFO`, `WARN`, `ERROR` |
| `LOG_DIR` | λ‘κ·Έ λλ ν 리 κ²½λ‘ | `./logs` | μ λ/μλ κ²½λ‘ |
| `LOG_RETENTION_DAYS` | λ‘κ·Έ λ³΄κ΄ μΌμ | `30` | μ«μ (μΌ) |
| `LOG_ENABLE_CONSOLE` | μ½μ μΆλ ₯ μ¬λΆ | `true` | `true`, `false` |
### μ€μ λ°©λ²
#### Claude Code (~/.claude.json)
```json
{
"mcpServers": {
"google-chat": {
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx",
"LOG_LEVEL": "INFO",
"LOG_RETENTION_DAYS": "30"
}
}
}
}
```
#### .env νμΌ (κ°λ°μ©)
νλ‘μ νΈ λ£¨νΈμ `.env` νμΌ μμ±:
```env
GOOGLE_CHAT_WEBHOOK_URL=https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx
LOG_LEVEL=INFO
LOG_DIR=./logs
LOG_RETENTION_DAYS=30
LOG_ENABLE_CONSOLE=true
```
#### μμ€ν
νκ²½ λ³μ
**Windows (PowerShell):**
```powershell
$env:GOOGLE_CHAT_WEBHOOK_URL="https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx"
```
**Linux/macOS (Bash/Zsh):**
```bash
export GOOGLE_CHAT_WEBHOOK_URL="https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx&token=xxx"
```
## κ°λ°
```bash
# μμ‘΄μ± μ€μΉ
npm install
# λΉλ
npm run build
# κ°λ° λͺ¨λ (TypeScript μ§μ μ€ν)
npm run dev
# Lint κ²μ¬
npm run lint
# Lint μλ μμ
npm run lint:fix
# ν
μ€νΈ
npm run test:snapshot # μ€λ
μ· ν
μ€νΈ (12κ°)
npm run test:logging # λ‘κΉ
μμ€ν
ν
μ€νΈ
npm run test:integration # ν΅ν© ν
μ€νΈ (μΉν
νμ)
npm test # μ 체 ν
μ€νΈ
```
## μν€ν
μ²
```
src/
βββ index.ts # μ§μ
μ
βββ server.ts # MCP μλ² μ€μ
βββ tools/ # MCP λꡬ
β βββ sendTextMessage.ts # ν
μ€νΈ μ μ‘
β βββ sendCardsV2Message.ts # Cards V2 μ μ‘
β βββ sendMarkdownMessage.ts # Markdown μ μ‘ (λ©μΈ)
β βββ markdownToCards.ts # Markdown β Cards V2 λ³ν
βββ utils/ # μ νΈλ¦¬ν°
β βββ imageValidator.ts # μ΄λ―Έμ§ URL κ²μ¦
β βββ cardsV2Validator.ts # Cards V2 μ€ν€λ§ κ²μ¦
β βββ logger.ts # λ‘κΉ
μμ€ν
β βββ logCleaner.ts # λ‘κ·Έ μ 리
βββ types/ # νμ
μ μ
βββ markdown.ts
βββ googleChat.ts
βββ log.ts
```
## λ‘κΉ
### λ‘κ·Έ νμΌ κ΅¬μ‘°
```
logs/
βββ app-2025-10-29.log # μΌλ³ λ‘κ·Έ (λͺ¨λ λ 벨)
βββ errors-2025-10-29.log # μλ¬ μ μ© λ‘κ·Έ
βββ ... # 30μΌ μλ μμ
```
### λ‘κ·Έ ν¬λ§· (JSON)
```json
{
"timestamp": "2025-10-29T12:34:56.789Z",
"level": "INFO",
"module": "sendMarkdownMessage",
"event": "message_sent",
"messageId": "spaces/xxx/messages/yyy",
"elapsed": 123,
"usedFallback": false,
"cardTitle": "Test Card"
}
```
### λ‘κ·Έ μ΄λ²€νΈ
- `message_sent`: λ©μμ§ μ μ‘ μ±κ³΅
- `fallback_used`: ν΄λ°± μ¬μ© (Cards V2 β Text)
- `image_validation_failed`: μ΄λ―Έμ§ κ²μ¦ μ€ν¨
- `send_failed`: μ μ‘ μ€ν¨
- `validation_failed`: κ²μ¦ μ€ν¨
### λ‘κ·Έ μ 리
- μλ² μμ μ μλ μ 리 (30μΌ μ΄μ λ‘κ·Έ μμ )
- 24μκ°λ§λ€ μλ μ€ν
- νκ²½ λ³μ `LOG_RETENTION_DAYS`λ‘ μ€μ κ°λ₯
## μ νμ¬ν
### Google Chat API μ μ½μ¬ν
| νλͺ© | μ ν | λμ λ°©λ² |
|------|------|-----------|
| **μ΄λ―Έμ§ νλ‘ν μ½** | HTTPSλ§ μ§μ | HTTP URLμ ν
μ€νΈ λ§ν¬λ‘ λ체 |
| **μ΄λ―Έμ§ ν¬κΈ°** | μ΅λ 5MB | κ²μ¦ μ€ν¨ μ λ§ν¬λ‘ νμ |
| **μ΄λ―Έμ§ μΈμ¦** | κ³΅κ° URLλ§ κ°λ₯ | μΈμ¦ νμ μ μ κ·Ό λΆκ° |
| **Content-Type** | `image/*`λ§ νμ© | HTML νμ΄μ§ λ±μ κ±°λΆ |
| **Markdown μ§μ** | μ νμ | λ―Έμ§μ λ¬Έλ²μ κ·Όμ¬μΉλ‘ λ³ν |
### Markdown λ³ν μ μ½μ¬ν
**β
μμ μ§μ:**
- ν€λ (H1~H6)
- κ΅΅κ², κΈ°μΈμ, μΈλΌμΈ μ½λ
- μμ/λΉμμ 리μ€νΈ (μ΅λ 3λ¨κ³ μ€μ²©)
- μ½λλΈλ‘ (ꡬ문 κ°μ‘°)
- ν (κ³ μ ν ν°νΈ)
- λ§ν¬, μ΄λ―Έμ§
**β οΈ λΆλΆ μ§μ:**
- 볡μ‘ν μ€μ²© ꡬ쑰 β λ¨μνλ¨
- HTML νκ·Έ β ν
μ€νΈλ‘ λ³ν
- μΈμ©λ¬Έ β λ€μ¬μ°κΈ°λ‘ νν
**β λ―Έμ§μ:**
- κ°μ£Ό (footnotes)
- μ μ 리μ€νΈ (definition lists)
- μν μμ (LaTeX)
- μμ
체ν¬λ°μ€ (`- [ ]`, `- [x]`)
- Emoji λ¨μΆμ½λ (`:smile:` λ±, μ λμ½λ μ΄λͺ¨μ§λ κ°λ₯)
### μ±λ₯ λ° μ ν
- **μ΄λ―Έμ§ κ²μ¦ νμμμ**: 5μ΄
- **Webhook μμ² νμμμ**: 5μ΄
- **λ‘κ·Έ νμΌ ν¬κΈ°**: 무μ ν (30μΌ μλ μμ )
- **λμ μμ²**: μ ν μμ (Google Chat API μ ν μ€μ)
### 보μ κ³ λ €μ¬ν
β οΈ **Webhook URLμ λ―Όκ° μ 보μ
λλ€:**
- Gitμ 컀λ°νμ§ λ§μΈμ
- κ³΅κ° μ μ₯μμ λ
ΈμΆ κΈμ§
- μ κΈ°μ μΌλ‘ μ¬μμ± κΆμ₯
- `.env` νμΌμ `.gitignore`μ ν¬ν¨ νμ
## FAQ
### Q: μ΄λ―Έμ§κ° νμλμ§ μμ΅λλ€
**A**: μ΄λ―Έμ§ URL κ²μ¦ μ€ν¨ μμΈ:
1. **HTTPSλ§ μ§μ** (HTTPλ λΆκ°)
2. **νμΌ ν¬κΈ°**: 5MB μ΄νμ¬μΌ ν¨
3. **κ³΅κ° μ κ·Ό**: μΈμ¦ μμ΄ μ κ·Ό κ°λ₯ν URLμ΄μ΄μΌ ν¨
4. **Content-Type**: μλ΅ ν€λκ° `image/*`μ¬μΌ ν¨
**λλ²κΉ
:**
```bash
# λ‘κ·Έ νμΈ
cat logs/app-YYYY-MM-DD.log | grep "image_validation_failed"
```
**κ²μ¦ μ€ν¨ μ λμ:**
- μ΄λ―Έμ§λ ν
μ€νΈ λ§ν¬λ‘ λ체λ¨
- μ: `β οΈ μ΄λ―Έμ§ λ‘λ μ€ν¨: https://... (HTTP 404: Not Found)`
### Q: Cards V2 λ³νμ΄ μ€ν¨ν©λλ€
**A**: λ€μμ νμΈνμΈμ:
1. **fallbackToText μ΅μ
μ¬μ©**:
```json
{
"markdown": "...",
"fallbackToText": true
}
```
λ³ν μ€ν¨ μ μλμΌλ‘ ν
μ€νΈλ‘ μ μ‘λ©λλ€.
2. **λ‘κ·Έμμ μμΈ νμΈ**:
```bash
cat logs/errors-YYYY-MM-DD.log
```
3. **μ§μνμ§ μλ Markdown λ¬Έλ²**:
- κ°μ£Ό (footnotes)
- μ μ 리μ€νΈ (definition lists)
- 볡μ‘ν HTML νκ·Έ
### Q: λ‘κ·Έ νμΌμ΄ λ무 λ§μ΄ μμ
λλ€
**A**: νκ²½ λ³μλ‘ μ‘°μ :
```json
{
"env": {
"LOG_LEVEL": "WARN",
"LOG_RETENTION_DAYS": "7"
}
}
```
- `LOG_LEVEL=ERROR`: μλ¬λ§ κΈ°λ‘
- `LOG_RETENTION_DAYS=7`: 7μΌλ§ 보κ΄
- `LOG_ENABLE_CONSOLE=false`: μ½μ μΆλ ₯ λΉνμ±ν
### Q: npx μ€ν μ "command not found" μ€λ₯
**A**: Node.jsμ npmμ΄ μ€μΉλμ΄ μλμ§ νμΈ:
```bash
node --version # v18.0.0 μ΄μ κΆμ₯
npm --version
```
μ€μΉλμ§ μμλ€λ©΄:
- **Windows**: https://nodejs.org/ μμ λ€μ΄λ‘λ
- **macOS**: `brew install node`
- **Linux**: `sudo apt install nodejs npm` (Ubuntu/Debian)
### Q: Webhook URLμ μ΄λ»κ² μμ νκ² κ΄λ¦¬νλμ?
**A**:
1. **νκ²½ λ³μ μ¬μ©** (μ€μ νμΌμ μ§μ μ°μ§ λ§μΈμ)
2. **Gitμ 컀λ°νμ§ λ§μΈμ** (.gitignore νμΈ)
3. **μ κΈ°μ μΌλ‘ μ¬μμ±** (μ μΆ μμ¬ μ)
4. **Google Chatμμ Webhook μμ **λ‘ λ¬΄ν¨ν κ°λ₯
### Q: μ¬λ¬ Google Chat μ€νμ΄μ€μ λ©μμ§λ₯Ό 보λ΄κ³ μΆμ΅λλ€
**A**: κ° μ€νμ΄μ€λ§λ€ λ€λ₯Έ MCP μλ² μΈμ€ν΄μ€ λ±λ‘:
```json
{
"mcpServers": {
"google-chat-team-a": {
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "https://chat.googleapis.com/.../team-a/..."
}
},
"google-chat-team-b": {
"command": "npx",
"args": ["-y", "google-chat-webhook-mcp"],
"env": {
"GOOGLE_CHAT_WEBHOOK_URL": "https://chat.googleapis.com/.../team-b/..."
}
}
}
}
```
Claudeμμ "Send to team-a" λλ "Send to team-b"λ‘ κ΅¬λΆνμ¬ μ¬μ©ν μ μμ΅λλ€.
## CI/CD
GitHub Actionsλ‘ μλν:
- β
Node.js 18.x, 20.x λ§€νΈλ¦μ€ λΉλ
- β
ESLint, λΉλ, ν
μ€νΈ
- β
μ€λ
μ· ν
μ€νΈ (12κ°)
- β
ν΅ν© ν
μ€νΈ (master λΈλμΉ)
μν¬νλ‘μ°: [`.github/workflows/ci.yml`](.github/workflows/ci.yml)
## κΈ°μ¬
μ΄μμ PRμ νμν©λλ€!
## λΌμ΄μ μ€
MIT License - [LICENSE](LICENSE)
## λ¬Έμ
- [λ‘κΉ
μ€κ³](docs/logging-design.md)
- [CI μ€μ κ°μ΄λ](docs/ci-setup.md)
- [Markdown ꡬν κ³ν](docs/markdown-to-cards-implementation.md)
## κ΄λ ¨ νλ‘μ νΈ
- [Model Context Protocol](https://github.com/modelcontextprotocol)
- [Claude Code](https://claude.ai/desktop)
- [Google Chat API](https://developers.google.com/chat)
TDQS
Scored across 3 tools
Each tool has a clearly distinct purpose: send_google_chat_cards_v2 sends Cards V2 messages, send_google_chat_markdown converts Markdown to Cards V2 with fallback, and send_google_chat_text sends plain text messages. There is no ambiguity in their functions, as they target different message formats and conversion behaviors.
All tool names follow a consistent verb_noun pattern with 'send_google_chat_' as a prefix and specific suffixes (_cards_v2, _markdown, _text). This predictable naming scheme makes it easy to understand their roles and ensures no mixing of conventions.
With 3 tools, the count is appropriate for the server's purpose of sending messages to Google Chat webhooks, covering key message types. It is slightly lean but reasonable, as it includes essential formats (Cards V2, Markdown, text) without unnecessary bloat.
The tool set provides complete coverage for sending messages via Google Chat webhooks, including Cards V2, Markdown conversion with fallback, and plain text. There are no obvious gaps, as these tools cover the primary message formats and conversion needs for this domain.