- name
- GitHub Agentic Workflows MCP Configuration
- description
- Comprehensive guide for MCP (Model Context Protocol) server setup, transport protocols, configuration validation, lifecycle management, tool discovery, and error handling patterns
- license
- Apache-2.0
- version
- 2.0.1
- last_updated
- 2026-04-13T00:00:00.000Z
- tags
- ["github-agentic-workflows","mcp","model-context-protocol","server-configuration","transport-protocols","tool-discovery","lifecycle-management","error-handling","stdio","http","sse"]
# 🔌 GitHub Agentic Workflows MCP Configuration
## 🔴 AI FIRST Quality Principle
> **Apply the AI FIRST principle: never accept first-pass quality. Minimum 2 iterations. Read all output, improve every section. No shortcuts.**
## 📋 Overview
This skill provides comprehensive guidance for configuring Model Context Protocol (MCP) servers in GitHub Agentic Workflows. MCP enables AI agents to interact with external tools and data sources through a standardized protocol. Understanding MCP configuration is essential for building powerful, extensible agentic workflows.
### What is Model Context Protocol (MCP)?
**Model Context Protocol (MCP)** is a standardized protocol for connecting AI models to external tools, data sources, and services:
- **Standardized Interface**: Consistent API for tool registration, discovery, and invocation
- **Multiple Transports**: Support for stdio, HTTP, and Server-Sent Events (SSE)
- **Tool Discovery**: Dynamic tool registration and capability discovery
- **Type Safety**: JSON Schema validation for tool inputs and outputs
- **Lifecycle Management**: Server startup, health checks, graceful shutdown
- **Error Handling**: Structured error responses and retry mechanisms
### Why Use MCP Servers?
MCP servers provide several benefits for agentic workflows:
- ✅ **Extensibility**: Add new tools without modifying agent code
- ✅ **Reusability**: Share MCP servers across multiple agents and projects
- ✅ **Isolation**: Run tools in separate processes for security and stability
- ✅ **Standardization**: Use community-maintained MCP servers
- ✅ **Polyglot**: Write servers in any language (Node.js, Python, Go, Rust)
- ✅ **Discoverability**: Agents automatically discover available tools
---
## 🏗️ MCP Architecture
### System Overview
```
┌─────────────────────────────────────────────────────────────┐
│ GitHub Copilot Agent │
│ (AI Model + Orchestration) │
└──────────────────────┬──────────────────────────────────────┘
│ Tool Calls
│ (JSON-RPC 2.0)
▼
┌─────────────────────────────────────────────────────────────┐
│ MCP Client Runtime │
│ (Tool Discovery & Invocation) │
└─┬──────────────────┬──────────────────┬────────────────────┘
│ stdio │ HTTP │ SSE
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Filesystem │ │ GitHub API │ │ Database │
│ MCP Server │ │ MCP Server │ │ MCP Server │
└──────────────┘ └──────────────┘ └──────────────┘
```
### Configuration File Structure
MCP servers are configured in `.github/copilot-mcp.json`:
```json
{
"$schema": "https://github.com/modelcontextprotocol/schema/v1",
"mcpServers": {
"server-name": {
"type": "local",
"command": "command-to-run",
"args": ["arg1", "arg2"],
"env": {
"ENV_VAR": "value"
},
"tools": ["*"]
}
}
}
```
---
## 🚀 MCP Server Setup Patterns
### Pattern 1: Local stdio Server
**Use case**: File system operations, git commands, local tools.
```json
{
"mcpServers": {
"filesystem": {
"type": "local",
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/home/runner/work/myrepo/myrepo"
],
"env": {},
"tools": ["*"]
}
}
}
```
**Implementation** (Node.js):
```javascript
// filesystem-mcp-server.js
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import fs from 'fs/promises';
import path from 'path';
class FileSystemMCPServer {
constructor(rootPath) {
this.rootPath = path.resolve(rootPath);
this.server = new Server({
name: 'filesystem',
version: '1.0.0',
}, {
capabilities: {
tools: {},
},
});
this.setupTools();
}
setupTools() {
// Register read_file tool
this.server.setRequestHandler('tools/list', async () => ({
tools: [
{
name: 'read_file',
description: 'Read contents of a file',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: 'File path relative to root',
},
},
required: ['path'],
},
},
{
name: 'write_file',
description: 'Write contents to a file',
inputSchema: {
type: 'object',
properties: {
path: { type: 'string' },
content: { type: 'string' },
},
required: ['path', 'content'],
},
},
{
name: 'list_directory',
description: 'List files in a directory',
inputSchema: {
type: 'object',
properties: {
path: { type: 'string' },
},
required: ['path'],
},
},
],
}));
// Handle tool calls
this.server.setRequestHandler('tools/call', async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case 'read_file':
return this.readFile(args.path);
case 'write_file':
return this.writeFile(args.path, args.content);
case 'list_directory':
return this.listDirectory(args.path);
default:
throw new Error(`Unknown tool: ${name}`);
}
});
}
validatePath(filePath) {
const resolved = path.resolve(this.rootPath, filePath);
if (!resolved.startsWith(this.rootPath)) {
throw new Error('Path outside root directory');
}
return resolved;
}
async readFile(filePath) {
const validated = this.validatePath(filePath);
const content = await fs.readFile(validated, 'utf8');
return {
content: [
{
type: 'text',
text: content,
},
],
};
}
async writeFile(filePath, content) {
const validated = this.validatePath(filePath);
await fs.writeFile(validated, content, 'utf8');
return {
content: [
{
type: 'text',
text: `File written successfully: ${filePath}`,
},
],
};
}
async listDirectory(dirPath) {
const validated = this.validatePath(dirPath);
const entries = await fs.readdir(validated, { withFileTypes: true });
const files = entries.map(entry => ({
name: entry.name,
type: entry.isDirectory() ? 'directory' : 'file',
}));
return {
content: [
{
type: 'text',
text: JSON.stringify(files, null, 2),
},
],
};
}
async start() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('Filesystem MCP server started');
}
}
// Start server
const rootPath = process.argv[2] || process.cwd();
const server = new FileSystemMCPServer(rootPath);
server.start().catch(console.error);
```
**Usage**:
```bash
# Start server
npx -y @modelcontextprotocol/server-filesystem /workspace
# Server communicates via stdin/stdout
# Input (JSON-RPC request):
{"jsonrpc":"2.0","id":1,"method":"tools/list"}
# Output (JSON-RPC response):
{"jsonrpc":"2.0","id":1,"result":{"tools":[...]}}
```
### Pattern 2: HTTP Server
**Use case**: Remote services, APIs, databases.
```json
{
"mcpServers": {
"github-api": {
"type": "http",
"url": "https://mcp.github.com/v1",
"headers": {
"Authorization": "Bearer ${{ secrets.GITHUB_TOKEN }}"
},
"tools": ["*"]
}
}
}
```
**Implementation** (Node.js with Express):
```javascript
// github-api-mcp-server.js
import express from 'express';
import { Octokit } from '@octokit/rest';
const app = express();
app.use(express.json());
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN,
});
// MCP endpoint: List tools
app.post('/mcp/tools/list', async (req, res) => {
res.json({
tools: [
{
name: 'github_create_issue',
description: 'Create a GitHub issue',
inputSchema: {
type: 'object',
properties: {
owner: { type: 'string' },
repo: { type: 'string' },
title: { type: 'string' },
body: { type: 'string' },
},
required: ['owner', 'repo', 'title'],
},
},
{
name: 'github_list_issues',
description: 'List GitHub issues',
inputSchema: {
type: 'object',
properties: {
owner: { type: 'string' },
repo: { type: 'string' },
state: { type: 'string', enum: ['open', 'closed', 'all'] },
},
required: ['owner', 'repo'],
},
},
],
});
});
// MCP endpoint: Call tool
app.post('/mcp/tools/call', async (req, res) => {
const { name, arguments: args } = req.body;
try {
switch (name) {
case 'github_create_issue': {
const { data } = await octokit.issues.create({
owner: args.owner,
repo: args.repo,
title: args.title,
body: args.body,
});
res.json({
content: [
{
type: 'text',
text: `Issue created: ${data.html_url}`,
},
],
});
break;
}
case 'github_list_issues': {
const { data } = await octokit.issues.listForRepo({
owner: args.owner,
repo: args.repo,
state: args.state || 'open',
});
res.json({
content: [
{
type: 'text',
text: JSON.stringify(data, null, 2),
},
],
});
break;
}
default:
res.status(404).json({ error: 'Tool not found' });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Health check
app.get('/health', (req, res) => {
res.json({ status: 'ok' });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`GitHub API MCP server listening on port ${PORT}`);
});
```
### Pattern 3: Server-Sent Events (SSE)
**Use case**: Real-time updates, streaming data, webhooks.
```json
{
"mcpServers": {
"realtime-monitor": {
"type": "sse",
"url": "https://monitor.example.com/events",
"headers": {
"Authorization": "Bearer ${{ secrets.API_TOKEN }}"
},
"tools": ["*"]
}
}
}
```
**Implementation** (Node.js with SSE):
```javascript
// realtime-monitor-mcp-server.js
import express from 'express';
const app = express();
const clients = new Set();
// SSE endpoint
app.get('/events', (req, res) => {
// Set headers for SSE
View on GitHub