@clawhub-bithostgits-a6b389dd47
Web search via Zhipu GLM — supports both MCP (mcporter) and cURL (REST API) backends. Provides multi-engine search (Pro, Sogou, Quark, Std) with intent recog...
---
name: glm-search-pro
description: >
Web search via Zhipu GLM — supports both MCP (mcporter) and cURL (REST API) backends.
Provides multi-engine search (Pro, Sogou, Quark, Std) with intent recognition, time range
filtering, domain filtering, and configurable result count/detail level.
Use when the agent needs to search the web, look up current information, find news,
or retrieve online resources. Works from China without VPN.
Trigger on: "search the web", "web search", "look up", "find online", "latest news",
"search for", "google for", "联网搜索", "在线搜索", "查最新", "搜索一下".
metadata:
{
"openclaw":
{
"requires": { "env": ["ZHIPU_API_KEY"], "bins": ["curl", "python3"] },
},
}
---
# GLM Search Pro
Web search powered by Zhipu GLM, with dual-backend support: **cURL** (REST API, preferred) and **MCP** (via mcporter).
## Credentials
This skill requires a **Zhipu API key**, provided via the `ZHIPU_API_KEY` environment variable.
### cURL mode (preferred)
No setup required. The key is read from `$ZHIPU_API_KEY` at runtime and sent via HTTP `Authorization: Bearer` header. In cURL mode, no files are written to disk.
### MCP mode (advanced)
If you need MCP mode, `setup.sh` will write a config file to disk:
| File | What it contains | Permissions |
|------|-----------------|-------------|
| `~/.openclaw/config/mcporter/mcporter.json` | MCP server URL with API key as query param | `600` (owner-only) |
| `~/.openclaw/config/mcporter/` directory | Parent directory | `700` (owner-only) |
**Important**: The Zhipu MCP broker endpoint requires the API key as a URL query parameter (`Authorization=<key>`). This is how their SSE endpoint works — the key cannot be passed via HTTP header for MCP connections. Setup writes this to `mcporter.json` with `600` permissions. If this is not acceptable, use cURL mode only (which passes the key via `Authorization` header at runtime and writes nothing to disk).
### What this skill reads
| Source | When | Purpose |
|--------|------|---------|
| `$ZHIPU_API_KEY` env var | Every search (cURL mode), and during setup (MCP mode) | API key |
### Recommendation
For maximum security, use cURL mode and skip `setup.sh`. MCP mode is provided as a convenience but requires persisting the key on disk due to the Zhipu MCP broker's authentication design.
## Quick Start
```bash
# Set your API key
export ZHIPU_API_KEY="your-api-key"
# Search (cURL mode, no setup needed)
bash scripts/glm-search.sh "your query"
# With options
bash scripts/glm-search.sh -q "latest AI news" -c 20 -r oneWeek -e quark
```
## Backends
The script auto-selects the best available backend:
1. **cURL mode** (preferred) — `curl` + `ZHIPU_API_KEY` env var. Key sent via HTTP header. Nothing written to disk.
2. **MCP mode** (advanced) — `mcporter` + config from `setup.sh`. Key stored in config file for MCP broker auth.
Force a specific mode with `--curl` or `--mcp`.
## Search Engines
| Engine | Flag | Best For |
|--------|------|----------|
| Pro | `-e pro` | General purpose, best quality (**default**) |
| Quark | `-e quark` | Advanced scenarios, Chinese content |
| Sogou | `-e sogou` | China domestic content |
| Std | `-e std` | Basic search, Q&A |
## Parameters
| Flag | Long | Default | Description |
|------|------|---------|-------------|
| `-q` | `--query` | — | Search text (required, ≤70 chars recommended) |
| `-c` | `--count` | 10 | Number of results (1-50) |
| `-e` | `--engine` | pro | `pro`, `sogou`, `quark`, `std` |
| `-r` | `--recency` | noLimit | `noLimit`, `oneYear`, `oneMonth`, `oneWeek`, `oneDay` |
| `-s` | `--size` | medium | `medium` (400-600 chars) or `high` (up to 2500) |
| `-i` | `--intent` | off | Enable search intent recognition (cURL only) |
| `-d` | `--domain` | — | Restrict results to specific domain |
| | `--curl` | — | Force cURL backend |
| | `--mcp` | — | Force MCP backend |
## Examples
```bash
# Basic search (cURL mode auto-selected)
glm-search "OpenClaw framework"
# Recent news, more results
glm-search -q "AI news" -c 20 -r oneWeek
# Chinese content via Sogou
glm-search -q "最新科技新闻" -e sogou -r oneDay
# Domain-specific search
glm-search -q "Python async" -d docs.python.org
# Intent recognition (cURL only)
glm-search -i "What is machine learning"
```
## Response Format
```json
{
"id": "task-id",
"created": 1704067200,
"search_result": [
{
"title": "Page Title",
"content": "Page summary...",
"link": "https://example.com",
"media": "Source Name",
"refer": "ref_1",
"publish_date": "2026-04-27"
}
]
}
```
## Architecture
```
glm-search (script)
├── cURL mode (preferred)
│ └── curl + $ZHIPU_API_KEY → Authorization: Bearer header → Zhipu REST API
└── MCP mode (advanced, requires setup)
└── mcporter → config from setup.sh → Zhipu MCP Broker SSE endpoint
```
## Setup (MCP mode only)
```bash
export ZHIPU_API_KEY="your-api-key"
bash scripts/setup.sh
```
This is **only needed for MCP mode**. cURL mode works immediately with `ZHIPU_API_KEY` set.
## Prerequisites
- **Zhipu API key** — <https://open.bigmodel.cn> (set as `ZHIPU_API_KEY` env var)
- **curl** — pre-installed on most systems
- **python3** — used by setup.sh for JSON config generation
- **mcporter** (optional, for MCP mode) — `npm i -g mcporter` (invoked via `npx`)
## Troubleshooting
See `references/api-notes.md` for detailed API reference and common issues.
FILE:references/api-notes.md
# Zhipu GLM Web Search — API Reference
## Endpoints
### REST API (cURL mode)
```
POST https://open.bigmodel.cn/api/paas/v4/web_search
Authorization: Bearer <ZHIPU_API_KEY>
Content-Type: application/json
```
### MCP Broker (mcporter mode)
```
SSE: https://open.bigmodel.cn/api/mcp-broker/proxy/web-search/mcp?Authorization=<ZHIPU_API_KEY>
```
- **Transport**: SSE (Server-Sent Events)
- **Auth**: API key as URL query parameter `Authorization=`
- **⚠️ Do NOT use**: `https://open.bigmodel.cn/api/mcp/web_search_prime/mcp` (deprecated; returns 401 on tools/call)
## Search Engines
| REST API Name | MCP Tool Name | Description |
|---------------|---------------|-------------|
| `search_pro` | `webSearchPro` | Advanced multi-engine search (**recommended**) |
| `search_pro_quark` | `webSearchQuark` | Quark engine, Chinese content |
| `search_pro_sogou` | `webSearchSogou` | Sogou engine, China domestic |
| `search_std` | `webSearchStd` | Basic standard search |
## Parameters
| Parameter | REST API | MCP | Type | Default | Description |
|-----------|----------|-----|------|---------|-------------|
| `search_query` | ✅ | ✅ | string | — | Search text (≤70 chars recommended) |
| `search_engine` | ✅ | — (tool name) | enum | — | Engine selection |
| `search_intent` | ✅ | ❌ | boolean | false | Enable intent recognition |
| `count` | ✅ | ✅ | integer | 10 | Results 1-50 |
| `search_recency_filter` | ✅ | ✅ | enum | noLimit | Time range filter |
| `content_size` | ✅ | ✅ | enum | medium | Summary detail level |
| `search_domain_filter` | ✅ | ✅ | string | — | Domain whitelist |
### Time Range Values
`noLimit` · `oneYear` · `oneMonth` · `oneWeek` · `oneDay`
### Content Size Values
- `medium` — 400-600 character summaries
- `high` — up to 2500 character summaries (higher cost)
## cURL Examples
### Basic
```bash
curl -s POST https://open.bigmodel.cn/api/paas/v4/web_search \
-H "Authorization: Bearer $ZHIPU_API_KEY" \
-H "Content-Type: application/json" \
-d '{"search_query":"AI news","search_engine":"search_pro","count":10}'
```
### With All Options
```bash
curl -s POST https://open.bigmodel.cn/api/paas/v4/web_search \
-H "Authorization: Bearer $ZHIPU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"search_query": "latest AI developments",
"search_engine": "search_pro_quark",
"search_intent": true,
"count": 20,
"search_recency_filter": "oneWeek",
"content_size": "high",
"search_domain_filter": "arstechnica.com"
}'
```
## Common Issues
### "Api key not found" (MCP mode)
Wrong endpoint. Use the `mcp-broker/proxy` URL, not the deprecated `web_search_prime` endpoint.
### "Tool not found: web_search_prime"
The broker endpoint uses different tool names (`webSearchPro`, etc.). Use `webSearchPro` instead.
### Empty results `[]`
- Verify your Zhipu account plan supports web search
- Check quota at <https://open.bigmodel.cn>
- Try a different query or engine
### mcporter not found
Install it: `npm i -g mcporter`
Or use cURL fallback by setting `ZHIPU_API_KEY` env var.
## Official Docs
- Web Search: <https://docs.bigmodel.cn/cn/guide/tools/web-search>
- MCP Server: <https://docs.bigmodel.cn/cn/coding-plan/mcp/search-mcp-server>
FILE:scripts/glm-search.sh
#!/usr/bin/env bash
# glm-search — Search the web via Zhipu GLM
# Supports two modes:
# 1. cURL mode (preferred) — only requires curl + ZHIPU_API_KEY env var
# 2. MCP mode (advanced) — requires mcporter + setup.sh
#
# Usage: glm-search [options] <query>
# -q, --query TEXT Search text (required)
# -c, --count N Number of results 1-50 (default: 10)
# -e, --engine NAME Engine: pro|sogou|quark|std (default: pro)
# -r, --recency FILTER noLimit|oneYear|oneMonth|oneWeek|oneDay (default: noLimit)
# -s, --size SIZE medium|high (default: medium)
# -i, --intent Enable search intent recognition (cURL mode only)
# -d, --domain DOMAIN Restrict to specific domain
# --curl Force cURL mode (skip mcporter)
# --mcp Force MCP mode (skip cURL fallback)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")" && pwd)"
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
MCP_CONFIG="HOME/.openclaw/config/mcporter/mcporter.json"
# Defaults
QUERY=""
COUNT=10
ENGINE="pro"
RECENCY="noLimit"
CONTENT_SIZE="medium"
INTENT=false
DOMAIN=""
FORCE_MODE=""
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-q|--query) QUERY="$2"; shift 2 ;;
-c|--count) COUNT="$2"; shift 2 ;;
-e|--engine) ENGINE="$2"; shift 2 ;;
-r|--recency) RECENCY="$2"; shift 2 ;;
-s|--size) CONTENT_SIZE="$2"; shift 2 ;;
-i|--intent) INTENT=true; shift ;;
-d|--domain) DOMAIN="$2"; shift 2 ;;
--curl) FORCE_MODE="curl"; shift ;;
--mcp) FORCE_MODE="mcp"; shift ;;
*) QUERY="$1"; shift ;;
esac
done
if [ -z "$QUERY" ]; then
echo "Usage: glm-search [options] <query>" >&2
echo " -q, --query TEXT Search text (required)" >&2
echo " -c, --count N Results 1-50 (default: 10)" >&2
echo " -e, --engine NAME pro|sogou|quark|std (default: pro)" >&2
echo " -r, --recency F noLimit|oneYear|oneMonth|oneWeek|oneDay" >&2
echo " -s, --size SIZE medium|high" >&2
echo " -i, --intent Enable intent recognition (cURL mode)" >&2
echo " -d, --domain D Restrict to domain" >&2
echo " --curl Force cURL mode" >&2
echo " --mcp Force MCP mode" >&2
exit 2
fi
# Engine mapping for MCP tool names
declare -A MCP_ENGINES=(
[pro]="webSearchPro"
[sogou]="webSearchSogou"
[quark]="webSearchQuark"
[std]="webSearchStd"
)
# Engine mapping for REST API engine names
declare -A REST_ENGINES=(
[pro]="search_pro"
[sogou]="search_pro_sogou"
[quark]="search_pro_quark"
[std]="search_std"
)
MCP_TOOL="-webSearchPro"
REST_ENGINE="-search_pro"
# Build JSON payload for cURL (safe quoting via python3)
build_payload() {
python3 -c "
import json
payload = {
'search_query': $(python3 -c "import json;print(json.dumps('$QUERY'))" 2>/dev/null || echo "\"$QUERY\""),
'search_engine': 'REST_ENGINE',
'search_intent': $( [ "$INTENT" = true ] && echo "True" || echo "False" ),
'count': COUNT,
'search_recency_filter': 'RECENCY',
'content_size': 'CONTENT_SIZE'
}
$( [ -n "$DOMAIN" ] && echo "payload['search_domain_filter'] = '$DOMAIN'" )
print(json.dumps(payload))
"
}
# MCP mode via mcporter
search_mcp() {
if [ ! -f "$MCP_CONFIG" ]; then
echo "Error: mcporter config not found at $MCP_CONFIG" >&2
echo "Run setup first: bash SKILL_DIR/scripts/setup.sh" >&2
return 1
fi
if ! command -v mcporter &>/dev/null && ! command -v npx &>/dev/null; then
echo "Error: mcporter/npx not found." >&2
echo "Install: npm i -g mcporter" >&2
return 1
fi
local extra_args=()
[ -n "$DOMAIN" ] && extra_args+=("search_domain_filter=$DOMAIN")
exec npx -y mcporter --config "$MCP_CONFIG" call "glm-search.MCP_TOOL" \
search_query="$QUERY" \
count="$COUNT" \
search_recency_filter="$RECENCY" \
content_size="$CONTENT_SIZE" \
"extra_args[@]+"${extra_args[@]"}"
}
# cURL mode via REST API
search_curl() {
if [ -z "-" ]; then
echo "Error: ZHIPU_API_KEY environment variable not set." >&2
echo "Set it with: export ZHIPU_API_KEY=\"your-api-key\"" >&2
return 1
fi
local payload
payload=$(build_payload)
curl --silent --show-error --request POST \
--url "https://open.bigmodel.cn/api/paas/v4/web_search" \
--header "Authorization: Bearer ZHIPU_API_KEY" \
--header "Content-Type: application/json" \
--data "$payload"
}
# Auto-select mode: prefer cURL (simpler, no extra deps), fallback to MCP
if [ "$FORCE_MODE" = "mcp" ]; then
search_mcp
elif [ "$FORCE_MODE" = "curl" ]; then
search_curl
elif [ -n "-" ] && command -v curl &>/dev/null; then
search_curl
elif [ -f "$MCP_CONFIG" ]; then
search_mcp
else
echo "Error: No usable search backend found." >&2
echo "Set ZHIPU_API_KEY for cURL mode, or run setup.sh for MCP mode." >&2
exit 1
fi
FILE:scripts/setup.sh
#!/usr/bin/env bash
# setup.sh — Initialize glm-search-pro skill
# Reads API key ONLY from ZHIPU_API_KEY environment variable.
# Writes mcporter config with restrictive permissions (600/700).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")" && pwd)"
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
MCP_DIR="HOME/.openclaw/config/mcporter"
MCP_CONFIG="MCP_DIR/mcporter.json"
echo "=== glm-search-pro setup ==="
# 1. Check curl (required)
if ! command -v curl &>/dev/null; then
echo "Error: curl is required but not found." >&2
exit 1
fi
# 2. Check mcporter (optional, for MCP mode)
HAS_MCPORTER=false
if command -v mcporter &>/dev/null || command -v npx &>/dev/null; then
HAS_MCPORTER=true
echo "mcporter detected (optional, for MCP mode)."
else
echo "mcporter not found. cURL mode will be used (mcporter is optional)."
fi
# 3. Get API key — ONLY from environment variable
if [ -z "-" ]; then
echo ""
echo "Error: ZHIPU_API_KEY environment variable is not set." >&2
echo "Get your API key at https://open.bigmodel.cn then:" >&2
echo " export ZHIPU_API_KEY=\"your-api-key\"" >&2
echo " bash scripts/setup.sh" >&2
exit 1
fi
API_KEY="$ZHIPU_API_KEY"
echo "API key found in ZHIPU_API_KEY env var."
# 4. Write mcporter config with restrictive permissions
mkdir -p "$MCP_DIR"
chmod 700 "$MCP_DIR"
python3 << PYEOF
import json, os, stat
config_path = "$MCP_CONFIG"
api_key = "$API_KEY"
if os.path.exists(config_path):
with open(config_path) as f:
config = json.load(f)
else:
config = {}
if "mcpServers" not in config:
config["mcpServers"] = {}
config["mcpServers"]["glm-search"] = {
"type": "sse",
"url": f"https://open.bigmodel.cn/api/mcp-broker/proxy/web-search/mcp?Authorization={api_key}"
}
with open(config_path, "w") as f:
json.dump(config, f, indent=2)
# Set restrictive permissions (owner read/write only)
os.chmod(config_path, 0o600)
print(f"Config written to {config_path} (permissions: 600)")
PYEOF
# 5. Verify connection
echo ""
if [ "$HAS_MCPORTER" = true ]; then
echo "Verifying MCP connection..."
RESULT=$(npx -y mcporter --config "$MCP_CONFIG" list glm-search 2>&1) || true
if echo "$RESULT" | grep -q "webSearchPro"; then
echo "✅ MCP connection successful. Available: webSearchPro, webSearchSogou, webSearchQuark, webSearchStd"
else
echo "⚠️ MCP verification inconclusive. Check with: npx -y mcporter --config $MCP_CONFIG list glm-search"
fi
fi
echo "Verifying cURL connection..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"search_query":"test","search_engine":"search_pro","count":1}' \
"https://open.bigmodel.cn/api/paas/v4/web_search")
if [ "$HTTP_CODE" = "200" ]; then
echo "✅ cURL connection successful."
else
echo "⚠️ cURL returned HTTP $HTTP_CODE. Check your API key."
fi
echo ""
echo "Setup complete."
echo " MCP mode: bash SKILL_DIR/scripts/glm-search.sh --mcp \"query\""
echo " cURL mode: bash SKILL_DIR/scripts/glm-search.sh --curl \"query\""
echo " Auto: bash SKILL_DIR/scripts/glm-search.sh \"query\""