6 Commits

Author SHA1 Message Date
appleboy
5308fbfb2b docs: add Table of Contents to all README translations (#46)
- Add a Table of Contents section to the README files in English, Simplified Chinese, and Traditional Chinese for improved navigation.

Signed-off-by: appleboy <appleboy.tw@gmail.com>

Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/46
Co-authored-by: appleboy <appleboy.tw@gmail.com>
Co-committed-by: appleboy <appleboy.tw@gmail.com>
2025-05-27 12:32:27 +00:00
Hubert Wawrzyńczyk
a7061f9b64 fix: make API bool parameters in search_repos and list_releases optional (#40) (#44)
Fix #40

Left the `mcp.DefaultBool(false)` for `is_draft` and `is_pre_release` in `list_releases`, because I guess they are default, but it's up to the client whether to set them or not.
11e04b5b8d/operation/repo/release.go (L67-L68)

Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/44
Reviewed-by: Bo-Yi Wu (吳柏毅) <appleboy.tw@gmail.com>
Co-authored-by: Hubert Wawrzyńczyk <hubert@fit-it.pl>
Co-committed-by: Hubert Wawrzyńczyk <hubert@fit-it.pl>
2025-05-27 12:20:47 +00:00
appleboy
f25cc0de8c feat: add HTTP server mode with updated docs and localization (#45)
- Update download instructions for clarity and consistency in all README files
- Add example configuration for HTTP mode to all README files
- Expand transport type support to include "http" in command-line flags and documentation
- Implement HTTP server mode in the application entrypoint
- Update log output behavior to include "http" mode alongside "sse" for stdout logging
- Refine Chinese README translations for greater accuracy and localization

Signed-off-by: appleboy <appleboy.tw@gmail.com>

Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/45
Co-authored-by: appleboy <appleboy.tw@gmail.com>
Co-committed-by: appleboy <appleboy.tw@gmail.com>
2025-05-27 12:17:37 +00:00
Bo-Yi Wu
417ef26da0 build: add VS Code server config and enable versioning of settings (#43)
- Remove .vscode directory from .gitignore to allow versioning of VS Code settings
- Add a VS Code server configuration file with prompts for Gitea host, access token, and insecure connection option
- Configure a stdio-based server launch for gitea-mcp with relevant environment variables

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/43
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2025-05-27 04:15:22 +00:00
Bo-Yi Wu
34ca5d45db refactor(args): request argument access and update dependencies (#42)
- Update dependencies to newer versions in go.mod
- Refactor all request argument accesses to use req.GetArguments() instead of direct access to req.Params.Arguments
- Change variable declaration for ListRepoCommitsTool from a grouped var block to a single var statement for consistency

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/42
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2025-05-26 06:10:10 +00:00
Bo-Yi Wu
796fd4682d docs: document get_user_orgs tool in Chinese guides (#41)
- Add get_user_orgs tool to the list of supported tools in both Simplified and Traditional Chinese documentation

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/41
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2025-05-26 06:01:59 +00:00
20 changed files with 390 additions and 253 deletions

3
.gitignore vendored
View File

@@ -1,7 +1,4 @@
.idea .idea
.vscode
gitea-mcp gitea-mcp
gitea-mcp.exe gitea-mcp.exe
*.log *.log

35
.vscode/mcp.json vendored Normal file
View File

@@ -0,0 +1,35 @@
{
// 💡 Inputs are prompted on first server start, then stored securely by VS Code.
"inputs": [
{
"type": "promptString",
"id": "gitea-host",
"description": "Gitea Host",
"password": false
},
{
"type": "promptString",
"id": "gitea-token",
"description": "Gitea Access Token",
"password": true
},
{
"type": "promptString",
"id": "gitea-insecure",
"description": "Allow insecure connections (e.g., self-signed certificates)",
"default": "false"
}
],
"servers": {
"gitea": {
"type": "stdio",
"command": "gitea-mcp",
"args": ["-t", "stdio"],
"env": {
"GITEA_HOST": "${input:gitea-host}",
"GITEA_ACCESS_TOKEN": "${input:gitea-token}",
"GITEA_INSECURE": "${input:gitea-insecure}"
}
}
}
}

View File

@@ -6,6 +6,22 @@
[![Install with Docker in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=gitea&inputs=[{%22id%22:%22gitea_token%22,%22type%22:%22promptString%22,%22description%22:%22Gitea%20Personal%20Access%20Token%22,%22password%22:true}]&config={%22command%22:%22docker%22,%22args%22:[%22run%22,%22-i%22,%22--rm%22,%22-e%22,%22GITEA_ACCESS_TOKEN%22,%22docker.gitea.com/gitea-mcp-server%22],%22env%22:{%22GITEA_ACCESS_TOKEN%22:%22${input:gitea_token}%22}}) [![Install with Docker in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=gitea&inputs=[{%22id%22:%22gitea_token%22,%22type%22:%22promptString%22,%22description%22:%22Gitea%20Personal%20Access%20Token%22,%22password%22:true}]&config={%22command%22:%22docker%22,%22args%22:[%22run%22,%22-i%22,%22--rm%22,%22-e%22,%22GITEA_ACCESS_TOKEN%22,%22docker.gitea.com/gitea-mcp-server%22],%22env%22:{%22GITEA_ACCESS_TOKEN%22:%22${input:gitea_token}%22}}&quality=insiders) [![Install with Docker in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=gitea&inputs=[{%22id%22:%22gitea_token%22,%22type%22:%22promptString%22,%22description%22:%22Gitea%20Personal%20Access%20Token%22,%22password%22:true}]&config={%22command%22:%22docker%22,%22args%22:[%22run%22,%22-i%22,%22--rm%22,%22-e%22,%22GITEA_ACCESS_TOKEN%22,%22docker.gitea.com/gitea-mcp-server%22],%22env%22:{%22GITEA_ACCESS_TOKEN%22:%22${input:gitea_token}%22}}) [![Install with Docker in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=gitea&inputs=[{%22id%22:%22gitea_token%22,%22type%22:%22promptString%22,%22description%22:%22Gitea%20Personal%20Access%20Token%22,%22password%22:true}]&config={%22command%22:%22docker%22,%22args%22:[%22run%22,%22-i%22,%22--rm%22,%22-e%22,%22GITEA_ACCESS_TOKEN%22,%22docker.gitea.com/gitea-mcp-server%22],%22env%22:{%22GITEA_ACCESS_TOKEN%22:%22${input:gitea_token}%22}}&quality=insiders)
## Table of Contents
- [Gitea MCP Server](#gitea-mcp-server)
- [Table of Contents](#table-of-contents)
- [What is Gitea?](#what-is-gitea)
- [What is MCP?](#what-is-mcp)
- [🚧 Installation](#-installation)
- [Usage with VS Code](#usage-with-vs-code)
- [📥 Download the official binary release](#-download-the-official-binary-release)
- [🔧 Build from Source](#-build-from-source)
- [📁 Add to PATH](#-add-to-path)
- [🚀 Usage](#-usage)
- [✅ Available Tools](#-available-tools)
- [🐛 Debugging](#-debugging)
- [🛠 Troubleshooting](#-troubleshooting)
## What is Gitea? ## What is Gitea?
Gitea is a community-managed lightweight code hosting solution written in Go. It is published under the MIT license. Gitea provides Git hosting including a repository viewer, issue tracking, pull requests, and more. Gitea is a community-managed lightweight code hosting solution written in Go. It is published under the MIT license. Gitea provides Git hosting including a repository viewer, issue tracking, pull requests, and more.
@@ -59,7 +75,7 @@ Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace
### 📥 Download the official binary release ### 📥 Download the official binary release
You can download the official release from [here](https://gitea.com/gitea/gitea-mcp/releases). You can download the official release from [official Gitea MCP binary releases](https://gitea.com/gitea/gitea-mcp/releases).
### 🔧 Build from Source ### 🔧 Build from Source
@@ -129,6 +145,18 @@ To configure the MCP server for Gitea, add the following to your MCP configurati
} }
``` ```
- **http mode**
```json
{
"mcpServers": {
"gitea": {
"url": "http://localhost:8080/mcp"
}
}
}
```
**Default log path**: `$HOME/.gitea-mcp/gitea-mcp.log` **Default log path**: `$HOME/.gitea-mcp/gitea-mcp.log`
> [!NOTE] > [!NOTE]
@@ -146,7 +174,7 @@ list all my repositories
The Gitea MCP Server supports the following tools: The Gitea MCP Server supports the following tools:
| Tool | Scope | Description | | Tool | Scope | Description |
| :--------------------------: | :----------: | :---------------------------------------------------: | | :--------------------------: | :----------: | :------------------------------------------------------: |
| get_my_user_info | User | Get the information of the authenticated user | | get_my_user_info | User | Get the information of the authenticated user |
| get_user_orgs | User | Get organizations associated with the authenticated user | | get_user_orgs | User | Get organizations associated with the authenticated user |
| create_repo | Repository | Create a new repository | | create_repo | Repository | Create a new repository |

View File

@@ -6,6 +6,22 @@
[![在 VS Code 中使用 Docker 安装](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=gitea&inputs=[{%22id%22:%22gitea_token%22,%22type%22:%22promptString%22,%22description%22:%22Gitea%20Personal%20Access%20Token%22,%22password%22:true}]&config={%22command%22:%22docker%22,%22args%22:[%22run%22,%22-i%22,%22--rm%22,%22-e%22,%22GITEA_ACCESS_TOKEN%22,%22docker.gitea.com/gitea-mcp-server%22],%22env%22:{%22GITEA_ACCESS_TOKEN%22:%22${input:gitea_token}%22}}) [![在 VS Code Insiders 中使用 Docker 安装](https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=gitea&inputs=[{%22id%22:%22gitea_token%22,%22type%22:%22promptString%22,%22description%22:%22Gitea%20Personal%20Access%20Token%22,%22password%22:true}]&config={%22command%22:%22docker%22,%22args%22:[%22run%22,%22-i%22,%22--rm%22,%22-e%22,%22GITEA_ACCESS_TOKEN%22,%22docker.gitea.com/gitea-mcp-server%22],%22env%22:{%22GITEA_ACCESS_TOKEN%22:%22${input:gitea_token}%22}}&quality=insiders) [![在 VS Code 中使用 Docker 安装](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=gitea&inputs=[{%22id%22:%22gitea_token%22,%22type%22:%22promptString%22,%22description%22:%22Gitea%20Personal%20Access%20Token%22,%22password%22:true}]&config={%22command%22:%22docker%22,%22args%22:[%22run%22,%22-i%22,%22--rm%22,%22-e%22,%22GITEA_ACCESS_TOKEN%22,%22docker.gitea.com/gitea-mcp-server%22],%22env%22:{%22GITEA_ACCESS_TOKEN%22:%22${input:gitea_token}%22}}) [![在 VS Code Insiders 中使用 Docker 安装](https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=gitea&inputs=[{%22id%22:%22gitea_token%22,%22type%22:%22promptString%22,%22description%22:%22Gitea%20Personal%20Access%20Token%22,%22password%22:true}]&config={%22command%22:%22docker%22,%22args%22:[%22run%22,%22-i%22,%22--rm%22,%22-e%22,%22GITEA_ACCESS_TOKEN%22,%22docker.gitea.com/gitea-mcp-server%22],%22env%22:{%22GITEA_ACCESS_TOKEN%22:%22${input:gitea_token}%22}}&quality=insiders)
## 目录
- [Gitea MCP 服务器](#gitea-mcp-服务器)
- [目录](#目录)
- [什么是 Gitea](#什么是-gitea)
- [什么是 MCP](#什么是-mcp)
- [🚧 安装](#-安装)
- [在 VS Code 中使用](#在-vs-code-中使用)
- [📥 下载官方 Gitea MCP 二进制版本](#-下载官方-gitea-mcp-二进制版本)
- [🔧 从源代码构建](#-从源代码构建)
- [📁 添加到 PATH](#-添加到-path)
- [🚀 使用](#-使用)
- [✅ 可用工具](#-可用工具)
- [🐛 调试](#-调试)
- [🛠 疑难排解](#-疑难排解)
## 什么是 Gitea ## 什么是 Gitea
Gitea 是一个由社区管理的轻量级代码托管解决方案,使用 Go 语言编写。它以 MIT 许可证发布。Gitea 提供 Git 托管,包括仓库查看器、问题追踪、拉取请求等功能。 Gitea 是一个由社区管理的轻量级代码托管解决方案,使用 Go 语言编写。它以 MIT 许可证发布。Gitea 提供 Git 托管,包括仓库查看器、问题追踪、拉取请求等功能。
@@ -57,9 +73,9 @@ Model Context Protocol (MCP) 是一种协议,允许通过聊天界面整合各
} }
``` ```
### 📥 下载官方二进制版本 ### 📥 下载官方 Gitea MCP 二进制版本
您可以从[这里](https://gitea.com/gitea/gitea-mcp/releases)下载官方版本。 您可以从[官方 Gitea MCP 二进制版本](https://gitea.com/gitea/gitea-mcp/releases)下载官方版本。
### 🔧 从源代码构建 ### 🔧 从源代码构建
@@ -129,6 +145,18 @@ cp gitea-mcp /usr/local/bin/
} }
``` ```
- **http 模式**
```json
{
"mcpServers": {
"gitea": {
"url": "http://localhost:8080/mcp"
}
}
}
```
**默认日志路径**: `$HOME/.gitea-mcp/gitea-mcp.log` **默认日志路径**: `$HOME/.gitea-mcp/gitea-mcp.log`
> [!注意] > [!注意]
@@ -148,6 +176,7 @@ Gitea MCP 服务器支持以下工具:
| 工具 | 范围 | 描述 | | 工具 | 范围 | 描述 |
| :--------------------------: | :------: | :--------------------------: | | :--------------------------: | :------: | :--------------------------: |
| get_my_user_info | 用户 | 获取已认证用户的信息 | | get_my_user_info | 用户 | 获取已认证用户的信息 |
| get_user_orgs | 用户 | 获取已认证用户关联的组织 |
| create_repo | 仓库 | 创建一个新仓库 | | create_repo | 仓库 | 创建一个新仓库 |
| fork_repo | 仓库 | 复刻一个仓库 | | fork_repo | 仓库 | 复刻一个仓库 |
| list_my_repos | 仓库 | 列出已认证用户拥有的所有仓库 | | list_my_repos | 仓库 | 列出已认证用户拥有的所有仓库 |

View File

@@ -6,6 +6,22 @@
[![在 VS Code 中使用 Docker 安裝](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=gitea&inputs=[{%22id%22:%22gitea_token%22,%22type%22:%22promptString%22,%22description%22:%22Gitea%20Personal%20Access%20Token%22,%22password%22:true}]&config={%22command%22:%22docker%22,%22args%22:[%22run%22,%22-i%22,%22--rm%22,%22-e%22,%22GITEA_ACCESS_TOKEN%22,%22docker.gitea.com/gitea-mcp-server%22],%22env%22:{%22GITEA_ACCESS_TOKEN%22:%22${input:gitea_token}%22}}) [![在 VS Code Insiders 中使用 Docker 安裝](https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=gitea&inputs=[{%22id%22:%22gitea_token%22,%22type%22:%22promptString%22,%22description%22:%22Gitea%20Personal%20Access%20Token%22,%22password%22:true}]&config={%22command%22:%22docker%22,%22args%22:[%22run%22,%22-i%22,%22--rm%22,%22-e%22,%22GITEA_ACCESS_TOKEN%22,%22docker.gitea.com/gitea-mcp-server%22],%22env%22:{%22GITEA_ACCESS_TOKEN%22:%22${input:gitea_token}%22}}&quality=insiders) [![在 VS Code 中使用 Docker 安裝](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=gitea&inputs=[{%22id%22:%22gitea_token%22,%22type%22:%22promptString%22,%22description%22:%22Gitea%20Personal%20Access%20Token%22,%22password%22:true}]&config={%22command%22:%22docker%22,%22args%22:[%22run%22,%22-i%22,%22--rm%22,%22-e%22,%22GITEA_ACCESS_TOKEN%22,%22docker.gitea.com/gitea-mcp-server%22],%22env%22:{%22GITEA_ACCESS_TOKEN%22:%22${input:gitea_token}%22}}) [![在 VS Code Insiders 中使用 Docker 安裝](https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=gitea&inputs=[{%22id%22:%22gitea_token%22,%22type%22:%22promptString%22,%22description%22:%22Gitea%20Personal%20Access%20Token%22,%22password%22:true}]&config={%22command%22:%22docker%22,%22args%22:[%22run%22,%22-i%22,%22--rm%22,%22-e%22,%22GITEA_ACCESS_TOKEN%22,%22docker.gitea.com/gitea-mcp-server%22],%22env%22:{%22GITEA_ACCESS_TOKEN%22:%22${input:gitea_token}%22}}&quality=insiders)
## 目錄
- [Gitea MCP 伺服器](#gitea-mcp-伺服器)
- [目錄](#目錄)
- [什麼是 Gitea](#什麼是-gitea)
- [什麼是 MCP](#什麼是-mcp)
- [🚧 安裝](#-安裝)
- [在 VS Code 中使用](#在-vs-code-中使用)
- [📥 下載官方 Gitea MCP 二進位版本](#-下載官方-gitea-mcp-二進位版本)
- [🔧 從源代碼構建](#-從源代碼構建)
- [📁 添加到 PATH](#-添加到-path)
- [🚀 使用](#-使用)
- [✅ 可用工具](#-可用工具)
- [🐛 調試](#-調試)
- [🛠 疑難排解](#-疑難排解)
## 什麼是 Gitea ## 什麼是 Gitea
Gitea 是一個由社群管理的輕量級代碼託管解決方案,使用 Go 語言編寫。它以 MIT 許可證發布。Gitea 提供 Git 託管,包括倉庫查看器、問題追蹤、拉取請求等功能。 Gitea 是一個由社群管理的輕量級代碼託管解決方案,使用 Go 語言編寫。它以 MIT 許可證發布。Gitea 提供 Git 託管,包括倉庫查看器、問題追蹤、拉取請求等功能。
@@ -57,9 +73,9 @@ Model Context Protocol (MCP) 是一種協議,允許通過聊天界面整合各
} }
``` ```
### 📥 下載官方二進版本 ### 📥 下載官方 Gitea MCP 二進版本
您可以從[這裡](https://gitea.com/gitea/gitea-mcp/releases)下載官方版本。 您可以從[官方 Gitea MCP 二進位版本](https://gitea.com/gitea/gitea-mcp/releases)下載官方版本。
### 🔧 從源代碼構建 ### 🔧 從源代碼構建
@@ -129,11 +145,23 @@ cp gitea-mcp /usr/local/bin/
} }
``` ```
**默認日誌路徑**: `$HOME/.gitea-mcp/gitea-mcp.log` - **http 模式**
```json
{
"mcpServers": {
"gitea": {
"url": "http://localhost:8080/mcp"
}
}
}
```
**預設日誌路徑**: `$HOME/.gitea-mcp/gitea-mcp.log`
> [!注意] > [!注意]
> 您可以通過命令參數或環境變提供您的 Gitea 主機和訪問令牌。 > 您可以通過命令參數或環境變提供您的 Gitea 主機和訪問令牌。
> 命令參數具有最高優先 > 命令參數具有最高優先
一切設置完成後,請嘗試在您的 MCP 兼容聊天框中輸入以下內容: 一切設置完成後,請嘗試在您的 MCP 兼容聊天框中輸入以下內容:
@@ -144,9 +172,11 @@ cp gitea-mcp /usr/local/bin/
## ✅ 可用工具 ## ✅ 可用工具
Gitea MCP 伺服器支持以下工具: Gitea MCP 伺服器支持以下工具:
| 工具 | 範圍 | 描述 | | 工具 | 範圍 | 描述 |
| :--------------------------: | :------: | :--------------------------: | | :--------------------------: | :------: | :--------------------------: |
| get_my_user_info | 用戶 | 獲取已認證用戶的信息 | | get_my_user_info | 用戶 | 獲取已認證用戶的信息 |
| get_user_orgs | 用戶 | 取得已認證用戶所屬組織 |
| create_repo | 倉庫 | 創建一個新倉庫 | | create_repo | 倉庫 | 創建一個新倉庫 |
| fork_repo | 倉庫 | 復刻一個倉庫 | | fork_repo | 倉庫 | 復刻一個倉庫 |
| list_my_repos | 倉庫 | 列出已認證用戶擁有的所有倉庫 | | list_my_repos | 倉庫 | 列出已認證用戶擁有的所有倉庫 |
@@ -182,7 +212,7 @@ Gitea MCP 伺服器支持以下工具:
## 🐛 調試 ## 🐛 調試
要啟用調試模式,請在使用 sse 模式運行 Gitea MCP 伺服器時添加 `-d` 要啟用調試模式,請在使用 sse 模式運行 Gitea MCP 伺服器時添加 `-d` 標:
```sh ```sh
./gitea-mcp -t sse [--port 8080] --token <your personal access token> -d ./gitea-mcp -t sse [--port 8080] --token <your personal access token> -d

View File

@@ -21,13 +21,13 @@ func init() {
&flagPkg.Mode, &flagPkg.Mode,
"t", "t",
"stdio", "stdio",
"Transport type (stdio or sse)", "Transport type (stdio, sse or http)",
) )
flag.StringVar( flag.StringVar(
&flagPkg.Mode, &flagPkg.Mode,
"transport", "transport",
"stdio", "stdio",
"Transport type (stdio or sse)", "Transport type (stdio, sse or http)",
) )
flag.StringVar( flag.StringVar(
&host, &host,
@@ -39,7 +39,7 @@ func init() {
&port, &port,
"port", "port",
8080, 8080,
"sse port", "see or http port",
) )
flag.StringVar( flag.StringVar(
&token, &token,

10
go.mod
View File

@@ -4,20 +4,20 @@ go 1.24.0
require ( require (
code.gitea.io/sdk/gitea v0.21.0 code.gitea.io/sdk/gitea v0.21.0
github.com/mark3labs/mcp-go v0.22.0 github.com/mark3labs/mcp-go v0.30.0
go.uber.org/zap v1.27.0 go.uber.org/zap v1.27.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
) )
require ( require (
github.com/42wim/httpsig v1.2.2 // indirect github.com/42wim/httpsig v1.2.3 // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect github.com/davidmz/go-pageant v1.0.2 // indirect
github.com/go-fed/httpsig v1.1.0 // indirect github.com/go-fed/httpsig v1.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect
github.com/spf13/cast v1.7.1 // indirect github.com/spf13/cast v1.8.0 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.37.0 // indirect golang.org/x/crypto v0.38.0 // indirect
golang.org/x/sys v0.32.0 // indirect golang.org/x/sys v0.33.0 // indirect
) )

24
go.sum
View File

@@ -1,7 +1,7 @@
code.gitea.io/sdk/gitea v0.21.0 h1:69n6oz6kEVHRo1+APQQyizkhrZrLsTLXey9142pfkD4= code.gitea.io/sdk/gitea v0.21.0 h1:69n6oz6kEVHRo1+APQQyizkhrZrLsTLXey9142pfkD4=
code.gitea.io/sdk/gitea v0.21.0/go.mod h1:tnBjVhuKJCn8ibdyyhvUyxrR1Ca2KHEoTWoukNhXQPA= code.gitea.io/sdk/gitea v0.21.0/go.mod h1:tnBjVhuKJCn8ibdyyhvUyxrR1Ca2KHEoTWoukNhXQPA=
github.com/42wim/httpsig v1.2.2 h1:ofAYoHUNs/MJOLqQ8hIxeyz2QxOz8qdSVvp3PX/oPgA= github.com/42wim/httpsig v1.2.3 h1:xb0YyWhkYj57SPtfSttIobJUPJZB9as1nsfo7KWVcEs=
github.com/42wim/httpsig v1.2.2/go.mod h1:P/UYo7ytNBFwc+dg35IubuAUIs8zj5zzFIgUCEl55WY= github.com/42wim/httpsig v1.2.3/go.mod h1:nZq9OlYKDrUBhptd77IHx4/sZZD+IxTBADvAPI9G/EM=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
@@ -20,14 +20,14 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mark3labs/mcp-go v0.22.0 h1:cCEBWi4Yy9Kio+OW1hWIyi4WLsSr+RBBK6FI5tj+b7I= github.com/mark3labs/mcp-go v0.30.0 h1:Taz7fiefkxY/l8jz1nA90V+WdM2eoMtlvwfWforVYbo=
github.com/mark3labs/mcp-go v0.22.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= github.com/mark3labs/mcp-go v0.30.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.8.0 h1:gEN9K4b8Xws4EX0+a0reLmhq8moKn7ntRlQYgjPeCDk=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cast v1.8.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
@@ -41,18 +41,18 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@@ -99,15 +99,15 @@ func init() {
func GetIssueByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func GetIssueByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called GetIssueByIndexFn") log.Debugf("Called GetIssueByIndexFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
index, ok := req.Params.Arguments["index"].(float64) index, ok := req.GetArguments()["index"].(float64)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("index is required")) return to.ErrorResult(fmt.Errorf("index is required"))
} }
@@ -121,23 +121,23 @@ func GetIssueByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
func ListRepoIssuesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func ListRepoIssuesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called ListIssuesFn") log.Debugf("Called ListIssuesFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
state, ok := req.Params.Arguments["state"].(string) state, ok := req.GetArguments()["state"].(string)
if !ok { if !ok {
state = "all" state = "all"
} }
page, ok := req.Params.Arguments["page"].(float64) page, ok := req.GetArguments()["page"].(float64)
if !ok { if !ok {
page = 1 page = 1
} }
pageSize, ok := req.Params.Arguments["pageSize"].(float64) pageSize, ok := req.GetArguments()["pageSize"].(float64)
if !ok { if !ok {
pageSize = 100 pageSize = 100
} }
@@ -157,19 +157,19 @@ func ListRepoIssuesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
func CreateIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func CreateIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called CreateIssueFn") log.Debugf("Called CreateIssueFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
title, ok := req.Params.Arguments["title"].(string) title, ok := req.GetArguments()["title"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("title is required")) return to.ErrorResult(fmt.Errorf("title is required"))
} }
body, ok := req.Params.Arguments["body"].(string) body, ok := req.GetArguments()["body"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("body is required")) return to.ErrorResult(fmt.Errorf("body is required"))
} }
@@ -186,19 +186,19 @@ func CreateIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
func CreateIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func CreateIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called CreateIssueCommentFn") log.Debugf("Called CreateIssueCommentFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
index, ok := req.Params.Arguments["index"].(float64) index, ok := req.GetArguments()["index"].(float64)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("index is required")) return to.ErrorResult(fmt.Errorf("index is required"))
} }
body, ok := req.Params.Arguments["body"].(string) body, ok := req.GetArguments()["body"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("body is required")) return to.ErrorResult(fmt.Errorf("body is required"))
} }
@@ -215,38 +215,38 @@ func CreateIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
func EditIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func EditIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called EditIssueFn") log.Debugf("Called EditIssueFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
index, ok := req.Params.Arguments["index"].(float64) index, ok := req.GetArguments()["index"].(float64)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("index is required")) return to.ErrorResult(fmt.Errorf("index is required"))
} }
opt := gitea_sdk.EditIssueOption{} opt := gitea_sdk.EditIssueOption{}
title, ok := req.Params.Arguments["title"].(string) title, ok := req.GetArguments()["title"].(string)
if ok { if ok {
opt.Title = title opt.Title = title
} }
body, ok := req.Params.Arguments["body"].(string) body, ok := req.GetArguments()["body"].(string)
if ok { if ok {
opt.Body = ptr.To(body) opt.Body = ptr.To(body)
} }
assignees, ok := req.Params.Arguments["assignees"].([]string) assignees, ok := req.GetArguments()["assignees"].([]string)
if ok { if ok {
opt.Assignees = assignees opt.Assignees = assignees
} }
milestone, ok := req.Params.Arguments["milestone"].(float64) milestone, ok := req.GetArguments()["milestone"].(float64)
if ok { if ok {
opt.Milestone = ptr.To(int64(milestone)) opt.Milestone = ptr.To(int64(milestone))
} }
state, ok := req.Params.Arguments["state"].(string) state, ok := req.GetArguments()["state"].(string)
if ok { if ok {
opt.State = ptr.To(gitea_sdk.StateType(state)) opt.State = ptr.To(gitea_sdk.StateType(state))
} }

View File

@@ -15,9 +15,7 @@ import (
"github.com/mark3labs/mcp-go/server" "github.com/mark3labs/mcp-go/server"
) )
var ( var mcpServer *server.MCPServer
mcpServer *server.MCPServer
)
func RegisterTool(s *server.MCPServer) { func RegisterTool(s *server.MCPServer) {
// User Tool // User Tool
@@ -55,8 +53,14 @@ func Run() error {
if err := sseServer.Start(fmt.Sprintf(":%d", flag.Port)); err != nil { if err := sseServer.Start(fmt.Sprintf(":%d", flag.Port)); err != nil {
return err return err
} }
case "http":
httpServer := server.NewStreamableHTTPServer(mcpServer)
log.Infof("Gitea MCP HTTP server listening on :%d", flag.Port)
if err := httpServer.Start(fmt.Sprintf(":%d", flag.Port)); err != nil {
return err
}
default: default:
return fmt.Errorf("invalid transport type: %s. Must be 'stdio' or 'sse'", flag.Mode) return fmt.Errorf("invalid transport type: %s. Must be 'stdio', 'sse' or 'http'", flag.Mode)
} }
return nil return nil
} }

View File

@@ -72,15 +72,15 @@ func init() {
func GetPullRequestByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func GetPullRequestByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called GetPullRequestByIndexFn") log.Debugf("Called GetPullRequestByIndexFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
index, ok := req.Params.Arguments["index"].(float64) index, ok := req.GetArguments()["index"].(float64)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("index is required")) return to.ErrorResult(fmt.Errorf("index is required"))
} }
@@ -94,25 +94,25 @@ func GetPullRequestByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp
func ListRepoPullRequestsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func ListRepoPullRequestsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called ListRepoPullRequests") log.Debugf("Called ListRepoPullRequests")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
state, _ := req.Params.Arguments["state"].(string) state, _ := req.GetArguments()["state"].(string)
sort, ok := req.Params.Arguments["sort"].(string) sort, ok := req.GetArguments()["sort"].(string)
if !ok { if !ok {
sort = "recentupdate" sort = "recentupdate"
} }
milestone, _ := req.Params.Arguments["milestone"].(float64) milestone, _ := req.GetArguments()["milestone"].(float64)
page, ok := req.Params.Arguments["page"].(float64) page, ok := req.GetArguments()["page"].(float64)
if !ok { if !ok {
page = 1 page = 1
} }
pageSize, ok := req.Params.Arguments["pageSize"].(float64) pageSize, ok := req.GetArguments()["pageSize"].(float64)
if !ok { if !ok {
pageSize = 100 pageSize = 100
} }
@@ -135,27 +135,27 @@ func ListRepoPullRequestsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.
func CreatePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func CreatePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called CreatePullRequestFn") log.Debugf("Called CreatePullRequestFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
title, ok := req.Params.Arguments["title"].(string) title, ok := req.GetArguments()["title"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("title is required")) return to.ErrorResult(fmt.Errorf("title is required"))
} }
body, ok := req.Params.Arguments["body"].(string) body, ok := req.GetArguments()["body"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("body is required")) return to.ErrorResult(fmt.Errorf("body is required"))
} }
head, ok := req.Params.Arguments["head"].(string) head, ok := req.GetArguments()["head"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("head is required")) return to.ErrorResult(fmt.Errorf("head is required"))
} }
base, ok := req.Params.Arguments["base"].(string) base, ok := req.GetArguments()["base"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("base is required")) return to.ErrorResult(fmt.Errorf("base is required"))
} }

View File

@@ -62,19 +62,19 @@ func init() {
func CreateBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func CreateBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called CreateBranchFn") log.Debugf("Called CreateBranchFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
branch, ok := req.Params.Arguments["branch"].(string) branch, ok := req.GetArguments()["branch"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("branch is required")) return to.ErrorResult(fmt.Errorf("branch is required"))
} }
oldBranch, _ := req.Params.Arguments["old_branch"].(string) oldBranch, _ := req.GetArguments()["old_branch"].(string)
_, _, err := gitea.Client().CreateBranch(owner, repo, gitea_sdk.CreateBranchOption{ _, _, err := gitea.Client().CreateBranch(owner, repo, gitea_sdk.CreateBranchOption{
BranchName: branch, BranchName: branch,
@@ -89,15 +89,15 @@ func CreateBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
func DeleteBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func DeleteBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called DeleteBranchFn") log.Debugf("Called DeleteBranchFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
branch, ok := req.Params.Arguments["branch"].(string) branch, ok := req.GetArguments()["branch"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("branch is required")) return to.ErrorResult(fmt.Errorf("branch is required"))
} }
@@ -111,11 +111,11 @@ func DeleteBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
func ListBranchesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func ListBranchesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called ListBranchesFn") log.Debugf("Called ListBranchesFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }

View File

@@ -17,8 +17,7 @@ const (
ListRepoCommitsToolName = "list_repo_commits" ListRepoCommitsToolName = "list_repo_commits"
) )
var ( var ListRepoCommitsTool = mcp.NewTool(
ListRepoCommitsTool = mcp.NewTool(
ListRepoCommitsToolName, ListRepoCommitsToolName,
mcp.WithDescription("List repository commits"), mcp.WithDescription("List repository commits"),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")), mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
@@ -27,7 +26,6 @@ var (
mcp.WithString("path", mcp.Description("path indicates that only commits that include the path's file/dir should be returned.")), mcp.WithString("path", mcp.Description("path indicates that only commits that include the path's file/dir should be returned.")),
mcp.WithNumber("page", mcp.Required(), mcp.Description("page number"), mcp.DefaultNumber(1), mcp.Min(1)), mcp.WithNumber("page", mcp.Required(), mcp.Description("page number"), mcp.DefaultNumber(1), mcp.Min(1)),
mcp.WithNumber("page_size", mcp.Required(), mcp.Description("page size"), mcp.DefaultNumber(50), mcp.Min(1)), mcp.WithNumber("page_size", mcp.Required(), mcp.Description("page size"), mcp.DefaultNumber(50), mcp.Min(1)),
)
) )
func init() { func init() {
@@ -39,24 +37,24 @@ func init() {
func ListRepoCommitsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func ListRepoCommitsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called ListRepoCommitsFn") log.Debugf("Called ListRepoCommitsFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
page, ok := req.Params.Arguments["page"].(float64) page, ok := req.GetArguments()["page"].(float64)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("page is required")) return to.ErrorResult(fmt.Errorf("page is required"))
} }
pageSize, ok := req.Params.Arguments["page_size"].(float64) pageSize, ok := req.GetArguments()["page_size"].(float64)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("page_size is required")) return to.ErrorResult(fmt.Errorf("page_size is required"))
} }
sha, _ := req.Params.Arguments["sha"].(string) sha, _ := req.GetArguments()["sha"].(string)
path, _ := req.Params.Arguments["path"].(string) path, _ := req.GetArguments()["path"].(string)
opt := gitea_sdk.ListCommitOptions{ opt := gitea_sdk.ListCommitOptions{
ListOptions: gitea_sdk.ListOptions{ ListOptions: gitea_sdk.ListOptions{
Page: int(page), Page: int(page),

View File

@@ -88,16 +88,16 @@ func init() {
func GetFileContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func GetFileContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called GetFileFn") log.Debugf("Called GetFileFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
ref, _ := req.Params.Arguments["ref"].(string) ref, _ := req.GetArguments()["ref"].(string)
filePath, ok := req.Params.Arguments["filePath"].(string) filePath, ok := req.GetArguments()["filePath"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("filePath is required")) return to.ErrorResult(fmt.Errorf("filePath is required"))
} }
@@ -110,21 +110,21 @@ func GetFileContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
func CreateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func CreateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called CreateFileFn") log.Debugf("Called CreateFileFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
filePath, ok := req.Params.Arguments["filePath"].(string) filePath, ok := req.GetArguments()["filePath"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("filePath is required")) return to.ErrorResult(fmt.Errorf("filePath is required"))
} }
content, _ := req.Params.Arguments["content"].(string) content, _ := req.GetArguments()["content"].(string)
message, _ := req.Params.Arguments["message"].(string) message, _ := req.GetArguments()["message"].(string)
branchName, _ := req.Params.Arguments["branch_name"].(string) branchName, _ := req.GetArguments()["branch_name"].(string)
opt := gitea_sdk.CreateFileOptions{ opt := gitea_sdk.CreateFileOptions{
Content: base64.StdEncoding.EncodeToString([]byte(content)), Content: base64.StdEncoding.EncodeToString([]byte(content)),
FileOptions: gitea_sdk.FileOptions{ FileOptions: gitea_sdk.FileOptions{
@@ -142,25 +142,25 @@ func CreateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
func UpdateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func UpdateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called UpdateFileFn") log.Debugf("Called UpdateFileFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
filePath, ok := req.Params.Arguments["filePath"].(string) filePath, ok := req.GetArguments()["filePath"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("filePath is required")) return to.ErrorResult(fmt.Errorf("filePath is required"))
} }
sha, ok := req.Params.Arguments["sha"].(string) sha, ok := req.GetArguments()["sha"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("sha is required")) return to.ErrorResult(fmt.Errorf("sha is required"))
} }
content, _ := req.Params.Arguments["content"].(string) content, _ := req.GetArguments()["content"].(string)
message, _ := req.Params.Arguments["message"].(string) message, _ := req.GetArguments()["message"].(string)
branchName, _ := req.Params.Arguments["branch_name"].(string) branchName, _ := req.GetArguments()["branch_name"].(string)
opt := gitea_sdk.UpdateFileOptions{ opt := gitea_sdk.UpdateFileOptions{
SHA: sha, SHA: sha,
@@ -179,21 +179,21 @@ func UpdateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
func DeleteFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func DeleteFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called DeleteFileFn") log.Debugf("Called DeleteFileFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("owner is required")) return to.ErrorResult(fmt.Errorf("owner is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("repo is required")) return to.ErrorResult(fmt.Errorf("repo is required"))
} }
filePath, ok := req.Params.Arguments["filePath"].(string) filePath, ok := req.GetArguments()["filePath"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("filePath is required")) return to.ErrorResult(fmt.Errorf("filePath is required"))
} }
message, _ := req.Params.Arguments["message"].(string) message, _ := req.GetArguments()["message"].(string)
branchName, _ := req.Params.Arguments["branch_name"].(string) branchName, _ := req.GetArguments()["branch_name"].(string)
sha, ok := req.Params.Arguments["sha"].(string) sha, ok := req.GetArguments()["sha"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("sha is required")) return to.ErrorResult(fmt.Errorf("sha is required"))
} }

View File

@@ -109,28 +109,28 @@ type ListReleaseResult struct {
func CreateReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func CreateReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called CreateReleasesFn") log.Debugf("Called CreateReleasesFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("owner is required") return nil, fmt.Errorf("owner is required")
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("repo is required") return nil, fmt.Errorf("repo is required")
} }
tagName, ok := req.Params.Arguments["tag_name"].(string) tagName, ok := req.GetArguments()["tag_name"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("tag_name is required") return nil, fmt.Errorf("tag_name is required")
} }
target, ok := req.Params.Arguments["target"].(string) target, ok := req.GetArguments()["target"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("target is required") return nil, fmt.Errorf("target is required")
} }
title, ok := req.Params.Arguments["title"].(string) title, ok := req.GetArguments()["title"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("title is required") return nil, fmt.Errorf("title is required")
} }
isDraft, _ := req.Params.Arguments["is_draft"].(bool) isDraft, _ := req.GetArguments()["is_draft"].(bool)
isPreRelease, _ := req.Params.Arguments["is_pre_release"].(bool) isPreRelease, _ := req.GetArguments()["is_pre_release"].(bool)
_, _, err := gitea.Client().CreateRelease(owner, repo, gitea_sdk.CreateReleaseOption{ _, _, err := gitea.Client().CreateRelease(owner, repo, gitea_sdk.CreateReleaseOption{
TagName: tagName, TagName: tagName,
@@ -148,15 +148,15 @@ func CreateReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
func DeleteReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func DeleteReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called DeleteReleaseFn") log.Debugf("Called DeleteReleaseFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("owner is required") return nil, fmt.Errorf("owner is required")
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("repo is required") return nil, fmt.Errorf("repo is required")
} }
id, ok := req.Params.Arguments["id"].(float64) id, ok := req.GetArguments()["id"].(float64)
if !ok { if !ok {
return nil, fmt.Errorf("id is required") return nil, fmt.Errorf("id is required")
} }
@@ -171,15 +171,15 @@ func DeleteReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
func GetReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func GetReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called GetReleaseFn") log.Debugf("Called GetReleaseFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("owner is required") return nil, fmt.Errorf("owner is required")
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("repo is required") return nil, fmt.Errorf("repo is required")
} }
id, ok := req.Params.Arguments["id"].(float64) id, ok := req.GetArguments()["id"].(float64)
if !ok { if !ok {
return nil, fmt.Errorf("id is required") return nil, fmt.Errorf("id is required")
} }
@@ -194,11 +194,11 @@ func GetReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
func GetLatestReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func GetLatestReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called GetLatestReleaseFn") log.Debugf("Called GetLatestReleaseFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("owner is required") return nil, fmt.Errorf("owner is required")
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("repo is required") return nil, fmt.Errorf("repo is required")
} }
@@ -213,26 +213,34 @@ func GetLatestReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
func ListReleasesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func ListReleasesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called ListReleasesFn") log.Debugf("Called ListReleasesFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("owner is required") return nil, fmt.Errorf("owner is required")
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("repo is required") return nil, fmt.Errorf("repo is required")
} }
isDraft, _ := req.Params.Arguments["is_draft"].(bool) var pIsDraft *bool
isPreRelease, _ := req.Params.Arguments["is_pre_release"].(bool) isDraft, ok := req.GetArguments()["is_draft"].(bool)
page, _ := req.Params.Arguments["page"].(float64) if ok {
pageSize, _ := req.Params.Arguments["pageSize"].(float64) pIsDraft = ptr.To(isDraft)
}
var pIsPreRelease *bool
isPreRelease, ok := req.GetArguments()["is_pre_release"].(bool)
if ok {
pIsPreRelease = ptr.To(isPreRelease)
}
page, _ := req.GetArguments()["page"].(float64)
pageSize, _ := req.GetArguments()["pageSize"].(float64)
releases, _, err := gitea.Client().ListReleases(owner, repo, gitea_sdk.ListReleasesOptions{ releases, _, err := gitea.Client().ListReleases(owner, repo, gitea_sdk.ListReleasesOptions{
ListOptions: gitea_sdk.ListOptions{ ListOptions: gitea_sdk.ListOptions{
Page: int(page), Page: int(page),
PageSize: int(pageSize), PageSize: int(pageSize),
}, },
IsDraft: ptr.To(isDraft), IsDraft: pIsDraft,
IsPreRelease: ptr.To(isPreRelease), IsPreRelease: pIsPreRelease,
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("list releases error: %v", err) return nil, fmt.Errorf("list releases error: %v", err)

View File

@@ -107,19 +107,19 @@ func RegisterTool(s *server.MCPServer) {
func CreateRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func CreateRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called CreateRepoFn") log.Debugf("Called CreateRepoFn")
name, ok := req.Params.Arguments["name"].(string) name, ok := req.GetArguments()["name"].(string)
if !ok { if !ok {
return to.ErrorResult(errors.New("repository name is required")) return to.ErrorResult(errors.New("repository name is required"))
} }
description, _ := req.Params.Arguments["description"].(string) description, _ := req.GetArguments()["description"].(string)
private, _ := req.Params.Arguments["private"].(bool) private, _ := req.GetArguments()["private"].(bool)
issueLabels, _ := req.Params.Arguments["issue_labels"].(string) issueLabels, _ := req.GetArguments()["issue_labels"].(string)
autoInit, _ := req.Params.Arguments["auto_init"].(bool) autoInit, _ := req.GetArguments()["auto_init"].(bool)
template, _ := req.Params.Arguments["template"].(bool) template, _ := req.GetArguments()["template"].(bool)
gitignores, _ := req.Params.Arguments["gitignores"].(string) gitignores, _ := req.GetArguments()["gitignores"].(string)
license, _ := req.Params.Arguments["license"].(string) license, _ := req.GetArguments()["license"].(string)
readme, _ := req.Params.Arguments["readme"].(string) readme, _ := req.GetArguments()["readme"].(string)
defaultBranch, _ := req.Params.Arguments["default_branch"].(string) defaultBranch, _ := req.GetArguments()["default_branch"].(string)
opt := gitea_sdk.CreateRepoOption{ opt := gitea_sdk.CreateRepoOption{
Name: name, Name: name,
@@ -142,20 +142,20 @@ func CreateRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
func ForkRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func ForkRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called ForkRepoFn") log.Debugf("Called ForkRepoFn")
user, ok := req.Params.Arguments["user"].(string) user, ok := req.GetArguments()["user"].(string)
if !ok { if !ok {
return to.ErrorResult(errors.New("user name is required")) return to.ErrorResult(errors.New("user name is required"))
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return to.ErrorResult(errors.New("repository name is required")) return to.ErrorResult(errors.New("repository name is required"))
} }
organization, ok := req.Params.Arguments["organization"].(string) organization, ok := req.GetArguments()["organization"].(string)
organizationPtr := ptr.To(organization) organizationPtr := ptr.To(organization)
if !ok || organization == "" { if !ok || organization == "" {
organizationPtr = nil organizationPtr = nil
} }
name, ok := req.Params.Arguments["name"].(string) name, ok := req.GetArguments()["name"].(string)
namePtr := ptr.To(name) namePtr := ptr.To(name)
if !ok || name == "" { if !ok || name == "" {
namePtr = nil namePtr = nil
@@ -173,11 +173,11 @@ func ForkRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResu
func ListMyReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func ListMyReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called ListMyReposFn") log.Debugf("Called ListMyReposFn")
page, ok := req.Params.Arguments["page"].(float64) page, ok := req.GetArguments()["page"].(float64)
if !ok { if !ok {
page = 1 page = 1
} }
pageSize, ok := req.Params.Arguments["pageSize"].(float64) pageSize, ok := req.GetArguments()["pageSize"].(float64)
if !ok { if !ok {
pageSize = 100 pageSize = 100
} }

View File

@@ -87,20 +87,20 @@ type ListTagResult struct {
func CreateTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func CreateTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called CreateTagFn") log.Debugf("Called CreateTagFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("owner is required") return nil, fmt.Errorf("owner is required")
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("repo is required") return nil, fmt.Errorf("repo is required")
} }
tagName, ok := req.Params.Arguments["tag_name"].(string) tagName, ok := req.GetArguments()["tag_name"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("tag_name is required") return nil, fmt.Errorf("tag_name is required")
} }
target, _ := req.Params.Arguments["target"].(string) target, _ := req.GetArguments()["target"].(string)
message, _ := req.Params.Arguments["message"].(string) message, _ := req.GetArguments()["message"].(string)
_, _, err := gitea.Client().CreateTag(owner, repo, gitea_sdk.CreateTagOption{ _, _, err := gitea.Client().CreateTag(owner, repo, gitea_sdk.CreateTagOption{
TagName: tagName, TagName: tagName,
@@ -116,15 +116,15 @@ func CreateTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes
func DeleteTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func DeleteTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called DeleteTagFn") log.Debugf("Called DeleteTagFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("owner is required") return nil, fmt.Errorf("owner is required")
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("repo is required") return nil, fmt.Errorf("repo is required")
} }
tagName, ok := req.Params.Arguments["tag_name"].(string) tagName, ok := req.GetArguments()["tag_name"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("tag_name is required") return nil, fmt.Errorf("tag_name is required")
} }
@@ -139,15 +139,15 @@ func DeleteTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes
func GetTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func GetTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called GetTagFn") log.Debugf("Called GetTagFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("owner is required") return nil, fmt.Errorf("owner is required")
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("repo is required") return nil, fmt.Errorf("repo is required")
} }
tagName, ok := req.Params.Arguments["tag_name"].(string) tagName, ok := req.GetArguments()["tag_name"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("tag_name is required") return nil, fmt.Errorf("tag_name is required")
} }
@@ -162,16 +162,16 @@ func GetTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult
func ListTagsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func ListTagsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called ListTagsFn") log.Debugf("Called ListTagsFn")
owner, ok := req.Params.Arguments["owner"].(string) owner, ok := req.GetArguments()["owner"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("owner is required") return nil, fmt.Errorf("owner is required")
} }
repo, ok := req.Params.Arguments["repo"].(string) repo, ok := req.GetArguments()["repo"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("repo is required") return nil, fmt.Errorf("repo is required")
} }
page, _ := req.Params.Arguments["page"].(float64) page, _ := req.GetArguments()["page"].(float64)
pageSize, _ := req.Params.Arguments["pageSize"].(float64) pageSize, _ := req.GetArguments()["pageSize"].(float64)
tags, _, err := gitea.Client().ListRepoTags(owner, repo, gitea_sdk.ListRepoTagsOptions{ tags, _, err := gitea.Client().ListRepoTags(owner, repo, gitea_sdk.ListRepoTagsOptions{
ListOptions: gitea_sdk.ListOptions{ ListOptions: gitea_sdk.ListOptions{

View File

@@ -75,15 +75,15 @@ func init() {
func SearchUsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func SearchUsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called SearchUsersFn") log.Debugf("Called SearchUsersFn")
keyword, ok := req.Params.Arguments["keyword"].(string) keyword, ok := req.GetArguments()["keyword"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("keyword is required")) return to.ErrorResult(fmt.Errorf("keyword is required"))
} }
page, ok := req.Params.Arguments["page"].(float64) page, ok := req.GetArguments()["page"].(float64)
if !ok { if !ok {
page = 1 page = 1
} }
pageSize, ok := req.Params.Arguments["pageSize"].(float64) pageSize, ok := req.GetArguments()["pageSize"].(float64)
if !ok { if !ok {
pageSize = 100 pageSize = 100
} }
@@ -103,20 +103,20 @@ func SearchUsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
func SearchOrgTeamsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func SearchOrgTeamsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called SearchOrgTeamsFn") log.Debugf("Called SearchOrgTeamsFn")
org, ok := req.Params.Arguments["org"].(string) org, ok := req.GetArguments()["org"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("organization is required")) return to.ErrorResult(fmt.Errorf("organization is required"))
} }
query, ok := req.Params.Arguments["query"].(string) query, ok := req.GetArguments()["query"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("query is required")) return to.ErrorResult(fmt.Errorf("query is required"))
} }
includeDescription, _ := req.Params.Arguments["includeDescription"].(bool) includeDescription, _ := req.GetArguments()["includeDescription"].(bool)
page, ok := req.Params.Arguments["page"].(float64) page, ok := req.GetArguments()["page"].(float64)
if !ok { if !ok {
page = 1 page = 1
} }
pageSize, ok := req.Params.Arguments["pageSize"].(float64) pageSize, ok := req.GetArguments()["pageSize"].(float64)
if !ok { if !ok {
pageSize = 100 pageSize = 100
} }
@@ -137,22 +137,30 @@ func SearchOrgTeamsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
func SearchReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func SearchReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called SearchReposFn") log.Debugf("Called SearchReposFn")
keyword, ok := req.Params.Arguments["keyword"].(string) keyword, ok := req.GetArguments()["keyword"].(string)
if !ok { if !ok {
return to.ErrorResult(fmt.Errorf("keyword is required")) return to.ErrorResult(fmt.Errorf("keyword is required"))
} }
keywordIsTopic, _ := req.Params.Arguments["keywordIsTopic"].(bool) keywordIsTopic, _ := req.GetArguments()["keywordIsTopic"].(bool)
keywordInDescription, _ := req.Params.Arguments["keywordInDescription"].(bool) keywordInDescription, _ := req.GetArguments()["keywordInDescription"].(bool)
ownerID, _ := req.Params.Arguments["ownerID"].(float64) ownerID, _ := req.GetArguments()["ownerID"].(float64)
isPrivate, _ := req.Params.Arguments["isPrivate"].(bool) var pIsPrivate *bool
isArchived, _ := req.Params.Arguments["isArchived"].(bool) isPrivate, ok := req.GetArguments()["isPrivate"].(bool)
sort, _ := req.Params.Arguments["sort"].(string) if ok {
order, _ := req.Params.Arguments["order"].(string) pIsPrivate = ptr.To(isPrivate)
page, ok := req.Params.Arguments["page"].(float64) }
var pIsArchived *bool
isArchived, ok := req.GetArguments()["isArchived"].(bool)
if ok {
pIsArchived = ptr.To(isArchived)
}
sort, _ := req.GetArguments()["sort"].(string)
order, _ := req.GetArguments()["order"].(string)
page, ok := req.GetArguments()["page"].(float64)
if !ok { if !ok {
page = 1 page = 1
} }
pageSize, ok := req.Params.Arguments["pageSize"].(float64) pageSize, ok := req.GetArguments()["pageSize"].(float64)
if !ok { if !ok {
pageSize = 100 pageSize = 100
} }
@@ -161,8 +169,8 @@ func SearchReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
KeywordIsTopic: keywordIsTopic, KeywordIsTopic: keywordIsTopic,
KeywordInDescription: keywordInDescription, KeywordInDescription: keywordInDescription,
OwnerID: int64(ownerID), OwnerID: int64(ownerID),
IsPrivate: ptr.To(isPrivate), IsPrivate: pIsPrivate,
IsArchived: ptr.To(isArchived), IsArchived: pIsArchived,
Sort: sort, Sort: sort,
Order: order, Order: order,
ListOptions: gitea_sdk.ListOptions{ ListOptions: gitea_sdk.ListOptions{

View File

@@ -59,11 +59,11 @@ func GetUserInfoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
func GetUserOrgsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { func GetUserOrgsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called GetUserOrgsFn") log.Debugf("Called GetUserOrgsFn")
page, ok := req.Params.Arguments["page"].(float64) page, ok := req.GetArguments()["page"].(float64)
if !ok || page < 1 { if !ok || page < 1 {
page = 1 page = 1
} }
pageSize, ok := req.Params.Arguments["pageSize"].(float64) pageSize, ok := req.GetArguments()["pageSize"].(float64)
if !ok || pageSize < 1 { if !ok || pageSize < 1 {
pageSize = 100 pageSize = 100
} }

View File

@@ -39,7 +39,7 @@ func Default() *zap.Logger {
MaxAge: 30, MaxAge: 30,
})) }))
if flag.Mode == "sse" { if flag.Mode == "http" || flag.Mode == "sse" {
wss = append(wss, zapcore.AddSync(os.Stdout)) wss = append(wss, zapcore.AddSync(os.Stdout))
} }