diff --git a/cmd/fetch-api/main.go b/cmd/fetch-api/main.go index b2ea53e..7ff2bf9 100644 --- a/cmd/fetch-api/main.go +++ b/cmd/fetch-api/main.go @@ -71,6 +71,7 @@ func main() { }) mux.Handle("/", app.LoggerMiddleware(app.PanicRecoveryMiddleware(playground.Handler("GraphQL playground", "/query")))) mux.Handle("/query", application.Handler) + mux.Handle("/mcp", application.MCPHandler) logger.Info().Msgf("Server started on port: %d", cfg.Port) runner.RunHandler(runnerCtx, runnerGroup, mux, ":"+strconv.Itoa(cfg.Port)) diff --git a/go.mod b/go.mod index 07d8a31..e169bd0 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,11 @@ module github.com/DIMO-Network/fetch-api go 1.25.0 require ( - github.com/99designs/gqlgen v0.17.86 + github.com/99designs/gqlgen v0.17.89 github.com/ClickHouse/clickhouse-go/v2 v2.43.0 github.com/DIMO-Network/clickhouse-infra v0.0.7 github.com/DIMO-Network/cloudevent v0.2.7 - github.com/DIMO-Network/server-garage v0.0.7 + github.com/DIMO-Network/server-garage v0.1.0 github.com/DIMO-Network/shared v1.1.7 github.com/DIMO-Network/token-exchange-api v0.4.0 github.com/auth0/go-jwt-middleware/v2 v2.2.2 @@ -19,12 +19,13 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 + github.com/modelcontextprotocol/go-sdk v1.4.1 github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 - github.com/vektah/gqlparser/v2 v2.5.31 + github.com/vektah/gqlparser/v2 v2.5.32 github.com/volatiletech/sqlboiler/v4 v4.19.1 go.uber.org/mock v0.6.0 - golang.org/x/sync v0.19.0 + golang.org/x/sync v0.20.0 google.golang.org/grpc v1.79.3 google.golang.org/protobuf v1.36.11 ) @@ -50,6 +51,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect @@ -69,20 +71,21 @@ require ( github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/goccy/go-yaml v1.19.2 // indirect github.com/gofiber/fiber/v2 v2.52.12 // indirect - github.com/golang-jwt/jwt/v5 v5.3.0 // indirect + github.com/golang-jwt/jwt/v5 v5.3.1 // indirect + github.com/google/jsonschema-go v0.4.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.1 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/holiman/uint256 v1.3.2 // indirect - github.com/klauspost/compress v1.18.4 // indirect + github.com/klauspost/compress v1.18.5 // indirect github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect github.com/magiconair/properties v1.8.10 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mattn/go-runewidth v0.0.21 // indirect github.com/mdelapenya/tlscert v0.2.0 // indirect github.com/mfridman/interpolate v0.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect @@ -105,17 +108,17 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/pressly/goose/v3 v3.27.0 // indirect - github.com/prometheus/client_golang v1.23.0 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.65.0 // indirect - github.com/prometheus/procfs v0.19.2 // indirect - github.com/rivo/uniseg v0.4.7 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/procfs v0.20.1 // indirect github.com/segmentio/asm v1.2.1 // indirect + github.com/segmentio/encoding v0.5.4 // indirect github.com/sethvargo/go-retry v0.3.0 // indirect github.com/shirou/gopsutil/v4 v4.25.6 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/sosodev/duration v1.3.1 // indirect + github.com/sosodev/duration v1.4.0 // indirect github.com/spf13/cast v1.7.0 // indirect github.com/testcontainers/testcontainers-go v0.40.0 // indirect github.com/testcontainers/testcontainers-go/modules/clickhouse v0.38.0 // indirect @@ -125,11 +128,12 @@ require ( github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect github.com/twpayne/go-geom v1.6.1 // indirect - github.com/urfave/cli/v3 v3.6.1 // indirect + github.com/urfave/cli/v3 v3.7.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.65.0 // indirect + github.com/valyala/fasthttp v1.69.0 // indirect github.com/volatiletech/inflect v0.0.1 // indirect github.com/volatiletech/strmangle v0.0.7-0.20240503230658-86517898275a // indirect + github.com/yosida95/uritemplate/v3 v3.0.2 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect @@ -137,12 +141,14 @@ require ( go.opentelemetry.io/otel/metric v1.42.0 // indirect go.opentelemetry.io/otel/trace v1.42.0 // indirect go.uber.org/multierr v1.11.0 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.48.0 // indirect + golang.org/x/crypto v0.49.0 // indirect golang.org/x/mod v0.33.0 // indirect - golang.org/x/net v0.50.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/text v0.34.0 // indirect + golang.org/x/net v0.51.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect golang.org/x/tools v0.42.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect diff --git a/go.sum b/go.sum index 7432874..36f20cb 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= -github.com/99designs/gqlgen v0.17.86 h1:C8N3UTa5heXX6twl+b0AJyGkTwYL6dNmFrgZNLRcU6w= -github.com/99designs/gqlgen v0.17.86/go.mod h1:KTrPl+vHA1IUzNlh4EYkl7+tcErL3MgKnhHrBcV74Fw= +github.com/99designs/gqlgen v0.17.89 h1:KzEcxPiMgQoMw3m/E85atUEHyZyt0PbAflMia5Kw8z8= +github.com/99designs/gqlgen v0.17.89/go.mod h1:GFqruTVGB7ZTdrf1uzOagpXbY7DrEt1pIxnTdhIbWvQ= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= @@ -18,8 +18,8 @@ github.com/DIMO-Network/clickhouse-infra v0.0.7 h1:TAsjkFFKu3D5Xg6dwBcRBryjCVSlX github.com/DIMO-Network/clickhouse-infra v0.0.7/go.mod h1:XS80lhSJNWBWGgZ+m4j7++zFj1wAXfmtV2gJfhGlabQ= github.com/DIMO-Network/cloudevent v0.2.7 h1:/cgFhUcWcliZYrmITkB8oIZb+zDhZvYNxWVGS2D3894= github.com/DIMO-Network/cloudevent v0.2.7/go.mod h1:I/9NcpMozV5Fw194WimhbkAsJtKVZf5UKYJ9hgc8Cdg= -github.com/DIMO-Network/server-garage v0.0.7 h1:kOBVyOtIbxa1x9pAf1epABTb9l/U3khf0PwUaHeHiKs= -github.com/DIMO-Network/server-garage v0.0.7/go.mod h1:7DFor8MMJ8fLv9EB16Z5LrN+ftW3qeIk+swpkT7F2cU= +github.com/DIMO-Network/server-garage v0.1.0 h1:AglbxOj0duQz/4Et2eSh+pPEq3qOfInREBycIJEBOTs= +github.com/DIMO-Network/server-garage v0.1.0/go.mod h1:Z3A1KDUsXey+XhrPhmw/wyCidfrQvmEdWp7nShno7ZM= github.com/DIMO-Network/shared v1.1.7 h1:5Ex8bZ6BpOjcLj4u7n5Kih1Ho6b9BVJsKpKn4iU2EaM= github.com/DIMO-Network/shared v1.1.7/go.mod h1:lDHUKwwT2LW6Zvd42Nb33dXklRNTmfyOlbUNx2dQfGY= github.com/DIMO-Network/token-exchange-api v0.4.0 h1:EayDrw9VdyAfc6rbpdnDxFhlN3lMhbonUJoouKZu35g= @@ -83,6 +83,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= @@ -146,8 +148,8 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= -github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -157,8 +159,8 @@ github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1 github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= -github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -173,6 +175,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8= +github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= @@ -194,8 +198,8 @@ github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXei github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= -github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= +github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -217,8 +221,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w= +github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI= github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o= github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= @@ -239,6 +243,8 @@ github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= +github.com/modelcontextprotocol/go-sdk v1.4.1 h1:M4x9GyIPj+HoIlHNGpK2hq5o3BFhC+78PkEaldQRphc= +github.com/modelcontextprotocol/go-sdk v1.4.1/go.mod h1:Bo/mS87hPQqHSRkMv4dQq1XCu6zv4INdXnFZabkNU6s= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= @@ -272,20 +278,17 @@ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/pressly/goose/v3 v3.27.0 h1:/D30gVTuQhu0WsNZYbJi4DMOsx1lNq+6SkLe+Wp59BM= github.com/pressly/goose/v3 v3.27.0/go.mod h1:3ZBeCXqzkgIRvrEMDkYh1guvtoJTU5oMMuDdkutoM78= -github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc= -github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= -github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= -github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= -github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= @@ -293,6 +296,8 @@ github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfvNt0= +github.com/segmentio/encoding v0.5.4/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= @@ -304,8 +309,8 @@ github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+D github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4= -github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= +github.com/sosodev/duration v1.4.0 h1:35ed0KiVFriGHHzZZJaZLgmTEEICIyt8Sx0RQfj9IjE= +github.com/sosodev/duration v1.4.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -338,14 +343,14 @@ github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfj github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/twpayne/go-geom v1.6.1 h1:iLE+Opv0Ihm/ABIcvQFGIiFBXd76oBIar9drAwHFhR4= github.com/twpayne/go-geom v1.6.1/go.mod h1:Kr+Nly6BswFsKM5sd31YaoWS5PeDDH2NftJTK7Gd028= -github.com/urfave/cli/v3 v3.6.1 h1:j8Qq8NyUawj/7rTYdBGrxcH7A/j7/G8Q5LhWEW4G3Mo= -github.com/urfave/cli/v3 v3.6.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= +github.com/urfave/cli/v3 v3.7.0 h1:AGSnbUyjtLiM+WJUb4dzXKldl/gL+F8OwmRDtVr6g2U= +github.com/urfave/cli/v3 v3.7.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.65.0 h1:j/u3uzFEGFfRxw79iYzJN+TteTJwbYkru9uDp3d0Yf8= -github.com/valyala/fasthttp v1.65.0/go.mod h1:P/93/YkKPMsKSnATEeELUCkG8a7Y+k99uxNHVbKINr4= -github.com/vektah/gqlparser/v2 v2.5.31 h1:YhWGA1mfTjID7qJhd1+Vxhpk5HTgydrGU9IgkWBTJ7k= -github.com/vektah/gqlparser/v2 v2.5.31/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts= +github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZyVI= +github.com/valyala/fasthttp v1.69.0/go.mod h1:4wA4PfAraPlAsJ5jMSqCE2ug5tqUPwKXxVj8oNECGcw= +github.com/vektah/gqlparser/v2 v2.5.32 h1:k9QPJd4sEDTL+qB4ncPLflqTJ3MmjB9SrVzJrawpFSc= +github.com/vektah/gqlparser/v2 v2.5.32/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts= github.com/volatiletech/inflect v0.0.1 h1:2a6FcMQyhmPZcLa+uet3VJ8gLn/9svWhJxJYwvE8KsU= github.com/volatiletech/inflect v0.0.1/go.mod h1:IBti31tG6phkHitLlr5j7shC5SOo//x0AjDzaJU1PLA= github.com/volatiletech/null/v8 v8.1.2 h1:kiTiX1PpwvuugKwfvUNX/SU/5A2KGZMXfGD0DUHdKEI= @@ -361,6 +366,8 @@ github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23n github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= +github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -397,14 +404,16 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= @@ -425,17 +434,19 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= +golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -453,17 +464,17 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= -golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= +golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/gqlgen.yml b/gqlgen.yml index bc6caf0..92d8ad9 100644 --- a/gqlgen.yml +++ b/gqlgen.yml @@ -19,6 +19,12 @@ resolver: filename_template: "{name}.resolvers.go" +directives: + mcpTool: + skip_runtime: true + mcpExample: + skip_runtime: true + models: Time: model: github.com/99designs/gqlgen/graphql.Time diff --git a/internal/app/app.go b/internal/app/app.go index 8986289..19d66d0 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -3,6 +3,7 @@ package app import ( "fmt" "net/http" + "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/handler/extension" "github.com/99designs/gqlgen/graphql/handler/transport" @@ -17,6 +18,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/DIMO-Network/server-garage/pkg/gql/errorhandler" gqlmetrics "github.com/DIMO-Network/server-garage/pkg/gql/metrics" + "github.com/DIMO-Network/server-garage/pkg/mcpserver" "github.com/DIMO-Network/shared/pkg/middleware/metrics" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags" @@ -31,8 +33,9 @@ var AppName = "fetch-api" // App is the main application (GraphQL over net/http). gRPC is created separately via CreateGRPCServer. type App struct { - Handler http.Handler - cleanup func() + Handler http.Handler + MCPHandler http.Handler + cleanup func() } // New creates a new application with GraphQL handler and middleware. @@ -50,7 +53,8 @@ func New(settings config.Settings) (*App, error) { identityClient = identity.New(settings.IdentityAPIURL) } - gqlSrv := newGraphQLHandler(&settings, eventService, buckets, identityClient) + es := newExecutableSchema(eventService, buckets, identityClient) + gqlSrv := newGraphQLHandler(es) jwtMiddleware, err := auth.NewJWTMiddleware(settings.TokenExchangeIssuer, settings.TokenExchangeJWTKeySetURL) if err != nil { @@ -66,21 +70,34 @@ func New(settings config.Settings) (*App, error) { return nil, fmt.Errorf("couldn't create request time limit middleware: %w", err) } - serverHandler := PanicRecoveryMiddleware( - LoggerMiddleware( - limiter.AddRequestTimeout( - jwtMiddleware.CheckJWT( - authLoggerMiddleware( - auth.AddClaimHandler(gqlSrv), + authChain := func(inner http.Handler) http.Handler { + return PanicRecoveryMiddleware( + LoggerMiddleware( + limiter.AddRequestTimeout( + jwtMiddleware.CheckJWT( + authLoggerMiddleware( + auth.AddClaimHandler(inner), + ), ), ), ), - ), + ) + } + + serverHandler := authChain(gqlSrv) + + mcpHandler, err := mcpserver.New(mcpserver.NewGQLGenExecutor(es), "DIMO Fetch", "0.1.0", "fetch", + mcpserver.WithTools(graph.MCPTools), + mcpserver.WithCondensedSchema(graph.CondensedSchema), ) + if err != nil { + return nil, fmt.Errorf("couldn't create MCP handler: %w", err) + } return &App{ - Handler: serverHandler, - cleanup: func() {}, + Handler: serverHandler, + MCPHandler: authChain(mcpHandler), + cleanup: func() {}, }, nil } @@ -91,16 +108,19 @@ func (a *App) Cleanup() { } } -// newGraphQLHandler creates a configured gqlgen handler.Server. -func newGraphQLHandler(settings *config.Settings, eventService *eventrepo.Service, buckets []string, identityClient identity.Client) *handler.Server { +// newExecutableSchema builds the gqlgen ExecutableSchema shared by the GraphQL and MCP handlers. +func newExecutableSchema(eventService *eventrepo.Service, buckets []string, identityClient identity.Client) graphql.ExecutableSchema { resolver := &graph.Resolver{ EventService: eventService, Buckets: buckets, IdentityClient: identityClient, } + return graph.NewExecutableSchema(graph.Config{Resolvers: resolver}) +} - cfg := graph.Config{Resolvers: resolver} - srv := handler.New(graph.NewExecutableSchema(cfg)) +// newGraphQLHandler creates a configured gqlgen handler.Server. +func newGraphQLHandler(es graphql.ExecutableSchema) *handler.Server { + srv := handler.New(es) srv.AddTransport(transport.Options{}) srv.AddTransport(transport.GET{}) srv.AddTransport(transport.POST{}) diff --git a/internal/graph/base.resolvers.go b/internal/graph/base.resolvers.go index 84dfe4a..02877eb 100644 --- a/internal/graph/base.resolvers.go +++ b/internal/graph/base.resolvers.go @@ -3,7 +3,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver // implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.86 +// Code generated by github.com/99designs/gqlgen version v0.17.89 import ( "context" diff --git a/internal/graph/generated.go b/internal/graph/generated.go index 7e13e7d..5c36e23 100644 --- a/internal/graph/generated.go +++ b/internal/graph/generated.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "strconv" - "sync" "sync/atomic" "time" @@ -24,20 +23,10 @@ import ( // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { - return &executableSchema{ - schema: cfg.Schema, - resolvers: cfg.Resolvers, - directives: cfg.Directives, - complexity: cfg.Complexity, - } + return &executableSchema{SchemaData: cfg.Schema, Resolvers: cfg.Resolvers, Directives: cfg.Directives, ComplexityRoot: cfg.Complexity} } -type Config struct { - Schema *ast.Schema - Resolvers ResolverRoot - Directives DirectiveRoot - Complexity ComplexityRoot -} +type Config = graphql.Config[ResolverRoot, DirectiveRoot, ComplexityRoot] type ResolverRoot interface { CloudEvent() CloudEventResolver @@ -45,6 +34,7 @@ type ResolverRoot interface { } type DirectiveRoot struct { + McpHide func(ctx context.Context, obj any, next graphql.Resolver) (res any, err error) } type ComplexityRoot struct { @@ -105,169 +95,164 @@ type QueryResolver interface { AvailableCloudEventTypes(ctx context.Context, did string, filter *model.CloudEventFilter) ([]*model.CloudEventTypeSummary, error) } -type executableSchema struct { - schema *ast.Schema - resolvers ResolverRoot - directives DirectiveRoot - complexity ComplexityRoot -} +type executableSchema graphql.ExecutableSchemaState[ResolverRoot, DirectiveRoot, ComplexityRoot] func (e *executableSchema) Schema() *ast.Schema { - if e.schema != nil { - return e.schema + if e.SchemaData != nil { + return e.SchemaData } return parsedSchema } func (e *executableSchema) Complexity(ctx context.Context, typeName, field string, childComplexity int, rawArgs map[string]any) (int, bool) { - ec := executionContext{nil, e, 0, 0, nil} + ec := newExecutionContext(nil, e, nil) _ = ec switch typeName + "." + field { case "CloudEvent.data": - if e.complexity.CloudEvent.Data == nil { + if e.ComplexityRoot.CloudEvent.Data == nil { break } - return e.complexity.CloudEvent.Data(childComplexity), true + return e.ComplexityRoot.CloudEvent.Data(childComplexity), true case "CloudEvent.dataBase64": - if e.complexity.CloudEvent.DataBase64 == nil { + if e.ComplexityRoot.CloudEvent.DataBase64 == nil { break } - return e.complexity.CloudEvent.DataBase64(childComplexity), true + return e.ComplexityRoot.CloudEvent.DataBase64(childComplexity), true case "CloudEvent.dataUrl": - if e.complexity.CloudEvent.DataURL == nil { + if e.ComplexityRoot.CloudEvent.DataURL == nil { break } - return e.complexity.CloudEvent.DataURL(childComplexity), true + return e.ComplexityRoot.CloudEvent.DataURL(childComplexity), true case "CloudEvent.header": - if e.complexity.CloudEvent.Header == nil { + if e.ComplexityRoot.CloudEvent.Header == nil { break } - return e.complexity.CloudEvent.Header(childComplexity), true + return e.ComplexityRoot.CloudEvent.Header(childComplexity), true case "CloudEventHeader.datacontenttype": - if e.complexity.CloudEventHeader.DataContentType == nil { + if e.ComplexityRoot.CloudEventHeader.DataContentType == nil { break } - return e.complexity.CloudEventHeader.DataContentType(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.DataContentType(childComplexity), true case "CloudEventHeader.dataschema": - if e.complexity.CloudEventHeader.DataSchema == nil { + if e.ComplexityRoot.CloudEventHeader.DataSchema == nil { break } - return e.complexity.CloudEventHeader.DataSchema(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.DataSchema(childComplexity), true case "CloudEventHeader.dataversion": - if e.complexity.CloudEventHeader.DataVersion == nil { + if e.ComplexityRoot.CloudEventHeader.DataVersion == nil { break } - return e.complexity.CloudEventHeader.DataVersion(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.DataVersion(childComplexity), true case "CloudEventHeader.id": - if e.complexity.CloudEventHeader.ID == nil { + if e.ComplexityRoot.CloudEventHeader.ID == nil { break } - return e.complexity.CloudEventHeader.ID(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.ID(childComplexity), true case "CloudEventHeader.producer": - if e.complexity.CloudEventHeader.Producer == nil { + if e.ComplexityRoot.CloudEventHeader.Producer == nil { break } - return e.complexity.CloudEventHeader.Producer(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.Producer(childComplexity), true case "CloudEventHeader.raweventid": - if e.complexity.CloudEventHeader.RawEventID == nil { + if e.ComplexityRoot.CloudEventHeader.RawEventID == nil { break } - return e.complexity.CloudEventHeader.RawEventID(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.RawEventID(childComplexity), true case "CloudEventHeader.signature": - if e.complexity.CloudEventHeader.Signature == nil { + if e.ComplexityRoot.CloudEventHeader.Signature == nil { break } - return e.complexity.CloudEventHeader.Signature(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.Signature(childComplexity), true case "CloudEventHeader.source": - if e.complexity.CloudEventHeader.Source == nil { + if e.ComplexityRoot.CloudEventHeader.Source == nil { break } - return e.complexity.CloudEventHeader.Source(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.Source(childComplexity), true case "CloudEventHeader.specversion": - if e.complexity.CloudEventHeader.SpecVersion == nil { + if e.ComplexityRoot.CloudEventHeader.SpecVersion == nil { break } - return e.complexity.CloudEventHeader.SpecVersion(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.SpecVersion(childComplexity), true case "CloudEventHeader.subject": - if e.complexity.CloudEventHeader.Subject == nil { + if e.ComplexityRoot.CloudEventHeader.Subject == nil { break } - return e.complexity.CloudEventHeader.Subject(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.Subject(childComplexity), true case "CloudEventHeader.tags": - if e.complexity.CloudEventHeader.Tags == nil { + if e.ComplexityRoot.CloudEventHeader.Tags == nil { break } - return e.complexity.CloudEventHeader.Tags(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.Tags(childComplexity), true case "CloudEventHeader.time": - if e.complexity.CloudEventHeader.Time == nil { + if e.ComplexityRoot.CloudEventHeader.Time == nil { break } - return e.complexity.CloudEventHeader.Time(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.Time(childComplexity), true case "CloudEventHeader.type": - if e.complexity.CloudEventHeader.Type == nil { + if e.ComplexityRoot.CloudEventHeader.Type == nil { break } - return e.complexity.CloudEventHeader.Type(childComplexity), true + return e.ComplexityRoot.CloudEventHeader.Type(childComplexity), true case "CloudEventIndex.header": - if e.complexity.CloudEventIndex.Header == nil { + if e.ComplexityRoot.CloudEventIndex.Header == nil { break } - return e.complexity.CloudEventIndex.Header(childComplexity), true + return e.ComplexityRoot.CloudEventIndex.Header(childComplexity), true case "CloudEventIndex.indexKey": - if e.complexity.CloudEventIndex.IndexKey == nil { + if e.ComplexityRoot.CloudEventIndex.IndexKey == nil { break } - return e.complexity.CloudEventIndex.IndexKey(childComplexity), true + return e.ComplexityRoot.CloudEventIndex.IndexKey(childComplexity), true case "CloudEventTypeSummary.count": - if e.complexity.CloudEventTypeSummary.Count == nil { + if e.ComplexityRoot.CloudEventTypeSummary.Count == nil { break } - return e.complexity.CloudEventTypeSummary.Count(childComplexity), true + return e.ComplexityRoot.CloudEventTypeSummary.Count(childComplexity), true case "CloudEventTypeSummary.firstSeen": - if e.complexity.CloudEventTypeSummary.FirstSeen == nil { + if e.ComplexityRoot.CloudEventTypeSummary.FirstSeen == nil { break } - return e.complexity.CloudEventTypeSummary.FirstSeen(childComplexity), true + return e.ComplexityRoot.CloudEventTypeSummary.FirstSeen(childComplexity), true case "CloudEventTypeSummary.lastSeen": - if e.complexity.CloudEventTypeSummary.LastSeen == nil { + if e.ComplexityRoot.CloudEventTypeSummary.LastSeen == nil { break } - return e.complexity.CloudEventTypeSummary.LastSeen(childComplexity), true + return e.ComplexityRoot.CloudEventTypeSummary.LastSeen(childComplexity), true case "CloudEventTypeSummary.type": - if e.complexity.CloudEventTypeSummary.Type == nil { + if e.ComplexityRoot.CloudEventTypeSummary.Type == nil { break } - return e.complexity.CloudEventTypeSummary.Type(childComplexity), true + return e.ComplexityRoot.CloudEventTypeSummary.Type(childComplexity), true case "Query.availableCloudEventTypes": - if e.complexity.Query.AvailableCloudEventTypes == nil { + if e.ComplexityRoot.Query.AvailableCloudEventTypes == nil { break } @@ -276,9 +261,9 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return 0, false } - return e.complexity.Query.AvailableCloudEventTypes(childComplexity, args["did"].(string), args["filter"].(*model.CloudEventFilter)), true + return e.ComplexityRoot.Query.AvailableCloudEventTypes(childComplexity, args["did"].(string), args["filter"].(*model.CloudEventFilter)), true case "Query.cloudEvents": - if e.complexity.Query.CloudEvents == nil { + if e.ComplexityRoot.Query.CloudEvents == nil { break } @@ -287,9 +272,9 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return 0, false } - return e.complexity.Query.CloudEvents(childComplexity, args["did"].(string), args["limit"].(*int), args["filter"].(*model.CloudEventFilter)), true + return e.ComplexityRoot.Query.CloudEvents(childComplexity, args["did"].(string), args["limit"].(*int), args["filter"].(*model.CloudEventFilter)), true case "Query.indexes": - if e.complexity.Query.Indexes == nil { + if e.ComplexityRoot.Query.Indexes == nil { break } @@ -298,9 +283,10 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return 0, false } - return e.complexity.Query.Indexes(childComplexity, args["did"].(string), args["limit"].(*int), args["filter"].(*model.CloudEventFilter)), true + return e.ComplexityRoot.Query.Indexes(childComplexity, args["did"].(string), args["limit"].(*int), args["filter"].(*model.CloudEventFilter)), true + case "Query.latestCloudEvent": - if e.complexity.Query.LatestCloudEvent == nil { + if e.ComplexityRoot.Query.LatestCloudEvent == nil { break } @@ -309,9 +295,9 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return 0, false } - return e.complexity.Query.LatestCloudEvent(childComplexity, args["did"].(string), args["filter"].(*model.CloudEventFilter)), true + return e.ComplexityRoot.Query.LatestCloudEvent(childComplexity, args["did"].(string), args["filter"].(*model.CloudEventFilter)), true case "Query.latestIndex": - if e.complexity.Query.LatestIndex == nil { + if e.ComplexityRoot.Query.LatestIndex == nil { break } @@ -320,7 +306,7 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return 0, false } - return e.complexity.Query.LatestIndex(childComplexity, args["did"].(string), args["filter"].(*model.CloudEventFilter)), true + return e.ComplexityRoot.Query.LatestIndex(childComplexity, args["did"].(string), args["filter"].(*model.CloudEventFilter)), true } return 0, false @@ -328,7 +314,7 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { opCtx := graphql.GetOperationContext(ctx) - ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)} + ec := newExecutionContext(opCtx, e, make(chan graphql.DeferredResult)) inputUnmarshalMap := graphql.BuildUnmarshalerMap( ec.unmarshalInputCloudEventFilter, ) @@ -344,9 +330,9 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) data = ec._Query(ctx, opCtx.Operation.SelectionSet) } else { - if atomic.LoadInt32(&ec.pendingDeferred) > 0 { - result := <-ec.deferredResults - atomic.AddInt32(&ec.pendingDeferred, -1) + if atomic.LoadInt32(&ec.PendingDeferred) > 0 { + result := <-ec.DeferredResults + atomic.AddInt32(&ec.PendingDeferred, -1) data = result.Result response.Path = result.Path response.Label = result.Label @@ -358,8 +344,8 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { var buf bytes.Buffer data.MarshalGQL(&buf) response.Data = buf.Bytes() - if atomic.LoadInt32(&ec.deferred) > 0 { - hasNext := atomic.LoadInt32(&ec.pendingDeferred) > 0 + if atomic.LoadInt32(&ec.Deferred) > 0 { + hasNext := atomic.LoadInt32(&ec.PendingDeferred) > 0 response.HasNext = &hasNext } @@ -372,44 +358,22 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { } type executionContext struct { - *graphql.OperationContext - *executableSchema - deferred int32 - pendingDeferred int32 - deferredResults chan graphql.DeferredResult -} - -func (ec *executionContext) processDeferredGroup(dg graphql.DeferredGroup) { - atomic.AddInt32(&ec.pendingDeferred, 1) - go func() { - ctx := graphql.WithFreshResponseContext(dg.Context) - dg.FieldSet.Dispatch(ctx) - ds := graphql.DeferredResult{ - Path: dg.Path, - Label: dg.Label, - Result: dg.FieldSet, - Errors: graphql.GetErrors(ctx), - } - // null fields should bubble up - if dg.FieldSet.Invalids > 0 { - ds.Result = graphql.Null - } - ec.deferredResults <- ds - }() + *graphql.ExecutionContextState[ResolverRoot, DirectiveRoot, ComplexityRoot] } -func (ec *executionContext) introspectSchema() (*introspection.Schema, error) { - if ec.DisableIntrospection { - return nil, errors.New("introspection disabled") +func newExecutionContext( + opCtx *graphql.OperationContext, + execSchema *executableSchema, + deferredResults chan graphql.DeferredResult, +) executionContext { + return executionContext{ + ExecutionContextState: graphql.NewExecutionContextState[ResolverRoot, DirectiveRoot, ComplexityRoot]( + opCtx, + (*graphql.ExecutableSchemaState[ResolverRoot, DirectiveRoot, ComplexityRoot])(execSchema), + parsedSchema, + deferredResults, + ), } - return introspection.WrapSchema(ec.Schema()), nil -} - -func (ec *executionContext) introspectType(name string) (*introspection.Type, error) { - if ec.DisableIntrospection { - return nil, errors.New("introspection disabled") - } - return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil } var sources = []*ast.Source{ @@ -459,26 +423,51 @@ type Query { Latest cloud event index matching filters. """ latestIndex(did: String!, filter: CloudEventFilter): CloudEventIndex! + @mcpTool( + name: "get_latest_index" + description: "Get the latest CloudEvent index entry (header + storage key) for a DID-scoped subject, optionally filtered by event type, source, producer, or time range. Returns metadata only — use fetch_get_latest_cloud_event for the full payload." + selection: "header { type source subject id time producer dataversion } indexKey" + ) """ List cloud event indexes matching filters. """ indexes(did: String!, limit: Int = 10, filter: CloudEventFilter): [CloudEventIndex!]! + @mcpTool( + name: "list_indexes" + description: "List CloudEvent index entries for a DID-scoped subject, optionally filtered and limited (default 10). Returns headers + storage keys without payloads — cheaper than fetch_list_cloud_events when exploring." + selection: "header { type source subject id time producer } indexKey" + ) """ Latest full cloud event. """ latestCloudEvent(did: String!, filter: CloudEventFilter): CloudEvent! + @mcpTool( + name: "get_latest_cloud_event" + description: "Get the latest full CloudEvent (header + JSON payload) for a DID-scoped subject, optionally filtered. Returns dataUrl (presigned S3 link) for large binary payloads instead of inlining them." + selection: "header { type source subject id time producer } data dataUrl" + ) """ List full cloud events. """ cloudEvents(did: String!, limit: Int = 10, filter: CloudEventFilter): [CloudEvent!]! + @mcpTool( + name: "list_cloud_events" + description: "List full CloudEvents (headers + JSON payloads) for a DID-scoped subject, optionally filtered and limited (default 10). Large binary payloads are returned as presigned S3 URLs via dataUrl instead of inlined data." + selection: "header { type source subject id time producer } data dataUrl" + ) """ List cloud event types available for a subject, with counts and time ranges. """ availableCloudEventTypes(did: String!, filter: CloudEventFilter): [CloudEventTypeSummary!]! + @mcpTool( + name: "list_available_event_types" + description: "Summarize the CloudEvent types present for a DID-scoped subject. Returns each type with its count, firstSeen, and lastSeen timestamps — useful for discovering what kinds of events exist before querying them." + selection: "type count firstSeen lastSeen" + ) } """ @@ -522,6 +511,10 @@ input CloudEventFilter { before: Time after: Time } +`, BuiltIn: false}, + {Name: "../../schema/mcp.graphqls", Input: `directive @mcpTool(name: String!, description: String!, selection: String!, readOnly: Boolean = true) on FIELD_DEFINITION +directive @mcpExample(description: String!, query: String!) repeatable on FIELD_DEFINITION +directive @mcpHide on FIELD_DEFINITION `, BuiltIn: false}, } var parsedSchema = gqlparser.MustLoadSchema(sources...) @@ -690,7 +683,7 @@ func (ec *executionContext) _CloudEvent_header(ctx context.Context, field graphq field, ec.fieldContext_CloudEvent_header, func(ctx context.Context) (any, error) { - return ec.resolvers.CloudEvent().Header(ctx, obj) + return ec.Resolvers.CloudEvent().Header(ctx, obj) }, nil, ec.marshalNCloudEventHeader2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋcloudeventᚐCloudEventHeader, @@ -747,7 +740,7 @@ func (ec *executionContext) _CloudEvent_data(ctx context.Context, field graphql. field, ec.fieldContext_CloudEvent_data, func(ctx context.Context) (any, error) { - return ec.resolvers.CloudEvent().Data(ctx, obj) + return ec.Resolvers.CloudEvent().Data(ctx, obj) }, nil, ec.marshalOJSON2githubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚐRawJSON, @@ -776,7 +769,7 @@ func (ec *executionContext) _CloudEvent_dataBase64(ctx context.Context, field gr field, ec.fieldContext_CloudEvent_dataBase64, func(ctx context.Context) (any, error) { - return ec.resolvers.CloudEvent().DataBase64(ctx, obj) + return ec.Resolvers.CloudEvent().DataBase64(ctx, obj) }, nil, ec.marshalOString2ᚖstring, @@ -1414,7 +1407,7 @@ func (ec *executionContext) _Query_latestIndex(ctx context.Context, field graphq ec.fieldContext_Query_latestIndex, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.resolvers.Query().LatestIndex(ctx, fc.Args["did"].(string), fc.Args["filter"].(*model.CloudEventFilter)) + return ec.Resolvers.Query().LatestIndex(ctx, fc.Args["did"].(string), fc.Args["filter"].(*model.CloudEventFilter)) }, nil, ec.marshalNCloudEventIndex2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚋmodelᚐCloudEventIndex, @@ -1461,7 +1454,7 @@ func (ec *executionContext) _Query_indexes(ctx context.Context, field graphql.Co ec.fieldContext_Query_indexes, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.resolvers.Query().Indexes(ctx, fc.Args["did"].(string), fc.Args["limit"].(*int), fc.Args["filter"].(*model.CloudEventFilter)) + return ec.Resolvers.Query().Indexes(ctx, fc.Args["did"].(string), fc.Args["limit"].(*int), fc.Args["filter"].(*model.CloudEventFilter)) }, nil, ec.marshalNCloudEventIndex2ᚕᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚋmodelᚐCloudEventIndexᚄ, @@ -1508,7 +1501,7 @@ func (ec *executionContext) _Query_latestCloudEvent(ctx context.Context, field g ec.fieldContext_Query_latestCloudEvent, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.resolvers.Query().LatestCloudEvent(ctx, fc.Args["did"].(string), fc.Args["filter"].(*model.CloudEventFilter)) + return ec.Resolvers.Query().LatestCloudEvent(ctx, fc.Args["did"].(string), fc.Args["filter"].(*model.CloudEventFilter)) }, nil, ec.marshalNCloudEvent2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚐCloudEventWrapper, @@ -1559,7 +1552,7 @@ func (ec *executionContext) _Query_cloudEvents(ctx context.Context, field graphq ec.fieldContext_Query_cloudEvents, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.resolvers.Query().CloudEvents(ctx, fc.Args["did"].(string), fc.Args["limit"].(*int), fc.Args["filter"].(*model.CloudEventFilter)) + return ec.Resolvers.Query().CloudEvents(ctx, fc.Args["did"].(string), fc.Args["limit"].(*int), fc.Args["filter"].(*model.CloudEventFilter)) }, nil, ec.marshalNCloudEvent2ᚕᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚐCloudEventWrapperᚄ, @@ -1610,7 +1603,7 @@ func (ec *executionContext) _Query_availableCloudEventTypes(ctx context.Context, ec.fieldContext_Query_availableCloudEventTypes, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.resolvers.Query().AvailableCloudEventTypes(ctx, fc.Args["did"].(string), fc.Args["filter"].(*model.CloudEventFilter)) + return ec.Resolvers.Query().AvailableCloudEventTypes(ctx, fc.Args["did"].(string), fc.Args["filter"].(*model.CloudEventFilter)) }, nil, ec.marshalNCloudEventTypeSummary2ᚕᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚋmodelᚐCloudEventTypeSummaryᚄ, @@ -1661,7 +1654,7 @@ func (ec *executionContext) _Query___type(ctx context.Context, field graphql.Col ec.fieldContext_Query___type, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.introspectType(fc.Args["name"].(string)) + return ec.IntrospectType(fc.Args["name"].(string)) }, nil, ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType, @@ -1725,7 +1718,7 @@ func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.C field, ec.fieldContext_Query___schema, func(ctx context.Context) (any, error) { - return ec.introspectSchema() + return ec.IntrospectSchema() }, nil, ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema, @@ -3209,6 +3202,10 @@ func (ec *executionContext) fieldContext___Type_isOneOf(_ context.Context, field func (ec *executionContext) unmarshalInputCloudEventFilter(ctx context.Context, obj any) (model.CloudEventFilter, error) { var it model.CloudEventFilter + if obj == nil { + return it, nil + } + asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v @@ -3279,7 +3276,6 @@ func (ec *executionContext) unmarshalInputCloudEventFilter(ctx context.Context, it.After = data } } - return it, nil } @@ -3415,10 +3411,10 @@ func (ec *executionContext) _CloudEvent(ctx context.Context, sel ast.SelectionSe return graphql.Null } - atomic.AddInt32(&ec.deferred, int32(len(deferred))) + atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ + ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, @@ -3499,10 +3495,10 @@ func (ec *executionContext) _CloudEventHeader(ctx context.Context, sel ast.Selec return graphql.Null } - atomic.AddInt32(&ec.deferred, int32(len(deferred))) + atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ + ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, @@ -3543,10 +3539,10 @@ func (ec *executionContext) _CloudEventIndex(ctx context.Context, sel ast.Select return graphql.Null } - atomic.AddInt32(&ec.deferred, int32(len(deferred))) + atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ + ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, @@ -3597,10 +3593,10 @@ func (ec *executionContext) _CloudEventTypeSummary(ctx context.Context, sel ast. return graphql.Null } - atomic.AddInt32(&ec.deferred, int32(len(deferred))) + atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ + ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, @@ -3757,10 +3753,10 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr return graphql.Null } - atomic.AddInt32(&ec.deferred, int32(len(deferred))) + atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ + ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, @@ -3813,10 +3809,10 @@ func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionS return graphql.Null } - atomic.AddInt32(&ec.deferred, int32(len(deferred))) + atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ + ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, @@ -3861,10 +3857,10 @@ func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionS return graphql.Null } - atomic.AddInt32(&ec.deferred, int32(len(deferred))) + atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ + ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, @@ -3919,10 +3915,10 @@ func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, return graphql.Null } - atomic.AddInt32(&ec.deferred, int32(len(deferred))) + atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ + ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, @@ -3974,10 +3970,10 @@ func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.Selection return graphql.Null } - atomic.AddInt32(&ec.deferred, int32(len(deferred))) + atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ + ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, @@ -4029,10 +4025,10 @@ func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, return graphql.Null } - atomic.AddInt32(&ec.deferred, int32(len(deferred))) + atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ + ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, @@ -4088,10 +4084,10 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o return graphql.Null } - atomic.AddInt32(&ec.deferred, int32(len(deferred))) + atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ + ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, @@ -4127,39 +4123,11 @@ func (ec *executionContext) marshalNCloudEvent2githubᚗcomᚋDIMOᚑNetworkᚋf } func (ec *executionContext) marshalNCloudEvent2ᚕᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚐCloudEventWrapperᚄ(ctx context.Context, sel ast.SelectionSet, v []*CloudEventWrapper) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalNCloudEvent2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚐCloudEventWrapper(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() + ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { + fc := graphql.GetFieldContext(ctx) + fc.Result = &v[i] + return ec.marshalNCloudEvent2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚐCloudEventWrapper(ctx, sel, v[i]) + }) for _, e := range ret { if e == graphql.Null { @@ -4199,39 +4167,11 @@ func (ec *executionContext) marshalNCloudEventIndex2githubᚗcomᚋDIMOᚑNetwor } func (ec *executionContext) marshalNCloudEventIndex2ᚕᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚋmodelᚐCloudEventIndexᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.CloudEventIndex) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalNCloudEventIndex2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚋmodelᚐCloudEventIndex(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() + ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { + fc := graphql.GetFieldContext(ctx) + fc.Result = &v[i] + return ec.marshalNCloudEventIndex2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚋmodelᚐCloudEventIndex(ctx, sel, v[i]) + }) for _, e := range ret { if e == graphql.Null { @@ -4253,39 +4193,11 @@ func (ec *executionContext) marshalNCloudEventIndex2ᚖgithubᚗcomᚋDIMOᚑNet } func (ec *executionContext) marshalNCloudEventTypeSummary2ᚕᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚋmodelᚐCloudEventTypeSummaryᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.CloudEventTypeSummary) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalNCloudEventTypeSummary2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚋmodelᚐCloudEventTypeSummary(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() + ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { + fc := graphql.GetFieldContext(ctx) + fc.Result = &v[i] + return ec.marshalNCloudEventTypeSummary2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋfetchᚑapiᚋinternalᚋgraphᚋmodelᚐCloudEventTypeSummary(ctx, sel, v[i]) + }) for _, e := range ret { if e == graphql.Null { @@ -4389,39 +4301,11 @@ func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlge } func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Directive) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() + ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { + fc := graphql.GetFieldContext(ctx) + fc.Result = &v[i] + return ec.marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx, sel, v[i]) + }) for _, e := range ret { if e == graphql.Null { @@ -4464,39 +4348,11 @@ func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx conte } func (ec *executionContext) marshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__DirectiveLocation2string(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() + ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { + fc := graphql.GetFieldContext(ctx) + fc.Result = &v[i] + return ec.marshalN__DirectiveLocation2string(ctx, sel, v[i]) + }) for _, e := range ret { if e == graphql.Null { @@ -4520,39 +4376,11 @@ func (ec *executionContext) marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlg } func (ec *executionContext) marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() + ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { + fc := graphql.GetFieldContext(ctx) + fc.Result = &v[i] + return ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) + }) for _, e := range ret { if e == graphql.Null { @@ -4568,39 +4396,11 @@ func (ec *executionContext) marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋg } func (ec *executionContext) marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() + ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { + fc := graphql.GetFieldContext(ctx) + fc.Result = &v[i] + return ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) + }) for _, e := range ret { if e == graphql.Null { @@ -4797,39 +4597,11 @@ func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgq if v == nil { return graphql.Null } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() + ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { + fc := graphql.GetFieldContext(ctx) + fc.Result = &v[i] + return ec.marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx, sel, v[i]) + }) for _, e := range ret { if e == graphql.Null { @@ -4844,39 +4616,11 @@ func (ec *executionContext) marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgen if v == nil { return graphql.Null } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() + ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { + fc := graphql.GetFieldContext(ctx) + fc.Result = &v[i] + return ec.marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx, sel, v[i]) + }) for _, e := range ret { if e == graphql.Null { @@ -4891,39 +4635,11 @@ func (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋg if v == nil { return graphql.Null } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() + ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { + fc := graphql.GetFieldContext(ctx) + fc.Result = &v[i] + return ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) + }) for _, e := range ret { if e == graphql.Null { @@ -4945,39 +4661,11 @@ func (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgen if v == nil { return graphql.Null } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() + ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { + fc := graphql.GetFieldContext(ctx) + fc.Result = &v[i] + return ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) + }) for _, e := range ret { if e == graphql.Null { diff --git a/internal/graph/mcp_tools_gen.go b/internal/graph/mcp_tools_gen.go new file mode 100644 index 0000000..d01e01d --- /dev/null +++ b/internal/graph/mcp_tools_gen.go @@ -0,0 +1,91 @@ +// Code generated by mcpgen. DO NOT EDIT. +package graph + +import ( + "github.com/DIMO-Network/server-garage/pkg/mcpserver" + "github.com/modelcontextprotocol/go-sdk/mcp" +) + +func boolPtr(b bool) *bool { return &b } + +var MCPTools = []mcpserver.ToolDefinition{ + { + Name: "fetch_get_latest_index", + Description: "Get the latest CloudEvent index entry (header + storage key) for a DID-scoped subject, optionally filtered by event type, source, producer, or time range. Returns metadata only — use fetch_get_latest_cloud_event for the full payload.", + Args: []mcpserver.ArgDefinition{ + {Name: "did", Type: "string", Description: "did (String!, required)", Required: true, ItemsType: ""}, + {Name: "filter", Type: "object", Description: "filter (CloudEventFilter, optional)", Required: false, ItemsType: ""}, + }, + Query: "query($did: String!, $filter: CloudEventFilter) { latestIndex(did: $did, filter: $filter) { header { type source subject id time producer dataversion } indexKey } }", + Annotations: &mcp.ToolAnnotations{ + ReadOnlyHint: true, + DestructiveHint: boolPtr(false), + OpenWorldHint: boolPtr(false), + IdempotentHint: true, + }, + }, + { + Name: "fetch_list_indexes", + Description: "List CloudEvent index entries for a DID-scoped subject, optionally filtered and limited (default 10). Returns headers + storage keys without payloads — cheaper than fetch_list_cloud_events when exploring.", + Args: []mcpserver.ArgDefinition{ + {Name: "did", Type: "string", Description: "did (String!, required)", Required: true, ItemsType: ""}, + {Name: "limit", Type: "integer", Description: "limit (Int, optional)", Required: false, ItemsType: ""}, + {Name: "filter", Type: "object", Description: "filter (CloudEventFilter, optional)", Required: false, ItemsType: ""}, + }, + Query: "query($did: String!, $limit: Int, $filter: CloudEventFilter) { indexes(did: $did, limit: $limit, filter: $filter) { header { type source subject id time producer } indexKey } }", + Annotations: &mcp.ToolAnnotations{ + ReadOnlyHint: true, + DestructiveHint: boolPtr(false), + OpenWorldHint: boolPtr(false), + IdempotentHint: true, + }, + }, + { + Name: "fetch_get_latest_cloud_event", + Description: "Get the latest full CloudEvent (header + JSON payload) for a DID-scoped subject, optionally filtered. Returns dataUrl (presigned S3 link) for large binary payloads instead of inlining them.", + Args: []mcpserver.ArgDefinition{ + {Name: "did", Type: "string", Description: "did (String!, required)", Required: true, ItemsType: ""}, + {Name: "filter", Type: "object", Description: "filter (CloudEventFilter, optional)", Required: false, ItemsType: ""}, + }, + Query: "query($did: String!, $filter: CloudEventFilter) { latestCloudEvent(did: $did, filter: $filter) { header { type source subject id time producer } data dataUrl } }", + Annotations: &mcp.ToolAnnotations{ + ReadOnlyHint: true, + DestructiveHint: boolPtr(false), + OpenWorldHint: boolPtr(false), + IdempotentHint: true, + }, + }, + { + Name: "fetch_list_cloud_events", + Description: "List full CloudEvents (headers + JSON payloads) for a DID-scoped subject, optionally filtered and limited (default 10). Large binary payloads are returned as presigned S3 URLs via dataUrl instead of inlined data.", + Args: []mcpserver.ArgDefinition{ + {Name: "did", Type: "string", Description: "did (String!, required)", Required: true, ItemsType: ""}, + {Name: "limit", Type: "integer", Description: "limit (Int, optional)", Required: false, ItemsType: ""}, + {Name: "filter", Type: "object", Description: "filter (CloudEventFilter, optional)", Required: false, ItemsType: ""}, + }, + Query: "query($did: String!, $limit: Int, $filter: CloudEventFilter) { cloudEvents(did: $did, limit: $limit, filter: $filter) { header { type source subject id time producer } data dataUrl } }", + Annotations: &mcp.ToolAnnotations{ + ReadOnlyHint: true, + DestructiveHint: boolPtr(false), + OpenWorldHint: boolPtr(false), + IdempotentHint: true, + }, + }, + { + Name: "fetch_list_available_event_types", + Description: "Summarize the CloudEvent types present for a DID-scoped subject. Returns each type with its count, firstSeen, and lastSeen timestamps — useful for discovering what kinds of events exist before querying them.", + Args: []mcpserver.ArgDefinition{ + {Name: "did", Type: "string", Description: "did (String!, required)", Required: true, ItemsType: ""}, + {Name: "filter", Type: "object", Description: "filter (CloudEventFilter, optional)", Required: false, ItemsType: ""}, + }, + Query: "query($did: String!, $filter: CloudEventFilter) { availableCloudEventTypes(did: $did, filter: $filter) { type count firstSeen lastSeen } }", + Annotations: &mcp.ToolAnnotations{ + ReadOnlyHint: true, + DestructiveHint: boolPtr(false), + OpenWorldHint: boolPtr(false), + IdempotentHint: true, + }, + }, +} + +var CondensedSchema = "scalar JSON # Arbitrary JSON value; serialized as raw JSON (object/array), not an escaped string.\nscalar Time # A point in time, encoded per RFC-3339.\n\ntype Query {\n \"Latest cloud event index matching filters.\"\n latestIndex(did: String!, filter: CloudEventFilter): CloudEventIndex!\n\n indexes(did: String!, limit: Int = 10, filter: CloudEventFilter): [CloudEventIndex!]!\n \"Latest full cloud event.\"\n latestCloudEvent(did: String!, filter: CloudEventFilter): CloudEvent!\n\n cloudEvents(did: String!, limit: Int = 10, filter: CloudEventFilter): [CloudEvent!]!\n availableCloudEventTypes(did: String!, filter: CloudEventFilter): [CloudEventTypeSummary!]!\n}\n\ntype CloudEvent { header: CloudEventHeader!, data: JSON, dataBase64: String, dataUrl: String }\n\ninput CloudEventFilter { id: String, type: String, types: [String!], dataversion: String, source: String, producer: String, before: Time, after: Time }\n\ntype CloudEventHeader { specversion: String!, type: String!, source: String!, subject: String!, id: String!, time: Time!, datacontenttype: String, dataschema: String, dataversion: String, producer: String!, signature: String, raweventid: String, tags: [String!]! }\n\ntype CloudEventIndex { header: CloudEventHeader!, indexKey: String! }\n\ntype CloudEventTypeSummary { type: String!, count: Int!, firstSeen: Time!, lastSeen: Time! }\n" diff --git a/internal/graph/resolver.go b/internal/graph/resolver.go index 2121961..0a50835 100644 --- a/internal/graph/resolver.go +++ b/internal/graph/resolver.go @@ -1,5 +1,7 @@ package graph +//go:generate go run github.com/DIMO-Network/server-garage/cmd/mcpgen -schema ../../schema/ -prefix fetch -out mcp_tools_gen.go -package graph + import ( "context" "fmt" diff --git a/schema/base.graphqls b/schema/base.graphqls index 467070e..27e0d83 100644 --- a/schema/base.graphqls +++ b/schema/base.graphqls @@ -44,26 +44,51 @@ type Query { Latest cloud event index matching filters. """ latestIndex(did: String!, filter: CloudEventFilter): CloudEventIndex! + @mcpTool( + name: "get_latest_index" + description: "Get the latest CloudEvent index entry (header + storage key) for a DID-scoped subject, optionally filtered by event type, source, producer, or time range. Returns metadata only — use fetch_get_latest_cloud_event for the full payload." + selection: "header { type source subject id time producer dataversion } indexKey" + ) """ List cloud event indexes matching filters. """ indexes(did: String!, limit: Int = 10, filter: CloudEventFilter): [CloudEventIndex!]! + @mcpTool( + name: "list_indexes" + description: "List CloudEvent index entries for a DID-scoped subject, optionally filtered and limited (default 10). Returns headers + storage keys without payloads — cheaper than fetch_list_cloud_events when exploring." + selection: "header { type source subject id time producer } indexKey" + ) """ Latest full cloud event. """ latestCloudEvent(did: String!, filter: CloudEventFilter): CloudEvent! + @mcpTool( + name: "get_latest_cloud_event" + description: "Get the latest full CloudEvent (header + JSON payload) for a DID-scoped subject, optionally filtered. Returns dataUrl (presigned S3 link) for large binary payloads instead of inlining them." + selection: "header { type source subject id time producer } data dataUrl" + ) """ List full cloud events. """ cloudEvents(did: String!, limit: Int = 10, filter: CloudEventFilter): [CloudEvent!]! + @mcpTool( + name: "list_cloud_events" + description: "List full CloudEvents (headers + JSON payloads) for a DID-scoped subject, optionally filtered and limited (default 10). Large binary payloads are returned as presigned S3 URLs via dataUrl instead of inlined data." + selection: "header { type source subject id time producer } data dataUrl" + ) """ List cloud event types available for a subject, with counts and time ranges. """ availableCloudEventTypes(did: String!, filter: CloudEventFilter): [CloudEventTypeSummary!]! + @mcpTool( + name: "list_available_event_types" + description: "Summarize the CloudEvent types present for a DID-scoped subject. Returns each type with its count, firstSeen, and lastSeen timestamps — useful for discovering what kinds of events exist before querying them." + selection: "type count firstSeen lastSeen" + ) } """ diff --git a/schema/mcp.graphqls b/schema/mcp.graphqls new file mode 100644 index 0000000..6dad621 --- /dev/null +++ b/schema/mcp.graphqls @@ -0,0 +1,3 @@ +directive @mcpTool(name: String!, description: String!, selection: String!, readOnly: Boolean = true) on FIELD_DEFINITION +directive @mcpExample(description: String!, query: String!) repeatable on FIELD_DEFINITION +directive @mcpHide on FIELD_DEFINITION