import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
import { z } from "zod"
// 创建 MCP Server 实例
const server = new McpServer({
name: "github-tools", // Server 名称
version: "1.0.0", // Server 版本
})
// 注册工具:查询 GitHub 仓库信息
server.tool(
"github_repo_info", // 工具名称
"查询 GitHub 仓库的基本信息,包括 star 数、描述、语言等", // 工具描述
{
owner: z.string().describe("仓库所有者(用户名或组织名)"),
repo: z.string().describe("仓库名称"),
},
async ({ owner, repo }) => {
try {
const response = await fetch(
`https://api.github.com/repos/${owner}/${repo}`,
{
headers: {
"Accept": "application/vnd.github.v3+json",
"User-Agent": "my-mcp-server",
},
}
)
if (!response.ok) {
return {
content: [{
type: "text" as const,
text: `错误:无法获取仓库 ${owner}/${repo},HTTP ${response.status}`,
}],
}
}
const data = await response.json()
const info = [
`📦 ${data.full_name}`,
`📝 ${data.description || "无描述"}`,
`⭐ ${data.stargazers_count} stars`,
`🔀 ${data.forks_count} forks`,
`👁️ ${data.watchers_count} watchers`,
`💻 主要语言: ${data.language || "未知"}`,
`📄 许可证: ${data.license?.name || "无"}`,
`🔗 ${data.html_url}`,
`📅 创建于: ${new Date(data.created_at).toLocaleDateString()}`,
`📅 最近更新: ${new Date(data.updated_at).toLocaleDateString()}`,
].join("\n")
return {
content: [{ type: "text" as const, text: info }],
}
} catch (error: any) {
return {
content: [{
type: "text" as const,
text: `请求失败: ${error.message}`,
}],
}
}
}
)
// 注册第二个工具:搜索 GitHub 仓库
server.tool(
"github_search_repos",
"在 GitHub 上搜索仓库",
{
query: z.string().describe("搜索关键词"),
limit: z.number().min(1).max(10).default(5)
.describe("返回结果数量,默认 5"),
},
async ({ query, limit }) => {
try {
const response = await fetch(
`https://api.github.com/search/repositories?q=${
encodeURIComponent(query)
}&sort=stars&per_page=${limit}`,
{
headers: {
"Accept": "application/vnd.github.v3+json",
"User-Agent": "my-mcp-server",
},
}
)
const data = await response.json()
if (!data.items?.length) {
return {
content: [{
type: "text" as const,
text: `未找到与 "${query}" 相关的仓库`,
}],
}
}
const results = data.items.map((item: any, i: number) =>
`${i + 1}. ${item.full_name} ⭐${item.stargazers_count}\n` +
` ${item.description || "无描述"}\n` +
` ${item.html_url}`
).join("\n\n")
return {
content: [{
type: "text" as const,
text: `搜索 "${query}" 的结果(共 ${data.total_count} 个,显示前 ${limit} 个):\n\n${results}`,
}],
}
} catch (error: any) {
return {
content: [{
type: "text" as const,
text: `搜索失败: ${error.message}`,
}],
}
}
}
)
// 启动 Server,使用 Stdio 传输
async function main() {
const transport = new StdioServerTransport()
await server.connect(transport)
// Server 现在通过 stdin/stdout 等待请求
// 注意:不要在 Server 中使用 console.log,它会干扰 Stdio 通信
console.error("GitHub MCP Server 已启动")
}
main().catch(console.error)