Skip to main content
Glama
JDeun

Unified Search MCP Server

by JDeun
README.md
# Unified Search MCP Server ๐Ÿ”

**ํ”„๋กœ๋•์…˜ ๋ ˆ๋ฒจ** MCP (Model Context Protocol) ์„œ๋ฒ„๋กœ Google Scholar, Google Web Search, YouTube๋ฅผ ํ†ตํ•ฉ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![smithery badge](https://smithery.ai/badge/@JDeun/unified-search-mcp-server)](https://smithery.ai/server/@JDeun/unified-search-mcp-server)

## ๐Ÿš€ ์ฃผ์š” ๊ธฐ๋Šฅ

### ํ•ต์‹ฌ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ
- **๐ŸŽ“ Google Scholar**: ํ•™์ˆ  ๋…ผ๋ฌธ ๊ฒ€์ƒ‰ (์ €์ž, ์—ฐ๋„ ํ•„ํ„ฐ๋ง)
- **๐ŸŒ Google Web Search**: Google Custom Search API๋ฅผ ์‚ฌ์šฉํ•œ ์›น ๊ฒ€์ƒ‰
- **๐Ÿ“บ YouTube Search**: ๋™์˜์ƒ ๊ฒ€์ƒ‰ (๊ธธ์ด, ์—…๋กœ๋“œ ๋‚ ์งœ, ์ •๋ ฌ ์˜ต์…˜)
- **๐Ÿ”„ ํ†ตํ•ฉ ๊ฒ€์ƒ‰**: ๋ชจ๋“  ์†Œ์Šค์—์„œ ๋™์‹œ ๊ฒ€์ƒ‰

### ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ๊ธฐ๋Šฅ
- **๐Ÿ” ๋ณด์•ˆ**: API ํ‚ค ์•”ํ˜ธํ™”, ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ, XSS/SQL ์ธ์ ์…˜ ๋ฐฉ์ง€
- **๐Ÿ’พ ๋ถ„์‚ฐ ์บ์‹ฑ**: Redis ๊ธฐ๋ฐ˜ ์บ์‹ฑ ๋ฐ TTL ๊ด€๋ฆฌ
- **โšก Rate Limiting**: Redis ๋ฐฑ์—”๋“œ ๊ธฐ๋ฐ˜ ์„ค์ • ๊ฐ€๋Šฅํ•œ rate limit
- **๐Ÿ“Š ๋ชจ๋‹ˆํ„ฐ๋ง**: Prometheus ๋ฉ”ํŠธ๋ฆญ, ํ—ฌ์Šค ์ฒดํฌ, ๊ตฌ์กฐํ™”๋œ ๋กœ๊น…
- **๐Ÿ”„ ๋ณต์›๋ ฅ**: ์žฌ์‹œ๋„ ๋กœ์ง, ์„œํ‚ท ๋ธŒ๋ ˆ์ด์ปค, ์šฐ์•„ํ•œ ์„ฑ๋Šฅ ์ €ํ•˜
- **๐Ÿ“ ๊ฐ์‚ฌ ๋กœ๊น…**: ๊ทœ์ • ์ค€์ˆ˜๋ฅผ ์œ„ํ•œ ํฌ๊ด„์ ์ธ ๊ฐ์‚ฌ ์ถ”์ 

## ๐Ÿ“‹ ์š”๊ตฌ ์‚ฌํ•ญ

- Python 3.11+
- Redis (์„ ํƒ์‚ฌํ•ญ, ๋ถ„์‚ฐ ๊ธฐ๋Šฅ์šฉ)
- API ํ‚ค:
  - Google Custom Search API (์›น ๊ฒ€์ƒ‰์šฉ)
  - YouTube Data API v3 (YouTube ๊ฒ€์ƒ‰์šฉ)

## ๐Ÿ› ๏ธ ์„ค์น˜

### Smithery๋ฅผ ํ†ตํ•œ ๋น ๋ฅธ ์„ค์น˜

Smithery ํ”Œ๋žซํผ์„ ํ†ตํ•ด ์ง์ ‘ ๋ฐฐํฌํ•˜๋ฉด ์ž๋™์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

### ์ˆ˜๋™ ์„ค์น˜

1. ์ €์žฅ์†Œ ํด๋ก :
```bash
git clone https://github.com/JDeun/unified-search-mcp-server.git
cd unified-search-mcp-server
```

2. ๊ฐ€์ƒ ํ™˜๊ฒฝ ์ƒ์„ฑ:
```bash
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
```

3. ์˜์กด์„ฑ ์„ค์น˜:
```bash
pip install -r requirements.txt
```

4. ํ™˜๊ฒฝ ์„ค์ •:
```bash
cp .env.example .env
# .env ํŒŒ์ผ์„ ํŽธ์ง‘ํ•˜์—ฌ API ํ‚ค์™€ ์„ค์ • ์ž…๋ ฅ
```

## โš™๏ธ ์„ค์ •

### ํ™˜๊ฒฝ ๋ณ€์ˆ˜

```env
# API ํ‚ค
GOOGLE_API_KEY=your-google-api-key
GOOGLE_CUSTOM_SEARCH_ENGINE_ID=your-cse-id
YOUTUBE_API_KEY=your-youtube-api-key

# ๋ณด์•ˆ
MCP_ENCRYPTION_KEY=your-256-bit-key
MCP_RATE_LIMIT_SECRET=your-secret

# Redis (์„ ํƒ์‚ฌํ•ญ)
MCP_REDIS_URL=redis://localhost:6379/0

# ์„ค์ •
MCP_ENV=production
MCP_LOG_LEVEL=INFO
MCP_CACHE_TTL=3600
```

### API ํ‚ค ๋ฐœ๊ธ‰ ๋ฐฉ๋ฒ•

1. **Google Custom Search API**:
   - [Google Cloud Console](https://console.cloud.google.com/) ์ ‘์†
   - "Custom Search API" ํ™œ์„ฑํ™”
   - ์ธ์ฆ ์ •๋ณด ์ƒ์„ฑ (API ํ‚ค)
   - [cse.google.com](https://cse.google.com/)์—์„œ Custom Search Engine ์ƒ์„ฑ

2. **YouTube Data API v3**:
   - ๋™์ผํ•œ Google Cloud Console ํ”„๋กœ์ ํŠธ ์‚ฌ์šฉ
   - "YouTube Data API v3" ํ™œ์„ฑํ™”
   - ๋™์ผํ•œ API ํ‚ค ์‚ฌ์šฉ ๋˜๋Š” ์ƒˆ๋กœ ์ƒ์„ฑ

## ๐Ÿš€ ์‚ฌ์šฉ๋ฒ•

### ์„œ๋ฒ„ ์‹คํ–‰

```bash
# ๊ฐœ๋ฐœ ๋ชจ๋“œ (stdio)
python unified_search_server.py

# ํ”„๋กœ๋•์…˜ ๋ชจ๋“œ (HTTP)
python unified_search_server.py --transport streamable-http

# ์ปค์Šคํ…€ ํฌํŠธ
MCP_PORT=8080 python unified_search_server.py --transport streamable-http
```

### Docker ๋ฐฐํฌ

```bash
# ์ด๋ฏธ์ง€ ๋นŒ๋“œ
docker build -t unified-search-mcp .

# ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰
docker run -p 8000:8000 \
  -e GOOGLE_API_KEY=your-key \
  -e GOOGLE_CUSTOM_SEARCH_ENGINE_ID=your-cse \
  -e YOUTUBE_API_KEY=your-key \
  unified-search-mcp
```

### Claude Desktop ํ†ตํ•ฉ

`claude_desktop_config.json`์— ์ถ”๊ฐ€:

```json
{
  "mcpServers": {
    "unified-search": {
      "command": "python",
      "args": ["/path/to/unified_search_server.py"],
      "env": {
        "GOOGLE_API_KEY": "your-key",
        "GOOGLE_CUSTOM_SEARCH_ENGINE_ID": "your-cse",
        "YOUTUBE_API_KEY": "your-key"
      }
    }
  }
}
```

## ๐Ÿ“– ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋„๊ตฌ

### unified_search
๋ชจ๋“  ์†Œ์Šค์—์„œ ๋™์‹œ์— ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.
```python
results = await unified_search(
    query="์ธ๊ณต์ง€๋Šฅ",
    sources=["scholar", "web", "youtube"],
    num_results=10
)
```

### search_google_scholar
ํ•™์ˆ  ๋…ผ๋ฌธ์„ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.
```python
results = await search_google_scholar(
    query="๋จธ์‹ ๋Ÿฌ๋‹",
    author="Yann LeCun",
    year_start=2020,
    year_end=2024,
    num_results=10
)
```

### search_google_web
์›น์„ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.
```python
results = await search_google_web(
    query="ChatGPT",
    language="ko",
    safe_search="medium",
    num_results=10
)
```

### search_youtube
YouTube ๋™์˜์ƒ์„ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.
```python
results = await search_youtube(
    query="ํŒŒ์ด์ฌ ํŠœํ† ๋ฆฌ์–ผ",
    video_duration="medium",
    upload_date="month",
    order="viewCount",
    num_results=20
)
```

### get_author_info
Google Scholar์—์„œ ์ €์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
```python
info = await get_author_info("Geoffrey Hinton")
```

### clear_cache
์บ์‹œ๋œ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.
```python
await clear_cache(source="web")  # ๋˜๋Š” None์œผ๋กœ ์ „์ฒด ์‚ญ์ œ
```

### get_api_usage_stats
API ์‚ฌ์šฉ๋Ÿ‰๊ณผ ์ œํ•œ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค.
```python
stats = await get_api_usage_stats()
```

## ๐Ÿ—๏ธ ์•„ํ‚คํ…์ฒ˜

### ๋ชจ๋“ˆ์‹ ์„ค๊ณ„
```
src/
โ”œโ”€โ”€ config/       # ์„ค์ • ๋ฐ ๋ณด์•ˆ
โ”œโ”€โ”€ models/       # ๋ฐ์ดํ„ฐ ๋ชจ๋ธ ๋ฐ ๊ฒ€์ฆ
โ”œโ”€โ”€ services/     # ๊ฒ€์ƒ‰ ์„œ๋น„์Šค ๊ตฌํ˜„
โ”œโ”€โ”€ cache/        # ์บ์‹ฑ ๋ ˆ์ด์–ด
โ”œโ”€โ”€ utils/        # ์œ ํ‹ธ๋ฆฌํ‹ฐ (๋กœ๊น…, rate limiting)
โ”œโ”€โ”€ monitoring/   # ๋ฉ”ํŠธ๋ฆญ ๋ฐ ํ—ฌ์Šค ์ฒดํฌ
โ””โ”€โ”€ mcp_server.py # ๋ฉ”์ธ ์„œ๋ฒ„ ๊ตฌํ˜„
```

### ๋ณด์•ˆ ๋ ˆ์ด์–ด
- ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ ๋ฐ ์‚ด๊ท 
- API ํ‚ค ์•”ํ˜ธํ™” ์ €์žฅ
- ํด๋ผ์ด์–ธํŠธ/์—”๋“œํฌ์ธํŠธ๋ณ„ rate limiting
- ๊ทœ์ • ์ค€์ˆ˜๋ฅผ ์œ„ํ•œ ๊ฐ์‚ฌ ๋กœ๊น…
- CORS ๋ฐ ์š”์ฒญ ID ์ถ”์ 

### ์„ฑ๋Šฅ ์ตœ์ ํ™”
- Redis ๊ธฐ๋ฐ˜ ๋ถ„์‚ฐ ์บ์‹ฑ
- HTTP ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ํ’€๋ง
- ๋™์‹œ ๊ฒ€์ƒ‰ ์‹คํ–‰
- ์ง€์ˆ˜ ๋ฐฑ์˜คํ”„๋ฅผ ํ†ตํ•œ ์Šค๋งˆํŠธ ์žฌ์‹œ๋„
- ์™ธ๋ถ€ API์šฉ ์„œํ‚ท ๋ธŒ๋ ˆ์ด์ปค

## ๐Ÿ“Š ๋ชจ๋‹ˆํ„ฐ๋ง

### ํ—ฌ์Šค ์ฒดํฌ ์—”๋“œํฌ์ธํŠธ
```
๋ฆฌ์†Œ์Šค: health://status
```

### ๋ฉ”ํŠธ๋ฆญ ์—”๋“œํฌ์ธํŠธ
```
๋ฆฌ์†Œ์Šค: metrics://stats
```

### ์ฃผ์š” ๋ฉ”ํŠธ๋ฆญ
- ๊ฒ€์ƒ‰ ์š”์ฒญ ์ˆ˜ ๋ฐ ์ง€์—ฐ ์‹œ๊ฐ„
- ์บ์‹œ ํžˆํŠธ์œจ
- API ํ• ๋‹น๋Ÿ‰ ์‚ฌ์šฉ๋Ÿ‰
- ์†Œ์Šค๋ณ„ ์˜ค๋ฅ˜์œจ
- Rate limit ์œ„๋ฐ˜

## ๐Ÿ”’ ๋ณด์•ˆ

### ๋ชจ๋ฒ” ์‚ฌ๋ก€
- ๋ชจ๋“  API ํ‚ค Fernet์œผ๋กœ ์•”ํ˜ธํ™”
- XSS/SQL ์ธ์ ์…˜ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ์ž…๋ ฅ ๊ฒ€์ฆ
- ๋‚จ์šฉ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ rate limiting
- ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ ์—†๋Š” ๊ตฌ์กฐํ™”๋œ ๋กœ๊น…
- ์ •๊ธฐ์ ์ธ ๋ณด์•ˆ ์—…๋ฐ์ดํŠธ

### ๊ทœ์ • ์ค€์ˆ˜
- PII ์ €์žฅ ์—†๋Š” GDPR ์ค€๋น„
- ๋ชจ๋“  ๊ฒ€์ƒ‰์— ๋Œ€ํ•œ ๊ฐ์‚ฌ ์ถ”์ 
- ์„ค์ • ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ ๋ณด์กด
- API ์‚ฌ์šฉ๋Ÿ‰ ์ถ”์ 

## ๐Ÿงช ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธ ์‹คํ–‰:
```bash
pytest tests/ -v --cov=src
```

## ๐Ÿค ๊ธฐ์—ฌ

1. ์ €์žฅ์†Œ ํฌํฌ
2. ๊ธฐ๋Šฅ ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ (`git checkout -b feature/amazing`)
3. ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์ปค๋ฐ‹ (`git commit -m 'Add feature'`)
4. ๋ธŒ๋žœ์น˜์— ํ‘ธ์‹œ (`git push origin feature/amazing`)
5. Pull Request ์—ด๊ธฐ

## ๐Ÿ“ ๋ผ์ด์„ ์Šค

MIT ๋ผ์ด์„ ์Šค - ์ž์„ธํ•œ ๋‚ด์šฉ์€ [LICENSE](LICENSE) ํŒŒ์ผ ์ฐธ์กฐ

## ๐Ÿ™ ๊ฐ์‚ฌ์˜ ๋ง

- [FastMCP](https://github.com/jlowin/fastmcp)๋กœ ๊ตฌ์ถ•
- [scholarly](https://github.com/scholarly/scholarly)๋ฅผ ํ†ตํ•œ Google Scholar ๊ฒ€์ƒ‰
- MCP ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ์˜๊ฐ

## โš ๏ธ ์ค‘์š” ์‚ฌํ•ญ

### API ์ œํ•œ
- **Google Web Search**: 100 ์ฟผ๋ฆฌ/์ผ (๋ฌด๋ฃŒ ํ‹ฐ์–ด)
- **YouTube API**: 10,000 ์œ ๋‹›/์ผ (์•ฝ 100 ๊ฒ€์ƒ‰)
- **Google Scholar**: ๊ณต์‹ API ์—†์Œ, rate ์ œํ•œ ์žˆ์Œ

### ํ”„๋กœ๋•์…˜ ๊ณ ๋ ค์‚ฌํ•ญ
- ๋ถ„์‚ฐ ๋ฐฐํฌ๋ฅผ ์œ„ํ•ด Redis ์‚ฌ์šฉ
- ์ ์ ˆํ•œ API ํ‚ค ๋กœํ…Œ์ด์…˜ ์„ค์ •
- Rate limit ๋ฐ ํ• ๋‹น๋Ÿ‰ ๋ชจ๋‹ˆํ„ฐ๋ง
- API ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์•Œ๋ฆผ ์„ค์ •
- ์ •๊ธฐ์ ์ธ ์„ค์ • ๋ฐฑ์—…

## ๐Ÿ“ž ์ง€์›

๋ฌธ์ œ ๋ฐ ์งˆ๋ฌธ:
- GitHub Issues: [์ด์Šˆ ์ƒ์„ฑ](https://github.com/JDeun/unified-search-mcp-server/issues)
- Smithery ์ง€์›: ๋ฐฐํฌ ๊ด€๋ จ ๋ฌธ์ œ

---

**MCP ์ปค๋ฎค๋‹ˆํ‹ฐ๋ฅผ ์œ„ํ•ด โค๏ธ๋กœ ์ œ์ž‘**