Skip to content

feat: add dispatch_repository safe-output type for repository_dispatch events (experimental)#22315

Merged
pelikhan merged 7 commits intomainfrom
copilot/add-dispatch-repository-safe-output
Mar 22, 2026
Merged

feat: add dispatch_repository safe-output type for repository_dispatch events (experimental)#22315
pelikhan merged 7 commits intomainfrom
copilot/add-dispatch-repository-safe-output

Conversation

Copy link
Contributor

Copilot AI commented Mar 22, 2026

Introduces a new dispatch_repository safe-output using the map-of-tools pattern, enabling agentic workflows to trigger GitHub repository_dispatch events against external repositories with structured input validation and execution limits.

⚠️ Experimental feature — compiling a workflow with dispatch_repository emits Using experimental feature: dispatch_repository to stderr.

Go (compile-time)

  • dispatch_repository.goDispatchRepositoryConfig + DispatchRepositoryToolConfig structs; parser supports both dispatch_repository and dispatch-repository YAML keys
  • dispatch_repository_validation.go — validates workflow, event_type, and at least one repo target per tool; validates owner/repo slug format with GitHub Actions expressions bypass (values containing ${{ skip format validation)
  • compiler.go — emits "Using experimental feature: dispatch_repository" warning and increments warning count when dispatch_repository is configured (same pattern as rate-limit and dependencies (APM))
  • Schema (main_workflow_schema.json) — full dispatch_repository JSON Schema entry with per-tool additionalProperties validation
  • Wired into SafeOutputsConfig, state reflection map, tools filtering (both JSON strategies), config serialization, compiler validation hook, and prompt tools list

JavaScript (runtime)

  • dispatch_repository.cjs — handler factory; resolves target repo per message, enforces cross-repo allowlist (SEC-005), builds client_payload from inputs + workflow identifier, calls repos.createDispatchEvent; supports staged mode
  • Wired into safe_output_handler_manager.cjs (HANDLER_MAP), safe_outputs_tools_loader.cjs (_dispatch_repository_tool metadata attach + register), and safe_outputs_mcp_server_http.cjs (HTTP server registration)

Tests

  • Unit tests (dispatch_repository_test.go) — 19 tests covering parsing, validation, tool generation, config serialization, and end-to-end compilation; includes TestValidateDispatchRepository_GitHubExpression verifying expressions bypass slug format checks
  • Experimental warning tests (dispatch_repository_experimental_warning_test.go) — 3 integration tests verifying the warning is emitted when dispatch_repository is configured and absent otherwise
  • Integration tests (pkg/cli/compile_integration_test.go) — 6 new CLI-level integration tests that compile real workflows and assert on the generated lock file:
    • TestCompileDispatchRepository — single-tool compile; asserts _dispatch_repository_tool metadata and handler config fields
    • TestCompileDispatchRepositoryMultipleTools — two tools with inputs and allowed_repositories
    • TestCompileDispatchRepositoryValidationFailure — missing workflow field causes compilation failure with descriptive error
    • TestCompileDispatchRepositoryWorkflowFile — end-to-end compilation of the canonical pkg/cli/workflows/test-copilot-dispatch-repository.md
    • TestCompileDispatchRepositoryGitHubActionsExpression${{ inputs.target_repo }} in repository field compiles successfully and is preserved verbatim in the handler config
    • TestCompileDispatchRepositoryGitHubActionsExpressionAllowedRepos — mixed static slugs and ${{ vars.DYNAMIC_REPO }} expressions in allowed_repositories compile and are preserved intact
  • Canonical workflow (pkg/cli/workflows/test-copilot-dispatch-repository.md) — reference workflow with two tools (trigger_ci with single repository, notify_service with allowed_repositories and inputs)

Example

safe-outputs:
  dispatch_repository:
    trigger_ci:
      description: Trigger CI in another repository
      workflow: ci.yml
      event_type: ci_trigger
      repository: ${{ inputs.target_repo }}   # GitHub Actions expressions are supported
      inputs:
        environment:
          type: choice
          options: [staging, production]
          default: staging
      max: 1
    notify_service:
      workflow: notify.yml
      event_type: notify_event
      allowed_repositories:
        - org/service-repo
        - ${{ vars.DYNAMIC_REPO }}             # Expressions bypass slug format validation
      inputs:
        message:
          type: string

Each tool becomes a named MCP tool exposed to the agent. At runtime the handler resolves the target repository, validates the allowlist, and sends repository_dispatch with client_payload containing all resolved inputs plus the workflow identifier for downstream routing. Both repository and allowed_repositories accept static owner/repo slugs or GitHub Actions expressions — expressions are passed through without format validation since their values are only known at runtime.


📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.

Copilot AI changed the title [WIP] Add dispatch_repository safe-output for triggering dispatch events feat: add dispatch_repository safe-output type for repository_dispatch events Mar 22, 2026
Copilot AI requested a review from pelikhan March 22, 2026 20:24
@pelikhan
Copy link
Contributor

@copilot add integration tests in pkg/cli/workflows to ensure the compilation is properly happening at all levels

Copy link
Contributor Author

Copilot AI commented Mar 22, 2026

@copilot add integration tests in pkg/cli/workflows to ensure the compilation is properly happening at all levels

Added 4 integration tests in pkg/cli/compile_integration_test.go (commit 220c32e) and a canonical test workflow at pkg/cli/workflows/test-copilot-dispatch-repository.md:

  • TestCompileDispatchRepository — single-tool compile; asserts _dispatch_repository_tool metadata, normalized tool name, and handler config fields (workflow, event_type, repository)
  • TestCompileDispatchRepositoryMultipleTools — two tools with inputs and allowed_repositories; asserts both tools appear in the generated JSON and allowed repos are serialized correctly
  • TestCompileDispatchRepositoryValidationFailure — missing required workflow field; asserts compilation fails with a descriptive error
  • TestCompileDispatchRepositoryWorkflowFile — compiles the canonical test-copilot-dispatch-repository.md end-to-end and asserts the handler config is present in the lock file

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 (http block)
    • 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 k/gh-aw/gh-aw/pk-C k/gh-aw/gh-aw/pk/home/REDACTED/work/gh-aw/gh-aw/.github/workflows 64/pkg/tool/linuconfig k/gh�� k/gh-aw/gh-aw/pkremote.origin.url .cfg 64/pkg/tool/linux_amd64/vet k/gh-aw/gh-aw/pk/usr/bin/unpigz k/gh-aw/gh-aw/pk-d k/gh-aw/gh-aw/pk-c 64/pkg/tool/linux_amd64/vet (http block)
    • 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 chr/testify/asse-1 (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 (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha -unreachable=false /tmp/go-build1279503598/b208/vet.cfg repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha ithub/workflows -buildtags repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -errorsas r -nilfunc /opt/hostedtoolc-f -ato�� ithub/workflows -buildtags r: $owner, name:-f -errorsas -ifaceassert -nilfunc /bin/sh (http block)
  • https://api.github.com/repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq .object.sha (http block)
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq .object.sha se 9503598/b159/vet.cfg n-dir/node (http block)
  • https://api.github.com/repos/github/gh-aw
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw --jq .visibility on' --ignore-path ../../../.pret.prettierignore .cfg r: $owner, name: $name) { hasDiscussionsEnabled } } (http block)
  • https://api.github.com/repos/githubnext/agentics/git/ref/tags/
    • Triggering command: /usr/bin/gh gh api /repos/githubnext/agentics/git/ref/tags/# --jq .object.sha get --local x_amd64/vet credential.helpeinfocmp (http block)
    • Triggering command: /usr/bin/gh gh api /repos/githubnext/agentics/git/ref/tags/# --jq .object.sha .js' --ignore-pa-f (http block)

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

@pelikhan
Copy link
Contributor

@copilot make sure github actions expression are also allowed.

Copy link
Contributor Author

Copilot AI commented Mar 22, 2026

@copilot make sure github actions expression are also allowed.

Added two integration tests in commit c6b5a47:

  • TestCompileDispatchRepositoryGitHubActionsExpression — compiles a workflow with repository: ${{ inputs.target_repo }} and asserts the expression is preserved verbatim in the handler config
  • TestCompileDispatchRepositoryGitHubActionsExpressionAllowedRepos — compiles a workflow with a mixed allowed_repositories list (org/static-repo alongside ${{ vars.DYNAMIC_REPO }}) and asserts both entries appear unchanged in the lock file

The validation code already skips format checking when ${{ is detected; these tests verify that bypasses correctly at the CLI level.

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/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 (http block)

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

@github-actions github-actions bot added the lgtm label Mar 22, 2026
@github-actions
Copy link
Contributor

Hey @Copilot 👋 — great work on the dispatch_repository safe-output type! This is a well-structured addition that extends the map-of-tools pattern to cover repository_dispatch events, complete with structured input validation, GitHub Actions expression support, and an allowlist enforcement for cross-repo security (SEC-005).

The PR checks all the boxes:

  • Focused — all 18 changed files are tightly scoped to the new dispatch_repository feature
  • Tests included — 19 unit tests in dispatch_repository_test.go and 6 integration tests in compile_integration_test.go, covering happy paths, validation failures, and expression passthrough
  • Description — the PR body provides a thorough breakdown of Go structs, JS runtime wiring, schema changes, and an illustrative YAML example
  • No new dependencies introduced
  • Follows project process — authored by the Copilot coding agent with a core team member (pelikhan) assigned and requested as reviewer

This PR looks ready for maintainer review. 🎉

Generated by Contribution Check ·

@pelikhan
Copy link
Contributor

@copilot make it expiremental

Copy link
Contributor Author

Copilot AI commented Mar 22, 2026

@copilot make it expiremental

Done in commit 2b1dc42. dispatch_repository now emits ⚠ Using experimental feature: dispatch_repository to stderr during compilation (same pattern as rate-limit and dependencies (APM)). Added dispatch_repository_experimental_warning_test.go with 3 integration tests covering the warning on/off cases.

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/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 (http block)

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

Copilot AI changed the title feat: add dispatch_repository safe-output type for repository_dispatch events feat: add dispatch_repository safe-output type for repository_dispatch events (experimental) Mar 22, 2026
@pelikhan pelikhan marked this pull request as ready for review March 22, 2026 22:35
Copilot AI review requested due to automatic review settings March 22, 2026 22:35
@pelikhan pelikhan merged commit d9036ed into main Mar 22, 2026
98 of 102 checks passed
@pelikhan pelikhan deleted the copilot/add-dispatch-repository-safe-output branch March 22, 2026 22:35
Copy link
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

Adds an experimental dispatch_repository safe-output type to enable agent tools that trigger GitHub repository_dispatch events against external repositories, with compile-time schema/validation and runtime handler wiring.

Changes:

  • Go compiler support: parse/validate dispatch_repository, generate dynamic MCP tools, serialize handler config, and emit an experimental-feature warning.
  • JSON Schema updates for safe-outputs.dispatch_repository plus new canonical workflow + Go unit/integration tests.
  • JS runtime support: new dispatch_repository handler and registration in the safe-outputs MCP server/tool loader.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/workflow/unified_prompt_step.go Adds dispatch_repository to the prompt tools hint list when configured.
pkg/workflow/safe_outputs_tools_filtering.go Generates dynamic dispatch_repository tool definitions (legacy + meta strategies).
pkg/workflow/safe_outputs_state.go Wires DispatchRepository into safe-output state reflection mapping.
pkg/workflow/safe_outputs_config_generation.go Serializes dispatch_repository runtime config (per-tool map) into handler config JSON.
pkg/workflow/safe_outputs_config.go Parses dispatch_repository from frontmatter during safe-outputs extraction.
pkg/workflow/dispatch_repository_validation.go New compiler validation for tool fields + repo slug format (with expression bypass).
pkg/workflow/dispatch_repository_test.go Unit tests for parsing/validation/tool generation/config serialization + compilation.
pkg/workflow/dispatch_repository_experimental_warning_test.go Integration tests asserting experimental warning emission.
pkg/workflow/dispatch_repository.go New config structs + parser + dynamic tool schema generation.
pkg/workflow/compiler_types.go Adds DispatchRepository to SafeOutputsConfig.
pkg/workflow/compiler_safe_outputs_config.go Adds handler-config serialization entry for dispatch_repository.
pkg/workflow/compiler.go Emits experimental warning + hooks compiler validation for dispatch_repository.
pkg/parser/schemas/main_workflow_schema.json Adds JSON Schema for safe-outputs.dispatch_repository.
pkg/cli/workflows/test-copilot-dispatch-repository.md Adds a canonical example workflow using dispatch_repository.
pkg/cli/compile_integration_test.go Adds CLI-level compilation integration tests for dispatch_repository.
actions/setup/js/safe_outputs_tools_loader.cjs Attaches/registers dynamic dispatch tools with _dispatch_repository_tool metadata.
actions/setup/js/safe_outputs_mcp_server_http.cjs Registers dispatch_repository tools in HTTP server tool registration logic.
actions/setup/js/safe_output_handler_manager.cjs Adds dispatch_repository to the handler module map.
actions/setup/js/dispatch_repository.cjs New runtime handler that dispatches repository_dispatch events with allowlist + staged support.
Comments suppressed due to low confidence (5)

actions/setup/js/dispatch_repository.cjs:105

  • Cross-repo allowlist enforcement is effectively optional here: when targetRepoSlug !== contextRepoSlug and allowed_repositories is empty/omitted, the code skips validateTargetRepo entirely and will dispatch to the configured repository (or any message-provided repo). This differs from the SEC-005 default-deny behavior used in dispatch_workflow.cjs and contradicts the intended “enforces cross-repo allowlist” contract.

Consider default-denying cross-repo dispatch when no allowlist is configured (return an E004-style error), or otherwise ensuring the resolved target is always validated against an explicit allowlist before calling the GitHub API.

    // Validate cross-repo dispatch (SEC-005 pattern)
    const isCrossRepo = targetRepoSlug !== contextRepoSlug;
    if (isCrossRepo && allowedRepos.size > 0) {
      const repoValidation = validateTargetRepo(targetRepoSlug, contextRepoSlug, allowedRepos);
      if (!repoValidation.valid) {
        core.warning(`dispatch_repository: cross-repo check failed for "${targetRepoSlug}": ${repoValidation.error}`);
        return {
          success: false,
          error: `E004: ${repoValidation.error}`,
        };
      }
    }

actions/setup/js/dispatch_repository.cjs:93

  • message.repository is treated as an override for choosing the dispatch target, but the dynamic tool wrapper added in safe_outputs_tools_loader.cjs only forwards tool arguments under message.inputs (and the generated tool schema disallows extra properties). As a result, callers can’t actually set message.repository, and tools configured with only allowed_repositories will silently default to the first entry (which may be a glob like org/* and will then fail slug parsing).

To make multi-repo selection work, either read the target from message.inputs.repository (and add repository to the tool input schema), or update the wrapper to pass a top-level repository field and ensure the tool schema allows it.

    // Resolve target repository
    // Prefer message.repository > toolConfig.repository > first allowed_repository
    const messageRepo = message.repository || "";
    const configuredRepo = toolConfig.repository || "";
    const allowedReposConfig = toolConfig.allowed_repositories || [];
    const allowedRepos = parseAllowedRepos(allowedReposConfig);

    let targetRepoSlug = messageRepo || configuredRepo;

    if (!targetRepoSlug && allowedReposConfig.length > 0) {
      // Default to first allowed repository if no specific target given
      targetRepoSlug = allowedReposConfig[0];
    }

    if (!targetRepoSlug) {
      core.warning(`dispatch_repository: no target repository for tool "${toolName}"`);
      return {
        success: false,
        error: `E001: No target repository configured for tool "${toolName}"`,
      };
    }

actions/setup/js/dispatch_repository.cjs:70

  • max is described/validated as capped at 50 at compile time, but at runtime maxCount is parsed and used as-is. If max is templated (e.g. ${{ inputs.max }}) and resolves to >50, this handler will permit more than 50 dispatches, bypassing the intended execution limit.

Consider capping maxCount to 50 in the handler after parsing (and potentially returning a validation error if it exceeds the cap) so the limit is enforced even when max is expression-driven.

    const maxCount = typeof toolConfig.max === "number" ? toolConfig.max : parseInt(String(toolConfig.max || "1"), 10) || 1;
    const currentCount = dispatchCounts[toolName] || 0;

    if (currentCount >= maxCount) {
      core.warning(`dispatch_repository: max count of ${maxCount} reached for tool "${toolName}", skipping`);
      return {
        success: false,
        error: `E002: Max count of ${maxCount} reached for tool "${toolName}"`,
      };
    }

pkg/parser/schemas/main_workflow_schema.json:6919

  • The repository slug validation in this schema doesn’t match the compiler’s validation logic in pkg/workflow/dispatch_repository_validation.go: the schema’s repository.pattern allows dots (and underscores) in the owner segment ([a-zA-Z0-9._-]+/...), while the Go validator comment explicitly disallows dots in owners and uses a different regex. This can lead to confusing behavior where a value passes schema validation but fails compilation (or vice versa if the validator is relaxed).

Align the schema pattern with the actual accepted slug format (and/or update the Go validator) so users get consistent validation errors.

              "repository": {
                "type": "string",
                "description": "Target repository in 'owner/repo' format. Dispatches to this repository when no 'allowed_repositories' list is given.",
                "pattern": "^[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+$|^\\$\\{\\{.*\\}\\}$"
              },

actions/setup/js/dispatch_repository.cjs:28

  • Per-tool github-token overrides won’t take effect with the current implementation. The handler creates githubClient once from the top-level handler config (createAuthenticatedGitHubClient(config)), but dispatch_repository stores github-token under each tools[toolName] entry. As a result, toolConfig["github-token"] is ignored and all dispatches use the step-level token (or any hypothetical handler-level token).

Either (a) support only a single handler-level github-token for dispatch_repository and remove the per-tool field from schema/config generation, or (b) create/select an authenticated client per message based on the selected tool’s github-token.

async function main(config = {}) {
  const tools = config.tools || {};
  const githubClient = await createAuthenticatedGitHubClient(config);
  const isStaged = isStagedMode(config);

  const contextRepoSlug = `${context.repo.owner}/${context.repo.repo}`;
  core.info(`dispatch_repository handler initialized: tools=${Object.keys(tools).join(", ")}, context_repo=${contextRepoSlug}`);

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

const contextRepoSlug = `${context.repo.owner}/${context.repo.repo}`;
core.info(`dispatch_repository handler initialized: tools=${Object.keys(tools).join(", ")}, context_repo=${contextRepoSlug}`);

// Per-tool dispatch counters for max enforcement
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

There’s no JS unit test coverage for the new dispatch_repository handler, while similar handlers (e.g. dispatch_workflow.cjs) have dedicated tests covering max enforcement, cross-repo allowlists, staged mode, and error paths. Given the security-sensitive nature of cross-repo dispatch, adding a dispatch_repository.test.cjs (and possibly MCP tool registration tests) would help prevent regressions.

This issue also appears in the following locations of the same file:

  • line 94
  • line 72
  • line 61
  • line 22
Suggested change
// Per-tool dispatch counters for max enforcement
// Per-tool dispatch counters for max enforcement; this state underpins security-sensitive
// rate/usage limits and is expected to be covered by dedicated unit tests (similar to
// dispatch_workflow handler tests).

Copilot uses AI. Check for mistakes.
Comment on lines +6894 to +6899
"dispatch_repository": {
"type": "object",
"description": "Dispatch repository_dispatch events to external repositories. Each sub-key defines a named dispatch tool with its own event_type, target repository, input schema, and execution limits.",
"additionalProperties": {
"type": "object",
"description": "Configuration for a single repository dispatch tool",
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

The parser supports both dispatch_repository and the dispatch-repository alias, but the schema only defines dispatch_repository. Workflows using the dash alias will likely fail JSON Schema frontmatter validation even though the compiler can parse them.

Either add a dispatch-repository schema entry (matching this object schema) or drop the alias to keep schema and parsing behavior aligned.

This issue also appears on line 6915 of the same file.

Copilot uses AI. Check for mistakes.
// repoSlugPattern matches a valid owner/repo GitHub repository slug.
// Owner names: alphanumerics and hyphens (no dots - GitHub usernames/org names cannot have dots).
// Repository names: alphanumerics, hyphens, dots and underscores.
var repoSlugPattern = regexp.MustCompile(`^[a-zA-Z0-9_-]+/[a-zA-Z0-9._-]+$`)
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

The comment says owner names are “alphanumerics and hyphens”, but the actual regex allows underscores in the owner segment ([a-zA-Z0-9_-]+). Either update the regex to match the documented constraint, or adjust the comment (and consider aligning with the JSON Schema slug pattern too) so validation rules are consistent and predictable.

Suggested change
var repoSlugPattern = regexp.MustCompile(`^[a-zA-Z0-9_-]+/[a-zA-Z0-9._-]+$`)
var repoSlugPattern = regexp.MustCompile(`^[a-zA-Z0-9-]+/[a-zA-Z0-9._-]+$`)

Copilot uses AI. Check for mistakes.
Comment on lines +147 to +220
// Build input schema from the tool's inputs definition
properties := make(map[string]any)
required := []string{}

for inputName, inputDef := range toolConfig.Inputs {
inputDefMap, ok := inputDef.(map[string]any)
if !ok {
continue
}

inputType := "string"
inputDescription := "Input parameter '" + inputName + "'"
inputRequired := false

if desc, ok := inputDefMap["description"].(string); ok && desc != "" {
inputDescription = desc
}
if req, ok := inputDefMap["required"].(bool); ok {
inputRequired = req
}

// Map input types to JSON Schema types
if typeStr, ok := inputDefMap["type"].(string); ok {
switch typeStr {
case "number":
inputType = "number"
case "boolean":
inputType = "boolean"
case "choice":
inputType = "string"
if options, ok := inputDefMap["options"].([]any); ok && len(options) > 0 {
prop := map[string]any{
"type": inputType,
"description": inputDescription,
"enum": options,
}
if defaultVal, ok := inputDefMap["default"]; ok {
prop["default"] = defaultVal
}
properties[inputName] = prop
if inputRequired {
required = append(required, inputName)
}
continue
}
case "environment":
inputType = "string"
}
}

prop := map[string]any{
"type": inputType,
"description": inputDescription,
}
if defaultVal, ok := inputDefMap["default"]; ok {
prop["default"] = defaultVal
}
properties[inputName] = prop

if inputRequired {
required = append(required, inputName)
}
}

tool := map[string]any{
"name": toolName,
"description": description,
"_dispatch_repository_tool": toolKey, // Internal metadata for handler routing
"inputSchema": map[string]any{
"type": "object",
"properties": properties,
"additionalProperties": false,
},
}
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

The generated MCP tool schema only exposes inputs fields and sets additionalProperties: false, but the runtime handler supports selecting a target repo via message.repository (and the config supports allowed_repositories). With the current tool schema, agents can’t provide a repository override when multiple repositories are allowed, which effectively makes allowed_repositories either (a) just an allowlist for a fixed repository, or (b) a list where the handler will default to the first entry.

If per-invocation repo selection is intended, consider adding an optional repository (or repo) field to the tool’s inputSchema when allowed_repositories is configured (and update the handler/wrapper to read it consistently).

Copilot uses AI. Check for mistakes.
github-actions bot added a commit that referenced this pull request Mar 23, 2026
- Fix broken architecture link in index.mdx (closes #22226)
- Add dispatch_repository safe-output type documentation (from #22315)
- Add engine feature comparison table to engines reference (closes #22147)
- Add frontmatter common field name mistakes to troubleshooting (addresses #22092)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants