Add OutputSchema to status and compile MCP server tools#16929
Add OutputSchema to status and compile MCP server tools#16929
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds MCP OutputSchema support for the status and compile tools so MCP clients can understand the structured response shape ahead of time, while preserving the existing text (JSON array) output for backward compatibility. It also updates multiple compiled workflow .lock.yml files, primarily expanding firewall allowlisted domains.
Changes:
- Add wrapper output types and attach generated object
OutputSchemato MCPstatusandcompiletools; return wrapper objects as structured output while keeping text JSON arrays. - Parse
compilesubprocess JSON output into[]ValidationResultto populate structured output when possible. - Update numerous workflow
.lock.ymlfiles (notably expanding--allow-domains/GH_AW_ALLOWED_DOMAINSlists).
Reviewed changes
Copilot reviewed 37 out of 37 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/cli/mcp_server.go | Adds object-wrapped OutputSchema for status/compile and returns structured wrapper results. |
| pkg/cli/mcp_tool_schemas_test.go | Adds tests ensuring wrapper schemas are objects with expected top-level properties. |
| .github/workflows/workflow-normalizer.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/weekly-issue-summary.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/stale-repo-identifier.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/smoke-test-tools.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/smoke-temporary-id.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/smoke-project.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/smoke-macos-arm64.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/smoke-copilot.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/slide-deck-maintainer.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/research.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/release.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/python-data-charts.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/prompt-clustering-analysis.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/portfolio-analyst.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/org-health-report.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/mcp-inspector.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/jsweep.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/github-mcp-structural-analysis.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/firewall.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/firewall-escape.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/docs-noob-tester.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/deep-report.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/daily-repo-chronicle.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/daily-news.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/daily-multi-device-docs-tester.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/daily-issues-report.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/daily-copilot-token-report.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/daily-code-metrics.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/copilot-session-insights.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/copilot-pr-prompt-analysis.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/copilot-pr-nlp-analysis.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/cli-version-checker.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/cli-consistency-checker.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/changeset.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
| .github/workflows/artifacts-summary.lock.yml | Updates compiled workflow; expands firewall allowlisted domains. |
Comments suppressed due to low confidence (2)
pkg/cli/mcp_server.go:461
- If schema generation fails, this returns the server early and the
statustool is never registered. Since schema generation issues shouldn't disable a core tool, consider logging the error and registering the tool withoutOutputSchema(nil) as a fallback instead of returning here.
pkg/cli/mcp_server.go:584 - Same as
status: the description says this tool returns a JSON array, butOutputSchemanow describes an object wrapper ({"results": [...]}) and structured output follows that shape. Please update the description to document both the structured wrapper and the backward-compatible text array.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| set -o pipefail | ||
| sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains '*.jsr.io,*.pythonhosted.org,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,binstar.org,bootstrap.pypa.io,bun.sh,conda.anaconda.org,conda.binstar.org,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,deb.nodesource.com,deno.land,files.pythonhosted.org,get.pnpm.io,github.com,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.yarnpkg.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.npmjs.com,www.npmjs.org,yarnpkg.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.20.1 --skip-pull --enable-api-proxy \ | ||
| sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains '*.jsr.io,*.pythonhosted.org,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,binstar.org,bootstrap.pypa.io,bun.sh,cdn.jsdelivr.net,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,deb.nodesource.com,deno.land,esm.sh,files.pythonhosted.org,get.pnpm.io,github.com,googleapis.deno.dev,googlechromelabs.github.io,host.docker.internal,index.crates.io,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.yarnpkg.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,static.crates.io,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.npmjs.com,www.npmjs.org,yarnpkg.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.20.1 --skip-pull --enable-api-proxy \ | ||
| -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log |
There was a problem hiding this comment.
This PR broadens the firewall --allow-domains list in the compiled workflow lock file (e.g., adding cdn.jsdelivr.net, crates.io, esm.sh, etc.). Since this relaxes network egress constraints, please confirm these additions are intentional/required and ideally explain why in the PR description (or split into a separate PR if unrelated to MCP OutputSchema).
| compileOutputSchema, err := GenerateSchema[compileResult]() | ||
| if err != nil { | ||
| mcpLog.Printf("Failed to generate compile output schema: %v", err) | ||
| return server | ||
| } |
There was a problem hiding this comment.
If output schema generation fails, this returns the server early and the compile tool is never registered. Consider registering the tool without OutputSchema (nil) as a fallback so MCP server still provides compile even if schema generation breaks.
This issue also appears on line 457 of the same file.
| Description: `Show status of agentic workflow files and workflows. | ||
|
|
||
| Returns a JSON array where each element has the following structure: | ||
| - workflow: Name of the workflow file | ||
| - agent: AI engine used (e.g., "copilot", "claude", "codex") | ||
| - compiled: Whether the workflow is compiled ("Yes", "No", or "N/A") | ||
| - status: GitHub workflow status ("active", "disabled", "Unknown") | ||
| - time_remaining: Time remaining until workflow deadline (if applicable)`, | ||
| OutputSchema: statusOutputSchema, |
There was a problem hiding this comment.
The tool description still states the response is a JSON array, but OutputSchema now advertises an object ({"workflows": [...]}) and structured output returns that wrapper. Update the description to explicitly document the structured vs text response shapes to avoid confusing MCP clients.
This issue also appears on line 567 of the same file.
| // Parse the JSON output into ValidationResults for structured content. | ||
| // Keep the flat array in TextContent for backward compatibility. | ||
| var results []ValidationResult | ||
| if jsonErr := json.Unmarshal(stdout, &results); jsonErr == nil { | ||
| return &mcp.CallToolResult{ | ||
| Content: []mcp.Content{ | ||
| &mcp.TextContent{Text: outputStr}, | ||
| }, | ||
| }, compileResult{Results: results}, nil | ||
| } |
There was a problem hiding this comment.
When JSON parsing fails, the tool returns no structured content even though it advertises an OutputSchema. At minimum, log the unmarshal error to aid debugging; alternatively, consider returning a jsonrpc error (while still including TextContent) because the handler can't satisfy the advertised schema in this case.
MCP SDK v1.2.0+ supports structured
OutputSchemaon tools, enabling LLM clients to understand response structure before calling. Thestatusandcompiletools have well-defined JSON response structures making them ideal candidates.Changes
Wrapper structs (MCP requires
type: "object"schemas — arrays are rejected with a panic):Schema generation + attachment in
pkg/cli/mcp_server.go:GenerateSchema[statusResult]()→ attached asOutputSchemaon thestatustoolGenerateSchema[compileResult]()→ attached asOutputSchemaon thecompiletoolBackward-compatible output: handlers return the wrapper struct as the second value (populates
StructuredContent) while keeping the existing flat JSON array inTextContent. Compile tool parses subprocess JSON output into[]ValidationResultbefore wrapping; falls back to text-only if parsing fails.Tests added in
mcp_tool_schemas_test.goverifying both wrapper schemas are valid objects with the expectedworkflows/resultsproperties.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/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 -c=4 -nolocalimports git init�� -pack /tmp/go-build1609364112/b386/_testmain.go /usr/bin/git(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v3/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha /var/log(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v4 --jq .object.sha vaScript4031224889/001/test-frontmatter-with-env-template-expressions.md /tmp/go-build1670619015/b023/vet.cfg /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v4 --jq .object.sha 7 /tmp/go-build1670619015/b030/vet-ifaceassert /opt/hostedtoolcache/go/1.25.0/x-nilfunc(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v4 --jq .object.sha y rev-parse /usr/bin/git(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v5/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha te '**/*.cjs' '**/*.ts' '**/*.js-c=4 .cfg 64/pkg/tool/linux_amd64/vet(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha ErrorFormatting1473531992/001 -importcfg ipts.test -s -w -buildmode=exe ipts.test 6093�� bility_SameInputSameOutput354231923/001/stability-test.md -importcfg /usr/bin/git -s -w -buildmode=exe git(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha user.email test@example.com /usr/bin/git(http block)https://api.github.com/repos/actions/github-script/git/ref/tags/v8/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha go1.25.0 -c=4 -nolocalimports -importcfg /tmp/go-build1609364112/b392/importcfg -pack /tmp/go-build1609364112/b392/_testmain.go(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha -c=4 -nolocalimports -importcfg /tmp/go-build1609364112/b394/importcfg -pack /home/REDACTED/work/gh-aw/gh-aw/pkg/fileutil/fileutil.go /home/REDACTED/work/gh-aw/gh-aw/pkg/fileutil/fileutil_test.go(http block)https://api.github.com/repos/actions/setup-go/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha -unreachable=false /tmp/go-build1670619015/b026/vet.cfg 0619015/b289/vet.cfg(http block)https://api.github.com/repos/actions/setup-node/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha brave.md /tmp/go-build1670619015/b025/vetREDACTED .cfg(http block)https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts/usr/bin/gh gh run download 1 --dir test-logs/run-1(http block)/usr/bin/gh gh run download 1 --dir test-logs/run-1 ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet /usr/bin/git 2426-12305/test-git 0619015/b160/vetrev-parse ache/go/1.25.0/x--show-toplevel git rev-�� --show-toplevel ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet /usr/bin/gh "prettier" --wrigit(http block)https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts/usr/bin/gh gh run download 12345 --dir test-logs/run-12345(http block)/usr/bin/gh gh run download 12345 --dir test-logs/run-12345 ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet /usr/bin/git 2646331971 0619015/b151/vet-C ache/go/1.25.0/x/tmp/gh-aw-test-runs/20260219-222728-16209/test-1641750893 git rev-�� --show-toplevel ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet /usr/bin/git se 0619015/b280/vetrev-parse clusion,workflow--show-toplevel git(http block)https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts/usr/bin/gh gh run download 12346 --dir test-logs/run-12346(http block)/usr/bin/gh gh run download 12346 --dir test-logs/run-12346 ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet /usr/bin/git "prettier" --wrigit(http block)https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts/usr/bin/gh gh run download 2 --dir test-logs/run-2(http block)/usr/bin/gh gh run download 2 --dir test-logs/run-2 ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet /usr/bin/git 01/main.md(http block)https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts/usr/bin/gh gh run download 3 --dir test-logs/run-3(http block)/usr/bin/gh gh run download 3 --dir test-logs/run-3 ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet /usr/bin/git 2426-12305/test-git(http block)https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts/usr/bin/gh gh run download 4 --dir test-logs/run-4(http block)/usr/bin/gh gh run download 4 --dir test-logs/run-4 ache/go/1.25.0/x-goversion /usr/bin/git 2426-12305/test-git(http block)https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts/usr/bin/gh gh run download 5 --dir test-logs/run-5(http block)/usr/bin/gh gh run download 5 --dir test-logs/run-5 ache/go/1.25.0/x-tests /usr/bin/git 2426-12305/test-git 0619015/b159/vetcheckout ache/go/1.25.0/x.github/workflows/test.md git rev-�� --show-toplevel ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet /usr/bin/infocmp "prettier" --wrigit(http block)https://api.github.com/repos/github/gh-aw/actions/workflows/usr/bin/gh gh workflow list --json name,state,path(http block)/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(http block)/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(http block)https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha --noprofile .cfg 64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999/usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha(http block)https://api.github.com/repos/nonexistent/repo/actions/runs/12345/usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion(http block)/usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion 2426-12305/test-git **/*.cjs g_.a git rev-�� 63e5abfce2b75faf910c15f0..HEAD ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet /usr/bin/git ../../../**/*.jsgit !../../../pkg/worev-parse ache/go/1.25.0/x--show-toplevel git(http block)https://api.github.com/repos/owner/repo/actions/workflows/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo node(http block)/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo p/bin/git hub.com/.extrahe/opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo /usr/bin/git run --auto x_amd64/compile git rev-�� --show-toplevel x_amd64/compile /usr/bin/git g_.a(http block)https://api.github.com/repos/owner/repo/contents/file.md/tmp/go-build1609364112/b380/cli.test /tmp/go-build1609364112/b380/cli.test -test.testlogfile=/tmp/go-build1609364112/b380/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true(http block)/tmp/go-build910752524/b001/cli.test /tmp/go-build910752524/b001/cli.test -test.paniconexit0 -test.timeout=10m0s -test.count=1 rev-�� --show-toplevel x_amd64/vet /usr/bin/git *.json' '!../../gh main x_amd64/vet git rev-�� --show-toplevel x_amd64/vet /usr/bin/git om/github/gh-aw .cfg 64/pkg/tool/linu--show-toplevel git(http block)https://api.github.com/repos/test-owner/test-repo/actions/secrets/usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name(http block)/usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name /home/REDACTED/work/gh-aw/gh-aw/.github/workflows/brave.md x_amd64/vet /usr/bin/git origin main x_amd64/link git rev-�� --show-toplevel x_amd64/link /usr/bin/git y-test.md(http block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.