Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions .github/agents/go-sdk-tool-migrator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
name: go-sdk-tool-migrator
description: Agent specializing in migrating MCP tools from mark3labs/mcp-go to modelcontextprotocol/go-sdk
---

You are a specialized agent designed to assist developers in migrating MCP tools from the mark3labs/mcp-go library to the modelcontextprotocol/go-sdk. Your primary function is to analyze a single existing MCP tool implemented using mark3labs/mcp-go and convert it to use the modelcontextprotocol/go-sdk.

You should focus on ONLY the tool provided to you and it's corresponding test file.

When generating the migration guide, consider the following aspects:

* The initial tool file and it's corresponding test file will be fully commented out, as the tests will fail if the code is uncommented. The code should be uncommented before work begins.
* The import for `github.com/mark3labs/mcp-go/mcp` should be changed to `github.com/modelcontextprotocol/go-sdk/mcp`
* The return type for the tool constructor function should be updated from `mcp.Tool, server.ToolHandlerFunc` to `(mcp.Tool, mcp.ToolHandlerFor[map[string]any, any])`.
* The tool handler function signature should be updated to use generics, changing from `func(ctx context.Context, mcp.CallToolRequest) (*mcp.CallToolResult, error)` to `func(context.Context, *mcp.CallToolRequest, map[string]any) (*mcp.CallToolResult, any, error)`.
* The `RequiredParam`, `RequiredInt`, `RequiredBigInt`, `OptionalParamOK`, `OptionalParam`, `OptionalIntParam`, `OptionalIntParamWithDefault`, `OptionalBoolParamWithDefault`, `OptionalStringArrayParam`, `OptionalBigIntArrayParam` and `OptionalCursorPaginationParams` functions should be changed to use the tool arguments that are now passed as a map in the tool handler function, rather than extracting them from the `mcp.CallToolRequest`.

# Schema Changes

The biggest change when migrating MCP tools from mark3labs/mcp-go to modelcontextprotocol/go-sdk is the way input and output schemas are defined and handled. In mark3labs/mcp-go, input and output schemas were often defined using a DSL provided by the library. In modelcontextprotocol/go-sdk, schemas are defined using jsonschema.Schema structures, which are more verbose.

When migrating a tool, you will need to convert the existing schema definitions to JSON Schema format. This involves defining the properties, types, and any validation rules using the JSON Schema specification.

# Example Schema Guide

If we take an example of a tool that has the following input schema in mark3labs/mcp-go:

```go
...
return mcp.NewTool(
"list_dependabot_alerts",
mcp.WithDescription(t("TOOL_LIST_DEPENDABOT_ALERTS_DESCRIPTION", "List dependabot alerts in a GitHub repository.")),
mcp.WithToolAnnotation(mcp.ToolAnnotation{
Title: t("TOOL_LIST_DEPENDABOT_ALERTS_USER_TITLE", "List dependabot alerts"),
ReadOnlyHint: ToBoolPtr(true),
}),
mcp.WithString("owner",
mcp.Required(),
mcp.Description("The owner of the repository."),
),
mcp.WithString("repo",
mcp.Required(),
mcp.Description("The name of the repository."),
),
mcp.WithString("state",
mcp.Description("Filter dependabot alerts by state. Defaults to open"),
mcp.DefaultString("open"),
mcp.Enum("open", "fixed", "dismissed", "auto_dismissed"),
),
mcp.WithString("severity",
mcp.Description("Filter dependabot alerts by severity"),
mcp.Enum("low", "medium", "high", "critical"),
),
),
...
```

The corresponding input schema in modelcontextprotocol/go-sdk would look like this:

```go
...
return mcp.Tool{
Name: "list_dependabot_alerts",
Description: t("TOOL_LIST_DEPENDABOT_ALERTS_DESCRIPTION", "List dependabot alerts in a GitHub repository."),
Annotations: &mcp.ToolAnnotations{
Title: t("TOOL_LIST_DEPENDABOT_ALERTS_USER_TITLE", "List dependabot alerts"),
ReadOnlyHint: true,
},
InputSchema: &jsonschema.Schema{
Type: "object",
Properties: map[string]*jsonschema.Schema{
"owner": {
Type: "string",
Description: "The owner of the repository.",
},
"repo": {
Type: "string",
Description: "The name of the repository.",
},
"state": {
Type: "string",
Description: "Filter dependabot alerts by state. Defaults to open",
Enum: []string{"open", "fixed", "dismissed", "auto_dismissed"},
Default: "open",
},
"severity": {
Type: "string",
Description: "Filter dependabot alerts by severity",
Enum: []string{"low", "medium", "high", "critical"},
},
},
Required: []string{"owner", "repo"},
},
}
```

2 changes: 1 addition & 1 deletion .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
Expand Down
24 changes: 15 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ The following sets of tools are available:
| `users` | GitHub User related tools |
<!-- END AUTOMATED TOOLSETS -->

### Additional Toolsets in Remote Github MCP Server
### Additional Toolsets in Remote GitHub MCP Server

| Toolset | Description |
| ----------------------- | ------------------------------------------------------------- |
Expand Down Expand Up @@ -844,24 +844,30 @@ Options are:
- `project_number`: The project's number. (number, required)

- **list_project_fields** - List project fields
- `after`: Forward pagination cursor from previous pageInfo.nextCursor. (string, optional)
- `before`: Backward pagination cursor from previous pageInfo.prevCursor (rare). (string, optional)
- `owner`: If owner_type == user it is the handle for the GitHub user account. If owner_type == org it is the name of the organization. The name is not case sensitive. (string, required)
- `owner_type`: Owner type (string, required)
- `per_page`: Number of results per page (max 100, default: 30) (number, optional)
- `per_page`: Results per page (max 50) (number, optional)
- `project_number`: The project's number. (number, required)

- **list_project_items** - List project items
- `fields`: Specific list of field IDs to include in the response (e.g. ["102589", "985201", "169875"]). If not provided, only the title field is included. (string[], optional)
- `after`: Forward pagination cursor from previous pageInfo.nextCursor. (string, optional)
- `before`: Backward pagination cursor from previous pageInfo.prevCursor (rare). (string, optional)
- `fields`: Field IDs to include (e.g. ["102589", "985201"]). CRITICAL: Always provide to get field values. Without this, only titles returned. (string[], optional)
- `owner`: If owner_type == user it is the handle for the GitHub user account. If owner_type == org it is the name of the organization. The name is not case sensitive. (string, required)
- `owner_type`: Owner type (string, required)
- `per_page`: Number of results per page (max 100, default: 30) (number, optional)
- `per_page`: Results per page (max 50) (number, optional)
- `project_number`: The project's number. (number, required)
- `query`: Search query to filter items (string, optional)
- `query`: Query string for advanced filtering of project items using GitHub's project filtering syntax. (string, optional)

- **list_projects** - List projects
- `after`: Forward pagination cursor from previous pageInfo.nextCursor. (string, optional)
- `before`: Backward pagination cursor from previous pageInfo.prevCursor (rare). (string, optional)
- `owner`: If owner_type == user it is the handle for the GitHub user account. If owner_type == org it is the name of the organization. The name is not case sensitive. (string, required)
- `owner_type`: Owner type (string, required)
- `per_page`: Number of results per page (max 100, default: 30) (number, optional)
- `query`: Filter projects by a search query (matches title and description) (string, optional)
- `per_page`: Results per page (max 50) (number, optional)
- `query`: Filter projects by title text and open/closed state; permitted qualifiers: is:open, is:closed; examples: "roadmap is:open", "is:open feature planning". (string, optional)

- **update_project_item** - Update project item
- `item_id`: The unique identifier of the project item. This is not the issue or pull request ID. (number, required)
Expand Down Expand Up @@ -1182,7 +1188,7 @@ Possible options:
</details>
<!-- END AUTOMATED TOOLS -->

### Additional Tools in Remote Github MCP Server
### Additional Tools in Remote GitHub MCP Server

<details>

Expand Down Expand Up @@ -1218,7 +1224,7 @@ Possible options:

## Dynamic Tool Discovery

**Note**: This feature is currently in beta and may not be available in all environments. Please test it out and let us know if you encounter any issues.
**Note**: This feature is currently in beta and is not available in the Remote GitHub MCP Server. Please test it out and let us know if you encounter any issues.

Instead of starting with all tools enabled, you can turn on dynamic toolset discovery. Dynamic toolsets allow the MCP host to list and enable toolsets in response to a user prompt. This should help to avoid situations where the model gets confused by the sheer number of tools available.

Expand Down
2 changes: 1 addition & 1 deletion cmd/github-mcp-server/generate_docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/github/github-mcp-server/pkg/raw"
"github.com/github/github-mcp-server/pkg/toolsets"
"github.com/github/github-mcp-server/pkg/translations"
gogithub "github.com/google/go-github/v77/github"
gogithub "github.com/google/go-github/v79/github"
"github.com/mark3labs/mcp-go/mcp"
"github.com/shurcooL/githubv4"
"github.com/spf13/cobra"
Expand Down
2 changes: 1 addition & 1 deletion docs/remote-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ The Remote GitHub MCP server has optional headers equivalent to the Local server

- `X-MCP-Toolsets`: Comma-separated list of toolsets to enable. E.g. "repos,issues".
- Equivalent to `GITHUB_TOOLSETS` env var for Local server.
- If the list is empty, default toolsets will be used. If a bad toolset is provided, the server will fail to start and emit a 400 bad request status. Whitespace is ignored.
- If the list is empty, default toolsets will be used. Invalid or unknown toolsets are silently ignored without error and will not prevent the server from starting. Whitespace is ignored.
- `X-MCP-Readonly`: Enables only "read" tools.
- Equivalent to `GITHUB_READ_ONLY` env var for Local server.
- If this header is empty, "false", "f", "no", "n", "0", or "off" (ignoring whitespace and case), it will be interpreted as false. All other values are interpreted as true.
Expand Down
2 changes: 1 addition & 1 deletion e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"github.com/github/github-mcp-server/internal/ghmcp"
"github.com/github/github-mcp-server/pkg/github"
"github.com/github/github-mcp-server/pkg/translations"
gogithub "github.com/google/go-github/v77/github"
gogithub "github.com/google/go-github/v79/github"
mcpClient "github.com/mark3labs/mcp-go/client"
"github.com/mark3labs/mcp-go/mcp"
"github.com/stretchr/testify/require"
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/github/github-mcp-server
go 1.24.0

require (
github.com/google/go-github/v77 v77.0.0
github.com/google/go-github/v79 v79.0.0
github.com/josephburnett/jd v1.9.2
github.com/mark3labs/mcp-go v0.36.0
github.com/microcosm-cc/bluemonday v1.0.27
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-github/v71 v71.0.0 h1:Zi16OymGKZZMm8ZliffVVJ/Q9YZreDKONCr+WUd0Z30=
github.com/google/go-github/v71 v71.0.0/go.mod h1:URZXObp2BLlMjwu0O8g4y6VBneUj2bCHgnI8FfgZ51M=
github.com/google/go-github/v77 v77.0.0 h1:9DsKKbZqil5y/4Z9mNpZDQnpli6PJbqipSuuNdcbjwI=
github.com/google/go-github/v77 v77.0.0/go.mod h1:c8VmGXRUmaZUqbctUcGEDWYnMrtzZfJhDSylEf1wfmA=
github.com/google/go-github/v79 v79.0.0 h1:MdodQojuFPBhmtwHiBcIGLw/e/wei2PvFX9ndxK0X4Y=
github.com/google/go-github/v79 v79.0.0/go.mod h1:OAFbNhq7fQwohojb06iIIQAB9CBGYLq999myfUFnrS4=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
Expand Down
2 changes: 1 addition & 1 deletion internal/ghmcp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
mcplog "github.com/github/github-mcp-server/pkg/log"
"github.com/github/github-mcp-server/pkg/raw"
"github.com/github/github-mcp-server/pkg/translations"
gogithub "github.com/google/go-github/v77/github"
gogithub "github.com/google/go-github/v79/github"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"github.com/shurcooL/githubv4"
Expand Down
2 changes: 1 addition & 1 deletion pkg/errors/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"fmt"

"github.com/google/go-github/v77/github"
"github.com/google/go-github/v79/github"
"github.com/mark3labs/mcp-go/mcp"
)

Expand Down
2 changes: 1 addition & 1 deletion pkg/errors/error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"net/http"
"testing"

"github.com/google/go-github/v77/github"
"github.com/google/go-github/v79/github"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down
10 changes: 9 additions & 1 deletion pkg/github/__toolsnaps__/list_project_fields.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
"description": "List Project fields for a user or org",
"inputSchema": {
"properties": {
"after": {
"description": "Forward pagination cursor from previous pageInfo.nextCursor.",
"type": "string"
},
"before": {
"description": "Backward pagination cursor from previous pageInfo.prevCursor (rare).",
"type": "string"
},
"owner": {
"description": "If owner_type == user it is the handle for the GitHub user account. If owner_type == org it is the name of the organization. The name is not case sensitive.",
"type": "string"
Expand All @@ -19,7 +27,7 @@
"type": "string"
},
"per_page": {
"description": "Number of results per page (max 100, default: 30)",
"description": "Results per page (max 50)",
"type": "number"
},
"project_number": {
Expand Down
16 changes: 12 additions & 4 deletions pkg/github/__toolsnaps__/list_project_items.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@
"title": "List project items",
"readOnlyHint": true
},
"description": "List Project items for a user or org",
"description": "Search project items with advanced filtering",
"inputSchema": {
"properties": {
"after": {
"description": "Forward pagination cursor from previous pageInfo.nextCursor.",
"type": "string"
},
"before": {
"description": "Backward pagination cursor from previous pageInfo.prevCursor (rare).",
"type": "string"
},
"fields": {
"description": "Specific list of field IDs to include in the response (e.g. [\"102589\", \"985201\", \"169875\"]). If not provided, only the title field is included.",
"description": "Field IDs to include (e.g. [\"102589\", \"985201\"]). CRITICAL: Always provide to get field values. Without this, only titles returned.",
"items": {
"type": "string"
},
Expand All @@ -26,15 +34,15 @@
"type": "string"
},
"per_page": {
"description": "Number of results per page (max 100, default: 30)",
"description": "Results per page (max 50)",
"type": "number"
},
"project_number": {
"description": "The project's number.",
"type": "number"
},
"query": {
"description": "Search query to filter items",
"description": "Query string for advanced filtering of project items using GitHub's project filtering syntax.",
"type": "string"
}
},
Expand Down
14 changes: 11 additions & 3 deletions pkg/github/__toolsnaps__/list_projects.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@
"title": "List projects",
"readOnlyHint": true
},
"description": "List Projects for a user or org",
"description": "List Projects for a user or organization",
"inputSchema": {
"properties": {
"after": {
"description": "Forward pagination cursor from previous pageInfo.nextCursor.",
"type": "string"
},
"before": {
"description": "Backward pagination cursor from previous pageInfo.prevCursor (rare).",
"type": "string"
},
"owner": {
"description": "If owner_type == user it is the handle for the GitHub user account. If owner_type == org it is the name of the organization. The name is not case sensitive.",
"type": "string"
Expand All @@ -19,11 +27,11 @@
"type": "string"
},
"per_page": {
"description": "Number of results per page (max 100, default: 30)",
"description": "Results per page (max 50)",
"type": "number"
},
"query": {
"description": "Filter projects by a search query (matches title and description)",
"description": "Filter projects by title text and open/closed state; permitted qualifiers: is:open, is:closed; examples: \"roadmap is:open\", \"is:open feature planning\".",
"type": "string"
}
},
Expand Down
2 changes: 1 addition & 1 deletion pkg/github/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
buffer "github.com/github/github-mcp-server/pkg/buffer"
ghErrors "github.com/github/github-mcp-server/pkg/errors"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/google/go-github/v77/github"
"github.com/google/go-github/v79/github"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
Expand Down
2 changes: 1 addition & 1 deletion pkg/github/actions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/github/github-mcp-server/internal/profiler"
buffer "github.com/github/github-mcp-server/pkg/buffer"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/google/go-github/v77/github"
"github.com/google/go-github/v79/github"
"github.com/migueleliasweb/go-github-mock/src/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down
2 changes: 1 addition & 1 deletion pkg/github/code_scanning.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

ghErrors "github.com/github/github-mcp-server/pkg/errors"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/google/go-github/v77/github"
"github.com/google/go-github/v79/github"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
Expand Down
2 changes: 1 addition & 1 deletion pkg/github/code_scanning_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

"github.com/github/github-mcp-server/internal/toolsnaps"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/google/go-github/v77/github"
"github.com/google/go-github/v79/github"
"github.com/migueleliasweb/go-github-mock/src/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down
2 changes: 1 addition & 1 deletion pkg/github/context_tools_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/github/github-mcp-server/internal/githubv4mock"
"github.com/github/github-mcp-server/internal/toolsnaps"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/google/go-github/v77/github"
"github.com/google/go-github/v79/github"
"github.com/migueleliasweb/go-github-mock/src/mock"
"github.com/shurcooL/githubv4"
"github.com/stretchr/testify/assert"
Expand Down
2 changes: 1 addition & 1 deletion pkg/github/dependabot.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

ghErrors "github.com/github/github-mcp-server/pkg/errors"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/google/go-github/v77/github"
"github.com/google/go-github/v79/github"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
Expand Down
Loading
Loading