Skip to content

Instantly share code, notes, and snippets.

@phosae
Created March 11, 2026 12:39
Show Gist options
  • Select an option

  • Save phosae/58736bb6ef388232ea19e4bd5e074fe8 to your computer and use it in GitHub Desktop.

Select an option

Save phosae/58736bb6ef388232ea19e4bd5e074fe8 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
# Configure Claude Code
# Usage: PPIO_API_KEY=sk_xxx bash setup-claude-code.sh
# After running, the key is stored in settings.json — just run `claude`, no env needed.
set -euo pipefail
: "${PPIO_API_KEY:?Usage: PPIO_API_KEY=sk_xxx bash setup-claude-code.sh}"
CLAUDE_DIR="$HOME/.claude"
mkdir -p "$CLAUDE_DIR/mcp-servers"
# --- settings.json ---
cat > "$CLAUDE_DIR/settings.json" <<EOF
{
"env": {
"ANTHROPIC_API_KEY": "${PPIO_API_KEY}",
"ANTHROPIC_BASE_URL": "https://api.ppinfra.com/anthropic",
"ANTHROPIC_MODEL": "pa/claude-opus-4-6",
"PPIO_API_KEY": "${PPIO_API_KEY}"
},
"permissions": {
"allow": [],
"deny": [],
"mode": "bypassPermissions"
},
"autoUpdaterStatus": "disabled",
"skipDangerousModePermissionPrompt": true
}
EOF
# --- settings.local.json (optional tool permissions) ---
cat > "$CLAUDE_DIR/settings.local.json" <<'EOF'
{
"permissions": {
"allow": [
"mcp__google-search__google_search",
"WebFetch(domain:linear.app)",
"WebSearch"
]
}
}
EOF
# --- MCP Server: Google Search via Gemini on PPIO ---
cat > "$CLAUDE_DIR/mcp-servers/google-search.sh" <<'MCPEOF'
#!/usr/bin/env bash
# MCP Server: Gemini Google Search via PPIO
set -euo pipefail
API_URL="https://api.ppinfra.com/gemini/v1/models/pa/gmn-2.5-fls-lt:generateContent"
send_response() { printf '%s\n' "$1"; }
send_error() {
local id="$1" code="$2" msg="$3"
send_response "{\"jsonrpc\":\"2.0\",\"id\":${id},\"error\":{\"code\":${code},\"message\":$(python3 -c "import json; print(json.dumps('$msg'))")}}"
}
handle_initialize() {
local id="$1"
send_response "{\"jsonrpc\":\"2.0\",\"id\":${id},\"result\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{\"tools\":{}},\"serverInfo\":{\"name\":\"google-search\",\"version\":\"1.0.0\"}}}"
}
handle_tools_list() {
local id="$1"
send_response "{\"jsonrpc\":\"2.0\",\"id\":${id},\"result\":{\"tools\":[{\"name\":\"google_search\",\"description\":\"Search the web using Google Search via Gemini. Returns an answer with grounding sources.\",\"inputSchema\":{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"The search query\"}},\"required\":[\"query\"]}}]}}"
}
handle_tools_call() {
local id="$1" raw_params="$2"
local tool_name query
tool_name=$(printf '%s' "$raw_params" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('name',''))")
query=$(printf '%s' "$raw_params" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('arguments',{}).get('query',''))")
if [ "$tool_name" != "google_search" ]; then
send_error "$id" -32602 "Unknown tool: ${tool_name}"; return
fi
if [ -z "$query" ]; then
send_error "$id" -32602 "Missing required parameter: query"; return
fi
local request_body
request_body=$(python3 -c "
import json, sys
q = sys.argv[1]
body = {
'contents': [{'role': 'user', 'parts': [{'text': q}]}],
'tools': [{'google_search': {}}]
}
print(json.dumps(body))
" "$query")
local api_response http_code body
api_response=$(curl -s -w '\n%{http_code}' -X POST "$API_URL" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${PPIO_API_KEY}" \
-d "$request_body" 2>/dev/null) || true
http_code=$(printf '%s' "$api_response" | tail -n1)
body=$(printf '%s' "$api_response" | sed '$d')
if [ "$http_code" != "200" ]; then
local err_text
err_text=$(printf '%s' "$body" | python3 -c "
import sys, json
try:
d = json.load(sys.stdin)
print(d.get('error', {}).get('message', 'API error'))
except: print('API request failed with status $http_code')
" 2>/dev/null)
local result
result=$(python3 -c "
import json, sys
text = sys.argv[1]
print(json.dumps({'jsonrpc':'2.0','id':${id},'result':{'content':[{'type':'text','text':text}],'isError':True}}))
" "$err_text")
send_response "$result"; return
fi
local result
result=$(printf '%s' "$body" | python3 -c '
import sys, json
data = json.load(sys.stdin)
parts = []
for candidate in data.get("candidates", []):
for part in candidate.get("content", {}).get("parts", []):
if "text" in part:
parts.append(part["text"])
search_queries, sources, supports = [], [], []
for candidate in data.get("candidates", []):
meta = candidate.get("groundingMetadata", {})
for q in meta.get("webSearchQueries", []):
search_queries.append(q)
chunks = meta.get("groundingChunks", [])
for chunk in chunks:
web = chunk.get("web", {})
uri = web.get("uri", "")
title = web.get("title", "")
domain = web.get("domain", "")
if uri:
sources.append("- [" + (title or domain or uri) + "](" + uri + ")")
for sup in meta.get("groundingSupports", []):
seg = sup.get("segment", {})
text = seg.get("text", "")
indices = sup.get("groundingChunkIndices", [])
if text and indices:
refs = [chunks[i].get("web", {}).get("title", chunks[i].get("web", {}).get("domain", "[" + str(i) + "]")) for i in indices if i < len(chunks)]
supports.append("- \"" + text + "\" -- " + ", ".join(refs))
output = "\n".join(parts)
if search_queries: output += "\n\n## Search Queries\n" + "\n".join("- " + q for q in search_queries)
if sources: output += "\n\n## Sources\n" + "\n".join(sources)
if supports: output += "\n\n## Grounding Details\n" + "\n".join(supports)
rpc_id = '"'"'${id}'"'"'
try: rpc_id = json.loads(rpc_id)
except: pass
print(json.dumps({"jsonrpc": "2.0", "id": rpc_id, "result": {"content": [{"type": "text", "text": output}]}}))
')
send_response "$result"
}
while IFS= read -r line; do
[ -z "$line" ] && continue
method=$(printf '%s' "$line" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('method',''))")
id=$(printf '%s' "$line" | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get('id')))")
case "$method" in
initialize) handle_initialize "$id" ;;
notifications/initialized) ;;
tools/list) handle_tools_list "$id" ;;
tools/call)
params=$(printf '%s' "$line" | python3 -c "import sys,json; print(json.dumps(json.load(sys.stdin).get('params',{})))")
handle_tools_call "$id" "$params" ;;
*) [ "$id" != "null" ] && send_error "$id" -32601 "Method not found: ${method}" ;;
esac
done
MCPEOF
chmod +x "$CLAUDE_DIR/mcp-servers/google-search.sh"
echo "Claude Code configured successfully."
echo "Just run: claude"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment