Skip to content

Commit 4115e53

Browse files
committed
feat(gatekeeper): add Vertex AI support and refactor configuration
Add first-class support for the Vertex AI provider in the gatekeeper system. The configuration structure has been refactored to accommodate separate settings for each provider type.
1 parent e177829 commit 4115e53

23 files changed

Lines changed: 410 additions & 259 deletions

docs/config-reference.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,21 @@ These are used when `LINUX_MCP_TOOLSET` is set to `run_script` or `both`.
5858
| Option / Env Var | Default | Description |
5959
| ---------------- | ------- | ----------- |
6060
| `--always-confirm-scripts` / `--no-always-confirm-scripts`<br>`LINUX_MCP_ALWAYS_CONFIRM_SCRIPTS` | `False` | All scripts must be confirmed by the user |
61-
| `--gatekeeper.provider`<br>`LINUX_MCP_GATEKEEPER__PROVIDER` | `openai` (inferred from model if unset) | LLM provider: `openai`, `anthropic`, `gemini`, or `openrouter` |
62-
| `--gatekeeper.backend`<br>`LINUX_MCP_GATEKEEPER__BACKEND` | `direct` | API backend: `direct` or `vertex` (GCP/Vertex AI) |
61+
| `--gatekeeper.provider`<br>`LINUX_MCP_GATEKEEPER__PROVIDER` | `openai` (inferred from model if unset) | LLM provider: `openai`, `anthropic`, `gemini`, `openrouter`, or `vertex_ai` |
6362
| `--gatekeeper.model`<br>`LINUX_MCP_GATEKEEPER__MODEL` | _(none)_ | Required: provider-native model ID (e.g. `gpt-5.4`, `claude-sonnet-4-6`, `gemini-2.0-flash`, `openai/gpt-oss-120b` for OpenRouter) |
64-
| `--gatekeeper.quantization`<br>`LINUX_MCP_GATEKEEPER__QUANTIZATION` | _(none)_ | OpenRouter only: filter providers by quantization level (e.g. `fp4`, `bf16`) |
65-
| `--gatekeeper.base_url`<br>`LINUX_MCP_GATEKEEPER__BASE_URL` / `OPENAI_API_BASE` | `https://api.openai.com/v1` | OpenAI-compatible API base URL (OpenAI provider only) |
66-
| `--gatekeeper.project`<br>`LINUX_MCP_GATEKEEPER__PROJECT` / `VERTEXAI_PROJECT` | _(none)_ | GCP project for Vertex backends |
67-
| `--gatekeeper.location`<br>`LINUX_MCP_GATEKEEPER__LOCATION` / `VERTEXAI_LOCATION` | `global` | GCP region for Vertex backends |
6863
| `--gatekeeper.reasoning_effort`<br>`LINUX_MCP_GATEKEEPER__REASONING_EFFORT` | _(model specific)_ | Reasoning effort (`none`, `minimal`, `low`, `medium`, `high`, `xhigh`). Not all values are supported for all models. |
6964
| `--gatekeeper.structured_output`<br>`LINUX_MCP_GATEKEEPER__STRUCTURED_OUTPUT` | `True` | Whether to use structured JSON output from the model |
7065
| `--gatekeeper.temperature`<br>`LINUX_MCP_GATEKEEPER__TEMPERATURE` | 0.0 | Temperature to use for the model |
71-
| `--gatekeeper.template_kwargs`<br>`LINUX_MCP_GATEKEEPER__TEMPLATE_KWARGS` | _(none)_ | _Not usually needed_ - Extra chat-template arguments for OpenAI-compatible servers (e.g. llama.cpp `enable_thinking`), sent as `chat_template_kwargs` on Chat Completions requests. JSON object, e.g. `{ "enable_thinking": false }` |
72-
| Provider credentials | _(none)_ | `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_API_KEY` / `GEMINI_API_KEY`, or `OPENROUTER_API_KEY` for direct backends; `GOOGLE_APPLICATION_CREDENTIALS` for Vertex backends |
66+
| `--gatekeeper.cost`<br>`LINUX_MCP_GATEKEEPER__COST` | _(none)_ | Gatekeeper cost for accounting (`input$/token:output$/token`) |
67+
| `--gatekeeper.openai.base_url`<br>`LINUX_MCP_GATEKEEPER__OPENAI__BASE_URL` / `OPENAI_API_BASE` | `https://api.openai.com/v1` | OpenAI provider: API base URL |
68+
| `--gatekeeper.openai.template_kwargs`<br>`LINUX_MCP_GATEKEEPER__OPENAI__TEMPLATE_KWARGS` | _(none)_ | OpenAI provider: extra chat-template arguments (e.g. llama.cpp `enable_thinking`), sent as `chat_template_kwargs` |
69+
| `--gatekeeper.openrouter.base_url`<br>`LINUX_MCP_GATEKEEPER__OPENROUTER__BASE_URL` | `https://openrouter.ai/api/v1` | OpenRouter provider: API base URL |
70+
| `--gatekeeper.openrouter.quantization`<br>`LINUX_MCP_GATEKEEPER__OPENROUTER__QUANTIZATION` | _(none)_ | OpenRouter provider: filter providers by quantization level (e.g. `fp4`, `bf16`) |
71+
| `--gatekeeper.openrouter.template_kwargs`<br>`LINUX_MCP_GATEKEEPER__OPENROUTER__TEMPLATE_KWARGS` | _(none)_ | OpenRouter provider: extra chat-template arguments |
72+
| `--gatekeeper.vertex_ai.project`<br>`LINUX_MCP_GATEKEEPER__VERTEX_AI__PROJECT` / `VERTEXAI_PROJECT` | _(none)_ | Vertex AI provider: GCP project |
73+
| `--gatekeeper.vertex_ai.location`<br>`LINUX_MCP_GATEKEEPER__VERTEX_AI__LOCATION` / `VERTEXAI_LOCATION` | `global` | Vertex AI provider: GCP region |
74+
| `--gatekeeper.vertex_ai.base_url`<br>`LINUX_MCP_GATEKEEPER__VERTEX_AI__BASE_URL` | _(computed)_ | Vertex AI provider: override OpenAI-compatible MaaS endpoint URL (default derived from project/location) |
75+
| Provider credentials | _(none)_ | `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_API_KEY` / `GEMINI_API_KEY`, or `OPENROUTER_API_KEY` for direct providers; `GOOGLE_APPLICATION_CREDENTIALS` for `vertex_ai` |
7376

7477
## Logging Configuration
7578

docs/guarded-command-execution.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ LINUX_MCP_TOOLSET=run_script
108108

109109
Set `LINUX_MCP_GATEKEEPER__PROVIDER` and `LINUX_MCP_GATEKEEPER__MODEL` to configure the gatekeeper.
110110
Set the matching API credentials for your provider (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`,
111-
`GOOGLE_API_KEY`, or `OPENROUTER_API_KEY`). For Vertex AI backends, install the `gcp` extra and configure
111+
`GOOGLE_API_KEY`, or `OPENROUTER_API_KEY`). For the `vertex_ai` provider, install the `gcp` extra and configure
112112
`GOOGLE_APPLICATION_CREDENTIALS`, `VERTEXAI_PROJECT`, and `VERTEXAI_LOCATION`.
113113

114114
Example (OpenAI):
@@ -132,10 +132,19 @@ Example (OpenRouter):
132132
```sh
133133
LINUX_MCP_GATEKEEPER__PROVIDER=openrouter
134134
LINUX_MCP_GATEKEEPER__MODEL=openai/gpt-oss-120b
135-
LINUX_MCP_GATEKEEPER__QUANTIZATION=fp4
135+
LINUX_MCP_GATEKEEPER__OPENROUTER__QUANTIZATION=fp4
136136
OPENROUTER_API_KEY=<....>
137137
```
138138

139+
Example (Vertex AI):
140+
141+
```sh
142+
LINUX_MCP_GATEKEEPER__PROVIDER=vertex_ai
143+
LINUX_MCP_GATEKEEPER__MODEL=gemini-3.1-pro-preview
144+
LINUX_MCP_GATEKEEPER__VERTEX_AI__PROJECT=my-gcp-project
145+
GOOGLE_APPLICATION_CREDENTIALS=<path-to-service-account.json>
146+
```
147+
139148

140149
**Configure your client's tool policy**
141150

eval/gatekeeper/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ uv run eval/gatekeeper/run-eval.py testcases/selinux-port-denial.yaml -o results
7575
export OPENROUTER_API_KEY="..."
7676
./eval/gatekeeper/standard-evals.sh --no-save gpt-oss-120b:low,fp4@openrouter
7777
78+
# Run via standard-evals.sh (Vertex AI example)
79+
export VERTEXAI_PROJECT="my-gcp-project"
80+
./eval/gatekeeper/standard-evals.sh --no-save gemini-3.1-pro-preview:low@vertex_ai
81+
7882
# Run all test case files in testcases/
7983
uv run eval/gatekeeper/run-eval.py --all -o results.yaml
8084

eval/gatekeeper/standard-evals.sh

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -263,25 +263,23 @@ case "$provider" in
263263
anthropic)
264264
: "${ANTHROPIC_API_KEY:?'api key must be set'}"
265265
LINUX_MCP_GATEKEEPER__PROVIDER=anthropic
266-
LINUX_MCP_GATEKEEPER__BACKEND=direct
267266
LINUX_MCP_GATEKEEPER__MODEL="$model"
268267
;;
269268
llama_cpp)
270269
OPENAI_API_KEY=tasty
271270
LINUX_MCP_GATEKEEPER__PROVIDER=openai
272-
LINUX_MCP_GATEKEEPER__BACKEND=direct
273-
LINUX_MCP_GATEKEEPER__BASE_URL=http://localhost:8080/v1
271+
LINUX_MCP_GATEKEEPER__OPENAI__BASE_URL=http://localhost:8080/v1
274272
# gemma-4 and qwen3.5 support enable_thinking via chat_template_kwargs; granite-4 has no control
275273
case "$reasoning" in
276274
none)
277-
LINUX_MCP_GATEKEEPER__TEMPLATE_KWARGS='{ "enable_thinking": false }'
275+
LINUX_MCP_GATEKEEPER__OPENAI__TEMPLATE_KWARGS='{ "enable_thinking": false }'
278276
;;
279277
default)
280-
LINUX_MCP_GATEKEEPER__TEMPLATE_KWARGS='{ "enable_thinking": true }'
278+
LINUX_MCP_GATEKEEPER__OPENAI__TEMPLATE_KWARGS='{ "enable_thinking": true }'
281279
;;
282280
esac
283281
export OPENAI_API_KEY
284-
export LINUX_MCP_GATEKEEPER__BASE_URL
282+
export LINUX_MCP_GATEKEEPER__OPENAI__BASE_URL
285283
max_parallel=1
286284
quant_tag="${quantization^^}"
287285
case "$model" in
@@ -317,37 +315,25 @@ case "$provider" in
317315
: "${VERTEXAI_PROJECT:?'project must be set'}"
318316
uv_args+=("--extra" "gcp")
319317
max_parallel=50
320-
LINUX_MCP_GATEKEEPER__BACKEND=vertex
321-
vertex_location="${VERTEXAI_LOCATION:-global}"
322-
vertex_openapi_base="https://aiplatform.googleapis.com/v1/projects/${VERTEXAI_PROJECT}/locations/${vertex_location}/endpoints/openapi"
318+
LINUX_MCP_GATEKEEPER__PROVIDER=vertex_ai
319+
LINUX_MCP_GATEKEEPER__VERTEX_AI__PROJECT="${VERTEXAI_PROJECT}"
323320
case $model in
324-
claude-*)
325-
LINUX_MCP_GATEKEEPER__PROVIDER=anthropic
326-
LINUX_MCP_GATEKEEPER__MODEL="$model"
327-
;;
328-
gemini-*)
329-
LINUX_MCP_GATEKEEPER__PROVIDER=gemini
321+
claude-*|gemini-*)
330322
LINUX_MCP_GATEKEEPER__MODEL="$model"
331323
;;
332324
gemma-4-26b-a4b-it)
333325
if [[ $reasoning == "none" ]] ; then
334326
LINUX_MCP_GATEKEEPER__REASONING_EFFORT=
335327
fi
336-
LINUX_MCP_GATEKEEPER__PROVIDER=openai
337328
LINUX_MCP_GATEKEEPER__MODEL="${model}-maas"
338-
LINUX_MCP_GATEKEEPER__BASE_URL="${vertex_openapi_base}"
339329
LINUX_MCP_GATEKEEPER__COST=0.15e-6:0.60e-6
340330
;;
341331
gpt-oss-20b)
342-
LINUX_MCP_GATEKEEPER__PROVIDER=openai
343332
LINUX_MCP_GATEKEEPER__MODEL="${model}-maas"
344-
LINUX_MCP_GATEKEEPER__BASE_URL="${vertex_openapi_base}"
345333
LINUX_MCP_GATEKEEPER__COST="0.07e-6:0.25e-6"
346334
;;
347335
gpt-oss-120b)
348-
LINUX_MCP_GATEKEEPER__PROVIDER=openai
349336
LINUX_MCP_GATEKEEPER__MODEL="${model}-maas"
350-
LINUX_MCP_GATEKEEPER__BASE_URL="${vertex_openapi_base}"
351337
LINUX_MCP_GATEKEEPER__COST="0.09e-6:0.36e-6"
352338
;;
353339
esac
@@ -357,7 +343,6 @@ case "$provider" in
357343
SSL_CERT_FILE=${SSL_CERT_FILE:-/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem}
358344
export SSL_CERT_FILE
359345
LINUX_MCP_GATEKEEPER__PROVIDER=openai
360-
LINUX_MCP_GATEKEEPER__BACKEND=direct
361346
case $model in
362347
granite-*)
363348
LINUX_MCP_GATEKEEPER__MODEL="ibm-granite/$model"
@@ -366,15 +351,14 @@ case "$provider" in
366351
LINUX_MCP_GATEKEEPER__MODEL="openai/$model"
367352
;;
368353
esac
369-
LINUX_MCP_GATEKEEPER__BASE_URL="$(get_MC_base_url "$model")"
354+
LINUX_MCP_GATEKEEPER__OPENAI__BASE_URL="$(get_MC_base_url "$model")"
370355
max_parallel=5
371356
;;
372357
openrouter)
373358
: "${OPENROUTER_API_KEY:?'api key must be set'}"
374359
LINUX_MCP_GATEKEEPER__PROVIDER=openrouter
375-
LINUX_MCP_GATEKEEPER__BACKEND=direct
376360
if [[ -n $quantization ]] ; then
377-
LINUX_MCP_GATEKEEPER__QUANTIZATION=$quantization
361+
LINUX_MCP_GATEKEEPER__OPENROUTER__QUANTIZATION=$quantization
378362
fi
379363
case $model in
380364
claude-*)
@@ -399,11 +383,12 @@ case "$provider" in
399383
;;
400384
esac
401385

402-
export LINUX_MCP_GATEKEEPER__PROVIDER LINUX_MCP_GATEKEEPER__BACKEND LINUX_MCP_GATEKEEPER__MODEL
386+
export LINUX_MCP_GATEKEEPER__PROVIDER LINUX_MCP_GATEKEEPER__MODEL
403387
export LINUX_MCP_GATEKEEPER__COST LINUX_MCP_GATEKEEPER__REASONING_EFFORT
404-
[[ -n "${LINUX_MCP_GATEKEEPER__QUANTIZATION:-}" ]] && export LINUX_MCP_GATEKEEPER__QUANTIZATION
405-
[[ -n "${LINUX_MCP_GATEKEEPER__BASE_URL:-}" ]] && export LINUX_MCP_GATEKEEPER__BASE_URL
406-
[[ -n "${LINUX_MCP_GATEKEEPER__TEMPLATE_KWARGS:-}" ]] && export LINUX_MCP_GATEKEEPER__TEMPLATE_KWARGS
388+
[[ -n "${LINUX_MCP_GATEKEEPER__OPENROUTER__QUANTIZATION:-}" ]] && export LINUX_MCP_GATEKEEPER__OPENROUTER__QUANTIZATION
389+
[[ -n "${LINUX_MCP_GATEKEEPER__OPENAI__BASE_URL:-}" ]] && export LINUX_MCP_GATEKEEPER__OPENAI__BASE_URL
390+
[[ -n "${LINUX_MCP_GATEKEEPER__OPENAI__TEMPLATE_KWARGS:-}" ]] && export LINUX_MCP_GATEKEEPER__OPENAI__TEMPLATE_KWARGS
391+
[[ -n "${LINUX_MCP_GATEKEEPER__VERTEX_AI__PROJECT:-}" ]] && export LINUX_MCP_GATEKEEPER__VERTEX_AI__PROJECT
407392

408393
variant_suffix=""
409394
if [[ -n "$variant" ]] ; then

src/linux_mcp_server/config.py

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,7 @@ class GatekeeperProvider(StrEnum):
5555
ANTHROPIC = "anthropic"
5656
GEMINI = "gemini"
5757
OPENROUTER = "openrouter"
58-
59-
60-
class GatekeeperBackend(StrEnum):
61-
"""API backend for the gatekeeper provider."""
62-
63-
DIRECT = "direct"
64-
VERTEX = "vertex"
58+
VERTEX_AI = "vertex_ai"
6559

6660

6761
class AuthProvider(StrEnum):
@@ -129,39 +123,43 @@ def parse_cost(v: Any) -> Any:
129123
return v
130124

131125

132-
class GatekeeperConfig(BaseSettings):
133-
"""Gatekeeper Model configuration"""
126+
class OpenAIGatekeeperConfig(BaseSettings):
127+
"""OpenAI gatekeeper provider configuration."""
134128

135-
provider: GatekeeperProvider | None = None
136-
backend: GatekeeperBackend = GatekeeperBackend.DIRECT
137-
model: str | None = None
129+
base_url: str | None = None
130+
template_kwargs: dict[str, Any] = Field(default_factory=dict)
138131

139-
# Model quantization for OpenRouter provider routing (e.g. fp8, bf16)
140-
quantization: str | None = None
141132

142-
# OpenAI-compatible API base URL (OpenAI provider only)
133+
class OpenRouterGatekeeperConfig(BaseSettings):
134+
"""OpenRouter gatekeeper provider configuration."""
135+
143136
base_url: str | None = None
137+
quantization: str | None = None
138+
template_kwargs: dict[str, Any] = Field(default_factory=dict)
139+
140+
141+
class VertexAIGatekeeperConfig(BaseSettings):
142+
"""Vertex AI gatekeeper provider configuration."""
144143

145-
# GCP project and region for Vertex backends
146144
project: str | None = None
147145
location: str | None = None
146+
base_url: str | None = None
148147

149-
# reasoning effort
150-
reasoning_effort: ReasoningEffort | None = None
151148

152-
# Whether we should use structured output
153-
structured_output: bool = True
154-
155-
# Extra chat-template arguments for OpenAI-compatible servers (e.g. llama.cpp enable_thinking).
156-
# Passed as chat_template_kwargs on Chat Completions requests.
157-
template_kwargs: dict[str, Any] = Field(default_factory=dict)
149+
class GatekeeperConfig(BaseSettings):
150+
"""Gatekeeper Model configuration"""
158151

159-
# Temperature for gatekeeper model
152+
provider: GatekeeperProvider | None = None
153+
model: str | None = None
154+
reasoning_effort: ReasoningEffort | None = None
155+
structured_output: bool = True
160156
temperature: float = 0.0
161-
162-
# Gatekeeper cost for accounting (input $/token, output $/token)
163157
cost: Annotated[tuple[float, float] | None, BeforeValidator(parse_cost)] = None
164158

159+
openai: OpenAIGatekeeperConfig | None = None
160+
openrouter: OpenRouterGatekeeperConfig | None = None
161+
vertex_ai: VertexAIGatekeeperConfig | None = None
162+
165163

166164
class Config(BaseSettings):
167165
# The '_' is required in the env_prefix, otherwise, pydantic would

src/linux_mcp_server/gatekeeper/anthropic_client.py

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,10 @@
33
from typing import Any
44

55
from linux_mcp_server.config import CONFIG
6-
from linux_mcp_server.config import GatekeeperBackend
7-
from linux_mcp_server.gatekeeper.gcp_auth import get_gcp_access_token
8-
from linux_mcp_server.gatekeeper.gcp_auth import get_gcp_location
9-
from linux_mcp_server.gatekeeper.gcp_auth import get_gcp_project
106
from linux_mcp_server.gatekeeper.http_utils import ANTHROPIC_API_URL
117
from linux_mcp_server.gatekeeper.http_utils import ANTHROPIC_API_VERSION
128
from linux_mcp_server.gatekeeper.http_utils import ANTHROPIC_DEFAULT_MAX_TOKENS
139
from linux_mcp_server.gatekeeper.http_utils import anthropic_thinking_block
14-
from linux_mcp_server.gatekeeper.http_utils import ANTHROPIC_VERTEX_VERSION
1510
from linux_mcp_server.gatekeeper.http_utils import DEFAULT_TIMEOUT_SECONDS
1611
from linux_mcp_server.gatekeeper.http_utils import get_anthropic_api_key
1712
from linux_mcp_server.gatekeeper.http_utils import normalize_model_id
@@ -20,7 +15,7 @@
2015
from linux_mcp_server.gatekeeper.schema import anthropic_output_config
2116

2217

23-
def _build_messages_body(prompt: str, *, include_model: bool) -> dict[str, Any]:
18+
def build_messages_body(prompt: str, *, include_model: bool) -> dict[str, Any]:
2419
body: dict[str, Any] = {
2520
"max_tokens": ANTHROPIC_DEFAULT_MAX_TOKENS,
2621
"messages": [{"role": "user", "content": prompt}],
@@ -36,14 +31,7 @@ def _build_messages_body(prompt: str, *, include_model: bool) -> dict[str, Any]:
3631
return body
3732

3833

39-
def _vertex_url(model: str) -> str:
40-
project = get_gcp_project()
41-
location = get_gcp_location()
42-
host = "aiplatform.googleapis.com" if location == "global" else f"{location}-aiplatform.googleapis.com"
43-
return f"https://{host}/v1/projects/{project}/locations/{location}/publishers/anthropic/models/{model}:rawPredict"
44-
45-
46-
def _extract_messages_text(response: dict[str, Any]) -> str:
34+
def extract_messages_text(response: dict[str, Any]) -> str:
4735
for item in response.get("content", []):
4836
if isinstance(item, dict) and item.get("type") == "text":
4937
text = item.get("text")
@@ -53,24 +41,6 @@ def _extract_messages_text(response: dict[str, Any]) -> str:
5341

5442

5543
def complete_anthropic(prompt: str, *, timeout: int = DEFAULT_TIMEOUT_SECONDS) -> GatekeeperCompletion:
56-
model = normalize_model_id(CONFIG.gatekeeper.model or "")
57-
58-
if CONFIG.gatekeeper.backend == GatekeeperBackend.VERTEX:
59-
body = _build_messages_body(prompt, include_model=False)
60-
body["anthropic_version"] = ANTHROPIC_VERTEX_VERSION
61-
headers = {
62-
"Authorization": f"Bearer {get_gcp_access_token()}",
63-
"Content-Type": "application/json",
64-
}
65-
response = post_json(
66-
provider="anthropic",
67-
url=_vertex_url(model),
68-
headers=headers,
69-
body=body,
70-
timeout=timeout,
71-
)
72-
return GatekeeperCompletion(text=_extract_messages_text(response))
73-
7444
headers = {
7545
"x-api-key": get_anthropic_api_key(),
7646
"anthropic-version": ANTHROPIC_API_VERSION,
@@ -80,7 +50,7 @@ def complete_anthropic(prompt: str, *, timeout: int = DEFAULT_TIMEOUT_SECONDS) -
8050
provider="anthropic",
8151
url=ANTHROPIC_API_URL,
8252
headers=headers,
83-
body=_build_messages_body(prompt, include_model=True),
53+
body=build_messages_body(prompt, include_model=True),
8454
timeout=timeout,
8555
)
86-
return GatekeeperCompletion(text=_extract_messages_text(response))
56+
return GatekeeperCompletion(text=extract_messages_text(response))

src/linux_mcp_server/gatekeeper/gcp_auth.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,23 @@ class GCPAuthError(RuntimeError):
1010

1111

1212
def get_gcp_project() -> str:
13-
project = CONFIG.gatekeeper.project or os.environ.get("VERTEXAI_PROJECT") or os.environ.get("GOOGLE_CLOUD_PROJECT")
13+
vertex_ai = CONFIG.gatekeeper.vertex_ai
14+
project = (
15+
(vertex_ai.project if vertex_ai else None)
16+
or os.environ.get("VERTEXAI_PROJECT")
17+
or os.environ.get("GOOGLE_CLOUD_PROJECT")
18+
)
1419
if not project:
1520
raise GCPAuthError(
16-
"Vertex backend requires a GCP project. Set VERTEXAI_PROJECT, GOOGLE_CLOUD_PROJECT, "
17-
"or LINUX_MCP_GATEKEEPER__PROJECT."
21+
"Vertex AI provider requires a GCP project. Set VERTEXAI_PROJECT, GOOGLE_CLOUD_PROJECT, "
22+
"or LINUX_MCP_GATEKEEPER__VERTEX_AI__PROJECT."
1823
)
1924
return project
2025

2126

2227
def get_gcp_location() -> str:
23-
return CONFIG.gatekeeper.location or os.environ.get("VERTEXAI_LOCATION") or "global"
28+
vertex_ai = CONFIG.gatekeeper.vertex_ai
29+
return (vertex_ai.location if vertex_ai else None) or os.environ.get("VERTEXAI_LOCATION") or "global"
2430

2531

2632
def get_gcp_access_token() -> str:

0 commit comments

Comments
 (0)