Skip to content

Commit 474d225

Browse files
kristentralmaleksiakubajanuszCopilot
authored
merge commit update changes (#8)
* Stricter matching for github.com and ghe.com URLs * Gracefully handle numeric parameters passed as strings (github#2130) * Gracefully handle numeric parameters passed as strings * Fix SHA validation in create_or_update_file (github#2134) * Fix SHA validation in create_or_update_file * Doc update * Handle non-404 errors * Handle directory paths * Update instructions * fix: handle empty files in get_file_contents (github#2042) 1. Empty (0-byte) files caused an unhandled error because the GitHub API returns null content with base64 encoding for them; GetContent() fails with "malformed response: base64 encoding of null content". Return empty text/plain content directly, bypassing decoding entirely. Co-authored-by: Ksenia Bobrova <almaleksia@github.com> * Cline & Roo code installation guides (github#2146) * Cline & Roo code installation guides * Update docs/installation-guides/install-cline.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Correctly wrap GraphQl error (github#2149) --------- Co-authored-by: Ksenia Bobrova <almaleksia@github.com> Co-authored-by: Jakub Janusz <32165716+kubajanusz@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent bf64678 commit 474d225

18 files changed

+920
-152
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1171,7 +1171,7 @@ The following sets of tools are available:
11711171
- `owner`: Repository owner (username or organization) (string, required)
11721172
- `path`: Path where to create/update the file (string, required)
11731173
- `repo`: Repository name (string, required)
1174-
- `sha`: The blob SHA of the file being replaced. (string, optional)
1174+
- `sha`: The blob SHA of the file being replaced. Required if the file already exists. (string, optional)
11751175

11761176
- **create_repository** - Create repository
11771177
- **Required OAuth Scopes**: `repo`

docs/installation-guides/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ This directory contains detailed installation instructions for the GitHub MCP Se
77
- **[GitHub Copilot in other IDEs](install-other-copilot-ides.md)** - Installation for JetBrains, Visual Studio, Eclipse, and Xcode with GitHub Copilot
88
- **[Antigravity](install-antigravity.md)** - Installation for Google Antigravity IDE
99
- **[Claude Applications](install-claude.md)** - Installation guide for Claude Web, Claude Desktop and Claude Code CLI
10+
- **[Cline](install-cline.md)** - Installation guide for Cline
1011
- **[Cursor](install-cursor.md)** - Installation guide for Cursor IDE
1112
- **[Google Gemini CLI](install-gemini-cli.md)** - Installation guide for Google Gemini CLI
1213
- **[OpenAI Codex](install-codex.md)** - Installation guide for OpenAI Codex
14+
- **[Roo Code](install-roo-code.md)** - Installation guide for Roo Code
1315
- **[Windsurf](install-windsurf.md)** - Installation guide for Windsurf IDE
1416

1517
## Support by Host Application
@@ -23,8 +25,10 @@ This directory contains detailed installation instructions for the GitHub MCP Se
2325
| Copilot in JetBrains || ✅ Full (OAuth + PAT) | Local: Docker or Go build, GitHub PAT<br>Remote: JetBrains Copilot Extension v1.5.53+ | Easy |
2426
| Claude Code || ✅ PAT + ❌ No OAuth| GitHub MCP Server binary or remote URL, GitHub PAT | Easy |
2527
| Claude Desktop || ✅ PAT + ❌ No OAuth | Docker or Go build, GitHub PAT | Moderate |
28+
| Cline || ✅ PAT + ❌ No OAuth | Docker or Go build, GitHub PAT | Easy |
2629
| Cursor || ✅ PAT + ❌ No OAuth | Docker or Go build, GitHub PAT | Easy |
2730
| Google Gemini CLI || ✅ PAT + ❌ No OAuth | Docker or Go build, GitHub PAT | Easy |
31+
| Roo Code || ✅ PAT + ❌ No OAuth | Docker or Go build, GitHub PAT | Easy |
2832
| Windsurf || ✅ PAT + ❌ No OAuth | Docker or Go build, GitHub PAT | Easy |
2933
| Copilot in Xcode || ✅ Full (OAuth + PAT) | Local: Docker or Go build, GitHub PAT<br>Remote: Copilot for Xcode 0.41.0+ | Easy |
3034
| Copilot in Eclipse || ✅ Full (OAuth + PAT) | Local: Docker or Go build, GitHub PAT<br>Remote: Eclipse Plug-in for Copilot 0.10.0+ | Easy |
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Install GitHub MCP Server in Cline
2+
3+
[Cline](https://github.com/cline/cline) is an AI coding assistant that runs in VS Code-compatible editors (VS Code, Cursor, Windsurf, etc.). For general setup information (prerequisites, Docker installation, security best practices), see the [Installation Guides README](./README.md).
4+
5+
## Remote Server
6+
7+
Cline stores MCP settings in `cline_mcp_settings.json`. To edit it, click the Cline icon in your editor's sidebar, open the menu in the top right corner of the Cline panel, and select **"MCP Servers"**. You can add a remote server through the **"Remote Servers"** tab, or click **"Configure MCP Servers"** to edit the JSON directly.
8+
9+
```json
10+
{
11+
"mcpServers": {
12+
"github": {
13+
"url": "https://api.githubcopilot.com/mcp/",
14+
"type": "streamableHttp",
15+
"disabled": false,
16+
"headers": {
17+
"Authorization": "Bearer <YOUR_GITHUB_PAT>"
18+
},
19+
"autoApprove": []
20+
}
21+
}
22+
}
23+
```
24+
25+
Replace `YOUR_GITHUB_PAT` with your [GitHub Personal Access Token](https://github.com/settings/tokens). To customize toolsets, add server-side headers like `X-MCP-Toolsets` or `X-MCP-Readonly` to the `headers` object — see [Server Configuration Guide](../server-configuration.md).
26+
27+
> **Important:** The transport type must be `"streamableHttp"` (camelCase, no hyphen). Using `"streamable-http"` or omitting the type will cause Cline to fall back to SSE, resulting in a `405` error.
28+
29+
## Local Server (Docker)
30+
31+
1. Click the Cline icon in your editor's sidebar (or open the command palette and search for "Cline"), then click the **MCP Servers** icon (server stack icon at the top of the Cline panel), and click **"Configure MCP Servers"** to open `cline_mcp_settings.json`.
32+
2. Add the configuration below, replacing `YOUR_GITHUB_PAT` with your [GitHub Personal Access Token](https://github.com/settings/tokens).
33+
34+
```json
35+
{
36+
"mcpServers": {
37+
"github": {
38+
"command": "docker",
39+
"args": [
40+
"run", "-i", "--rm",
41+
"-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
42+
"ghcr.io/github/github-mcp-server"
43+
],
44+
"env": {
45+
"GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_GITHUB_PAT"
46+
}
47+
}
48+
}
49+
}
50+
```
51+
52+
## Troubleshooting
53+
54+
- **SSE error 405 with remote server**: Ensure `"type"` is set to `"streamableHttp"` (camelCase, no hyphen) in `cline_mcp_settings.json`. Using `"streamable-http"` or omitting `"type"` causes Cline to fall back to SSE, which this server does not support.
55+
- **Authentication failures**: Verify your PAT has the required scopes
56+
- **Docker issues**: Ensure Docker Desktop is installed and running
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Install GitHub MCP Server in Roo Code
2+
3+
[Roo Code](https://github.com/RooCodeInc/Roo-Code) is an AI coding assistant that runs in VS Code-compatible editors (VS Code, Cursor, Windsurf, etc.). For general setup information (prerequisites, Docker installation, security best practices), see the [Installation Guides README](./README.md).
4+
5+
## Remote Server
6+
7+
### Step-by-step setup
8+
9+
1. Click the **Roo Code icon** in your editor's sidebar to open the Roo Code pane
10+
2. Click the **gear icon** (⚙️) in the top navigation of the Roo Code pane, then click on **"MCP Servers"** icon on the left.
11+
3. Scroll to the bottom and click **"Edit Global MCP"** (for all projects) or **"Edit Project MCP"** (for the current project only)
12+
4. Add the configuration below to the opened file (`mcp_settings.json` or `.roo/mcp.json`)
13+
5. Replace `YOUR_GITHUB_PAT` with your [GitHub Personal Access Token](https://github.com/settings/tokens)
14+
6. Save the file — the server should connect automatically
15+
16+
```json
17+
{
18+
"mcpServers": {
19+
"github": {
20+
"type": "streamable-http",
21+
"url": "https://api.githubcopilot.com/mcp/",
22+
"headers": {
23+
"Authorization": "Bearer YOUR_GITHUB_PAT"
24+
}
25+
}
26+
}
27+
}
28+
```
29+
30+
> **Important:** The `type` must be `"streamable-http"` (with hyphen). Using `"http"` or omitting the type will fail.
31+
32+
To customize toolsets, add server-side headers like `X-MCP-Toolsets` or `X-MCP-Readonly` to the `headers` object — see [Server Configuration Guide](../server-configuration.md).
33+
34+
## Local Server (Docker)
35+
36+
```json
37+
{
38+
"mcpServers": {
39+
"github": {
40+
"command": "docker",
41+
"args": [
42+
"run", "-i", "--rm",
43+
"-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
44+
"ghcr.io/github/github-mcp-server"
45+
],
46+
"env": {
47+
"GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_GITHUB_PAT"
48+
}
49+
}
50+
}
51+
}
52+
```
53+
54+
## Troubleshooting
55+
56+
- **Connection failures**: Ensure `type` is `streamable-http`, not `http`
57+
- **Authentication failures**: Verify PAT is prefixed with `Bearer ` in the `Authorization` header
58+
- **Docker issues**: Ensure Docker Desktop is running

pkg/github/__toolsnaps__/create_or_update_file.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"annotations": {
33
"title": "Create or update file"
44
},
5-
"description": "Create or update a single file in a GitHub repository. \nIf updating, you should provide the SHA of the file you want to update. Use this tool to create or update a file in a GitHub repository remotely; do not use it for local file operations.\n\nIn order to obtain the SHA of original file version before updating, use the following git command:\ngit ls-tree HEAD \u003cpath to file\u003e\n\nIf the SHA is not provided, the tool will attempt to acquire it by fetching the current file contents from the repository, which may lead to rewriting latest committed changes if the file has changed since last retrieval.\n",
5+
"description": "Create or update a single file in a GitHub repository. \nIf updating, you should provide the SHA of the file you want to update. Use this tool to create or update a file in a GitHub repository remotely; do not use it for local file operations.\n\nIn order to obtain the SHA of original file version before updating, use the following git command:\ngit rev-parse \u003cbranch\u003e:\u003cpath to file\u003e\n\nSHA MUST be provided for existing file updates.\n",
66
"inputSchema": {
77
"properties": {
88
"branch": {
@@ -30,7 +30,7 @@
3030
"type": "string"
3131
},
3232
"sha": {
33-
"description": "The blob SHA of the file being replaced.",
33+
"description": "The blob SHA of the file being replaced. Required if the file already exists.",
3434
"type": "string"
3535
}
3636
},

pkg/github/copilot.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ func AssignCopilotToIssue(t translations.TranslationHelperFunc) inventory.Server
209209
BaseRef string `mapstructure:"base_ref"`
210210
CustomInstructions string `mapstructure:"custom_instructions"`
211211
}
212-
if err := mapstructure.Decode(args, &params); err != nil {
212+
if err := mapstructure.WeakDecode(args, &params); err != nil {
213213
return utils.NewToolResultError(err.Error()), nil, nil
214214
}
215215

pkg/github/copilot_test.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,115 @@ func TestAssignCopilotToIssue(t *testing.T) {
165165
),
166166
),
167167
},
168+
{
169+
name: "successful assignment with string issue_number",
170+
requestArgs: map[string]any{
171+
"owner": "owner",
172+
"repo": "repo",
173+
"issue_number": "123", // Some MCP clients send numeric values as strings
174+
},
175+
mockedClient: githubv4mock.NewMockedHTTPClient(
176+
githubv4mock.NewQueryMatcher(
177+
struct {
178+
Repository struct {
179+
SuggestedActors struct {
180+
Nodes []struct {
181+
Bot struct {
182+
ID githubv4.ID
183+
Login githubv4.String
184+
TypeName string `graphql:"__typename"`
185+
} `graphql:"... on Bot"`
186+
}
187+
PageInfo struct {
188+
HasNextPage bool
189+
EndCursor string
190+
}
191+
} `graphql:"suggestedActors(first: 100, after: $endCursor, capabilities: CAN_BE_ASSIGNED)"`
192+
} `graphql:"repository(owner: $owner, name: $name)"`
193+
}{},
194+
map[string]any{
195+
"owner": githubv4.String("owner"),
196+
"name": githubv4.String("repo"),
197+
"endCursor": (*githubv4.String)(nil),
198+
},
199+
githubv4mock.DataResponse(map[string]any{
200+
"repository": map[string]any{
201+
"suggestedActors": map[string]any{
202+
"nodes": []any{
203+
map[string]any{
204+
"id": githubv4.ID("copilot-swe-agent-id"),
205+
"login": githubv4.String("copilot-swe-agent"),
206+
"__typename": "Bot",
207+
},
208+
},
209+
},
210+
},
211+
}),
212+
),
213+
githubv4mock.NewQueryMatcher(
214+
struct {
215+
Repository struct {
216+
ID githubv4.ID
217+
Issue struct {
218+
ID githubv4.ID
219+
Assignees struct {
220+
Nodes []struct {
221+
ID githubv4.ID
222+
}
223+
} `graphql:"assignees(first: 100)"`
224+
} `graphql:"issue(number: $number)"`
225+
} `graphql:"repository(owner: $owner, name: $name)"`
226+
}{},
227+
map[string]any{
228+
"owner": githubv4.String("owner"),
229+
"name": githubv4.String("repo"),
230+
"number": githubv4.Int(123),
231+
},
232+
githubv4mock.DataResponse(map[string]any{
233+
"repository": map[string]any{
234+
"id": githubv4.ID("test-repo-id"),
235+
"issue": map[string]any{
236+
"id": githubv4.ID("test-issue-id"),
237+
"assignees": map[string]any{
238+
"nodes": []any{},
239+
},
240+
},
241+
},
242+
}),
243+
),
244+
githubv4mock.NewMutationMatcher(
245+
struct {
246+
UpdateIssue struct {
247+
Issue struct {
248+
ID githubv4.ID
249+
Number githubv4.Int
250+
URL githubv4.String
251+
}
252+
} `graphql:"updateIssue(input: $input)"`
253+
}{},
254+
UpdateIssueInput{
255+
ID: githubv4.ID("test-issue-id"),
256+
AssigneeIDs: []githubv4.ID{githubv4.ID("copilot-swe-agent-id")},
257+
AgentAssignment: &AgentAssignmentInput{
258+
BaseRef: nil,
259+
CustomAgent: ptrGitHubv4String(""),
260+
CustomInstructions: ptrGitHubv4String(""),
261+
TargetRepositoryID: githubv4.ID("test-repo-id"),
262+
},
263+
},
264+
nil,
265+
githubv4mock.DataResponse(map[string]any{
266+
"updateIssue": map[string]any{
267+
"issue": map[string]any{
268+
"id": githubv4.ID("test-issue-id"),
269+
"number": githubv4.Int(123),
270+
"url": githubv4.String("https://github.com/owner/repo/issues/123"),
271+
},
272+
},
273+
}),
274+
),
275+
),
276+
},
168277
{
169278
name: "successful assignment when there are existing assignees",
170279
requestArgs: map[string]any{

pkg/github/discussions.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ func GetDiscussion(t translations.TranslationHelperFunc) inventory.ServerTool {
313313
Repo string
314314
DiscussionNumber int32
315315
}
316-
if err := mapstructure.Decode(args, &params); err != nil {
316+
if err := mapstructure.WeakDecode(args, &params); err != nil {
317317
return utils.NewToolResultError(err.Error()), nil, nil
318318
}
319319
client, err := deps.GetGQLClient(ctx)
@@ -417,7 +417,7 @@ func GetDiscussionComments(t translations.TranslationHelperFunc) inventory.Serve
417417
Repo string
418418
DiscussionNumber int32
419419
}
420-
if err := mapstructure.Decode(args, &params); err != nil {
420+
if err := mapstructure.WeakDecode(args, &params); err != nil {
421421
return utils.NewToolResultError(err.Error()), nil, nil
422422
}
423423

0 commit comments

Comments
 (0)