Skip to content

Return structured JSON instead of MCP protocol errors for invalid inputs in logs/audit/compile tools#24058

Merged
pelikhan merged 4 commits intomainfrom
copilot/fix-mcp-tools-json-response
Apr 2, 2026
Merged

Return structured JSON instead of MCP protocol errors for invalid inputs in logs/audit/compile tools#24058
pelikhan merged 4 commits intomainfrom
copilot/fix-mcp-tools-json-response

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 2, 2026

Three MCP tools throw protocol errors (-32602/-32603) for certain invalid inputs instead of returning structured JSON, breaking callers that expect consistent JSON responses.

Changes

logs — workflow not found → empty result set

  • Instead of throwing -32602 when validateMCPWorkflowName fails, return a valid LogsData JSON response with runs: [], zeroed summary, and a message field indicating the workflow was not found
  • Added Message string field (omitempty) to LogsData so the reason is conveyed without breaking existing callers
  • Explicit empty slice ensures "runs":[] (not null) in JSON output

audit — run not found → JSON error envelope

  • Instead of throwing -32603, return a JSON error object {"error": "...", "run_id_or_url": "..."} as tool content
  • Run ID is now always present in the response, making it actionable for callers

compile — Docker unavailable → per-workflow validation errors

  • Instead of throwing -32603 when CheckAndPrepareDockerImages fails, enumerate the target workflows and return a []ValidationResult with valid: false and a config_error entry per workflow
  • Added buildDockerErrorResults() helper that discovers workflow files automatically when no specific workflows are requested
  • Matches the existing structured format already used for other compile errors:
[{"workflow": "my-workflow", "valid": false, "errors": [{"type": "config_error", "message": "Docker is not available..."}], "warnings": []}]

Integration test update

  • Updated TestMCPServer_ErrorCodes_InternalError to assert that audit returns JSON content with error and run_id_or_url fields rather than an MCP protocol error
  • Extracted isTestEnvPermissionError helper to deduplicate CI-skip logic

…uts in logs/audit/compile tools

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/4b2dea1f-e4c0-4f4d-88e3-a09eb6b003b2

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix MCP tools to return structured JSON instead of exceptions Return structured JSON instead of MCP protocol errors for invalid inputs in logs/audit/compile tools Apr 2, 2026
Copilot AI requested a review from pelikhan April 2, 2026 11:39
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 2, 2026

@copilot Implement fixes

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 2, 2026

@copilot Implement fixes

Implemented in commit 8d99388. The three fixes are:

  1. logs — workflow not found: Instead of -32602, returns {"summary":{…zeroed…},"runs":[],"message":"workflow 'x' not found…"}.
  2. audit — run not found/failed: Instead of -32603, returns {"error":"failed to audit workflow run: …","run_id_or_url":"…"} as tool content so the run ID is always present.
  3. compile — Docker unavailable: Added buildDockerErrorResults() helper that enumerates the target workflows and returns [{"workflow":"x","valid":false,"errors":[{"type":"config_error","message":"docker is not available…"}],"warnings":[]}] — consistent with how other compile errors are returned.

The integration test for audit was also updated to assert JSON content is returned rather than an MCP protocol error.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GO111MODULE ache/go/1.25.0/x--show-toplevel git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE ache/go/1.25.0/x--show-toplevel git (http block)
  • https://api.github.com/orgs/test-owner/actions/secrets
    • Triggering command: /usr/bin/gh gh api /orgs/test-owner/actions/secrets --jq .secrets[].name GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE node (http block)
  • https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha --show-toplevel go /opt/hostedtoolcache/node/24.14.0/x64/bin/node -json GO111MODULE 64/bin/go node /tmp�� /home/REDACTED/work/gh-aw/gh-aw/.github/workflows/blog-auditor.md go /usr/bin/infocmp -json GO111MODULE 64/bin/go infocmp (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v3
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha -json GO111MODULE ache/node/24.14.0/x64/bin/node GOINSECURE GOMOD GOMODCACHE gh t-26�� sistency_KeyOrdering1027065490/001/test1.md --jq /usr/bin/git GOSUMDB GOWORK 64/bin/go git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v5
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE ache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha list --json /usr/bin/git --workflow nonexistent-workrev-parse --limit git rev-�� --show-toplevel x_amd64/link /usr/bin/git -json GO111MODULE 64/bin/go git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel go /usr/bin/git -json GO111MODULE bash git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE 0/x64/bin/node git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel -goversion /usr/bin/git ays.md -nolocalimports -importcfg git -C /tmp/gh-aw-test-runs/20260402-115222-29349/test-4097909177 status /usr/bin/git .github/workflowgit -trimpath 64/bin/go git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel go /usr/bin/git 5222-29349/test-git GO111MODULE .cfg git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE ache/go/1.25.0/x--show-toplevel git (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD erignore go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE node (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE sh -c npx prettier --cGOINSECURE GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go sh (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha --show-toplevel 9313482/b406/imp-importcfg /usr/bin/git k/gh-aw/gh-aw/pkgit GOPROXY 64/bin/go git chec�� .github/workflows/test.md /opt/hostedtoolc-extld=gcc /usr/bin/git /tmp/go-build166git -trimpath 64/bin/go git (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha uts.branch config /usr/bin/git remote.origin.urgit GOPROXY 64/bin/go git -C /tmp/gh-aw-test-runs/20260402-115222-29349/test-4097909177 rev-parse /usr/bin/git @{u} -trimpath 64/bin/go git (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v0.1.2
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v0.1.2 --jq .object.sha /tmp/go-build3499991205/b446/timeutil.test -importcfg /usr/bin/git -s -w -buildmode=exe git rev-�� --show-toplevel -extld=gcc /usr/bin/git /tmp/go-build166git -trimpath 64/bin/go git (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq .object.sha 5222-29349/test-4097909177 GO111MODULE 0/x64/bin/node l GOMOD GOMODCACHE go -has�� ithub/workflows/audit-workflows.md GO111MODULE ache/node/24.14.0/x64/bin/node GOINSECURE GOMOD GOMODCACHE /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linuREDACTED (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq .object.sha ithub/workflows/agent-persona-explorer.md GO111MODULE 9991205/b383/vet.cfg GOINSECURE GOMOD GOMODCACHE go ortc�� -json stmain.go ache/go/1.25.0/x64/pkg/tool/linux_amd64/link GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/x64/pkg/tool/linux_amd64/link (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts
    • Triggering command: /usr/bin/gh gh run download 1 --dir test-logs/run-1 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env 4271009014/.github/workflows GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts
    • Triggering command: /usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts
    • Triggering command: /usr/bin/gh gh run download 12346 --dir test-logs/run-12346 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts
    • Triggering command: /usr/bin/gh gh run download 2 --dir test-logs/run-2 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env 4271009014/.github/workflows GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts
    • Triggering command: /usr/bin/gh gh run download 3 --dir test-logs/run-3 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env 4271009014/.github/workflows GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts
    • Triggering command: /usr/bin/gh gh run download 4 --dir test-logs/run-4 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env 4271009014/.github/workflows GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts
    • Triggering command: /usr/bin/gh gh run download 5 --dir test-logs/run-5 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env 4271009014/.github/workflows GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE sh (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100 GOMOD GOMODCACHE sh -c &#34;prettier&#34; --che-errorsas GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go git (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6 GOMOD GOMODCACHE x_amd64/compile env d GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v0.47.4
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v0.47.4 --jq .object.sha --show-toplevel go /usr/bin/git -json GO111MODULE 64/bin/go git rev-�� --show-toplevel go /usr/bin/git edOutput71745907git GO111MODULE x_amd64/compile git (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha -json GO111MODULE At,event,headBranch,headSha,displayTitle GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.2.3 --jq .object.sha sdFl/I7quLUnZ5FkGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE _DylcajvvIkt -c k/gh-aw/gh-aw/pk-errorsas k/gh-aw/gh-aw/pk-ifaceassert 64/bin/go GOSUMDB GOWORK 64/bin/go /opt/hostedtoolc-tests (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v2.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha sH24/Sh1e_-bpvi7GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE 9313482/b407/imp-buildtags -c che/go-build/d5/-errorsas GOPROXY 64/bin/go iles use Prettiegit GOWORK 64/bin/go /opt/hostedtoolc-tests (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE node /hom�� --check **/*.cjs 64/bin/go **/*.json --ignore-path ../../../.prettiuser.email /opt/hostedtoolctest@example.com (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha T7yu/lu-oIEfj_EbGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE 9313482/b428/imp-importcfg /hom�� k/gh-aw/gh-aw/pk-s k/gh-aw/gh-aw/pk-w 64/bin/go **/*.json --ignore-path ../../../.pretti/tmp/compile-instructions-test-3501611032/.github/workflows /opt/hostedtoolcrev-parse (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v3.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v3.0.0 --jq .object.sha YPYY/8PAlU9pnoWDGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE 9313482/b418/impGOPROXY --ch�� che/go-build/a1/GOSUMDB **/*.ts 64/bin/go --ignore-path ../../../.pretti-C 64/bin/go /opt/hostedtoolcconfig (http block)
  • https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/nonexistent/repo/actions/runs/12345
    • Triggering command: /usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE js/uDCnOMIzC21Ht0aGmiv0/5puQaHSjhz6mE2DcpwiA env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/owner/repo/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE sh (http block)
  • https://api.github.com/repos/owner/repo/contents/file.md
    • Triggering command: /tmp/go-build3499991205/b396/cli.test /tmp/go-build3499991205/b396/cli.test -test.testlogfile=/tmp/go-build3499991205/b396/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/xGO111MODULE env 9313482/b413/_pkGOINSECURE GO111MODULE 64/bin/go GOINSECURE b/gh-aw/pkg/repoenv GOMODCACHE go (http block)
  • https://api.github.com/repos/test-owner/test-repo/actions/secrets
    • Triggering command: /usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)

If you need me to access, download, or install something from one of these locations, you can either:

@pelikhan pelikhan marked this pull request as ready for review April 2, 2026 12:03
Copilot AI review requested due to automatic review settings April 2, 2026 12:03
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts MCP tool behavior so logs, audit, and compile return structured JSON for certain invalid/error inputs instead of emitting MCP protocol errors, improving response consistency for callers.

Changes:

  • logs: return an empty LogsData JSON payload (with a message) when the workflow name is invalid/not found.
  • audit: return a JSON error envelope (error, run_id_or_url) in tool content instead of -32603.
  • compile: when Docker prep fails, return per-workflow []ValidationResult entries with config_error instead of -32603; update integration test expectations.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pkg/cli/mcp_tools_readonly.go Changes compile tool to return JSON validation results when Docker image prep fails; adds helper to generate per-workflow error results.
pkg/cli/mcp_tools_privileged.go Changes logs and audit tools to return JSON payloads instead of MCP protocol errors for specific invalid/error inputs.
pkg/cli/mcp_server_error_codes_test.go Updates integration test to assert audit returns JSON content (not MCP errors) and adds helper for CI permission-error skipping.
pkg/cli/logs_report.go Adds an optional message field to LogsData for conveying “workflow not found” without breaking existing callers.
.github/workflows/stale-repo-identifier.lock.yml Adjusts a job-level concurrency group to include a per-input discriminator.
.github/workflows/slide-deck-maintainer.lock.yml Adjusts a job-level concurrency group to include a per-input discriminator.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

results := buildDockerErrorResults(args.Workflows, err.Error())
jsonBytes, jsonErr := json.Marshal(results)
if jsonErr != nil {
return nil, nil, newMCPError(jsonrpc.CodeInternalError, err.Error(), nil)
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the json.Marshal failure path, the error message passed to newMCPError uses the Docker-prep error (err.Error()) rather than the marshal error (jsonErr). This makes debugging misleading; return an InternalError that references jsonErr (and ideally a clear message like "failed to marshal docker error results").

Suggested change
return nil, nil, newMCPError(jsonrpc.CodeInternalError, err.Error(), nil)
return nil, nil, newMCPError(jsonrpc.CodeInternalError, "failed to marshal docker error results", jsonErr.Error())

Copilot uses AI. Check for mistakes.
// Determine which workflow names to report
var workflowNames []string
if len(requestedWorkflows) > 0 {
for _, w := range requestedWorkflows {
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildDockerErrorResults derives workflow names via filepath.Base(w). When callers pass workflow IDs without an extension (common in MCP tests and CLI usage, e.g. "test1"), this will emit "test1" instead of the usual "test1.md" seen in normal compile ValidationResult outputs (compileWorkflowFile uses filepath.Base(resolvedFile) after resolveWorkflowFile appends .md). Consider normalizing requestedWorkflows the same way (append .md when missing, then Base) so error results match standard output.

Suggested change
for _, w := range requestedWorkflows {
for _, w := range requestedWorkflows {
// Normalize workflow identifiers so they match the standard compile output.
// If the caller passed an ID without an extension (e.g. "test1"),
// treat it as a markdown workflow file ("test1.md") before taking the basename.
if filepath.Ext(w) == "" {
w = w + ".md"
}

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +102
// Use an explicit empty slice for Runs so JSON marshaling produces "runs":[]
// rather than "runs":null (nil slice).
emptyData := LogsData{
Runs: []RunData{},
Message: err.Error(),
}
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The invalid-workflow early return only sets Runs (empty) and Message. Because LogsData.Episodes and LogsData.Edges are non-omitempty slices, they will marshal as null here (and Summary.TotalDuration will be ""), while normal logs output uses empty slices ([]) and a formatted duration string (timeutil.FormatDuration(0) => "0ns"). To keep the JSON shape consistent for callers, initialize Summary (at least TotalDuration) and set Episodes/Edges to empty slices as well.

Suggested change
// Use an explicit empty slice for Runs so JSON marshaling produces "runs":[]
// rather than "runs":null (nil slice).
emptyData := LogsData{
Runs: []RunData{},
Message: err.Error(),
}
// Use explicit empty slices so JSON marshaling produces "runs":[], etc.,
// rather than null (nil slices).
emptyData := LogsData{
Runs: []RunData{},
Episodes: []EpisodeData{},
Edges: []EdgeData{},
Message: err.Error(),
}
// Ensure Summary.TotalDuration matches the normal zero-duration formatting.
emptyData.Summary.TotalDuration = "0ns"

Copilot uses AI. Check for mistakes.
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 2, 2026

@copilot Review comments

…w IDs, initialize empty LogsData slices

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/94274ad0-c46c-4ff1-a6dd-82902d3516e6

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 2, 2026

@copilot Review comments

Addressed all three review comments in commit 95fd580:

  1. Marshal error message (mcp_tools_readonly.go:138): the json.Marshal failure path now passes jsonErr.Error() and the message "failed to marshal docker error results" instead of the unrelated Docker prep error.
  2. Workflow ID normalization (buildDockerErrorResults): workflow identifiers without a file extension (e.g. "test1") now get .md appended before filepath.Base is called, matching the standard compile output shape.
  3. Empty LogsData shape (mcp_tools_privileged.go): the not-found early return now initialises Episodes: []EpisodeData{}, Edges: []EpisodeEdge{}, and sets Summary.TotalDuration = "0ns" so the JSON shape is consistent with normal zero-result output.

@pelikhan pelikhan merged commit b471688 into main Apr 2, 2026
49 of 51 checks passed
@pelikhan pelikhan deleted the copilot/fix-mcp-tools-json-response branch April 2, 2026 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[cli-tools-test] MCP tools return exceptions instead of structured JSON for some invalid inputs

3 participants