Skip to content

Commit c4aa911

Browse files
shanemcdclaude
andauthored
feat: add Google Vertex AI support for Claude models (#146)
Add support for using Claude models via Google Cloud Vertex AI through the `google-vertex-anthropic` provider. This enables users who have Claude access through their Google Cloud account to use mcphost with Vertex AI authentication. Changes: - Add `google-vertex-anthropic` provider case and createVertexAnthropicProvider() - Support multiple env var names for project/region to match eino-claude: - Project: ANTHROPIC_VERTEX_PROJECT_ID, GOOGLE_CLOUD_PROJECT, GCLOUD_PROJECT - Region: CLOUD_ML_REGION (defaults to "global" if not set) - Upgrade eino from v0.5.11 to v0.7.11 (required by eino-claude v0.1.12) - Migrate schema API from OpenAPI v3 to JSON Schema (eino v0.7.11 change) Usage: # Authenticate with Google Cloud gcloud auth application-default login # Set required environment variables export ANTHROPIC_VERTEX_PROJECT_ID="your-project-id" export CLOUD_ML_REGION="us-east5" # or use default "global" # Run mcphost mcphost --model google-vertex-anthropic:claude-sonnet-4@20250514 Reference: https://docs.anthropic.com/en/docs/claude-code/google-vertex-ai 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <[email protected]>
1 parent 7ece291 commit c4aa911

File tree

7 files changed

+126
-33
lines changed

7 files changed

+126
-33
lines changed

go.mod

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ require (
1010
github.com/bytedance/sonic v1.14.1
1111
github.com/charmbracelet/fang v0.4.0
1212
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834
13-
github.com/cloudwego/eino v0.5.11
14-
github.com/cloudwego/eino-ext/components/model/claude v0.1.0
13+
github.com/cloudwego/eino v0.7.11
14+
github.com/cloudwego/eino-ext/components/model/claude v0.1.12
1515
github.com/cloudwego/eino-ext/components/model/ollama v0.1.2
1616
github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250903035842-96774a3ec845
17-
github.com/getkin/kin-openapi v0.120.0
17+
github.com/eino-contrib/jsonschema v1.0.3
1818
github.com/mark3labs/mcp-filesystem-server v0.11.1
1919
github.com/mark3labs/mcp-go v0.44.0-beta.2
2020
github.com/ollama/ollama v0.11.8
@@ -29,6 +29,7 @@ require (
2929
require (
3030
cloud.google.com/go v0.121.6 // indirect
3131
cloud.google.com/go/auth v0.16.5 // indirect
32+
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
3233
cloud.google.com/go/compute/metadata v0.8.0 // indirect
3334
github.com/alecthomas/chroma/v2 v2.20.0 // indirect
3435
github.com/andybalholm/cascadia v1.3.3 // indirect
@@ -65,11 +66,11 @@ require (
6566
github.com/djherbis/times v1.6.0 // indirect
6667
github.com/dlclark/regexp2 v1.11.5 // indirect
6768
github.com/dustin/go-humanize v1.0.1 // indirect
68-
github.com/eino-contrib/jsonschema v1.0.2 // indirect
6969
github.com/evanphx/json-patch v0.5.2 // indirect
7070
github.com/felixge/httpsnoop v1.0.4 // indirect
7171
github.com/fsnotify/fsnotify v1.9.0 // indirect
7272
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
73+
github.com/getkin/kin-openapi v0.120.0 // indirect
7374
github.com/go-logr/logr v1.4.3 // indirect
7475
github.com/go-logr/stdr v1.2.2 // indirect
7576
github.com/go-openapi/jsonpointer v0.22.0 // indirect
@@ -122,13 +123,17 @@ require (
122123
github.com/yuin/goldmark v1.7.13 // indirect
123124
github.com/yuin/goldmark-emoji v1.0.6 // indirect
124125
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
126+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
125127
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
126128
go.opentelemetry.io/otel v1.38.0 // indirect
127129
go.opentelemetry.io/otel/metric v1.38.0 // indirect
128130
go.opentelemetry.io/otel/trace v1.38.0 // indirect
129131
golang.org/x/arch v0.20.0 // indirect
130132
golang.org/x/crypto v0.41.0 // indirect
131133
golang.org/x/net v0.43.0 // indirect
134+
golang.org/x/oauth2 v0.30.0 // indirect
135+
golang.org/x/time v0.12.0 // indirect
136+
google.golang.org/api v0.246.0 // indirect
132137
google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect
133138
google.golang.org/grpc v1.75.0 // indirect
134139
google.golang.org/protobuf v1.36.8 // indirect

go.sum

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
22
cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI=
33
cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI=
44
cloud.google.com/go/auth v0.16.5/go.mod h1:utzRfHMP+Vv0mpOkTRQoWD2q3BatTOoWbA7gCc2dUhQ=
5+
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
6+
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
57
cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA=
68
cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw=
79
github.com/JohannesKaufmann/html-to-markdown v1.6.0 h1:04VXMiE50YYfCfLboJCLcgqF5x+rHJnb1ssNmqpLH/k=
@@ -108,10 +110,10 @@ github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQ
108110
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
109111
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
110112
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
111-
github.com/cloudwego/eino v0.5.11 h1:R/BPZJPiMrGm1kA4ql2T0P8SlqLC16Pbxev+v6a6AGY=
112-
github.com/cloudwego/eino v0.5.11/go.mod h1:N6E+toMzWw/3ql0IVM5n5lbYFCeblCYx7ebH16kt1JQ=
113-
github.com/cloudwego/eino-ext/components/model/claude v0.1.0 h1:UZVwYzV7gOBCBKHGdAT2fZzm/+2TBEfDDYn713EvLF0=
114-
github.com/cloudwego/eino-ext/components/model/claude v0.1.0/go.mod h1:lacy0WE3yKuOSxrhJQKqWAxn3LiUy/CJ91jU7nLDNNQ=
113+
github.com/cloudwego/eino v0.7.11 h1:QQ3Ik4/nW1462CuvFsmH3gWAqNI/70BXRDmsYyvXyds=
114+
github.com/cloudwego/eino v0.7.11/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ=
115+
github.com/cloudwego/eino-ext/components/model/claude v0.1.12 h1:c66gFH9J5Ku2/v1f7jPwI9R4CYw5TiAlIVzsfzjsF1g=
116+
github.com/cloudwego/eino-ext/components/model/claude v0.1.12/go.mod h1:a9oQkf4Ib+/VqjsLRdRETytt2m/C4fbcvfjPNu6nVAg=
115117
github.com/cloudwego/eino-ext/components/model/ollama v0.1.2 h1:WxJ+7oXnr3AhM6u4VbFF3L2ionxCrPfmLetx7V+zthw=
116118
github.com/cloudwego/eino-ext/components/model/ollama v0.1.2/go.mod h1:OgGMCiR/G/RnOWaJvdK8pVSxAzoz2SlCqim43oFTuwo=
117119
github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250903035842-96774a3ec845 h1:nxflfiBwWNPoKS9X4SMhmT+si7rtYv+lQzIyPJik4DM=
@@ -128,8 +130,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ
128130
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
129131
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
130132
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
131-
github.com/eino-contrib/jsonschema v1.0.2 h1:HaxruBMUdnXa7Lg/lX8g0Hk71ZIfdTZXmBQz0e3esr8=
132-
github.com/eino-contrib/jsonschema v1.0.2/go.mod h1:cpnX4SyKjWjGC7iN2EbhxaTdLqGjCi0e9DxpLYxddD4=
133+
github.com/eino-contrib/jsonschema v1.0.3 h1:2Kfsm1xlMV0ssY2nuxshS4AwbLFuqmPmzIjLVJ1Fsp0=
134+
github.com/eino-contrib/jsonschema v1.0.3/go.mod h1:cpnX4SyKjWjGC7iN2EbhxaTdLqGjCi0e9DxpLYxddD4=
133135
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
134136
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
135137
github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
@@ -361,6 +363,8 @@ github.com/yuin/goldmark-emoji v1.0.6 h1:QWfF2FYaXwL74tfGOW5izeiZepUDroDJfWubQI9
361363
github.com/yuin/goldmark-emoji v1.0.6/go.mod h1:ukxJDKFpdFb5x0a5HqbdlcKtebh086iJpI31LTKmWuA=
362364
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
363365
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
366+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
367+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
364368
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
365369
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
366370
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
@@ -408,6 +412,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
408412
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
409413
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
410414
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
415+
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
416+
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
411417
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
412418
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
413419
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -463,6 +469,8 @@ golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
463469
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
464470
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
465471
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
472+
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
473+
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
466474
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
467475
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
468476
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
@@ -472,6 +480,8 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb
472480
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
473481
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
474482
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
483+
google.golang.org/api v0.246.0 h1:H0ODDs5PnMZVZAEtdLMn2Ul2eQi7QNjqM2DIFp8TlTM=
484+
google.golang.org/api v0.246.0/go.mod h1:dMVhVcylamkirHdzEBAIQWUCgqY885ivNeZYd7VAVr8=
475485
google.golang.org/genai v1.22.0 h1:5hrEhXXWJQZa3tdPocl4vQ/0w6myEAxdNns2Kmx0f4Y=
476486
google.golang.org/genai v1.22.0/go.mod h1:QPj5NGJw+3wEOHg+PrsWwJKvG6UC84ex5FR7qAYsN/M=
477487
google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 h1:pmJpJEvT846VzausCQ5d7KreSROcDqmO388w5YbnltA=

internal/models/gemini/gemini.go

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/cloudwego/eino/components"
1212
"github.com/cloudwego/eino/components/model"
1313
"github.com/cloudwego/eino/schema"
14+
"github.com/eino-contrib/jsonschema"
1415
"github.com/getkin/kin-openapi/openapi3"
1516
"google.golang.org/genai"
1617
)
@@ -83,7 +84,7 @@ type Config struct {
8384

8485
// ResponseSchema defines the structure for JSON responses
8586
// Optional. Used when you want structured output in JSON format
86-
ResponseSchema *openapi3.Schema
87+
ResponseSchema *jsonschema.Schema
8788

8889
// EnableCodeExecution allows the model to execute code
8990
// Warning: Be cautious with code execution in production
@@ -103,7 +104,7 @@ type options struct {
103104
// TopK limits the number of tokens to sample from
104105
TopK *int32
105106
// ResponseSchema defines the expected JSON structure for responses
106-
ResponseSchema *openapi3.Schema
107+
ResponseSchema *jsonschema.Schema
107108
}
108109

109110
// ChatModel implements the Gemini chat model for the eino framework.
@@ -124,7 +125,7 @@ type ChatModel struct {
124125
// topK limits token sampling
125126
topK *int32
126127
// responseSchema for structured JSON output
127-
responseSchema *openapi3.Schema
128+
responseSchema *jsonschema.Schema
128129
// tools converted to Gemini format
129130
tools []*genai.Tool
130131
// origTools stores the original tool definitions
@@ -448,7 +449,7 @@ func (cm *ChatModel) buildGenerateConfig(opts ...model.Option) (*genai.GenerateC
448449

449450
// Set response schema for JSON mode
450451
if geminiOptions.ResponseSchema != nil {
451-
gSchema, err := cm.convertOpenAPISchema(geminiOptions.ResponseSchema)
452+
gSchema, err := cm.convertJSONSchema(geminiOptions.ResponseSchema)
452453
if err != nil {
453454
return nil, nil, fmt.Errorf("convert response schema failed: %w", err)
454455
}
@@ -466,12 +467,12 @@ func (cm *ChatModel) convertToGeminiTools(tools []*schema.ToolInfo) ([]*genai.To
466467

467468
var functionDeclarations []*genai.FunctionDeclaration
468469
for _, tool := range tools {
469-
openSchema, err := tool.ToOpenAPIV3()
470+
openSchema, err := tool.ToJSONSchema()
470471
if err != nil {
471472
return nil, fmt.Errorf("get open schema failed: %w", err)
472473
}
473474

474-
gSchema, err := cm.convertOpenAPISchema(openSchema)
475+
gSchema, err := cm.convertJSONSchema(openSchema)
475476
if err != nil {
476477
return nil, fmt.Errorf("convert open schema failed: %w", err)
477478
}
@@ -487,7 +488,7 @@ func (cm *ChatModel) convertToGeminiTools(tools []*schema.ToolInfo) ([]*genai.To
487488
return []*genai.Tool{{FunctionDeclarations: functionDeclarations}}, nil
488489
}
489490

490-
func (cm *ChatModel) convertOpenAPISchema(schema *openapi3.Schema) (*genai.Schema, error) {
491+
func (cm *ChatModel) convertJSONSchema(schema *jsonschema.Schema) (*genai.Schema, error) {
491492
if schema == nil {
492493
return nil, nil
493494
}
@@ -501,15 +502,12 @@ func (cm *ChatModel) convertOpenAPISchema(schema *openapi3.Schema) (*genai.Schem
501502
result.Type = genai.TypeObject
502503
if schema.Properties != nil {
503504
properties := make(map[string]*genai.Schema)
504-
for name, prop := range schema.Properties {
505-
if prop == nil || prop.Value == nil {
506-
continue
507-
}
508-
propSchema, err := cm.convertOpenAPISchema(prop.Value)
505+
for pair := schema.Properties.Oldest(); pair != nil; pair = pair.Next() {
506+
propSchema, err := cm.convertJSONSchema(pair.Value)
509507
if err != nil {
510508
return nil, err
511509
}
512-
properties[name] = propSchema
510+
properties[pair.Key] = propSchema
513511
}
514512
result.Properties = properties
515513
}
@@ -518,8 +516,8 @@ func (cm *ChatModel) convertOpenAPISchema(schema *openapi3.Schema) (*genai.Schem
518516
}
519517
case openapi3.TypeArray:
520518
result.Type = genai.TypeArray
521-
if schema.Items != nil && schema.Items.Value != nil {
522-
itemSchema, err := cm.convertOpenAPISchema(schema.Items.Value)
519+
if schema.Items != nil {
520+
itemSchema, err := cm.convertJSONSchema(schema.Items)
523521
if err != nil {
524522
return nil, err
525523
}

internal/models/providers.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,12 @@ func CreateProvider(ctx context.Context, config *ProviderConfig) (*ProviderResul
218218
return nil, err
219219
}
220220
return &ProviderResult{Model: model, Message: ""}, nil
221+
case "google-vertex-anthropic":
222+
model, err := createVertexAnthropicProvider(ctx, config, modelName)
223+
if err != nil {
224+
return nil, err
225+
}
226+
return &ProviderResult{Model: model, Message: ""}, nil
221227
default:
222228
return nil, fmt.Errorf("unsupported provider: %s", provider)
223229
}
@@ -350,6 +356,67 @@ func createAnthropicProvider(ctx context.Context, config *ProviderConfig, modelN
350356
return anthropic.NewCustomChatModel(ctx, claudeConfig)
351357
}
352358

359+
func createVertexAnthropicProvider(ctx context.Context, config *ProviderConfig, modelName string) (model.ToolCallingChatModel, error) {
360+
projectID := os.Getenv("GOOGLE_VERTEX_PROJECT")
361+
if projectID == "" {
362+
projectID = os.Getenv("ANTHROPIC_VERTEX_PROJECT_ID")
363+
}
364+
if projectID == "" {
365+
projectID = os.Getenv("GOOGLE_CLOUD_PROJECT")
366+
}
367+
if projectID == "" {
368+
projectID = os.Getenv("GCLOUD_PROJECT")
369+
}
370+
if projectID == "" {
371+
projectID = os.Getenv("CLOUDSDK_CORE_PROJECT")
372+
}
373+
if projectID == "" {
374+
return nil, fmt.Errorf("Google Vertex project ID not provided. Set ANTHROPIC_VERTEX_PROJECT_ID, GOOGLE_CLOUD_PROJECT, or GCLOUD_PROJECT environment variable")
375+
}
376+
377+
region := os.Getenv("GOOGLE_VERTEX_LOCATION")
378+
if region == "" {
379+
region = os.Getenv("ANTHROPIC_VERTEX_REGION")
380+
}
381+
if region == "" {
382+
region = os.Getenv("CLOUD_ML_REGION")
383+
}
384+
if region == "" {
385+
region = "global"
386+
}
387+
388+
maxTokens := config.MaxTokens
389+
if maxTokens == 0 {
390+
maxTokens = 4096 // Default value
391+
}
392+
393+
claudeConfig := &einoclaude.Config{
394+
ByVertex: true,
395+
VertexProjectID: projectID,
396+
VertexRegion: region,
397+
Model: modelName,
398+
MaxTokens: maxTokens,
399+
}
400+
401+
if config.Temperature != nil {
402+
claudeConfig.Temperature = config.Temperature
403+
}
404+
405+
if config.TopP != nil {
406+
claudeConfig.TopP = config.TopP
407+
}
408+
409+
if config.TopK != nil {
410+
claudeConfig.TopK = config.TopK
411+
}
412+
413+
if len(config.StopSequences) > 0 {
414+
claudeConfig.StopSequences = config.StopSequences
415+
}
416+
417+
return anthropic.NewCustomChatModel(ctx, claudeConfig)
418+
}
419+
353420
func createOpenAIProvider(ctx context.Context, config *ProviderConfig, modelName string) (model.ToolCallingChatModel, error) {
354421
apiKey := config.ProviderAPIKey
355422
if apiKey == "" {

internal/models/registry.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,19 @@ func (r *ModelsRegistry) ValidateEnvironment(provider string, apiKey string) err
100100
return nil
101101
}
102102

103+
// Add alternative environment variable names for google-vertex-anthropic
104+
// These match the env vars checked by eino-claude and other tools
105+
if provider == "google-vertex-anthropic" {
106+
envVars = append(envVars,
107+
"ANTHROPIC_VERTEX_PROJECT_ID",
108+
"GOOGLE_CLOUD_PROJECT",
109+
"GCLOUD_PROJECT",
110+
"CLOUDSDK_CORE_PROJECT",
111+
"ANTHROPIC_VERTEX_REGION",
112+
"CLOUD_ML_REGION",
113+
)
114+
}
115+
103116
// Check if at least one environment variable is set
104117
var foundVar bool
105118
for _, envVar := range envVars {

internal/tools/mcp.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"github.com/cloudwego/eino/components/model"
1212
"github.com/cloudwego/eino/components/tool"
1313
"github.com/cloudwego/eino/schema"
14-
"github.com/getkin/kin-openapi/openapi3"
14+
"github.com/eino-contrib/jsonschema"
1515
"github.com/mark3labs/mcp-go/client"
1616
"github.com/mark3labs/mcp-go/client/transport"
1717
"github.com/mark3labs/mcp-go/mcp"
@@ -228,7 +228,7 @@ func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string,
228228
// Pre-process the schema to convert numeric exclusive bounds to boolean format.
229229
marshaledInputSchema = convertExclusiveBoundsToBoolean(marshaledInputSchema)
230230

231-
inputSchema := &openapi3.Schema{}
231+
inputSchema := &jsonschema.Schema{}
232232
err = sonic.Unmarshal(marshaledInputSchema, inputSchema)
233233
if err != nil {
234234
return fmt.Errorf("conv mcp tool input schema fail(unmarshal): %w, tool name: %s", err, mcpTool.Name)
@@ -238,7 +238,7 @@ func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string,
238238
// OpenAI function calling requires object schemas to have a "properties" field
239239
// even if it's empty, otherwise it throws "object schema missing properties" error
240240
if inputSchema.Type == "object" && inputSchema.Properties == nil {
241-
inputSchema.Properties = make(openapi3.Schemas)
241+
inputSchema.Properties = jsonschema.NewProperties()
242242
}
243243

244244
// Create prefixed tool name
@@ -258,7 +258,7 @@ func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string,
258258
info: &schema.ToolInfo{
259259
Name: prefixedName,
260260
Desc: mcpTool.Description,
261-
ParamsOneOf: schema.NewParamsOneOfByOpenAPIV3(inputSchema),
261+
ParamsOneOf: schema.NewParamsOneOfByJSONSchema(inputSchema),
262262
},
263263
mapping: mapping,
264264
}

internal/tools/mcp_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"time"
88

99
"github.com/cloudwego/eino/schema"
10-
"github.com/getkin/kin-openapi/openapi3"
10+
"github.com/eino-contrib/jsonschema"
1111
"github.com/mark3labs/mcphost/internal/config"
1212
)
1313

@@ -132,7 +132,7 @@ func TestMCPToolManager_ToolWithoutProperties(t *testing.T) {
132132
func TestIssue89_ObjectSchemaMissingProperties(t *testing.T) {
133133
// Create a schema that would cause the OpenAI validation error
134134
// This simulates what might happen with tools that have no input properties
135-
brokenSchema := &openapi3.Schema{
135+
brokenSchema := &jsonschema.Schema{
136136
Type: "object",
137137
// Properties is nil - this causes "object schema missing properties" error in OpenAI
138138
}
@@ -144,7 +144,7 @@ func TestIssue89_ObjectSchemaMissingProperties(t *testing.T) {
144144

145145
// Apply the fix from issue #89
146146
if brokenSchema.Type == "object" && brokenSchema.Properties == nil {
147-
brokenSchema.Properties = make(openapi3.Schemas)
147+
brokenSchema.Properties = jsonschema.NewProperties()
148148
}
149149

150150
// Verify the fix worked
@@ -154,7 +154,7 @@ func TestIssue89_ObjectSchemaMissingProperties(t *testing.T) {
154154

155155
// Test that we can create a ParamsOneOf from the fixed schema
156156
// This is what would fail before the fix
157-
paramsOneOf := schema.NewParamsOneOfByOpenAPIV3(brokenSchema)
157+
paramsOneOf := schema.NewParamsOneOfByJSONSchema(brokenSchema)
158158
if paramsOneOf == nil {
159159
t.Error("Failed to create ParamsOneOf from fixed schema - OpenAI function calling would fail")
160160
}

0 commit comments

Comments
 (0)