feat: support separate Gitea MCP runtime profiles via env config (#19)
Allow the same MCP server to run as separate MCP entries, each with its own token and profile name, so roles stay task-scoped (the profile is the role, not the LLM). - gitea_auth.get_profile(): reads GITEA_PROFILE_NAME, GITEA_ALLOWED_OPERATIONS, GITEA_BASE_URL as non-secret metadata. Never reads/returns/logs the token. - gitea_whoami now surfaces the safe profile metadata (name + allowed operations) alongside identity; token still never exposed. - .env.example: placeholder-only template for a runtime profile. - .gitignore: track .env.example while keeping real .env* ignored. - README: document multiple env-configured MCP entries. - tests: profile defaults/parsing, token-never-included, whoami surfaces profile without leaking token. One token + one profile per process. No multi-token switching in a single runtime. No approve/merge/eligibility workflow. No Jenkins/Ops/GlitchTip/Release/deploy behavior. No real secrets. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+10
-1
@@ -36,6 +36,7 @@ from gitea_auth import ( # noqa: E402
|
||||
get_auth_header,
|
||||
api_request,
|
||||
repo_api_url,
|
||||
get_profile,
|
||||
)
|
||||
|
||||
mcp = FastMCP("gitea-tools", instructions=(
|
||||
@@ -617,7 +618,8 @@ def gitea_whoami(
|
||||
|
||||
Returns:
|
||||
dict with 'authenticated', 'username', 'display_name', 'user_id',
|
||||
'email', 'server', and 'remote'.
|
||||
'email', 'server', 'remote', and 'profile' (safe runtime profile
|
||||
metadata: profile_name + allowed_operations; never the token).
|
||||
"""
|
||||
if remote not in REMOTES:
|
||||
raise ValueError(f"Unknown remote '{remote}'. Choose from: {list(REMOTES)}")
|
||||
@@ -631,6 +633,9 @@ def gitea_whoami(
|
||||
f"Could not determine the authenticated Gitea identity for {h}. "
|
||||
"Verify the configured token is valid for this instance."
|
||||
)
|
||||
# Runtime profile metadata is non-secret (name + allowed op categories).
|
||||
# The token is resolved separately and is never included here.
|
||||
profile = get_profile()
|
||||
return {
|
||||
"authenticated": True,
|
||||
"username": data.get("login"),
|
||||
@@ -639,6 +644,10 @@ def gitea_whoami(
|
||||
"email": data.get("email") or None,
|
||||
"server": f"https://{h}",
|
||||
"remote": remote,
|
||||
"profile": {
|
||||
"profile_name": profile["profile_name"],
|
||||
"allowed_operations": profile["allowed_operations"],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user