Sketch out MCP

This commit is contained in:
Sean Goedecke
2025-07-15 23:23:39 +00:00
parent 75eeed10d7
commit 0b82ac474e
8 changed files with 15531 additions and 220 deletions

View File

@@ -1,6 +1,8 @@
import * as core from '@actions/core'
import ModelClient, { isUnexpected } from '@azure-rest/ai-inference'
import { AzureKeyCredential } from '@azure/core-auth'
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
import * as fs from 'fs'
import * as os from 'os'
import * as path from 'path'
@@ -56,35 +58,93 @@ export async function run(): Promise<void> {
const modelName: string = core.getInput('model')
const maxTokens: number = parseInt(core.getInput('max-tokens'), 10)
const token = core.getInput('token') || process.env['GITHUB_TOKEN']
const token = process.env['GITHUB_TOKEN'] || core.getInput('token')
if (token === undefined) {
throw new Error('GITHUB_TOKEN is not set')
}
const endpoint = core.getInput('endpoint')
// Get MCP server configuration
const mcpServerUrl = 'https://api.githubcopilot.com/mcp/'
const enableMcp = core.getBooleanInput('enable-mcp') || false
let azureTools: any[] = []
// Connect to MCP server if enabled
if (enableMcp || true) {
core.info('Connecting to GitHub MCP server...' + token)
const transport = new StreamableHTTPClientTransport(
new URL(mcpServerUrl),
{
requestInit: {
headers: {
Authorization: `Bearer ${token}`
}
}
}
)
const mcp = new Client({
name: 'ai-inference-action',
version: '1.0.0',
transport
})
try {
await mcp.connect(transport)
} catch (mcpError) {
core.warning(`Failed to connect to MCP server: ${mcpError}`)
// Continue without tools if MCP connection fails
return
}
core.info('Successfully connected to MCP server')
// Pull tool metadata
const tools = await mcp.listTools()
core.info(`Retrieved ${tools.tools?.length || 0} tools from MCP server`)
// Map MCP → Azure tool definitions
azureTools = (tools.tools || []).map((t) => ({
type: 'function',
function: {
name: t.name,
description: t.description,
parameters: t.inputSchema
}
}))
core.info(`Mapped ${azureTools.length} tools for Azure AI Inference`)
}
const client = ModelClient(endpoint, new AzureKeyCredential(token), {
userAgentOptions: { userAgentPrefix: 'github-actions-ai-inference' }
})
const requestBody: any = {
messages: [
{
role: 'system',
content: systemPrompt
},
{ role: 'user', content: prompt }
],
max_tokens: maxTokens,
model: modelName
}
// Add tools if available
if (azureTools.length > 0) {
requestBody.tools = azureTools
}
const response = await client.path('/chat/completions').post({
body: {
messages: [
{
role: 'system',
content: systemPrompt
},
{ role: 'user', content: prompt }
],
max_tokens: maxTokens,
model: modelName
}
body: requestBody
})
if (isUnexpected(response)) {
if (response.body.error) {
throw response.body.error
}
throw new Error(
'An error occurred while fetching the response (' +
response.status +
@@ -96,6 +156,21 @@ export async function run(): Promise<void> {
const modelResponse: string | null =
response.body.choices[0].message.content
core.info(`Model response: ${response || 'No response content'}`)
// Handle tool calls if present
const toolCalls = response.body.choices[0].message.tool_calls
if (toolCalls && toolCalls.length > 0) {
core.info(`Model requested ${toolCalls.length} tool calls`)
// Note: For now, we'll just log the tool calls
// In a full implementation, you'd execute them via MCP and continue the conversation
for (const toolCall of toolCalls) {
core.info(
`Tool call: ${toolCall.function.name} with args: ${toolCall.function.arguments}`
)
}
}
// Set outputs for other workflow steps to use
core.setOutput('response', modelResponse || '')