diff --git a/go.mod b/go.mod index a7a0b6e..227cd76 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/google/jsonschema-go v0.4.3 github.com/joho/godotenv v1.5.1 github.com/lib/pq v1.10.9 - github.com/mark3labs/x402-go v0.12.1 github.com/modelcontextprotocol/go-sdk v1.6.1 github.com/nacorid/logger v0.0.0-20251221013547-5fc8fd94ed80 github.com/ollama/ollama v0.12.10 @@ -17,42 +16,18 @@ require ( ) require ( - filippo.io/edwards25519 v1.1.0 // indirect - github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect - github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect - github.com/benbjohnson/clock v1.3.5 // indirect github.com/bits-and-blooms/bitset v1.24.2 // indirect - github.com/blendle/zapdriver v1.3.1 // indirect github.com/consensys/gnark-crypto v0.19.2 // indirect github.com/crate-crypto/go-eth-kzg v1.5.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set/v2 v2.8.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.6 // indirect github.com/ethereum/go-ethereum v1.17.2 // indirect - github.com/fatih/color v1.18.0 // indirect - github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/gagliardetto/binary v0.8.0 // indirect - github.com/gagliardetto/solana-go v1.14.0 // indirect - github.com/gagliardetto/treeout v0.1.4 // indirect github.com/holiman/uint256 v1.3.2 // indirect - github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.1 // indirect - github.com/logrusorgru/aurora v2.0.3+incompatible // indirect - github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mitchellh/go-testing-interface v1.14.1 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect - github.com/streamingfast/logging v0.0.0-20250918142248-ac5a1e292845 // indirect github.com/supranational/blst v0.3.16 // indirect - github.com/tyler-smith/go-bip32 v1.0.0 // indirect - github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect - go.mongodb.org/mongo-driver v1.17.6 // indirect - go.uber.org/ratelimit v0.3.1 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/term v0.38.0 // indirect ) require ( @@ -116,6 +91,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.46.0 // indirect + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/net v0.48.0 // indirect golang.org/x/oauth2 v0.35.0 // indirect golang.org/x/sys v0.41.0 // indirect diff --git a/go.sum b/go.sum index f7de63b..f88d49c 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,6 @@ -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= -filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI= -github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= -github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= -github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= -github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU= @@ -18,24 +10,16 @@ github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9 github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= -github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.24.2 h1:M7/NzVbsytmtfHbumG+K2bremQPMJuqv1JD3vOaFxp0= github.com/bits-and-blooms/bitset v1.24.2/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= -github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/bluesky-social/indigo v0.0.0-20251009224519-09f107c1109e h1:6oNYIMh+kbArCQiwZYPGgfxQq88tnMyiBIZtg5clq90= github.com/bluesky-social/indigo v0.0.0-20251009224519-09f107c1109e/go.mod h1:RuQVrCGm42QNsgumKaR6se+XkFKfCPNwdCiTvqKRUck= github.com/carlmjohnson/versioninfo v0.22.5 h1:O00sjOLUAFxYQjlN/bzYTuZiS0y6fWDQjMRvwtKgwwc= github.com/carlmjohnson/versioninfo v0.22.5/go.mod h1:QT9mph3wcVfISUKd0i9sZfVrPviHuSF+cUtLjm2WSf8= -github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= -github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= 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/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= -github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= @@ -74,22 +58,10 @@ github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJ github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8= github.com/ethereum/go-ethereum v1.17.2 h1:ag6geu0kn8Hv5FLKTpH+Hm2DHD+iuFtuqKxEuwUsDOI= github.com/ethereum/go-ethereum v1.17.2/go.mod h1:KHcRXfGOUfUmKg51IhQ0IowiqZ6PqZf08CMtk0g5K1o= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/gagliardetto/binary v0.8.0 h1:U9ahc45v9HW0d15LoN++vIXSJyqR/pWw8DDlhd7zvxg= -github.com/gagliardetto/binary v0.8.0/go.mod h1:2tfj51g5o9dnvsc+fL3Jxr22MuWzYXwx9wEoN0XQ7/c= -github.com/gagliardetto/gofuzz v1.2.2 h1:XL/8qDMzcgvR4+CyRQW9UGdwPRPMHVJfqQ/uMvSUuQw= -github.com/gagliardetto/gofuzz v1.2.2/go.mod h1:bkH/3hYLZrMLbfYWA0pWzXmi5TTRZnu4pMGZBkqMKvY= -github.com/gagliardetto/solana-go v1.14.0 h1:3WfAi70jOOjAJ0deFMjdhFYlLXATF4tOQXsDNWJtOLw= -github.com/gagliardetto/solana-go v1.14.0/go.mod h1:l/qqqIN6qJJPtxW/G1PF4JtcE3Zg2vD2EliZrr9Gn5k= -github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw= -github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -114,7 +86,6 @@ github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/jsonschema-go v0.4.3 h1:/DBOLZTfDow7pe2GmaJNhltueGTtDKICi8V8p+DQPd0= @@ -182,19 +153,15 @@ github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0 github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 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.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -207,10 +174,6 @@ github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzW github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= -github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/mark3labs/x402-go v0.12.1 h1:yWlT/mjF0P1j2sB0xAM4GJb+1/Ycv6p6EqUrT6RB2X0= -github.com/mark3labs/x402-go v0.12.1/go.mod h1:srAvV9FosjBiqrclF15thrQbz0fVVfNXtMcqD0e1hKU= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= @@ -221,21 +184,12 @@ github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvls github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= -github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= -github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/modelcontextprotocol/go-sdk v1.6.1 h1:0zOSupjKUxPKSocPT1Wtago+mUHU2/uZ4xSOY0FGReU= github.com/modelcontextprotocol/go-sdk v1.6.1/go.mod h1:kzm3kzFL1/+AziGOE0nUs3gvPoNxMCvkxokMkuFapXQ= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk= -github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= @@ -252,8 +206,6 @@ github.com/nacorid/logger v0.0.0-20251221013547-5fc8fd94ed80 h1:nZwGInvJNQzPSFYp github.com/nacorid/logger v0.0.0-20251221013547-5fc8fd94ed80/go.mod h1:hd9h4KEPU1f/Vv2qP0x/fZUwz2clFvOV/uIF0pkGo+s= github.com/ollama/ollama v0.12.10 h1:Dd0/SeCc+nv+FffxmWuQTGiRreib7Gt3nBhIIFuKwZA= github.com/ollama/ollama v0.12.10/go.mod h1:RUSmYywUWx/YZMaHrqtnT1ZChu+iSz/7jx2aO9+Mgfg= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= @@ -295,8 +247,6 @@ github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfv github.com/segmentio/encoding v0.5.4/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= @@ -306,11 +256,7 @@ github.com/sokkalf/slog-seq v0.5.1 h1:4LicZGsMhuCtmZkbS++JOm3Wn8PLIrjFkuvEp0yeGH github.com/sokkalf/slog-seq v0.5.1/go.mod h1:B82pc/cMpdQQg6hkBbstHEL4vqI1eZ1MISuN1IK7h14= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU= -github.com/streamingfast/logging v0.0.0-20250918142248-ac5a1e292845 h1:VMA0pZ3MI8BErRA3kh8dKJThP5d0Xh5vZVk5yFIgH/A= -github.com/streamingfast/logging v0.0.0-20250918142248-ac5a1e292845/go.mod h1:BtDq81Tyc7H8up5aXNi/I95nPmG3C0PLEqGWY/iWQ2E= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -321,16 +267,10 @@ github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jq github.com/supranational/blst v0.3.16/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= -github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= -github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= -github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= -github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/urfave/cli v1.22.10 h1:p8Fspmz3iTctJstry1PYS3HVdllxnEzTEsgIgtxTrCk= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= @@ -354,8 +294,6 @@ github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT0 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss= -go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= @@ -370,35 +308,26 @@ go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4A go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 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/ratelimit v0.3.1 h1:K4qVE+byfv/B3tC+4nYWP7v/6SimcO7HzHekoMNBma0= -go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJhRk= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= @@ -414,7 +343,6 @@ 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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= @@ -431,9 +359,7 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -446,7 +372,6 @@ golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= @@ -487,7 +412,5 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= -launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= diff --git a/internal/config/config.go b/internal/config/config.go index e44789a..22d283b 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -25,6 +25,7 @@ type Config struct { ApiKey string ApiSecret string LogFile string + ActiveNetworks string } func Load() *Config { @@ -53,6 +54,7 @@ func Load() *Config { ApiKey: getEnv("CDP_API_KEY_ID", ""), ApiSecret: getEnv("CDP_API_SECRET", ""), LogFile: getEnv("LOG_FILE", "/var/log/mcpserver/output.log"), + ActiveNetworks: getEnv("ACTIVE_NETWORKS", "base"), } } diff --git a/internal/server/GlobalLoggingMiddleware.go b/internal/server/GlobalLoggingMiddleware.go new file mode 100644 index 0000000..073676e --- /dev/null +++ b/internal/server/GlobalLoggingMiddleware.go @@ -0,0 +1,63 @@ +package server + +import ( + "fmt" + "net/http" + "strings" + "time" + + log "github.com/nacorid/logger" +) + +type statusTrackingWriter struct { + http.ResponseWriter + statusCode int +} + +func (stw *statusTrackingWriter) WriteHeader(code int) { + stw.statusCode = code + stw.ResponseWriter.WriteHeader(code) +} + +func (stw *statusTrackingWriter) Write(b []byte) (int, error) { + if stw.statusCode == 0 { + stw.statusCode = http.StatusOK + } + return stw.ResponseWriter.Write(b) +} + +func GlobalLoggingMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/healthz" { + next.ServeHTTP(w, r) + return + } + start := time.Now() + + ipAddr := r.RemoteAddr + if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" { + ipAddr = strings.TrimSpace(strings.Split(forwarded, ",")[0]) + } else if realIP := r.Header.Get("X-Real-Ip"); realIP != "" { + ipAddr = realIP + } + + stw := &statusTrackingWriter{ResponseWriter: w} + + next.ServeHTTP(stw, r) + + duration := fmt.Sprintf("%.2fms", float64(time.Since(start))/float64(time.Millisecond)) + status := stw.statusCode + if status == 0 { + status = http.StatusOK + } + + log.InfoWithContext(r.Context(), "HTTP Request Processed", + "method", r.Method, + "path", r.URL.Path, + "status", status, + "duration", duration, + "remote_ip", ipAddr, + "user_agent", r.UserAgent(), + ) + }) +} diff --git a/internal/server/LoggingMiddleware.go b/internal/server/LoggingMiddleware.go new file mode 100644 index 0000000..bb4e7f0 --- /dev/null +++ b/internal/server/LoggingMiddleware.go @@ -0,0 +1,66 @@ +package server + +import ( + "context" + "fmt" + "net/http" + "strings" + "time" + + "github.com/modelcontextprotocol/go-sdk/mcp" + log "github.com/nacorid/logger" +) + +type LoggingMiddleware struct{} + +func NewLoggingMiddleware() *LoggingMiddleware { + return &LoggingMiddleware{} +} + +// OnCall logs native MCP tool requests streamed over SSE/WebSockets +func (lm *LoggingMiddleware) OnCall(next mcp.MethodHandler) mcp.MethodHandler { + return func(ctx context.Context, method string, request mcp.Request) (mcp.Result, error) { + if method == "tools/call" { + start := time.Now() + + result, err := next(ctx, method, request) + + duration := fmt.Sprintf("%.2fms", float64(time.Since(start))/float64(time.Millisecond)) + + toolName := "unknown" + if callReq, ok := request.(*mcp.CallToolRequest); ok && callReq.Params != nil { + toolName = callReq.Params.Name + } + + log.InfoWithContext(ctx, "MCP Tool Processed", + "transport", "mcp_native", + "tool", toolName, + "duration", duration, + "success", err == nil, + ) + return result, err + } + return next(ctx, method, request) + } +} + +func (lm *LoggingMiddleware) OnCallHTTP(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + ipAddr := r.RemoteAddr + if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" { + ipAddr = strings.TrimSpace(strings.Split(forwarded, ",")[0]) + } + + next.ServeHTTP(w, r) + + duration := fmt.Sprintf("%.2fms", float64(time.Since(start))/float64(time.Millisecond)) + log.InfoWithContext(r.Context(), "REST Tool Processed", + "transport", "rest", + "path", r.URL.Path, + "duration", duration, + "remote_ip", ipAddr, + ) + }) +} diff --git a/internal/server/metricsMiddleware.go b/internal/server/metricsMiddleware.go index a62b14d..138af47 100644 --- a/internal/server/metricsMiddleware.go +++ b/internal/server/metricsMiddleware.go @@ -2,6 +2,7 @@ package server import ( "context" + "fmt" "net/http" "time" @@ -29,7 +30,7 @@ func (mh *MetricsMiddleware) OnCall(next mcp.MethodHandler) mcp.MethodHandler { mh.requestsBucket.Increment() mh.totalRequests.Increment() result, err := next(ctx, method, request) - duration := time.Since(start) + duration := fmt.Sprintf("%.2fms", float64(time.Since(start))/float64(time.Millisecond)) log.DebugWithContext(ctx, "MetricsMiddleware: MCP Handler", "duration", duration) return result, err } @@ -43,7 +44,7 @@ func (mh *MetricsMiddleware) OnCallHTTP(next http.Handler) http.Handler { mh.requestsBucket.Increment() mh.totalRequests.Increment() next.ServeHTTP(w, r) - duration := time.Since(start) + duration := fmt.Sprintf("%.2fms", float64(time.Since(start))/float64(time.Millisecond)) log.DebugWithContext(r.Context(), "MetricsMiddleware: HTTP Handler", "duration", duration) }) } diff --git a/internal/server/networkInfo.go b/internal/server/networkInfo.go new file mode 100644 index 0000000..be96613 --- /dev/null +++ b/internal/server/networkInfo.go @@ -0,0 +1,34 @@ +package server + +type NetworkInfo struct { + Network string + Asset string + Extra map[string]any +} + +// NetworkRegistry maps human-readable names (slugs) to their full configuration parameters. +var NetworkRegistry = map[string]NetworkInfo{ + "base": { + Network: "eip155:8453", + Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + }, + "sepolia": { + Network: "eip155:84532", + Asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + }, + "polygon": { + Network: "eip155:137", + Asset: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + }, + "arbitrum": { + Network: "eip155:42161", + Asset: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + }, + "solana": { + Network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", + Asset: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + Extra: map[string]any{ + "feePayer": "BENrLoUbndxoNMUS5JXApGMtNykLjFXXixMtpDwDR9SP", + }, + }, +} diff --git a/internal/server/server.go b/internal/server/server.go index b88ab62..caa40eb 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "maps" "net/http" "os" "strings" @@ -21,29 +22,32 @@ import ( "github.com/nacorid/naco-api/internal/x402" x402v2 "github.com/x402-foundation/x402/go/v2" x402http "github.com/x402-foundation/x402/go/v2/http/nethttp" - "github.com/x402-foundation/x402/go/v2/types" ) type Server struct { - listenAddress string - permissions os.FileMode - mcpHandler *x402.X402Server - db *store.Queries - apClient *activitypub.APClient - bskyClient *bluesky.BlueskyClient - ollama *ollama.OllamaClient - x402Wallet string + listenAddress string + permissions os.FileMode + mcpHandler *x402.X402Server + db *store.Queries + apClient *activitypub.APClient + bskyClient *bluesky.BlueskyClient + ollama *ollama.OllamaClient + x402Wallet string + activeNetworks []NetworkInfo } func New(ctx context.Context, db *store.Queries, ap *activitypub.APClient, bsky *bluesky.BlueskyClient, o *ollama.OllamaClient, cfg *config.Config) *Server { rateLimits := NewRateLimitMiddleware(float64(1.0/10.0), 2, []string{"getFeed"}) metrics := NewMetricsHook() + logging := NewLoggingMiddleware() toolChain := x402.X402Middlewares{ MCPMiddleware: []mcp.Middleware{ + logging.OnCall, metrics.OnCall, rateLimits.OnCall, }, HTTPMiddleware: []func(http.Handler) http.Handler{ + logging.OnCallHTTP, metrics.OnCallHTTP, rateLimits.OnCallHTTP, }, @@ -59,13 +63,13 @@ func New(ctx context.Context, db *store.Queries, ap *activitypub.APClient, bsky cfg.X402FacilitatorURL, auth, toolChain, + GlobalLoggingMiddleware, func(w http.ResponseWriter, r *http.Request, resp *x402v2.SettleResponse) { requirements, ok := x402http.RequirementsFromContext(r.Context()) if !ok { log.WarnWithContext(r.Context(), "failed to extract payment requirements from context during settlement hook") return } - amount := requirements.Amount asset := requirements.Asset to := requirements.PayTo @@ -85,15 +89,27 @@ func New(ctx context.Context, db *store.Queries, ap *activitypub.APClient, bsky return settleHook(settleCtx.Ctx, db, settleCtx.Result.Transaction, amount, asset, string(settleCtx.Result.Network), to, from) }) + enabledNetworkNames := parseActiveNetworks(cfg.ActiveNetworks) + + var activeNetworks []NetworkInfo + for _, name := range enabledNetworkNames { + if info, exists := NetworkRegistry[name]; exists { + activeNetworks = append(activeNetworks, info) + } else { + log.WarnWithContext(ctx, "configured network is not defined in the registry", "name", name) + } + } + s := &Server{ - listenAddress: cfg.ListenAddress, - permissions: cfg.UnixSocketPermissions, - mcpHandler: srv, - db: db, - apClient: ap, - bskyClient: bsky, - ollama: o, - x402Wallet: cfg.X402WalletAddress, + listenAddress: cfg.ListenAddress, + permissions: cfg.UnixSocketPermissions, + mcpHandler: srv, + db: db, + apClient: ap, + bskyClient: bsky, + ollama: o, + x402Wallet: cfg.X402WalletAddress, + activeNetworks: activeNetworks, } s.registerTools() @@ -139,16 +155,6 @@ func (s *Server) registerTools() { }, } - requirement := types.PaymentRequirements{ - Scheme: "exact", - Network: "eip155:8453", - Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", - Amount: "10000", - PayTo: s.x402Wallet, - MaxTimeoutSeconds: 60, - Extra: extra, - } - requirements := []types.PaymentRequirements{requirement} s.mcpHandler.AddPayableTool( mcp.Tool{Name: "getPost", Description: "Get a specific post from a specific actor", @@ -156,7 +162,7 @@ func (s *Server) registerTools() { OutputSchema: GetPostResponsePost{}, }, s.getPost, - requirements..., + s.buildRequirements("0.01", extra)..., ) extra = map[string]any{ @@ -191,18 +197,6 @@ func (s *Server) registerTools() { }, } - requirement = types.PaymentRequirements{ - Scheme: "exact", - Network: "eip155:8453", - Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", - Amount: "100000", - PayTo: s.x402Wallet, - MaxTimeoutSeconds: 60, - Extra: extra, - } - - requirements = []types.PaymentRequirements{requirement} - s.mcpHandler.AddPayableTool( mcp.Tool{Name: "getLatestPosts", Description: "Get the latest n posts from a specific actor", @@ -210,7 +204,7 @@ func (s *Server) registerTools() { OutputSchema: GetLatestPostsResponse{}, }, s.getLatestPosts, - requirements..., + s.buildRequirements("0.10", extra)..., ) extra = map[string]any{ @@ -255,18 +249,6 @@ func (s *Server) registerTools() { }, } - requirement = types.PaymentRequirements{ - Scheme: "exact", - Network: "eip155:8453", - Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", - Amount: "100000", - PayTo: s.x402Wallet, - MaxTimeoutSeconds: 60, - Extra: extra, - } - - requirements = []types.PaymentRequirements{requirement} - s.mcpHandler.AddPayableTool( mcp.Tool{Name: "getPostsInTime", Description: "Get posts from a specific actor in a time range", @@ -274,7 +256,7 @@ func (s *Server) registerTools() { OutputSchema: GetPostsInTimeResponse{}, }, s.getPostsInTime, - requirements..., + s.buildRequirements("0.10", extra)..., ) extra = map[string]any{ @@ -312,27 +294,15 @@ func (s *Server) registerTools() { }, } - requirement = types.PaymentRequirements{ - Scheme: "exact", - Network: "eip155:8453", - Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", - Amount: "100000", - PayTo: s.x402Wallet, - MaxTimeoutSeconds: 60, - Extra: extra, - } - - requirements = []types.PaymentRequirements{requirement} - - s.mcpHandler.AddPayableTool( + /*s.mcpHandler.AddPayableTool( mcp.Tool{Name: "getStyleProfile", Description: "Get an actor's style Profile", InputSchema: GetStyleProfileRequest{}, OutputSchema: GetStyleProfileResponse{}, }, s.getStyleProfile, - requirements..., - ) + s.buildRequirements("100000", extra)..., + )*/ s.mcpHandler.AddTool( mcp.Tool{Name: "getFeed", @@ -733,6 +703,39 @@ func settleHook(ctx context.Context, db *store.Queries, transaction, amount, ass return nil } +func (s *Server) buildRequirements(amount string, extra map[string]any) []x402v2.PaymentRequirements { + requirements := make([]x402v2.PaymentRequirements, 0, len(s.activeNetworks)) + + for _, info := range s.activeNetworks { + mergedExtra := make(map[string]any) + maps.Copy(mergedExtra, extra) + maps.Copy(mergedExtra, info.Extra) + requirements = append(requirements, x402v2.PaymentRequirements{ + Scheme: "exact", + Network: info.Network, + Asset: info.Asset, + Amount: amount, + PayTo: s.x402Wallet, + MaxTimeoutSeconds: 60, + Extra: mergedExtra, + }) + } + + return requirements +} + +func parseActiveNetworks(raw string) []string { + parts := strings.Split(raw, ",") + var slugs []string + for _, part := range parts { + trimmed := strings.ToLower(strings.TrimSpace(part)) + if trimmed != "" { + slugs = append(slugs, trimmed) + } + } + return slugs +} + func (s *Server) Start() error { return s.mcpHandler.Start(s.listenAddress, s.permissions) } diff --git a/internal/utils/counter.go b/internal/utils/counter.go index 22b70d5..39e8399 100644 --- a/internal/utils/counter.go +++ b/internal/utils/counter.go @@ -3,7 +3,7 @@ package utils import "sync/atomic" type Counter struct { - valut atomic.Int64 + value atomic.Int64 } func NewCounter() *Counter { @@ -11,13 +11,13 @@ func NewCounter() *Counter { } func (c *Counter) Increment() { - c.valut.Add(1) + c.value.Add(1) } func (c *Counter) Get() int64 { - return c.valut.Load() + return c.value.Load() } func (c *Counter) Reset() { - c.valut.Store(0) + c.value.Store(0) } diff --git a/internal/x402/x402.go b/internal/x402/x402.go index 6a47b16..08e7b8b 100644 --- a/internal/x402/x402.go +++ b/internal/x402/x402.go @@ -44,11 +44,12 @@ type X402Server struct { version string middlewareChain func(http.Handler) http.Handler tools []ToolInfo + globalReqLog func(http.Handler) http.Handler } const VERSION1 = "v1/" -func NewX402Server(name, version string, facilitatorURL string, auth x402http.AuthProvider, mws X402Middlewares, settleHook func(w http.ResponseWriter, r *http.Request, resp *x402.SettleResponse)) (*X402Server, error) { +func NewX402Server(name, version string, facilitatorURL string, auth x402http.AuthProvider, mws X402Middlewares, globalLoggingMw func(http.Handler) http.Handler, settleHook func(http.ResponseWriter, *http.Request, *x402.SettleResponse)) (*X402Server, error) { mcpServer := mcp.NewServer( &mcp.Implementation{ Name: name, @@ -84,6 +85,7 @@ func NewX402Server(name, version string, facilitatorURL string, auth x402http.Au version: version, middlewareChain: chainHTTPMiddlewares(mws.HTTPMiddleware...), tools: make([]ToolInfo, 0), + globalReqLog: globalLoggingMw, } s.mux.HandleFunc("GET /healthz", func(w http.ResponseWriter, r *http.Request) { @@ -176,8 +178,7 @@ func (s *X402Server) AddPayableTool( restHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { s.handleRESTCall(w, r, tool.Name, handler) }) - chained := s.middlewareChain(restHandler) - s.mux.Handle("POST /"+VERSION1+tool.Name, paymentMiddleware(chained)) + s.mux.Handle("POST /"+VERSION1+tool.Name, s.middlewareChain(paymentMiddleware(restHandler))) } func (s *X402Server) handleRESTCall(w http.ResponseWriter, r *http.Request, toolName string, handler mcp.ToolHandler) { @@ -267,7 +268,7 @@ func (s *X402Server) serveOpenAPI(w http.ResponseWriter, r *http.Request) { } } - paths["/"+info.Tool.Name] = map[string]any{ + paths["/"+VERSION1+info.Tool.Name] = map[string]any{ "post": postOp, } } @@ -278,6 +279,9 @@ func (s *X402Server) serveOpenAPI(w http.ResponseWriter, r *http.Request) { "title": s.name, "version": s.version, "description": "Auto-generated REST API matching active Model Context Protocol (MCP) tools.", + "contact": map[string]any{ + "email": "x402@naco.li", + }, }, "paths": paths, } @@ -315,7 +319,7 @@ func (s *X402Server) Start(addr string, permissions os.FileMode) error { defer listener.Close() srv := &http.Server{ - Handler: s.mux, + Handler: s.globalReqLog(s.mux), ErrorLog: slog.NewLogLogger(slog.Default().Handler(), slog.LevelDebug), } return srv.Serve(listener) diff --git a/internal/x402/x402_test.go b/internal/x402/x402_test.go index ba6e84a..19f8036 100644 --- a/internal/x402/x402_test.go +++ b/internal/x402/x402_test.go @@ -29,6 +29,7 @@ func TestX402Server_HTTPBoundaries(t *testing.T) { mockFacilitator.URL, &DummyAuthProvider{}, X402Middlewares{}, + func(next http.Handler) http.Handler { return next }, func(w http.ResponseWriter, r *http.Request, resp *x402.SettleResponse) {}, ) if err != nil { @@ -99,6 +100,7 @@ func TestX402Server_MCPBoundaries(t *testing.T) { mockFacilitator.URL, &DummyAuthProvider{}, X402Middlewares{}, + func(next http.Handler) http.Handler { return next }, func(w http.ResponseWriter, r *http.Request, resp *x402.SettleResponse) {}, ) if err != nil { diff --git a/testClient/main.go b/testClient/main.go index 75279a5..394d2c1 100644 --- a/testClient/main.go +++ b/testClient/main.go @@ -3,7 +3,6 @@ package main import ( "bytes" "context" - "encoding/json" "fmt" "io" "log" @@ -14,12 +13,10 @@ import ( "github.com/joho/godotenv" - //"github.com/mark3labs/mcp-go/client" - "github.com/mark3labs/x402-go" - x402http "github.com/mark3labs/x402-go/http" - - //x402client "github.com/mark3labs/x402-go/mcp/client" - "github.com/mark3labs/x402-go/signers/evm" + x402 "github.com/x402-foundation/x402/go/v2" + x402http "github.com/x402-foundation/x402/go/v2/http" + evm "github.com/x402-foundation/x402/go/v2/mechanisms/evm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/v2/signers/evm" ) type LoggingRoundTripper struct { @@ -63,27 +60,17 @@ func main() { godotenv.Load() var ( privateKey = os.Getenv("PRIVATE_KEY") - serverURL = "https://api.naco.li" - err error + serverURL = "https://api.naco.li/v1" + ctx = context.Background() ) - chainConfig := x402.BaseMainnet - - signerOpts := []evm.SignerOption{ - evm.WithPrivateKey(privateKey), - evm.WithNetwork(chainConfig.NetworkID), - evm.WithToken(chainConfig.USDCAddress, chainConfig.EIP3009Name, int(chainConfig.Decimals)), + signer, err := evmsigners.NewClientSignerFromPrivateKey(privateKey) + if err != nil { + log.Fatal("Failed to create EVM signer:", err) } - signer, err := evm.NewSigner(signerOpts...) - if err != nil { - log.Fatal("Failed to create signer:", err) - } - - /*x402mcpTransport, err := x402client.NewTransport(serverURL+"/mcp", x402client.WithSigner(signer)) - if err != nil { - log.Fatal("Failed to create transport:", err) - }*/ + x402Client := x402.Newx402Client(). + Register("eip155:*", evm.NewExactEvmScheme(signer, nil)) debugClient := &http.Client{ Transport: &LoggingRoundTripper{ @@ -91,306 +78,44 @@ func main() { }, } - callback := x402.PaymentCallback(func(pe x402.PaymentEvent) { - log.Printf("Type: %s, Tool: %s, Error: %s", pe.Type, pe.Tool, pe.Error) - }) - // Create MCP client with x402 transport - //mcpClient := client.NewClient(x402mcpTransport) - httpClient, err := x402http.NewClient(x402http.WithPaymentCallbacks( - callback, - callback, - callback, - ), - x402http.WithHTTPClient(debugClient), - x402http.WithSelector(x402.NewDefaultPaymentSelector()), - x402http.WithSigner(signer), + httpClient := x402http.WrapHTTPClientWithPayment( + debugClient, + x402http.Newx402HTTPClient(x402Client), ) + + log.Println("Starting REST API tests...") + + log.Println("\nCalling getFeed (free tool) via HTTP client...") + bodyGetFeed := []byte(`{"uri": "https://bsky.app/profile/did:plc:z72i7hdynmk6r22z27h6tvur/feed/whats-hot"}`) + resp, err := httpClient.Post(fmt.Sprintf("%s/getFeed", serverURL), "application/json", bytes.NewReader(bodyGetFeed)) if err != nil { - log.Fatal("Failed to create HTTP client:", err) - } - - ctx := context.Background() - /*if err := mcpClient.Start(ctx); err != nil { - log.Fatal("Failed to start client:", err) - } - defer mcpClient.Close() - */ - //startTime, _ := time.Parse(time.DateOnly, "2025-10-25") - //endTime, _ := time.Parse(time.DateOnly, "2025-10-31") - - /*// Initialize MCP session - initResp, err := mcpClient.Initialize(ctx, mcp.InitializeRequest{ - Params: mcp.InitializeParams{ - ProtocolVersion: "2024-11-05", - ClientInfo: mcp.Implementation{ - Name: "x402-test", - Version: "1.0.0", - }, - }, - }) - if err != nil { - log.Fatal("Failed to initialize:", err) - } - - log.Printf("Connected to server: %s v%s", - initResp.ServerInfo.Name, initResp.ServerInfo.Version) - - // List all available tools - log.Println("\nListing available tools...") - toolsResp, err := mcpClient.ListTools(ctx, mcp.ListToolsRequest{}) - if err != nil { - log.Printf("Failed to list tools: %v", err) + log.Println("getFeed HTTP request failed:", err) } else { - log.Println("Available tools:") - for _, tool := range toolsResp.Tools { - log.Printf(" - %s: %s", tool.Name, tool.Description) - } + defer resp.Body.Close() + body, _ := io.ReadAll(resp.Body) + log.Printf("getFeed Response Status: %s\n", resp.Status) + log.Printf("getFeed Response Body: %s\n", string(body)) } - log.Println("\nCalling feed tool (free)...") - _, err = mcpClient.CallTool(ctx, mcp.CallToolRequest{ - Params: mcp.CallToolParams{ - Name: "getFeed", - Arguments: map[string]any{ - "uri": "https://bsky.app/profile/did:plc:z72i7hdynmk6r22z27h6tvur/feed/whats-hot", - }, - }, - }) + log.Println("\nCalling getPost (gated paid tool) via HTTP client...") + bodyGetPost := []byte(`{"actor":"sharkgamiart.bsky.social","rkey":"3m47y27c67c2b"}`) + req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/getPost", serverURL), bytes.NewReader(bodyGetPost)) if err != nil { - log.Printf("Feed failed: %v", err) - } else { - log.Println("Feed response:") - if len(echoResp.Content) > 0 { - if textContent, ok := mcp.AsTextContent(echoResp.Content[0]); ok { - log.Println(textContent.Text) - } - } - log.Println("Feed response received successfully.") + log.Fatal("Failed to create getPost request:", err) } - - log.Println("\nCalling feed tool again with proper feed uri...") - _, err = mcpClient.CallTool(ctx, mcp.CallToolRequest{ - Params: mcp.CallToolParams{ - Name: "getFeed", - Arguments: map[string]any{ - "uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot", - }, - }, - }) - - if err != nil { - log.Printf("Feed failed: %v", err) - } else { - log.Println("Feed response:") - if len(echoResp.Content) > 0 { - if textContent, ok := mcp.AsTextContent(echoResp.Content[0]); ok { - log.Println(textContent.Text) - } - } - log.Println("Feed response received successfully.") - } - - // Call the search tool (paid) - log.Println("\nGet Post (paid tool)...") - searchResp, err := mcpClient.CallTool(ctx, mcp.CallToolRequest{ - Params: mcp.CallToolParams{ - Name: "getPost", - Arguments: map[string]any{ - "actor": "sharkgamiart.bsky.social", - "rkey": "3m47y27c67c2b", - }, - }, - }) - - if err != nil { - log.Fatalf("Get Post failed: %v", err) - } - - log.Println("Post results:") - if len(searchResp.Content) > 0 { - if textContent, ok := mcp.AsTextContent(searchResp.Content[0]); ok { - log.Println(textContent.Text) - } - } - - log.Println("\nGet latest posts (paid tool)...") - latestResp, err := mcpClient.CallTool(ctx, mcp.CallToolRequest{ - Params: mcp.CallToolParams{ - Name: "getLatestPosts", - Arguments: map[string]any{ - "actor": "sharkgamiart.bsky.social", - "n": 10, - }, - }, - }) - - if err != nil { - log.Fatalf("Get Latest Posts failed: %v", err) - } - - log.Printf("Latest posts (%d):\n", len(latestResp.Content)) - if len(latestResp.Content) > 0 { - if textContent, ok := mcp.AsTextContent(latestResp.Content[0]); ok { - log.Println(" - ", textContent.Text) - } - } - - log.Println("\nGet posts in timeframe (paid tool)...") - timeframeResp, err := mcpClient.CallTool(ctx, mcp.CallToolRequest{ - Params: mcp.CallToolParams{ - Name: "getPostsInTime", - Arguments: map[string]any{ - "actor": "sharkgamiart.bsky.social", - "startTime": startTime.Format(time.RFC3339), - "endTime": endTime.Format(time.RFC3339), - "n": 5, - }, - }, - }) - - if err != nil { - log.Fatalf("Get Posts in Timeframe failed: %v", err) - } - - log.Println("Posts in timeframe results:") - if len(timeframeResp.Content) > 0 { - if textContent, ok := mcp.AsTextContent(timeframeResp.Content[0]); ok { - log.Println(textContent.Text) - } - } - - mcpClient.Close()*/ - - var dataGetFeed any - log.Println("Calling getFeed via HTTP client") - resp, err := httpClient.Post(fmt.Sprintf("%s/getFeed", serverURL), "application/json", bytes.NewReader([]byte(`{"uri": "https://bsky.app/profile/did:plc:z72i7hdynmk6r22z27h6tvur/feed/whats-hot"}`))) - if err != nil { - log.Println("getFeed failed:", err) - } - - body, err := io.ReadAll(resp.Body) - if err != nil { - log.Println("Failed to read getFeed response body:", err) - } - if resp.StatusCode != http.StatusOK { - log.Printf("Raw Response Body: %s\n", string(body)) - } - err = json.Unmarshal(body, &dataGetFeed) - if err != nil { - log.Println("Failed to unmarshal getFeed response body:", err) - log.Printf("Received Raw Body: %s\n", string(body)) - } - //log.Println("getFeed response:", dataGetFeed) - resp.Body.Close() - - /* var dataGetFeed2 any - log.Println("Calling getFeed via HTTP client with proper feed uri") - resp, err = httpClient.Post(fmt.Sprintf("%s/getFeed", serverURL), "application/json", bytes.NewReader([]byte(`{"uri":"at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot"}`))) - if err != nil { - log.Println("getFeed failed:", err) - } - - body, err = io.ReadAll(resp.Body) - if err != nil { - log.Println("Failed to read getFeed response body:", err) - } - if resp.StatusCode != http.StatusOK { - log.Printf("Raw Response Body: %s\n", string(body)) - } - err = json.Unmarshal(body, &dataGetFeed2) - if err != nil { - log.Println("Failed to unmarshal getFeed response body:", err) - log.Printf("Received Raw Body: %s\n", string(body)) - } - //log.Println("getFeed response:", dataGetFeed2) - resp.Body.Close() - */ - var dataGetPost any - log.Println("Calling getPost via HTTP client") - bodyBytes := []byte(`{"actor":"sharkgamiart.bsky.social","rkey":"3m47y27c67c2b"}`) - - req, _ := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/getPost", serverURL), bytes.NewReader(bodyBytes)) req.GetBody = func() (io.ReadCloser, error) { - return io.NopCloser(bytes.NewReader(bodyBytes)), nil + return io.NopCloser(bytes.NewReader(bodyGetPost)), nil } req.Header.Set("Content-Type", "application/json") - resp, err = httpClient.Do(req) + respPost, err := httpClient.Do(req) if err != nil { - log.Println("getPost failed:", err) + log.Println("getPost HTTP request failed:", err) + } else { + defer respPost.Body.Close() + body, _ := io.ReadAll(respPost.Body) + log.Printf("getPost Response Status: %s\n", respPost.Status) + log.Printf("getPost Response Body: %s\n", string(body)) } - - body, err = io.ReadAll(resp.Body) - if err != nil { - log.Println("Failed to read getPost response body:", err) - } - if resp.StatusCode != http.StatusOK { - log.Printf("Raw Response Body: %s\n", string(body)) - } - err = json.Unmarshal(body, &dataGetPost) - if err != nil { - log.Println("Failed to unmarshal getPost response body:", err) - log.Printf("Received Raw Body: %s\n", string(body)) - } - log.Println("getPost response:", dataGetPost) - resp.Body.Close() - /* - var dataGetLatestPosts any - log.Println("Calling getLatestPosts via HTTP client") - resp, err = httpClient.Post(fmt.Sprintf("%s/getLatestPosts", serverURL), "application/json", bytes.NewReader([]byte(`{"actor":"sharkgamiart.bsky.social","n":10}`))) - - if err != nil { - log.Println("getLatestPosts failed:", err) - } - - log.Println(resp.Proto) - body, err = io.ReadAll(resp.Body) - - if err != nil { - log.Println("Failed to read getLatestPosts response body:", err) - } - - if resp.StatusCode != http.StatusOK { - log.Printf("Raw Response Body: %s\n", string(body)) - } - - err = json.Unmarshal(body, &dataGetLatestPosts) - - if err != nil { - log.Println("Failed to unmarshal getLatestPosts response body:", err) - log.Printf("Received Raw Body: %s\n", string(body)) - } - - log.Println("getLatestPosts response:", dataGetLatestPosts) - resp.Body.Close() - - var dataGetPostsInTime any - log.Println("Calling getPostsInTime via HTTP client") - resp, err = httpClient.Post(fmt.Sprintf("%s/getPostsInTime", serverURL), "application/json", bytes.NewReader([]byte(fmt.Sprintf(`{"actor":"sharkgamiart.bsky.social","startTime":"%s","endTime":"%s","n":5}`, startTime.Format(time.RFC3339), endTime.Format(time.RFC3339))))) - - if err != nil { - log.Println("getPostsInTime failed:", err) - } - - body, err = io.ReadAll(resp.Body) - - if err != nil { - log.Println("Failed to read getPostsInTime response body:", err) - } - - if resp.StatusCode != http.StatusOK { - log.Printf("Raw Response Body: %s\n", string(body)) - } - - err = json.Unmarshal(body, &dataGetPostsInTime) - - if err != nil { - log.Println("Failed to unmarshal getPostsInTime response body:", err) - log.Printf("Received Raw Body: %s\n", string(body)) - } - - log.Println("getPostsInTime response:", dataGetPostsInTime) - resp.Body.Close() - */ }