5a558eb09e
Backend Tests / discover-tests (push) Waiting to run
Backend Tests / ${{ matrix.name }} (push) Blocked by required conditions
Build and Publish SDK / build-and-publish (push) Waiting to run
Build Opik Docker Images / set-version (push) Waiting to run
Build Opik Docker Images / build-backend (push) Blocked by required conditions
Build Opik Docker Images / build-sandbox-executor-python (push) Blocked by required conditions
Build Opik Docker Images / build-python-backend (push) Blocked by required conditions
Build Opik Docker Images / build-frontend (push) Blocked by required conditions
Build Opik Docker Images / create-git-tag (push) Blocked by required conditions
ClickHouse Migration Cluster Check / validate-clickhouse-migrations (push) Waiting to run
Docs - Publish / run (push) Waiting to run
E2E Tests - Post Merge (v2) / 🧪 E2E v2 Tests (${{ github.event.inputs.tier || 't1' }}) (push) Waiting to run
E2E Tests - Post Merge (v2) / 📢 Slack Notification (push) Blocked by required conditions
Frontend Unit Tests / Test on Node 20 (push) Waiting to run
Guardrails E2E Tests / Select Python version matrix (push) Waiting to run
Guardrails E2E Tests / Guardrails E2E Tests ${{matrix.python_version}} (push) Blocked by required conditions
Guardrails E2E Tests / 📢 Slack Notification (push) Blocked by required conditions
Guardrails Backend Unit Tests / Guardrails Backend Unit Tests (push) Waiting to run
Guardrails Backend Unit Tests / 📢 Slack Notification (push) Blocked by required conditions
SDK Library Integration Tests Runner / Check Secrets (push) Waiting to run
SDK Library Integration Tests Runner / Missed OpenAI API Key Warning (push) Blocked by required conditions
SDK Library Integration Tests Runner / Build (push) Blocked by required conditions
SDK Library Integration Tests Runner / openai_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / langchain_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / langchain_legacy_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / llama_index_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / anthropic_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / mistral_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / groq_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / aisuite_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / haystack_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / dspy_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / crewai_v0_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / crewai_v1_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / genai_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / adk_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / adk_legacy_1_3_0_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / evaluation_metrics_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / bedrock_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / litellm_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / harbor_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / Slack Notification (push) Blocked by required conditions
Lint Opik Helm Chart / lint-helm-chart (Helm v3.21.0) (push) Waiting to run
Lint Opik Helm Chart / lint-helm-chart (Helm v4.2.0) (push) Waiting to run
Lint Opik Helm Chart / unittest-helm-chart (push) Waiting to run
Lint Opik Helm Chart / render-equality (push) Waiting to run
Opik Optimizer - Unit Tests / Opik Optimizer Unit Tests Python ${{matrix.python_version}} (push) Waiting to run
Python BE E2E Tests / Python BE E2E (push) Waiting to run
Python Backend Tests / run-python-backend-tests (push) Waiting to run
Python SDK Unit Tests / Python SDK Unit Tests ${{matrix.python_version}} (push) Waiting to run
Release Drafter / update_release_draft (push) Waiting to run
SDK E2E Libraries Integration Tests / Check Secrets (push) Waiting to run
SDK E2E Libraries Integration Tests / Missed OpenAI API Key Warning (push) Blocked by required conditions
SDK E2E Libraries Integration Tests / build-opik (push) Blocked by required conditions
SDK E2E Libraries Integration Tests / E2E Lib Integration Python ${{matrix.python_version}} (push) Blocked by required conditions
TypeScript SDK Integration Build & Publish / build-and-publish (opik-gemini) (push) Waiting to run
TypeScript SDK Integration Build & Publish / build-and-publish (opik-langchain) (push) Waiting to run
TypeScript SDK Integration Build & Publish / build-and-publish (opik-openai) (push) Waiting to run
TypeScript SDK Integration Build & Publish / build-and-publish (opik-otel) (push) Waiting to run
TypeScript SDK Integration Build & Publish / build-and-publish (opik-vercel) (push) Waiting to run
TypeScript SDK Library Integration Tests / Check Secrets (push) Waiting to run
TypeScript SDK Library Integration Tests / opik-vercel (Vercel AI SDK / eve) (push) Blocked by required conditions
TypeScript SDK Build & Publish / build-and-publish (push) Waiting to run
TypeScript SDK Unit Tests / Test on Node ${{ matrix.node-version }} (push) Waiting to run
TypeScript SDK Compatibility V1.x E2E Tests / Select Node version matrix (push) Has been cancelled
TypeScript SDK Compatibility V1.x E2E Tests / TypeScript SDK Compatibility V1.x E2E Tests Node ${{matrix.node_version}} (push) Has been cancelled
TypeScript SDK E2E Tests / TypeScript SDK E2E Tests Node ${{matrix.node_version}} (push) Has been cancelled
Opik Optimizer - E2E Tests / build-opik (push) Has been cancelled
TypeScript SDK Compatibility V1.x E2E Tests / build-opik (push) Has been cancelled
Python SDK E2E Tests / Select Python version matrix (push) Has been cancelled
Python SDK E2E Tests / Python SDK E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Python SDK E2E Tests / build-opik (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / Select Python version matrix (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / Python SDK Compatibility V1.x E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / build-opik (push) Has been cancelled
TypeScript SDK E2E Tests / Select Node version matrix (push) Has been cancelled
TypeScript SDK E2E Tests / build-opik (push) Has been cancelled
Opik Optimizer - E2E Tests / Opik Optimizer E2E Tests Python ${{matrix.python_version}} (push) Has been cancelled
Opik Optimizer - E2E Tests / Opik Optimizer Integration Smoke Tests (push) Has been cancelled
🐙 Code Quality / detect (push) Has been cancelled
🐙 Code Quality / lint (${{ matrix.leg.name }}) (push) Has been cancelled
🐙 Code Quality / summary (push) Has been cancelled
189 lines
5.7 KiB
Bash
Executable File
189 lines
5.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Convert .agents/mcp.json (Cursor format) to .mcp.json (Claude CLI format)
|
|
# Usage: convert-mcp.sh <input-file> <output-file>
|
|
#
|
|
# Transformations:
|
|
# 1. Replace ${workspaceFolder}/ with empty string in all paths
|
|
# 2. For docker commands with envFile:
|
|
# - Add --env-file <path> to args (after --rm if present, otherwise prepend)
|
|
# - Remove -e VARNAME pairs (where VARNAME has no =)
|
|
# - Remove the envFile property
|
|
# 3. For non-docker commands with envFile:
|
|
# - Parse the env file and merge into .env map
|
|
# - Remove the envFile property
|
|
|
|
set -euo pipefail
|
|
|
|
input="${1:-}"
|
|
output="${2:-}"
|
|
|
|
if [[ -z "$input" || -z "$output" ]]; then
|
|
echo "Usage: convert-mcp.sh <input-file> <output-file>" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "$input" ]]; then
|
|
echo "Error: Input file '$input' does not exist" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v jq &> /dev/null; then
|
|
echo "Error: jq is required but not installed" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Validate input is valid JSON
|
|
if ! jq empty "$input" 2>/dev/null; then
|
|
echo "Error: Input file '$input' is not valid JSON" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Helper function to parse env file into JSON object
|
|
# Handles: missing files, empty files, comment-only files, special characters
|
|
parse_env_file() {
|
|
local file="$1"
|
|
if [[ ! -f "$file" ]]; then
|
|
echo "{}"
|
|
return
|
|
fi
|
|
|
|
# Use jq to properly escape values for JSON safety
|
|
local pairs=()
|
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
# Skip empty lines and comments
|
|
[[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
|
|
# Must contain =
|
|
[[ "$line" != *"="* ]] && continue
|
|
|
|
# Split on first = only
|
|
key="${line%%=*}"
|
|
value="${line#*=}"
|
|
|
|
# Trim whitespace from key
|
|
key="${key#"${key%%[![:space:]]*}"}"
|
|
key="${key%"${key##*[![:space:]]}"}"
|
|
|
|
# Skip if key is empty
|
|
[[ -z "$key" ]] && continue
|
|
|
|
# Clean ${workspaceFolder}/ from value
|
|
value="${value//\$\{workspaceFolder\}\//}"
|
|
|
|
# Use jq to safely escape both key and value
|
|
pairs+=("$(jq -n --arg k "$key" --arg v "$value" '{($k): $v}')")
|
|
done < "$file"
|
|
|
|
# Merge all pairs into single object
|
|
if [[ ${#pairs[@]} -eq 0 ]]; then
|
|
echo "{}"
|
|
else
|
|
printf '%s\n' "${pairs[@]}" | jq -s 'add // {}'
|
|
fi
|
|
}
|
|
|
|
# Pre-parse env files for non-docker commands
|
|
# Build a JSON object mapping cleaned envFile path -> parsed env vars
|
|
env_data="{}"
|
|
|
|
# Check if mcpServers exists and has entries
|
|
if jq -e '.mcpServers // empty | keys | length > 0' "$input" >/dev/null 2>&1; then
|
|
while IFS= read -r env_path; do
|
|
[[ -z "$env_path" ]] && continue
|
|
parsed=$(parse_env_file "$env_path")
|
|
[[ "$parsed" == "{}" ]] && continue
|
|
env_data=$(echo "$env_data" | jq --arg path "$env_path" --argjson vars "$parsed" '. + {($path): $vars}')
|
|
done < <(jq -r '
|
|
.mcpServers // {} | to_entries[] |
|
|
select(.value.envFile and .value.command != "docker") |
|
|
.value.envFile |
|
|
gsub("\\$\\{workspaceFolder\\}/"; "")
|
|
' "$input" 2>/dev/null | sort -u)
|
|
fi
|
|
|
|
jq --argjson envData "$env_data" '
|
|
# Helper: clean ${workspaceFolder}/ from paths
|
|
def clean_path:
|
|
if type == "string" then gsub("\\$\\{workspaceFolder\\}/"; "") else . end;
|
|
|
|
# Helper: safely get array, defaulting null/non-array to []
|
|
def safe_array:
|
|
if type == "array" then . else [] end;
|
|
|
|
# Helper: safely get object, defaulting null/non-object to {}
|
|
def safe_object:
|
|
if type == "object" then . else {} end;
|
|
|
|
# Helper: remove -e VARNAME pairs where VARNAME has no = (env vars provided by env-file)
|
|
def remove_standalone_env_vars:
|
|
safe_array |
|
|
. as $arr |
|
|
reduce range(0; $arr | length) as $i (
|
|
{result: [], skip: false};
|
|
if .skip then
|
|
.skip = false
|
|
elif ($arr[$i] == "-e") and ($i + 1 < ($arr | length)) and (($arr[$i + 1] // "") | tostring | contains("=") | not) then
|
|
.skip = true
|
|
else
|
|
.result += [$arr[$i]]
|
|
end
|
|
) | .result;
|
|
|
|
# Helper: insert --env-file into args
|
|
# Tries to insert after --rm; if --rm not found, prepends to args
|
|
def insert_env_file($path):
|
|
safe_array |
|
|
if any(. == "--rm") then
|
|
# Insert after --rm
|
|
reduce .[] as $item (
|
|
[];
|
|
. + [$item] + (if $item == "--rm" then ["--env-file", $path] else [] end)
|
|
)
|
|
else
|
|
# Prepend --env-file to args
|
|
["--env-file", $path] + .
|
|
end;
|
|
|
|
# Main transformation - handle missing/null mcpServers gracefully
|
|
if .mcpServers | type == "object" then
|
|
.mcpServers |= with_entries(
|
|
# Skip null server entries
|
|
if .value | type != "object" then .
|
|
else
|
|
.value |= (
|
|
# Get cleaned envFile path if present and non-empty
|
|
(if (.envFile // "") | length > 0 then (.envFile | clean_path) else null end) as $envPath |
|
|
|
|
# Transform based on command type
|
|
if .command == "docker" and $envPath then
|
|
# Docker: move envFile to --env-file arg, remove standalone -e vars
|
|
.args = (.args | remove_standalone_env_vars | insert_env_file($envPath)) |
|
|
del(.envFile)
|
|
elif $envPath then
|
|
# Non-docker: parse envFile and merge into .env map
|
|
# (Claude CLI only expands envFile for docker commands)
|
|
($envData[$envPath] // {}) as $parsedEnv |
|
|
.env = ((.env | safe_object) + $parsedEnv) |
|
|
del(.envFile)
|
|
else
|
|
.
|
|
end |
|
|
|
|
# Clean ${workspaceFolder}/ from cwd if present
|
|
if .cwd then .cwd |= clean_path else . end |
|
|
|
|
# Clean ${workspaceFolder}/ from env values if present
|
|
if .env | type == "object" then
|
|
.env |= with_entries(
|
|
if .value | type == "string" then .value |= clean_path else . end
|
|
)
|
|
else . end
|
|
)
|
|
end
|
|
)
|
|
else
|
|
.
|
|
end
|
|
' "$input" > "$output"
|
|
|
|
echo " Converted MCP config: $input -> $output"
|