- Python 97.4%
- Dockerfile 2.6%
| .env.example | ||
| .gitignore | ||
| Dockerfile | ||
| forgejo_client.py | ||
| LICENSE | ||
| README.md | ||
| requirements.txt | ||
| server.py | ||
forgejo-mcp
A Model Context Protocol (MCP) server that exposes a Forgejo instance as LLM-callable tools. Reads repositories, files, commits, and issues; can create issues and post comments. Runs as a Streamable HTTP server with bearer-token auth, deployable behind any reverse proxy.
Built as a working portfolio piece for Skip's Forgejo at https://git.opensourcesecurity.net. The deployed instance lets evaluators hand a token to Claude (or any MCP-compatible client) and explore the codebase by natural language: "list the repos", "read the README from glassbox", "what's Skip been working on in safenet lately?"
Tools
| Tool | Type | What it does |
|---|---|---|
forgejo_whoami |
read | Health check: returns the authenticated user. |
forgejo_list_repos |
read | All repos in an organization, slimmed to LLM-friendly fields. |
forgejo_get_repo |
read | Detailed metadata for one repo. |
forgejo_get_file_contents |
read | Read a file from a repo. Handles base64 decode, binary detection, size caps. |
forgejo_list_commits |
read | Recent commit history of a repo. |
forgejo_list_issues |
read | Open issues, optionally filtered by repo or state. |
forgejo_search_repos |
read | Search repos by name/description. |
forgejo_create_issue |
write | Open a new issue. Authored by the token's owner. |
forgejo_comment_issue |
write | Comment on an existing issue. |
Tool annotations (readOnlyHint, destructiveHint, etc.) are set per the MCP spec so clients can make informed decisions about confirmation prompts.
Public endpoint
https://mcp.opensourcesecurity.net/mcp
Bearer token required. Contact Skip for an evaluator token if you're reviewing portfolio work.
Architecture
LLM client (Claude Desktop, Inspector, etc.)
|
| JSON-RPC over Streamable HTTP + Bearer auth
v
+---------------------+ +-------------------+
| server.py | ---> | forgejo_client.py |
| (FastMCP) | | (httpx wrapper) |
+---------------------+ +-------------------+
|
v
https://git.opensourcesecurity.net
(Forgejo HTTP API)
Two-file design:
server.pyknows MCP; declares tools, handles auth, runs uvicorn.forgejo_client.pyknows Forgejo; wraps httpx, shapes API responses.
Neither knows about the other's concerns. Either could be replaced independently (different MCP framework, different git forge).
Running locally
git clone https://git.opensourcesecurity.net/opensourcesecurity/forgejo-mcp.git
cd forgejo-mcp
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# Edit .env with your Forgejo token and a fresh bearer token
python server.py
Then in another terminal, point the MCP Inspector (npx @modelcontextprotocol/inspector) at http://127.0.0.1:8765/mcp with your bearer token in the Authorization header.
Running in Docker
docker build -t forgejo-mcp:latest .
docker run -d \
--name forgejo-mcp \
--env-file .env \
-e MCP_BIND_HOST=0.0.0.0 \
-p 8765:8765 \
forgejo-mcp:latest
The MCP_BIND_HOST=0.0.0.0 override is required for the container's port publish to work (the .env default of 127.0.0.1 is for laptop dev).
Security model
- Server requires
Authorization: Bearer <token>on every request. - Token comes from
MCP_BEARER_TOKENenv var; the server refuses to start if it's not set. - Token comparison is a plain string compare; for higher-security deployments, switch to
secrets.compare_digest()(one-line change). - The Forgejo token (
FORGEJO_TOKEN) is what limits what the MCP server can DO. The bearer token is what limits WHO can use the MCP server. Treat both as secrets.
Built with
- MCP Python SDK 1.27 (https://github.com/modelcontextprotocol/python-sdk)
- httpx for async HTTP (https://www.python-httpx.org/)
- Starlette ASGI for auth middleware (https://www.starlette.io/)
- Forgejo API v1 (https://forgejo.org/docs/latest/user/api-usage/)
License
BSD 2-Clause. See LICENSE.