MCP Scripts
The mcp-scripts: element allows you to define custom MCP (Model Context Protocol) tools directly in your workflow frontmatter using JavaScript, shell scripts, or Python. These tools are generated at runtime and run as an HTTP MCP server on the GitHub Actions runner, outside the agent container. The agent reaches the server via host.docker.internal, keeping tool execution isolated from the AI sandbox while still providing controlled secret access.
MCP Scripts run outside the agent sandbox and must only implement READ-ONLY operations.
Because MCP Scripts execute directly on the GitHub Actions runner host — not inside the isolated agent container — they can access the runner’s file system, network, and environment without the safety constraints of the sandbox. Implementing write operations (creating files, pushing commits, calling mutating APIs, etc.) in MCP Scripts bypasses the audit trail and approval gates that protect your repository.
- ✓ Use MCP Scripts for: reading data, querying APIs, fetching information, performing calculations.
- ✗ Do not use MCP Scripts for: writing files, creating issues/PRs, modifying repository content, or any other mutating action.
For write operations, use Safe Output Jobs or Custom Safe Output Jobs instead. These run in a controlled, auditable step that is separate from the AI agent’s execution.
Quick Start
Section titled “Quick Start”mcp-scripts:greet-user:description: "Greet a user by name"inputs:name:type: stringrequired: truescript: |return { message: `Hello, ${name}!` };
The agent can now call greet-user with a name parameter.
Tool Definition
Section titled “Tool Definition”Each mcp-script tool requires a unique name and configuration:
mcp-scripts:tool-name:description: "What the tool does" # Requiredinputs: # Optional parametersparam1:type: stringrequired: truedescription: "Parameter description"param2:type: numberdefault: 10script: | # JavaScript implementation// Your code hereenv: # Environment variablesAPI_KEY: "${{ secrets.API_KEY }}"timeout: 120 # Optional: timeout in seconds (default: 60)
Each tool requires description: and exactly one of script:, run:, py:, or go:.
JavaScript Tools (script:)
Section titled “JavaScript Tools (script:)”JavaScript tools wrap your script: in async function execute(inputs) with inputs destructured. Access secrets via process.env:
mcp-scripts:fetch-data:description: "Fetch data from API"inputs:endpoint:type: stringrequired: truescript: |const apiKey = process.env.API_KEY;const response = await fetch(`https://api.example.com/${endpoint}`, {headers: { Authorization: `Bearer ${apiKey}` }});return await response.json();env:API_KEY: "${{ secrets.API_KEY }}"
Shell Tools (run:)
Section titled “Shell Tools (run:)”Shell scripts execute in bash with inputs as environment variables (e.g., repo → INPUT_REPO):
mcp-scripts:list-prs:description: "List pull requests"inputs:repo:type: stringrequired: truestate:type: stringdefault: "open"run: |gh pr list --repo "$INPUT_REPO" --state "$INPUT_STATE" --json number,titleenv:GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
Shared gh CLI Tool: Import shared/gh.md for a reusable gh tool that accepts any CLI command via args parameter.
Python Tools (py:)
Section titled “Python Tools (py:)”Python tools execute using python3 with inputs available as a dictionary. Access inputs via inputs.get('name'), secrets via os.environ, and return results by printing JSON to stdout:
mcp-scripts:analyze-data:description: "Analyze data with Python"inputs:numbers:type: stringdescription: "Comma-separated numbers"required: truepy: |import jsonnumbers_str = inputs.get('numbers', '')numbers = [float(x.strip()) for x in numbers_str.split(',') if x.strip()]result = {"count": len(numbers),"sum": sum(numbers),"average": sum(numbers) / len(numbers) if numbers else 0}print(json.dumps(result))
Python 3.10+ is available with standard library modules. For third-party packages, use the dependencies: field with exact version pins (for example, requests==2.32.3) so gh-aw installs them before first tool invocation.
Go Tools (go:)
Section titled “Go Tools (go:)”Go tools execute using go run with inputs provided as a map[string]any parsed from stdin. Standard library imports (encoding/json, fmt, io, os) are automatically included:
mcp-scripts:calculate:description: "Perform calculations with Go"inputs:a:type: numberrequired: trueb:type: numberrequired: truego: |a := inputs["a"].(float64)b := inputs["b"].(float64)result := map[string]any{"sum": a + b,"product": a * b,}json.NewEncoder(os.Stdout).Encode(result)
Your Go code receives inputs map[string]any from stdin and should output JSON to stdout. The code is wrapped in a package main with a main() function that handles input parsing.
Access secrets via os.Getenv("VAR_NAME") (see Environment Variables for the env: field).
Input Parameters
Section titled “Input Parameters”Define typed parameters with validation:
mcp-scripts:example-tool:description: "Example with all input options"inputs:required-param:type: stringrequired: truedescription: "This parameter is required"optional-param:type: numberdefault: 42description: "This has a default value"choice-param:type: stringenum: ["option1", "option2", "option3"]description: "Limited to specific values"
Timeout Configuration
Section titled “Timeout Configuration”Set execution timeout with timeout: field (default: 60 seconds):
mcp-scripts:slow-processing:description: "Process large dataset"timeout: 300 # 5 minutes (default: 60)py: |import jsonimport timetime.sleep(120)print(json.dumps({"status": "complete"}))
Enforced for shell (run:) and Python (py:) tools. JavaScript (script:) tools run in-process without timeout enforcement.
Environment Variables (env:)
Section titled “Environment Variables (env:)”Pass secrets and configuration via env: (available in JavaScript via process.env, shell via $VAR_NAME):
mcp-scripts:secure-tool:description: "Tool with multiple secrets"script: |const { API_KEY, API_SECRET } = process.env;// Use secrets...env:API_KEY: "${{ secrets.SERVICE_API_KEY }}"API_SECRET: "${{ secrets.SERVICE_API_SECRET }}"
Secrets using ${{ secrets.* }} are masked in logs.
Large Output Handling
Section titled “Large Output Handling”When output exceeds 500 characters, it’s saved to a file. The agent receives the file path, size, and JSON schema preview (if applicable).
Importing MCP Scripts
Section titled “Importing MCP Scripts”Import tools from shared workflows using imports:. Local tool definitions override imported ones on name conflicts:
imports:- shared/github-tools.md
Complete Example
Section titled “Complete Example”---on: workflow_dispatchengine: copilotimports:- shared/pr-data-mcp-script.mdmcp-scripts:analyze-text:description: "Analyze text and return statistics"inputs:text:type: stringrequired: truescript: |const words = text.split(/\s+/).filter(w => w.length > 0);return {word_count: words.length,char_count: text.length,avg_word_length: (text.length / words.length).toFixed(2)};safe-outputs:create-discussion:category: "General"---Analyze provided text using the `analyze-text` tool and create a discussion with results.
Security Considerations
Section titled “Security Considerations”MCP Scripts tools run on the GitHub Actions runner host — outside the agent container — so they can access the runner’s file system and environment but are isolated from the AI’s own execution environment. Tools also provide secret isolation (only specified env vars are forwarded), process isolation (separate execution), and output sanitization (large outputs saved to files). Only predefined tools are available to agents.
Troubleshooting
Section titled “Troubleshooting”- Tool Not Found: The tool name the agent calls must exactly match the key under mcp-scripts: in frontmatter (case-sensitive). Check the agent’s tool list in the run logs against your mcp-scripts: block.
- Script Errors: Open the workflow run logs and search for the mcp-scripts server output (MCP Scripts step) for a stack trace or syntax error; the line number in the trace maps directly to your script:/run:/py:/go: block.
- Secret Not Available: Confirm the secret referenced in env: (e.g., ${{ secrets.API_KEY }}) is defined at the repository or organization level under Settings > Secrets and variables > Actions, and that its name matches exactly.
- Large Output: When output exceeds 500 characters, the agent receives a file path instead of inline content (see Large Output Handling); read that file if the agent’s response looks truncated.
Learn More
Section titled “Learn More”- MCP Scripts Specification - Formal W3C-style specification
- Tools - Other tool configuration options
- Imports - Importing shared workflows
- Safe Outputs - Automated post-workflow actions
- MCPs - External MCP server integration
- Custom Safe Output Jobs - Post-workflow custom jobs
| Back | FazBrowse Home | New Git URL |