Merge pull request #142 from maartenvandiemen/feature/pass-toolsets

Pass GitHub MCP Tools
This commit is contained in:
Sean Goedecke
2025-12-01 08:48:16 +11:00
committed by GitHub
13 changed files with 108 additions and 30 deletions

View File

@@ -28,11 +28,11 @@ jobs:
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Setup Node.js
id: setup-node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
@@ -66,7 +66,7 @@ jobs:
- if: ${{ failure() && steps.diff.outcome == 'failure' }}
name: Upload Artifact
id: upload
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: dist
path: dist/

View File

@@ -20,11 +20,11 @@ jobs:
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Setup Node.js
id: setup-node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
@@ -54,7 +54,7 @@ jobs:
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
@@ -108,7 +108,7 @@ jobs:
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4

View File

@@ -30,19 +30,19 @@ jobs:
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Initialize CodeQL
id: initialize
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
source-root: src
- name: Autobuild
id: autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@v4
- name: Perform CodeQL Analysis
id: analyze
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v4

View File

@@ -27,11 +27,11 @@ jobs:
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Setup Node.js
id: setup-node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
@@ -42,7 +42,7 @@ jobs:
- name: Setup Ruby
id: setup-ruby
uses: ruby/setup-ruby@829114fc20da43a41d27359103ec7a63020954d4
uses: ruby/setup-ruby@8aeb6ff8030dd539317f8e1769a044873b56ea71
with:
ruby-version: ruby

View File

@@ -21,7 +21,7 @@ jobs:
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0

View File

@@ -201,6 +201,25 @@ steps:
github-mcp-token: ${{ secrets.USER_PAT }} # or a ghs_ installation token
```
#### Configuring GitHub MCP Toolsets
By default, the GitHub MCP server provides a standard set of tools (`context`, `repos`, `issues`, `pull_requests`, `users`). You can customize which toolsets are available by specifying the `github-mcp-toolsets` parameter:
```yaml
steps:
- name: AI Inference with Custom Toolsets
id: inference
uses: actions/ai-inference@v2
with:
prompt: 'Analyze recent workflow runs and check security alerts'
enable-github-mcp: true
token: ${{ secrets.USER_PAT }}
github-mcp-toolsets: 'repos,issues,pull_requests,actions,code_security'
```
**Available toolsets:**
See: [Tool configuration](https://github.com/github/github-mcp-server/blob/main/README.md#tool-configuration)
When MCP is enabled, the AI model will have access to GitHub tools and can
perform actions like searching issues and PRs.

View File

@@ -195,7 +195,7 @@ describe('main.ts', () => {
await run()
expect(mockConnectToGitHubMCP).toHaveBeenCalledWith('fake-token')
expect(mockConnectToGitHubMCP).toHaveBeenCalledWith('fake-token', '')
expect(mockMcpInference).toHaveBeenCalledWith(
expect.objectContaining({
messages: [
@@ -222,7 +222,7 @@ describe('main.ts', () => {
await run()
expect(mockConnectToGitHubMCP).toHaveBeenCalledWith('fake-token')
expect(mockConnectToGitHubMCP).toHaveBeenCalledWith('fake-token', '')
expect(mockSimpleInference).toHaveBeenCalled()
expect(mockMcpInference).not.toHaveBeenCalled()
expect(core.warning).toHaveBeenCalledWith('MCP connection failed, falling back to simple inference')

View File

@@ -113,6 +113,40 @@ describe('mcp.ts', () => {
expect(result?.tools).toHaveLength(0)
expect(core.info).toHaveBeenCalledWith('Retrieved 0 tools from GitHub MCP server')
})
it('uses default toolsets when toolsets parameter is not provided', async () => {
const token = 'test-token'
mockConnect.mockResolvedValue(undefined)
mockListTools.mockResolvedValue({tools: []})
await connectToGitHubMCP(token)
expect(core.info).toHaveBeenCalledWith('Using default GitHub MCP toolsets')
})
it('uses custom toolsets when toolsets parameter is provided', async () => {
const token = 'test-token'
const toolsets = 'repos,issues,pull_requests,actions'
mockConnect.mockResolvedValue(undefined)
mockListTools.mockResolvedValue({tools: []})
await connectToGitHubMCP(token, toolsets)
expect(core.info).toHaveBeenCalledWith('Using GitHub MCP toolsets: repos,issues,pull_requests,actions')
})
it('ignores empty toolsets parameter', async () => {
const token = 'test-token'
mockConnect.mockResolvedValue(undefined)
mockListTools.mockResolvedValue({tools: []})
await connectToGitHubMCP(token, ' ')
expect(core.info).toHaveBeenCalledWith('Using default GitHub MCP toolsets')
})
})
describe('executeToolCall', () => {

View File

@@ -58,6 +58,10 @@ inputs:
description: The token to use for GitHub MCP server (defaults to the main token if not specified). This must be a PAT for MCP to work.
required: false
default: ''
github-mcp-toolsets:
description: 'Comma-separated list of toolsets to enable for GitHub MCP (e.g., "repos,issues,pull_requests,actions"). Use "all" for all toolsets, "default" for default set. If not specified, uses default toolsets (context,repos,issues,pull_requests,users).'
required: false
default: ''
# Define your outputs here.
outputs:

22
dist/index.js generated vendored
View File

@@ -42717,15 +42717,24 @@ class StreamableHTTPClientTransport {
/**
* Connect to the GitHub MCP server and retrieve available tools
*/
async function connectToGitHubMCP(token) {
async function connectToGitHubMCP(token, toolsets) {
const githubMcpUrl = 'https://api.githubcopilot.com/mcp/';
coreExports.info('Connecting to GitHub MCP server...');
const headers = {
Authorization: `Bearer ${token}`,
'X-MCP-Readonly': 'true',
};
// Add toolsets header if specified
if (toolsets && toolsets.trim() !== '') {
headers['X-MCP-Toolsets'] = toolsets;
coreExports.info(`Using GitHub MCP toolsets: ${toolsets}`);
}
else {
coreExports.info('Using default GitHub MCP toolsets');
}
const transport = new StreamableHTTPClientTransport(new URL(githubMcpUrl), {
requestInit: {
headers: {
Authorization: `Bearer ${token}`,
'X-MCP-Readonly': 'true',
},
headers,
},
});
const client = new Client({
@@ -52653,13 +52662,14 @@ async function run() {
}
// Get GitHub MCP token (use dedicated token if provided, otherwise fall back to main token)
const githubMcpToken = coreExports.getInput('github-mcp-token') || token;
const githubMcpToolsets = coreExports.getInput('github-mcp-toolsets');
const endpoint = coreExports.getInput('endpoint');
// Build the inference request with pre-processed messages and response format
const inferenceRequest = buildInferenceRequest(promptConfig, systemPrompt, prompt, modelName, promptConfig?.modelParameters?.temperature, promptConfig?.modelParameters?.topP, maxTokens, endpoint, token);
const enableMcp = coreExports.getBooleanInput('enable-github-mcp') || false;
let modelResponse = null;
if (enableMcp) {
const mcpClient = await connectToGitHubMCP(githubMcpToken);
const mcpClient = await connectToGitHubMCP(githubMcpToken, githubMcpToolsets);
if (mcpClient) {
modelResponse = await mcpInference(inferenceRequest, mcpClient);
}

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

View File

@@ -61,6 +61,7 @@ export async function run(): Promise<void> {
// Get GitHub MCP token (use dedicated token if provided, otherwise fall back to main token)
const githubMcpToken = core.getInput('github-mcp-token') || token
const githubMcpToolsets = core.getInput('github-mcp-toolsets')
const endpoint = core.getInput('endpoint')
@@ -82,7 +83,7 @@ export async function run(): Promise<void> {
let modelResponse: string | null = null
if (enableMcp) {
const mcpClient = await connectToGitHubMCP(githubMcpToken)
const mcpClient = await connectToGitHubMCP(githubMcpToken, githubMcpToolsets)
if (mcpClient) {
modelResponse = await mcpInference(inferenceRequest, mcpClient)

View File

@@ -35,17 +35,27 @@ export interface GitHubMCPClient {
/**
* Connect to the GitHub MCP server and retrieve available tools
*/
export async function connectToGitHubMCP(token: string): Promise<GitHubMCPClient | null> {
export async function connectToGitHubMCP(token: string, toolsets?: string): Promise<GitHubMCPClient | null> {
const githubMcpUrl = 'https://api.githubcopilot.com/mcp/'
core.info('Connecting to GitHub MCP server...')
const headers: Record<string, string> = {
Authorization: `Bearer ${token}`,
'X-MCP-Readonly': 'true',
}
// Add toolsets header if specified
if (toolsets && toolsets.trim() !== '') {
headers['X-MCP-Toolsets'] = toolsets
core.info(`Using GitHub MCP toolsets: ${toolsets}`)
} else {
core.info('Using default GitHub MCP toolsets')
}
const transport = new StreamableHTTPClientTransport(new URL(githubMcpUrl), {
requestInit: {
headers: {
Authorization: `Bearer ${token}`,
'X-MCP-Readonly': 'true',
},
headers,
},
})