## Problem Binary discovery was returning the first absolute path without checking if it exists. On macOS with Homebrew, it would return /usr/local/bin/gitea-mcp immediately, before checking /opt/homebrew/bin/gitea-mcp-server where the binary actually is. ## Solution Restructure the binary path search logic: 1. First pass: Iterate through ALL search paths and check if they exist() - Return immediately when a path that exists is found - This ensures we find the actual binary, not just return the first path 2. Fallback: Only if NO paths exist (WASM sandbox restricts exists() checks), use the first absolute path ## Impact - Homebrew binaries on macOS are now properly discovered - Binary discovery works correctly on all platforms - WASM sandbox fallback still works for cases where exists() is restricted ## Testing - ✅ Tested on Linux with explicit path - works - ✅ Tested on Linux with auto-discovery - works - 🔄 Testing on macOS M4 with Homebrew - should now work
551 lines
15 KiB
Markdown
551 lines
15 KiB
Markdown
# Tendril: Gitea MCP for Zed
|
|
|
|
A Zed IDE extension that integrates with Gitea through the Model Context Protocol (MCP). Tendril is part of **The Mycelium Project** and provides seamless access to Gitea repositories, issues, pull requests, and more directly within your editor.
|
|
|
|
## What is This?
|
|
|
|
Tendril is a **Zed IDE extension** that acts as a bridge between Zed and a Gitea MCP server. The extension itself is lightweight - it's the glue that connects your editor to a Gitea MCP server running on your system (or in Docker). You'll need to have either the `gitea-mcp` binary installed or Docker available.
|
|
|
|
Think of it as:
|
|
- **Extension**: Tendril (this repository) - runs inside Zed
|
|
- **Server**: gitea-mcp binary or Docker container - runs on your system, communicates with Gitea
|
|
- **Result**: Full Gitea access from your editor through Zed's AI features
|
|
|
|
## Requirements
|
|
|
|
Before you can use Tendril, you need:
|
|
|
|
1. **Zed IDE** - Download from https://zed.dev
|
|
2. **Gitea MCP Server** - Either:
|
|
- Binary installed locally, OR
|
|
- Docker with gitea-mcp image available
|
|
3. **Gitea Access Token** - Generated from your Gitea instance
|
|
4. **Rust** (if installing as dev extension) - Installed via rustup
|
|
|
|
## Quick Start
|
|
|
|
### Option A: Using Local Binary
|
|
|
|
#### 1. Install the Gitea MCP Binary
|
|
|
|
The extension automatically searches for `gitea-mcp` (and `gitea-mcp-server`) in these locations:
|
|
- `/usr/local/bin/gitea-mcp` or `gitea-mcp-server`
|
|
- `~/.local/bin/gitea-mcp` or `gitea-mcp-server`
|
|
- `~/.cargo/bin/gitea-mcp` or `gitea-mcp-server`
|
|
- `/opt/homebrew/bin/gitea-mcp` or `gitea-mcp-server` (macOS)
|
|
- Anywhere in your PATH
|
|
|
|
Choose an installation method:
|
|
|
|
**macOS (Recommended - Homebrew):**
|
|
```bash
|
|
# Install via Homebrew (handles binary verification and updates)
|
|
brew install gitea/tap/gitea-mcp-server
|
|
```
|
|
This installs to `/opt/homebrew/bin/gitea-mcp-server` and is the easiest method for macOS users.
|
|
|
|
**Download Pre-built Binary:**
|
|
```bash
|
|
# Download from: https://gitea.com/gitea/gitea-mcp/releases
|
|
# For example, Linux x64:
|
|
wget https://gitea.com/gitea/gitea-mcp/releases/download/v1.0.0/gitea-mcp-linux-amd64
|
|
chmod +x gitea-mcp-linux-amd64
|
|
sudo mv gitea-mcp-linux-amd64 /usr/local/bin/gitea-mcp
|
|
```
|
|
|
|
**Build from Source:**
|
|
```bash
|
|
git clone https://gitea.com/gitea/gitea-mcp.git
|
|
cd gitea-mcp
|
|
make install
|
|
```
|
|
|
|
**Verify Installation:**
|
|
```bash
|
|
/usr/local/bin/gitea-mcp --help
|
|
```
|
|
|
|
#### 2. Generate a Gitea Access Token
|
|
|
|
1. Log in to your Gitea instance
|
|
2. Go to **Settings** → **Applications** → **Authorize New Application**
|
|
3. Give it a name like "Zed MCP"
|
|
4. Select required permissions (recommend repository-related scopes)
|
|
5. Click **Authorize** and copy the token
|
|
|
|
#### 3. Install Tendril as a Dev Extension
|
|
|
|
1. Open Zed
|
|
2. Go to **Extensions** panel (left sidebar or Cmd+K → "Extensions")
|
|
3. Click **Install Dev Extension**
|
|
4. Select the `tendril` directory
|
|
5. Zed will compile and load the extension
|
|
|
|
#### 4. Configure Zed Settings
|
|
|
|
Open your Zed settings (`Cmd+,`) and add:
|
|
|
|
```json
|
|
{
|
|
"context_servers": {
|
|
"tendril-gitea-mcp": {
|
|
"settings": {
|
|
"gitea_access_token": "YOUR_GITEA_TOKEN_HERE"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Option B: Using Docker
|
|
|
|
If you have Docker installed and prefer containerized deployment:
|
|
|
|
#### 1. Generate a Gitea Access Token
|
|
|
|
Same as Option A, step 2 above.
|
|
|
|
#### 2. Install Tendril as a Dev Extension
|
|
|
|
Same as Option A, steps 3-4, but with Docker settings:
|
|
|
|
```json
|
|
{
|
|
"context_servers": {
|
|
"tendril-gitea-mcp": {
|
|
"settings": {
|
|
"gitea_access_token": "YOUR_GITEA_TOKEN_HERE",
|
|
"use_docker": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
The extension will automatically pull and run `gitea/gitea-mcp-server:latest` in Docker.
|
|
|
|
Optionally, specify a different image:
|
|
|
|
```json
|
|
{
|
|
"context_servers": {
|
|
"tendril-gitea-mcp": {
|
|
"settings": {
|
|
"gitea_access_token": "YOUR_GITEA_TOKEN_HERE",
|
|
"use_docker": true,
|
|
"docker_image": "gitea/gitea-mcp-server:v1.0.0"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 3. Test the Connection
|
|
|
|
In Zed's Assistant panel, try:
|
|
|
|
```
|
|
list my repositories
|
|
```
|
|
|
|
### 5. Test the Connection
|
|
|
|
In Zed's Assistant panel, try a command like:
|
|
|
|
```
|
|
list my repositories
|
|
```
|
|
|
|
The MCP server should respond with your Gitea repositories.
|
|
|
|
## Configuration Reference
|
|
|
|
### Basic Settings
|
|
|
|
| Setting | Type | Required | Description |
|
|
|---------|------|----------|-------------|
|
|
| `gitea_access_token` | string | Yes | Your Gitea personal access token |
|
|
| `gitea_host` | string | No | URL of your Gitea instance (for self-hosted) |
|
|
| `gitea_insecure` | boolean | No | Allow self-signed certificates (default: false) |
|
|
|
|
### Binary Path Settings
|
|
|
|
| Setting | Type | Default | Description |
|
|
|---------|------|---------|-------------|
|
|
| `gitea_mcp_binary_path` | string | (auto-detect) | Explicit path to gitea-mcp binary |
|
|
|
|
If `gitea_mcp_binary_path` is not set, Tendril automatically searches standard locations. Use this setting if your binary is in a non-standard location.
|
|
|
|
### Docker Settings
|
|
|
|
| Setting | Type | Default | Description |
|
|
|---------|------|---------|-------------|
|
|
| `use_docker` | boolean | false | Use Docker to run gitea-mcp instead of local binary |
|
|
| `docker_image` | string | gitea/gitea-mcp-server:latest | Docker image to use |
|
|
|
|
## Configuration Examples
|
|
|
|
### Basic Setup (Auto-Detect Binary)
|
|
|
|
```json
|
|
{
|
|
"context_servers": {
|
|
"tendril-gitea-mcp": {
|
|
"settings": {
|
|
"gitea_access_token": "YOUR_GITEA_TOKEN_HERE"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Self-Hosted Gitea
|
|
|
|
```json
|
|
{
|
|
"context_servers": {
|
|
"tendril-gitea-mcp": {
|
|
"settings": {
|
|
"gitea_access_token": "YOUR_TOKEN",
|
|
"gitea_host": "https://git.example.com",
|
|
"gitea_insecure": false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Custom Binary Path
|
|
|
|
```json
|
|
{
|
|
"context_servers": {
|
|
"tendril-gitea-mcp": {
|
|
"settings": {
|
|
"gitea_access_token": "YOUR_TOKEN",
|
|
"gitea_mcp_binary_path": "/home/user/custom/location/gitea-mcp"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Docker Setup
|
|
|
|
```json
|
|
{
|
|
"context_servers": {
|
|
"tendril-gitea-mcp": {
|
|
"settings": {
|
|
"gitea_access_token": "YOUR_TOKEN",
|
|
"use_docker": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Docker with Custom Image and Self-Hosted Gitea
|
|
|
|
```json
|
|
{
|
|
"context_servers": {
|
|
"tendril-gitea-mcp": {
|
|
"settings": {
|
|
"gitea_access_token": "YOUR_TOKEN",
|
|
"gitea_host": "https://git.internal.company.com",
|
|
"gitea_insecure": true,
|
|
"use_docker": true,
|
|
"docker_image": "my-registry.com/gitea-mcp:v1.0.0"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Available Tools
|
|
|
|
Through the Gitea MCP server, you get access to:
|
|
|
|
- **User Management**: Get user info, list organizations, search users
|
|
- **Repository Management**: List repos, create repos, fork repos
|
|
- **Branch Management**: Create/delete/list branches
|
|
- **Release Management**: Create/list/delete releases
|
|
- **Tag Management**: Create/list/delete tags
|
|
- **File Operations**: View, create, update, delete files
|
|
- **Issue Management**: Create/edit/list issues, add comments
|
|
- **Pull Requests**: Create/list/manage pull requests
|
|
- **Commits**: List and view commits
|
|
|
|
See the [Gitea MCP documentation](https://gitea.com/gitea/gitea-mcp) for complete tool details.
|
|
|
|
## Installation Methods
|
|
|
|
### For Development (Recommended)
|
|
|
|
Use the dev extension approach (see Quick Start above). This allows you to:
|
|
- Test changes immediately
|
|
- Reload the extension without restarting Zed
|
|
- Contribute improvements back
|
|
|
|
### For Production (When Published)
|
|
|
|
Once Tendril is published to the Zed Extension Marketplace, you'll be able to install it like any other extension from within Zed's Extensions panel.
|
|
|
|
## Troubleshooting
|
|
|
|
### "Binary Not Found" Error
|
|
|
|
If you get an error about gitea-mcp not being found:
|
|
|
|
**For macOS:**
|
|
- Install via Homebrew: `brew install gitea/tap/gitea-mcp-server`
|
|
- Or set `gitea_mcp_binary_path` to the full path in your settings
|
|
- Verify it works: `/opt/homebrew/bin/gitea-mcp-server --help`
|
|
|
|
**For Linux:**
|
|
- Download from https://gitea.com/gitea/gitea-mcp/releases to `/usr/local/bin/gitea-mcp`
|
|
- Or build from source and run `make install`
|
|
- Or set `gitea_mcp_binary_path` to your custom location
|
|
|
|
**For all platforms:**
|
|
- Verify the binary is executable: `chmod +x /path/to/gitea-mcp`
|
|
- Test it manually: `/path/to/gitea-mcp --help`
|
|
- If you've installed it in a non-standard location, use the `gitea_mcp_binary_path` setting
|
|
|
|
**Using Docker mode:**
|
|
- Ensure Docker is installed and running
|
|
- Set `use_docker: true` in settings
|
|
- Let Docker pull the image automatically
|
|
|
|
### "Failed to Spawn Command" Error
|
|
|
|
The binary exists but isn't executable:
|
|
|
|
```bash
|
|
chmod +x /usr/local/bin/gitea-mcp
|
|
```
|
|
|
|
Then restart Zed.
|
|
|
|
### Authentication Issues
|
|
|
|
- Verify your Gitea token has repository permissions
|
|
- Ensure you've copied the entire token correctly (no extra spaces)
|
|
- Check that the token hasn't expired
|
|
- Log out and back in to your Gitea instance if using session-based auth
|
|
|
|
### Self-Hosted Gitea with Self-Signed Certificates
|
|
|
|
If you're getting SSL certificate errors with a self-hosted Gitea instance:
|
|
|
|
```json
|
|
{
|
|
"context_servers": {
|
|
"tendril-gitea-mcp": {
|
|
"settings": {
|
|
"gitea_access_token": "YOUR_TOKEN",
|
|
"gitea_host": "https://git.example.com",
|
|
"gitea_insecure": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Security Note**: Only use `gitea_insecure: true` for trusted internal servers.
|
|
|
|
### Docker Not Available
|
|
|
|
If you see "docker: command not found":
|
|
|
|
1. Install Docker from https://www.docker.com/products/docker-desktop
|
|
2. Ensure Docker Desktop is running (macOS/Windows)
|
|
3. Or install Docker on Linux: `sudo apt install docker.io` (Ubuntu) or equivalent for your distro
|
|
4. Restart Zed after installing Docker
|
|
|
|
### Dev Extension Not Loading
|
|
|
|
Check the Zed log for errors:
|
|
|
|
1. In Zed, run: `zed: open log`
|
|
2. Look for errors related to "tendril"
|
|
3. If you see build errors, try:
|
|
```bash
|
|
cd tendril
|
|
cargo build --release
|
|
cargo clippy
|
|
```
|
|
4. Ensure Rust is installed via rustup: `rustup --version`
|
|
5. Restart Zed completely
|
|
|
|
## Binary Path Resolution
|
|
|
|
When **not** using Docker, Tendril uses this search order:
|
|
|
|
1. **Explicitly configured path** (if `gitea_mcp_binary_path` is set)
|
|
- User configuration takes priority
|
|
- Example: `"gitea_mcp_binary_path": "/opt/homebrew/bin/gitea-mcp-server"`
|
|
|
|
2. **System standard locations** (searches for both `gitea-mcp` and `gitea-mcp-server`):
|
|
- `/usr/local/bin/gitea-mcp` or `gitea-mcp-server`
|
|
- `/usr/bin/gitea-mcp` or `gitea-mcp-server`
|
|
- `~/.local/bin/gitea-mcp` or `gitea-mcp-server`
|
|
- `~/bin/gitea-mcp` or `gitea-mcp-server`
|
|
- `~/.cargo/bin/gitea-mcp` or `gitea-mcp-server`
|
|
- `/opt/homebrew/bin/gitea-mcp` or `gitea-mcp-server` (macOS - installed via Homebrew)
|
|
|
|
3. **PATH environment variable** (any location in your system PATH)
|
|
|
|
If the binary isn't found, you'll get a helpful error message with troubleshooting steps.
|
|
|
|
### macOS Homebrew Note
|
|
|
|
If you installed via Homebrew (`brew install gitea/tap/gitea-mcp-server`), the binary will be at:
|
|
- `/opt/homebrew/bin/gitea-mcp-server` (M-series/ARM64 Macs)
|
|
|
|
This location is automatically searched, so no configuration needed!
|
|
|
|
## Debugging
|
|
|
|
### View Gitea MCP Logs
|
|
|
|
```bash
|
|
tail -f ~/.gitea-mcp/gitea-mcp.log
|
|
```
|
|
|
|
### View Zed Logs
|
|
|
|
1. In Zed, run: `zed: open log`
|
|
2. Or check the system log location:
|
|
- macOS: `~/Library/Logs/Zed.log`
|
|
- Linux: `~/.local/share/zed/logs/Zed.log`
|
|
- Windows: `%APPDATA%\Zed\logs\Zed.log`
|
|
|
|
### Debug with Verbose Logging
|
|
|
|
Start Zed from the command line for more output:
|
|
|
|
```bash
|
|
zed --foreground
|
|
```
|
|
|
|
### Manual Binary Testing
|
|
|
|
Test the binary directly (without Zed):
|
|
|
|
```bash
|
|
# STDIO mode
|
|
export GITEA_ACCESS_TOKEN="your_token"
|
|
/usr/local/bin/gitea-mcp -t stdio --host https://git.example.com
|
|
|
|
# Type any command and press Ctrl+D when done
|
|
# (This is a low-level test)
|
|
```
|
|
|
|
## Development
|
|
|
|
### Building from Source
|
|
|
|
Prerequisites:
|
|
- Rust (installed via rustup)
|
|
- Zed development environment
|
|
|
|
Build the extension:
|
|
|
|
```bash
|
|
cd tendril
|
|
cargo build --release
|
|
```
|
|
|
|
This generates the WASM module used by Zed.
|
|
|
|
### Reloading During Development
|
|
|
|
After making changes to the Rust code:
|
|
|
|
1. Run `cargo build --release`
|
|
2. Reload the extension in Zed (restart Zed or use extension reload if available)
|
|
3. Changes take effect immediately
|
|
|
|
### Project Structure
|
|
|
|
```
|
|
tendril/
|
|
├── Cargo.toml # Rust project configuration
|
|
├── extension.toml # Zed extension manifest
|
|
├── src/
|
|
│ └── mcp_server_gitea.rs # Main extension logic (~350 lines)
|
|
├── configuration/
|
|
│ ├── default_settings.jsonc # Default configuration with comments
|
|
│ └── installation_instructions.md # Quick setup guide for Zed UI
|
|
├── README.md # This file
|
|
├── DEVELOPMENT.md # Developer guide
|
|
├── PROJECT_STATUS.md # Project status and roadmap
|
|
└── LICENSE # Apache 2.0
|
|
```
|
|
|
|
### Code Overview
|
|
|
|
**src/mcp_server_gitea.rs**:
|
|
- `GiteaContextServerSettings`: Struct defining all configuration options
|
|
- `build_binary_command()`: Creates command to run gitea-mcp binary
|
|
- `build_docker_command()`: Creates Docker command to run gitea-mcp
|
|
- `resolve_binary_path()`: Implements smart binary path discovery
|
|
|
|
## Related Projects
|
|
|
|
- **Gitea**: https://gitea.io - Lightweight Git service
|
|
- **Gitea MCP**: https://gitea.com/gitea/gitea-mcp - MCP server for Gitea
|
|
- **Model Context Protocol**: https://modelcontextprotocol.io
|
|
- **The Mycelium Project**: https://git.parkingmeter.info/Mycelium
|
|
- **Zed IDE**: https://zed.dev
|
|
|
|
## License
|
|
|
|
Licensed under the Apache License 2.0. See [LICENSE](./LICENSE) for details.
|
|
|
|
## Support
|
|
|
|
For issues or questions:
|
|
|
|
1. **Check troubleshooting** above
|
|
2. **Review logs** using `zed: open log`
|
|
3. **Open an issue** on [Tendril repository](https://git.parkingmeter.info/Mycelium/tendril)
|
|
4. **Consult documentation**:
|
|
- [Zed Extensions](https://zed.dev/docs/extensions)
|
|
- [Gitea MCP](https://gitea.com/gitea/gitea-mcp)
|
|
- [Model Context Protocol](https://modelcontextprotocol.io)
|
|
|
|
## Contributing
|
|
|
|
Contributions are welcome! Please:
|
|
|
|
1. Fork the repository
|
|
2. Create a feature branch: `git checkout -b feature/your-feature`
|
|
3. Make your changes and test: `cargo build --release && cargo clippy`
|
|
4. Submit a pull request with a clear description
|
|
|
|
## Authors
|
|
|
|
- Ryan Parmeter ([@parkingmeter](https://git.parkingmeter.info/parkingmeter))
|
|
- The Mycelium Project Contributors
|
|
|
|
## Changelog
|
|
|
|
### v0.1.0 (Upcoming)
|
|
|
|
- ✨ Configurable binary path with intelligent fallback search
|
|
- ✨ Docker support for containerized deployment
|
|
- ✨ Cross-platform binary discovery (Linux, macOS, Windows)
|
|
- 🐛 Improved error messages with troubleshooting guidance
|
|
- 📚 Enhanced documentation
|
|
|
|
### v0.0.1 (Initial Development Release)
|
|
|
|
- Initial development version
|
|
- STDIO mode support
|
|
- Basic configuration through Zed settings.json
|
|
- Support for self-hosted Gitea instances
|
|
- Hardcoded binary path to `/usr/local/bin/gitea-mcp`
|