Support the canonical contexts-shape version 2 config (contexts / profiles /
projects / rules) alongside the existing environments shape and v1:
- Require a boolean 'enabled' on every context, profile, service, and
project. Disabled entries are surfaced in audits but fail closed at
selection/resolution — never a silent fallback to another profile,
service, or credential source.
- Resolve the active identity from GITEA_MCP_PROFILE via the existing
select_profile path; profile base_url falls back to the context's enabled
gitea block.
- Add resolve_service() and project_for_path() for context service and
project-to-context resolution (internal use; fail closed on disabled).
- get_auth_header now propagates ConfigError when GITEA_MCP_CONFIG is set
instead of silently degrading to Basic auth.
- Hide endpoint URLs and keychain ids from normal LLM-facing output:
gitea_whoami / gitea_get_profile report logical names and auth status
only; new gitea_audit_config tool reports enabled/disabled state and safe
one-line service summaries. The GITEA_MCP_REVEAL_ENDPOINTS opt-in (and
'python3 gitea_config.py audit --reveal-endpoints' locally) restores
endpoints and auth source names for admin diagnostics; token values are
never printed on any path.
- Ship gitea-mcp.v2-contexts.example.json (synthetic values) and validate
it in tests.
Implements #120
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Let one MCP server select among named Gitea runtime profiles from a JSON file
instead of editing code or juggling many .env files:
GITEA_MCP_CONFIG=/path/to/gitea-mcp.json
GITEA_MCP_PROFILE=dev
- New gitea_config.py: load/validate the JSON, select the named profile, and
resolve its token by env-var reference. Profiles supply base_url,
profile_name, token_env, owner/repo, allowed/forbidden operations, and audit
label.
- gitea_auth.get_profile() now overlays env over the selected JSON profile:
explicit env vars win, the JSON profile fills only what env leaves unset.
- gitea_auth.get_auth_header() gains a JSON token_env fallback after explicit
env tokens (env still wins).
Security / safety:
- Tokens are referenced by env-var NAME (token_env); an inline "token" is
rejected and never echoed. The value is never stored in or returned as
profile metadata.
- Fail-safe errors: missing file / invalid JSON / unknown or unset selected
profile raise a clear ConfigError that never prints file contents or tokens
(JSONDecodeError context is suppressed so the raw file text can't surface).
- No network calls during config parsing.
- Real config files are gitignored (gitea-mcp*.json), example kept.
Backwards compatible: with GITEA_MCP_CONFIG unset, behaviour is exactly the
prior env-only behaviour (all existing get_profile/get_auth_header tests pass
unchanged).
Docs: README JSON-profiles section + env table rows, .env.example placeholders,
gitea-mcp.example.json.
Tests: tests/test_config.py (22 cases) — env-only, selection, multiple
profiles, env-override precedence, missing file, invalid JSON, missing/unset
profile, inline-token rejection + redaction, and no-network-during-parse.
Refs #10. Note: issue #19 (env-based profiles) was already implemented and
closed; this JSON-file capability is adjacent new scope tracked under the
roadmap rather than reopening #19.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>