Compare commits
13 Commits
v1.3.0
...
ci-binford
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a79cb7d9e | |||
| d2e0d1e3b7 | |||
| 6dbc2c3cce | |||
| 7d90afd456 | |||
| c7128a3996 | |||
| 8b4ac7f8aa | |||
| cd7c29271a | |||
| bbde7ee110 | |||
| 3af6250589 | |||
| a35fd26112 | |||
| 4d7a33e57e | |||
| 371a06403a | |||
| e36137f5a1 |
@@ -0,0 +1,48 @@
|
|||||||
|
name: Build and Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
target_branch:
|
||||||
|
description: 'Branch to build'
|
||||||
|
required: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
verify:
|
||||||
|
runs-on: container-builder
|
||||||
|
container:
|
||||||
|
image: debian:trixie-slim
|
||||||
|
env:
|
||||||
|
GOPROXY: https://gitea.nehmer.net/api/packages/torben/go,https://proxy.golang.org,direct
|
||||||
|
steps:
|
||||||
|
- name: Install CI Dependencies
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y --no-install-recommends git nodejs curl unzip ca-certificates build-essential
|
||||||
|
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.target_branch }}
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: 'go.mod'
|
||||||
|
- name: Show Go Version
|
||||||
|
run: go version
|
||||||
|
|
||||||
|
- name: lint
|
||||||
|
run: make lint
|
||||||
|
- name: build
|
||||||
|
run: make build
|
||||||
|
- name: security-check
|
||||||
|
run: make security-check
|
||||||
|
|
||||||
|
- name: Paket als Artefakt hochladen
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: gitea-mcp-amd64
|
||||||
|
path: gitea-mcp
|
||||||
|
retention-days: 7
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
name: Build and Push Container Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
target_branch:
|
||||||
|
description: 'Branch to build'
|
||||||
|
required: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: gitea.nehmer.net/torben
|
||||||
|
IMAGE_NAME: gitea-mcp
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push-image:
|
||||||
|
runs-on: container-builder
|
||||||
|
container:
|
||||||
|
image: debian:trixie-slim
|
||||||
|
env:
|
||||||
|
GOPROXY: https://gitea.nehmer.net/api/packages/torben/go,https://proxy.golang.org,direct
|
||||||
|
steps:
|
||||||
|
- name: Install CI Dependencies
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y --no-install-recommends git nodejs curl docker-cli docker-buildx unzip ca-certificates iproute2 gawk
|
||||||
|
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.target_branch }}
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
|
||||||
|
- name: Load Secrets from 1Password
|
||||||
|
uses: 1password/load-secrets-action@v2
|
||||||
|
with:
|
||||||
|
export-env: true
|
||||||
|
env:
|
||||||
|
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
|
||||||
|
REGISTRY_USER: op://CI-CD/gitea-package-token/username
|
||||||
|
REGISTRY_PAT: op://CI-CD/gitea-package-token/password
|
||||||
|
|
||||||
|
- name: BuildKit Setup (Remote Builder konfigurieren)
|
||||||
|
run: |
|
||||||
|
HOST_IP=$(ip route | awk '/default/ { print $3 }')
|
||||||
|
docker buildx create --name remote-builder --driver remote tcp://$HOST_IP:1234 --use --bootstrap
|
||||||
|
|
||||||
|
- name: Log in to the Container registry
|
||||||
|
run: |
|
||||||
|
echo "$REGISTRY_PAT" | docker login $REGISTRY -u "$REGISTRY_USER" --password-stdin
|
||||||
|
|
||||||
|
|
||||||
|
- name: Get Meta
|
||||||
|
id: meta
|
||||||
|
run: |
|
||||||
|
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT
|
||||||
|
echo REPO_VERSION=$(git describe --tags --always | sed 's/-/+/' | sed 's/^v//') >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: |
|
||||||
|
linux/amd64
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-server:${{ inputs.target_branch }}
|
||||||
|
build-args: |
|
||||||
|
VERSION=${{ steps.meta.outputs.REPO_VERSION }}
|
||||||
|
|
||||||
|
# - name: Build and Push
|
||||||
|
# run: |
|
||||||
|
# TAG="${{ gitea.ref_name }}"
|
||||||
|
|
||||||
|
# # Note: This repository only builds and pushes images.
|
||||||
|
# # FluxCD Image Automation in another repository performs deployment.
|
||||||
|
# # Stable tags (vX.Y.Z) also publish :latest.
|
||||||
|
# # Pre-release tags (e.g. vX.Y.Z-rc1) also publish :prerelease-tag.
|
||||||
|
# if printf '%s' "$TAG" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
|
||||||
|
# docker buildx build \
|
||||||
|
# --platform linux/amd64 \
|
||||||
|
# --push \
|
||||||
|
# --tag "$REGISTRY/$IMAGE_NAME:$TAG" \
|
||||||
|
# --tag "$REGISTRY/$IMAGE_NAME:latest" \
|
||||||
|
# .
|
||||||
|
# else
|
||||||
|
# docker buildx build \
|
||||||
|
# --platform linux/amd64 \
|
||||||
|
# --push \
|
||||||
|
# --tag "$REGISTRY/$IMAGE_NAME:$TAG" \
|
||||||
|
# --tag "$REGISTRY/$IMAGE_NAME:prerelease-tag" \
|
||||||
|
# .
|
||||||
|
# fi
|
||||||
@@ -22,11 +22,14 @@ RUN --mount=type=cache,target=/go/pkg/mod \
|
|||||||
# Final stage
|
# Final stage
|
||||||
FROM gcr.io/distroless/static-debian12:nonroot
|
FROM gcr.io/distroless/static-debian12:nonroot
|
||||||
|
|
||||||
|
ARG VERSION=dev
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=builder --chown=nonroot:nonroot /app/gitea-mcp .
|
COPY --from=builder --chown=nonroot:nonroot /app/gitea-mcp .
|
||||||
|
|
||||||
USER nonroot:nonroot
|
USER nonroot:nonroot
|
||||||
|
|
||||||
LABEL org.opencontainers.image.version="${VERSION}"
|
LABEL org.opencontainers.image.version="${VERSION}"
|
||||||
|
LABEL org.opencontainers.image.source="https://gitea.com/gitea/gitea-mcp"
|
||||||
|
|
||||||
CMD ["/app/gitea-mcp"]
|
CMD ["/app/gitea-mcp"]
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
- [🚧 Installation](#-installation)
|
- [🚧 Installation](#-installation)
|
||||||
- [Usage with Claude Code](#usage-with-claude-code)
|
- [Usage with Claude Code](#usage-with-claude-code)
|
||||||
- [Usage with VS Code](#usage-with-vs-code)
|
- [Usage with VS Code](#usage-with-vs-code)
|
||||||
|
- [Usage with Mistral Vibe](#usage-with-mistral-vibe)
|
||||||
- [📥 Download the official binary release](#-download-the-official-binary-release)
|
- [📥 Download the official binary release](#-download-the-official-binary-release)
|
||||||
- [🔧 Build from Source](#-build-from-source)
|
- [🔧 Build from Source](#-build-from-source)
|
||||||
- [📁 Add to PATH](#-add-to-path)
|
- [📁 Add to PATH](#-add-to-path)
|
||||||
@@ -33,6 +34,23 @@ Model Context Protocol (MCP) is a protocol that allows for the integration of va
|
|||||||
|
|
||||||
## 🚧 Installation
|
## 🚧 Installation
|
||||||
|
|
||||||
|
### Usage with OpenCode (opencode.ai)
|
||||||
|
|
||||||
|
Add a snippet like the following in the "mcp" top-level object (add one if you don't have any):
|
||||||
|
|
||||||
|
```json
|
||||||
|
"gitea-mcp": {
|
||||||
|
"enabled": true,
|
||||||
|
"type": "local",
|
||||||
|
"command": [
|
||||||
|
"gitea-mcp",
|
||||||
|
"-t", "stdio",
|
||||||
|
"-H", "https://git.your-domain.org",
|
||||||
|
"-T", "<your personal access token>"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Usage with Claude Code
|
### Usage with Claude Code
|
||||||
|
|
||||||
This method uses `go run` and requires [Go](https://go.dev) to be installed.
|
This method uses `go run` and requires [Go](https://go.dev) to be installed.
|
||||||
@@ -85,6 +103,31 @@ Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Usage with Mistral Vibe
|
||||||
|
|
||||||
|
Add the following configuration to your Mistral Vibe MCP configuration file (`~/.vibe/config.toml`):
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[mcp_servers]]
|
||||||
|
name = "gitea"
|
||||||
|
transport = "stdio"
|
||||||
|
command = "docker"
|
||||||
|
args = [
|
||||||
|
"run",
|
||||||
|
"--rm",
|
||||||
|
"-i",
|
||||||
|
"-e",
|
||||||
|
"GITEA_ACCESS_TOKEN",
|
||||||
|
"-e",
|
||||||
|
"GITEA_HOST",
|
||||||
|
"docker.gitea.com/gitea-mcp-server",
|
||||||
|
]
|
||||||
|
|
||||||
|
[mcp_servers.env]
|
||||||
|
GITEA_ACCESS_TOKEN = "TOKEN"
|
||||||
|
GITEA_HOST = "https://gitea.com"
|
||||||
|
```
|
||||||
|
|
||||||
### 📥 Download the official binary release
|
### 📥 Download the official binary release
|
||||||
|
|
||||||
You can download the official release from [official Gitea MCP binary releases](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).
|
||||||
|
|||||||
@@ -3,27 +3,27 @@ module gitea.com/gitea/gitea-mcp
|
|||||||
go 1.26.0
|
go 1.26.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.gitea.io/sdk/gitea v0.23.2
|
gitea.dev/sdk v1.0.1
|
||||||
github.com/mark3labs/mcp-go v0.45.0
|
github.com/mark3labs/mcp-go v0.45.0
|
||||||
go.uber.org/zap v1.27.1
|
go.uber.org/zap v1.27.1
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/42wim/httpsig v1.2.3 // indirect
|
github.com/42wim/httpsig v1.2.4 // indirect
|
||||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||||
github.com/buger/jsonparser v1.1.1 // indirect
|
github.com/buger/jsonparser v1.1.1 // 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.8.0 // indirect
|
github.com/hashicorp/go-version v1.9.0 // indirect
|
||||||
github.com/invopop/jsonschema v0.13.0 // indirect
|
github.com/invopop/jsonschema v0.13.0 // indirect
|
||||||
github.com/mailru/easyjson v0.9.1 // indirect
|
github.com/mailru/easyjson v0.9.1 // indirect
|
||||||
github.com/spf13/cast v1.10.0 // indirect
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
github.com/wk8/go-ordered-map/v2 v2.1.8 // 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.48.0 // indirect
|
golang.org/x/crypto v0.51.0 // indirect
|
||||||
golang.org/x/sys v0.41.0 // indirect
|
golang.org/x/sys v0.44.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
code.gitea.io/sdk/gitea v0.23.2 h1:iJB1FDmLegwfwjX8gotBDHdPSbk/ZR8V9VmEJaVsJYg=
|
gitea.dev/sdk v1.0.1 h1:CWXQUQvp2I6YKOWkhYo1Flx2sRNfMK1X9Op4oR2awXs=
|
||||||
code.gitea.io/sdk/gitea v0.23.2/go.mod h1:yyF5+GhljqvA30sRDreoyHILruNiy4ASufugzYg0VHM=
|
gitea.dev/sdk v1.0.1/go.mod h1:jCf5Uzz0Jkb61jxNgMxLOCWwle1J1B2nKdcRtxuK9rY=
|
||||||
github.com/42wim/httpsig v1.2.3 h1:xb0YyWhkYj57SPtfSttIobJUPJZB9as1nsfo7KWVcEs=
|
github.com/42wim/httpsig v1.2.4 h1:mI5bH0nm4xn7K18fo1K3okNDRq8CCJ0KbBYWyA6r8lU=
|
||||||
github.com/42wim/httpsig v1.2.3/go.mod h1:nZq9OlYKDrUBhptd77IHx4/sZZD+IxTBADvAPI9G/EM=
|
github.com/42wim/httpsig v1.2.4/go.mod h1:yKsYfSyTBEohkPik224QPFylmzEBtda/kjyIAJjh3ps=
|
||||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||||
@@ -18,8 +18,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
|||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4=
|
github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA=
|
||||||
github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
|
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
|
||||||
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
@@ -36,8 +36,8 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV
|
|||||||
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.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||||
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||||
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||||
@@ -51,18 +51,18 @@ go.uber.org/zap v1.27.1/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.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
|
||||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
|
||||||
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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
|
||||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
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.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
|
||||||
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
|
||||||
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=
|
||||||
|
|||||||
+99
-123
@@ -2,7 +2,6 @@ package actions
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -10,11 +9,10 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -133,17 +131,14 @@ func configWriteFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Secret functions
|
|
||||||
|
|
||||||
func listRepoActionSecretsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listRepoActionSecretsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listRepoActionSecretsFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
||||||
|
|
||||||
@@ -152,7 +147,7 @@ func listRepoActionSecretsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp
|
|||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
secrets, _, err := client.ListRepoActionSecret(owner, repo, gitea_sdk.ListRepoActionSecretOption{
|
secrets, _, err := client.Actions.ListRepoSecrets(ctx, owner, repo, gitea_sdk.ListRepoActionsSecretOption{
|
||||||
ListOptions: gitea_sdk.ListOptions{Page: page, PageSize: pageSize},
|
ListOptions: gitea_sdk.ListOptions{Page: page, PageSize: pageSize},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -163,22 +158,21 @@ func listRepoActionSecretsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp
|
|||||||
}
|
}
|
||||||
|
|
||||||
func upsertRepoActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func upsertRepoActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called upsertRepoActionSecretFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
name, err := params.GetString(req.GetArguments(), "name")
|
name, err := params.GetString(req.GetArguments(), "name")
|
||||||
if err != nil || name == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("name is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
data, err := params.GetString(req.GetArguments(), "data")
|
data, err := params.GetString(req.GetArguments(), "data")
|
||||||
if err != nil || data == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("data is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
description, _ := req.GetArguments()["description"].(string)
|
description, _ := req.GetArguments()["description"].(string)
|
||||||
|
|
||||||
@@ -186,8 +180,7 @@ func upsertRepoActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mc
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
resp, err := client.CreateRepoActionSecret(owner, repo, gitea_sdk.CreateSecretOption{
|
resp, err := client.Actions.CreateRepoSecret(ctx, owner, repo, name, gitea_sdk.CreateOrUpdateSecretOption{
|
||||||
Name: name,
|
|
||||||
Data: data,
|
Data: data,
|
||||||
Description: description,
|
Description: description,
|
||||||
})
|
})
|
||||||
@@ -198,25 +191,24 @@ func upsertRepoActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mc
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteRepoActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deleteRepoActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deleteRepoActionSecretFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
name, err := params.GetString(req.GetArguments(), "name")
|
name, err := params.GetString(req.GetArguments(), "name")
|
||||||
if err != nil || name == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("name is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
resp, err := client.DeleteRepoActionSecret(owner, repo, name)
|
resp, err := client.Actions.DeleteRepoSecret(ctx, owner, repo, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("delete repo action secret err: %v", err))
|
return to.ErrorResult(fmt.Errorf("delete repo action secret err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -224,10 +216,9 @@ func deleteRepoActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mc
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listOrgActionSecretsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listOrgActionSecretsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listOrgActionSecretsFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil || org == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("org is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
||||||
|
|
||||||
@@ -236,7 +227,7 @@ func listOrgActionSecretsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.
|
|||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
secrets, _, err := client.ListOrgActionSecret(org, gitea_sdk.ListOrgActionSecretOption{
|
secrets, _, err := client.Actions.ListOrgSecrets(ctx, org, gitea_sdk.ListOrgActionsSecretOption{
|
||||||
ListOptions: gitea_sdk.ListOptions{Page: page, PageSize: pageSize},
|
ListOptions: gitea_sdk.ListOptions{Page: page, PageSize: pageSize},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -247,18 +238,17 @@ func listOrgActionSecretsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func upsertOrgActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func upsertOrgActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called upsertOrgActionSecretFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil || org == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("org is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
name, err := params.GetString(req.GetArguments(), "name")
|
name, err := params.GetString(req.GetArguments(), "name")
|
||||||
if err != nil || name == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("name is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
data, err := params.GetString(req.GetArguments(), "data")
|
data, err := params.GetString(req.GetArguments(), "data")
|
||||||
if err != nil || data == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("data is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
description, _ := req.GetArguments()["description"].(string)
|
description, _ := req.GetArguments()["description"].(string)
|
||||||
|
|
||||||
@@ -266,8 +256,7 @@ func upsertOrgActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
resp, err := client.CreateOrgActionSecret(org, gitea_sdk.CreateSecretOption{
|
resp, err := client.Actions.CreateOrgSecret(ctx, org, name, gitea_sdk.CreateOrUpdateSecretOption{
|
||||||
Name: name,
|
|
||||||
Data: data,
|
Data: data,
|
||||||
Description: description,
|
Description: description,
|
||||||
})
|
})
|
||||||
@@ -278,14 +267,13 @@ func upsertOrgActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteOrgActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deleteOrgActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deleteOrgActionSecretFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil || org == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("org is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
name, err := params.GetString(req.GetArguments(), "name")
|
name, err := params.GetString(req.GetArguments(), "name")
|
||||||
if err != nil || name == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("name is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
escapedOrg := url.PathEscape(org)
|
escapedOrg := url.PathEscape(org)
|
||||||
@@ -297,17 +285,14 @@ func deleteOrgActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp
|
|||||||
return to.TextResult(map[string]any{"message": "secret deleted"})
|
return to.TextResult(map[string]any{"message": "secret deleted"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variable functions
|
|
||||||
|
|
||||||
func listRepoActionVariablesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listRepoActionVariablesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listRepoActionVariablesFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
||||||
|
|
||||||
@@ -324,25 +309,24 @@ func listRepoActionVariablesFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getRepoActionVariableFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
name, err := params.GetString(req.GetArguments(), "name")
|
name, err := params.GetString(req.GetArguments(), "name")
|
||||||
if err != nil || name == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("name is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
variable, _, err := client.GetRepoActionVariable(owner, repo, name)
|
variable, _, err := client.Actions.GetRepoVariable(ctx, owner, repo, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get repo action variable err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get repo action variable err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -350,29 +334,28 @@ func getRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func createRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called createRepoActionVariableFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
name, err := params.GetString(req.GetArguments(), "name")
|
name, err := params.GetString(req.GetArguments(), "name")
|
||||||
if err != nil || name == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("name is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
value, err := params.GetString(req.GetArguments(), "value")
|
value, err := params.GetString(req.GetArguments(), "value")
|
||||||
if err != nil || value == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("value is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
resp, err := client.CreateRepoActionVariable(owner, repo, name, value)
|
resp, err := client.Actions.CreateRepoVariable(ctx, owner, repo, name, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("create repo action variable err: %v", err))
|
return to.ErrorResult(fmt.Errorf("create repo action variable err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -380,29 +363,28 @@ func createRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func updateRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called updateRepoActionVariableFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
name, err := params.GetString(req.GetArguments(), "name")
|
name, err := params.GetString(req.GetArguments(), "name")
|
||||||
if err != nil || name == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("name is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
value, err := params.GetString(req.GetArguments(), "value")
|
value, err := params.GetString(req.GetArguments(), "value")
|
||||||
if err != nil || value == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("value is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
resp, err := client.UpdateRepoActionVariable(owner, repo, name, value)
|
resp, err := client.Actions.UpdateRepoVariable(ctx, owner, repo, name, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("update repo action variable err: %v", err))
|
return to.ErrorResult(fmt.Errorf("update repo action variable err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -410,25 +392,24 @@ func updateRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deleteRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deleteRepoActionVariableFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
name, err := params.GetString(req.GetArguments(), "name")
|
name, err := params.GetString(req.GetArguments(), "name")
|
||||||
if err != nil || name == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("name is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
resp, err := client.DeleteRepoActionVariable(owner, repo, name)
|
resp, err := client.Actions.DeleteRepoVariable(ctx, owner, repo, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("delete repo action variable err: %v", err))
|
return to.ErrorResult(fmt.Errorf("delete repo action variable err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -436,10 +417,9 @@ func deleteRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listOrgActionVariablesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listOrgActionVariablesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listOrgActionVariablesFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil || org == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("org is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
||||||
|
|
||||||
@@ -447,7 +427,7 @@ func listOrgActionVariablesFn(ctx context.Context, req mcp.CallToolRequest) (*mc
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
variables, _, err := client.ListOrgActionVariable(org, gitea_sdk.ListOrgActionVariableOption{
|
variables, _, err := client.Actions.ListOrgVariables(ctx, org, gitea_sdk.ListOrgActionsVariableOption{
|
||||||
ListOptions: gitea_sdk.ListOptions{Page: page, PageSize: pageSize},
|
ListOptions: gitea_sdk.ListOptions{Page: page, PageSize: pageSize},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -457,21 +437,20 @@ func listOrgActionVariablesFn(ctx context.Context, req mcp.CallToolRequest) (*mc
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getOrgActionVariableFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil || org == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("org is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
name, err := params.GetString(req.GetArguments(), "name")
|
name, err := params.GetString(req.GetArguments(), "name")
|
||||||
if err != nil || name == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("name is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
variable, _, err := client.GetOrgActionVariable(org, name)
|
variable, _, err := client.Actions.GetOrgVariable(ctx, org, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get org action variable err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get org action variable err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -479,18 +458,17 @@ func getOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func createOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called createOrgActionVariableFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil || org == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("org is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
name, err := params.GetString(req.GetArguments(), "name")
|
name, err := params.GetString(req.GetArguments(), "name")
|
||||||
if err != nil || name == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("name is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
value, err := params.GetString(req.GetArguments(), "value")
|
value, err := params.GetString(req.GetArguments(), "value")
|
||||||
if err != nil || value == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("value is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
description, _ := req.GetArguments()["description"].(string)
|
description, _ := req.GetArguments()["description"].(string)
|
||||||
|
|
||||||
@@ -498,8 +476,7 @@ func createOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
resp, err := client.CreateOrgActionVariable(org, gitea_sdk.CreateOrgActionVariableOption{
|
resp, err := client.Actions.CreateOrgVariable(ctx, org, name, gitea_sdk.CreateActionsVariableOption{
|
||||||
Name: name,
|
|
||||||
Value: value,
|
Value: value,
|
||||||
Description: description,
|
Description: description,
|
||||||
})
|
})
|
||||||
@@ -510,18 +487,17 @@ func createOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func updateOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called updateOrgActionVariableFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil || org == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("org is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
name, err := params.GetString(req.GetArguments(), "name")
|
name, err := params.GetString(req.GetArguments(), "name")
|
||||||
if err != nil || name == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("name is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
value, err := params.GetString(req.GetArguments(), "value")
|
value, err := params.GetString(req.GetArguments(), "value")
|
||||||
if err != nil || value == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("value is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
description, _ := req.GetArguments()["description"].(string)
|
description, _ := req.GetArguments()["description"].(string)
|
||||||
|
|
||||||
@@ -529,7 +505,8 @@ func updateOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
resp, err := client.UpdateOrgActionVariable(org, name, gitea_sdk.UpdateOrgActionVariableOption{
|
resp, err := client.Actions.UpdateOrgVariable(ctx, org, name, gitea_sdk.UpdateActionsVariableOption{
|
||||||
|
Name: name,
|
||||||
Value: value,
|
Value: value,
|
||||||
Description: description,
|
Description: description,
|
||||||
})
|
})
|
||||||
@@ -540,14 +517,13 @@ func updateOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deleteOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deleteOrgActionVariableFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil || org == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("org is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
name, err := params.GetString(req.GetArguments(), "name")
|
name, err := params.GetString(req.GetArguments(), "name")
|
||||||
if err != nil || name == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("name is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = gitea.DoJSON(ctx, "DELETE", fmt.Sprintf("orgs/%s/actions/variables/%s", url.PathEscape(org), url.PathEscape(name)), nil, nil, nil)
|
_, err = gitea.DoJSON(ctx, "DELETE", fmt.Sprintf("orgs/%s/actions/variables/%s", url.PathEscape(org), url.PathEscape(name)), nil, nil, nil)
|
||||||
|
|||||||
+42
-56
@@ -12,7 +12,6 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
|
|
||||||
@@ -125,14 +124,13 @@ func doJSONWithFallback(ctx context.Context, method string, paths []string, quer
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listRepoActionWorkflowsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listRepoActionWorkflowsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listRepoActionWorkflowsFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
@@ -153,18 +151,17 @@ func listRepoActionWorkflowsFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getRepoActionWorkflowFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getRepoActionWorkflowFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getRepoActionWorkflowFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
workflowID, err := params.GetString(req.GetArguments(), "workflow_id")
|
workflowID, err := params.GetString(req.GetArguments(), "workflow_id")
|
||||||
if err != nil || workflowID == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("workflow_id is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var result any
|
var result any
|
||||||
@@ -181,22 +178,21 @@ func getRepoActionWorkflowFn(ctx context.Context, req mcp.CallToolRequest) (*mcp
|
|||||||
}
|
}
|
||||||
|
|
||||||
func dispatchRepoActionWorkflowFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func dispatchRepoActionWorkflowFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called dispatchRepoActionWorkflowFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
workflowID, err := params.GetString(req.GetArguments(), "workflow_id")
|
workflowID, err := params.GetString(req.GetArguments(), "workflow_id")
|
||||||
if err != nil || workflowID == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("workflow_id is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
ref, err := params.GetString(req.GetArguments(), "ref")
|
ref, err := params.GetString(req.GetArguments(), "ref")
|
||||||
if err != nil || ref == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("ref is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var inputs map[string]any
|
var inputs map[string]any
|
||||||
@@ -231,14 +227,13 @@ func dispatchRepoActionWorkflowFn(ctx context.Context, req mcp.CallToolRequest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listRepoActionRunsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listRepoActionRunsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listRepoActionRunsFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
||||||
statusFilter, _ := req.GetArguments()["status"].(string)
|
statusFilter, _ := req.GetArguments()["status"].(string)
|
||||||
@@ -264,14 +259,13 @@ func listRepoActionRunsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getRepoActionRunFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
runID, err := params.GetIndex(req.GetArguments(), "run_id")
|
runID, err := params.GetIndex(req.GetArguments(), "run_id")
|
||||||
if err != nil || runID <= 0 {
|
if err != nil || runID <= 0 {
|
||||||
@@ -292,14 +286,13 @@ func getRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
}
|
}
|
||||||
|
|
||||||
func cancelRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func cancelRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called cancelRepoActionRunFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
runID, err := params.GetIndex(req.GetArguments(), "run_id")
|
runID, err := params.GetIndex(req.GetArguments(), "run_id")
|
||||||
if err != nil || runID <= 0 {
|
if err != nil || runID <= 0 {
|
||||||
@@ -319,14 +312,13 @@ func cancelRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
func rerunRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func rerunRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called rerunRepoActionRunFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
runID, err := params.GetIndex(req.GetArguments(), "run_id")
|
runID, err := params.GetIndex(req.GetArguments(), "run_id")
|
||||||
if err != nil || runID <= 0 {
|
if err != nil || runID <= 0 {
|
||||||
@@ -351,14 +343,13 @@ func rerunRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listRepoActionJobsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listRepoActionJobsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listRepoActionJobsFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
||||||
statusFilter, _ := req.GetArguments()["status"].(string)
|
statusFilter, _ := req.GetArguments()["status"].(string)
|
||||||
@@ -384,14 +375,13 @@ func listRepoActionJobsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listRepoActionRunJobsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listRepoActionRunJobsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listRepoActionRunJobsFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil || owner == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("owner is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
repo, err := params.GetString(req.GetArguments(), "repo")
|
repo, err := params.GetString(req.GetArguments(), "repo")
|
||||||
if err != nil || repo == "" {
|
if err != nil {
|
||||||
return to.ErrorResult(errors.New("repo is required"))
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
runID, err := params.GetIndex(req.GetArguments(), "run_id")
|
runID, err := params.GetIndex(req.GetArguments(), "run_id")
|
||||||
if err != nil || runID <= 0 {
|
if err != nil || runID <= 0 {
|
||||||
@@ -416,8 +406,6 @@ func listRepoActionRunJobsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp
|
|||||||
return to.TextResult(slimActionJobs(result))
|
return to.TextResult(slimActionJobs(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log functions (merged from logs.go)
|
|
||||||
|
|
||||||
func logPaths(owner, repo string, jobID int64) []string {
|
func logPaths(owner, repo string, jobID int64) []string {
|
||||||
return []string{
|
return []string{
|
||||||
fmt.Sprintf("repos/%s/%s/actions/jobs/%d/logs", url.PathEscape(owner), url.PathEscape(repo), jobID),
|
fmt.Sprintf("repos/%s/%s/actions/jobs/%d/logs", url.PathEscape(owner), url.PathEscape(repo), jobID),
|
||||||
@@ -473,7 +461,6 @@ func limitBytes(data []byte, maxBytes int) ([]byte, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getRepoActionJobLogPreviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getRepoActionJobLogPreviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getRepoActionJobLogPreviewFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -508,7 +495,6 @@ func getRepoActionJobLogPreviewFn(ctx context.Context, req mcp.CallToolRequest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func downloadRepoActionJobLogFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func downloadRepoActionJobLogFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called downloadRepoActionJobLogFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
|
|||||||
+44
-54
@@ -7,12 +7,12 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
|
"gitea.com/gitea/gitea-mcp/pkg/slim"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -40,11 +40,14 @@ const (
|
|||||||
var (
|
var (
|
||||||
ListRepoIssuesTool = mcp.NewTool(
|
ListRepoIssuesTool = mcp.NewTool(
|
||||||
ListRepoIssuesToolName,
|
ListRepoIssuesToolName,
|
||||||
|
mcp.WithDescription("List issues in a repository (or pull requests, via the 'type' filter), filterable by state, labels, milestones, and update time range."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("List repository issues")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("List repository issues")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
mcp.WithString("state", mcp.DefaultString("all")),
|
mcp.WithString("state", mcp.DefaultString("all")),
|
||||||
|
mcp.WithString("type", mcp.Description("issues or pulls"), mcp.Enum("issues", "pulls")),
|
||||||
mcp.WithArray("labels", mcp.Description("label name filter"), mcp.Items(map[string]any{"type": "string"})),
|
mcp.WithArray("labels", mcp.Description("label name filter"), mcp.Items(map[string]any{"type": "string"})),
|
||||||
|
mcp.WithArray("milestones", mcp.Description("milestone name or ID filter"), mcp.Items(map[string]any{"type": "string"})),
|
||||||
mcp.WithString("since", mcp.Description("updated after ISO 8601")),
|
mcp.WithString("since", mcp.Description("updated after ISO 8601")),
|
||||||
mcp.WithString("before", mcp.Description("updated before ISO 8601")),
|
mcp.WithString("before", mcp.Description("updated before ISO 8601")),
|
||||||
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1)),
|
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1)),
|
||||||
@@ -145,7 +148,6 @@ func issueWriteFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -164,12 +166,11 @@ func getIssueByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
return to.ErrorResult(fmt.Errorf("get %v/%v/issue/%v err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("get %v/%v/issue/%v err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
m := slimIssue(&issue.Issue)
|
m := slimIssue(&issue.Issue)
|
||||||
m["body"] = bodyWithAttachments(issue.Body, issue.Assets)
|
m["body"] = slim.BodyWithAttachments(issue.Body, issue.Assets)
|
||||||
return to.TextResult(m)
|
return to.TextResult(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -183,15 +184,23 @@ func listRepoIssuesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
state = "all"
|
state = "all"
|
||||||
}
|
}
|
||||||
labels := params.GetStringSlice(req.GetArguments(), "labels")
|
labels := params.GetStringSlice(req.GetArguments(), "labels")
|
||||||
|
milestones := params.GetStringSlice(req.GetArguments(), "milestones")
|
||||||
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
||||||
opt := gitea_sdk.ListIssueOption{
|
opt := gitea_sdk.ListIssueOption{
|
||||||
State: gitea_sdk.StateType(state),
|
State: gitea_sdk.StateType(state),
|
||||||
Labels: labels,
|
Labels: labels,
|
||||||
|
Milestones: milestones,
|
||||||
ListOptions: gitea_sdk.ListOptions{
|
ListOptions: gitea_sdk.ListOptions{
|
||||||
Page: page,
|
Page: page,
|
||||||
PageSize: pageSize,
|
PageSize: pageSize,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
switch req.GetArguments()["type"] {
|
||||||
|
case "issues":
|
||||||
|
opt.Type = gitea_sdk.IssueTypeIssue
|
||||||
|
case "pulls":
|
||||||
|
opt.Type = gitea_sdk.IssueTypePull
|
||||||
|
}
|
||||||
if t := params.GetOptionalTime(req.GetArguments(), "since"); t != nil {
|
if t := params.GetOptionalTime(req.GetArguments(), "since"); t != nil {
|
||||||
opt.Since = *t
|
opt.Since = *t
|
||||||
}
|
}
|
||||||
@@ -202,7 +211,7 @@ func listRepoIssuesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
issues, _, err := client.ListRepoIssues(owner, repo, opt)
|
issues, _, err := client.Issues.ListRepoIssues(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get %v/%v/issues err: %v", owner, repo, err))
|
return to.ErrorResult(fmt.Errorf("get %v/%v/issues err: %v", owner, repo, err))
|
||||||
}
|
}
|
||||||
@@ -210,7 +219,6 @@ 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")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -248,7 +256,7 @@ func createIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
|
|||||||
opt.Ref = ref
|
opt.Ref = ref
|
||||||
}
|
}
|
||||||
opt.Deadline = params.GetOptionalTime(req.GetArguments(), "deadline")
|
opt.Deadline = params.GetOptionalTime(req.GetArguments(), "deadline")
|
||||||
issue, _, err := client.CreateIssue(owner, repo, opt)
|
issue, _, err := client.Issues.CreateIssue(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("create %v/%v/issue err: %v", owner, repo, err))
|
return to.ErrorResult(fmt.Errorf("create %v/%v/issue err: %v", owner, repo, err))
|
||||||
}
|
}
|
||||||
@@ -257,7 +265,6 @@ 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")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -281,7 +288,7 @@ func createIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
issueComment, _, err := client.CreateIssueComment(owner, repo, index, opt)
|
issueComment, _, err := client.Issues.CreateIssueComment(ctx, owner, repo, index, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("create %v/%v/issue/%v/comment err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("create %v/%v/issue/%v/comment err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -290,7 +297,6 @@ 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")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -304,39 +310,32 @@ func editIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes
|
|||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
opt := gitea_sdk.EditIssueOption{}
|
args := req.GetArguments()
|
||||||
|
opt := gitea_sdk.EditIssueOption{
|
||||||
title, ok := req.GetArguments()["title"].(string)
|
Body: params.GetPresentStringPtr(args, "body"),
|
||||||
if ok {
|
Ref: params.GetPresentStringPtr(args, "ref"),
|
||||||
|
Assignees: params.GetStringSlice(args, "assignees"),
|
||||||
|
Deadline: params.GetOptionalTime(args, "deadline"),
|
||||||
|
RemoveDeadline: params.GetOptionalBoolPtr(args, "remove_deadline"),
|
||||||
|
}
|
||||||
|
if title, ok := args["title"].(string); ok {
|
||||||
opt.Title = title
|
opt.Title = title
|
||||||
}
|
}
|
||||||
body, ok := req.GetArguments()["body"].(string)
|
if val, exists := args["milestone"]; exists {
|
||||||
if ok {
|
|
||||||
opt.Body = new(body)
|
|
||||||
}
|
|
||||||
opt.Assignees = params.GetStringSlice(req.GetArguments(), "assignees")
|
|
||||||
if val, exists := req.GetArguments()["milestone"]; exists {
|
|
||||||
if milestone, ok := params.ToInt64(val); ok {
|
if milestone, ok := params.ToInt64(val); ok {
|
||||||
opt.Milestone = new(milestone)
|
opt.Milestone = &milestone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state, ok := req.GetArguments()["state"].(string)
|
if state, ok := args["state"].(string); ok {
|
||||||
if ok {
|
s := gitea_sdk.StateType(state)
|
||||||
opt.State = new(gitea_sdk.StateType(state))
|
opt.State = &s
|
||||||
}
|
|
||||||
if ref, ok := req.GetArguments()["ref"].(string); ok {
|
|
||||||
opt.Ref = &ref
|
|
||||||
}
|
|
||||||
opt.Deadline = params.GetOptionalTime(req.GetArguments(), "deadline")
|
|
||||||
if removeDeadline, ok := req.GetArguments()["remove_deadline"].(bool); ok {
|
|
||||||
opt.RemoveDeadline = &removeDeadline
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
issue, _, err := client.EditIssue(owner, repo, index, opt)
|
issue, _, err := client.Issues.EditIssue(ctx, owner, repo, index, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("edit %v/%v/issue/%v err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("edit %v/%v/issue/%v err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -345,7 +344,6 @@ func editIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
func editIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func editIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called editIssueCommentFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -369,7 +367,7 @@ func editIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
issueComment, _, err := client.EditIssueComment(owner, repo, commentID, opt)
|
issueComment, _, err := client.Issues.EditIssueComment(ctx, owner, repo, commentID, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("edit %v/%v/issues/comments/%v err: %v", owner, repo, commentID, err))
|
return to.ErrorResult(fmt.Errorf("edit %v/%v/issues/comments/%v err: %v", owner, repo, commentID, err))
|
||||||
}
|
}
|
||||||
@@ -378,7 +376,6 @@ func editIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getIssueCommentsByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getIssueCommentsByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getIssueCommentsByIndexFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -399,14 +396,13 @@ func getIssueCommentsByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
out := make([]map[string]any, 0, len(comments))
|
out := make([]map[string]any, 0, len(comments))
|
||||||
for i := range comments {
|
for i := range comments {
|
||||||
m := slimComment(&comments[i].Comment)
|
m := slimComment(&comments[i].Comment)
|
||||||
m["body"] = bodyWithAttachments(comments[i].Body, comments[i].Assets)
|
m["body"] = slim.BodyWithAttachments(comments[i].Body, comments[i].Assets)
|
||||||
out = append(out, m)
|
out = append(out, m)
|
||||||
}
|
}
|
||||||
return to.TextResult(out)
|
return to.TextResult(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getIssueLabelsFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -424,17 +420,14 @@ func getIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
labels, _, err := client.GetIssueLabels(owner, repo, index, gitea_sdk.ListLabelsOptions{})
|
labels, _, err := client.Issues.GetIssueLabels(ctx, owner, repo, index, gitea_sdk.ListLabelsOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get %v/%v/issues/%v/labels err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("get %v/%v/issues/%v/labels err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimLabels(labels))
|
return to.TextResult(slim.Labels(labels))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue label operations (moved from label package)
|
|
||||||
|
|
||||||
func addIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func addIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called addIssueLabelsFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -456,15 +449,14 @@ func addIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
issueLabels, _, err := client.AddIssueLabels(owner, repo, index, gitea_sdk.IssueLabelsOption{Labels: labels})
|
issueLabels, _, err := client.Issues.AddIssueLabels(ctx, owner, repo, index, gitea_sdk.IssueLabelsOption{Labels: labels})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("add labels to %v/%v/issue/%v err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("add labels to %v/%v/issue/%v err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimLabels(issueLabels))
|
return to.TextResult(slim.Labels(issueLabels))
|
||||||
}
|
}
|
||||||
|
|
||||||
func replaceIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func replaceIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called replaceIssueLabelsFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -486,15 +478,14 @@ func replaceIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
issueLabels, _, err := client.ReplaceIssueLabels(owner, repo, index, gitea_sdk.IssueLabelsOption{Labels: labels})
|
issueLabels, _, err := client.Issues.ReplaceIssueLabels(ctx, owner, repo, index, gitea_sdk.IssueLabelsOption{Labels: labels})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("replace labels on %v/%v/issue/%v err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("replace labels on %v/%v/issue/%v err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimLabels(issueLabels))
|
return to.TextResult(slim.Labels(issueLabels))
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func clearIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called clearIssueLabelsFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -512,7 +503,7 @@ func clearIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, err = client.ClearIssueLabels(owner, repo, index)
|
_, err = client.Issues.ClearIssueLabels(ctx, owner, repo, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("clear labels on %v/%v/issue/%v err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("clear labels on %v/%v/issue/%v err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -520,7 +511,6 @@ func clearIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
}
|
}
|
||||||
|
|
||||||
func removeIssueLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func removeIssueLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called removeIssueLabelFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -542,7 +532,7 @@ func removeIssueLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, err = client.DeleteIssueLabel(owner, repo, index, labelID)
|
_, err = client.Issues.DeleteIssueLabel(ctx, owner, repo, index, labelID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("remove label %v from %v/%v/issue/%v err: %v", labelID, owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("remove label %v from %v/%v/issue/%v err: %v", labelID, owner, repo, index, err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,10 +63,12 @@ func Test_listRepoIssuesFn_filters(t *testing.T) {
|
|||||||
req := mcp.CallToolRequest{
|
req := mcp.CallToolRequest{
|
||||||
Params: mcp.CallToolParams{
|
Params: mcp.CallToolParams{
|
||||||
Arguments: map[string]any{
|
Arguments: map[string]any{
|
||||||
"owner": owner,
|
"owner": owner,
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
"labels": []any{"bug", "enhancement"},
|
"type": "issues",
|
||||||
"since": "2026-01-01T00:00:00Z",
|
"labels": []any{"bug", "enhancement"},
|
||||||
|
"milestones": []any{"v1.0", "2"},
|
||||||
|
"since": "2026-01-01T00:00:00Z",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -85,6 +87,59 @@ func Test_listRepoIssuesFn_filters(t *testing.T) {
|
|||||||
if !strings.Contains(gotQuery, "since=2026-01-01") {
|
if !strings.Contains(gotQuery, "since=2026-01-01") {
|
||||||
t.Fatalf("expected since query param, got %s", gotQuery)
|
t.Fatalf("expected since query param, got %s", gotQuery)
|
||||||
}
|
}
|
||||||
|
if !strings.Contains(gotQuery, "milestones=v1.0%2C2") {
|
||||||
|
t.Fatalf("expected milestones query param, got %s", gotQuery)
|
||||||
|
}
|
||||||
|
if !strings.Contains(gotQuery, "type=issues") {
|
||||||
|
t.Fatalf("expected type query param, got %s", gotQuery)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_listRepoIssuesFn_includesMilestone(t *testing.T) {
|
||||||
|
const (
|
||||||
|
owner = "octo"
|
||||||
|
repo = "demo"
|
||||||
|
)
|
||||||
|
|
||||||
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch r.URL.Path {
|
||||||
|
case "/api/v1/version":
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_, _ = w.Write([]byte(`{"version":"1.12.0"}`))
|
||||||
|
case fmt.Sprintf("/api/v1/repos/%s/%s", owner, repo):
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_, _ = w.Write([]byte(`{"private":false}`))
|
||||||
|
case fmt.Sprintf("/api/v1/repos/%s/%s/issues", owner, repo):
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_, _ = w.Write([]byte(`[
|
||||||
|
{"number": 1, "title": "with milestone", "state": "closed", "milestone": {"id": 5, "title": "v1.0"}},
|
||||||
|
{"number": 2, "title": "without milestone", "state": "open"}
|
||||||
|
]`))
|
||||||
|
default:
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
server := httptest.NewServer(handler)
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
origHost, origToken, origVersion := flag.Host, flag.Token, flag.Version
|
||||||
|
flag.Host, flag.Token, flag.Version = server.URL, "", "test"
|
||||||
|
defer func() { flag.Host, flag.Token, flag.Version = origHost, origToken, origVersion }()
|
||||||
|
|
||||||
|
req := mcp.CallToolRequest{Params: mcp.CallToolParams{Arguments: map[string]any{
|
||||||
|
"owner": owner, "repo": repo,
|
||||||
|
}}}
|
||||||
|
res, err := listRepoIssuesFn(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("listRepoIssuesFn() error = %v", err)
|
||||||
|
}
|
||||||
|
if res.IsError {
|
||||||
|
t.Fatalf("unexpected error result: %v", res.Content)
|
||||||
|
}
|
||||||
|
body := res.Content[0].(mcp.TextContent).Text
|
||||||
|
if !strings.Contains(body, `"milestone"`) || !strings.Contains(body, `"v1.0"`) {
|
||||||
|
t.Fatalf("expected milestone in list output, got: %s", body)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_createIssueFn_labels(t *testing.T) {
|
func Test_createIssueFn_labels(t *testing.T) {
|
||||||
|
|||||||
+14
-77
@@ -1,63 +1,11 @@
|
|||||||
package issue
|
package issue
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"gitea.com/gitea/gitea-mcp/pkg/slim"
|
||||||
"strings"
|
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func userLogin(u *gitea_sdk.User) string {
|
|
||||||
if u == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return u.UserName
|
|
||||||
}
|
|
||||||
|
|
||||||
func userLogins(users []*gitea_sdk.User) []string {
|
|
||||||
if len(users) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := make([]string, 0, len(users))
|
|
||||||
for _, u := range users {
|
|
||||||
if u != nil {
|
|
||||||
out = append(out, u.UserName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func labelNames(labels []*gitea_sdk.Label) []string {
|
|
||||||
if len(labels) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := make([]string, 0, len(labels))
|
|
||||||
for _, l := range labels {
|
|
||||||
if l != nil {
|
|
||||||
out = append(out, l.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func bodyWithAttachments(body string, atts []*gitea_sdk.Attachment) string {
|
|
||||||
links := make([]string, 0, len(atts))
|
|
||||||
for _, a := range atts {
|
|
||||||
if a == nil || a.DownloadURL == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
links = append(links, fmt.Sprintf("[%s](%s)", a.Name, a.DownloadURL))
|
|
||||||
}
|
|
||||||
if len(links) == 0 {
|
|
||||||
return body
|
|
||||||
}
|
|
||||||
joined := strings.Join(links, "\n")
|
|
||||||
if body == "" {
|
|
||||||
return joined
|
|
||||||
}
|
|
||||||
return body + "\n\n" + joined
|
|
||||||
}
|
|
||||||
|
|
||||||
func slimIssue(i *gitea_sdk.Issue) map[string]any {
|
func slimIssue(i *gitea_sdk.Issue) map[string]any {
|
||||||
if i == nil {
|
if i == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -68,15 +16,15 @@ func slimIssue(i *gitea_sdk.Issue) map[string]any {
|
|||||||
"body": i.Body,
|
"body": i.Body,
|
||||||
"state": i.State,
|
"state": i.State,
|
||||||
"html_url": i.HTMLURL,
|
"html_url": i.HTMLURL,
|
||||||
"user": userLogin(i.Poster),
|
"user": slim.UserLogin(i.Poster),
|
||||||
"labels": labelNames(i.Labels),
|
"labels": slim.LabelNames(i.Labels),
|
||||||
"comments": i.Comments,
|
"comments": i.Comments,
|
||||||
"created_at": i.Created,
|
"created_at": i.Created,
|
||||||
"updated_at": i.Updated,
|
"updated_at": i.Updated,
|
||||||
"closed_at": i.Closed,
|
"closed_at": i.Closed,
|
||||||
}
|
}
|
||||||
if len(i.Assignees) > 0 {
|
if len(i.Assignees) > 0 {
|
||||||
m["assignees"] = userLogins(i.Assignees)
|
m["assignees"] = slim.UserLogins(i.Assignees)
|
||||||
}
|
}
|
||||||
if i.Milestone != nil {
|
if i.Milestone != nil {
|
||||||
m["milestone"] = map[string]any{
|
m["milestone"] = map[string]any{
|
||||||
@@ -107,13 +55,19 @@ func slimIssues(issues []*gitea_sdk.Issue) []map[string]any {
|
|||||||
"title": i.Title,
|
"title": i.Title,
|
||||||
"state": i.State,
|
"state": i.State,
|
||||||
"html_url": i.HTMLURL,
|
"html_url": i.HTMLURL,
|
||||||
"user": userLogin(i.Poster),
|
"user": slim.UserLogin(i.Poster),
|
||||||
"comments": i.Comments,
|
"comments": i.Comments,
|
||||||
"created_at": i.Created,
|
"created_at": i.Created,
|
||||||
"updated_at": i.Updated,
|
"updated_at": i.Updated,
|
||||||
}
|
}
|
||||||
if len(i.Labels) > 0 {
|
if len(i.Labels) > 0 {
|
||||||
m["labels"] = labelNames(i.Labels)
|
m["labels"] = slim.LabelNames(i.Labels)
|
||||||
|
}
|
||||||
|
if i.Milestone != nil {
|
||||||
|
m["milestone"] = map[string]any{
|
||||||
|
"id": i.Milestone.ID,
|
||||||
|
"title": i.Milestone.Title,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if i.Ref != "" {
|
if i.Ref != "" {
|
||||||
m["ref"] = i.Ref
|
m["ref"] = i.Ref
|
||||||
@@ -133,26 +87,9 @@ func slimComment(c *gitea_sdk.Comment) map[string]any {
|
|||||||
return map[string]any{
|
return map[string]any{
|
||||||
"id": c.ID,
|
"id": c.ID,
|
||||||
"body": c.Body,
|
"body": c.Body,
|
||||||
"user": userLogin(c.Poster),
|
"user": slim.UserLogin(c.Poster),
|
||||||
"html_url": c.HTMLURL,
|
"html_url": c.HTMLURL,
|
||||||
"created_at": c.Created,
|
"created_at": c.Created,
|
||||||
"updated_at": c.Updated,
|
"updated_at": c.Updated,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func slimLabels(labels []*gitea_sdk.Label) []map[string]any {
|
|
||||||
out := make([]map[string]any, 0, len(labels))
|
|
||||||
for _, l := range labels {
|
|
||||||
if l == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
out = append(out, map[string]any{
|
|
||||||
"id": l.ID,
|
|
||||||
"name": l.Name,
|
|
||||||
"color": l.Color,
|
|
||||||
"description": l.Description,
|
|
||||||
"exclusive": l.Exclusive,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package issue
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSlimIssue(t *testing.T) {
|
func TestSlimIssue(t *testing.T) {
|
||||||
@@ -40,29 +40,6 @@ func TestSlimIssue(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBodyWithAttachments(t *testing.T) {
|
|
||||||
atts := []*gitea_sdk.Attachment{
|
|
||||||
{Name: "shot.png", DownloadURL: "https://example/shot.png"},
|
|
||||||
{Name: "log.txt", DownloadURL: "https://example/log.txt"},
|
|
||||||
}
|
|
||||||
got := bodyWithAttachments("see attached", atts)
|
|
||||||
want := "see attached\n\n[shot.png](https://example/shot.png)\n[log.txt](https://example/log.txt)"
|
|
||||||
if got != want {
|
|
||||||
t.Errorf("got %q, want %q", got, want)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got := bodyWithAttachments("only body", nil); got != "only body" {
|
|
||||||
t.Errorf("nil attachments should return body unchanged, got %q", got)
|
|
||||||
}
|
|
||||||
if got := bodyWithAttachments("", atts); got != "[shot.png](https://example/shot.png)\n[log.txt](https://example/log.txt)" {
|
|
||||||
t.Errorf("empty body should drop separator, got %q", got)
|
|
||||||
}
|
|
||||||
skipped := []*gitea_sdk.Attachment{nil, {Name: "noop", DownloadURL: ""}}
|
|
||||||
if got := bodyWithAttachments("body", skipped); got != "body" {
|
|
||||||
t.Errorf("nil/empty-URL attachments should be skipped, got %q", got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSlimIssues_ListIsSlimmer(t *testing.T) {
|
func TestSlimIssues_ListIsSlimmer(t *testing.T) {
|
||||||
i := &gitea_sdk.Issue{
|
i := &gitea_sdk.Issue{
|
||||||
Index: 1,
|
Index: 1,
|
||||||
|
|||||||
+30
-51
@@ -6,12 +6,12 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
|
"gitea.com/gitea/gitea-mcp/pkg/slim"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -108,7 +108,6 @@ func labelWriteFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listRepoLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listRepoLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listRepoLabelsFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -129,15 +128,14 @@ func listRepoLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
labels, _, err := client.ListRepoLabels(owner, repo, opt)
|
labels, _, err := client.Repositories.ListRepoLabels(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("list %v/%v/labels err: %v", owner, repo, err))
|
return to.ErrorResult(fmt.Errorf("list %v/%v/labels err: %v", owner, repo, err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimLabels(labels))
|
return to.TextResult(slim.Labels(labels))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getRepoLabelFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -155,15 +153,14 @@ func getRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
label, _, err := client.GetRepoLabel(owner, repo, id)
|
label, _, err := client.Repositories.GetRepoLabel(ctx, owner, repo, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get %v/%v/label/%v err: %v", owner, repo, id, err))
|
return to.ErrorResult(fmt.Errorf("get %v/%v/label/%v err: %v", owner, repo, id, err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimLabel(label))
|
return to.TextResult(slim.Label(label))
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func createRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called createRepoLabelFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -195,15 +192,14 @@ func createRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
label, _, err := client.CreateLabel(owner, repo, opt)
|
label, _, err := client.Repositories.CreateLabel(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("create %v/%v/label err: %v", owner, repo, err))
|
return to.ErrorResult(fmt.Errorf("create %v/%v/label err: %v", owner, repo, err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimLabel(label))
|
return to.TextResult(slim.Label(label))
|
||||||
}
|
}
|
||||||
|
|
||||||
func editRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func editRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called editRepoLabelFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -217,33 +213,26 @@ func editRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
opt := gitea_sdk.EditLabelOption{}
|
args := req.GetArguments()
|
||||||
if name, ok := req.GetArguments()["name"].(string); ok {
|
opt := gitea_sdk.EditLabelOption{
|
||||||
opt.Name = new(name)
|
Name: params.GetOptionalStringPtr(args, "name"),
|
||||||
}
|
Color: params.GetOptionalStringPtr(args, "color"),
|
||||||
if color, ok := req.GetArguments()["color"].(string); ok {
|
Description: params.GetPresentStringPtr(args, "description"),
|
||||||
opt.Color = new(color)
|
IsArchived: params.GetOptionalBoolPtr(args, "is_archived"),
|
||||||
}
|
|
||||||
if description, ok := req.GetArguments()["description"].(string); ok {
|
|
||||||
opt.Description = new(description)
|
|
||||||
}
|
|
||||||
if isArchived, ok := req.GetArguments()["is_archived"].(bool); ok {
|
|
||||||
opt.IsArchived = &isArchived
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
label, _, err := client.EditLabel(owner, repo, id, opt)
|
label, _, err := client.Repositories.EditLabel(ctx, owner, repo, id, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("edit %v/%v/label/%v err: %v", owner, repo, id, err))
|
return to.ErrorResult(fmt.Errorf("edit %v/%v/label/%v err: %v", owner, repo, id, err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimLabel(label))
|
return to.TextResult(slim.Label(label))
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deleteRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deleteRepoLabelFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -261,7 +250,7 @@ func deleteRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, err = client.DeleteLabel(owner, repo, id)
|
_, err = client.Repositories.DeleteLabel(ctx, owner, repo, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("delete %v/%v/label/%v err: %v", owner, repo, id, err))
|
return to.ErrorResult(fmt.Errorf("delete %v/%v/label/%v err: %v", owner, repo, id, err))
|
||||||
}
|
}
|
||||||
@@ -269,7 +258,6 @@ func deleteRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listOrgLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listOrgLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listOrgLabelsFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -286,15 +274,14 @@ func listOrgLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
labels, _, err := client.ListOrgLabels(org, opt)
|
labels, _, err := client.Organizations.ListOrgLabels(ctx, org, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("list %v/labels err: %v", org, err))
|
return to.ErrorResult(fmt.Errorf("list %v/labels err: %v", org, err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimLabels(labels))
|
return to.TextResult(slim.Labels(labels))
|
||||||
}
|
}
|
||||||
|
|
||||||
func createOrgLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func createOrgLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called createOrgLabelFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -321,15 +308,14 @@ func createOrgLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
label, _, err := client.CreateOrgLabel(org, opt)
|
label, _, err := client.Organizations.CreateOrgLabel(ctx, org, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("create %v/labels err: %v", org, err))
|
return to.ErrorResult(fmt.Errorf("create %v/labels err: %v", org, err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimLabel(label))
|
return to.TextResult(slim.Label(label))
|
||||||
}
|
}
|
||||||
|
|
||||||
func editOrgLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func editOrgLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called editOrgLabelFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -339,33 +325,26 @@ func editOrgLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
|
|||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
opt := gitea_sdk.EditOrgLabelOption{}
|
args := req.GetArguments()
|
||||||
if name, ok := req.GetArguments()["name"].(string); ok {
|
opt := gitea_sdk.EditOrgLabelOption{
|
||||||
opt.Name = new(name)
|
Name: params.GetOptionalStringPtr(args, "name"),
|
||||||
}
|
Color: params.GetOptionalStringPtr(args, "color"),
|
||||||
if color, ok := req.GetArguments()["color"].(string); ok {
|
Description: params.GetPresentStringPtr(args, "description"),
|
||||||
opt.Color = new(color)
|
Exclusive: params.GetOptionalBoolPtr(args, "exclusive"),
|
||||||
}
|
|
||||||
if description, ok := req.GetArguments()["description"].(string); ok {
|
|
||||||
opt.Description = new(description)
|
|
||||||
}
|
|
||||||
if exclusive, ok := req.GetArguments()["exclusive"].(bool); ok {
|
|
||||||
opt.Exclusive = new(exclusive)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
label, _, err := client.EditOrgLabel(org, id, opt)
|
label, _, err := client.Organizations.EditOrgLabel(ctx, org, id, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("edit %v/labels/%v err: %v", org, id, err))
|
return to.ErrorResult(fmt.Errorf("edit %v/labels/%v err: %v", org, id, err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimLabel(label))
|
return to.TextResult(slim.Label(label))
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteOrgLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deleteOrgLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deleteOrgLabelFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -379,7 +358,7 @@ func deleteOrgLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, err = client.DeleteOrgLabel(org, id)
|
_, err = client.Organizations.DeleteOrgLabel(ctx, org, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("delete %v/labels/%v err: %v", org, id, err))
|
return to.ErrorResult(fmt.Errorf("delete %v/labels/%v err: %v", org, id, err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1 @@
|
|||||||
package label
|
package label
|
||||||
|
|
||||||
import (
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
|
||||||
)
|
|
||||||
|
|
||||||
func slimLabel(l *gitea_sdk.Label) map[string]any {
|
|
||||||
if l == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return map[string]any{
|
|
||||||
"id": l.ID,
|
|
||||||
"name": l.Name,
|
|
||||||
"color": l.Color,
|
|
||||||
"description": l.Description,
|
|
||||||
"exclusive": l.Exclusive,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func slimLabels(labels []*gitea_sdk.Label) []map[string]any {
|
|
||||||
out := make([]map[string]any, 0, len(labels))
|
|
||||||
for _, l := range labels {
|
|
||||||
out = append(out, slimLabel(l))
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
package label
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSlimLabel(t *testing.T) {
|
|
||||||
l := &gitea_sdk.Label{
|
|
||||||
ID: 1,
|
|
||||||
Name: "bug",
|
|
||||||
Color: "#d73a4a",
|
|
||||||
Description: "Something isn't working",
|
|
||||||
Exclusive: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
m := slimLabel(l)
|
|
||||||
if m["name"] != "bug" {
|
|
||||||
t.Errorf("expected name bug, got %v", m["name"])
|
|
||||||
}
|
|
||||||
if m["color"] != "#d73a4a" {
|
|
||||||
t.Errorf("expected color, got %v", m["color"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,12 +6,11 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -99,7 +98,6 @@ func milestoneWriteFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getMilestoneFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -116,7 +114,7 @@ func getMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
milestone, _, err := client.GetMilestone(owner, repo, id)
|
milestone, _, err := client.Repositories.GetMilestone(ctx, owner, repo, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get %v/%v/milestone/%v err: %v", owner, repo, id, err))
|
return to.ErrorResult(fmt.Errorf("get %v/%v/milestone/%v err: %v", owner, repo, id, err))
|
||||||
}
|
}
|
||||||
@@ -125,7 +123,6 @@ func getMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listMilestonesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listMilestonesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listMilestonesFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -149,7 +146,7 @@ func listMilestonesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
milestones, _, err := client.ListRepoMilestones(owner, repo, opt)
|
milestones, _, err := client.Repositories.ListMilestones(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get %v/%v/milestones err: %v", owner, repo, err))
|
return to.ErrorResult(fmt.Errorf("get %v/%v/milestones err: %v", owner, repo, err))
|
||||||
}
|
}
|
||||||
@@ -157,7 +154,6 @@ func listMilestonesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func createMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called createMilestoneFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -185,7 +181,7 @@ func createMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
milestone, _, err := client.CreateMilestone(owner, repo, opt)
|
milestone, _, err := client.Repositories.CreateMilestone(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("create %v/%v/milestone err: %v", owner, repo, err))
|
return to.ErrorResult(fmt.Errorf("create %v/%v/milestone err: %v", owner, repo, err))
|
||||||
}
|
}
|
||||||
@@ -194,7 +190,6 @@ func createMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
}
|
}
|
||||||
|
|
||||||
func editMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func editMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called editMilestoneFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -208,27 +203,24 @@ func editMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
opt := gitea_sdk.EditMilestoneOption{}
|
args := req.GetArguments()
|
||||||
|
opt := gitea_sdk.EditMilestoneOption{
|
||||||
title, ok := req.GetArguments()["title"].(string)
|
Description: params.GetPresentStringPtr(args, "description"),
|
||||||
if ok {
|
Deadline: params.GetOptionalTime(args, "due_on"),
|
||||||
|
}
|
||||||
|
if title, ok := args["title"].(string); ok {
|
||||||
opt.Title = title
|
opt.Title = title
|
||||||
}
|
}
|
||||||
description, ok := req.GetArguments()["description"].(string)
|
if state, ok := args["state"].(string); ok {
|
||||||
if ok {
|
s := gitea_sdk.StateType(state)
|
||||||
opt.Description = new(description)
|
opt.State = &s
|
||||||
}
|
}
|
||||||
state, ok := req.GetArguments()["state"].(string)
|
|
||||||
if ok {
|
|
||||||
opt.State = new(gitea_sdk.StateType(state))
|
|
||||||
}
|
|
||||||
opt.Deadline = params.GetOptionalTime(req.GetArguments(), "due_on")
|
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
milestone, _, err := client.EditMilestone(owner, repo, id, opt)
|
milestone, _, err := client.Repositories.EditMilestone(ctx, owner, repo, id, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("edit %v/%v/milestone/%v err: %v", owner, repo, id, err))
|
return to.ErrorResult(fmt.Errorf("edit %v/%v/milestone/%v err: %v", owner, repo, id, err))
|
||||||
}
|
}
|
||||||
@@ -237,7 +229,6 @@ func editMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deleteMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deleteMilestoneFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -254,7 +245,7 @@ func deleteMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, err = client.DeleteMilestone(owner, repo, id)
|
_, err = client.Repositories.DeleteMilestone(ctx, owner, repo, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("delete %v/%v/milestone/%v err: %v", owner, repo, id, err))
|
return to.ErrorResult(fmt.Errorf("delete %v/%v/milestone/%v err: %v", owner, repo, id, err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package milestone
|
package milestone
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func slimMilestone(m *gitea_sdk.Milestone) map[string]any {
|
func slimMilestone(m *gitea_sdk.Milestone) map[string]any {
|
||||||
|
|||||||
@@ -7,12 +7,11 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -97,7 +96,6 @@ func notificationWriteFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listNotificationsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listNotificationsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listNotificationsFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
page, pageSize := params.GetPagination(args, 30)
|
page, pageSize := params.GetPagination(args, 30)
|
||||||
opt := gitea_sdk.ListNotificationOptions{
|
opt := gitea_sdk.ListNotificationOptions{
|
||||||
@@ -107,10 +105,10 @@ func listNotificationsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
if status, ok := args["status"].(string); ok {
|
if status, ok := args["status"].(string); ok {
|
||||||
opt.Status = []gitea_sdk.NotifyStatus{gitea_sdk.NotifyStatus(status)}
|
opt.Status = []gitea_sdk.NotificationStatus{gitea_sdk.NotificationStatus(status)}
|
||||||
}
|
}
|
||||||
if subjectType, ok := args["subject_type"].(string); ok {
|
if subjectType, ok := args["subject_type"].(string); ok {
|
||||||
opt.SubjectTypes = []gitea_sdk.NotifySubjectType{gitea_sdk.NotifySubjectType(subjectType)}
|
opt.SubjectTypes = []gitea_sdk.NotificationSubjectType{gitea_sdk.NotificationSubjectType(subjectType)}
|
||||||
}
|
}
|
||||||
if t := params.GetOptionalTime(args, "since"); t != nil {
|
if t := params.GetOptionalTime(args, "since"); t != nil {
|
||||||
opt.Since = *t
|
opt.Since = *t
|
||||||
@@ -127,14 +125,14 @@ func listNotificationsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal
|
|||||||
owner := params.GetOptionalString(args, "owner", "")
|
owner := params.GetOptionalString(args, "owner", "")
|
||||||
repo := params.GetOptionalString(args, "repo", "")
|
repo := params.GetOptionalString(args, "repo", "")
|
||||||
if owner != "" && repo != "" {
|
if owner != "" && repo != "" {
|
||||||
threads, _, err := client.ListRepoNotifications(owner, repo, opt)
|
threads, _, err := client.Notifications.ListByRepo(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("list %v/%v/notifications err: %v", owner, repo, err))
|
return to.ErrorResult(fmt.Errorf("list %v/%v/notifications err: %v", owner, repo, err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimThreads(threads))
|
return to.TextResult(slimThreads(threads))
|
||||||
}
|
}
|
||||||
|
|
||||||
threads, _, err := client.ListNotifications(opt)
|
threads, _, err := client.Notifications.List(ctx, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("list notifications err: %v", err))
|
return to.ErrorResult(fmt.Errorf("list notifications err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -142,7 +140,6 @@ func listNotificationsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getNotificationFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getNotificationFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getNotificationFn")
|
|
||||||
id, err := params.GetIndex(req.GetArguments(), "id")
|
id, err := params.GetIndex(req.GetArguments(), "id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -151,7 +148,7 @@ func getNotificationFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
thread, _, err := client.GetNotification(id)
|
thread, _, err := client.Notifications.GetByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get notification/%v err: %v", id, err))
|
return to.ErrorResult(fmt.Errorf("get notification/%v err: %v", id, err))
|
||||||
}
|
}
|
||||||
@@ -159,7 +156,6 @@ func getNotificationFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
}
|
}
|
||||||
|
|
||||||
func markNotificationReadFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func markNotificationReadFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called markNotificationReadFn")
|
|
||||||
id, err := params.GetIndex(req.GetArguments(), "id")
|
id, err := params.GetIndex(req.GetArguments(), "id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -168,7 +164,7 @@ func markNotificationReadFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
thread, _, err := client.ReadNotification(id)
|
thread, _, err := client.Notifications.MarkReadByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("mark notification/%v read err: %v", id, err))
|
return to.ErrorResult(fmt.Errorf("mark notification/%v read err: %v", id, err))
|
||||||
}
|
}
|
||||||
@@ -179,7 +175,6 @@ func markNotificationReadFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func markAllNotificationsReadFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func markAllNotificationsReadFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called markAllNotificationsReadFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
lastReadAt := time.Now()
|
lastReadAt := time.Now()
|
||||||
if t := params.GetOptionalTime(args, "last_read_at"); t != nil {
|
if t := params.GetOptionalTime(args, "last_read_at"); t != nil {
|
||||||
@@ -197,7 +192,7 @@ func markAllNotificationsReadFn(ctx context.Context, req mcp.CallToolRequest) (*
|
|||||||
owner := params.GetOptionalString(args, "owner", "")
|
owner := params.GetOptionalString(args, "owner", "")
|
||||||
repo := params.GetOptionalString(args, "repo", "")
|
repo := params.GetOptionalString(args, "repo", "")
|
||||||
if owner != "" && repo != "" {
|
if owner != "" && repo != "" {
|
||||||
threads, _, err := client.ReadRepoNotifications(owner, repo, opt)
|
threads, _, err := client.Notifications.MarkReadByRepo(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("mark %v/%v/notifications read err: %v", owner, repo, err))
|
return to.ErrorResult(fmt.Errorf("mark %v/%v/notifications read err: %v", owner, repo, err))
|
||||||
}
|
}
|
||||||
@@ -207,7 +202,7 @@ func markAllNotificationsReadFn(ctx context.Context, req mcp.CallToolRequest) (*
|
|||||||
return to.TextResult("All repository notifications marked as read")
|
return to.TextResult("All repository notifications marked as read")
|
||||||
}
|
}
|
||||||
|
|
||||||
threads, _, err := client.ReadNotifications(opt)
|
threads, _, err := client.Notifications.MarkRead(ctx, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("mark all notifications read err: %v", err))
|
return to.ErrorResult(fmt.Errorf("mark all notifications read err: %v", err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package notification
|
package notification
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func slimThread(t *gitea_sdk.NotificationThread) map[string]any {
|
func slimThread(t *gitea_sdk.NotificationThread) map[string]any {
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ func RegisterTool(s *server.MCPServer) {
|
|||||||
for _, t := range domainTools {
|
for _, t := range domainTools {
|
||||||
s.AddTools(t.Tools()...)
|
s.AddTools(t.Tools()...)
|
||||||
}
|
}
|
||||||
s.DeleteTools("")
|
|
||||||
tool.WarnUnmatchedAllowedTools(domainTools...)
|
tool.WarnUnmatchedAllowedTools(domainTools...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +96,7 @@ func Run() error {
|
|||||||
case "http":
|
case "http":
|
||||||
httpServer := server.NewStreamableHTTPServer(
|
httpServer := server.NewStreamableHTTPServer(
|
||||||
mcpServer,
|
mcpServer,
|
||||||
server.WithLogger(log.New()),
|
server.WithLogger(log.Default().Sugar()),
|
||||||
server.WithHeartbeatInterval(30*time.Second),
|
server.WithHeartbeatInterval(30*time.Second),
|
||||||
server.WithHTTPContextFunc(getContextWithToken),
|
server.WithHTTPContextFunc(getContextWithToken),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,8 +2,36 @@ package operation
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"gitea.com/gitea/gitea-mcp/pkg/flag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TestAllToolsHaveDescriptions ensures every registered tool sets a non-empty
|
||||||
|
// Tool.Description. mcp-go only serializes the "description" field of a tool
|
||||||
|
// when it is non-empty, so an omitted description makes strict MCP clients
|
||||||
|
// (e.g. mcp-probe) reject the tools/list response with "missing field
|
||||||
|
// `description`".
|
||||||
|
func TestAllToolsHaveDescriptions(t *testing.T) {
|
||||||
|
origRO, origAllow := flag.ReadOnly, flag.AllowedTools
|
||||||
|
t.Cleanup(func() {
|
||||||
|
flag.ReadOnly, flag.AllowedTools = origRO, origAllow
|
||||||
|
})
|
||||||
|
flag.ReadOnly = false
|
||||||
|
flag.AllowedTools = nil
|
||||||
|
|
||||||
|
var missing []string
|
||||||
|
for _, d := range domainTools {
|
||||||
|
for _, st := range d.Tools() {
|
||||||
|
if st.Tool.Description == "" {
|
||||||
|
missing = append(missing, st.Tool.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(missing) > 0 {
|
||||||
|
t.Errorf("tools missing a description: %v", missing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseAuthToken(t *testing.T) {
|
func TestParseAuthToken(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
||||||
@@ -110,7 +109,6 @@ func escapePackageName(name string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listPackagesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listPackagesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listPackagesFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -138,7 +136,6 @@ func listPackagesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listPackageVersionsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listPackageVersionsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listPackageVersionsFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -168,7 +165,6 @@ func listPackageVersionsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getPackageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getPackageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getPackageFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -197,7 +193,6 @@ func getPackageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deletePackageVersionFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deletePackageVersionFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deletePackageVersionFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+44
-99
@@ -10,10 +10,11 @@ import (
|
|||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
"gitea.com/gitea/gitea-mcp/pkg/log"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
|
"gitea.com/gitea/gitea-mcp/pkg/slim"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -30,6 +31,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
ListRepoPullRequestsTool = mcp.NewTool(
|
ListRepoPullRequestsTool = mcp.NewTool(
|
||||||
ListRepoPullRequestsToolName,
|
ListRepoPullRequestsToolName,
|
||||||
|
mcp.WithDescription("List pull requests in a repository, filterable by state and milestone, with configurable sort order (e.g. recently updated, most commented)."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("List pull requests")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("List pull requests")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -201,7 +203,7 @@ func closePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
}
|
}
|
||||||
|
|
||||||
state := gitea_sdk.StateClosed
|
state := gitea_sdk.StateClosed
|
||||||
pr, _, err := client.EditPullRequest(owner, repo, index, gitea_sdk.EditPullRequestOption{
|
pr, _, err := client.PullRequests.EditPullRequest(ctx, owner, repo, index, gitea_sdk.EditPullRequestOption{
|
||||||
State: &state,
|
State: &state,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -231,7 +233,7 @@ func reopenPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal
|
|||||||
}
|
}
|
||||||
|
|
||||||
state := gitea_sdk.StateOpen
|
state := gitea_sdk.StateOpen
|
||||||
pr, _, err := client.EditPullRequest(owner, repo, index, gitea_sdk.EditPullRequestOption{
|
pr, _, err := client.PullRequests.EditPullRequest(ctx, owner, repo, index, gitea_sdk.EditPullRequestOption{
|
||||||
State: &state,
|
State: &state,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -261,7 +263,6 @@ func pullRequestReviewWriteFn(ctx context.Context, req mcp.CallToolRequest) (*mc
|
|||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -279,7 +280,7 @@ func getPullRequestByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
pr, _, err := client.GetPullRequest(owner, repo, index)
|
pr, _, err := client.PullRequests.GetPullRequest(ctx, owner, repo, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get %v/%v/pr/%v err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("get %v/%v/pr/%v err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -293,12 +294,11 @@ func getPullRequestByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp
|
|||||||
}
|
}
|
||||||
|
|
||||||
m := slimPullRequest(pr)
|
m := slimPullRequest(pr)
|
||||||
m["body"] = bodyWithAttachments(pr.Body, assets)
|
m["body"] = slim.BodyWithAttachments(pr.Body, assets)
|
||||||
return to.TextResult(m)
|
return to.TextResult(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPullRequestDiffFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getPullRequestDiffFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getPullRequestDiffFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -318,7 +318,7 @@ func getPullRequestDiffFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
diffBytes, _, err := client.GetPullRequestDiff(owner, repo, index, gitea_sdk.PullRequestDiffOptions{
|
diffBytes, _, err := client.PullRequests.GetPullRequestDiff(ctx, owner, repo, index, gitea_sdk.PullRequestDiffOptions{
|
||||||
Binary: binary,
|
Binary: binary,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -329,7 +329,6 @@ func getPullRequestDiffFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
|
|||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -356,7 +355,7 @@ func listRepoPullRequestsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
pullRequests, _, err := client.ListRepoPullRequests(owner, repo, opt)
|
pullRequests, _, err := client.PullRequests.ListRepoPullRequests(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("list %v/%v/pull_requests err: %v", owner, repo, err))
|
return to.ErrorResult(fmt.Errorf("list %v/%v/pull_requests err: %v", owner, repo, err))
|
||||||
}
|
}
|
||||||
@@ -387,7 +386,6 @@ func applyDraftPrefix(title string, isDraft bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -432,7 +430,7 @@ func createPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal
|
|||||||
opt.Labels = labelIDs
|
opt.Labels = labelIDs
|
||||||
}
|
}
|
||||||
opt.Deadline = params.GetOptionalTime(args, "deadline")
|
opt.Deadline = params.GetOptionalTime(args, "deadline")
|
||||||
pr, _, err := client.CreatePullRequest(owner, repo, opt)
|
pr, _, err := client.PullRequests.CreatePullRequest(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("create %v/%v/pull_request err: %v", owner, repo, err))
|
return to.ErrorResult(fmt.Errorf("create %v/%v/pull_request err: %v", owner, repo, err))
|
||||||
}
|
}
|
||||||
@@ -440,8 +438,9 @@ func createPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal
|
|||||||
return to.TextResult(slimPullRequest(pr))
|
return to.TextResult(slimPullRequest(pr))
|
||||||
}
|
}
|
||||||
|
|
||||||
func createPullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
type reviewerOp func(client *gitea_sdk.PullRequestsService, ctx context.Context, owner, repo string, index int64, opt gitea_sdk.PullReviewRequestOptions) (*gitea_sdk.Response, error)
|
||||||
log.Debugf("Called createPullRequestReviewerFn")
|
|
||||||
|
func pullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest, verb string, op reviewerOp) (*mcp.CallToolResult, error) {
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -464,70 +463,31 @@ func createPullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) (
|
|||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.CreateReviewRequests(owner, repo, index, gitea_sdk.PullReviewRequestOptions{
|
if _, err := op(client.PullRequests, ctx, owner, repo, index, gitea_sdk.PullReviewRequestOptions{
|
||||||
Reviewers: reviewers,
|
Reviewers: reviewers,
|
||||||
TeamReviewers: teamReviewers,
|
TeamReviewers: teamReviewers,
|
||||||
})
|
}); err != nil {
|
||||||
if err != nil {
|
return to.ErrorResult(fmt.Errorf("%s review requests for %v/%v/pr/%v err: %v", verb, owner, repo, index, err))
|
||||||
return to.ErrorResult(fmt.Errorf("create review requests for %v/%v/pr/%v err: %v", owner, repo, index, err))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
successMsg := map[string]any{
|
return to.TextResult(map[string]any{
|
||||||
"message": "Successfully created review requests",
|
"message": fmt.Sprintf("Successfully %sd review requests", verb),
|
||||||
"reviewers": reviewers,
|
"reviewers": reviewers,
|
||||||
"team_reviewers": teamReviewers,
|
"team_reviewers": teamReviewers,
|
||||||
"pr_index": index,
|
"pr_index": index,
|
||||||
"repository": fmt.Sprintf("%s/%s", owner, repo),
|
"repository": fmt.Sprintf("%s/%s", owner, repo),
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return to.TextResult(successMsg)
|
func createPullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
|
return pullRequestReviewerFn(ctx, req, "create", (*gitea_sdk.PullRequestsService).CreateReviewRequests)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deletePullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deletePullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deletePullRequestReviewerFn")
|
return pullRequestReviewerFn(ctx, req, "delete", (*gitea_sdk.PullRequestsService).DeleteReviewRequests)
|
||||||
args := req.GetArguments()
|
|
||||||
owner, err := params.GetString(args, "owner")
|
|
||||||
if err != nil {
|
|
||||||
return to.ErrorResult(err)
|
|
||||||
}
|
|
||||||
repo, err := params.GetString(args, "repo")
|
|
||||||
if err != nil {
|
|
||||||
return to.ErrorResult(err)
|
|
||||||
}
|
|
||||||
index, err := params.GetIndex(args, "pull_number")
|
|
||||||
if err != nil {
|
|
||||||
return to.ErrorResult(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
reviewers := params.GetStringSlice(args, "reviewers")
|
|
||||||
teamReviewers := params.GetStringSlice(args, "team_reviewers")
|
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = client.DeleteReviewRequests(owner, repo, index, gitea_sdk.PullReviewRequestOptions{
|
|
||||||
Reviewers: reviewers,
|
|
||||||
TeamReviewers: teamReviewers,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return to.ErrorResult(fmt.Errorf("delete review requests for %v/%v/pr/%v err: %v", owner, repo, index, err))
|
|
||||||
}
|
|
||||||
|
|
||||||
successMsg := map[string]any{
|
|
||||||
"message": "Successfully deleted review requests",
|
|
||||||
"reviewers": reviewers,
|
|
||||||
"team_reviewers": teamReviewers,
|
|
||||||
"pr_index": index,
|
|
||||||
"repository": fmt.Sprintf("%s/%s", owner, repo),
|
|
||||||
}
|
|
||||||
|
|
||||||
return to.TextResult(successMsg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func listPullRequestReviewsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listPullRequestReviewsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listPullRequestReviewsFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -548,7 +508,7 @@ func listPullRequestReviewsFn(ctx context.Context, req mcp.CallToolRequest) (*mc
|
|||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
reviews, _, err := client.ListPullReviews(owner, repo, index, gitea_sdk.ListPullReviewsOptions{
|
reviews, _, err := client.PullRequests.ListPullReviews(ctx, owner, repo, index, gitea_sdk.ListPullReviewsOptions{
|
||||||
ListOptions: gitea_sdk.ListOptions{
|
ListOptions: gitea_sdk.ListOptions{
|
||||||
Page: page,
|
Page: page,
|
||||||
PageSize: pageSize,
|
PageSize: pageSize,
|
||||||
@@ -562,7 +522,6 @@ func listPullRequestReviewsFn(ctx context.Context, req mcp.CallToolRequest) (*mc
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getPullRequestReviewFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -586,7 +545,7 @@ func getPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.
|
|||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
review, _, err := client.GetPullReview(owner, repo, index, reviewID)
|
review, _, err := client.PullRequests.GetPullReview(ctx, owner, repo, index, reviewID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get review %v for %v/%v/pr/%v err: %v", reviewID, owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("get review %v for %v/%v/pr/%v err: %v", reviewID, owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -595,7 +554,6 @@ func getPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listPullRequestReviewCommentsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listPullRequestReviewCommentsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listPullRequestReviewCommentsFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -619,7 +577,7 @@ func listPullRequestReviewCommentsFn(ctx context.Context, req mcp.CallToolReques
|
|||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
comments, _, err := client.ListPullReviewComments(owner, repo, index, reviewID)
|
comments, _, err := client.PullRequests.ListPullReviewComments(ctx, owner, repo, index, reviewID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("list review comments for review %v on %v/%v/pr/%v err: %v", reviewID, owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("list review comments for review %v on %v/%v/pr/%v err: %v", reviewID, owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -628,7 +586,6 @@ func listPullRequestReviewCommentsFn(ctx context.Context, req mcp.CallToolReques
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func createPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called createPullRequestReviewFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -684,7 +641,7 @@ func createPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
review, _, err := client.CreatePullReview(owner, repo, index, opt)
|
review, _, err := client.PullRequests.CreatePullReview(ctx, owner, repo, index, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("create review for %v/%v/pr/%v err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("create review for %v/%v/pr/%v err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -693,7 +650,6 @@ func createPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
}
|
}
|
||||||
|
|
||||||
func submitPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func submitPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called submitPullRequestReviewFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -728,7 +684,7 @@ func submitPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
review, _, err := client.SubmitPullReview(owner, repo, index, reviewID, opt)
|
review, _, err := client.PullRequests.SubmitPullReview(ctx, owner, repo, index, reviewID, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("submit review %v for %v/%v/pr/%v err: %v", reviewID, owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("submit review %v for %v/%v/pr/%v err: %v", reviewID, owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -737,7 +693,6 @@ func submitPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deletePullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deletePullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deletePullRequestReviewFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -761,7 +716,7 @@ func deletePullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.DeletePullReview(owner, repo, index, reviewID)
|
_, err = client.PullRequests.DeletePullReview(ctx, owner, repo, index, reviewID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("delete review %v for %v/%v/pr/%v err: %v", reviewID, owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("delete review %v for %v/%v/pr/%v err: %v", reviewID, owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -777,7 +732,6 @@ func deletePullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
}
|
}
|
||||||
|
|
||||||
func dismissPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func dismissPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called dismissPullRequestReviewFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -806,7 +760,7 @@ func dismissPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*
|
|||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.DismissPullReview(owner, repo, index, reviewID, opt)
|
_, err = client.PullRequests.DismissPullReview(ctx, owner, repo, index, reviewID, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("dismiss review %v for %v/%v/pr/%v err: %v", reviewID, owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("dismiss review %v for %v/%v/pr/%v err: %v", reviewID, owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -822,7 +776,6 @@ func dismissPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mergePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func mergePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called mergePullRequestFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -850,18 +803,19 @@ func mergePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
forceMerge, _ := args["force_merge"].(bool)
|
forceMerge, _ := args["force_merge"].(bool)
|
||||||
mergeWhenChecksSucceed, _ := args["merge_when_checks_succeed"].(bool)
|
mergeWhenChecksSucceed, _ := args["merge_when_checks_succeed"].(bool)
|
||||||
headCommitID, _ := args["head_commit_id"].(string)
|
headCommitID, _ := args["head_commit_id"].(string)
|
||||||
|
deleteBranchAfterMerge := &deleteBranch
|
||||||
|
|
||||||
opt := gitea_sdk.MergePullRequestOption{
|
opt := gitea_sdk.MergePullRequestOption{
|
||||||
Style: gitea_sdk.MergeStyle(mergeStyle),
|
Style: gitea_sdk.MergeStyle(mergeStyle),
|
||||||
Title: title,
|
Title: title,
|
||||||
Message: message,
|
Message: message,
|
||||||
DeleteBranchAfterMerge: deleteBranch,
|
DeleteBranchAfterMerge: deleteBranchAfterMerge,
|
||||||
ForceMerge: forceMerge,
|
ForceMerge: forceMerge,
|
||||||
MergeWhenChecksSucceed: mergeWhenChecksSucceed,
|
MergeWhenChecksSucceed: mergeWhenChecksSucceed,
|
||||||
HeadCommitId: headCommitID,
|
HeadCommitId: headCommitID,
|
||||||
}
|
}
|
||||||
|
|
||||||
merged, resp, err := client.MergePullRequest(owner, repo, index, opt)
|
merged, resp, err := client.PullRequests.MergePullRequest(ctx, owner, repo, index, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("merge %v/%v/pr/%v err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("merge %v/%v/pr/%v err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -886,7 +840,6 @@ func mergePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
}
|
}
|
||||||
|
|
||||||
func editPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func editPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called editPullRequestFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -914,7 +867,7 @@ func editPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
pr, _, err := client.GetPullRequest(owner, repo, index)
|
pr, _, err := client.PullRequests.GetPullRequest(ctx, owner, repo, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get %v/%v/pr/%v err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("get %v/%v/pr/%v err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -922,9 +875,10 @@ func editPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
}
|
}
|
||||||
opt.Title = applyDraftPrefix(opt.Title, draft)
|
opt.Title = applyDraftPrefix(opt.Title, draft)
|
||||||
}
|
}
|
||||||
if body, ok := args["body"].(string); ok {
|
opt.Body = params.GetPresentStringPtr(args, "body")
|
||||||
opt.Body = new(body)
|
opt.AllowMaintainerEdit = params.GetOptionalBoolPtr(args, "allow_maintainer_edit")
|
||||||
}
|
opt.RemoveDeadline = params.GetOptionalBoolPtr(args, "remove_deadline")
|
||||||
|
opt.Deadline = params.GetOptionalTime(args, "deadline")
|
||||||
if base, ok := args["base"].(string); ok {
|
if base, ok := args["base"].(string); ok {
|
||||||
opt.Base = base
|
opt.Base = base
|
||||||
}
|
}
|
||||||
@@ -940,25 +894,19 @@ func editPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if state, ok := args["state"].(string); ok {
|
if state, ok := args["state"].(string); ok {
|
||||||
opt.State = new(gitea_sdk.StateType(state))
|
s := gitea_sdk.StateType(state)
|
||||||
}
|
opt.State = &s
|
||||||
if allowMaintainerEdit, ok := args["allow_maintainer_edit"].(bool); ok {
|
|
||||||
opt.AllowMaintainerEdit = new(allowMaintainerEdit)
|
|
||||||
}
|
}
|
||||||
if labelIDs, err := params.GetInt64Slice(args, "labels"); err == nil {
|
if labelIDs, err := params.GetInt64Slice(args, "labels"); err == nil {
|
||||||
opt.Labels = labelIDs
|
opt.Labels = labelIDs
|
||||||
}
|
}
|
||||||
opt.Deadline = params.GetOptionalTime(args, "deadline")
|
|
||||||
if removeDeadline, ok := args["remove_deadline"].(bool); ok {
|
|
||||||
opt.RemoveDeadline = &removeDeadline
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
pr, _, err := client.EditPullRequest(owner, repo, index, opt)
|
pr, _, err := client.PullRequests.EditPullRequest(ctx, owner, repo, index, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("edit %v/%v/pr/%v err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("edit %v/%v/pr/%v err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -967,7 +915,6 @@ func editPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updatePullRequestBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func updatePullRequestBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called updatePullRequestBranchFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -990,7 +937,6 @@ func updatePullRequestBranchFn(ctx context.Context, req mcp.CallToolRequest) (*m
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getPullRequestFilesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getPullRequestFilesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getPullRequestFilesFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1009,7 +955,7 @@ func getPullRequestFilesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.C
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
files, _, err := client.ListPullRequestFiles(owner, repo, index, gitea_sdk.ListPullRequestFilesOptions{
|
files, _, err := client.PullRequests.ListPullRequestFiles(ctx, owner, repo, index, gitea_sdk.ListPullRequestFilesOptions{
|
||||||
ListOptions: gitea_sdk.ListOptions{Page: page, PageSize: pageSize},
|
ListOptions: gitea_sdk.ListOptions{Page: page, PageSize: pageSize},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1019,7 +965,6 @@ func getPullRequestFilesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getPullRequestStatusFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getPullRequestStatusFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getPullRequestStatusFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1037,7 +982,7 @@ func getPullRequestStatusFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
pr, _, err := client.GetPullRequest(owner, repo, index)
|
pr, _, err := client.PullRequests.GetPullRequest(ctx, owner, repo, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get %v/%v/pr/%v err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("get %v/%v/pr/%v err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -1045,7 +990,7 @@ func getPullRequestStatusFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.
|
|||||||
return to.ErrorResult(fmt.Errorf("pr %v/%v/%v has no head SHA", owner, repo, index))
|
return to.ErrorResult(fmt.Errorf("pr %v/%v/%v has no head SHA", owner, repo, index))
|
||||||
}
|
}
|
||||||
|
|
||||||
status, _, err := client.GetCombinedStatus(owner, repo, pr.Head.Sha)
|
status, _, err := client.Repositories.GetCombinedStatus(ctx, owner, repo, pr.Head.Sha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get %v/%v/pr/%v status err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("get %v/%v/pr/%v status err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,6 +158,9 @@ func Test_mergePullRequestFn(t *testing.T) {
|
|||||||
case "/api/v1/version":
|
case "/api/v1/version":
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
_, _ = w.Write([]byte(`{"version":"1.12.0"}`))
|
_, _ = w.Write([]byte(`{"version":"1.12.0"}`))
|
||||||
|
case fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner, repo, index):
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_, _ = w.Write([]byte(`{"head":{"sha":"abc123"}}`))
|
||||||
case fmt.Sprintf("/api/v1/repos/%s/%s", owner, repo):
|
case fmt.Sprintf("/api/v1/repos/%s/%s", owner, repo):
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
_, _ = w.Write([]byte(`{"private":false}`))
|
_, _ = w.Write([]byte(`{"private":false}`))
|
||||||
|
|||||||
+10
-62
@@ -1,63 +1,11 @@
|
|||||||
package pull
|
package pull
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"gitea.com/gitea/gitea-mcp/pkg/slim"
|
||||||
"strings"
|
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func bodyWithAttachments(body string, atts []*gitea_sdk.Attachment) string {
|
|
||||||
links := make([]string, 0, len(atts))
|
|
||||||
for _, a := range atts {
|
|
||||||
if a == nil || a.DownloadURL == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
links = append(links, fmt.Sprintf("[%s](%s)", a.Name, a.DownloadURL))
|
|
||||||
}
|
|
||||||
if len(links) == 0 {
|
|
||||||
return body
|
|
||||||
}
|
|
||||||
joined := strings.Join(links, "\n")
|
|
||||||
if body == "" {
|
|
||||||
return joined
|
|
||||||
}
|
|
||||||
return body + "\n\n" + joined
|
|
||||||
}
|
|
||||||
|
|
||||||
func userLogin(u *gitea_sdk.User) string {
|
|
||||||
if u == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return u.UserName
|
|
||||||
}
|
|
||||||
|
|
||||||
func userLogins(users []*gitea_sdk.User) []string {
|
|
||||||
if len(users) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := make([]string, 0, len(users))
|
|
||||||
for _, u := range users {
|
|
||||||
if u != nil {
|
|
||||||
out = append(out, u.UserName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func labelNames(labels []*gitea_sdk.Label) []string {
|
|
||||||
if len(labels) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := make([]string, 0, len(labels))
|
|
||||||
for _, l := range labels {
|
|
||||||
if l != nil {
|
|
||||||
out = append(out, l.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func repoRef(r *gitea_sdk.Repository) map[string]any {
|
func repoRef(r *gitea_sdk.Repository) map[string]any {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -81,8 +29,8 @@ func slimPullRequest(pr *gitea_sdk.PullRequest) map[string]any {
|
|||||||
"merged": pr.HasMerged,
|
"merged": pr.HasMerged,
|
||||||
"mergeable": pr.Mergeable,
|
"mergeable": pr.Mergeable,
|
||||||
"html_url": pr.HTMLURL,
|
"html_url": pr.HTMLURL,
|
||||||
"user": userLogin(pr.Poster),
|
"user": slim.UserLogin(pr.Poster),
|
||||||
"labels": labelNames(pr.Labels),
|
"labels": slim.LabelNames(pr.Labels),
|
||||||
"comments": pr.Comments,
|
"comments": pr.Comments,
|
||||||
"created_at": pr.Created,
|
"created_at": pr.Created,
|
||||||
"updated_at": pr.Updated,
|
"updated_at": pr.Updated,
|
||||||
@@ -91,7 +39,7 @@ func slimPullRequest(pr *gitea_sdk.PullRequest) map[string]any {
|
|||||||
if pr.HasMerged {
|
if pr.HasMerged {
|
||||||
m["merged_at"] = pr.Merged
|
m["merged_at"] = pr.Merged
|
||||||
m["merge_commit_sha"] = pr.MergedCommitID
|
m["merge_commit_sha"] = pr.MergedCommitID
|
||||||
m["merged_by"] = userLogin(pr.MergedBy)
|
m["merged_by"] = slim.UserLogin(pr.MergedBy)
|
||||||
}
|
}
|
||||||
if pr.Head != nil {
|
if pr.Head != nil {
|
||||||
head := map[string]any{"ref": pr.Head.Ref, "sha": pr.Head.Sha}
|
head := map[string]any{"ref": pr.Head.Ref, "sha": pr.Head.Sha}
|
||||||
@@ -117,7 +65,7 @@ func slimPullRequest(pr *gitea_sdk.PullRequest) map[string]any {
|
|||||||
m["changed_files"] = *pr.ChangedFiles
|
m["changed_files"] = *pr.ChangedFiles
|
||||||
}
|
}
|
||||||
if len(pr.Assignees) > 0 {
|
if len(pr.Assignees) > 0 {
|
||||||
m["assignees"] = userLogins(pr.Assignees)
|
m["assignees"] = slim.UserLogins(pr.Assignees)
|
||||||
}
|
}
|
||||||
if pr.Milestone != nil {
|
if pr.Milestone != nil {
|
||||||
m["milestone"] = pr.Milestone.Title
|
m["milestone"] = pr.Milestone.Title
|
||||||
@@ -141,7 +89,7 @@ func slimPullRequests(prs []*gitea_sdk.PullRequest) []map[string]any {
|
|||||||
"draft": pr.Draft,
|
"draft": pr.Draft,
|
||||||
"merged": pr.HasMerged,
|
"merged": pr.HasMerged,
|
||||||
"html_url": pr.HTMLURL,
|
"html_url": pr.HTMLURL,
|
||||||
"user": userLogin(pr.Poster),
|
"user": slim.UserLogin(pr.Poster),
|
||||||
"created_at": pr.Created,
|
"created_at": pr.Created,
|
||||||
"updated_at": pr.Updated,
|
"updated_at": pr.Updated,
|
||||||
}
|
}
|
||||||
@@ -152,7 +100,7 @@ func slimPullRequests(prs []*gitea_sdk.PullRequest) []map[string]any {
|
|||||||
m["base"] = pr.Base.Ref
|
m["base"] = pr.Base.Ref
|
||||||
}
|
}
|
||||||
if len(pr.Labels) > 0 {
|
if len(pr.Labels) > 0 {
|
||||||
m["labels"] = labelNames(pr.Labels)
|
m["labels"] = slim.LabelNames(pr.Labels)
|
||||||
}
|
}
|
||||||
out = append(out, m)
|
out = append(out, m)
|
||||||
}
|
}
|
||||||
@@ -167,7 +115,7 @@ func slimReview(r *gitea_sdk.PullReview) map[string]any {
|
|||||||
"id": r.ID,
|
"id": r.ID,
|
||||||
"state": r.State,
|
"state": r.State,
|
||||||
"body": r.Body,
|
"body": r.Body,
|
||||||
"user": userLogin(r.Reviewer),
|
"user": slim.UserLogin(r.Reviewer),
|
||||||
"comments_count": r.CodeCommentsCount,
|
"comments_count": r.CodeCommentsCount,
|
||||||
"submitted_at": r.Submitted,
|
"submitted_at": r.Submitted,
|
||||||
"html_url": r.HTMLURL,
|
"html_url": r.HTMLURL,
|
||||||
@@ -196,7 +144,7 @@ func slimReviewComment(c *gitea_sdk.PullReviewComment) map[string]any {
|
|||||||
"position": c.LineNum,
|
"position": c.LineNum,
|
||||||
"old_position": c.OldLineNum,
|
"old_position": c.OldLineNum,
|
||||||
"diff_hunk": c.DiffHunk,
|
"diff_hunk": c.DiffHunk,
|
||||||
"user": userLogin(c.Reviewer),
|
"user": slim.UserLogin(c.Reviewer),
|
||||||
"html_url": c.HTMLURL,
|
"html_url": c.HTMLURL,
|
||||||
"created_at": c.Created,
|
"created_at": c.Created,
|
||||||
"updated_at": c.Updated,
|
"updated_at": c.Updated,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSlimPullRequest(t *testing.T) {
|
func TestSlimPullRequest(t *testing.T) {
|
||||||
|
|||||||
@@ -6,11 +6,10 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -24,6 +23,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
CreateBranchTool = mcp.NewTool(
|
CreateBranchTool = mcp.NewTool(
|
||||||
CreateBranchToolName,
|
CreateBranchToolName,
|
||||||
|
mcp.WithDescription("Create a new branch in a repository, optionally from a specific source branch (defaults to the repository's default branch)."),
|
||||||
mcp.WithToolAnnotation(annotation.Write("Create a new branch")),
|
mcp.WithToolAnnotation(annotation.Write("Create a new branch")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -33,6 +33,7 @@ var (
|
|||||||
|
|
||||||
DeleteBranchTool = mcp.NewTool(
|
DeleteBranchTool = mcp.NewTool(
|
||||||
DeleteBranchToolName,
|
DeleteBranchToolName,
|
||||||
|
mcp.WithDescription("Permanently delete a branch from a repository. This action is destructive and cannot be undone."),
|
||||||
mcp.WithToolAnnotation(annotation.Destructive("Delete a branch")),
|
mcp.WithToolAnnotation(annotation.Destructive("Delete a branch")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -41,6 +42,7 @@ var (
|
|||||||
|
|
||||||
ListBranchesTool = mcp.NewTool(
|
ListBranchesTool = mcp.NewTool(
|
||||||
ListBranchesToolName,
|
ListBranchesToolName,
|
||||||
|
mcp.WithDescription("List all branches in a repository, paginated."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("List repository branches")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("List repository branches")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -65,7 +67,6 @@ 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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -85,7 +86,7 @@ func CreateBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, _, err = client.CreateBranch(owner, repo, gitea_sdk.CreateBranchOption{
|
_, _, err = client.Repositories.CreateBranch(ctx, owner, repo, gitea_sdk.CreateBranchOption{
|
||||||
BranchName: branch,
|
BranchName: branch,
|
||||||
OldBranchName: oldBranch,
|
OldBranchName: oldBranch,
|
||||||
})
|
})
|
||||||
@@ -93,11 +94,10 @@ func CreateBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
|
|||||||
return to.ErrorResult(fmt.Errorf("create branch error: %v", err))
|
return to.ErrorResult(fmt.Errorf("create branch error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return mcp.NewToolResultText("Branch Created"), nil
|
return to.TextResult("Branch Created")
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -115,7 +115,7 @@ func DeleteBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, _, err = client.DeleteRepoBranch(owner, repo, branch)
|
_, _, err = client.Repositories.DeleteRepoBranch(ctx, owner, repo, branch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("delete branch error: %v", err))
|
return to.ErrorResult(fmt.Errorf("delete branch error: %v", err))
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,6 @@ 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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -145,7 +144,7 @@ func ListBranchesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
branches, _, err := client.ListRepoBranches(owner, repo, opt)
|
branches, _, err := client.Repositories.ListRepoBranches(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("list branches error: %v", err))
|
return to.ErrorResult(fmt.Errorf("list branches error: %v", err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,10 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -23,6 +22,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
ListRepoCommitsTool = mcp.NewTool(
|
ListRepoCommitsTool = mcp.NewTool(
|
||||||
ListRepoCommitsToolName,
|
ListRepoCommitsToolName,
|
||||||
|
mcp.WithDescription("List commits in a repository, optionally starting from a specific branch or SHA and filtered to commits touching a given file path."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("List repository commits")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("List repository commits")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -34,6 +34,7 @@ var (
|
|||||||
|
|
||||||
GetCommitTool = mcp.NewTool(
|
GetCommitTool = mcp.NewTool(
|
||||||
GetCommitToolName,
|
GetCommitToolName,
|
||||||
|
mcp.WithDescription("Get details for a single commit in a repository by its SHA."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("Get commit details")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("Get commit details")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -53,7 +54,6 @@ 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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -78,7 +78,7 @@ func ListRepoCommitsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
commits, _, err := client.ListRepoCommits(owner, repo, opt)
|
commits, _, err := client.Repositories.ListRepoCommits(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("list repo commits err: %v", err))
|
return to.ErrorResult(fmt.Errorf("list repo commits err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,6 @@ func ListRepoCommitsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetCommitFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func GetCommitFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called GetCommitFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,7 +103,7 @@ func GetCommitFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
commit, _, err := client.GetSingleCommit(owner, repo, sha)
|
commit, _, err := client.Repositories.GetSingleCommit(ctx, owner, repo, sha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get commit %v err: %v", sha, err))
|
return to.ErrorResult(fmt.Errorf("get commit %v err: %v", sha, err))
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-11
@@ -10,11 +10,10 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -40,6 +39,7 @@ var (
|
|||||||
|
|
||||||
GetDirContentTool = mcp.NewTool(
|
GetDirContentTool = mcp.NewTool(
|
||||||
GetDirToolName,
|
GetDirToolName,
|
||||||
|
mcp.WithDescription("List the entries (files and subdirectories) in a repository directory at a given ref (branch, tag, or commit SHA)."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("Get directory contents")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("Get directory contents")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -63,6 +63,7 @@ var (
|
|||||||
|
|
||||||
DeleteFileTool = mcp.NewTool(
|
DeleteFileTool = mcp.NewTool(
|
||||||
DeleteFileToolName,
|
DeleteFileToolName,
|
||||||
|
mcp.WithDescription("Delete a file from a repository by committing the removal to a branch. Requires the file's current SHA and a commit message."),
|
||||||
mcp.WithToolAnnotation(annotation.Destructive("Delete a file")),
|
mcp.WithToolAnnotation(annotation.Destructive("Delete a file")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -98,7 +99,6 @@ type ContentLine struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -117,7 +117,7 @@ func GetFileContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
content, _, err := client.GetContents(owner, repo, ref, filePath)
|
content, _, err := client.Repositories.GetContents(ctx, owner, repo, ref, filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get file err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get file err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -162,7 +162,6 @@ func GetFileContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetDirContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func GetDirContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called GetDirContentFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -181,7 +180,7 @@ func GetDirContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
content, _, err := client.ListContents(owner, repo, ref, filePath)
|
content, _, err := client.Repositories.ListContents(ctx, owner, repo, ref, filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get dir content err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get dir content err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -189,7 +188,6 @@ func GetDirContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateOrUpdateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func CreateOrUpdateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called CreateOrUpdateFileFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -223,7 +221,7 @@ func CreateOrUpdateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
|
|||||||
BranchName: branchName,
|
BranchName: branchName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, _, err = client.UpdateFile(owner, repo, filePath, opt)
|
_, _, err = client.Repositories.UpdateFile(ctx, owner, repo, filePath, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("update file err: %v", err))
|
return to.ErrorResult(fmt.Errorf("update file err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -241,7 +239,7 @@ func CreateOrUpdateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
|
|||||||
if newBranch, ok := args["new_branch_name"].(string); ok && newBranch != "" {
|
if newBranch, ok := args["new_branch_name"].(string); ok && newBranch != "" {
|
||||||
opt.NewBranchName = newBranch
|
opt.NewBranchName = newBranch
|
||||||
}
|
}
|
||||||
_, _, err = client.CreateFile(owner, repo, filePath, opt)
|
_, _, err = client.Repositories.CreateFile(ctx, owner, repo, filePath, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("create file err: %v", err))
|
return to.ErrorResult(fmt.Errorf("create file err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -249,7 +247,6 @@ func CreateOrUpdateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
|
|||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -280,7 +277,7 @@ func DeleteFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, err = client.DeleteFile(owner, repo, filePath, opt)
|
_, err = client.Repositories.DeleteFile(ctx, owner, repo, filePath, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("delete file err: %v", err))
|
return to.ErrorResult(fmt.Errorf("delete file err: %v", err))
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-34
@@ -6,11 +6,10 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -26,6 +25,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
CreateReleaseTool = mcp.NewTool(
|
CreateReleaseTool = mcp.NewTool(
|
||||||
CreateReleaseToolName,
|
CreateReleaseToolName,
|
||||||
|
mcp.WithDescription("Create a new release in a repository from a tag, optionally marking it as a draft or pre-release."),
|
||||||
mcp.WithToolAnnotation(annotation.Write("Create a release")),
|
mcp.WithToolAnnotation(annotation.Write("Create a release")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -39,6 +39,7 @@ var (
|
|||||||
|
|
||||||
DeleteReleaseTool = mcp.NewTool(
|
DeleteReleaseTool = mcp.NewTool(
|
||||||
DeleteReleaseToolName,
|
DeleteReleaseToolName,
|
||||||
|
mcp.WithDescription("Delete a release from a repository by its numeric ID. This action is destructive and cannot be undone."),
|
||||||
mcp.WithToolAnnotation(annotation.Destructive("Delete a release")),
|
mcp.WithToolAnnotation(annotation.Destructive("Delete a release")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -56,6 +57,7 @@ var (
|
|||||||
|
|
||||||
GetLatestReleaseTool = mcp.NewTool(
|
GetLatestReleaseTool = mcp.NewTool(
|
||||||
GetLatestReleaseToolName,
|
GetLatestReleaseToolName,
|
||||||
|
mcp.WithDescription("Get the most recent published (non-draft) release in a repository."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("Get latest release")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("Get latest release")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -63,6 +65,7 @@ var (
|
|||||||
|
|
||||||
ListReleasesTool = mcp.NewTool(
|
ListReleasesTool = mcp.NewTool(
|
||||||
ListReleasesToolName,
|
ListReleasesToolName,
|
||||||
|
mcp.WithDescription("List releases in a repository, optionally filtered to drafts or pre-releases."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("List releases")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("List releases")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -97,7 +100,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -127,7 +129,7 @@ func CreateReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, _, err = client.CreateRelease(owner, repo, gitea_sdk.CreateReleaseOption{
|
_, _, err = client.Releases.CreateRelease(ctx, owner, repo, gitea_sdk.CreateReleaseOption{
|
||||||
TagName: tagName,
|
TagName: tagName,
|
||||||
Target: target,
|
Target: target,
|
||||||
Title: title,
|
Title: title,
|
||||||
@@ -136,14 +138,13 @@ func CreateReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
IsPrerelease: isPreRelease,
|
IsPrerelease: isPreRelease,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("create release error: %v", err)
|
return to.ErrorResult(fmt.Errorf("create release error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return mcp.NewToolResultText("Release Created"), nil
|
return to.TextResult("Release Created")
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -162,16 +163,15 @@ func DeleteReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, err = client.DeleteRelease(owner, repo, id)
|
_, err = client.Releases.DeleteRelease(ctx, owner, repo, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("delete release error: %v", err)
|
return to.ErrorResult(fmt.Errorf("delete release error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return to.TextResult("Release deleted successfully")
|
return to.TextResult("Release deleted successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -190,16 +190,15 @@ func GetReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
release, _, err := client.GetRelease(owner, repo, id)
|
release, _, err := client.Releases.GetRelease(ctx, owner, repo, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get release error: %v", err)
|
return to.ErrorResult(fmt.Errorf("get release error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return to.TextResult(slimRelease(release))
|
return to.TextResult(slimRelease(release))
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -214,16 +213,15 @@ func GetLatestReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
release, _, err := client.GetLatestRelease(owner, repo)
|
release, _, err := client.Releases.GetLatestRelease(ctx, owner, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get latest release error: %v", err)
|
return to.ErrorResult(fmt.Errorf("get latest release error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return to.TextResult(slimRelease(release))
|
return to.TextResult(slimRelease(release))
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -233,33 +231,22 @@ func ListReleasesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
var pIsDraft *bool
|
page, pageSize := params.GetPagination(args, 20)
|
||||||
isDraft, ok := args["is_draft"].(bool)
|
|
||||||
if ok {
|
|
||||||
pIsDraft = new(isDraft)
|
|
||||||
}
|
|
||||||
var pIsPreRelease *bool
|
|
||||||
isPreRelease, ok := args["is_pre_release"].(bool)
|
|
||||||
if ok {
|
|
||||||
pIsPreRelease = new(isPreRelease)
|
|
||||||
}
|
|
||||||
page := params.GetOptionalInt(args, "page", 1)
|
|
||||||
pageSize := params.GetOptionalInt(args, "per_page", 20)
|
|
||||||
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
releases, _, err := client.ListReleases(owner, repo, gitea_sdk.ListReleasesOptions{
|
releases, _, err := client.Releases.ListReleases(ctx, owner, repo, gitea_sdk.ListReleasesOptions{
|
||||||
ListOptions: gitea_sdk.ListOptions{
|
ListOptions: gitea_sdk.ListOptions{
|
||||||
Page: int(page),
|
Page: page,
|
||||||
PageSize: int(pageSize),
|
PageSize: pageSize,
|
||||||
},
|
},
|
||||||
IsDraft: pIsDraft,
|
IsDraft: params.GetOptionalBoolPtr(args, "is_draft"),
|
||||||
IsPreRelease: pIsPreRelease,
|
IsPreRelease: params.GetOptionalBoolPtr(args, "is_pre_release"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("list releases error: %v", err)
|
return to.ErrorResult(fmt.Errorf("list releases error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return to.TextResult(slimReleases(releases))
|
return to.TextResult(slimReleases(releases))
|
||||||
|
|||||||
+18
-29
@@ -2,17 +2,16 @@ package repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
|
"gitea.com/gitea/gitea-mcp/pkg/slim"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -29,6 +28,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
CreateRepoTool = mcp.NewTool(
|
CreateRepoTool = mcp.NewTool(
|
||||||
CreateRepoToolName,
|
CreateRepoToolName,
|
||||||
|
mcp.WithDescription("Create a new Git repository, optionally under an organization (defaults to the authenticated user's account), with options for visibility, template, license, .gitignore, and initial README."),
|
||||||
mcp.WithToolAnnotation(annotation.Write("Create a new repository")),
|
mcp.WithToolAnnotation(annotation.Write("Create a new repository")),
|
||||||
mcp.WithString("name", mcp.Required()),
|
mcp.WithString("name", mcp.Required()),
|
||||||
mcp.WithString("description"),
|
mcp.WithString("description"),
|
||||||
@@ -47,6 +47,7 @@ var (
|
|||||||
|
|
||||||
ForkRepoTool = mcp.NewTool(
|
ForkRepoTool = mcp.NewTool(
|
||||||
ForkRepoToolName,
|
ForkRepoToolName,
|
||||||
|
mcp.WithDescription("Fork an existing repository into the authenticated user's account or a target organization, optionally under a new name."),
|
||||||
mcp.WithToolAnnotation(annotation.Write("Fork a repository")),
|
mcp.WithToolAnnotation(annotation.Write("Fork a repository")),
|
||||||
mcp.WithString("user", mcp.Required(), mcp.Description("owner of source repo")),
|
mcp.WithString("user", mcp.Required(), mcp.Description("owner of source repo")),
|
||||||
mcp.WithString("repo", mcp.Required()),
|
mcp.WithString("repo", mcp.Required()),
|
||||||
@@ -56,6 +57,7 @@ var (
|
|||||||
|
|
||||||
ListMyReposTool = mcp.NewTool(
|
ListMyReposTool = mcp.NewTool(
|
||||||
ListMyReposToolName,
|
ListMyReposToolName,
|
||||||
|
mcp.WithDescription("List repositories owned by the authenticated user."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("List my repositories")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("List my repositories")),
|
||||||
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1), mcp.Min(1)),
|
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1), mcp.Min(1)),
|
||||||
mcp.WithNumber("per_page", mcp.Description(params.PaginationDesc), mcp.DefaultNumber(30), mcp.Min(1)),
|
mcp.WithNumber("per_page", mcp.Description(params.PaginationDesc), mcp.DefaultNumber(30), mcp.Min(1)),
|
||||||
@@ -63,6 +65,7 @@ var (
|
|||||||
|
|
||||||
ListOrgReposTool = mcp.NewTool(
|
ListOrgReposTool = mcp.NewTool(
|
||||||
ListOrgReposToolName,
|
ListOrgReposToolName,
|
||||||
|
mcp.WithDescription("List repositories belonging to an organization."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("List organization repositories")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("List organization repositories")),
|
||||||
mcp.WithString("org", mcp.Required()),
|
mcp.WithString("org", mcp.Required()),
|
||||||
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1), mcp.Min(1)),
|
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1), mcp.Min(1)),
|
||||||
@@ -90,7 +93,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
name, err := params.GetString(args, "name")
|
name, err := params.GetString(args, "name")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -130,21 +132,20 @@ func CreateRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
|
|||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
if organization != "" {
|
if organization != "" {
|
||||||
repo, _, err = client.CreateOrgRepo(organization, opt)
|
repo, _, err = client.Repositories.CreateOrgRepo(ctx, organization, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("create organization repository '%s' in '%s' err: %v", name, organization, err))
|
return to.ErrorResult(fmt.Errorf("create organization repository '%s' in '%s' err: %v", name, organization, err))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
repo, _, err = client.CreateRepo(opt)
|
repo, _, err = client.Repositories.CreateRepo(ctx, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("create repository '%s' err: %v", name, err))
|
return to.ErrorResult(fmt.Errorf("create repository '%s' err: %v", name, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return to.TextResult(slimRepo(repo))
|
return to.TextResult(slim.Repo(repo))
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
user, err := params.GetString(args, "user")
|
user, err := params.GetString(args, "user")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -154,25 +155,15 @@ func ForkRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResu
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
organization, ok := args["organization"].(string)
|
|
||||||
organizationPtr := new(organization)
|
|
||||||
if !ok || organization == "" {
|
|
||||||
organizationPtr = nil
|
|
||||||
}
|
|
||||||
name, ok := args["name"].(string)
|
|
||||||
namePtr := new(name)
|
|
||||||
if !ok || name == "" {
|
|
||||||
namePtr = nil
|
|
||||||
}
|
|
||||||
opt := gitea_sdk.CreateForkOption{
|
opt := gitea_sdk.CreateForkOption{
|
||||||
Organization: organizationPtr,
|
Organization: params.GetOptionalStringPtr(args, "organization"),
|
||||||
Name: namePtr,
|
Name: params.GetOptionalStringPtr(args, "name"),
|
||||||
}
|
}
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, _, err = client.CreateFork(user, repo, opt)
|
_, _, err = client.Repositories.CreateFork(ctx, user, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("fork repository error: %v", err))
|
return to.ErrorResult(fmt.Errorf("fork repository error: %v", err))
|
||||||
}
|
}
|
||||||
@@ -180,7 +171,6 @@ 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")
|
|
||||||
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
||||||
opt := gitea_sdk.ListReposOptions{
|
opt := gitea_sdk.ListReposOptions{
|
||||||
ListOptions: gitea_sdk.ListOptions{
|
ListOptions: gitea_sdk.ListOptions{
|
||||||
@@ -192,19 +182,18 @@ func ListMyReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
repos, _, err := client.ListMyRepos(opt)
|
repos, _, err := client.Repositories.ListMyRepos(ctx, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("list my repositories error: %v", err))
|
return to.ErrorResult(fmt.Errorf("list my repositories error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return to.TextResult(slimRepos(repos))
|
return to.TextResult(slim.Repos(repos))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListOrgReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func ListOrgReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called ListOrgReposFn")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
org, ok := req.GetArguments()["org"].(string)
|
if err != nil {
|
||||||
if !ok {
|
return to.ErrorResult(err)
|
||||||
return to.ErrorResult(errors.New("organization name is required"))
|
|
||||||
}
|
}
|
||||||
page, pageSize := params.GetPagination(req.GetArguments(), 100)
|
page, pageSize := params.GetPagination(req.GetArguments(), 100)
|
||||||
opt := gitea_sdk.ListOrgReposOptions{
|
opt := gitea_sdk.ListOrgReposOptions{
|
||||||
@@ -217,7 +206,7 @@ func ListOrgReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
repos, _, err := client.ListOrgRepos(org, opt)
|
repos, _, err := client.Repositories.ListOrgRepos(ctx, org, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("list organization '%s' repositories error: %v", org, err))
|
return to.ErrorResult(fmt.Errorf("list organization '%s' repositories error: %v", org, err))
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-49
@@ -1,56 +1,11 @@
|
|||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/slim"
|
||||||
|
|
||||||
|
gitea_sdk "gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func userLogin(u *gitea_sdk.User) string {
|
|
||||||
if u == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return u.UserName
|
|
||||||
}
|
|
||||||
|
|
||||||
func slimRepo(r *gitea_sdk.Repository) map[string]any {
|
|
||||||
if r == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
m := map[string]any{
|
|
||||||
"id": r.ID,
|
|
||||||
"full_name": r.FullName,
|
|
||||||
"description": r.Description,
|
|
||||||
"html_url": r.HTMLURL,
|
|
||||||
"clone_url": r.CloneURL,
|
|
||||||
"ssh_url": r.SSHURL,
|
|
||||||
"default_branch": r.DefaultBranch,
|
|
||||||
"private": r.Private,
|
|
||||||
"fork": r.Fork,
|
|
||||||
"archived": r.Archived,
|
|
||||||
"language": r.Language,
|
|
||||||
"stars_count": r.Stars,
|
|
||||||
"forks_count": r.Forks,
|
|
||||||
"open_issues_count": r.OpenIssues,
|
|
||||||
"open_pr_counter": r.OpenPulls,
|
|
||||||
"created_at": r.Created,
|
|
||||||
"updated_at": r.Updated,
|
|
||||||
}
|
|
||||||
if r.Owner != nil {
|
|
||||||
m["owner"] = r.Owner.UserName
|
|
||||||
}
|
|
||||||
if len(r.Topics) > 0 {
|
|
||||||
m["topics"] = r.Topics
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func slimRepos(repos []*gitea_sdk.Repository) []map[string]any {
|
|
||||||
out := make([]map[string]any, 0, len(repos))
|
|
||||||
for _, r := range repos {
|
|
||||||
out = append(out, slimRepo(r))
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func slimBranch(b *gitea_sdk.Branch) map[string]any {
|
func slimBranch(b *gitea_sdk.Branch) map[string]any {
|
||||||
if b == nil {
|
if b == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -144,7 +99,7 @@ func slimRelease(r *gitea_sdk.Release) map[string]any {
|
|||||||
"draft": r.IsDraft,
|
"draft": r.IsDraft,
|
||||||
"prerelease": r.IsPrerelease,
|
"prerelease": r.IsPrerelease,
|
||||||
"html_url": r.HTMLURL,
|
"html_url": r.HTMLURL,
|
||||||
"author": userLogin(r.Publisher),
|
"author": slim.UserLogin(r.Publisher),
|
||||||
"created_at": r.CreatedAt,
|
"created_at": r.CreatedAt,
|
||||||
"published_at": r.PublishedAt,
|
"published_at": r.PublishedAt,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,42 +3,9 @@ package repo
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSlimRepo(t *testing.T) {
|
|
||||||
r := &gitea_sdk.Repository{
|
|
||||||
ID: 1,
|
|
||||||
FullName: "org/repo",
|
|
||||||
Description: "A test repo",
|
|
||||||
HTMLURL: "https://gitea.com/org/repo",
|
|
||||||
CloneURL: "https://gitea.com/org/repo.git",
|
|
||||||
SSHURL: "git@gitea.com:org/repo.git",
|
|
||||||
DefaultBranch: "main",
|
|
||||||
Private: false,
|
|
||||||
Fork: false,
|
|
||||||
Archived: false,
|
|
||||||
Language: "Go",
|
|
||||||
Stars: 10,
|
|
||||||
Forks: 2,
|
|
||||||
Owner: &gitea_sdk.User{UserName: "org"},
|
|
||||||
Topics: []string{"mcp", "gitea"},
|
|
||||||
}
|
|
||||||
|
|
||||||
m := slimRepo(r)
|
|
||||||
|
|
||||||
if m["full_name"] != "org/repo" {
|
|
||||||
t.Errorf("expected full_name org/repo, got %v", m["full_name"])
|
|
||||||
}
|
|
||||||
if m["owner"] != "org" {
|
|
||||||
t.Errorf("expected owner org, got %v", m["owner"])
|
|
||||||
}
|
|
||||||
topics := m["topics"].([]string)
|
|
||||||
if len(topics) != 2 {
|
|
||||||
t.Errorf("expected 2 topics, got %d", len(topics))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSlimTag(t *testing.T) {
|
func TestSlimTag(t *testing.T) {
|
||||||
tag := &gitea_sdk.Tag{
|
tag := &gitea_sdk.Tag{
|
||||||
Name: "v1.0.0",
|
Name: "v1.0.0",
|
||||||
|
|||||||
+14
-15
@@ -6,11 +6,10 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -25,6 +24,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
CreateTagTool = mcp.NewTool(
|
CreateTagTool = mcp.NewTool(
|
||||||
CreateTagToolName,
|
CreateTagToolName,
|
||||||
|
mcp.WithDescription("Create a new Git tag in a repository at a target commit, branch, or existing tag, with an optional annotation message."),
|
||||||
mcp.WithToolAnnotation(annotation.Write("Create a tag")),
|
mcp.WithToolAnnotation(annotation.Write("Create a tag")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -35,6 +35,7 @@ var (
|
|||||||
|
|
||||||
DeleteTagTool = mcp.NewTool(
|
DeleteTagTool = mcp.NewTool(
|
||||||
DeleteTagToolName,
|
DeleteTagToolName,
|
||||||
|
mcp.WithDescription("Permanently delete a tag from a repository. This action is destructive and cannot be undone."),
|
||||||
mcp.WithToolAnnotation(annotation.Destructive("Delete a tag")),
|
mcp.WithToolAnnotation(annotation.Destructive("Delete a tag")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -43,6 +44,7 @@ var (
|
|||||||
|
|
||||||
GetTagTool = mcp.NewTool(
|
GetTagTool = mcp.NewTool(
|
||||||
GetTagToolName,
|
GetTagToolName,
|
||||||
|
mcp.WithDescription("Get details for a single tag in a repository by name."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("Get tag details")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("Get tag details")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -51,6 +53,7 @@ var (
|
|||||||
|
|
||||||
ListTagsTool = mcp.NewTool(
|
ListTagsTool = mcp.NewTool(
|
||||||
ListTagsToolName,
|
ListTagsToolName,
|
||||||
|
mcp.WithDescription("List all tags in a repository, paginated."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("List tags")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("List tags")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -79,7 +82,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -100,20 +102,19 @@ func CreateTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, _, err = client.CreateTag(owner, repo, gitea_sdk.CreateTagOption{
|
_, _, err = client.Repositories.CreateTag(ctx, owner, repo, gitea_sdk.CreateTagOption{
|
||||||
TagName: tagName,
|
TagName: tagName,
|
||||||
Target: target,
|
Target: target,
|
||||||
Message: message,
|
Message: message,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("create tag error: %v", err)
|
return to.ErrorResult(fmt.Errorf("create tag error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return mcp.NewToolResultText("Tag Created"), nil
|
return to.TextResult("Tag Created")
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -132,16 +133,15 @@ func DeleteTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, err = client.DeleteTag(owner, repo, tagName)
|
_, err = client.Repositories.DeleteTag(ctx, owner, repo, tagName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("delete tag error: %v", err)
|
return to.ErrorResult(fmt.Errorf("delete tag error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return to.TextResult("Tag deleted")
|
return to.TextResult("Tag deleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -160,16 +160,15 @@ func GetTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
tag, _, err := client.GetTag(owner, repo, tagName)
|
tag, _, err := client.Repositories.GetTag(ctx, owner, repo, tagName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get tag error: %v", err)
|
return to.ErrorResult(fmt.Errorf("get tag error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return to.TextResult(slimTag(tag))
|
return to.TextResult(slimTag(tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -186,14 +185,14 @@ func ListTagsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResu
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
tags, _, err := client.ListRepoTags(owner, repo, gitea_sdk.ListRepoTagsOptions{
|
tags, _, err := client.Repositories.ListRepoTags(ctx, owner, repo, gitea_sdk.ListRepoTagsOptions{
|
||||||
ListOptions: gitea_sdk.ListOptions{
|
ListOptions: gitea_sdk.ListOptions{
|
||||||
Page: int(page),
|
Page: int(page),
|
||||||
PageSize: int(pageSize),
|
PageSize: int(pageSize),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("list tags error: %v", err)
|
return to.ErrorResult(fmt.Errorf("list tags error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return to.TextResult(slimTags(tags))
|
return to.TextResult(slimTags(tags))
|
||||||
|
|||||||
@@ -6,11 +6,10 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -21,6 +20,7 @@ const (
|
|||||||
|
|
||||||
var GetRepoTreeTool = mcp.NewTool(
|
var GetRepoTreeTool = mcp.NewTool(
|
||||||
GetRepoTreeToolName,
|
GetRepoTreeToolName,
|
||||||
|
mcp.WithDescription("Get the file tree of a repository at a given ref (SHA, branch, or tag), optionally recursively."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("Get repository file tree")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("Get repository file tree")),
|
||||||
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
|
||||||
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
|
||||||
@@ -38,7 +38,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetRepoTreeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func GetRepoTreeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called GetRepoTreeFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -67,7 +66,7 @@ func GetRepoTreeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
tree, _, err := client.GetTrees(owner, repo, opt)
|
tree, _, err := client.Git.GetTrees(ctx, owner, repo, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get repository tree err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get repository tree err: %v", err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSlimTree(t *testing.T) {
|
func TestSlimTree(t *testing.T) {
|
||||||
|
|||||||
+19
-30
@@ -7,12 +7,12 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
|
"gitea.com/gitea/gitea-mcp/pkg/slim"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -29,6 +29,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
SearchUsersTool = mcp.NewTool(
|
SearchUsersTool = mcp.NewTool(
|
||||||
SearchUsersToolName,
|
SearchUsersToolName,
|
||||||
|
mcp.WithDescription("Search for Gitea users by username or full name."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("Search users")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("Search users")),
|
||||||
mcp.WithString("query", mcp.Required()),
|
mcp.WithString("query", mcp.Required()),
|
||||||
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1)),
|
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1)),
|
||||||
@@ -37,6 +38,7 @@ var (
|
|||||||
|
|
||||||
SearOrgTeamsTool = mcp.NewTool(
|
SearOrgTeamsTool = mcp.NewTool(
|
||||||
SearchOrgTeamsToolName,
|
SearchOrgTeamsToolName,
|
||||||
|
mcp.WithDescription("Search for teams within an organization by name, optionally including each team's description in the results."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("Search organization teams")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("Search organization teams")),
|
||||||
mcp.WithString("org", mcp.Required()),
|
mcp.WithString("org", mcp.Required()),
|
||||||
mcp.WithString("query", mcp.Required()),
|
mcp.WithString("query", mcp.Required()),
|
||||||
@@ -47,6 +49,7 @@ var (
|
|||||||
|
|
||||||
SearchReposTool = mcp.NewTool(
|
SearchReposTool = mcp.NewTool(
|
||||||
SearchReposToolName,
|
SearchReposToolName,
|
||||||
|
mcp.WithDescription("Search for repositories by keyword, with filters for topic/description matching, owner, visibility, archived status, and sort order."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("Search repositories")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("Search repositories")),
|
||||||
mcp.WithString("query", mcp.Required()),
|
mcp.WithString("query", mcp.Required()),
|
||||||
mcp.WithBoolean("keywordIsTopic"),
|
mcp.WithBoolean("keywordIsTopic"),
|
||||||
@@ -94,7 +97,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func UsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called UsersFn")
|
|
||||||
keyword, err := params.GetString(req.GetArguments(), "query")
|
keyword, err := params.GetString(req.GetArguments(), "query")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -111,7 +113,7 @@ func UsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
users, _, err := client.SearchUsers(opt)
|
users, _, err := client.Users.SearchUsers(ctx, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("search users err: %v", err))
|
return to.ErrorResult(fmt.Errorf("search users err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -119,7 +121,6 @@ func UsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func OrgTeamsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func OrgTeamsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called OrgTeamsFn")
|
|
||||||
org, err := params.GetString(req.GetArguments(), "org")
|
org, err := params.GetString(req.GetArguments(), "org")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -142,7 +143,7 @@ func OrgTeamsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResu
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
teams, _, err := client.SearchOrgTeams(org, &opt)
|
teams, _, err := client.Organizations.SearchOrgTeams(ctx, org, &opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("search organization teams error: %v", err))
|
return to.ErrorResult(fmt.Errorf("search organization teams error: %v", err))
|
||||||
}
|
}
|
||||||
@@ -150,34 +151,23 @@ func OrgTeamsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResu
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func ReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called ReposFn")
|
|
||||||
keyword, err := params.GetString(req.GetArguments(), "query")
|
keyword, err := params.GetString(req.GetArguments(), "query")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
}
|
}
|
||||||
keywordIsTopic, _ := req.GetArguments()["keywordIsTopic"].(bool)
|
args := req.GetArguments()
|
||||||
keywordInDescription, _ := req.GetArguments()["keywordInDescription"].(bool)
|
keywordIsTopic, _ := args["keywordIsTopic"].(bool)
|
||||||
ownerID := params.GetOptionalInt(req.GetArguments(), "ownerID", 0)
|
keywordInDescription, _ := args["keywordInDescription"].(bool)
|
||||||
var pIsPrivate *bool
|
sort, _ := args["sort"].(string)
|
||||||
isPrivate, ok := req.GetArguments()["isPrivate"].(bool)
|
order, _ := args["order"].(string)
|
||||||
if ok {
|
page, pageSize := params.GetPagination(args, 30)
|
||||||
pIsPrivate = new(isPrivate)
|
|
||||||
}
|
|
||||||
var pIsArchived *bool
|
|
||||||
isArchived, ok := req.GetArguments()["isArchived"].(bool)
|
|
||||||
if ok {
|
|
||||||
pIsArchived = new(isArchived)
|
|
||||||
}
|
|
||||||
sort, _ := req.GetArguments()["sort"].(string)
|
|
||||||
order, _ := req.GetArguments()["order"].(string)
|
|
||||||
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
|
||||||
opt := gitea_sdk.SearchRepoOptions{
|
opt := gitea_sdk.SearchRepoOptions{
|
||||||
Keyword: keyword,
|
Keyword: keyword,
|
||||||
KeywordIsTopic: keywordIsTopic,
|
KeywordIsTopic: keywordIsTopic,
|
||||||
KeywordInDescription: keywordInDescription,
|
KeywordInDescription: keywordInDescription,
|
||||||
OwnerID: ownerID,
|
OwnerID: params.GetOptionalInt(args, "ownerID", 0),
|
||||||
IsPrivate: pIsPrivate,
|
IsPrivate: params.GetOptionalBoolPtr(args, "isPrivate"),
|
||||||
IsArchived: pIsArchived,
|
IsArchived: params.GetOptionalBoolPtr(args, "isArchived"),
|
||||||
Sort: sort,
|
Sort: sort,
|
||||||
Order: order,
|
Order: order,
|
||||||
ListOptions: gitea_sdk.ListOptions{
|
ListOptions: gitea_sdk.ListOptions{
|
||||||
@@ -189,15 +179,14 @@ func ReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
repos, _, err := client.SearchRepos(opt)
|
repos, _, err := client.Repositories.SearchRepos(ctx, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("search repos error: %v", err))
|
return to.ErrorResult(fmt.Errorf("search repos error: %v", err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimRepos(repos))
|
return to.TextResult(slim.Repos(repos))
|
||||||
}
|
}
|
||||||
|
|
||||||
func IssuesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func IssuesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called IssuesFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
query, err := params.GetString(args, "query")
|
query, err := params.GetString(args, "query")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -228,7 +217,7 @@ func IssuesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
issues, _, err := client.ListIssues(opt)
|
issues, _, err := client.Issues.ListIssues(ctx, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("search issues err: %v", err))
|
return to.ErrorResult(fmt.Errorf("search issues err: %v", err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,15 @@
|
|||||||
package search
|
package search
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/slim"
|
||||||
)
|
|
||||||
|
|
||||||
func slimUserDetail(u *gitea_sdk.User) map[string]any {
|
gitea_sdk "gitea.dev/sdk"
|
||||||
if u == nil {
|
)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return map[string]any{
|
|
||||||
"id": u.ID,
|
|
||||||
"login": u.UserName,
|
|
||||||
"full_name": u.FullName,
|
|
||||||
"email": u.Email,
|
|
||||||
"avatar_url": u.AvatarURL,
|
|
||||||
"html_url": u.HTMLURL,
|
|
||||||
"is_admin": u.IsAdmin,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func slimUserDetails(users []*gitea_sdk.User) []map[string]any {
|
func slimUserDetails(users []*gitea_sdk.User) []map[string]any {
|
||||||
out := make([]map[string]any, 0, len(users))
|
out := make([]map[string]any, 0, len(users))
|
||||||
for _, u := range users {
|
for _, u := range users {
|
||||||
out = append(out, slimUserDetail(u))
|
out = append(out, slim.UserDetail(u))
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
@@ -47,66 +34,6 @@ func slimTeams(teams []*gitea_sdk.Team) []map[string]any {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func slimRepo(r *gitea_sdk.Repository) map[string]any {
|
|
||||||
if r == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
m := map[string]any{
|
|
||||||
"id": r.ID,
|
|
||||||
"full_name": r.FullName,
|
|
||||||
"description": r.Description,
|
|
||||||
"html_url": r.HTMLURL,
|
|
||||||
"clone_url": r.CloneURL,
|
|
||||||
"ssh_url": r.SSHURL,
|
|
||||||
"default_branch": r.DefaultBranch,
|
|
||||||
"private": r.Private,
|
|
||||||
"fork": r.Fork,
|
|
||||||
"archived": r.Archived,
|
|
||||||
"language": r.Language,
|
|
||||||
"stars_count": r.Stars,
|
|
||||||
"forks_count": r.Forks,
|
|
||||||
"open_issues_count": r.OpenIssues,
|
|
||||||
"open_pr_counter": r.OpenPulls,
|
|
||||||
"created_at": r.Created,
|
|
||||||
"updated_at": r.Updated,
|
|
||||||
}
|
|
||||||
if r.Owner != nil {
|
|
||||||
m["owner"] = r.Owner.UserName
|
|
||||||
}
|
|
||||||
if len(r.Topics) > 0 {
|
|
||||||
m["topics"] = r.Topics
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func slimRepos(repos []*gitea_sdk.Repository) []map[string]any {
|
|
||||||
out := make([]map[string]any, 0, len(repos))
|
|
||||||
for _, r := range repos {
|
|
||||||
out = append(out, slimRepo(r))
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func userLogin(u *gitea_sdk.User) string {
|
|
||||||
if u == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return u.UserName
|
|
||||||
}
|
|
||||||
|
|
||||||
func labelNames(labels []*gitea_sdk.Label) []string {
|
|
||||||
if len(labels) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := make([]string, 0, len(labels))
|
|
||||||
for _, l := range labels {
|
|
||||||
if l != nil {
|
|
||||||
out = append(out, l.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func slimIssues(issues []*gitea_sdk.Issue) []map[string]any {
|
func slimIssues(issues []*gitea_sdk.Issue) []map[string]any {
|
||||||
out := make([]map[string]any, 0, len(issues))
|
out := make([]map[string]any, 0, len(issues))
|
||||||
for _, i := range issues {
|
for _, i := range issues {
|
||||||
@@ -118,13 +45,13 @@ func slimIssues(issues []*gitea_sdk.Issue) []map[string]any {
|
|||||||
"title": i.Title,
|
"title": i.Title,
|
||||||
"state": i.State,
|
"state": i.State,
|
||||||
"html_url": i.HTMLURL,
|
"html_url": i.HTMLURL,
|
||||||
"user": userLogin(i.Poster),
|
"user": slim.UserLogin(i.Poster),
|
||||||
"comments": i.Comments,
|
"comments": i.Comments,
|
||||||
"created_at": i.Created,
|
"created_at": i.Created,
|
||||||
"updated_at": i.Updated,
|
"updated_at": i.Updated,
|
||||||
}
|
}
|
||||||
if len(i.Labels) > 0 {
|
if len(i.Labels) > 0 {
|
||||||
m["labels"] = labelNames(i.Labels)
|
m["labels"] = slim.LabelNames(i.Labels)
|
||||||
}
|
}
|
||||||
if i.Repository != nil {
|
if i.Repository != nil {
|
||||||
m["repository"] = i.Repository.FullName
|
m["repository"] = i.Repository.FullName
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSlimIssues(t *testing.T) {
|
func TestSlimIssues(t *testing.T) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package timetracking
|
package timetracking
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func slimStopWatch(s *gitea_sdk.StopWatch) map[string]any {
|
func slimStopWatch(s *gitea_sdk.StopWatch) map[string]any {
|
||||||
|
|||||||
@@ -7,12 +7,11 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
@@ -95,10 +94,7 @@ func writeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stopwatch handler functions
|
|
||||||
|
|
||||||
func startStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func startStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called startStopwatchFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -115,7 +111,7 @@ func startStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, err = client.StartIssueStopWatch(owner, repo, index)
|
_, err = client.Issues.StartIssueStopWatch(ctx, owner, repo, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("start stopwatch on %s/%s#%d err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("start stopwatch on %s/%s#%d err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -123,7 +119,6 @@ func startStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func stopStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func stopStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called stopStopwatchFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -140,7 +135,7 @@ func stopStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, err = client.StopIssueStopWatch(owner, repo, index)
|
_, err = client.Issues.StopIssueStopWatch(ctx, owner, repo, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("stop stopwatch on %s/%s#%d err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("stop stopwatch on %s/%s#%d err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -148,7 +143,6 @@ func stopStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deleteStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deleteStopwatchFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -165,7 +159,7 @@ func deleteStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, err = client.DeleteIssueStopwatch(owner, repo, index)
|
_, err = client.Issues.DeleteIssueStopwatch(ctx, owner, repo, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("delete stopwatch on %s/%s#%d err: %v", owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("delete stopwatch on %s/%s#%d err: %v", owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -173,12 +167,11 @@ func deleteStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getMyStopwatchesFn(ctx context.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getMyStopwatchesFn(ctx context.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getMyStopwatchesFn")
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
stopwatches, _, err := client.ListMyStopwatches(gitea_sdk.ListStopwatchesOptions{})
|
stopwatches, _, err := client.Issues.ListMyStopwatches(ctx, gitea_sdk.ListStopwatchesOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get stopwatches err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get stopwatches err: %v", err))
|
||||||
}
|
}
|
||||||
@@ -188,10 +181,7 @@ func getMyStopwatchesFn(ctx context.Context, _ mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
return to.TextResult(slimStopWatches(stopwatches))
|
return to.TextResult(slimStopWatches(stopwatches))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tracked time handler functions
|
|
||||||
|
|
||||||
func listTrackedTimesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listTrackedTimesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listTrackedTimesFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -210,7 +200,7 @@ func listTrackedTimesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
times, _, err := client.ListIssueTrackedTimes(owner, repo, index, gitea_sdk.ListTrackedTimesOptions{
|
times, _, err := client.Issues.ListIssueTrackedTimes(ctx, owner, repo, index, gitea_sdk.ListTrackedTimesOptions{
|
||||||
ListOptions: gitea_sdk.ListOptions{
|
ListOptions: gitea_sdk.ListOptions{
|
||||||
Page: page,
|
Page: page,
|
||||||
PageSize: pageSize,
|
PageSize: pageSize,
|
||||||
@@ -226,7 +216,6 @@ func listTrackedTimesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addTrackedTimeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func addTrackedTimeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called addTrackedTimeFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -248,7 +237,7 @@ func addTrackedTimeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
trackedTime, _, err := client.AddTime(owner, repo, index, gitea_sdk.AddTimeOption{
|
trackedTime, _, err := client.Issues.AddTime(ctx, owner, repo, index, gitea_sdk.AddTimeOption{
|
||||||
Time: timeSeconds,
|
Time: timeSeconds,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -258,7 +247,6 @@ func addTrackedTimeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteTrackedTimeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deleteTrackedTimeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deleteTrackedTimeFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -280,7 +268,7 @@ func deleteTrackedTimeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
_, err = client.DeleteTime(owner, repo, index, id)
|
_, err = client.Issues.DeleteTime(ctx, owner, repo, index, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("delete tracked time %d from %s/%s#%d err: %v", id, owner, repo, index, err))
|
return to.ErrorResult(fmt.Errorf("delete tracked time %d from %s/%s#%d err: %v", id, owner, repo, index, err))
|
||||||
}
|
}
|
||||||
@@ -288,7 +276,6 @@ func deleteTrackedTimeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listRepoTimesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listRepoTimesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listRepoTimesFn")
|
|
||||||
owner, err := params.GetString(req.GetArguments(), "owner")
|
owner, err := params.GetString(req.GetArguments(), "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(err)
|
return to.ErrorResult(err)
|
||||||
@@ -303,7 +290,7 @@ func listRepoTimesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
times, _, err := client.ListRepoTrackedTimes(owner, repo, gitea_sdk.ListTrackedTimesOptions{
|
times, _, err := client.Issues.ListRepoTrackedTimes(ctx, owner, repo, gitea_sdk.ListTrackedTimesOptions{
|
||||||
ListOptions: gitea_sdk.ListOptions{
|
ListOptions: gitea_sdk.ListOptions{
|
||||||
Page: page,
|
Page: page,
|
||||||
PageSize: pageSize,
|
PageSize: pageSize,
|
||||||
@@ -319,12 +306,11 @@ func listRepoTimesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getMyTimesFn(ctx context.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getMyTimesFn(ctx context.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getMyTimesFn")
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
times, _, err := client.ListMyTrackedTimes(gitea_sdk.ListTrackedTimesOptions{})
|
times, _, err := client.Issues.ListMyTrackedTimes(ctx, gitea_sdk.ListTrackedTimesOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get tracked times err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get tracked times err: %v", err))
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-16
@@ -1,24 +1,9 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func slimUserDetail(u *gitea_sdk.User) map[string]any {
|
|
||||||
if u == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return map[string]any{
|
|
||||||
"id": u.ID,
|
|
||||||
"login": u.UserName,
|
|
||||||
"full_name": u.FullName,
|
|
||||||
"email": u.Email,
|
|
||||||
"avatar_url": u.AvatarURL,
|
|
||||||
"html_url": u.HTMLURL,
|
|
||||||
"is_admin": u.IsAdmin,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func slimOrg(o *gitea_sdk.Organization) map[string]any {
|
func slimOrg(o *gitea_sdk.Organization) map[string]any {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
package user
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSlimUserDetail(t *testing.T) {
|
|
||||||
u := &gitea_sdk.User{
|
|
||||||
ID: 42,
|
|
||||||
UserName: "alice",
|
|
||||||
FullName: "Alice Smith",
|
|
||||||
Email: "alice@example.com",
|
|
||||||
AvatarURL: "https://gitea.com/avatars/42",
|
|
||||||
HTMLURL: "https://gitea.com/alice",
|
|
||||||
IsAdmin: true,
|
|
||||||
}
|
|
||||||
m := slimUserDetail(u)
|
|
||||||
|
|
||||||
if m["id"] != int64(42) {
|
|
||||||
t.Errorf("expected id 42, got %v", m["id"])
|
|
||||||
}
|
|
||||||
if m["login"] != "alice" {
|
|
||||||
t.Errorf("expected login alice, got %v", m["login"])
|
|
||||||
}
|
|
||||||
if m["full_name"] != "Alice Smith" {
|
|
||||||
t.Errorf("expected full_name Alice Smith, got %v", m["full_name"])
|
|
||||||
}
|
|
||||||
if m["is_admin"] != true {
|
|
||||||
t.Errorf("expected is_admin true, got %v", m["is_admin"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSlimUserDetail_Nil(t *testing.T) {
|
|
||||||
if m := slimUserDetail(nil); m != nil {
|
|
||||||
t.Errorf("expected nil for nil user, got %v", m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+11
-43
@@ -6,90 +6,58 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
|
"gitea.com/gitea/gitea-mcp/pkg/slim"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
||||||
|
|
||||||
gitea_sdk "code.gitea.io/sdk/gitea"
|
gitea_sdk "gitea.dev/sdk"
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// GetMyUserInfoToolName is the unique tool name used for MCP registration and lookup of the get_me command.
|
|
||||||
GetMyUserInfoToolName = "get_me"
|
GetMyUserInfoToolName = "get_me"
|
||||||
// GetUserOrgsToolName is the unique tool name used for MCP registration and lookup of the get_user_orgs command.
|
GetUserOrgsToolName = "get_user_orgs"
|
||||||
GetUserOrgsToolName = "get_user_orgs"
|
|
||||||
|
|
||||||
// defaultPage is the default starting page number used for paginated organization listings.
|
|
||||||
defaultPage = 1
|
|
||||||
// defaultPageSize is the default number of organizations per page for paginated queries.
|
|
||||||
defaultPageSize = 30
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tool is the MCP tool manager instance for registering all MCP tools in this package.
|
|
||||||
var Tool = tool.New()
|
var Tool = tool.New()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// GetMyUserInfoTool is the MCP tool for retrieving the current user's info.
|
|
||||||
// It is registered with a specific name and a description string.
|
|
||||||
GetMyUserInfoTool = mcp.NewTool(
|
GetMyUserInfoTool = mcp.NewTool(
|
||||||
GetMyUserInfoToolName,
|
GetMyUserInfoToolName,
|
||||||
mcp.WithDescription("Get current user"),
|
mcp.WithDescription("Get current user"),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("Get current user information")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("Get current user information")),
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetUserOrgsTool is the MCP tool for listing organizations for the authenticated user.
|
|
||||||
// It supports pagination via "page" and "per_page" arguments with default values specified above.
|
|
||||||
GetUserOrgsTool = mcp.NewTool(
|
GetUserOrgsTool = mcp.NewTool(
|
||||||
GetUserOrgsToolName,
|
GetUserOrgsToolName,
|
||||||
mcp.WithDescription("List current user's organizations"),
|
mcp.WithDescription("List current user's organizations"),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("Get user organizations")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("Get user organizations")),
|
||||||
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(defaultPage)),
|
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1)),
|
||||||
mcp.WithNumber("per_page", mcp.Description(params.PaginationDesc), mcp.DefaultNumber(defaultPageSize)),
|
mcp.WithNumber("per_page", mcp.Description(params.PaginationDesc), mcp.DefaultNumber(30)),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
// init registers all MCP tools in Tool at package initialization.
|
|
||||||
// This function ensures the handler functions are registered before server usage.
|
|
||||||
func init() {
|
func init() {
|
||||||
registerTools()
|
Tool.RegisterRead(server.ServerTool{Tool: GetMyUserInfoTool, Handler: GetUserInfoFn})
|
||||||
|
Tool.RegisterRead(server.ServerTool{Tool: GetUserOrgsTool, Handler: GetUserOrgsFn})
|
||||||
}
|
}
|
||||||
|
|
||||||
// registerTools registers all local MCP tool definitions and their handler functions.
|
|
||||||
// To add new functionality, append your tool/handler pair to the tools slice below.
|
|
||||||
func registerTools() {
|
|
||||||
tools := []server.ServerTool{
|
|
||||||
{Tool: GetMyUserInfoTool, Handler: GetUserInfoFn},
|
|
||||||
{Tool: GetUserOrgsTool, Handler: GetUserOrgsFn},
|
|
||||||
}
|
|
||||||
for _, t := range tools {
|
|
||||||
Tool.RegisterRead(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserInfoFn is the handler for "get_me" MCP tool requests.
|
|
||||||
// Logs invocation, fetches current user info from gitea, wraps result for MCP.
|
|
||||||
func GetUserInfoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func GetUserInfoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("[User] Called GetUserInfoFn")
|
|
||||||
client, err := gitea.ClientFromContext(ctx)
|
client, err := gitea.ClientFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
user, _, err := client.GetMyUserInfo()
|
user, _, err := client.Users.GetMyUserInfo(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get user info err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get user info err: %v", err))
|
||||||
}
|
}
|
||||||
return to.TextResult(slimUserDetail(user))
|
return to.TextResult(slim.UserDetail(user))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserOrgsFn is the handler for "get_user_orgs" MCP tool requests.
|
|
||||||
// Logs invocation, pulls validated pagination arguments from request,
|
|
||||||
// performs Gitea organization listing, and wraps the result for MCP.
|
|
||||||
func GetUserOrgsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func GetUserOrgsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("[User] Called GetUserOrgsFn")
|
page, pageSize := params.GetPagination(req.GetArguments(), 30)
|
||||||
page, pageSize := params.GetPagination(req.GetArguments(), defaultPageSize)
|
|
||||||
|
|
||||||
opt := gitea_sdk.ListOrgsOptions{
|
opt := gitea_sdk.ListOrgsOptions{
|
||||||
ListOptions: gitea_sdk.ListOptions{
|
ListOptions: gitea_sdk.ListOptions{
|
||||||
@@ -101,7 +69,7 @@ func GetUserOrgsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
||||||
}
|
}
|
||||||
orgs, _, err := client.ListMyOrgs(opt)
|
orgs, _, err := client.Organizations.ListMyOrgs(ctx, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return to.ErrorResult(fmt.Errorf("get user orgs err: %v", err))
|
return to.ErrorResult(fmt.Errorf("get user orgs err: %v", err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/flag"
|
"gitea.com/gitea/gitea-mcp/pkg/flag"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
||||||
|
|
||||||
@@ -22,6 +21,7 @@ const (
|
|||||||
|
|
||||||
var GetGiteaMCPServerVersionTool = mcp.NewTool(
|
var GetGiteaMCPServerVersionTool = mcp.NewTool(
|
||||||
GetGiteaMCPServerVersion,
|
GetGiteaMCPServerVersion,
|
||||||
|
mcp.WithDescription("Get the running version of the Gitea MCP Server itself (not the Gitea instance it connects to)."),
|
||||||
mcp.WithToolAnnotation(annotation.ReadOnly("Get server version")),
|
mcp.WithToolAnnotation(annotation.ReadOnly("Get server version")),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,7 +33,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetGiteaMCPServerVersionFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func GetGiteaMCPServerVersionFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called GetGiteaMCPServerVersionFn")
|
|
||||||
version := flag.Version
|
version := flag.Version
|
||||||
if version == "" {
|
if version == "" {
|
||||||
version = "dev"
|
version = "dev"
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
"gitea.com/gitea/gitea-mcp/pkg/annotation"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
||||||
@@ -95,7 +94,6 @@ func wikiWriteFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listWikiPagesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func listWikiPagesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called listWikiPagesFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -116,7 +114,6 @@ func listWikiPagesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getWikiPageFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -141,7 +138,6 @@ func getWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getWikiRevisionsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func getWikiRevisionsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called getWikiRevisionsFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -166,7 +162,6 @@ func getWikiRevisionsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func createWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called createWikiPageFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -206,7 +201,6 @@ func createWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func updateWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called updateWikiPageFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -252,7 +246,6 @@ func updateWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func deleteWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
log.Debugf("Called deleteWikiPageFn")
|
|
||||||
args := req.GetArguments()
|
args := req.GetArguments()
|
||||||
owner, err := params.GetString(args, "owner")
|
owner, err := params.GetString(args, "owner")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
// Package annotation provides shared MCP tool annotation helpers.
|
|
||||||
package annotation
|
package annotation
|
||||||
|
|
||||||
import "github.com/mark3labs/mcp-go/mcp"
|
import "github.com/mark3labs/mcp-go/mcp"
|
||||||
|
|
||||||
// ReadOnly returns a ToolAnnotation for read-only tools.
|
|
||||||
func ReadOnly(title string) mcp.ToolAnnotation {
|
func ReadOnly(title string) mcp.ToolAnnotation {
|
||||||
t := true
|
t := true
|
||||||
return mcp.ToolAnnotation{Title: title, ReadOnlyHint: &t}
|
return mcp.ToolAnnotation{Title: title, ReadOnlyHint: &t}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write returns a ToolAnnotation for write tools.
|
|
||||||
func Write(title string) mcp.ToolAnnotation {
|
func Write(title string) mcp.ToolAnnotation {
|
||||||
f := false
|
f := false
|
||||||
return mcp.ToolAnnotation{Title: title, ReadOnlyHint: &f}
|
return mcp.ToolAnnotation{Title: title, ReadOnlyHint: &f}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destructive returns a ToolAnnotation for destructive write tools.
|
|
||||||
func Destructive(title string) mcp.ToolAnnotation {
|
func Destructive(title string) mcp.ToolAnnotation {
|
||||||
f, t := false, true
|
f, t := false, true
|
||||||
return mcp.ToolAnnotation{Title: title, ReadOnlyHint: &f, DestructiveHint: &t}
|
return mcp.ToolAnnotation{Title: title, ReadOnlyHint: &f, DestructiveHint: &t}
|
||||||
|
|||||||
+32
-13
@@ -6,28 +6,47 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
mcpContext "gitea.com/gitea/gitea-mcp/pkg/context"
|
mcpContext "gitea.com/gitea/gitea-mcp/pkg/context"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/flag"
|
"gitea.com/gitea/gitea-mcp/pkg/flag"
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
"gitea.dev/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
clientCache sync.Map // token -> *gitea.Client
|
||||||
|
sharedTransOnce sync.Once
|
||||||
|
sharedTrans *http.Transport
|
||||||
|
)
|
||||||
|
|
||||||
|
func sharedTransport() *http.Transport {
|
||||||
|
sharedTransOnce.Do(func() {
|
||||||
|
sharedTrans = http.DefaultTransport.(*http.Transport).Clone()
|
||||||
|
if flag.Insecure {
|
||||||
|
sharedTrans.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint:gosec // user-requested insecure mode
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return sharedTrans
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a cached *gitea.Client keyed by host+token. The SDK's per-client
|
||||||
|
// version cache and the shared transport let us reuse keep-alive connections
|
||||||
|
// and avoid the SDK's /api/v1/version preflight on every tool call.
|
||||||
func NewClient(token string) (*gitea.Client, error) {
|
func NewClient(token string) (*gitea.Client, error) {
|
||||||
httpClient := &http.Client{
|
key := flag.Host + "\x00" + token
|
||||||
Transport: http.DefaultTransport,
|
if v, ok := clientCache.Load(key); ok {
|
||||||
CheckRedirect: checkRedirect,
|
return v.(*gitea.Client), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
httpClient := &http.Client{
|
||||||
|
Transport: sharedTransport(),
|
||||||
|
CheckRedirect: checkRedirect,
|
||||||
|
}
|
||||||
opts := []gitea.ClientOption{
|
opts := []gitea.ClientOption{
|
||||||
gitea.SetToken(token),
|
gitea.SetToken(token),
|
||||||
|
gitea.SetHTTPClient(httpClient),
|
||||||
}
|
}
|
||||||
if flag.Insecure {
|
|
||||||
httpClient.Transport.(*http.Transport).TLSClientConfig = &tls.Config{
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
opts = append(opts, gitea.SetHTTPClient(httpClient))
|
|
||||||
if flag.Debug {
|
if flag.Debug {
|
||||||
opts = append(opts, gitea.SetDebugMode())
|
opts = append(opts, gitea.SetDebugMode())
|
||||||
}
|
}
|
||||||
@@ -35,10 +54,10 @@ func NewClient(token string) (*gitea.Client, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("create gitea client err: %w", err)
|
return nil, fmt.Errorf("create gitea client err: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set user agent for the client
|
|
||||||
client.SetUserAgent("gitea-mcp-server/" + flag.Version)
|
client.SetUserAgent("gitea-mcp-server/" + flag.Version)
|
||||||
return client, nil
|
|
||||||
|
actual, _ := clientCache.LoadOrStore(key, client)
|
||||||
|
return actual.(*gitea.Client), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkRedirect prevents Go from silently changing mutating requests (POST, PATCH, etc.)
|
// checkRedirect prevents Go from silently changing mutating requests (POST, PATCH, etc.)
|
||||||
|
|||||||
+25
-16
@@ -3,7 +3,6 @@ package gitea
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -11,12 +10,18 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
mcpContext "gitea.com/gitea/gitea-mcp/pkg/context"
|
mcpContext "gitea.com/gitea/gitea-mcp/pkg/context"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/flag"
|
"gitea.com/gitea/gitea-mcp/pkg/flag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
httpClientTimeout = 60 * time.Second
|
||||||
|
errBodySnippetSize = 8192
|
||||||
|
)
|
||||||
|
|
||||||
type HTTPError struct {
|
type HTTPError struct {
|
||||||
StatusCode int
|
StatusCode int
|
||||||
Body string
|
Body string
|
||||||
@@ -38,16 +43,20 @@ func tokenFromContext(ctx context.Context) string {
|
|||||||
return flag.Token
|
return flag.Token
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRESTHTTPClient() *http.Client {
|
var (
|
||||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
restClientOnce sync.Once
|
||||||
if flag.Insecure {
|
restClient *http.Client
|
||||||
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint:gosec // user-requested insecure mode
|
)
|
||||||
}
|
|
||||||
return &http.Client{
|
func restHTTPClient() *http.Client {
|
||||||
Transport: transport,
|
restClientOnce.Do(func() {
|
||||||
Timeout: 60 * time.Second,
|
restClient = &http.Client{
|
||||||
CheckRedirect: checkRedirect,
|
Transport: sharedTransport(),
|
||||||
}
|
Timeout: httpClientTimeout,
|
||||||
|
CheckRedirect: checkRedirect,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return restClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildAPIURL(path string, query url.Values) (string, error) {
|
func buildAPIURL(path string, query url.Values) (string, error) {
|
||||||
@@ -96,7 +105,7 @@ func DoJSON(ctx context.Context, method, path string, query url.Values, body, re
|
|||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
}
|
}
|
||||||
|
|
||||||
client := newRESTHTTPClient()
|
client := restHTTPClient()
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("do request: %w", err)
|
return 0, fmt.Errorf("do request: %w", err)
|
||||||
@@ -104,7 +113,7 @@ func DoJSON(ctx context.Context, method, path string, query url.Values, body, re
|
|||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
bodySnippet, _ := io.ReadAll(io.LimitReader(resp.Body, 8192))
|
bodySnippet, _ := io.ReadAll(io.LimitReader(resp.Body, errBodySnippetSize))
|
||||||
return resp.StatusCode, &HTTPError{StatusCode: resp.StatusCode, Body: strings.TrimSpace(string(bodySnippet))}
|
return resp.StatusCode, &HTTPError{StatusCode: resp.StatusCode, Body: strings.TrimSpace(string(bodySnippet))}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +160,7 @@ func DoBytes(ctx context.Context, method, path string, query url.Values, body an
|
|||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
}
|
}
|
||||||
|
|
||||||
client := newRESTHTTPClient()
|
client := restHTTPClient()
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, fmt.Errorf("do request: %w", err)
|
return nil, 0, fmt.Errorf("do request: %w", err)
|
||||||
@@ -165,8 +174,8 @@ func DoBytes(ctx context.Context, method, path string, query url.Values, body an
|
|||||||
|
|
||||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
bodySnippet := respBytes
|
bodySnippet := respBytes
|
||||||
if len(bodySnippet) > 8192 {
|
if len(bodySnippet) > errBodySnippetSize {
|
||||||
bodySnippet = bodySnippet[:8192]
|
bodySnippet = bodySnippet[:errBodySnippetSize]
|
||||||
}
|
}
|
||||||
return nil, resp.StatusCode, &HTTPError{StatusCode: resp.StatusCode, Body: strings.TrimSpace(string(bodySnippet))}
|
return nil, resp.StatusCode, &HTTPError{StatusCode: resp.StatusCode, Body: strings.TrimSpace(string(bodySnippet))}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,24 +79,6 @@ func SetDefault(logger *zap.Logger) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *Logger {
|
|
||||||
return &Logger{
|
|
||||||
defaultLogger: Default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Logger struct {
|
|
||||||
defaultLogger *zap.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) Infof(msg string, args ...any) {
|
|
||||||
l.defaultLogger.Sugar().Infof(msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) Errorf(msg string, args ...any) {
|
|
||||||
l.defaultLogger.Sugar().Errorf(msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Debug(msg string, fields ...zap.Field) {
|
func Debug(msg string, fields ...zap.Field) {
|
||||||
Default().Debug(msg, fields...)
|
Default().Debug(msg, fields...)
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-16
@@ -16,16 +16,15 @@ const (
|
|||||||
PaginationDesc = "results per page"
|
PaginationDesc = "results per page"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetString extracts a required string parameter from MCP tool arguments.
|
// GetString extracts a required string parameter. Empty strings are treated as missing.
|
||||||
func GetString(args map[string]any, key string) (string, error) {
|
func GetString(args map[string]any, key string) (string, error) {
|
||||||
val, ok := args[key].(string)
|
val, ok := args[key].(string)
|
||||||
if !ok {
|
if !ok || val == "" {
|
||||||
return "", fmt.Errorf("%s is required", key)
|
return "", fmt.Errorf("%s is required", key)
|
||||||
}
|
}
|
||||||
return val, nil
|
return val, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOptionalString extracts an optional string parameter with a default value.
|
|
||||||
func GetOptionalString(args map[string]any, key, defaultVal string) string {
|
func GetOptionalString(args map[string]any, key, defaultVal string) string {
|
||||||
if val, ok := args[key].(string); ok {
|
if val, ok := args[key].(string); ok {
|
||||||
return val
|
return val
|
||||||
@@ -33,7 +32,6 @@ func GetOptionalString(args map[string]any, key, defaultVal string) string {
|
|||||||
return defaultVal
|
return defaultVal
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStringSlice extracts an optional string slice parameter from MCP tool arguments.
|
|
||||||
func GetStringSlice(args map[string]any, key string) []string {
|
func GetStringSlice(args map[string]any, key string) []string {
|
||||||
val, ok := args[key]
|
val, ok := args[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -52,13 +50,11 @@ func GetStringSlice(args map[string]any, key string) []string {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPagination extracts page and per_page parameters, returning them as ints.
|
|
||||||
func GetPagination(args map[string]any, defaultPageSize int64) (page, pageSize int) {
|
func GetPagination(args map[string]any, defaultPageSize int64) (page, pageSize int) {
|
||||||
return int(GetOptionalInt(args, "page", 1)), int(GetOptionalInt(args, "per_page", defaultPageSize))
|
return int(GetOptionalInt(args, "page", 1)), int(GetOptionalInt(args, "per_page", defaultPageSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToInt64 converts a value to int64, accepting both float64 (JSON number) and
|
// ToInt64 accepts float64 (JSON number) and string representations.
|
||||||
// string representations. Returns false if the value cannot be converted.
|
|
||||||
func ToInt64(val any) (int64, bool) {
|
func ToInt64(val any) (int64, bool) {
|
||||||
switch v := val.(type) {
|
switch v := val.(type) {
|
||||||
case float64:
|
case float64:
|
||||||
@@ -74,10 +70,8 @@ func ToInt64(val any) (int64, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIndex extracts a required integer parameter from MCP tool arguments.
|
// GetIndex extracts a required integer. Accepts numeric or string forms — LLM callers
|
||||||
// It accepts both numeric (float64 from JSON) and string representations.
|
// often pass identifiers like issue/PR numbers as strings.
|
||||||
// This provides better UX for LLM callers that may naturally use strings
|
|
||||||
// for identifiers like issue/PR numbers.
|
|
||||||
func GetIndex(args map[string]any, key string) (int64, error) {
|
func GetIndex(args map[string]any, key string) (int64, error) {
|
||||||
val, exists := args[key]
|
val, exists := args[key]
|
||||||
if !exists {
|
if !exists {
|
||||||
@@ -95,7 +89,6 @@ func GetIndex(args map[string]any, key string) (int64, error) {
|
|||||||
return 0, fmt.Errorf("%s must be a number or numeric string", key)
|
return 0, fmt.Errorf("%s must be a number or numeric string", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInt64Slice extracts a required int64 slice parameter from MCP tool arguments.
|
|
||||||
func GetInt64Slice(args map[string]any, key string) ([]int64, error) {
|
func GetInt64Slice(args map[string]any, key string) ([]int64, error) {
|
||||||
raw, ok := args[key].([]any)
|
raw, ok := args[key].([]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -112,7 +105,7 @@ func GetInt64Slice(args map[string]any, key string) ([]int64, error) {
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOptionalTime extracts an optional RFC3339 timestamp parameter, returning nil if missing or unparseable.
|
// GetOptionalTime parses RFC3339, returning nil if missing or unparseable.
|
||||||
func GetOptionalTime(args map[string]any, key string) *time.Time {
|
func GetOptionalTime(args map[string]any, key string) *time.Time {
|
||||||
val, ok := args[key].(string)
|
val, ok := args[key].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -124,9 +117,6 @@ func GetOptionalTime(args map[string]any, key string) *time.Time {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOptionalInt extracts an optional integer parameter from MCP tool arguments.
|
|
||||||
// Returns defaultVal if the key is missing or the value cannot be parsed.
|
|
||||||
// Accepts both float64 (JSON number) and string representations.
|
|
||||||
func GetOptionalInt(args map[string]any, key string, defaultVal int64) int64 {
|
func GetOptionalInt(args map[string]any, key string, defaultVal int64) int64 {
|
||||||
val, exists := args[key]
|
val, exists := args[key]
|
||||||
if !exists {
|
if !exists {
|
||||||
@@ -137,3 +127,30 @@ func GetOptionalInt(args map[string]any, key string, defaultVal int64) int64 {
|
|||||||
}
|
}
|
||||||
return defaultVal
|
return defaultVal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOptionalBoolPtr is for SDK fields where nil/false/true are distinct (e.g. "no change" vs "set to false").
|
||||||
|
func GetOptionalBoolPtr(args map[string]any, key string) *bool {
|
||||||
|
if v, ok := args[key].(bool); ok {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOptionalStringPtr returns nil when the key is missing OR the value is an empty string.
|
||||||
|
// Use this for create/fork-style fields where "" is meaningless (e.g. fork target name).
|
||||||
|
func GetOptionalStringPtr(args map[string]any, key string) *string {
|
||||||
|
if v, ok := args[key].(string); ok && v != "" {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPresentStringPtr returns &v whenever the key is present as a string, including "".
|
||||||
|
// Use this for PATCH-style fields where the SDK distinguishes "no change" (nil) from
|
||||||
|
// "set to empty" (&""), e.g. clearing an issue body or label description.
|
||||||
|
func GetPresentStringPtr(args map[string]any, key string) *string {
|
||||||
|
if v, ok := args[key].(string); ok {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -73,6 +73,42 @@ func TestGetOptionalInt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetOptionalStringPtr(t *testing.T) {
|
||||||
|
if p := GetOptionalStringPtr(map[string]any{}, "k"); p != nil {
|
||||||
|
t.Errorf("missing key: got %v, want nil", p)
|
||||||
|
}
|
||||||
|
if p := GetOptionalStringPtr(map[string]any{"k": ""}, "k"); p != nil {
|
||||||
|
t.Errorf("empty string: got %v, want nil", p)
|
||||||
|
}
|
||||||
|
if p := GetOptionalStringPtr(map[string]any{"k": 42}, "k"); p != nil {
|
||||||
|
t.Errorf("non-string: got %v, want nil", p)
|
||||||
|
}
|
||||||
|
if p := GetOptionalStringPtr(map[string]any{"k": nil}, "k"); p != nil {
|
||||||
|
t.Errorf("nil value (JSON null): got %v, want nil", p)
|
||||||
|
}
|
||||||
|
if p := GetOptionalStringPtr(map[string]any{"k": "x"}, "k"); p == nil || *p != "x" {
|
||||||
|
t.Errorf("non-empty: got %v, want &\"x\"", p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetPresentStringPtr(t *testing.T) {
|
||||||
|
if p := GetPresentStringPtr(map[string]any{}, "k"); p != nil {
|
||||||
|
t.Errorf("missing key: got %v, want nil", p)
|
||||||
|
}
|
||||||
|
if p := GetPresentStringPtr(map[string]any{"k": 42}, "k"); p != nil {
|
||||||
|
t.Errorf("non-string: got %v, want nil", p)
|
||||||
|
}
|
||||||
|
if p := GetPresentStringPtr(map[string]any{"k": nil}, "k"); p != nil {
|
||||||
|
t.Errorf("nil value (JSON null): got %v, want nil", p)
|
||||||
|
}
|
||||||
|
if p := GetPresentStringPtr(map[string]any{"k": ""}, "k"); p == nil || *p != "" {
|
||||||
|
t.Errorf("empty string: got %v, want &\"\"", p)
|
||||||
|
}
|
||||||
|
if p := GetPresentStringPtr(map[string]any{"k": "x"}, "k"); p == nil || *p != "x" {
|
||||||
|
t.Errorf("non-empty: got %v, want &\"x\"", p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetIndex(t *testing.T) {
|
func TestGetIndex(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
package slim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
gitea_sdk "gitea.dev/sdk"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UserLogin(u *gitea_sdk.User) string {
|
||||||
|
if u == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return u.UserName
|
||||||
|
}
|
||||||
|
|
||||||
|
func UserLogins(users []*gitea_sdk.User) []string {
|
||||||
|
if len(users) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make([]string, 0, len(users))
|
||||||
|
for _, u := range users {
|
||||||
|
if u != nil {
|
||||||
|
out = append(out, u.UserName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func LabelNames(labels []*gitea_sdk.Label) []string {
|
||||||
|
if len(labels) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make([]string, 0, len(labels))
|
||||||
|
for _, l := range labels {
|
||||||
|
if l != nil {
|
||||||
|
out = append(out, l.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func BodyWithAttachments(body string, atts []*gitea_sdk.Attachment) string {
|
||||||
|
links := make([]string, 0, len(atts))
|
||||||
|
for _, a := range atts {
|
||||||
|
if a == nil || a.DownloadURL == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
links = append(links, fmt.Sprintf("[%s](%s)", a.Name, a.DownloadURL))
|
||||||
|
}
|
||||||
|
if len(links) == 0 {
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
joined := strings.Join(links, "\n")
|
||||||
|
if body == "" {
|
||||||
|
return joined
|
||||||
|
}
|
||||||
|
return body + "\n\n" + joined
|
||||||
|
}
|
||||||
|
|
||||||
|
func UserDetail(u *gitea_sdk.User) map[string]any {
|
||||||
|
if u == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return map[string]any{
|
||||||
|
"id": u.ID,
|
||||||
|
"login": u.UserName,
|
||||||
|
"full_name": u.FullName,
|
||||||
|
"email": u.Email,
|
||||||
|
"avatar_url": u.AvatarURL,
|
||||||
|
"html_url": u.HTMLURL,
|
||||||
|
"is_admin": u.IsAdmin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Repo(r *gitea_sdk.Repository) map[string]any {
|
||||||
|
if r == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
m := map[string]any{
|
||||||
|
"id": r.ID,
|
||||||
|
"full_name": r.FullName,
|
||||||
|
"description": r.Description,
|
||||||
|
"html_url": r.HTMLURL,
|
||||||
|
"clone_url": r.CloneURL,
|
||||||
|
"ssh_url": r.SSHURL,
|
||||||
|
"default_branch": r.DefaultBranch,
|
||||||
|
"private": r.Private,
|
||||||
|
"fork": r.Fork,
|
||||||
|
"archived": r.Archived,
|
||||||
|
"language": r.Language,
|
||||||
|
"stars_count": r.Stars,
|
||||||
|
"forks_count": r.Forks,
|
||||||
|
"open_issues_count": r.OpenIssues,
|
||||||
|
"open_pr_counter": r.OpenPulls,
|
||||||
|
"created_at": r.Created,
|
||||||
|
"updated_at": r.Updated,
|
||||||
|
}
|
||||||
|
if r.Owner != nil {
|
||||||
|
m["owner"] = r.Owner.UserName
|
||||||
|
}
|
||||||
|
if len(r.Topics) > 0 {
|
||||||
|
m["topics"] = r.Topics
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func Repos(repos []*gitea_sdk.Repository) []map[string]any {
|
||||||
|
out := make([]map[string]any, 0, len(repos))
|
||||||
|
for _, r := range repos {
|
||||||
|
out = append(out, Repo(r))
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func Label(l *gitea_sdk.Label) map[string]any {
|
||||||
|
if l == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return map[string]any{
|
||||||
|
"id": l.ID,
|
||||||
|
"name": l.Name,
|
||||||
|
"color": l.Color,
|
||||||
|
"description": l.Description,
|
||||||
|
"exclusive": l.Exclusive,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Labels(labels []*gitea_sdk.Label) []map[string]any {
|
||||||
|
out := make([]map[string]any, 0, len(labels))
|
||||||
|
for _, l := range labels {
|
||||||
|
out = append(out, Label(l))
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package slim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
gitea_sdk "gitea.dev/sdk"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUserDetail(t *testing.T) {
|
||||||
|
u := &gitea_sdk.User{
|
||||||
|
ID: 42,
|
||||||
|
UserName: "alice",
|
||||||
|
FullName: "Alice Smith",
|
||||||
|
Email: "alice@example.com",
|
||||||
|
AvatarURL: "https://gitea.com/avatars/42",
|
||||||
|
HTMLURL: "https://gitea.com/alice",
|
||||||
|
IsAdmin: true,
|
||||||
|
}
|
||||||
|
m := UserDetail(u)
|
||||||
|
|
||||||
|
if m["id"] != int64(42) {
|
||||||
|
t.Errorf("expected id 42, got %v", m["id"])
|
||||||
|
}
|
||||||
|
if m["login"] != "alice" {
|
||||||
|
t.Errorf("expected login alice, got %v", m["login"])
|
||||||
|
}
|
||||||
|
if m["full_name"] != "Alice Smith" {
|
||||||
|
t.Errorf("expected full_name Alice Smith, got %v", m["full_name"])
|
||||||
|
}
|
||||||
|
if m["is_admin"] != true {
|
||||||
|
t.Errorf("expected is_admin true, got %v", m["is_admin"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserDetail_Nil(t *testing.T) {
|
||||||
|
if m := UserDetail(nil); m != nil {
|
||||||
|
t.Errorf("expected nil for nil user, got %v", m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLabel(t *testing.T) {
|
||||||
|
l := &gitea_sdk.Label{
|
||||||
|
ID: 1,
|
||||||
|
Name: "bug",
|
||||||
|
Color: "#d73a4a",
|
||||||
|
Description: "Something isn't working",
|
||||||
|
Exclusive: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
m := Label(l)
|
||||||
|
if m["name"] != "bug" {
|
||||||
|
t.Errorf("expected name bug, got %v", m["name"])
|
||||||
|
}
|
||||||
|
if m["color"] != "#d73a4a" {
|
||||||
|
t.Errorf("expected color, got %v", m["color"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRepo(t *testing.T) {
|
||||||
|
r := &gitea_sdk.Repository{
|
||||||
|
ID: 1,
|
||||||
|
FullName: "org/repo",
|
||||||
|
Description: "A test repo",
|
||||||
|
HTMLURL: "https://gitea.com/org/repo",
|
||||||
|
CloneURL: "https://gitea.com/org/repo.git",
|
||||||
|
SSHURL: "git@gitea.com:org/repo.git",
|
||||||
|
DefaultBranch: "main",
|
||||||
|
Language: "Go",
|
||||||
|
Stars: 10,
|
||||||
|
Forks: 2,
|
||||||
|
Owner: &gitea_sdk.User{UserName: "org"},
|
||||||
|
Topics: []string{"mcp", "gitea"},
|
||||||
|
}
|
||||||
|
|
||||||
|
m := Repo(r)
|
||||||
|
|
||||||
|
if m["full_name"] != "org/repo" {
|
||||||
|
t.Errorf("expected full_name org/repo, got %v", m["full_name"])
|
||||||
|
}
|
||||||
|
if m["owner"] != "org" {
|
||||||
|
t.Errorf("expected owner org, got %v", m["owner"])
|
||||||
|
}
|
||||||
|
topics := m["topics"].([]string)
|
||||||
|
if len(topics) != 2 {
|
||||||
|
t.Errorf("expected 2 topics, got %d", len(topics))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBodyWithAttachments(t *testing.T) {
|
||||||
|
atts := []*gitea_sdk.Attachment{
|
||||||
|
{Name: "shot.png", DownloadURL: "https://example/shot.png"},
|
||||||
|
{Name: "log.txt", DownloadURL: "https://example/log.txt"},
|
||||||
|
}
|
||||||
|
got := BodyWithAttachments("see attached", atts)
|
||||||
|
want := "see attached\n\n[shot.png](https://example/shot.png)\n[log.txt](https://example/log.txt)"
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("got %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := BodyWithAttachments("only body", nil); got != "only body" {
|
||||||
|
t.Errorf("nil attachments should return body unchanged, got %q", got)
|
||||||
|
}
|
||||||
|
if got := BodyWithAttachments("", atts); got != "[shot.png](https://example/shot.png)\n[log.txt](https://example/log.txt)" {
|
||||||
|
t.Errorf("empty body should drop separator, got %q", got)
|
||||||
|
}
|
||||||
|
skipped := []*gitea_sdk.Attachment{nil, {Name: "noop", DownloadURL: ""}}
|
||||||
|
if got := BodyWithAttachments("body", skipped); got != "body" {
|
||||||
|
t.Errorf("nil/empty-URL attachments should be skipped, got %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-2
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"gitea.com/gitea/gitea-mcp/pkg/flag"
|
||||||
"gitea.com/gitea/gitea-mcp/pkg/log"
|
"gitea.com/gitea/gitea-mcp/pkg/log"
|
||||||
|
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
@@ -14,11 +15,13 @@ func TextResult(v any) (*mcp.CallToolResult, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("marshal result err: %v", err)
|
return nil, fmt.Errorf("marshal result err: %v", err)
|
||||||
}
|
}
|
||||||
log.Debugf("Text Result: %s", string(resultBytes))
|
if flag.Debug {
|
||||||
|
log.Debugf("Text Result: %s", string(resultBytes))
|
||||||
|
}
|
||||||
return mcp.NewToolResultText(string(resultBytes)), nil
|
return mcp.NewToolResultText(string(resultBytes)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrorResult(err error) (*mcp.CallToolResult, error) {
|
func ErrorResult(err error) (*mcp.CallToolResult, error) {
|
||||||
log.Errorf(err.Error())
|
log.Errorf("%s", err.Error())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user