diff --git a/.github/workflows/shared/opencode.md b/.github/workflows/shared/opencode.md index a0344570ca..b8945779bc 100644 --- a/.github/workflows/shared/opencode.md +++ b/.github/workflows/shared/opencode.md @@ -5,11 +5,72 @@ engine: GH_AW_AGENT_VERSION: "0.15.13" GH_AW_AGENT_MODEL: "anthropic/claude-3-5-sonnet-20241022" steps: - - name: Install OpenCode - run: npm install -g opencode-ai@${GH_AW_AGENT_VERSION} + - name: Install OpenCode and jq + run: | + npm install -g opencode-ai@${GH_AW_AGENT_VERSION} + sudo apt-get update && sudo apt-get install -y jq env: GH_AW_AGENT_VERSION: ${{ env.GH_AW_AGENT_VERSION }} + - name: Configure OpenCode MCP servers + run: | + set -e + + # Create OpenCode config directory + mkdir -p ~/.config/opencode + + # Check if MCP config exists + if [ -n "$GH_AW_MCP_CONFIG" ] && [ -f "$GH_AW_MCP_CONFIG" ]; then + echo "Found MCP configuration at: $GH_AW_MCP_CONFIG" + + # Create base OpenCode config with proper schema + echo '{"$schema": "https://opencode.sh/schema.json", "mcp": {}}' > ~/.config/opencode/opencode.json + + # Transform Copilot-style MCP config to OpenCode format + jq -r '.mcpServers | to_entries[] | + if .value.type == "local" or (.value.command and .value.args) then + { + key: .key, + value: { + type: "local", + command: ( + if .value.command then + [.value.command] + (.value.args // []) + else + [] + end + ), + enabled: true, + environment: (.value.env // {}) + } + } + elif .value.type == "http" then + { + key: .key, + value: { + type: "remote", + url: .value.url, + enabled: true, + headers: (.value.headers // {}) + } + } + else empty end' "$GH_AW_MCP_CONFIG" | \ + jq -s 'reduce .[] as $item ({}; .[$item.key] = $item.value)' > /tmp/mcp-servers.json + + # Merge MCP servers into config + jq --slurpfile servers /tmp/mcp-servers.json '.mcp = $servers[0]' \ + ~/.config/opencode/opencode.json > /tmp/opencode-final.json + mv /tmp/opencode-final.json ~/.config/opencode/opencode.json + + echo "✅ OpenCode MCP configuration created successfully" + echo "Configuration contents:" + cat ~/.config/opencode/opencode.json | jq . + else + echo "⚠️ No MCP config found - OpenCode will run without MCP tools" + fi + env: + GH_AW_MCP_CONFIG: ${{ env.GH_AW_MCP_CONFIG }} + - name: Run OpenCode id: opencode run: | @@ -49,8 +110,21 @@ engine: --- ``` +**MCP Server Integration:** +OpenCode automatically integrates with MCP servers configured in your workflow: + +1. **Automatic Configuration**: MCP servers defined in your workflow's `tools:` or `mcp-servers:` + sections are automatically configured for OpenCode +2. **Format Transformation**: The Copilot-style MCP config at `$GH_AW_MCP_CONFIG` is transformed + to OpenCode's format at `~/.config/opencode/opencode.json` +3. **Server Types Supported**: + - `local` servers (stdio): Command and args are merged into a single command array + - `remote` servers (http): URL and headers are preserved for HTTP-based MCP servers +4. **Environment Variables**: All environment variables from MCP server configs are preserved + **Requirements:** - The workflow will install opencode-ai npm package using version from `GH_AW_AGENT_VERSION` env var +- `jq` is installed for JSON transformation between MCP config formats - The prompt file is read directly in the Run OpenCode step using command substitution - OpenCode is executed in non-interactive mode with logs printed to stderr - Output is captured in the agent log file @@ -58,6 +132,7 @@ engine: **Environment Variables:** - `GH_AW_AGENT_VERSION`: OpenCode version (default: `0.15.13`) - `GH_AW_AGENT_MODEL`: AI model in `provider/model` format (default: `anthropic/claude-3-5-sonnet-20241022`) +- `GH_AW_MCP_CONFIG`: Path to MCP config JSON file (automatically set by gh-aw) - `ANTHROPIC_API_KEY`: Required if using Anthropic models - `OPENAI_API_KEY`: Required if using OpenAI models @@ -66,4 +141,5 @@ engine: - The opencode version can be customized by setting the `GH_AW_AGENT_VERSION` environment variable - The AI model can be customized by setting the `GH_AW_AGENT_MODEL` environment variable - OpenCode is provider-agnostic and supports multiple LLM providers +- MCP servers are configured automatically if the workflow includes MCP tools (github, playwright, safe-outputs, etc.) --> diff --git a/.github/workflows/smoke-opencode.lock.yml b/.github/workflows/smoke-opencode.lock.yml index 00de8be1de..7bc266a2d2 100644 --- a/.github/workflows/smoke-opencode.lock.yml +++ b/.github/workflows/smoke-opencode.lock.yml @@ -1106,8 +1106,74 @@ jobs: name: aw_info.json path: /tmp/gh-aw/aw_info.json if-no-files-found: warn - - name: Install OpenCode - run: npm install -g opencode-ai@${GH_AW_AGENT_VERSION} + - name: Install OpenCode and jq + run: | + npm install -g opencode-ai@${GH_AW_AGENT_VERSION} + sudo apt-get update && sudo apt-get install -y jq + env: + GH_AW_AGENT_MODEL: anthropic/claude-3-5-sonnet-20241022 + GH_AW_AGENT_VERSION: 0.15.13 + GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/mcp-servers.json + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} + GH_AW_SAFE_OUTPUTS_CONFIG: "\"{\\\"create_issue\\\":{\\\"max\\\":1,\\\"min\\\":1},\\\"missing_tool\\\":{}}\"" + GH_AW_SAFE_OUTPUTS_STAGED: "true" + - name: Configure OpenCode MCP servers + run: | + set -e + + # Create OpenCode config directory + mkdir -p ~/.config/opencode + + # Check if MCP config exists + if [ -n "$GH_AW_MCP_CONFIG" ] && [ -f "$GH_AW_MCP_CONFIG" ]; then + echo "Found MCP configuration at: $GH_AW_MCP_CONFIG" + + # Create base OpenCode config with proper schema + echo '{"$schema": "https://opencode.sh/schema.json", "mcp": {}}' > ~/.config/opencode/opencode.json + + # Transform Copilot-style MCP config to OpenCode format + jq -r '.mcpServers | to_entries[] | + if .value.type == "local" or (.value.command and .value.args) then + { + key: .key, + value: { + type: "local", + command: ( + if .value.command then + [.value.command] + (.value.args // []) + else + [] + end + ), + enabled: true, + environment: (.value.env // {}) + } + } + elif .value.type == "http" then + { + key: .key, + value: { + type: "remote", + url: .value.url, + enabled: true, + headers: (.value.headers // {}) + } + } + else empty end' "$GH_AW_MCP_CONFIG" | \ + jq -s 'reduce .[] as $item ({}; .[$item.key] = $item.value)' > /tmp/mcp-servers.json + + # Merge MCP servers into config + jq --slurpfile servers /tmp/mcp-servers.json '.mcp = $servers[0]' \ + ~/.config/opencode/opencode.json > /tmp/opencode-final.json + mv /tmp/opencode-final.json ~/.config/opencode/opencode.json + + echo "✅ OpenCode MCP configuration created successfully" + echo "Configuration contents:" + cat ~/.config/opencode/opencode.json | jq . + else + echo "⚠️ No MCP config found - OpenCode will run without MCP tools" + fi env: GH_AW_AGENT_MODEL: anthropic/claude-3-5-sonnet-20241022 GH_AW_AGENT_VERSION: 0.15.13 @@ -2365,8 +2431,74 @@ jobs: run: | mkdir -p /tmp/gh-aw/threat-detection touch /tmp/gh-aw/threat-detection/detection.log - - name: Install OpenCode - run: npm install -g opencode-ai@${GH_AW_AGENT_VERSION} + - name: Install OpenCode and jq + run: | + npm install -g opencode-ai@${GH_AW_AGENT_VERSION} + sudo apt-get update && sudo apt-get install -y jq + env: + GH_AW_AGENT_MODEL: anthropic/claude-3-5-sonnet-20241022 + GH_AW_AGENT_VERSION: 0.15.13 + GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/mcp-servers.json + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} + GH_AW_SAFE_OUTPUTS_CONFIG: "\"{\\\"create_issue\\\":{\\\"max\\\":1,\\\"min\\\":1},\\\"missing_tool\\\":{}}\"" + GH_AW_SAFE_OUTPUTS_STAGED: "true" + - name: Configure OpenCode MCP servers + run: | + set -e + + # Create OpenCode config directory + mkdir -p ~/.config/opencode + + # Check if MCP config exists + if [ -n "$GH_AW_MCP_CONFIG" ] && [ -f "$GH_AW_MCP_CONFIG" ]; then + echo "Found MCP configuration at: $GH_AW_MCP_CONFIG" + + # Create base OpenCode config with proper schema + echo '{"$schema": "https://opencode.sh/schema.json", "mcp": {}}' > ~/.config/opencode/opencode.json + + # Transform Copilot-style MCP config to OpenCode format + jq -r '.mcpServers | to_entries[] | + if .value.type == "local" or (.value.command and .value.args) then + { + key: .key, + value: { + type: "local", + command: ( + if .value.command then + [.value.command] + (.value.args // []) + else + [] + end + ), + enabled: true, + environment: (.value.env // {}) + } + } + elif .value.type == "http" then + { + key: .key, + value: { + type: "remote", + url: .value.url, + enabled: true, + headers: (.value.headers // {}) + } + } + else empty end' "$GH_AW_MCP_CONFIG" | \ + jq -s 'reduce .[] as $item ({}; .[$item.key] = $item.value)' > /tmp/mcp-servers.json + + # Merge MCP servers into config + jq --slurpfile servers /tmp/mcp-servers.json '.mcp = $servers[0]' \ + ~/.config/opencode/opencode.json > /tmp/opencode-final.json + mv /tmp/opencode-final.json ~/.config/opencode/opencode.json + + echo "✅ OpenCode MCP configuration created successfully" + echo "Configuration contents:" + cat ~/.config/opencode/opencode.json | jq . + else + echo "⚠️ No MCP config found - OpenCode will run without MCP tools" + fi env: GH_AW_AGENT_MODEL: anthropic/claude-3-5-sonnet-20241022 GH_AW_AGENT_VERSION: 0.15.13 diff --git a/docs/src/content/docs/status.md b/docs/src/content/docs/status.md index 6acac78f2f..49c79487bf 100644 --- a/docs/src/content/docs/status.md +++ b/docs/src/content/docs/status.md @@ -10,6 +10,7 @@ This page shows the current status of all agentic workflows in the repository. - [![Agentic Workflow Audit Agent](https://github.com/githubnext/gh-aw/actions/workflows/audit-workflows.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/audit-workflows.lock.yml) - [![Artifacts Summary](https://github.com/githubnext/gh-aw/actions/workflows/artifacts-summary.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/artifacts-summary.lock.yml) - [![Basic Research Agent](https://github.com/githubnext/gh-aw/actions/workflows/research.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/research.lock.yml) +- [![Blog Auditor](https://github.com/githubnext/gh-aw/actions/workflows/blog-auditor.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/blog-auditor.lock.yml) - [![Brave Web Search Agent](https://github.com/githubnext/gh-aw/actions/workflows/brave.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/brave.lock.yml) - [![Changeset Generator](https://github.com/githubnext/gh-aw/actions/workflows/changeset-generator.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/changeset-generator.lock.yml) - [![CI Failure Doctor](https://github.com/githubnext/gh-aw/actions/workflows/ci-doctor.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/ci-doctor.lock.yml)