Skip to main content
Glama

Claude TypeScript MCP Servers

by ukkz
github.ts13.4 kB
#!/usr/bin/env node /** * GitHub MCP サーバー * * このファイルは、GitHub APIを介してファイル操作、リポジトリ管理、 * 検索機能、Issue、プルリクエストなどの操作を可能にする * Model Context Protocol (MCP) サーバーを実装しています。 * * 主な機能: * - ファイルの作成・更新 * - リポジトリの検索・作成 * - Issue管理 * - プルリクエスト操作 * - ブランチ作成 * - コード検索 * - リリース管理 */ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js"; import { z } from "zod"; // Import shared utilities and types import { formatGitHubError, isGitHubError } from "./github/common/errors"; import { VERSION } from "./github/common/utils"; import * as interfaces from "./github/common/interfaces"; // Import operation modules import * as files from "./github/operations/files"; import * as repository from "./github/operations/repository"; import * as branches from "./github/operations/branches"; import * as issues from "./github/operations/issues"; import * as pulls from "./github/operations/pulls"; import * as search from "./github/operations/search"; import * as releases from "./github/operations/releases"; // Import tool definitions import { GITHUB_TOOLS } from "./github/tools/definitions"; // 共通ヘルパー関数 /** * 標準化されたJSONレスポンスを生成する */ function createJsonResponse(data: unknown) { return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], }; } /** * リスト操作系のデフォルト値を設定する */ function applyIssueListDefaults(options: Partial<interfaces.ListIssuesArguments>) { return { state: options.state || "open", sort: options.sort || "created", direction: options.direction || "desc", page: options.page || 1, per_page: options.per_page || 30, account_profile: options.account_profile, }; } /** * PRリストのデフォルト値を設定する */ function applyPullListDefaults(options: Partial<interfaces.ListPullRequestsArguments>) { return { state: options.state || "open", sort: options.sort || "created", direction: options.direction || "desc", page: options.page || 1, per_page: options.per_page || 30, account_profile: options.account_profile, }; } /** * PRマージのデフォルト値を設定する */ function applyMergeDefaults(options: Partial<interfaces.MergePullRequestArguments>) { return { commit_title: options.commit_title, commit_message: options.commit_message, merge_method: options.merge_method || "merge", }; } const server = new Server( { name: "github-mcp-server", version: VERSION, }, { capabilities: { tools: {}, }, }, ); // Register available tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: GITHUB_TOOLS, }; }); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request) => { try { if (!request.params.arguments) { throw new Error("Arguments are required"); } switch (request.params.name) { case "create_branch": { const args = branches.CreateBranchSchema.parse( request.params.arguments, ) as interfaces.CreateBranchArguments; const branch = await branches.createBranchFromRef( args.owner, args.repo, args.branch, args.from_branch, args.account_profile, ); return createJsonResponse(branch); } case "search_repositories": { const args = repository.SearchRepositoriesSchema.parse( request.params.arguments, ) as interfaces.SearchRepositoriesArguments; const results = await repository.searchRepositories( args.query, args.page, args.perPage, args.account_profile, ); return createJsonResponse(results); } case "create_repository": { const args = repository.CreateRepositoryOptionsSchema.parse( request.params.arguments, ) as interfaces.CreateRepositoryArguments; const result = await repository.createRepository(args); return createJsonResponse(result); } case "get_file_contents": { const args = files.GetFileContentsSchema.parse( request.params.arguments, ) as interfaces.GetFileContentsArguments; const contents = await files.getFileContents( args.owner, args.repo, args.path, args.branch, args.account_profile, ); return createJsonResponse(contents); } case "create_or_update_file": { const args = files.CreateOrUpdateFileSchema.parse( request.params.arguments, ) as interfaces.CreateOrUpdateFileArguments; const result = await files.createOrUpdateFile( args.owner, args.repo, args.path, args.content, args.message, args.branch, args.sha, args.account_profile, ); return createJsonResponse(result); } case "push_files": { const args = files.PushFilesSchema.parse( request.params.arguments, ) as interfaces.PushFilesArguments; const result = await files.pushFiles( args.owner, args.repo, args.branch, args.files, args.message, args.account_profile, ); return createJsonResponse(result); } case "create_issue": { const args = issues.CreateIssueSchema.parse( request.params.arguments, ) as interfaces.CreateIssueArguments; const { owner, repo, account_profile, ...options } = args; const issue = await issues.createIssue(owner, repo, options, account_profile); return createJsonResponse(issue); } case "get_issue": { const args = issues.GetIssueSchema.parse( request.params.arguments, ) as interfaces.GetIssueArguments; const issue = await issues.getIssue( args.owner, args.repo, args.issue_number, args.account_profile, ); return createJsonResponse(issue); } case "list_issues": { const args = issues.ListIssuesOptionsSchema.parse( request.params.arguments, ) as interfaces.ListIssuesArguments; const { owner, repo, ...options } = args; const issuesOptions = applyIssueListDefaults(options); const issuesList = await issues.listIssues(owner, repo, issuesOptions); return createJsonResponse(issuesList); } case "update_issue": { const args = issues.UpdateIssueOptionsSchema.parse( request.params.arguments, ) as interfaces.UpdateIssueArguments; const { owner, repo, issue_number, account_profile, ...options } = args; const issue = await issues.updateIssue(owner, repo, issue_number, options, account_profile); return createJsonResponse(issue); } case "add_issue_comment": { const args = issues.IssueCommentSchema.parse( request.params.arguments, ) as interfaces.IssueCommentArguments; const { owner, repo, issue_number, body, account_profile } = args; const result = await issues.addIssueComment( owner, repo, issue_number, body, account_profile, ); return createJsonResponse(result); } case "create_pull_request": { const args = pulls.CreatePullRequestSchema.parse( request.params.arguments, ) as interfaces.CreatePullRequestArguments; const pullRequest = await pulls.createPullRequest(args, args.account_profile); return createJsonResponse(pullRequest); } case "get_pull_request": { const args = pulls.GetPullRequestSchema.parse( request.params.arguments, ) as interfaces.GetPullRequestArguments; const pullRequest = await pulls.getPullRequest( args.owner, args.repo, args.pull_number, args.account_profile, ); return createJsonResponse(pullRequest); } case "list_pull_requests": { const args = pulls.ListPullRequestsSchema.parse( request.params.arguments, ) as interfaces.ListPullRequestsArguments; const { owner, repo, ...options } = args; const pullOptions = applyPullListDefaults(options); const pullRequests = await pulls.listPullRequests(owner, repo, pullOptions); return createJsonResponse(pullRequests); } case "merge_pull_request": { const args = pulls.MergePullRequestSchema.parse( request.params.arguments, ) as interfaces.MergePullRequestArguments; const { owner, repo, pull_number, account_profile, ...options } = args; const mergeOptions = applyMergeDefaults(options); const result = await pulls.mergePullRequest( owner, repo, pull_number, mergeOptions, account_profile, ); return createJsonResponse(result); } case "search_code": { const args = search.SearchCodeSchema.parse( request.params.arguments, ) as interfaces.SearchCodeArguments; const results = await search.searchCode(args); return createJsonResponse(results); } case "search_issues": { const args = search.SearchIssuesSchema.parse( request.params.arguments, ) as interfaces.SearchIssuesArguments; const results = await search.searchIssues(args); return createJsonResponse(results); } case "search_users": { const args = search.SearchUsersSchema.parse( request.params.arguments, ) as interfaces.SearchUsersArguments; const results = await search.searchUsers(args); return createJsonResponse(results); } case "create_release": { const args = releases.CreateReleaseSchema.parse( request.params.arguments, ) as interfaces.CreateReleaseArguments; const { owner, repo, tag_name, account_profile, ...options } = args; const release = await releases.createRelease( owner, repo, tag_name, options, account_profile, ); return createJsonResponse(release); } case "get_release": { const args = releases.GetReleaseSchema.parse( request.params.arguments, ) as interfaces.GetReleaseArguments; const release = await releases.getRelease( args.owner, args.repo, args.release_id, args.account_profile, ); return createJsonResponse(release); } case "get_latest_release": { const args = releases.GetLatestReleaseSchema.parse( request.params.arguments, ) as interfaces.GetLatestReleaseArguments; const release = await releases.getLatestRelease( args.owner, args.repo, args.account_profile, ); return createJsonResponse(release); } case "list_releases": { const args = releases.ListReleasesSchema.parse( request.params.arguments, ) as interfaces.ListReleasesArguments; const { owner, repo, account_profile, ...options } = args; const releasesList = await releases.listReleases(owner, repo, options, account_profile); return createJsonResponse(releasesList); } case "update_release": { const args = releases.UpdateReleaseSchema.parse( request.params.arguments, ) as interfaces.UpdateReleaseArguments; const { owner, repo, release_id, account_profile, ...options } = args; const release = await releases.updateRelease( owner, repo, release_id, options, account_profile, ); return createJsonResponse(release); } case "delete_release": { const args = releases.DeleteReleaseSchema.parse( request.params.arguments, ) as interfaces.DeleteReleaseArguments; const result = await releases.deleteRelease( args.owner, args.repo, args.release_id, args.account_profile, ); return createJsonResponse(result); } default: throw new Error(`Unknown tool: ${request.params.name}`); } } catch (error) { if (error instanceof z.ZodError) { throw new Error(`Invalid input: ${JSON.stringify(error.errors)}`); } if (isGitHubError(error)) { throw new Error(formatGitHubError(error)); } throw error; } }); // Start the server async function runServer() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("GitHub MCP Server running on stdio"); } runServer().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ukkz/claude-ts-mcps'

If you have feedback or need assistance with the MCP directory API, please join our Discord server