├── .github └── workflows │ ├── cd.yaml │ └── ci.yaml ├── .gitignore ├── LICENSE ├── README.md ├── go.work ├── go.work.sum ├── justfile ├── servlets ├── amadeus-flight-api │ ├── .gitignore │ ├── README.md │ ├── flights.go │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── pdk.gen.go │ ├── prepare.sh │ └── xtp.toml ├── assembly-ai │ ├── .gitignore │ ├── Makefile │ ├── assemblyai.go │ ├── data │ │ └── hello.mp3 │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── pdk.gen.go │ ├── prepare.sh │ ├── test.sh │ └── xtp.toml ├── bluesky │ ├── .gitignore │ ├── README.md │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── pdk.gen.go │ ├── post.go │ ├── prepare.sh │ ├── record.go │ ├── reply.go │ ├── search.go │ ├── session.go │ └── xtp.toml ├── brave-search │ ├── .gitignore │ ├── README.md │ ├── go.mod │ ├── go.sum │ ├── imgs │ │ └── img-search-results.png │ ├── main.go │ ├── pdk.gen.go │ ├── prepare.sh │ ├── search.go │ └── xtp.toml ├── crypto-hash │ ├── .gitignore │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── pdk.gen.go │ ├── prepare.sh │ └── xtp.toml ├── currency-converter │ ├── .clang-format │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── impl.cpp │ ├── install-wasi-sdk.sh │ ├── pdk.gen.cpp │ ├── pdk.gen.hpp │ └── xtp.toml ├── electricity-magnetism │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── README.md │ ├── esbuild.js │ ├── package-lock.json │ ├── package.json │ ├── prepare.sh │ ├── src │ │ ├── constants.ts │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── main.ts │ │ ├── math.ts │ │ ├── pdk.ts │ │ ├── physics.ts │ │ └── types.ts │ ├── tsconfig.json │ └── xtp.toml ├── eval-py │ ├── .gitignore │ ├── README.md │ ├── plugin │ │ ├── __init__.py │ │ ├── pdk_imports.py │ │ ├── pdk_types.py │ │ └── plugin.py │ ├── prepare.sh │ ├── pyproject.toml │ ├── pyrightconfig.json │ ├── uv.lock │ └── xtp.toml ├── eval_js │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── README.md │ ├── esbuild.js │ ├── package-lock.json │ ├── package.json │ ├── prepare.sh │ ├── src │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── main.ts │ │ └── pdk.ts │ ├── tsconfig.json │ └── xtp.toml ├── fetch-image │ ├── .cargo │ │ └── config.toml │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── prepare.sh │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml ├── fetch │ ├── .cargo │ │ └── config.toml │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── prepare.sh │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml ├── filesystem │ ├── .cargo │ │ └── config.toml │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── prepare.sh │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml ├── github │ ├── .gitignore │ ├── README.md │ ├── branches.go │ ├── files.go │ ├── gists.go │ ├── go.mod │ ├── go.sum │ ├── issues.go │ ├── main.go │ ├── pdk.gen.go │ ├── prepare.sh │ ├── repo.go │ └── xtp.toml ├── google-maps-image │ ├── .gitignore │ ├── README.md │ ├── go.mod │ ├── go.sum │ ├── imgs │ │ └── santa-route.png │ ├── main.go │ ├── pdk.gen.go │ ├── prepare.sh │ └── xtp.toml ├── google-maps │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── README.md │ ├── esbuild.js │ ├── package-lock.json │ ├── package.json │ ├── prepare.sh │ ├── src │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── main.ts │ │ ├── pdk.ts │ │ ├── tools.ts │ │ └── types.ts │ ├── tsconfig.json │ └── xtp.toml ├── greet │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── README.md │ ├── esbuild.js │ ├── mock_input.json │ ├── package-lock.json │ ├── package.json │ ├── prepare.sh │ ├── src │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── main.ts │ │ └── pdk.ts │ ├── tsconfig.json │ └── xtp.toml ├── historical-flight-api │ ├── .gitignore │ ├── README.md │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── pdk.gen.go │ ├── prepare.sh │ └── xtp.toml ├── image-resizer │ ├── .cargo │ │ └── config.toml │ ├── .gitignore │ ├── Cargo.toml │ ├── prepare.sh │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml ├── ipfs │ ├── .cargo │ │ └── config.toml │ ├── .gitignore │ ├── Cargo.toml │ ├── prepare.sh │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml ├── jq │ ├── .cargo │ │ └── config.toml │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── prepare.sh │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml ├── json-schema │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── Makefile │ ├── esbuild.js │ ├── package-lock.json │ ├── package.json │ ├── prepare.sh │ ├── src │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── main.ts │ │ └── pdk.ts │ ├── test.sh │ ├── tsconfig.json │ └── xtp.toml ├── notion │ ├── .cargo │ │ └── config.toml │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── prepare.sh │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml ├── obsidian │ ├── .gitignore │ ├── plugin │ │ ├── __init__.py │ │ ├── pdk_imports.py │ │ ├── pdk_types.py │ │ └── plugin.py │ ├── prepare.sh │ ├── pyproject.toml │ ├── pyrightconfig.json │ ├── uv.lock │ └── xtp.toml ├── pantry │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── prepare.sh │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml ├── perplexity-sonar │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── README.md │ ├── esbuild.js │ ├── package-lock.json │ ├── package.json │ ├── prepare.sh │ ├── src │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── main.ts │ │ └── pdk.ts │ ├── tsconfig.json │ └── xtp.toml ├── qr-code │ ├── .cargo │ │ └── config.toml │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml ├── sequential-thinking │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── README.md │ ├── esbuild.js │ ├── package-lock.json │ ├── package.json │ ├── prepare.sh │ ├── src │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── main.ts │ │ └── pdk.ts │ ├── tsconfig.json │ └── xtp.toml ├── slack │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── esbuild.js │ ├── package-lock.json │ ├── package.json │ ├── prepare.sh │ ├── src │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── main.ts │ │ └── pdk.ts │ ├── tsconfig.json │ └── xtp.toml ├── sqlite │ ├── .cargo │ │ └── config.toml │ ├── Cargo.lock │ ├── Cargo.toml │ ├── install-wasi-sdk.sh │ ├── prepare.sh │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml ├── tenor-gifs │ ├── .gitignore │ ├── build.sh │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── pdk.gen.go │ ├── prepare.sh │ └── xtp.toml ├── text-to-speech │ ├── .cargo │ │ └── config.toml │ ├── .gitignore │ ├── Cargo.toml │ ├── prepare.sh │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml ├── time │ ├── .cargo │ │ └── config.toml │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── prepare.sh │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml ├── trello │ ├── .gitignore │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── pdk.gen.go │ ├── prepare.sh │ ├── trello.go │ └── xtp.toml ├── twilio │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── esbuild.js │ ├── package-lock.json │ ├── package.json │ ├── prepare.sh │ ├── src │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── main.ts │ │ └── pdk.ts │ ├── tsconfig.json │ └── xtp.toml ├── unsplash │ ├── .gitignore │ ├── README.md │ ├── build.zig │ ├── build.zig.zon │ ├── src │ │ ├── main.zig │ │ ├── pdk.zig │ │ ├── schema.zig │ │ └── tools.json │ └── xtp.toml ├── wolfram-alpha │ ├── .cargo │ │ └── config.toml │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── prepare.sh │ ├── src │ │ ├── lib.rs │ │ └── pdk.rs │ └── xtp.toml └── wordpress │ ├── .gitignore │ ├── Makefile │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── pdk.gen.go │ ├── prepare.sh │ ├── wordpress.go │ └── xtp.toml ├── simulations └── describe-output │ ├── .gitignore │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── go.mod │ ├── go.sum │ └── main.go └── test ├── .gitignore └── testsuite ├── go.mod ├── go.sum ├── main.go ├── pdk.go └── xtp.toml /.github/workflows/cd.yaml: -------------------------------------------------------------------------------- 1 | name: Build and Push 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: Install Rust 15 | uses: actions-rs/toolchain@v1 16 | with: 17 | toolchain: stable 18 | override: true 19 | targets: wasm32-unknown-unknown, wasm32-wasi 20 | 21 | - name: Add wasm32-wasip1 target (can be moved to list above when the target is added to toolchain action above) 22 | run: rustup target add wasm32-wasip1 23 | 24 | - name: Install just 25 | uses: extractions/setup-just@v1 26 | 27 | - name: Install Node.js 28 | uses: actions/setup-node@v4 29 | with: 30 | node-version: 'lts/*' 31 | 32 | - name: Set up Go 33 | uses: actions/setup-go@v4 34 | with: 35 | go-version: '1.23' 36 | 37 | - name: Install TinyGo 38 | run: | 39 | wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_amd64.deb 40 | sudo dpkg -i tinygo_0.34.0_amd64.deb 41 | 42 | - name: Install extism-js 43 | run: | 44 | curl -L https://raw.githubusercontent.com/extism/js-pdk/main/install.sh | bash 45 | 46 | - name: Install extism-py and uv 47 | run: | 48 | curl -LsSf https://astral.sh/uv/install.sh | sh 49 | curl -Ls https://raw.githubusercontent.com/extism/python-pdk/main/install.sh | bash 50 | 51 | - name: Install Zig 52 | uses: mlugg/setup-zig@v1 53 | with: 54 | version: 0.13.0 55 | 56 | - name: Install xtp CLI 57 | run: | 58 | curl -L https://static.dylibso.com/cli/install.sh -s | bash 59 | 60 | - name: Build and test all the servlets 61 | env: 62 | TENOR_API_KEY: ${{ secrets.TENOR_API_KEY }} 63 | run: | 64 | just build 65 | just test 66 | 67 | - name: Publish all the servlets 68 | env: 69 | XTP_TOKEN: ${{ secrets.XTP_TOKEN }} 70 | TENOR_API_KEY: ${{ secrets.TENOR_API_KEY }} 71 | run: just push 72 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | branches: [ "main" ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: Install Rust 15 | uses: actions-rs/toolchain@v1 16 | with: 17 | toolchain: stable 18 | override: true 19 | targets: wasm32-unknown-unknown, wasm32-wasi 20 | 21 | - name: Add wasm32-wasip1 target (can be moved to list above when the target is added to toolchain action above) 22 | run: rustup target add wasm32-wasip1 23 | 24 | - name: Install just 25 | uses: extractions/setup-just@v1 26 | 27 | - name: Install Node.js 28 | uses: actions/setup-node@v4 29 | with: 30 | node-version: 'lts/*' 31 | 32 | - name: Set up Go 33 | uses: actions/setup-go@v4 34 | with: 35 | go-version: '1.23' 36 | 37 | - name: Install TinyGo 38 | run: | 39 | wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_amd64.deb 40 | sudo dpkg -i tinygo_0.34.0_amd64.deb 41 | 42 | - name: Install extism-js 43 | run: | 44 | curl -L https://raw.githubusercontent.com/extism/js-pdk/main/install.sh | bash 45 | 46 | - name: Install extism-py and uv 47 | run: | 48 | curl -LsSf https://astral.sh/uv/install.sh | sh 49 | curl -Ls https://raw.githubusercontent.com/extism/python-pdk/main/install.sh | bash 50 | 51 | - name: Install Zig 52 | uses: mlugg/setup-zig@v1 53 | with: 54 | version: 0.13.0 55 | 56 | - name: Install xtp CLI 57 | run: | 58 | curl -L https://static.dylibso.com/cli/install.sh -s | bash 59 | 60 | - name: Build and test all the servlets 61 | env: 62 | TENOR_API_KEY: ${{ secrets.TENOR_API_KEY }} 63 | run: | 64 | just build 65 | just test 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .idea/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Dylibso, Inc. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Official mcp.run Servlets 2 | 3 | These are the official servlets for the @dylibso account on [mcp.run](https://mcp.run). 4 | Merging changes here automatically deploys them to all users. 5 | 6 | ## Generating Servlets with LLMs 7 | 8 | Using Cursor, Cline, or other AI-enabled IDEs have their own ways of integrating source context - use this repo as a starting point to give them examples. All the code in the `servlets` directory is great fine-tuning material. 9 | 10 | If you are using a Chat interface, you can copy/paste context generated from here: 11 | https://gitingest.com/dylibso/mcp.run-servlets 12 | 13 | **Note:** to reduce context used, add these patterns to the "Exclude" dropdown so they are not tokenized: 14 | 15 | ``` 16 | **/package*.json, **/go.mod, **/go.sum, **/go.work*, **/LICENSE, LICENSE, .gitignore, **/.gitignore 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /go.work: -------------------------------------------------------------------------------- 1 | go 1.23 2 | 3 | use ( 4 | ./servlets/amadeus-flight-api 5 | ./servlets/assembly-ai 6 | ./servlets/bluesky 7 | ./servlets/brave-search 8 | ./servlets/crypto-hash 9 | ./servlets/github 10 | ./servlets/google-maps-image 11 | ./servlets/historical-flight-api 12 | ./servlets/tenor-gifs 13 | ./servlets/trello 14 | ./servlets/wordpress 15 | ./test/testsuite 16 | ) 17 | -------------------------------------------------------------------------------- /go.work.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= 2 | golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= 3 | golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 4 | golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= 5 | golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= 6 | golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= 7 | golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 8 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | 2 | [no-cd] 3 | prepare: 4 | #!/usr/bin/env bash 5 | set -eou pipefail 6 | if [ -f "./prepare.sh" ]; then 7 | bash ./prepare.sh || exit 1 8 | fi 9 | if [ -f "./pyproject.toml" ]; then 10 | uv sync 11 | fi 12 | 13 | build: 14 | #!/usr/bin/env bash 15 | set -eou pipefail 16 | for dir in servlets/*/; do 17 | cd "$dir" 18 | echo "Building $dir" 19 | just prepare 20 | xtp plugin build 21 | cd ../.. 22 | done 23 | 24 | push: 25 | #!/usr/bin/env bash 26 | set -eou pipefail 27 | for dir in servlets/*/; do 28 | cd "$dir" 29 | just prepare 30 | cd ../.. 31 | done 32 | 33 | test: 34 | #!/usr/bin/env bash 35 | set -eou pipefail 36 | xtp plugin build --path test/testsuite 37 | 38 | for dir in servlets/*/; do 39 | cd "$dir" 40 | echo "Testing $dir" 41 | xtp plugin test --allow-host '*' --log-level warn 42 | cd ../.. 43 | done 44 | -------------------------------------------------------------------------------- /servlets/amadeus-flight-api/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /servlets/amadeus-flight-api/go.mod: -------------------------------------------------------------------------------- 1 | module amadeus-flight-api 2 | 3 | go 1.23 4 | 5 | require github.com/extism/go-pdk v1.0.5 6 | -------------------------------------------------------------------------------- /servlets/amadeus-flight-api/go.sum: -------------------------------------------------------------------------------- 1 | github.com/extism/go-pdk v1.0.5 h1:5d5yYkWBweBP84Z+H3DP5DsD0fwvf2anWXyypCXpSW8= 2 | github.com/extism/go-pdk v1.0.5/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 3 | -------------------------------------------------------------------------------- /servlets/amadeus-flight-api/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | # Function to compare version numbers for "less than" 10 | version_lt() { 11 | test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" = "$1" && test "$1" != "$2" 12 | } 13 | 14 | missing_deps=0 15 | 16 | # Check for Go 17 | if ! (command_exists go); then 18 | missing_deps=1 19 | echo "❌ Go (supported version between 1.20 - 1.24) is not installed." 20 | echo "" 21 | echo "To install Go, visit the official download page:" 22 | echo "👉 https://go.dev/dl/" 23 | echo "" 24 | echo "Or install it using a package manager:" 25 | echo "" 26 | echo "🔹 macOS (Homebrew):" 27 | echo " brew install go" 28 | echo "" 29 | echo "🔹 Ubuntu/Debian:" 30 | echo " sudo apt-get -y install golang-go" 31 | echo "" 32 | echo "🔹 Arch Linux:" 33 | echo " sudo pacman -S go" 34 | echo "" 35 | echo "🔹 Windows:" 36 | echo " scoop install go" 37 | echo "" 38 | fi 39 | 40 | # Check for the right version of Go, needed by TinyGo (supports go 1.20 - 1.24) 41 | if (command_exists go); then 42 | compat=0 43 | for v in `seq 20 24`; do 44 | if (go version | grep -q "go1.$v"); then 45 | compat=1 46 | fi 47 | done 48 | 49 | if [ $compat -eq 0 ]; then 50 | echo "❌ Supported Go version is not installed. Must be Go 1.20 - 1.24." 51 | echo "" 52 | fi 53 | fi 54 | 55 | ARCH=$(arch) 56 | 57 | # Check for TinyGo and its version 58 | if ! (command_exists tinygo); then 59 | missing_deps=1 60 | echo "❌ TinyGo is not installed." 61 | echo "" 62 | echo "To install TinyGo, visit the official download page:" 63 | echo "👉 https://tinygo.org/getting-started/install/" 64 | echo "" 65 | echo "Or install it using a package manager:" 66 | echo "" 67 | echo "🔹 macOS (Homebrew):" 68 | echo " brew tap tinygo-org/tools" 69 | echo " brew install tinygo" 70 | echo "" 71 | echo "🔹 Ubuntu/Debian:" 72 | echo " wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_$ARCH.deb" 73 | echo " sudo dpkg -i tinygo_0.34.0_$ARCH.deb" 74 | echo "" 75 | echo "🔹 Arch Linux:" 76 | echo " pacman -S extra/tinygo" 77 | echo "" 78 | echo "🔹 Windows:" 79 | echo " scoop install tinygo" 80 | echo "" 81 | else 82 | # Check TinyGo version 83 | tinygo_version=$(tinygo version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n1) 84 | if version_lt "$tinygo_version" "0.34.0"; then 85 | missing_deps=1 86 | echo "❌ TinyGo version must be >= 0.34.0 (current version: $tinygo_version)" 87 | echo "Please update TinyGo to a newer version." 88 | echo "" 89 | fi 90 | fi 91 | 92 | go install golang.org/x/tools/cmd/goimports@latest 93 | -------------------------------------------------------------------------------- /servlets/amadeus-flight-api/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "amadeus-flight-api" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "mkdir -p dist && tinygo build -target wasi -o dist/plugin.wasm ." 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "go fmt && go mod tidy && goimports -w main.go" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "sh prepare.sh && go get ./..." 18 | -------------------------------------------------------------------------------- /servlets/assembly-ai/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm -------------------------------------------------------------------------------- /servlets/assembly-ai/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: run clean 2 | 3 | # Build target with caching - only rebuilds if source files change 4 | dist/plugin.wasm: $(shell find . -name '*.go') 5 | xtp plugin build 6 | 7 | # Run the WordPress categories list command 8 | run: dist/plugin.wasm 9 | ./test.sh 10 | 11 | # Clean built files 12 | clean: 13 | rm -f dist/plugin.wasm 14 | 15 | # Default target 16 | .DEFAULT_GOAL := run -------------------------------------------------------------------------------- /servlets/assembly-ai/data/hello.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dylibso/mcp.run-servlets/006e737a53ae666dec24655874d74ecf6d381f5c/servlets/assembly-ai/data/hello.mp3 -------------------------------------------------------------------------------- /servlets/assembly-ai/go.mod: -------------------------------------------------------------------------------- 1 | module AssemblyAI 2 | 3 | go 1.22.1 4 | 5 | require github.com/extism/go-pdk v1.1.0 6 | 7 | require github.com/extism/go-pdk/wasi-reactor v0.0.0-20241120064915-15022184ecbe // indirect 8 | -------------------------------------------------------------------------------- /servlets/assembly-ai/go.sum: -------------------------------------------------------------------------------- 1 | github.com/extism/go-pdk v1.0.5 h1:5d5yYkWBweBP84Z+H3DP5DsD0fwvf2anWXyypCXpSW8= 2 | github.com/extism/go-pdk v1.0.5/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 3 | github.com/extism/go-pdk v1.1.0 h1:K2On6XOERxrYdsgu0uLzCxeu/FYRHE8jId/hdEVSYoY= 4 | github.com/extism/go-pdk v1.1.0/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 5 | github.com/extism/go-pdk/wasi-reactor v0.0.0-20241120064915-15022184ecbe h1:UHtP9rWm95bdsKNrpSenYhfAcIV0Rien36vy7ecq+VE= 6 | github.com/extism/go-pdk/wasi-reactor v0.0.0-20241120064915-15022184ecbe/go.mod h1:WDu1fWWoFToXBPq+vRAnfFROFFdPayxGbiXf8ysq+no= 7 | -------------------------------------------------------------------------------- /servlets/assembly-ai/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | # Function to compare version numbers for "less than" 10 | version_lt() { 11 | test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" = "$1" && test "$1" != "$2" 12 | } 13 | 14 | missing_deps=0 15 | 16 | # Check for Go 17 | if ! (command_exists go); then 18 | missing_deps=1 19 | echo "❌ Go (supported version between 1.20 - 1.24) is not installed." 20 | echo "" 21 | echo "To install Go, visit the official download page:" 22 | echo "👉 https://go.dev/dl/" 23 | echo "" 24 | echo "Or install it using a package manager:" 25 | echo "" 26 | echo "🔹 macOS (Homebrew):" 27 | echo " brew install go" 28 | echo "" 29 | echo "🔹 Ubuntu/Debian:" 30 | echo " sudo apt-get -y install golang-go" 31 | echo "" 32 | echo "🔹 Arch Linux:" 33 | echo " sudo pacman -S go" 34 | echo "" 35 | echo "🔹 Windows:" 36 | echo " scoop install go" 37 | echo "" 38 | fi 39 | 40 | # Check for the right version of Go, needed by TinyGo (supports go 1.20 - 1.24) 41 | if (command_exists go); then 42 | compat=0 43 | for v in `seq 20 24`; do 44 | if (go version | grep -q "go1.$v"); then 45 | compat=1 46 | fi 47 | done 48 | 49 | if [ $compat -eq 0 ]; then 50 | echo "❌ Supported Go version is not installed. Must be Go 1.20 - 1.24." 51 | echo "" 52 | fi 53 | fi 54 | 55 | ARCH=$(arch) 56 | 57 | # Check for TinyGo and its version 58 | if ! (command_exists tinygo); then 59 | missing_deps=1 60 | echo "❌ TinyGo is not installed." 61 | echo "" 62 | echo "To install TinyGo, visit the official download page:" 63 | echo "👉 https://tinygo.org/getting-started/install/" 64 | echo "" 65 | echo "Or install it using a package manager:" 66 | echo "" 67 | echo "🔹 macOS (Homebrew):" 68 | echo " brew tap tinygo-org/tools" 69 | echo " brew install tinygo" 70 | echo "" 71 | echo "🔹 Ubuntu/Debian:" 72 | echo " wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_$ARCH.deb" 73 | echo " sudo dpkg -i tinygo_0.34.0_$ARCH.deb" 74 | echo "" 75 | echo "🔹 Arch Linux:" 76 | echo " pacman -S extra/tinygo" 77 | echo "" 78 | echo "🔹 Windows:" 79 | echo " scoop install tinygo" 80 | echo "" 81 | else 82 | # Check TinyGo version 83 | tinygo_version=$(tinygo version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n1) 84 | if version_lt "$tinygo_version" "0.34.0"; then 85 | missing_deps=1 86 | echo "❌ TinyGo version must be >= 0.34.0 (current version: $tinygo_version)" 87 | echo "Please update TinyGo to a newer version." 88 | echo "" 89 | fi 90 | fi 91 | 92 | go install golang.org/x/tools/cmd/goimports@latest 93 | -------------------------------------------------------------------------------- /servlets/assembly-ai/test.sh: -------------------------------------------------------------------------------- 1 | extism call \ 2 | --allow-path "data:/" \ 3 | --allow-host "api.assemblyai.com" \ 4 | --verbose \ 5 | --config ASSEMBLYAI_API_KEY="$ASSEMBLYAI_API_KEY" \ 6 | --wasi \ 7 | --input "{\"params\":{\"name\":\"transcribe\",\"arguments\":{\"audio_path\":\"hello.mp3\"}}}" \ 8 | --log-level debug \ 9 | ./dist/plugin.wasm \ 10 | call -------------------------------------------------------------------------------- /servlets/assembly-ai/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | # This is the 'binding' name used for the plugin. 7 | name = "assembly-ai" 8 | 9 | [scripts] 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "mkdir -p dist && tinygo build -buildmode c-shared -target wasip1 -o dist/plugin.wasm ." 12 | 13 | # xtp plugin init runs this script to format the code 14 | format = "go fmt && go mod tidy && goimports -w main.go" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "sh prepare.sh && go get ./..." 18 | -------------------------------------------------------------------------------- /servlets/bluesky/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /servlets/bluesky/README.md: -------------------------------------------------------------------------------- 1 | # BlueSky Servlet 2 | 3 | Implements a reduced subset of the BlueSky OpenAPI spec. 4 | Currently it supports [posting and replying to a post][post] and [getting threads][thread]. 5 | 6 | Additionally, it provides the `latest_mentions` tool, returning a list 7 | a list of mentions to the given handle within a specified amount of time 8 | (e.g. "5 minutes ago", `5m`); this tool uses the [search][search] feature 9 | under the hood. 10 | 11 | [post]: https://docs.bsky.app/docs/api/com-atproto-repo-put-record 12 | [search]: https://docs.bsky.app/docs/api/app-bsky-feed-search-posts 13 | [thread]: https://docs.bsky.app/docs/api/app-bsky-feed-get-post-thread 14 | 15 | ## Config 16 | 17 | - `BASE_URL` defaults to `https://bsky.social` 18 | - `HANDLE` your handle 19 | - `PASSWORD` use an [app password](https://bsky.app/settings/app-passwords) 20 | 21 | ## Domains 22 | 23 | You should grant access to `bsky.social`. 24 | 25 | ## Example 26 | 27 | > You are a helpful bot called mcprunbot.bsky.social 28 | > You always use your tools if possible. 29 | > 30 | > Find all your recent mentions, within 5 minutes from now. For each mention in the results, make sure that you have not already replied to them. If you have not replied to a mention, then make sure you reply. 31 | > 32 | > Do not reply twice to the same mention, but make sure you reply to each mention. 33 | 34 | 35 | > I have checked the recent mentions of `@mcprunbot.bsky.social` and verified the replies: 36 | > 37 | > 1. **Mention 1**: Request to search for a tutorial to build a bot using mcp.run. 38 | > - **Status**: Already replied with a link to a tutorial on creating a Telegram bot using mcp.run. 39 | > 40 | > 2. **Mention 2**: Request to tell a joke to `@nilslice.bsky.social`. 41 | > - **Status**: Already replied with a joke: "Why don't scientists trust atoms? Because they make up everything! 😄" 42 | > 43 | > 3. **Mention 3**: Request to tell a little about mcp.run. 44 | > - **Status**: Already replied with a brief explanation of mcp.run and a link to the site. 45 | > 46 | > All recent mentions have been replied to, and no further action is needed. 47 | -------------------------------------------------------------------------------- /servlets/bluesky/go.mod: -------------------------------------------------------------------------------- 1 | module bluesky 2 | 3 | go 1.22.1 4 | 5 | require ( 6 | github.com/extism/go-pdk v1.0.5 7 | github.com/wasilibs/go-re2 v1.9.0 8 | ) 9 | 10 | require ( 11 | github.com/tetratelabs/wazero v1.9.0 // indirect 12 | github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 // indirect 13 | golang.org/x/sys v0.29.0 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /servlets/bluesky/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 2 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/extism/go-pdk v1.0.5 h1:5d5yYkWBweBP84Z+H3DP5DsD0fwvf2anWXyypCXpSW8= 4 | github.com/extism/go-pdk v1.0.5/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 5 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 6 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 8 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 9 | github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I= 10 | github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM= 11 | github.com/wasilibs/go-re2 v1.9.0 h1:kjAd8qbNvV4Ve2Uf+zrpTCrDHtqH4dlsRXktywo73JQ= 12 | github.com/wasilibs/go-re2 v1.9.0/go.mod h1:0sRtscWgpUdNA137bmr1IUgrRX0Su4dcn9AEe61y+yI= 13 | github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 h1:OvLBa8SqJnZ6P+mjlzc2K7PM22rRUPE1x32G9DTPrC4= 14 | github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52/go.mod h1:jMeV4Vpbi8osrE/pKUxRZkVaA0EX7NZN0A9/oRzgpgY= 15 | golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= 16 | golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 17 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 18 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 19 | -------------------------------------------------------------------------------- /servlets/bluesky/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | # Function to compare version numbers for "less than" 10 | version_lt() { 11 | test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" = "$1" && test "$1" != "$2" 12 | } 13 | 14 | missing_deps=0 15 | 16 | # Check for Go 17 | if ! (command_exists go); then 18 | missing_deps=1 19 | echo "❌ Go (supported version between 1.20 - 1.24) is not installed." 20 | echo "" 21 | echo "To install Go, visit the official download page:" 22 | echo "👉 https://go.dev/dl/" 23 | echo "" 24 | echo "Or install it using a package manager:" 25 | echo "" 26 | echo "🔹 macOS (Homebrew):" 27 | echo " brew install go" 28 | echo "" 29 | echo "🔹 Ubuntu/Debian:" 30 | echo " sudo apt-get -y install golang-go" 31 | echo "" 32 | echo "🔹 Arch Linux:" 33 | echo " sudo pacman -S go" 34 | echo "" 35 | echo "🔹 Windows:" 36 | echo " scoop install go" 37 | echo "" 38 | fi 39 | 40 | # Check for the right version of Go, needed by TinyGo (supports go 1.20 - 1.24) 41 | if (command_exists go); then 42 | compat=0 43 | for v in `seq 20 24`; do 44 | if (go version | grep -q "go1.$v"); then 45 | compat=1 46 | fi 47 | done 48 | 49 | if [ $compat -eq 0 ]; then 50 | echo "❌ Supported Go version is not installed. Must be Go 1.20 - 1.24." 51 | echo "" 52 | fi 53 | fi 54 | 55 | ARCH=$(arch) 56 | 57 | # Check for TinyGo and its version 58 | if ! (command_exists tinygo); then 59 | missing_deps=1 60 | echo "❌ TinyGo is not installed." 61 | echo "" 62 | echo "To install TinyGo, visit the official download page:" 63 | echo "👉 https://tinygo.org/getting-started/install/" 64 | echo "" 65 | echo "Or install it using a package manager:" 66 | echo "" 67 | echo "🔹 macOS (Homebrew):" 68 | echo " brew tap tinygo-org/tools" 69 | echo " brew install tinygo" 70 | echo "" 71 | echo "🔹 Ubuntu/Debian:" 72 | echo " wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_$ARCH.deb" 73 | echo " sudo dpkg -i tinygo_0.34.0_$ARCH.deb" 74 | echo "" 75 | echo "🔹 Arch Linux:" 76 | echo " pacman -S extra/tinygo" 77 | echo "" 78 | echo "🔹 Windows:" 79 | echo " scoop install tinygo" 80 | echo "" 81 | else 82 | # Check TinyGo version 83 | tinygo_version=$(tinygo version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n1) 84 | if version_lt "$tinygo_version" "0.34.0"; then 85 | missing_deps=1 86 | echo "❌ TinyGo version must be >= 0.34.0 (current version: $tinygo_version)" 87 | echo "Please update TinyGo to a newer version." 88 | echo "" 89 | fi 90 | fi 91 | 92 | go install golang.org/x/tools/cmd/goimports@latest 93 | -------------------------------------------------------------------------------- /servlets/bluesky/record.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Record struct { 4 | Type string `json:"$type"` 5 | Text string `json:"text"` 6 | Facets []Facet `json:"facets,omitempty"` 7 | CreatedAt string `json:"createdAt"` 8 | Reply *Reply `json:"reply,omitempty"` 9 | } 10 | 11 | type Reply struct { 12 | Root Post `json:"root"` 13 | Parent Post `json:"parent"` 14 | } 15 | 16 | type Post struct { 17 | URI string `json:"uri"` 18 | CID string `json:"cid"` 19 | } 20 | -------------------------------------------------------------------------------- /servlets/bluesky/session.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | 9 | "github.com/extism/go-pdk" 10 | ) 11 | 12 | type LoginPayload struct { 13 | Handle string `json:"identifier"` 14 | Password string `json:"password"` 15 | } 16 | 17 | type Session struct { 18 | AccessJwt string `json:"accessJwt"` 19 | DID string `json:"did"` 20 | } 21 | 22 | func loadConfig() error { 23 | BASE_URL, _ = pdk.GetConfig("BASE_URL") // default https://bsky.social 24 | HANDLE, _ = pdk.GetConfig("HANDLE") 25 | PASSWORD, _ = pdk.GetConfig("APP_PASSWORD") 26 | 27 | if BASE_URL == "" { 28 | BASE_URL = "https://bsky.social" 29 | } 30 | if HANDLE == "" { 31 | return errors.New("handle is required") 32 | } 33 | if PASSWORD == "" { 34 | return errors.New("password is required") 35 | } 36 | return nil 37 | } 38 | 39 | func loginSession() error { 40 | url := BASE_URL + "/xrpc/com.atproto.server.createSession" 41 | req := pdk.NewHTTPRequest(pdk.MethodPost, url) 42 | req.SetHeader("Content-Type", "application/json") 43 | loginPayload := LoginPayload{ 44 | Handle: HANDLE, 45 | Password: PASSWORD, 46 | } 47 | jsonBytes, err := json.Marshal(&loginPayload) 48 | if err != nil { 49 | return err 50 | } 51 | req.SetBody(jsonBytes) 52 | resp := req.Send() 53 | if resp.Status() != http.StatusOK { 54 | return fmt.Errorf("failed to login: %d, %s", resp.Status(), string(resp.Body())) 55 | } 56 | body := resp.Body() 57 | if err := json.Unmarshal(body, ¤tSession); err != nil { 58 | return err 59 | } 60 | pdk.Log(pdk.LogInfo, "logged in") 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /servlets/bluesky/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "bluesky" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "mkdir -p dist && tinygo build -target wasi -o dist/plugin.wasm ." 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "go fmt && go mod tidy && goimports -w main.go" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "sh prepare.sh && go get ./..." 18 | -------------------------------------------------------------------------------- /servlets/brave-search/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /servlets/brave-search/README.md: -------------------------------------------------------------------------------- 1 | ## Brave Search 2 | 3 | ## Config 4 | 5 | - `api-key`: see [Brave Search API Key](https://api.search.brave.com/app/keys) 6 | 7 | ## Domains 8 | 9 | - `api.search.brave.com` 10 | 11 | ## Tools 12 | 13 | - `brave-web-search` searches the Web for content (text, image, video, etc...). 14 | Generally suitable for text-based searches. 15 | - `brave-image-search` to search specifically for pictures. 16 | 17 | ## Example 18 | 19 | can you find me some funny cartoon santa pictures using brave search? 20 | 21 |
22 | 23 | I'll help you search for funny cartoon Santa pictures using Brave Search. 24 | 25 | [...] 26 | 27 | I found several funny cartoon Santa images! Here are a few highlights: 28 | 29 | A skating Santa Claus doing some winter sports - he's shown gliding along with a big smile 30 | A cheerful running Santa that looks quite energetic 31 | A cute Santa character with an especially jolly expression 32 | A set of different Santa poses showing him in various funny situations 33 | Since these are mostly stock images, I could try to draw you a simple cartoon Santa using SVG if you'd like! I can make something simple and fun. Would you like me to try that instead? 34 |
35 | 36 | please fetch one of those pictures for me! 37 | 38 |
39 | Let me try to fetch one of the skating Santa images I found. 40 | 41 | [...] 42 | 43 | There's the skating Santa! It shows him doing an elegant skating pose against a nighttime city backdrop, with his arms raised joyfully. The cartoon style is modern and cute, with a simple color palette of red, white, and dark blue. Would you like to see any of the other Santa images as well? 44 |
45 | 46 | ![](imgs/img-search-results.png) 47 | -------------------------------------------------------------------------------- /servlets/brave-search/go.mod: -------------------------------------------------------------------------------- 1 | module brave-search 2 | 3 | go 1.22.1 4 | 5 | require github.com/extism/go-pdk v1.0.5 6 | -------------------------------------------------------------------------------- /servlets/brave-search/go.sum: -------------------------------------------------------------------------------- 1 | github.com/extism/go-pdk v1.0.5 h1:5d5yYkWBweBP84Z+H3DP5DsD0fwvf2anWXyypCXpSW8= 2 | github.com/extism/go-pdk v1.0.5/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 3 | -------------------------------------------------------------------------------- /servlets/brave-search/imgs/img-search-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dylibso/mcp.run-servlets/006e737a53ae666dec24655874d74ecf6d381f5c/servlets/brave-search/imgs/img-search-results.png -------------------------------------------------------------------------------- /servlets/brave-search/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | # Function to compare version numbers for "less than" 10 | version_lt() { 11 | test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" = "$1" && test "$1" != "$2" 12 | } 13 | 14 | missing_deps=0 15 | 16 | # Check for Go 17 | if ! (command_exists go); then 18 | missing_deps=1 19 | echo "❌ Go (supported version between 1.20 - 1.24) is not installed." 20 | echo "" 21 | echo "To install Go, visit the official download page:" 22 | echo "👉 https://go.dev/dl/" 23 | echo "" 24 | echo "Or install it using a package manager:" 25 | echo "" 26 | echo "🔹 macOS (Homebrew):" 27 | echo " brew install go" 28 | echo "" 29 | echo "🔹 Ubuntu/Debian:" 30 | echo " sudo apt-get -y install golang-go" 31 | echo "" 32 | echo "🔹 Arch Linux:" 33 | echo " sudo pacman -S go" 34 | echo "" 35 | echo "🔹 Windows:" 36 | echo " scoop install go" 37 | echo "" 38 | fi 39 | 40 | # Check for the right version of Go, needed by TinyGo (supports go 1.20 - 1.24) 41 | if (command_exists go); then 42 | compat=0 43 | for v in `seq 20 24`; do 44 | if (go version | grep -q "go1.$v"); then 45 | compat=1 46 | fi 47 | done 48 | 49 | if [ $compat -eq 0 ]; then 50 | echo "❌ Supported Go version is not installed. Must be Go 1.20 - 1.24." 51 | echo "" 52 | fi 53 | fi 54 | 55 | ARCH=$(arch) 56 | 57 | # Check for TinyGo and its version 58 | if ! (command_exists tinygo); then 59 | missing_deps=1 60 | echo "❌ TinyGo is not installed." 61 | echo "" 62 | echo "To install TinyGo, visit the official download page:" 63 | echo "👉 https://tinygo.org/getting-started/install/" 64 | echo "" 65 | echo "Or install it using a package manager:" 66 | echo "" 67 | echo "🔹 macOS (Homebrew):" 68 | echo " brew tap tinygo-org/tools" 69 | echo " brew install tinygo" 70 | echo "" 71 | echo "🔹 Ubuntu/Debian:" 72 | echo " wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_$ARCH.deb" 73 | echo " sudo dpkg -i tinygo_0.34.0_$ARCH.deb" 74 | echo "" 75 | echo "🔹 Arch Linux:" 76 | echo " pacman -S extra/tinygo" 77 | echo "" 78 | echo "🔹 Windows:" 79 | echo " scoop install tinygo" 80 | echo "" 81 | else 82 | # Check TinyGo version 83 | tinygo_version=$(tinygo version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n1) 84 | if version_lt "$tinygo_version" "0.34.0"; then 85 | missing_deps=1 86 | echo "❌ TinyGo version must be >= 0.34.0 (current version: $tinygo_version)" 87 | echo "Please update TinyGo to a newer version." 88 | echo "" 89 | fi 90 | fi 91 | 92 | go install golang.org/x/tools/cmd/goimports@latest 93 | -------------------------------------------------------------------------------- /servlets/brave-search/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "brave-search" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "mkdir -p dist && tinygo build -target wasi -o dist/plugin.wasm ." 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "go fmt && go mod tidy && goimports -w main.go" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "sh prepare.sh && go get ./..." 18 | -------------------------------------------------------------------------------- /servlets/crypto-hash/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm -------------------------------------------------------------------------------- /servlets/crypto-hash/go.mod: -------------------------------------------------------------------------------- 1 | module crypto-hash 2 | 3 | go 1.22.1 4 | 5 | require github.com/extism/go-pdk v1.0.5 6 | 7 | require golang.org/x/crypto v0.31.0 // indirect 8 | -------------------------------------------------------------------------------- /servlets/crypto-hash/go.sum: -------------------------------------------------------------------------------- 1 | github.com/extism/go-pdk v1.0.5 h1:5d5yYkWBweBP84Z+H3DP5DsD0fwvf2anWXyypCXpSW8= 2 | github.com/extism/go-pdk v1.0.5/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 3 | golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= 4 | golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= 5 | -------------------------------------------------------------------------------- /servlets/crypto-hash/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | # Function to compare version numbers for "less than" 10 | version_lt() { 11 | test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" = "$1" && test "$1" != "$2" 12 | } 13 | 14 | missing_deps=0 15 | 16 | # Check for Go 17 | if ! (command_exists go); then 18 | missing_deps=1 19 | echo "❌ Go (supported version between 1.20 - 1.24) is not installed." 20 | echo "" 21 | echo "To install Go, visit the official download page:" 22 | echo "👉 https://go.dev/dl/" 23 | echo "" 24 | echo "Or install it using a package manager:" 25 | echo "" 26 | echo "🔹 macOS (Homebrew):" 27 | echo " brew install go" 28 | echo "" 29 | echo "🔹 Ubuntu/Debian:" 30 | echo " sudo apt-get -y install golang-go" 31 | echo "" 32 | echo "🔹 Arch Linux:" 33 | echo " sudo pacman -S go" 34 | echo "" 35 | echo "🔹 Windows:" 36 | echo " scoop install go" 37 | echo "" 38 | fi 39 | 40 | # Check for the right version of Go, needed by TinyGo (supports go 1.20 - 1.24) 41 | if (command_exists go); then 42 | compat=0 43 | for v in `seq 20 24`; do 44 | if (go version | grep -q "go1.$v"); then 45 | compat=1 46 | fi 47 | done 48 | 49 | if [ $compat -eq 0 ]; then 50 | echo "❌ Supported Go version is not installed. Must be Go 1.20 - 1.24." 51 | echo "" 52 | fi 53 | fi 54 | 55 | ARCH=$(arch) 56 | 57 | # Check for TinyGo and its version 58 | if ! (command_exists tinygo); then 59 | missing_deps=1 60 | echo "❌ TinyGo is not installed." 61 | echo "" 62 | echo "To install TinyGo, visit the official download page:" 63 | echo "👉 https://tinygo.org/getting-started/install/" 64 | echo "" 65 | echo "Or install it using a package manager:" 66 | echo "" 67 | echo "🔹 macOS (Homebrew):" 68 | echo " brew tap tinygo-org/tools" 69 | echo " brew install tinygo" 70 | echo "" 71 | echo "🔹 Ubuntu/Debian:" 72 | echo " wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_$ARCH.deb" 73 | echo " sudo dpkg -i tinygo_0.34.0_$ARCH.deb" 74 | echo "" 75 | echo "🔹 Arch Linux:" 76 | echo " pacman -S extra/tinygo" 77 | echo "" 78 | echo "🔹 Windows:" 79 | echo " scoop install tinygo" 80 | echo "" 81 | else 82 | # Check TinyGo version 83 | tinygo_version=$(tinygo version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n1) 84 | if version_lt "$tinygo_version" "0.34.0"; then 85 | missing_deps=1 86 | echo "❌ TinyGo version must be >= 0.34.0 (current version: $tinygo_version)" 87 | echo "Please update TinyGo to a newer version." 88 | echo "" 89 | fi 90 | fi 91 | 92 | go install golang.org/x/tools/cmd/goimports@latest 93 | -------------------------------------------------------------------------------- /servlets/crypto-hash/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "crypto-hash" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "mkdir -p dist && tinygo build -target wasi -o dist/plugin.wasm ." 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "go fmt && go mod tidy && goimports -w main.go" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh && go get ./..." 18 | -------------------------------------------------------------------------------- /servlets/currency-converter/.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | IndentWidth: 2 3 | AllowShortFunctionsOnASingleLine: Empty 4 | -------------------------------------------------------------------------------- /servlets/currency-converter/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | dist/ 3 | wasi-sdk/ 4 | include/ 5 | -------------------------------------------------------------------------------- /servlets/currency-converter/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(origin WASI_SDK_PATH),undefined) 2 | WASI_SDK_PATH=./wasi-sdk 3 | ifeq ("$(wildcard ./wasi-sdk)","") 4 | $(shell chmod +x ./install-wasi-sdk.sh) 5 | $(shell ./install-wasi-sdk.sh) 6 | endif 7 | endif 8 | 9 | .PHONY: build 10 | build: dist/plugin.wasm 11 | 12 | .PHONY: fetchdeps 13 | fetchdeps: include/extism-pdk.hpp include/magic_enum/include/magic_enum include/jsoncons/include 14 | 15 | 16 | .PHONY: format 17 | format: 18 | $(WASI_SDK_PATH)/bin/clang-format -i *.cpp *.hpp 19 | 20 | .PHONY: clean 21 | clean: 22 | rm -f dist/*.wasm *.o 23 | 24 | .PHONY: veryclean 25 | veryclean: clean 26 | rm -rf include ./wasi-sdk 27 | 28 | 29 | include/extism-pdk.hpp: 30 | mkdir -p include 31 | cd include && \ 32 | curl -OsL https://raw.githubusercontent.com/extism/cpp-pdk/refs/tags/v0.1.0/extism-pdk.hpp 33 | 34 | include/magic_enum/include/magic_enum: 35 | mkdir -p include/magic_enum 36 | cd include/magic_enum && \ 37 | curl -OsL https://github.com/Neargye/magic_enum/releases/download/v0.9.6/magic_enum-v0.9.6.tar.gz && \ 38 | tar xf magic_enum-v0.9.6.tar.gz 39 | 40 | include/jsoncons/include: 41 | mkdir -p include 42 | cd include && \ 43 | curl -OsL https://github.com/danielaparker/jsoncons/archive/refs/tags/v0.177.0.zip && \ 44 | unzip -qq v0.177.0.zip && \ 45 | mv jsoncons-0.177.0 jsoncons 46 | 47 | pdk.gen.o: pdk.gen.cpp pdk.gen.hpp include/extism-pdk.hpp include/magic_enum/include/magic_enum include/jsoncons/include 48 | $(WASI_SDK_PATH)/bin/clang++ -Iinclude -Iinclude/jsoncons/include -Iinclude/magic_enum/include/magic_enum -std=c++23 -fno-exceptions -O2 -g -c pdk.gen.cpp 49 | 50 | impl.o: impl.cpp pdk.gen.hpp include/extism-pdk.hpp include/magic_enum/include/magic_enum include/jsoncons/include 51 | $(WASI_SDK_PATH)/bin/clang++ -Iinclude -Iinclude/jsoncons/include -Iinclude/magic_enum/include/magic_enum -std=c++23 -fno-exceptions -O2 -g -c impl.cpp 52 | 53 | dist/plugin.wasm: pdk.gen.o impl.o 54 | mkdir -p dist 55 | $(WASI_SDK_PATH)/bin/clang++ -std=c++23 -fno-exceptions -O2 -g -o $@ $^ -mexec-model=reactor 56 | -------------------------------------------------------------------------------- /servlets/currency-converter/README.md: -------------------------------------------------------------------------------- 1 | # Currency Converter Servlet 2 | 3 | A servlet that converts amounts between different currencies using current exchange rates. 4 | 5 | ## What it does 6 | 7 | Takes an amount and currency codes, returns the converted amount using current rates from fxratesapi.com. 8 | 9 | ## Usage 10 | 11 | Call with: 12 | ```typescript 13 | { 14 | arguments: { 15 | amount: 100, // Required: amount to convert 16 | from: "USD", // Required: source currency code 17 | to: "EUR" // Required: target currency code 18 | } 19 | } 20 | ``` 21 | 22 | Returns the converted amount as a string. -------------------------------------------------------------------------------- /servlets/currency-converter/install-wasi-sdk.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Orignal from: https://github.com/Shopify/javy 3 | 4 | set -euo pipefail 5 | 6 | PATH_TO_SDK="./wasi-sdk" 7 | if [[ ! -d $PATH_TO_SDK ]]; then 8 | TMPGZ=$(mktemp) 9 | VERSION_MAJOR="24" 10 | VERSION_MINOR="0" 11 | ARCH=$(uname -m) 12 | if [[ "$(uname -s)" == "Darwin" ]]; then 13 | curl --fail --location --silent https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${VERSION_MAJOR}/wasi-sdk-${VERSION_MAJOR}.${VERSION_MINOR}-${ARCH}-macos.tar.gz --output $TMPGZ 14 | else 15 | curl --fail --location --silent https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${VERSION_MAJOR}/wasi-sdk-${VERSION_MAJOR}.${VERSION_MINOR}-${ARCH}-linux.tar.gz --output $TMPGZ 16 | fi 17 | mkdir $PATH_TO_SDK 18 | tar xf $TMPGZ -C $PATH_TO_SDK --strip-components=1 19 | fi 20 | -------------------------------------------------------------------------------- /servlets/currency-converter/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "currency-converter" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "make -j4" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "make format" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "make wasisdk" 18 | 19 | 20 | [[test]] 21 | name = "basic tests" 22 | with = "../../test/testsuite/dist/test.wasm" 23 | -------------------------------------------------------------------------------- /servlets/electricity-magnetism/.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | 11 | pids 12 | logs 13 | results 14 | tmp 15 | 16 | # Build 17 | public/css/main.css 18 | 19 | # Coverage reports 20 | coverage 21 | 22 | # API keys and secrets 23 | .env 24 | 25 | # Dependency directory 26 | node_modules 27 | bower_components 28 | 29 | # Editors 30 | .idea 31 | *.iml 32 | 33 | # OS metadata 34 | .DS_Store 35 | Thumbs.db 36 | 37 | # Ignore built ts files 38 | dist/**/* 39 | 40 | # ignore yarn.lock 41 | yarn.lock 42 | 43 | -------------------------------------------------------------------------------- /servlets/electricity-magnetism/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .git 4 | 5 | -------------------------------------------------------------------------------- /servlets/electricity-magnetism/.prettierrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dylibso/mcp.run-servlets/006e737a53ae666dec24655874d74ecf6d381f5c/servlets/electricity-magnetism/.prettierrc -------------------------------------------------------------------------------- /servlets/electricity-magnetism/esbuild.js: -------------------------------------------------------------------------------- 1 | const esbuild = require('esbuild'); 2 | 3 | esbuild 4 | .build({ 5 | entryPoints: ['src/index.ts'], 6 | outdir: 'dist', 7 | bundle: true, 8 | sourcemap: true, 9 | minify: false, // might want to use true for production build 10 | format: 'cjs', // needs to be CJS for now 11 | target: ['es2020'], // don't go over es2020 because quickjs doesn't support it 12 | }) 13 | -------------------------------------------------------------------------------- /servlets/electricity-magnetism/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electricity-magnetism", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.ts", 6 | "scripts": { 7 | "build": "npx tsc --noEmit && node esbuild.js && extism-js dist/index.js -i src/index.d.ts -o dist/plugin.wasm", 8 | "format": "npx prettier --write \"src/**/*.{ts,tsx}\" --plugin=prettier-plugin-organize-imports" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "private": true, 13 | "license": "UNLICENSED", 14 | "devDependencies": { 15 | "@extism/js-pdk": "^1.0.1", 16 | "esbuild": "^0.19.6", 17 | "typescript": "^5.3.2", 18 | "prettier": "^3.3.2", 19 | "prettier-plugin-organize-imports": "^4.1.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /servlets/electricity-magnetism/src/constants.ts: -------------------------------------------------------------------------------- 1 | // src/constants.ts 2 | export const CONSTANTS = { 3 | EPSILON_0: 8.854e-12, // Vacuum permittivity in F/m 4 | MU_0: 4 * Math.PI * 1e-7, // Vacuum permeability in H/m 5 | K: 1 / (4 * Math.PI * 8.854e-12), // Coulomb constant 6 | }; 7 | -------------------------------------------------------------------------------- /servlets/electricity-magnetism/src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "main" { 2 | export function call(): I32; 3 | export function describe(): I32; 4 | } 5 | -------------------------------------------------------------------------------- /servlets/electricity-magnetism/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as main from "./main"; 2 | 3 | import { CallToolRequest, CallToolResult, ListToolsResult } from "./pdk"; 4 | 5 | export function call(): number { 6 | const untypedInput = JSON.parse(Host.inputString()); 7 | const input = CallToolRequest.fromJson(untypedInput); 8 | 9 | const output = main.callImpl(input); 10 | 11 | const untypedOutput = CallToolResult.toJson(output); 12 | Host.outputString(JSON.stringify(untypedOutput)); 13 | 14 | return 0; 15 | } 16 | 17 | export function describe(): number { 18 | const output = main.describeImpl(); 19 | 20 | const untypedOutput = ListToolsResult.toJson(output); 21 | Host.outputString(JSON.stringify(untypedOutput)); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /servlets/electricity-magnetism/src/math.ts: -------------------------------------------------------------------------------- 1 | import { Vector3D } from "./types"; 2 | 3 | // src/math.ts 4 | export class Vector3DMath { 5 | static magnitude(v: Vector3D): number { 6 | return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); 7 | } 8 | 9 | static normalize(v: Vector3D): Vector3D { 10 | const mag = this.magnitude(v); 11 | return { 12 | x: v.x / mag, 13 | y: v.y / mag, 14 | z: v.z / mag, 15 | }; 16 | } 17 | 18 | static subtract(a: Vector3D, b: Vector3D): Vector3D { 19 | return { 20 | x: a.x - b.x, 21 | y: a.y - b.y, 22 | z: a.z - b.z, 23 | }; 24 | } 25 | 26 | static crossProduct(a: Vector3D, b: Vector3D): Vector3D { 27 | return { 28 | x: a.y * b.z - a.z * b.y, 29 | y: a.z * b.x - a.x * b.z, 30 | z: a.x * b.y - a.y * b.x, 31 | }; 32 | } 33 | 34 | static scale(v: Vector3D, scalar: number): Vector3D { 35 | return { 36 | x: v.x * scalar, 37 | y: v.y * scalar, 38 | z: v.z * scalar, 39 | }; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /servlets/electricity-magnetism/src/types.ts: -------------------------------------------------------------------------------- 1 | // src/types.ts 2 | export interface Vector3D { 3 | x: number; 4 | y: number; 5 | z: number; 6 | } 7 | -------------------------------------------------------------------------------- /servlets/electricity-magnetism/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", // Specify ECMAScript target version 4 | "module": "commonjs", // Specify module code generation 5 | "lib": [ 6 | "es2020" 7 | ], // Specify a list of library files to be included in the compilation 8 | "types": [ 9 | "@extism/js-pdk", 10 | "./src/index.d.ts" 11 | ], // Specify a list of type definition files to be included in the compilation 12 | "strict": true, // Enable all strict type-checking options 13 | "esModuleInterop": true, // Enables compatibility with Babel-style module imports 14 | "skipLibCheck": true, // Skip type checking of declaration files 15 | "allowJs": true, // Allow JavaScript files to be compiled 16 | "noEmit": true // Do not emit outputs (no .js or .d.ts files) 17 | }, 18 | "include": [ 19 | "src/**/*.ts" // Include all TypeScript files in src directory 20 | ], 21 | "exclude": [ 22 | "node_modules" // Exclude the node_modules directory 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /servlets/electricity-magnetism/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "electricity-magnetism" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "bash prepare.sh && npm run build" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "npm run format" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | 19 | [[test]] 20 | name = "basic tests" 21 | with = "../../test/testsuite/dist/test.wasm" 22 | -------------------------------------------------------------------------------- /servlets/eval-py/.gitignore: -------------------------------------------------------------------------------- 1 | plugin.wasm 2 | plugin/__pycache__ 3 | -------------------------------------------------------------------------------- /servlets/eval-py/README.md: -------------------------------------------------------------------------------- 1 | # Python Eval Servlet 2 | 3 | A simple servlet that evaluates Python code in a CPython Wasm sandbox and returns the result. 4 | 5 | ## What it does 6 | 7 | Takes Python code as input, evaluates it using `exec()`, and returns the stdout output as a string. 8 | 9 | ## Usage 10 | 11 | Call with: 12 | 13 | ```json 14 | { 15 | "arguments": { 16 | "code": "print(2 + 2)" // Required: Python code to evaluate 17 | } 18 | } 19 | ``` 20 | 21 | Returns: 22 | 23 | ``` 24 | 4 25 | ``` 26 | -------------------------------------------------------------------------------- /servlets/eval-py/plugin/__init__.py: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS GENERATED BY `xtp-python-bindgen`. DO NOT EDIT. 2 | 3 | from typing import Optional, List # noqa: F401 4 | from datetime import datetime # noqa: F401 5 | import json 6 | import extism # pyright: ignore 7 | import plugin 8 | 9 | 10 | from pdk_types import ( 11 | BlobResourceContents, 12 | CallToolRequest, 13 | CallToolResult, 14 | Content, 15 | ContentType, 16 | ListToolsResult, 17 | Params, 18 | Role, 19 | TextAnnotation, 20 | TextResourceContents, 21 | ToolDescription, 22 | ) # noqa: F401 23 | 24 | 25 | # Imports 26 | 27 | 28 | # Exports 29 | # The implementations for these functions is in `plugin.py` 30 | 31 | 32 | # Called when the tool is invoked. 33 | # If you support multiple tools, you must switch on the input.params.name to detect which tool is being called. 34 | @extism.plugin_fn 35 | def call(): 36 | input = extism.input_str() 37 | input = CallToolRequest.from_json(input) 38 | res = plugin.call(input) 39 | extism.output_str(res.to_json()) 40 | 41 | 42 | # Called by mcpx to understand how and why to use this tool. 43 | # Note: Your servlet configs will not be set when this function is called, 44 | # so do not rely on config in this function 45 | @extism.plugin_fn 46 | def describe(): 47 | res = plugin.describe() 48 | extism.output_str(res.to_json()) 49 | -------------------------------------------------------------------------------- /servlets/eval-py/plugin/pdk_imports.py: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS GENERATED BY `xtp-python-bindgen`. DO NOT EDIT. 2 | 3 | from typing import Optional, List # noqa: F401 4 | from datetime import datetime # noqa: F401 5 | import extism # noqa: F401 # pyright: ignore 6 | import json 7 | 8 | 9 | from pdk_types import ( 10 | BlobResourceContents, 11 | CallToolRequest, 12 | CallToolResult, 13 | Content, 14 | ContentType, 15 | ListToolsResult, 16 | Params, 17 | Role, 18 | TextAnnotation, 19 | TextResourceContents, 20 | ToolDescription, 21 | ) # noqa: F401 22 | -------------------------------------------------------------------------------- /servlets/eval-py/plugin/plugin.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, List # noqa: F401 2 | from datetime import datetime # noqa: F401 3 | import extism # noqa: F401 # pyright: ignore 4 | import traceback 5 | from io import StringIO 6 | import sys 7 | 8 | from pdk_types import ( 9 | BlobResourceContents, 10 | CallToolRequest, 11 | CallToolResult, 12 | Content, 13 | ContentType, 14 | ListToolsResult, 15 | Params, 16 | Role, 17 | TextAnnotation, 18 | TextResourceContents, 19 | ToolDescription, 20 | ) # noqa: F401 21 | 22 | 23 | from typing import List, Optional # noqa: F401 24 | 25 | 26 | # Called when the tool is invoked. 27 | # If you support multiple tools, you must switch on the input.params.name to detect which tool is being called. 28 | def call(input: CallToolRequest) -> CallToolResult: 29 | try: 30 | code = input.params.arguments['code'] 31 | output = StringIO() 32 | old_stdout = sys.stdout 33 | sys.stdout = output 34 | exec(code) 35 | sys.stdout = old_stdout 36 | result = output.getvalue() 37 | output.close() 38 | isError = False 39 | except Exception as e: 40 | result = "\n".join([ 41 | "Traceback (most recent call last):", 42 | traceback.format_tb(e.__traceback__)[0].rstrip(), 43 | f"{type(e).__name__}: {e}" 44 | ]) 45 | isError = True 46 | return CallToolResult( 47 | content=[ 48 | Content( 49 | text=result, 50 | mimeType="text/plain", 51 | type=ContentType.Text, 52 | annotations=None, 53 | data=None, 54 | ) 55 | ], 56 | isError=isError, 57 | ) 58 | 59 | # Called by mcpx to understand how and why to use this tool. 60 | # Note: Your servlet configs will not be set when this function is called, 61 | # so do not rely on config in this function 62 | def describe() -> ListToolsResult: 63 | return ListToolsResult( 64 | [ 65 | ToolDescription( 66 | name="eval-py", 67 | description="Evaluate some Python using `exec()` in a sandbox.", 68 | inputSchema={ 69 | "type": "object", 70 | "properties": { 71 | "code": { 72 | "type": "string", 73 | "description": "The Python code to eval. This code gets passed into `exec()` and the stdout output is returned.", 74 | }, 75 | }, 76 | "required": ["code"], 77 | }, 78 | ) 79 | ] 80 | ) 81 | -------------------------------------------------------------------------------- /servlets/eval-py/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to check if a command exists 4 | command_exists () { 5 | command -v "$1" >/dev/null 2>&1 6 | } 7 | 8 | missing_deps=0 9 | 10 | # Check for uv 11 | if ! (command_exists uv); then 12 | missing_deps=1 13 | echo "❌ uv is not installed." 14 | echo "" 15 | echo "To install uv, visit the official download page:" 16 | echo "👉 https://docs.astral.sh/uv/getting-started/installation/" 17 | echo "" 18 | fi 19 | 20 | # Exit with a bad exit code if any dependencies are missing 21 | if [ "$missing_deps" -ne 0 ]; then 22 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 23 | # TODO: remove sleep when cli bug is fixed 24 | sleep 2 25 | exit 1 26 | fi 27 | 28 | # Check for extism-js 29 | if ! command_exists extism-py; then 30 | echo "❌ extism-py is not installed." 31 | echo "" 32 | echo "extism-py is needed to compile the plug-in. You can find the instructions to install it here: https://github.com/extism/python-pdk" 33 | echo "" 34 | echo "Alternatively, you can use an install script." 35 | echo "" 36 | echo "🔹 Mac / Linux:" 37 | echo "curl -L https://raw.githubusercontent.com/extism/python-pdk/main/install.sh | bash" 38 | echo "" 39 | # TODO: remove sleep when cli bug is fixed 40 | sleep 2 41 | exit 1 42 | fi 43 | -------------------------------------------------------------------------------- /servlets/eval-py/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "eval-py" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.13,<3.14" 7 | dependencies = [ 8 | "dataclass-wizard>=0.33.0,<0.34.0" 9 | ] 10 | 11 | [tool.uv] 12 | dev-dependencies = [ 13 | "pyright>=1.1.381", 14 | "ruff>=0.6.5", 15 | ] 16 | -------------------------------------------------------------------------------- /servlets/eval-py/pyrightconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "executionEnvironments": [ 3 | {"root": "plugin"} 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /servlets/eval-py/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "eval-py" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "PYTHONPATH=./plugin:./.venv/lib/python3.13/site-packages extism-py -o plugin.wasm plugin/__init__.py" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "uv run ruff format plugin/*.py" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh && uv sync" 18 | 19 | [[test]] 20 | name = "basic tests" 21 | with = "../../test/testsuite/dist/test.wasm" 22 | -------------------------------------------------------------------------------- /servlets/eval_js/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules 3 | -------------------------------------------------------------------------------- /servlets/eval_js/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .git 4 | 5 | -------------------------------------------------------------------------------- /servlets/eval_js/.prettierrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dylibso/mcp.run-servlets/006e737a53ae666dec24655874d74ecf6d381f5c/servlets/eval_js/.prettierrc -------------------------------------------------------------------------------- /servlets/eval_js/README.md: -------------------------------------------------------------------------------- 1 | # JavaScript Eval Servlet 2 | 3 | A simple servlet that evaluates JavaScript code in a QuickJS Wasm sandbox and returns the result. 4 | 5 | ## What it does 6 | 7 | Takes JavaScript code as input, evaluates it using `eval()`, and returns the result as a string. 8 | 9 | ## Usage 10 | 11 | Call with: 12 | ```typescript 13 | { 14 | arguments: { 15 | code: "2 + 2" // Required: JavaScript code to evaluate 16 | } 17 | } 18 | ``` 19 | 20 | Returns: 21 | ```typescript 22 | "4" 23 | ``` 24 | 25 | Note: Don't use `console.log()` in the code - the result needs to be returned directly. 26 | -------------------------------------------------------------------------------- /servlets/eval_js/esbuild.js: -------------------------------------------------------------------------------- 1 | const esbuild = require('esbuild'); 2 | 3 | esbuild 4 | .build({ 5 | entryPoints: ['src/index.ts'], 6 | outdir: 'dist', 7 | bundle: true, 8 | sourcemap: true, 9 | minify: false, // might want to use true for production build 10 | format: 'cjs', // needs to be CJS for now 11 | target: ['es2020'], // don't go over es2020 because quickjs doesn't support it 12 | }) 13 | -------------------------------------------------------------------------------- /servlets/eval_js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eval_js", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.ts", 6 | "scripts": { 7 | "build": "npx tsc --noEmit && node esbuild.js && extism-js dist/index.js -i src/index.d.ts -o dist/plugin.wasm", 8 | "format": "npx prettier --write \"src/**/*.{ts,tsx}\" --plugin=prettier-plugin-organize-imports" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "private": true, 13 | "license": "UNLICENSED", 14 | "devDependencies": { 15 | "@extism/js-pdk": "^1.0.1", 16 | "esbuild": "^0.19.6", 17 | "typescript": "^5.3.2", 18 | "prettier": "^3.3.2", 19 | "prettier-plugin-organize-imports": "^4.1.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /servlets/eval_js/src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "main" { 2 | export function call(): I32; 3 | export function describe(): I32; 4 | } 5 | -------------------------------------------------------------------------------- /servlets/eval_js/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as main from "./main"; 2 | 3 | import { CallToolRequest, CallToolResult, ListToolsResult } from "./pdk"; 4 | 5 | export function call(): number { 6 | const untypedInput = JSON.parse(Host.inputString()); 7 | const input = CallToolRequest.fromJson(untypedInput); 8 | 9 | const output = main.callImpl(input); 10 | 11 | const untypedOutput = CallToolResult.toJson(output); 12 | Host.outputString(JSON.stringify(untypedOutput)); 13 | 14 | return 0; 15 | } 16 | 17 | export function describe(): number { 18 | const output = main.describeImpl(); 19 | 20 | const untypedOutput = ListToolsResult.toJson(output); 21 | Host.outputString(JSON.stringify(untypedOutput)); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /servlets/eval_js/src/main.ts: -------------------------------------------------------------------------------- 1 | import { CallToolRequest, CallToolResult, ContentType, ListToolsResult, ToolDescription } from "./pdk"; 2 | 3 | /** 4 | * Called when the tool is invoked. 5 | * 6 | * @param {CallToolRequest} input - The incoming tool request from the LLM 7 | * @returns {CallToolResult} The servlet's response to the given tool call 8 | */ 9 | export function callImpl(input: CallToolRequest): CallToolResult { 10 | const code = input.params.arguments?.code 11 | if (!code) { 12 | throw new Error("Argument `code` must be provided") 13 | } 14 | return { 15 | content: [ 16 | { 17 | type: ContentType.Text, 18 | text: eval(code).toString() 19 | } 20 | ] 21 | } 22 | 23 | } 24 | 25 | /** 26 | * Called by mcpx to understand how and why to use this tool 27 | * 28 | * @returns {ToolDescription} The tool's description 29 | */ 30 | export function describeImpl(): ListToolsResult { 31 | return { 32 | tools: [ 33 | { 34 | name: "eval_js", 35 | description: "Evaluate some javascript using `eval()` in a sandbox.", 36 | inputSchema: { 37 | type: "object", 38 | properties: { 39 | code: { 40 | type: "string", 41 | description: "The javascript code to eval. This code gets passed into `eval()` and the result is stringified. Do not use console.log to emit the result.", 42 | }, 43 | }, 44 | required: ["code"], 45 | }, 46 | } 47 | ] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /servlets/eval_js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", // Specify ECMAScript target version 4 | "module": "commonjs", // Specify module code generation 5 | "lib": [ 6 | "es2020" 7 | ], // Specify a list of library files to be included in the compilation 8 | "types": [ 9 | "@extism/js-pdk", 10 | "./src/index.d.ts" 11 | ], // Specify a list of type definition files to be included in the compilation 12 | "strict": true, // Enable all strict type-checking options 13 | "esModuleInterop": true, // Enables compatibility with Babel-style module imports 14 | "skipLibCheck": true, // Skip type checking of declaration files 15 | "allowJs": true, // Allow JavaScript files to be compiled 16 | "noEmit": true // Do not emit outputs (no .js or .d.ts files) 17 | }, 18 | "include": [ 19 | "src/**/*.ts" // Include all TypeScript files in src directory 20 | ], 21 | "exclude": [ 22 | "node_modules" // Exclude the node_modules directory 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /servlets/eval_js/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "eval_js" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "bash prepare.sh && npm run build" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "npm run format" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh && npm install" 18 | 19 | [[test]] 20 | name = "basic tests" 21 | with = "../../test/testsuite/dist/test.wasm" 22 | -------------------------------------------------------------------------------- /servlets/fetch-image/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasip1" 3 | -------------------------------------------------------------------------------- /servlets/fetch-image/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | # RustRover 17 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 18 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 19 | # and can be added to the global gitignore or merged into this file. For a more nuclear 20 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 21 | #.idea/ 22 | -------------------------------------------------------------------------------- /servlets/fetch-image/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fetch" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | #extism-pdk = "1.3.0" 12 | extism-pdk = "=1.2.1" 13 | chrono = { version = "0.4", features = ["serde"] } 14 | serde = { version = "1.0", features = ["derive"] } 15 | serde_json = "1.0" 16 | base64-serde = "0.7" 17 | base64 = "0.21" 18 | htmd = "0.1.6" 19 | -------------------------------------------------------------------------------- /servlets/fetch-image/README.md: -------------------------------------------------------------------------------- 1 | # Fetch Image Servlet 2 | 3 | A servlet that fetches pictures and returns them as resources. Intended for interactive use (e.g. in Claude Desktop). 4 | 5 | ## What it does 6 | 7 | Takes a URL, fetches the image and return it base64-encoded for inline-display. 8 | 9 | ## Usage 10 | 11 | Call with: 12 | ```typescript 13 | { 14 | `arguments`: { 15 | `url`: `https://example.com`, // Required: URL to fetch 16 | `mime-type`: "image/png" // The mime type to filter by 17 | } 18 | } 19 | ``` 20 | -------------------------------------------------------------------------------- /servlets/fetch-image/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | missing_deps=0 10 | 11 | # Check for Cargo 12 | if ! (command_exists cargo); then 13 | missing_deps=1 14 | echo "❌ Cargo/rust is not installed." 15 | echo "" 16 | echo "To install Rust, visit the official download page:" 17 | echo "👉 https://www.rust-lang.org/tools/install" 18 | echo "" 19 | echo "Or install it using a package manager:" 20 | echo "" 21 | echo "🔹 macOS (Homebrew):" 22 | echo " brew install cargo" 23 | echo "" 24 | echo "🔹 Ubuntu/Debian:" 25 | echo " sudo apt-get install -y cargo" 26 | echo "" 27 | echo "🔹 Arch Linux:" 28 | echo " sudo pacman -S rust" 29 | echo "" 30 | fi 31 | 32 | # Exit with a bad exit code if any dependencies are missing 33 | if [ "$missing_deps" -ne 0 ]; then 34 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 35 | # TODO: remove sleep when cli bug is fixed 36 | sleep 2 37 | exit 1 38 | fi -------------------------------------------------------------------------------- /servlets/fetch-image/xtp.toml: -------------------------------------------------------------------------------- 1 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 2 | bin = "target/wasm32-wasip1/release/plugin.wasm" # when we are in a cargo workspace, bins are in root/target 3 | 4 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | # This is the 'binding' name used for the plugin. 7 | name = "fetch-image" 8 | 9 | [scripts] 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "cargo build --release --target wasm32-wasip1" 12 | 13 | # xtp plugin init runs this script to format the code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | 19 | [[test]] 20 | name = "basic tests" 21 | with = "../../test/testsuite/dist/test.wasm" 22 | -------------------------------------------------------------------------------- /servlets/fetch/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasip1" 3 | -------------------------------------------------------------------------------- /servlets/fetch/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | # RustRover 17 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 18 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 19 | # and can be added to the global gitignore or merged into this file. For a more nuclear 20 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 21 | #.idea/ 22 | -------------------------------------------------------------------------------- /servlets/fetch/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fetch" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | #extism-pdk = "1.3.0" 12 | extism-pdk = "=1.2.1" 13 | chrono = { version = "0.4", features = ["serde"] } 14 | serde = { version = "1.0", features = ["derive"] } 15 | serde_json = "1.0" 16 | base64-serde = "0.7" 17 | base64 = "0.21" 18 | htmd = "0.1.6" 19 | -------------------------------------------------------------------------------- /servlets/fetch/README.md: -------------------------------------------------------------------------------- 1 | # Fetch Servlet 2 | 3 | A servlet that fetches web pages and converts them to markdown. 4 | 5 | ## What it does 6 | 7 | Takes a URL, fetches the page content, strips out scripts and styles, and converts the HTML to markdown format. 8 | 9 | ## Usage 10 | 11 | Call with: 12 | ```typescript 13 | { 14 | arguments: { 15 | url: "https://example.com" // Required: URL to fetch 16 | } 17 | } 18 | ``` 19 | 20 | Returns the page content converted to markdown format. -------------------------------------------------------------------------------- /servlets/fetch/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | missing_deps=0 10 | 11 | # Check for Cargo 12 | if ! (command_exists cargo); then 13 | missing_deps=1 14 | echo "❌ Cargo/rust is not installed." 15 | echo "" 16 | echo "To install Rust, visit the official download page:" 17 | echo "👉 https://www.rust-lang.org/tools/install" 18 | echo "" 19 | echo "Or install it using a package manager:" 20 | echo "" 21 | echo "🔹 macOS (Homebrew):" 22 | echo " brew install cargo" 23 | echo "" 24 | echo "🔹 Ubuntu/Debian:" 25 | echo " sudo apt-get install -y cargo" 26 | echo "" 27 | echo "🔹 Arch Linux:" 28 | echo " sudo pacman -S rust" 29 | echo "" 30 | fi 31 | 32 | # Exit with a bad exit code if any dependencies are missing 33 | if [ "$missing_deps" -ne 0 ]; then 34 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 35 | # TODO: remove sleep when cli bug is fixed 36 | sleep 2 37 | exit 1 38 | fi -------------------------------------------------------------------------------- /servlets/fetch/xtp.toml: -------------------------------------------------------------------------------- 1 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 2 | bin = "target/wasm32-wasip1/release/plugin.wasm" # when we are in a cargo workspace, bins are in root/target 3 | 4 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | # This is the 'binding' name used for the plugin. 7 | name = "fetch" 8 | 9 | [scripts] 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "cargo build --release --target wasm32-wasip1" 12 | 13 | # xtp plugin init runs this script to format the code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | 19 | [[test]] 20 | name = "basic tests" 21 | with = "../../test/testsuite/dist/test.wasm" 22 | -------------------------------------------------------------------------------- /servlets/filesystem/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasip1" 3 | -------------------------------------------------------------------------------- /servlets/filesystem/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | # RustRover 17 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 18 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 19 | # and can be added to the global gitignore or merged into this file. For a more nuclear 20 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 21 | #.idea/ 22 | -------------------------------------------------------------------------------- /servlets/filesystem/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "filesystem" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | #extism-pdk = "1.3.0" 12 | extism-pdk = "=1.2.1" 13 | chrono = { version = "0.4", features = ["serde"] } 14 | serde = { version = "1.0", features = ["derive"] } 15 | serde_json = "1.0" 16 | base64-serde = "0.7" 17 | base64 = "0.21" 18 | walkdir = "2.5.0" 19 | -------------------------------------------------------------------------------- /servlets/filesystem/README.md: -------------------------------------------------------------------------------- 1 | # Filesystem Servlet 2 | 3 | A servlet that performs file system operations. 4 | 5 | ## What it does 6 | 7 | Provides four file system operations: 8 | - Read file contents 9 | - Write content to a file 10 | - List directory contents 11 | - Search for files by name pattern 12 | 13 | ## Tools 14 | 15 | ### read_file 16 | 17 | Reads the contents of a file at the specified path. 18 | 19 | ```json 20 | { 21 | "path": "path/to/file.txt" 22 | } 23 | ``` 24 | 25 | ### write_file 26 | 27 | Writes content to a file at the specified path. 28 | 29 | ```json 30 | { 31 | "path": "path/to/file.txt", 32 | "content": "Hello, world!" 33 | } 34 | ``` 35 | 36 | ### list_directory 37 | 38 | Lists the contents of a directory, marking items as either [DIR] or [FILE]. 39 | 40 | ```json 41 | { 42 | "path": "path/to/directory" 43 | } 44 | ``` 45 | 46 | ### search_files 47 | 48 | Recursively searches for files matching a pattern in the given directory. 49 | 50 | ```json 51 | { 52 | "path": "path/to/search", 53 | "pattern": "*.txt" 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /servlets/filesystem/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to check if a command exists 4 | command_exists () { 5 | command -v "$1" >/dev/null 2>&1 6 | } 7 | 8 | missing_deps=0 9 | 10 | # Check for Cargo 11 | if ! (command_exists cargo); then 12 | missing_deps=1 13 | echo "❌ Cargo/rust is not installed." 14 | echo "" 15 | echo "To install Rust, visit the official download page:" 16 | echo "👉 https://www.rust-lang.org/tools/install" 17 | echo "" 18 | echo "Or install it using a package manager:" 19 | echo "" 20 | echo "🔹 macOS (Homebrew):" 21 | echo " brew install cargo" 22 | echo "" 23 | echo "🔹 Ubuntu/Debian:" 24 | echo " sudo apt-get install -y cargo" 25 | echo "" 26 | echo "🔹 Arch Linux:" 27 | echo " sudo pacman -S rust" 28 | echo "" 29 | fi 30 | 31 | # Exit with a bad exit code if any dependencies are missing 32 | if [ "$missing_deps" -ne 0 ]; then 33 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 34 | # TODO: remove sleep when cli bug is fixed 35 | sleep 2 36 | exit 1 37 | fi 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /servlets/filesystem/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "target/wasm32-wasip1/release/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | # This is the 'binding' name used for the plugin. 7 | name = "filesystem" 8 | 9 | [scripts] 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "cargo build --release --target wasm32-wasip1" 12 | 13 | # xtp plugin init runs this script to format the code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/github/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /servlets/github/README.md: -------------------------------------------------------------------------------- 1 | # GitHub Servlet 2 | 3 | Currently supported: 4 | 5 | Issues: 6 | 7 | - `gh-create-issue` Create issue 8 | - `gh-get-issue` Get issue 9 | - `gh-update-issue` Add comments to an issue 10 | - `gh-add-issue-comment` Read the contents of an issue 11 | 12 | Files: 13 | 14 | - `gh-get-file-contents` Get contents and metadata about a file on a branch 15 | - `gh-create-or-update-file` Create or a update a file on a branch 16 | - `gh-push-files` Bulk push files to a branch 17 | 18 | Branches: 19 | 20 | - `gh-create-branch` Create a new branch 21 | - `gh-create-pull-request` Create a PR from a branch 22 | 23 | Gists 24 | 25 | - `gh-create-gist` Create a gist 26 | - `gh-update-gist` Create a gist 27 | - `gh-get-gist` Create a gist 28 | - `gh-delete-gist` Create a gist 29 | 30 | ## Config 31 | 32 | Requires the following config keys: 33 | 34 | - **api-key** with a [GitHub Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens). 35 | 36 | ## Permissions 37 | 38 | Requires access to the following **domains**: 39 | 40 | - `api.github.com` 41 | 42 | ## Example 43 | 44 | — can you add a funny comment on issue #1 from repo evacchi/mcpx-target-playground ? 45 | 46 |
47 | I'll add a playful comment to keep with the "don't panic" theme of the issue. 48 | 49 | I added a comment with a reference to The Hitchhiker's Guide to the Galaxy, since it fits well with the "don't panic" theme of the issue! The comment has been successfully posted. 50 |
51 | 52 | -------------------------------------------------------------------------------- /servlets/github/go.mod: -------------------------------------------------------------------------------- 1 | module github 2 | 3 | go 1.23 4 | 5 | require github.com/extism/go-pdk v1.0.5 6 | -------------------------------------------------------------------------------- /servlets/github/go.sum: -------------------------------------------------------------------------------- 1 | github.com/extism/go-pdk v1.0.5 h1:5d5yYkWBweBP84Z+H3DP5DsD0fwvf2anWXyypCXpSW8= 2 | github.com/extism/go-pdk v1.0.5/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 3 | -------------------------------------------------------------------------------- /servlets/github/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | # Function to compare version numbers for "less than" 10 | version_lt() { 11 | test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" = "$1" && test "$1" != "$2" 12 | } 13 | 14 | missing_deps=0 15 | 16 | # Check for Go 17 | if ! (command_exists go); then 18 | missing_deps=1 19 | echo "❌ Go (supported version between 1.20 - 1.24) is not installed." 20 | echo "" 21 | echo "To install Go, visit the official download page:" 22 | echo "👉 https://go.dev/dl/" 23 | echo "" 24 | echo "Or install it using a package manager:" 25 | echo "" 26 | echo "🔹 macOS (Homebrew):" 27 | echo " brew install go" 28 | echo "" 29 | echo "🔹 Ubuntu/Debian:" 30 | echo " sudo apt-get -y install golang-go" 31 | echo "" 32 | echo "🔹 Arch Linux:" 33 | echo " sudo pacman -S go" 34 | echo "" 35 | echo "🔹 Windows:" 36 | echo " scoop install go" 37 | echo "" 38 | fi 39 | 40 | # Check for the right version of Go, needed by TinyGo (supports go 1.20 - 1.24) 41 | if (command_exists go); then 42 | compat=0 43 | for v in `seq 20 24`; do 44 | if (go version | grep -q "go1.$v"); then 45 | compat=1 46 | fi 47 | done 48 | 49 | if [ $compat -eq 0 ]; then 50 | echo "❌ Supported Go version is not installed. Must be Go 1.20 - 1.24." 51 | echo "" 52 | fi 53 | fi 54 | 55 | ARCH=$(arch) 56 | 57 | # Check for TinyGo and its version 58 | if ! (command_exists tinygo); then 59 | missing_deps=1 60 | echo "❌ TinyGo is not installed." 61 | echo "" 62 | echo "To install TinyGo, visit the official download page:" 63 | echo "👉 https://tinygo.org/getting-started/install/" 64 | echo "" 65 | echo "Or install it using a package manager:" 66 | echo "" 67 | echo "🔹 macOS (Homebrew):" 68 | echo " brew tap tinygo-org/tools" 69 | echo " brew install tinygo" 70 | echo "" 71 | echo "🔹 Ubuntu/Debian:" 72 | echo " wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_$ARCH.deb" 73 | echo " sudo dpkg -i tinygo_0.34.0_$ARCH.deb" 74 | echo "" 75 | echo "🔹 Arch Linux:" 76 | echo " pacman -S extra/tinygo" 77 | echo "" 78 | echo "🔹 Windows:" 79 | echo " scoop install tinygo" 80 | echo "" 81 | else 82 | # Check TinyGo version 83 | tinygo_version=$(tinygo version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n1) 84 | if version_lt "$tinygo_version" "0.34.0"; then 85 | missing_deps=1 86 | echo "❌ TinyGo version must be >= 0.34.0 (current version: $tinygo_version)" 87 | echo "Please update TinyGo to a newer version." 88 | echo "" 89 | fi 90 | fi 91 | 92 | go install golang.org/x/tools/cmd/goimports@latest 93 | -------------------------------------------------------------------------------- /servlets/github/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "github" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "mkdir -p dist && tinygo build -target wasi -o dist/plugin.wasm ." 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "go fmt && go mod tidy && goimports -w main.go" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "sh prepare.sh && go get ./..." 18 | -------------------------------------------------------------------------------- /servlets/google-maps-image/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | 3 | -------------------------------------------------------------------------------- /servlets/google-maps-image/README.md: -------------------------------------------------------------------------------- 1 | # Google Maps Static Image API 2 | 3 | Generates an image using [Google's static Map generation API](https://developers.google.com/maps/documentation/maps-static/start). 4 | 5 | ## Config 6 | 7 | - `api-key`: see [docs](https://developers.google.com/maps/documentation/maps-static/get-api-key) 8 | 9 | ## Domains 10 | 11 | - `maps.googleapis.com` 12 | 13 | ## Example 14 | 15 | > can you draw santa's route on xmas eve on a map? start at the north pole, then show at least 15 waypoints! Make sure that the right-most waypoint is the first Santa encounters. Style the map in festive colors, and use red and green for the markers to celebrate the winter holidays! make it 2000x2000 16 | 17 | ![](imgs/santa-route.png) 18 | -------------------------------------------------------------------------------- /servlets/google-maps-image/go.mod: -------------------------------------------------------------------------------- 1 | module google-maps-image 2 | 3 | go 1.22.1 4 | 5 | require github.com/extism/go-pdk v1.0.5 6 | -------------------------------------------------------------------------------- /servlets/google-maps-image/go.sum: -------------------------------------------------------------------------------- 1 | github.com/extism/go-pdk v1.0.5 h1:5d5yYkWBweBP84Z+H3DP5DsD0fwvf2anWXyypCXpSW8= 2 | github.com/extism/go-pdk v1.0.5/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 3 | -------------------------------------------------------------------------------- /servlets/google-maps-image/imgs/santa-route.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dylibso/mcp.run-servlets/006e737a53ae666dec24655874d74ecf6d381f5c/servlets/google-maps-image/imgs/santa-route.png -------------------------------------------------------------------------------- /servlets/google-maps-image/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | # Function to compare version numbers for "less than" 10 | version_lt() { 11 | test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" = "$1" && test "$1" != "$2" 12 | } 13 | 14 | missing_deps=0 15 | 16 | # Check for Go 17 | if ! (command_exists go); then 18 | missing_deps=1 19 | echo "❌ Go (supported version between 1.20 - 1.24) is not installed." 20 | echo "" 21 | echo "To install Go, visit the official download page:" 22 | echo "👉 https://go.dev/dl/" 23 | echo "" 24 | echo "Or install it using a package manager:" 25 | echo "" 26 | echo "🔹 macOS (Homebrew):" 27 | echo " brew install go" 28 | echo "" 29 | echo "🔹 Ubuntu/Debian:" 30 | echo " sudo apt-get -y install golang-go" 31 | echo "" 32 | echo "🔹 Arch Linux:" 33 | echo " sudo pacman -S go" 34 | echo "" 35 | echo "🔹 Windows:" 36 | echo " scoop install go" 37 | echo "" 38 | fi 39 | 40 | # Check for the right version of Go, needed by TinyGo (supports go 1.20 - 1.24) 41 | if (command_exists go); then 42 | compat=0 43 | for v in `seq 20 24`; do 44 | if (go version | grep -q "go1.$v"); then 45 | compat=1 46 | fi 47 | done 48 | 49 | if [ $compat -eq 0 ]; then 50 | echo "❌ Supported Go version is not installed. Must be Go 1.20 - 1.24." 51 | echo "" 52 | fi 53 | fi 54 | 55 | ARCH=$(arch) 56 | 57 | # Check for TinyGo and its version 58 | if ! (command_exists tinygo); then 59 | missing_deps=1 60 | echo "❌ TinyGo is not installed." 61 | echo "" 62 | echo "To install TinyGo, visit the official download page:" 63 | echo "👉 https://tinygo.org/getting-started/install/" 64 | echo "" 65 | echo "Or install it using a package manager:" 66 | echo "" 67 | echo "🔹 macOS (Homebrew):" 68 | echo " brew tap tinygo-org/tools" 69 | echo " brew install tinygo" 70 | echo "" 71 | echo "🔹 Ubuntu/Debian:" 72 | echo " wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_$ARCH.deb" 73 | echo " sudo dpkg -i tinygo_0.34.0_$ARCH.deb" 74 | echo "" 75 | echo "🔹 Arch Linux:" 76 | echo " pacman -S extra/tinygo" 77 | echo "" 78 | echo "🔹 Windows:" 79 | echo " scoop install tinygo" 80 | echo "" 81 | else 82 | # Check TinyGo version 83 | tinygo_version=$(tinygo version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n1) 84 | if version_lt "$tinygo_version" "0.34.0"; then 85 | missing_deps=1 86 | echo "❌ TinyGo version must be >= 0.34.0 (current version: $tinygo_version)" 87 | echo "Please update TinyGo to a newer version." 88 | echo "" 89 | fi 90 | fi 91 | 92 | go install golang.org/x/tools/cmd/goimports@latest 93 | -------------------------------------------------------------------------------- /servlets/google-maps-image/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "google-maps-image" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "mkdir -p dist && tinygo build -target wasi -o dist/plugin.wasm ." 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "go fmt && go mod tidy && goimports -w main.go" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "sh prepare.sh && go get ./..." 18 | -------------------------------------------------------------------------------- /servlets/google-maps/.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | 11 | pids 12 | logs 13 | results 14 | tmp 15 | 16 | # Build 17 | public/css/main.css 18 | 19 | # Coverage reports 20 | coverage 21 | 22 | # API keys and secrets 23 | .env 24 | 25 | # Dependency directory 26 | node_modules 27 | bower_components 28 | 29 | # Editors 30 | .idea 31 | *.iml 32 | 33 | # OS metadata 34 | .DS_Store 35 | Thumbs.db 36 | 37 | # Ignore built ts files 38 | dist/**/* 39 | 40 | # ignore yarn.lock 41 | yarn.lock 42 | 43 | -------------------------------------------------------------------------------- /servlets/google-maps/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .git 4 | 5 | -------------------------------------------------------------------------------- /servlets/google-maps/.prettierrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dylibso/mcp.run-servlets/006e737a53ae666dec24655874d74ecf6d381f5c/servlets/google-maps/.prettierrc -------------------------------------------------------------------------------- /servlets/google-maps/esbuild.js: -------------------------------------------------------------------------------- 1 | const esbuild = require('esbuild'); 2 | 3 | esbuild 4 | .build({ 5 | entryPoints: ['src/index.ts'], 6 | outdir: 'dist', 7 | bundle: true, 8 | sourcemap: true, 9 | minify: false, // might want to use true for production build 10 | format: 'cjs', // needs to be CJS for now 11 | target: ['es2020'], // don't go over es2020 because quickjs doesn't support it 12 | }) 13 | -------------------------------------------------------------------------------- /servlets/google-maps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "google-maps", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.ts", 6 | "scripts": { 7 | "build": "npx tsc --noEmit && node esbuild.js && extism-js dist/index.js -i src/index.d.ts -o dist/plugin.wasm", 8 | "format": "npx prettier --write \"src/**/*.{ts,tsx}\" --plugin=prettier-plugin-organize-imports" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "private": true, 13 | "license": "UNLICENSED", 14 | "devDependencies": { 15 | "@extism/js-pdk": "^1.0.1", 16 | "@types/node": "^22.10.2", 17 | "esbuild": "^0.19.6", 18 | "prettier": "^3.3.2", 19 | "prettier-plugin-organize-imports": "^4.1.0", 20 | "typescript": "^5.3.2" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /servlets/google-maps/src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "main" { 2 | export function call(): I32; 3 | export function describe(): I32; 4 | } 5 | -------------------------------------------------------------------------------- /servlets/google-maps/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as main from "./main"; 2 | 3 | import { CallToolRequest, CallToolResult, ListToolsResult } from "./pdk"; 4 | 5 | export function call(): number { 6 | const untypedInput = JSON.parse(Host.inputString()); 7 | const input = CallToolRequest.fromJson(untypedInput); 8 | 9 | const output = main.callImpl(input); 10 | 11 | const untypedOutput = CallToolResult.toJson(output); 12 | Host.outputString(JSON.stringify(untypedOutput)); 13 | 14 | return 0; 15 | } 16 | 17 | export function describe(): number { 18 | const output = main.describeImpl(); 19 | 20 | const untypedOutput = ListToolsResult.toJson(output); 21 | Host.outputString(JSON.stringify(untypedOutput)); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /servlets/google-maps/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", // Specify ECMAScript target version 4 | "module": "commonjs", // Specify module code generation 5 | "lib": [ 6 | "es2020" 7 | ], // Specify a list of library files to be included in the compilation 8 | "types": [ 9 | "node", 10 | "@extism/js-pdk", 11 | "./src/index.d.ts" 12 | ], // Specify a list of type definition files to be included in the compilation 13 | "strict": true, // Enable all strict type-checking options 14 | "esModuleInterop": true, // Enables compatibility with Babel-style module imports 15 | "skipLibCheck": true, // Skip type checking of declaration files 16 | "allowJs": true, // Allow JavaScript files to be compiled 17 | "noEmit": true // Do not emit outputs (no .js or .d.ts files) 18 | }, 19 | "include": [ 20 | "src/**/*.ts" // Include all TypeScript files in src directory 21 | ], 22 | "exclude": [ 23 | "node_modules" // Exclude the node_modules directory 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /servlets/google-maps/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "google-maps" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "bash prepare.sh && npm run build" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "npm run format" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/greet/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules 3 | -------------------------------------------------------------------------------- /servlets/greet/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .git 4 | 5 | -------------------------------------------------------------------------------- /servlets/greet/.prettierrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dylibso/mcp.run-servlets/006e737a53ae666dec24655874d74ecf6d381f5c/servlets/greet/.prettierrc -------------------------------------------------------------------------------- /servlets/greet/README.md: -------------------------------------------------------------------------------- 1 | # Greeting Servlet 2 | 3 | A simple servlet that returns a greeting message. 4 | 5 | ## What it does 6 | 7 | Takes a name and returns "Hello {name}!!!" 8 | 9 | ## Usage 10 | 11 | Call with: 12 | ```typescript 13 | { 14 | arguments: { 15 | name: "Claude" // Required: name to greet 16 | } 17 | } 18 | ``` 19 | 20 | Returns: 21 | ```typescript 22 | "Hello Claude!!!" 23 | ``` 24 | -------------------------------------------------------------------------------- /servlets/greet/esbuild.js: -------------------------------------------------------------------------------- 1 | const esbuild = require('esbuild'); 2 | 3 | esbuild 4 | .build({ 5 | entryPoints: ['src/index.ts'], 6 | outdir: 'dist', 7 | bundle: true, 8 | sourcemap: true, 9 | minify: false, // might want to use true for production build 10 | format: 'cjs', // needs to be CJS for now 11 | target: ['es2020'], // don't go over es2020 because quickjs doesn't support it 12 | }) 13 | -------------------------------------------------------------------------------- /servlets/greet/mock_input.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "name": "Mo" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /servlets/greet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "greet", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.ts", 6 | "scripts": { 7 | "build": "npx tsc --noEmit && node esbuild.js && extism-js dist/index.js -i src/index.d.ts -o dist/plugin.wasm", 8 | "format": "npx prettier --write \"src/**/*.{ts,tsx}\" --plugin=prettier-plugin-organize-imports" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "private": true, 13 | "license": "UNLICENSED", 14 | "devDependencies": { 15 | "@extism/js-pdk": "^1.0.1", 16 | "esbuild": "^0.19.6", 17 | "typescript": "^5.3.2", 18 | "prettier": "^3.3.2", 19 | "prettier-plugin-organize-imports": "^4.1.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /servlets/greet/src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "main" { 2 | export function call(): I32; 3 | export function describe(): I32; 4 | } 5 | -------------------------------------------------------------------------------- /servlets/greet/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as main from "./main"; 2 | 3 | import { CallToolRequest, CallToolResult, ListToolsResult } from "./pdk"; 4 | 5 | export function call(): number { 6 | const untypedInput = JSON.parse(Host.inputString()); 7 | const input = CallToolRequest.fromJson(untypedInput); 8 | 9 | const output = main.callImpl(input); 10 | 11 | const untypedOutput = CallToolResult.toJson(output); 12 | Host.outputString(JSON.stringify(untypedOutput)); 13 | 14 | return 0; 15 | } 16 | 17 | export function describe(): number { 18 | const output = main.describeImpl(); 19 | 20 | const untypedOutput = ListToolsResult.toJson(output); 21 | Host.outputString(JSON.stringify(untypedOutput)); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /servlets/greet/src/main.ts: -------------------------------------------------------------------------------- 1 | import { CallToolRequest, CallToolResult, ContentType, ListToolsResult } from "./pdk"; 2 | 3 | /** 4 | * Called when the tool is invoked. 5 | * 6 | * @param {CallToolRequest} input - The incoming tool request from the LLM 7 | * @returns {CallToolResult} The servlet's response to the given tool call 8 | */ 9 | export function callImpl(input: CallToolRequest): CallToolResult { 10 | const name = input.params.arguments?.name 11 | if (!name) { 12 | throw new Error("Argument `name` must be provided") 13 | } 14 | return { 15 | content: [ 16 | { 17 | type: ContentType.Text, 18 | text: `Hello ${name}!!!` 19 | } 20 | ] 21 | } 22 | } 23 | 24 | /** 25 | * Called by mcpx to understand how and why to use this tool 26 | * 27 | * @returns {ToolDescription} The tool's description 28 | */ 29 | export function describeImpl(): ListToolsResult { 30 | return { 31 | tools: [{ 32 | name: "greet", 33 | description: "A very simple tool to provide a greeting", 34 | inputSchema: { 35 | type: "object", 36 | properties: { 37 | name: { 38 | type: "string", 39 | description: "the name of the person to greet", 40 | }, 41 | }, 42 | required: ["name"], 43 | }, 44 | }] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /servlets/greet/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", // Specify ECMAScript target version 4 | "module": "commonjs", // Specify module code generation 5 | "lib": [ 6 | "es2020" 7 | ], // Specify a list of library files to be included in the compilation 8 | "types": [ 9 | "@extism/js-pdk", 10 | "./src/index.d.ts" 11 | ], // Specify a list of type definition files to be included in the compilation 12 | "strict": true, // Enable all strict type-checking options 13 | "esModuleInterop": true, // Enables compatibility with Babel-style module imports 14 | "skipLibCheck": true, // Skip type checking of declaration files 15 | "allowJs": true, // Allow JavaScript files to be compiled 16 | "noEmit": true // Do not emit outputs (no .js or .d.ts files) 17 | }, 18 | "include": [ 19 | "src/**/*.ts" // Include all TypeScript files in src directory 20 | ], 21 | "exclude": [ 22 | "node_modules" // Exclude the node_modules directory 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /servlets/greet/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "greet" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "bash prepare.sh && npm run build" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "npm run format" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh && npm install" 18 | 19 | [[test]] 20 | name = "basic tests" 21 | with = "../../test/testsuite/dist/test.wasm" -------------------------------------------------------------------------------- /servlets/historical-flight-api/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ -------------------------------------------------------------------------------- /servlets/historical-flight-api/README.md: -------------------------------------------------------------------------------- 1 | # Historical Flight API Servlet 2 | 3 | Queries flight APIs for info about past flights, 4 | using the following services: 5 | 6 | - https://opensky-network.org 7 | - https://adsbdb.com 8 | - https://airport-data.com 9 | 10 | Note: 11 | 12 | > In OpenSky, Flights are updated by a batch process at night, 13 | > i.e., only flights from the previous day or earlier are available using this endpoint. 14 | 15 | OpenSky requires a username, password pair, you can easily get 16 | with [a free account](https://opensky-network.org/login?view=registration). 17 | 18 | ## Configuration 19 | 20 | - The servlet expects the config keys `username` `password` to be provided. 21 | - It requires network access to the following domains: 22 | - opensky-network.org 23 | - api.adsbdb.com 24 | - airport-data.com 25 | 26 | ## Usage 27 | 28 | We expose the [OpenSky `arrival` and `departure` endpoints](https://openskynetwork.github.io/opensky-api/rest.html) 29 | following their structure, except we also require a `requestType` field: 30 | 31 | ```json 32 | { 33 | "requestType": "departure", 34 | "airport": "LIMC", 35 | "begin": "1701428400", 36 | "end": "1701435600" 37 | } 38 | ``` 39 | 40 | Where `airport` is the ICAO code for the airport, and `begin`, `end` are UNIX timestamps 41 | at UTC. 42 | 43 | The return value is the contents of the return value for such endpoints. 44 | 45 | We also expose the `aircraft` endpoint from [adsbdb.com](https://www.adsbdb.com). 46 | This requires the `icao24` identifier of the aircraft, and its `callsign`, 47 | which are always returned as part of the `arrival` and `departure` responses. The request looks like: 48 | 49 | ```json 50 | { 51 | "icao24": "440170", 52 | "callsign": "EJU73BJ" 53 | } 54 | ``` 55 | 56 | The result contains the returned value from the [adsbdb.com](https://www.adsbdb.com) 57 | endpoint; we also automatically fetch and return the aircraft picture returned 58 | in the [adsbdb.com](https://www.adsbdb.com) response in the `url_photo` field. 59 | -------------------------------------------------------------------------------- /servlets/historical-flight-api/go.mod: -------------------------------------------------------------------------------- 1 | module historical-flight-api 2 | 3 | go 1.22.1 4 | 5 | require github.com/extism/go-pdk v1.0.5 6 | -------------------------------------------------------------------------------- /servlets/historical-flight-api/go.sum: -------------------------------------------------------------------------------- 1 | github.com/extism/go-pdk v1.0.5 h1:5d5yYkWBweBP84Z+H3DP5DsD0fwvf2anWXyypCXpSW8= 2 | github.com/extism/go-pdk v1.0.5/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 3 | -------------------------------------------------------------------------------- /servlets/historical-flight-api/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | # Function to compare version numbers for "less than" 10 | version_lt() { 11 | test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" = "$1" && test "$1" != "$2" 12 | } 13 | 14 | missing_deps=0 15 | 16 | # Check for Go 17 | if ! (command_exists go); then 18 | missing_deps=1 19 | echo "❌ Go (supported version between 1.20 - 1.24) is not installed." 20 | echo "" 21 | echo "To install Go, visit the official download page:" 22 | echo "👉 https://go.dev/dl/" 23 | echo "" 24 | echo "Or install it using a package manager:" 25 | echo "" 26 | echo "🔹 macOS (Homebrew):" 27 | echo " brew install go" 28 | echo "" 29 | echo "🔹 Ubuntu/Debian:" 30 | echo " sudo apt-get -y install golang-go" 31 | echo "" 32 | echo "🔹 Arch Linux:" 33 | echo " sudo pacman -S go" 34 | echo "" 35 | echo "🔹 Windows:" 36 | echo " scoop install go" 37 | echo "" 38 | fi 39 | 40 | # Check for the right version of Go, needed by TinyGo (supports go 1.20 - 1.24) 41 | if (command_exists go); then 42 | compat=0 43 | for v in `seq 20 24`; do 44 | if (go version | grep -q "go1.$v"); then 45 | compat=1 46 | fi 47 | done 48 | 49 | if [ $compat -eq 0 ]; then 50 | echo "❌ Supported Go version is not installed. Must be Go 1.20 - 1.24." 51 | echo "" 52 | fi 53 | fi 54 | 55 | ARCH=$(arch) 56 | 57 | # Check for TinyGo and its version 58 | if ! (command_exists tinygo); then 59 | missing_deps=1 60 | echo "❌ TinyGo is not installed." 61 | echo "" 62 | echo "To install TinyGo, visit the official download page:" 63 | echo "👉 https://tinygo.org/getting-started/install/" 64 | echo "" 65 | echo "Or install it using a package manager:" 66 | echo "" 67 | echo "🔹 macOS (Homebrew):" 68 | echo " brew tap tinygo-org/tools" 69 | echo " brew install tinygo" 70 | echo "" 71 | echo "🔹 Ubuntu/Debian:" 72 | echo " wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_$ARCH.deb" 73 | echo " sudo dpkg -i tinygo_0.34.0_$ARCH.deb" 74 | echo "" 75 | echo "🔹 Arch Linux:" 76 | echo " pacman -S extra/tinygo" 77 | echo "" 78 | echo "🔹 Windows:" 79 | echo " scoop install tinygo" 80 | echo "" 81 | else 82 | # Check TinyGo version 83 | tinygo_version=$(tinygo version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n1) 84 | if version_lt "$tinygo_version" "0.34.0"; then 85 | missing_deps=1 86 | echo "❌ TinyGo version must be >= 0.34.0 (current version: $tinygo_version)" 87 | echo "Please update TinyGo to a newer version." 88 | echo "" 89 | fi 90 | fi 91 | 92 | go install golang.org/x/tools/cmd/goimports@latest 93 | -------------------------------------------------------------------------------- /servlets/historical-flight-api/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "historical-flight-api" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "mkdir -p dist && tinygo build -target wasi -o dist/plugin.wasm ." 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "go fmt && go mod tidy && goimports -w main.go" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh && go get ./..." 18 | -------------------------------------------------------------------------------- /servlets/image-resizer/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasip1" 3 | -------------------------------------------------------------------------------- /servlets/image-resizer/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | # RustRover 17 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 18 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 19 | # and can be added to the global gitignore or merged into this file. For a more nuclear 20 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 21 | #.idea/ 22 | -------------------------------------------------------------------------------- /servlets/image-resizer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "image-resizer" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | extism-pdk = "1.1.0" 12 | chrono = { version = "0.4", features = ["serde"] } 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | base64-serde = "0.7" 16 | base64 = "0.21" 17 | image = "0.25.5" 18 | 19 | [workspace] 20 | -------------------------------------------------------------------------------- /servlets/image-resizer/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to check if a command exists 4 | command_exists () { 5 | command -v "$1" >/dev/null 2>&1 6 | } 7 | 8 | missing_deps=0 9 | 10 | # Check for Cargo 11 | if ! (command_exists cargo); then 12 | missing_deps=1 13 | echo "❌ Cargo/rust is not installed." 14 | echo "" 15 | echo "To install Rust, visit the official download page:" 16 | echo "👉 https://www.rust-lang.org/tools/install" 17 | echo "" 18 | echo "Or install it using a package manager:" 19 | echo "" 20 | echo "🔹 macOS (Homebrew):" 21 | echo " brew install cargo" 22 | echo "" 23 | echo "🔹 Ubuntu/Debian:" 24 | echo " sudo apt-get install -y cargo" 25 | echo "" 26 | echo "🔹 Arch Linux:" 27 | echo " sudo pacman -S rust" 28 | echo "" 29 | fi 30 | 31 | if ! (command_exists rustup); then 32 | missing_deps=1 33 | echo "❌ rustup is missing. Check your rust installation." 34 | echo "" 35 | fi 36 | 37 | # Exit with a bad exit code if any dependencies are missing 38 | if [ "$missing_deps" -ne 0 ]; then 39 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 40 | # TODO: remove sleep when cli bug is fixed 41 | sleep 2 42 | exit 1 43 | fi 44 | 45 | if ! (rustup target list --installed | grep -q '^wasm32-wasip1$'); then 46 | if ! (rustup target add wasm32-wasip1); then 47 | echo "❌ error encountered while adding target \"wasm32-wasip1\"" 48 | echo "" 49 | echo "Update rustup with:" 50 | echo "👉 rustup update" 51 | echo "" 52 | exit 1 53 | fi 54 | fi 55 | 56 | if ! (rustup target list --installed | grep -q '^wasm32-unknown-unknown$'); then 57 | rustup target add wasm32-unknown-unknown 58 | fi 59 | -------------------------------------------------------------------------------- /servlets/image-resizer/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "target/wasm32-wasip1/release/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "image-resizer" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "cargo build --release --target wasm32-wasip1" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/ipfs/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasip1" 3 | -------------------------------------------------------------------------------- /servlets/ipfs/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /servlets/ipfs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ipfs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | extism-pdk = "1.1.0" 12 | chrono = { version = "0.4", features = ["serde"] } 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | base64-serde = "0.7" 16 | base64 = "0.21" 17 | 18 | [workspace] 19 | -------------------------------------------------------------------------------- /servlets/ipfs/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to check if a command exists 4 | command_exists () { 5 | command -v "$1" >/dev/null 2>&1 6 | } 7 | 8 | missing_deps=0 9 | 10 | # Check for Cargo 11 | if ! (command_exists cargo); then 12 | missing_deps=1 13 | echo "❌ Cargo/rust is not installed." 14 | echo "" 15 | echo "To install Rust, visit the official download page:" 16 | echo "👉 https://www.rust-lang.org/tools/install" 17 | echo "" 18 | echo "Or install it using a package manager:" 19 | echo "" 20 | echo "🔹 macOS (Homebrew):" 21 | echo " brew install cargo" 22 | echo "" 23 | echo "🔹 Ubuntu/Debian:" 24 | echo " sudo apt-get install -y cargo" 25 | echo "" 26 | echo "🔹 Arch Linux:" 27 | echo " sudo pacman -S rust" 28 | echo "" 29 | fi 30 | 31 | if ! (command_exists rustup); then 32 | missing_deps=1 33 | echo "❌ rustup is missing. Check your rust installation." 34 | echo "" 35 | fi 36 | 37 | # Exit with a bad exit code if any dependencies are missing 38 | if [ "$missing_deps" -ne 0 ]; then 39 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 40 | # TODO: remove sleep when cli bug is fixed 41 | sleep 2 42 | exit 1 43 | fi 44 | 45 | if ! (rustup target list --installed | grep -q '^wasm32-wasip1$'); then 46 | if ! (rustup target add wasm32-wasip1); then 47 | echo "❌ error encountered while adding target \"wasm32-wasip1\"" 48 | echo "" 49 | echo "Update rustup with:" 50 | echo "👉 rustup update" 51 | echo "" 52 | exit 1 53 | fi 54 | fi 55 | 56 | if ! (rustup target list --installed | grep -q '^wasm32-unknown-unknown$'); then 57 | rustup target add wasm32-unknown-unknown 58 | fi 59 | -------------------------------------------------------------------------------- /servlets/ipfs/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "target/wasm32-wasip1/release/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "ipfs" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "cargo build --release --target wasm32-wasip1" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/jq/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasip1" 3 | -------------------------------------------------------------------------------- /servlets/jq/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jq" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | anyhow = "1.0.81" 12 | jaq-core = "2.1.0" 13 | jaq-parse = "1.0.3" 14 | jaq-std = "2.1.0" 15 | jaq-json = { version = "1.1.0", features = ["serde_json"] } 16 | extism-pdk = "1.1.0" 17 | chrono = { version = "0.4", features = ["serde"] } 18 | serde = { version = "1.0", features = ["derive"] } 19 | serde_json = "1.0" 20 | base64-serde = "0.7" 21 | base64 = "0.21" 22 | 23 | -------------------------------------------------------------------------------- /servlets/jq/README.md: -------------------------------------------------------------------------------- 1 | # jq 2 | 3 | A simple `jq` servlet based on the popular [`jaq` library](https://docs.rs/jaq-core/2.1.0/jaq_core/). It applies a JQ expression to a JSON input and returns the result. 4 | 5 | 6 | ## Example 7 | 8 | 9 | > You: can you extract the title of the window from this JSON payload? 10 | 11 | ```json 12 | {"widget": { 13 | "debug": "on", 14 | "window": { 15 | "title": "Sample Konfabulator Widget", 16 | "name": "main_window", 17 | "width": 500, 18 | "height": 500 19 | }, 20 | "image": { 21 | "src": "Images/Sun.png", 22 | "name": "sun1", 23 | "hOffset": 250, 24 | "vOffset": 250, 25 | "alignment": "center" 26 | }, 27 | "text": { 28 | "data": "Click Here", 29 | "size": 36, 30 | "style": "bold", 31 | "name": "text1", 32 | "hOffset": 250, 33 | "vOffset": 100, 34 | "alignment": "center", 35 | "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" 36 | } 37 | }} 38 | ``` 39 | 40 | > Assistant: The title of the window from the JSON payload is `"Sample Konfabulator Widget"`. -------------------------------------------------------------------------------- /servlets/jq/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to check if a command exists 4 | command_exists () { 5 | command -v "$1" >/dev/null 2>&1 6 | } 7 | 8 | missing_deps=0 9 | 10 | # Check for Cargo 11 | if ! (command_exists cargo); then 12 | missing_deps=1 13 | echo "❌ Cargo/rust is not installed." 14 | echo "" 15 | echo "To install Rust, visit the official download page:" 16 | echo "👉 https://www.rust-lang.org/tools/install" 17 | echo "" 18 | echo "Or install it using a package manager:" 19 | echo "" 20 | echo "🔹 macOS (Homebrew):" 21 | echo " brew install cargo" 22 | echo "" 23 | echo "🔹 Ubuntu/Debian:" 24 | echo " sudo apt-get install -y cargo" 25 | echo "" 26 | echo "🔹 Arch Linux:" 27 | echo " sudo pacman -S rust" 28 | echo "" 29 | fi 30 | 31 | if ! (command_exists rustup); then 32 | missing_deps=1 33 | echo "❌ rustup is missing. Check your rust installation." 34 | echo "" 35 | fi 36 | 37 | # Exit with a bad exit code if any dependencies are missing 38 | if [ "$missing_deps" -ne 0 ]; then 39 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 40 | # TODO: remove sleep when cli bug is fixed 41 | sleep 2 42 | exit 1 43 | fi 44 | 45 | if ! (rustup target list --installed | grep -q '^wasm32-wasip1$'); then 46 | if ! (rustup target add wasm32-wasip1); then 47 | echo "❌ error encountered while adding target \"wasm32-wasip1\"" 48 | echo "" 49 | echo "Update rustup with:" 50 | echo "👉 rustup update" 51 | echo "" 52 | exit 1 53 | fi 54 | fi 55 | 56 | if ! (rustup target list --installed | grep -q '^wasm32-unknown-unknown$'); then 57 | rustup target add wasm32-unknown-unknown 58 | fi 59 | -------------------------------------------------------------------------------- /servlets/jq/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "target/wasm32-wasip1/release/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "jq" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "cargo build --release --target wasm32-wasip1" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/json-schema/.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | 11 | pids 12 | logs 13 | results 14 | tmp 15 | 16 | # Build 17 | public/css/main.css 18 | 19 | # Coverage reports 20 | coverage 21 | 22 | # API keys and secrets 23 | .env 24 | 25 | # Dependency directory 26 | node_modules 27 | bower_components 28 | 29 | # Editors 30 | .idea 31 | *.iml 32 | 33 | # OS metadata 34 | .DS_Store 35 | Thumbs.db 36 | 37 | # Ignore built ts files 38 | dist/**/* 39 | 40 | # ignore yarn.lock 41 | yarn.lock 42 | 43 | *.wasm -------------------------------------------------------------------------------- /servlets/json-schema/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .git 4 | 5 | -------------------------------------------------------------------------------- /servlets/json-schema/.prettierrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dylibso/mcp.run-servlets/006e737a53ae666dec24655874d74ecf6d381f5c/servlets/json-schema/.prettierrc -------------------------------------------------------------------------------- /servlets/json-schema/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: run clean 2 | 3 | # Build target with caching - only rebuilds if source files change 4 | dist/plugin.wasm: $(shell find src -name '*.ts') 5 | xtp plugin build 6 | 7 | # Run the WordPress categories list command 8 | run: dist/plugin.wasm 9 | ./test.sh 10 | 11 | # Clean built files 12 | clean: 13 | rm -f dist/plugin.wasm 14 | 15 | # Default target 16 | .DEFAULT_GOAL := run -------------------------------------------------------------------------------- /servlets/json-schema/esbuild.js: -------------------------------------------------------------------------------- 1 | const esbuild = require('esbuild'); 2 | 3 | esbuild 4 | .build({ 5 | entryPoints: ['src/index.ts'], 6 | outdir: 'dist', 7 | bundle: true, 8 | sourcemap: true, 9 | minify: false, // might want to use true for production build 10 | format: 'cjs', // needs to be CJS for now 11 | target: ['es2020'], // don't go over es2020 because quickjs doesn't support it 12 | }) 13 | -------------------------------------------------------------------------------- /servlets/json-schema/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json-schema", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.ts", 6 | "scripts": { 7 | "build": "npx tsc --noEmit && node esbuild.js && extism-js dist/index.js -i src/index.d.ts -o dist/plugin.wasm", 8 | "format": "npx prettier --write \"src/**/*.{ts,tsx}\" --plugin=prettier-plugin-organize-imports" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "private": true, 13 | "license": "UNLICENSED", 14 | "devDependencies": { 15 | "@extism/js-pdk": "^1.0.1", 16 | "esbuild": "^0.19.6", 17 | "prettier": "^3.3.2", 18 | "prettier-plugin-organize-imports": "^4.1.0", 19 | "typescript": "^5.3.2" 20 | }, 21 | "overrides": { 22 | "fast-uri": "github:dylibso/fast-uri#remove-unicode-flags-from-regex" 23 | }, 24 | "dependencies": { 25 | "ajv": "^8.17.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /servlets/json-schema/src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "main" { 2 | export function call(): I32; 3 | export function describe(): I32; 4 | } 5 | -------------------------------------------------------------------------------- /servlets/json-schema/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as main from "./main"; 2 | 3 | import { CallToolRequest, CallToolResult, ListToolsResult } from "./pdk"; 4 | 5 | export function call(): number { 6 | const untypedInput = JSON.parse(Host.inputString()); 7 | const input = CallToolRequest.fromJson(untypedInput); 8 | 9 | const output = main.callImpl(input); 10 | 11 | const untypedOutput = CallToolResult.toJson(output); 12 | Host.outputString(JSON.stringify(untypedOutput)); 13 | 14 | return 0; 15 | } 16 | 17 | export function describe(): number { 18 | const output = main.describeImpl(); 19 | 20 | const untypedOutput = ListToolsResult.toJson(output); 21 | Host.outputString(JSON.stringify(untypedOutput)); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /servlets/json-schema/test.sh: -------------------------------------------------------------------------------- 1 | xtp plugin call ./dist/plugin.wasm --wasi --input '{ "params": { "name": "validate", "arguments": { "schema": {"$schema":"http://json-schema.org/draft-07/schema#","title":"Person","type":"object","properties":{"name":{"type":"string","description":"The person'\''s full name"},"age":{"type":"integer","minimum":0,"description":"The person'\''s age in years"},"isStudent":{"type":"boolean","description":"Whether the person is a student"}},"required":["name","age"]}, "document": {"namae":"John Doe","age":25,"isStudent":true} } } }' call -------------------------------------------------------------------------------- /servlets/json-schema/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", // Specify ECMAScript target version 4 | "module": "commonjs", // Specify module code generation 5 | "lib": [ 6 | "es2020" 7 | ], // Specify a list of library files to be included in the compilation 8 | "types": [ 9 | "@extism/js-pdk", 10 | "./src/index.d.ts" 11 | ], // Specify a list of type definition files to be included in the compilation 12 | "strict": true, // Enable all strict type-checking options 13 | "esModuleInterop": true, // Enables compatibility with Babel-style module imports 14 | "skipLibCheck": true, // Skip type checking of declaration files 15 | "allowJs": true, // Allow JavaScript files to be compiled 16 | "noEmit": true // Do not emit outputs (no .js or .d.ts files) 17 | }, 18 | "include": [ 19 | "src/**/*.ts" // Include all TypeScript files in src directory 20 | ], 21 | "exclude": [ 22 | "node_modules" // Exclude the node_modules directory 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /servlets/json-schema/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "json-schema" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "bash prepare.sh && npm run build" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "npm run format" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | 19 | [[test]] 20 | name = "basic tests" 21 | with = "../../test/testsuite/dist/test.wasm" -------------------------------------------------------------------------------- /servlets/notion/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasip1" 3 | -------------------------------------------------------------------------------- /servlets/notion/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | # RustRover 17 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 18 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 19 | # and can be added to the global gitignore or merged into this file. For a more nuclear 20 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 21 | #.idea/ 22 | -------------------------------------------------------------------------------- /servlets/notion/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "notion" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | extism-pdk = "1.1.0" 12 | chrono = { version = "0.4", features = ["serde"] } 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | base64-serde = "0.7" 16 | base64 = "0.21" -------------------------------------------------------------------------------- /servlets/notion/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | missing_deps=0 10 | 11 | # Check for Cargo 12 | if ! (command_exists cargo); then 13 | missing_deps=1 14 | echo "❌ Cargo/rust is not installed." 15 | echo "" 16 | echo "To install Rust, visit the official download page:" 17 | echo "👉 https://www.rust-lang.org/tools/install" 18 | echo "" 19 | echo "Or install it using a package manager:" 20 | echo "" 21 | echo "🔹 macOS (Homebrew):" 22 | echo " brew install cargo" 23 | echo "" 24 | echo "🔹 Ubuntu/Debian:" 25 | echo " sudo apt-get install -y cargo" 26 | echo "" 27 | echo "🔹 Arch Linux:" 28 | echo " sudo pacman -S rust" 29 | echo "" 30 | fi 31 | 32 | if ! (command_exists rustup); then 33 | missing_deps=1 34 | echo "❌ rustup is missing. Check your rust installation." 35 | echo "" 36 | fi 37 | 38 | # Exit with a bad exit code if any dependencies are missing 39 | if [ "$missing_deps" -ne 0 ]; then 40 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 41 | # TODO: remove sleep when cli bug is fixed 42 | sleep 2 43 | exit 1 44 | fi 45 | 46 | if ! (rustup target list --installed | grep -q '^wasm32-wasip1$'); then 47 | if ! (rustup target add wasm32-wasip1); then 48 | echo "❌ error encountered while adding target \"wasm32-wasip1\"" 49 | echo "" 50 | echo "Update rustup with:" 51 | echo "👉 rustup update" 52 | echo "" 53 | exit 1 54 | fi 55 | fi 56 | 57 | if ! (rustup target list --installed | grep -q '^wasm32-unknown-unknown$'); then 58 | rustup target add wasm32-unknown-unknown 59 | fi 60 | -------------------------------------------------------------------------------- /servlets/notion/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "target/wasm32-wasip1/release/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "notion" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "cargo build --release --target wasm32-wasip1" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/obsidian/.gitignore: -------------------------------------------------------------------------------- 1 | plugin.wasm 2 | plugin/__pycache__ 3 | -------------------------------------------------------------------------------- /servlets/obsidian/plugin/__init__.py: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS GENERATED BY `xtp-python-bindgen`. DO NOT EDIT. 2 | 3 | from typing import Optional, List # noqa: F401 4 | from datetime import datetime # noqa: F401 5 | import json 6 | import extism # pyright: ignore 7 | import plugin 8 | 9 | 10 | from pdk_types import ( 11 | BlobResourceContents, 12 | CallToolRequest, 13 | CallToolResult, 14 | Content, 15 | ContentType, 16 | ListToolsResult, 17 | Params, 18 | Role, 19 | TextAnnotation, 20 | TextResourceContents, 21 | ToolDescription, 22 | ) # noqa: F401 23 | 24 | 25 | # Imports 26 | 27 | 28 | # Exports 29 | # The implementations for these functions is in `plugin.py` 30 | 31 | 32 | # Called when the tool is invoked. 33 | # If you support multiple tools, you must switch on the input.params.name to detect which tool is being called. 34 | @extism.plugin_fn 35 | def call(): 36 | input = extism.input_str() 37 | input = CallToolRequest.from_json(input) 38 | res = plugin.call(input) 39 | extism.output_str(res.to_json()) 40 | 41 | 42 | # Called by mcpx to understand how and why to use this tool. 43 | # Note: Your servlet configs will not be set when this function is called, 44 | # so do not rely on config in this function 45 | @extism.plugin_fn 46 | def describe(): 47 | res = plugin.describe() 48 | extism.output_str(res.to_json()) 49 | -------------------------------------------------------------------------------- /servlets/obsidian/plugin/pdk_imports.py: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS GENERATED BY `xtp-python-bindgen`. DO NOT EDIT. 2 | 3 | from typing import Optional, List # noqa: F401 4 | from datetime import datetime # noqa: F401 5 | import extism # noqa: F401 # pyright: ignore 6 | import json 7 | 8 | 9 | from pdk_types import ( 10 | BlobResourceContents, 11 | CallToolRequest, 12 | CallToolResult, 13 | Content, 14 | ContentType, 15 | ListToolsResult, 16 | Params, 17 | Role, 18 | TextAnnotation, 19 | TextResourceContents, 20 | ToolDescription, 21 | ) # noqa: F401 22 | -------------------------------------------------------------------------------- /servlets/obsidian/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to check if a command exists 4 | command_exists () { 5 | command -v "$1" >/dev/null 2>&1 6 | } 7 | 8 | missing_deps=0 9 | 10 | # Check for uv 11 | if ! (command_exists uv); then 12 | missing_deps=1 13 | echo "❌ uv is not installed." 14 | echo "" 15 | echo "To install uv, visit the official download page:" 16 | echo "👉 https://docs.astral.sh/uv/getting-started/installation/" 17 | echo "" 18 | fi 19 | 20 | # Exit with a bad exit code if any dependencies are missing 21 | if [ "$missing_deps" -ne 0 ]; then 22 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 23 | # TODO: remove sleep when cli bug is fixed 24 | sleep 2 25 | exit 1 26 | fi 27 | 28 | # Check for extism-js 29 | if ! command_exists extism-py; then 30 | echo "❌ extism-py is not installed." 31 | echo "" 32 | echo "extism-py is needed to compile the plug-in. You can find the instructions to install it here: https://github.com/extism/python-pdk" 33 | echo "" 34 | echo "Alternatively, you can use an install script." 35 | echo "" 36 | echo "🔹 Mac / Linux:" 37 | echo "curl -L https://raw.githubusercontent.com/extism/python-pdk/main/install.sh | bash" 38 | echo "" 39 | # TODO: remove sleep when cli bug is fixed 40 | sleep 2 41 | exit 1 42 | fi 43 | -------------------------------------------------------------------------------- /servlets/obsidian/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "obsidian" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.13,<3.14" 7 | dependencies = [ 8 | "dataclass-wizard>=0.33.0,<0.34.0" 9 | ] 10 | 11 | [tool.uv] 12 | dev-dependencies = [ 13 | "pyright>=1.1.381", 14 | "ruff>=0.6.5", 15 | ] 16 | -------------------------------------------------------------------------------- /servlets/obsidian/pyrightconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "executionEnvironments": [ 3 | {"root": "plugin"} 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /servlets/obsidian/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "obsidian" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "PYTHONPATH=./plugin:./.venv/lib/python3.13/site-packages extism-py -o plugin.wasm plugin/__init__.py" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "uv run ruff format plugin/*.py" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh && uv sync" 18 | -------------------------------------------------------------------------------- /servlets/pantry/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pantry" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | extism-pdk = "1.1.0" 12 | chrono = { version = "0.4", features = ["serde"] } 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | base64-serde = "0.7" 16 | base64 = "0.21" 17 | 18 | [workspace] 19 | -------------------------------------------------------------------------------- /servlets/pantry/README.md: -------------------------------------------------------------------------------- 1 | # Pantry 2 | 3 | A simple JSON storage servlet based on [Pantry](https://getpantry.cloud). Use it to give long-term memory to your servlets or your tasks. 4 | 5 | Register a Pantry with just an email address on [Pantry](https://getpantry.cloud), you will be given a `PANTRY_ID` you can use to store and retrieve data. 6 | 7 | ## Config 8 | 9 | - `PANTRY_ID`: the ID of the pantry you want to use 10 | 11 | ## Domains 12 | 13 | - getpantry.cloud 14 | 15 | ## Tools 16 | The `pantry` tool takes an `action` (`get` or `post`) and a `basket` to identify the data. If the action is `post` then it also takes a `body` parameter in JSON format. 17 | -------------------------------------------------------------------------------- /servlets/pantry/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to check if a command exists 4 | command_exists () { 5 | command -v "$1" >/dev/null 2>&1 6 | } 7 | 8 | missing_deps=0 9 | 10 | # Check for Cargo 11 | if ! (command_exists cargo); then 12 | missing_deps=1 13 | echo "❌ Cargo/rust is not installed." 14 | echo "" 15 | echo "To install Rust, visit the official download page:" 16 | echo "👉 https://www.rust-lang.org/tools/install" 17 | echo "" 18 | echo "Or install it using a package manager:" 19 | echo "" 20 | echo "🔹 macOS (Homebrew):" 21 | echo " brew install cargo" 22 | echo "" 23 | echo "🔹 Ubuntu/Debian:" 24 | echo " sudo apt-get install -y cargo" 25 | echo "" 26 | echo "🔹 Arch Linux:" 27 | echo " sudo pacman -S rust" 28 | echo "" 29 | fi 30 | 31 | if ! (command_exists rustup); then 32 | missing_deps=1 33 | echo "❌ rustup is missing. Check your rust installation." 34 | echo "" 35 | fi 36 | 37 | # Exit with a bad exit code if any dependencies are missing 38 | if [ "$missing_deps" -ne 0 ]; then 39 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 40 | # TODO: remove sleep when cli bug is fixed 41 | sleep 2 42 | exit 1 43 | fi 44 | 45 | if ! (rustup target list --installed | grep -q '^wasm32-wasip1$'); then 46 | if ! (rustup target add wasm32-wasip1); then 47 | echo "❌ error encountered while adding target \"wasm32-wasip1\"" 48 | echo "" 49 | echo "Update rustup with:" 50 | echo "👉 rustup update" 51 | echo "" 52 | exit 1 53 | fi 54 | fi 55 | 56 | if ! (rustup target list --installed | grep -q '^wasm32-unknown-unknown$'); then 57 | rustup target add wasm32-unknown-unknown 58 | fi 59 | -------------------------------------------------------------------------------- /servlets/pantry/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "target/wasm32-wasip1/release/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "pantry" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "cargo build --release --target wasm32-wasip1" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/perplexity-sonar/.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | 11 | pids 12 | logs 13 | results 14 | tmp 15 | 16 | # Build 17 | public/css/main.css 18 | 19 | # Coverage reports 20 | coverage 21 | 22 | # API keys and secrets 23 | .env 24 | 25 | # Dependency directory 26 | node_modules 27 | bower_components 28 | 29 | # Editors 30 | .idea 31 | *.iml 32 | 33 | # OS metadata 34 | .DS_Store 35 | Thumbs.db 36 | 37 | # Ignore built ts files 38 | dist/**/* 39 | 40 | # ignore yarn.lock 41 | yarn.lock 42 | 43 | -------------------------------------------------------------------------------- /servlets/perplexity-sonar/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .git 4 | 5 | -------------------------------------------------------------------------------- /servlets/perplexity-sonar/.prettierrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dylibso/mcp.run-servlets/006e737a53ae666dec24655874d74ecf6d381f5c/servlets/perplexity-sonar/.prettierrc -------------------------------------------------------------------------------- /servlets/perplexity-sonar/esbuild.js: -------------------------------------------------------------------------------- 1 | const esbuild = require('esbuild'); 2 | 3 | esbuild 4 | .build({ 5 | entryPoints: ['src/index.ts'], 6 | outdir: 'dist', 7 | bundle: true, 8 | sourcemap: true, 9 | minify: false, // might want to use true for production build 10 | format: 'cjs', // needs to be CJS for now 11 | target: ['es2020'], // don't go over es2020 because quickjs doesn't support it 12 | }) 13 | -------------------------------------------------------------------------------- /servlets/perplexity-sonar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "perplexity-sonar", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.ts", 6 | "scripts": { 7 | "build": "npx tsc --noEmit && node esbuild.js && extism-js dist/index.js -i src/index.d.ts -o dist/plugin.wasm", 8 | "format": "npx prettier --write \"src/**/*.{ts,tsx}\" --plugin=prettier-plugin-organize-imports" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "private": true, 13 | "license": "UNLICENSED", 14 | "devDependencies": { 15 | "@extism/js-pdk": "^1.0.1", 16 | "esbuild": "^0.19.6", 17 | "typescript": "^5.3.2", 18 | "prettier": "^3.3.2", 19 | "prettier-plugin-organize-imports": "^4.1.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /servlets/perplexity-sonar/src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "main" { 2 | export function call(): I32; 3 | export function describe(): I32; 4 | } 5 | -------------------------------------------------------------------------------- /servlets/perplexity-sonar/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as main from "./main"; 2 | 3 | import { CallToolRequest, CallToolResult, ListToolsResult } from "./pdk"; 4 | 5 | export function call(): number { 6 | const untypedInput = JSON.parse(Host.inputString()); 7 | const input = CallToolRequest.fromJson(untypedInput); 8 | 9 | const output = main.callImpl(input); 10 | 11 | const untypedOutput = CallToolResult.toJson(output); 12 | Host.outputString(JSON.stringify(untypedOutput)); 13 | 14 | return 0; 15 | } 16 | 17 | export function describe(): number { 18 | const output = main.describeImpl(); 19 | 20 | const untypedOutput = ListToolsResult.toJson(output); 21 | Host.outputString(JSON.stringify(untypedOutput)); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /servlets/perplexity-sonar/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", // Specify ECMAScript target version 4 | "module": "commonjs", // Specify module code generation 5 | "lib": [ 6 | "es2020" 7 | ], // Specify a list of library files to be included in the compilation 8 | "types": [ 9 | "@extism/js-pdk", 10 | "./src/index.d.ts" 11 | ], // Specify a list of type definition files to be included in the compilation 12 | "strict": true, // Enable all strict type-checking options 13 | "esModuleInterop": true, // Enables compatibility with Babel-style module imports 14 | "skipLibCheck": true, // Skip type checking of declaration files 15 | "allowJs": true, // Allow JavaScript files to be compiled 16 | "noEmit": true, // Do not emit outputs (no .js or .d.ts files) 17 | "resolveJsonModule": true // Automatically resolve .json imports 18 | }, 19 | "include": [ 20 | "src/**/*.ts" // Include all TypeScript files in src directory 21 | ], 22 | "exclude": [ 23 | "node_modules" // Exclude the node_modules directory 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /servlets/perplexity-sonar/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "perplexity-sonar" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "bash prepare.sh && npm run build" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "npm run format" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/qr-code/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasip1" 3 | -------------------------------------------------------------------------------- /servlets/qr-code/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | # RustRover 17 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 18 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 19 | # and can be added to the global gitignore or merged into this file. For a more nuclear 20 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 21 | #.idea/ 22 | -------------------------------------------------------------------------------- /servlets/qr-code/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "qr-code" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | extism-pdk = "1.1.0" 12 | chrono = { version = "0.4", features = ["serde"] } 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | base64-serde = "0.7" 16 | base64 = "0.21" 17 | qrcode-png = "0.4.1" 18 | -------------------------------------------------------------------------------- /servlets/qr-code/README.md: -------------------------------------------------------------------------------- 1 | # QR Code Servlet 2 | 3 | A servlet that generates QR codes as PNG images. 4 | 5 | ## What it does 6 | 7 | Takes input text (like a URL or message) and generates a QR code image. 8 | 9 | ## Usage 10 | 11 | Call with: 12 | ```typescript 13 | { 14 | arguments: { 15 | data: "https://example.com", // Required: text to encode 16 | ecc: 4, // Optional: error correction (1-4, default 4) 17 | } 18 | } 19 | ``` 20 | 21 | Returns a base64-encoded PNG image of the QR code. -------------------------------------------------------------------------------- /servlets/qr-code/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "target/wasm32-wasip1/release/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | # This is the 'binding' name used for the plugin. 7 | name = "qr-code" 8 | 9 | [scripts] 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "cargo build --release --target wasm32-wasip1" 12 | 13 | # xtp plugin init runs this script to format the code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | # prepare = "" 18 | 19 | [[test]] 20 | name = "basic tests" 21 | with = "../../test/testsuite/dist/test.wasm" 22 | -------------------------------------------------------------------------------- /servlets/sequential-thinking/.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | 11 | pids 12 | logs 13 | results 14 | tmp 15 | 16 | # Build 17 | public/css/main.css 18 | 19 | # Coverage reports 20 | coverage 21 | 22 | # API keys and secrets 23 | .env 24 | 25 | # Dependency directory 26 | node_modules 27 | bower_components 28 | 29 | # Editors 30 | .idea 31 | *.iml 32 | 33 | # OS metadata 34 | .DS_Store 35 | Thumbs.db 36 | 37 | # Ignore built ts files 38 | dist/**/* 39 | 40 | # ignore yarn.lock 41 | yarn.lock 42 | 43 | -------------------------------------------------------------------------------- /servlets/sequential-thinking/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .git 4 | 5 | -------------------------------------------------------------------------------- /servlets/sequential-thinking/.prettierrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dylibso/mcp.run-servlets/006e737a53ae666dec24655874d74ecf6d381f5c/servlets/sequential-thinking/.prettierrc -------------------------------------------------------------------------------- /servlets/sequential-thinking/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Sequential Thinking MCP Server 3 | 4 | A port of [sequentialthinking](https://github.com/modelcontextprotocol/servers/tree/main/src/sequentialthinking), 5 | an MCP server implementation that provides a tool for dynamic and reflective problem-solving through a structured thinking process. 6 | 7 | ## Features 8 | 9 | - Break down complex problems into manageable steps 10 | - Revise and refine thoughts as understanding deepens 11 | - Branch into alternative paths of reasoning 12 | - Adjust the total number of thoughts dynamically 13 | - Generate and verify solution hypotheses 14 | 15 | ## Tool 16 | 17 | ### sequential_thinking 18 | 19 | Facilitates a detailed, step-by-step thinking process for problem-solving and analysis. 20 | 21 | **Inputs:** 22 | - `thought` (string): The current thinking step 23 | - `nextThoughtNeeded` (boolean): Whether another thought step is needed 24 | - `thoughtNumber` (integer): Current thought number 25 | - `totalThoughts` (integer): Estimated total thoughts needed 26 | - `isRevision` (boolean, optional): Whether this revises previous thinking 27 | - `revisesThought` (integer, optional): Which thought is being reconsidered 28 | - `branchFromThought` (integer, optional): Branching point thought number 29 | - `branchId` (string, optional): Branch identifier 30 | - `needsMoreThoughts` (boolean, optional): If more thoughts are needed 31 | 32 | ## Usage 33 | 34 | The Sequential Thinking tool is designed for: 35 | - Breaking down complex problems into steps 36 | - Planning and design with room for revision 37 | - Analysis that might need course correction 38 | - Problems where the full scope might not be clear initially 39 | - Tasks that need to maintain context over multiple steps 40 | - Situations where irrelevant information needs to be filtered out 41 | 42 | -------------------------------------------------------------------------------- /servlets/sequential-thinking/esbuild.js: -------------------------------------------------------------------------------- 1 | const esbuild = require('esbuild'); 2 | 3 | esbuild 4 | .build({ 5 | entryPoints: ['src/index.ts'], 6 | outdir: 'dist', 7 | bundle: true, 8 | sourcemap: true, 9 | minify: false, // might want to use true for production build 10 | format: 'cjs', // needs to be CJS for now 11 | target: ['es2020'], // don't go over es2020 because quickjs doesn't support it 12 | }) 13 | -------------------------------------------------------------------------------- /servlets/sequential-thinking/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sequential-thinking", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.ts", 6 | "scripts": { 7 | "build": "npx tsc --noEmit && node esbuild.js && extism-js dist/index.js -i src/index.d.ts -o dist/plugin.wasm", 8 | "format": "npx prettier --write \"src/**/*.{ts,tsx}\" --plugin=prettier-plugin-organize-imports" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "private": true, 13 | "license": "UNLICENSED", 14 | "devDependencies": { 15 | "@extism/js-pdk": "^1.0.1", 16 | "esbuild": "^0.19.6", 17 | "prettier": "^3.3.2", 18 | "prettier-plugin-organize-imports": "^4.1.0", 19 | "typescript": "^5.3.2" 20 | }, 21 | "dependencies": { 22 | "chalk": "^5.4.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /servlets/sequential-thinking/src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "main" { 2 | export function call(): I32; 3 | export function describe(): I32; 4 | } 5 | -------------------------------------------------------------------------------- /servlets/sequential-thinking/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as main from "./main"; 2 | 3 | import { CallToolRequest, CallToolResult, ListToolsResult } from "./pdk"; 4 | 5 | export function call(): number { 6 | const untypedInput = JSON.parse(Host.inputString()); 7 | const input = CallToolRequest.fromJson(untypedInput); 8 | 9 | const output = main.callImpl(input); 10 | 11 | const untypedOutput = CallToolResult.toJson(output); 12 | Host.outputString(JSON.stringify(untypedOutput)); 13 | 14 | return 0; 15 | } 16 | 17 | export function describe(): number { 18 | const output = main.describeImpl(); 19 | 20 | const untypedOutput = ListToolsResult.toJson(output); 21 | Host.outputString(JSON.stringify(untypedOutput)); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /servlets/sequential-thinking/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", // Specify ECMAScript target version 4 | "module": "commonjs", // Specify module code generation 5 | "lib": [ 6 | "es2020" 7 | ], // Specify a list of library files to be included in the compilation 8 | "types": [ 9 | "@extism/js-pdk", 10 | "./src/index.d.ts" 11 | ], // Specify a list of type definition files to be included in the compilation 12 | "strict": true, // Enable all strict type-checking options 13 | "esModuleInterop": true, // Enables compatibility with Babel-style module imports 14 | "skipLibCheck": true, // Skip type checking of declaration files 15 | "allowJs": true, // Allow JavaScript files to be compiled 16 | "noEmit": true, // Do not emit outputs (no .js or .d.ts files) 17 | "resolveJsonModule": true // Automatically resolve .json imports 18 | }, 19 | "include": [ 20 | "src/**/*.ts" // Include all TypeScript files in src directory 21 | ], 22 | "exclude": [ 23 | "node_modules" // Exclude the node_modules directory 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /servlets/sequential-thinking/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "sequential-thinking" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "bash prepare.sh && npm run build" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "npm run format" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/slack/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules 3 | -------------------------------------------------------------------------------- /servlets/slack/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .git 4 | 5 | -------------------------------------------------------------------------------- /servlets/slack/.prettierrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dylibso/mcp.run-servlets/006e737a53ae666dec24655874d74ecf6d381f5c/servlets/slack/.prettierrc -------------------------------------------------------------------------------- /servlets/slack/esbuild.js: -------------------------------------------------------------------------------- 1 | const esbuild = require('esbuild'); 2 | 3 | esbuild 4 | .build({ 5 | entryPoints: ['src/index.ts'], 6 | outdir: 'dist', 7 | bundle: true, 8 | sourcemap: true, 9 | minify: false, // might want to use true for production build 10 | format: 'cjs', // needs to be CJS for now 11 | target: ['es2020'], // don't go over es2020 because quickjs doesn't support it 12 | }) 13 | -------------------------------------------------------------------------------- /servlets/slack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slack", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.ts", 6 | "scripts": { 7 | "build": "npx tsc --noEmit && node esbuild.js && extism-js dist/index.js -i src/index.d.ts -o dist/plugin.wasm", 8 | "format": "npx prettier --write \"src/**/*.{ts,tsx}\" --plugin=prettier-plugin-organize-imports" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "private": true, 13 | "license": "UNLICENSED", 14 | "devDependencies": { 15 | "@extism/js-pdk": "^1.0.1", 16 | "esbuild": "^0.19.6", 17 | "typescript": "^5.3.2", 18 | "prettier": "^3.3.2", 19 | "prettier-plugin-organize-imports": "^4.1.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /servlets/slack/src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "main" { 2 | export function call(): I32; 3 | export function describe(): I32; 4 | } 5 | -------------------------------------------------------------------------------- /servlets/slack/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as main from "./main"; 2 | 3 | import { CallToolRequest, CallToolResult, ListToolsResult } from "./pdk"; 4 | 5 | export function call(): number { 6 | const untypedInput = JSON.parse(Host.inputString()); 7 | const input = CallToolRequest.fromJson(untypedInput); 8 | 9 | const output = main.callImpl(input); 10 | 11 | const untypedOutput = CallToolResult.toJson(output); 12 | Host.outputString(JSON.stringify(untypedOutput)); 13 | 14 | return 0; 15 | } 16 | 17 | export function describe(): number { 18 | const output = main.describeImpl(); 19 | 20 | const untypedOutput = ListToolsResult.toJson(output); 21 | Host.outputString(JSON.stringify(untypedOutput)); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /servlets/slack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", // Specify ECMAScript target version 4 | "module": "commonjs", // Specify module code generation 5 | "lib": [ 6 | "es2020" 7 | ], // Specify a list of library files to be included in the compilation 8 | "types": [ 9 | "@extism/js-pdk", 10 | "./src/index.d.ts" 11 | ], // Specify a list of type definition files to be included in the compilation 12 | "strict": true, // Enable all strict type-checking options 13 | "esModuleInterop": true, // Enables compatibility with Babel-style module imports 14 | "skipLibCheck": true, // Skip type checking of declaration files 15 | "allowJs": true, // Allow JavaScript files to be compiled 16 | "noEmit": true // Do not emit outputs (no .js or .d.ts files) 17 | }, 18 | "include": [ 19 | "src/**/*.ts" // Include all TypeScript files in src directory 20 | ], 21 | "exclude": [ 22 | "node_modules" // Exclude the node_modules directory 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /servlets/slack/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "slack" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "bash prepare.sh && npm run build" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "npm run format" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/sqlite/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasip1" 3 | -------------------------------------------------------------------------------- /servlets/sqlite/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sqlite" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | extism-pdk = "1.1.0" 12 | chrono = { version = "0.4", features = ["serde"] } 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | base64-serde = "0.7" 16 | base64 = "0.21" 17 | sqlite = "0.32.0" 18 | 19 | [workspace] 20 | -------------------------------------------------------------------------------- /servlets/sqlite/install-wasi-sdk.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Orignal from: https://github.com/Shopify/javy 3 | 4 | set -euo pipefail 5 | 6 | PATH_TO_SDK="./wasi-sdk" 7 | if [[ ! -d $PATH_TO_SDK ]]; then 8 | TMPGZ=$(mktemp) 9 | VERSION_MAJOR="24" 10 | VERSION_MINOR="0" 11 | ARCH=$(uname -m) 12 | if [[ "$(uname -s)" == "Darwin" ]]; then 13 | curl --fail --location --silent https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${VERSION_MAJOR}/wasi-sdk-${VERSION_MAJOR}.${VERSION_MINOR}-${ARCH}-macos.tar.gz --output $TMPGZ 14 | else 15 | curl --fail --location --silent https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${VERSION_MAJOR}/wasi-sdk-${VERSION_MAJOR}.${VERSION_MINOR}-${ARCH}-linux.tar.gz --output $TMPGZ 16 | fi 17 | mkdir $PATH_TO_SDK 18 | tar xf $TMPGZ -C $PATH_TO_SDK --strip-components=1 19 | fi 20 | -------------------------------------------------------------------------------- /servlets/sqlite/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to check if a command exists 4 | command_exists () { 5 | command -v "$1" >/dev/null 2>&1 6 | } 7 | 8 | missing_deps=0 9 | 10 | # Check for Cargo 11 | if ! (command_exists cargo); then 12 | missing_deps=1 13 | echo "❌ Cargo/rust is not installed." 14 | echo "" 15 | echo "To install Rust, visit the official download page:" 16 | echo "👉 https://www.rust-lang.org/tools/install" 17 | echo "" 18 | echo "Or install it using a package manager:" 19 | echo "" 20 | echo "🔹 macOS (Homebrew):" 21 | echo " brew install cargo" 22 | echo "" 23 | echo "🔹 Ubuntu/Debian:" 24 | echo " sudo apt-get install -y cargo" 25 | echo "" 26 | echo "🔹 Arch Linux:" 27 | echo " sudo pacman -S rust" 28 | echo "" 29 | fi 30 | 31 | if ! (command_exists rustup); then 32 | missing_deps=1 33 | echo "❌ rustup is missing. Check your rust installation." 34 | echo "" 35 | fi 36 | 37 | # Exit with a bad exit code if any dependencies are missing 38 | if [ "$missing_deps" -ne 0 ]; then 39 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 40 | # TODO: remove sleep when cli bug is fixed 41 | sleep 2 42 | exit 1 43 | fi 44 | 45 | if ! (rustup target list --installed | grep -q '^wasm32-wasip1$'); then 46 | if ! (rustup target add wasm32-wasip1); then 47 | echo "❌ error encountered while adding target \"wasm32-wasip1\"" 48 | echo "" 49 | echo "Update rustup with:" 50 | echo "👉 rustup update" 51 | echo "" 52 | exit 1 53 | fi 54 | fi 55 | 56 | if ! (rustup target list --installed | grep -q '^wasm32-unknown-unknown$'); then 57 | rustup target add wasm32-unknown-unknown 58 | fi 59 | 60 | # Check for ./wasi-sdk 61 | if ! (command_exists wasi-sdk/bin/clang); then 62 | echo "Installing wasi-sdk." 63 | echo "" 64 | source ./install-wasi-sdk.sh 65 | export PATH=$PWD/wasi-sdk/bin:$PATH 66 | fi 67 | -------------------------------------------------------------------------------- /servlets/sqlite/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "target/wasm32-wasip1/release/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "sqlite" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = 'PATH="$PWD/wasi-sdk/bin:$PATH"; cargo build --release --target wasm32-wasip1' 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/tenor-gifs/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | *.bak -------------------------------------------------------------------------------- /servlets/tenor-gifs/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Get API key from environment 4 | API_KEY=${TENOR_API_KEY:-""} 5 | 6 | if [ -z "$API_KEY" ]; then 7 | echo "Error: TENOR_API_KEY environment variable not set" 8 | exit 1 9 | fi 10 | 11 | # Replace placeholder in source code 12 | sed -i.bak 's/defaultAPIKey := "TENOR_API_KEY_PLACEHOLDER"/defaultAPIKey := "'$API_KEY'"/' main.go 13 | 14 | # Build the plugin 15 | tinygo build -target wasi -o dist/plugin.wasm . 16 | 17 | # Restore original source 18 | mv main.go.bak main.go -------------------------------------------------------------------------------- /servlets/tenor-gifs/go.mod: -------------------------------------------------------------------------------- 1 | module tenor-gifs 2 | 3 | go 1.22.1 4 | 5 | require github.com/extism/go-pdk v1.0.5 6 | -------------------------------------------------------------------------------- /servlets/tenor-gifs/go.sum: -------------------------------------------------------------------------------- 1 | github.com/extism/go-pdk v1.0.5 h1:5d5yYkWBweBP84Z+H3DP5DsD0fwvf2anWXyypCXpSW8= 2 | github.com/extism/go-pdk v1.0.5/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 3 | -------------------------------------------------------------------------------- /servlets/tenor-gifs/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | # Function to compare version numbers for "less than" 10 | version_lt() { 11 | test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" = "$1" && test "$1" != "$2" 12 | } 13 | 14 | missing_deps=0 15 | 16 | # Check for Go 17 | if ! (command_exists go); then 18 | missing_deps=1 19 | echo "❌ Go (supported version between 1.20 - 1.24) is not installed." 20 | echo "" 21 | echo "To install Go, visit the official download page:" 22 | echo "👉 https://go.dev/dl/" 23 | echo "" 24 | echo "Or install it using a package manager:" 25 | echo "" 26 | echo "🔹 macOS (Homebrew):" 27 | echo " brew install go" 28 | echo "" 29 | echo "🔹 Ubuntu/Debian:" 30 | echo " sudo apt-get -y install golang-go" 31 | echo "" 32 | echo "🔹 Arch Linux:" 33 | echo " sudo pacman -S go" 34 | echo "" 35 | echo "🔹 Windows:" 36 | echo " scoop install go" 37 | echo "" 38 | fi 39 | 40 | # Check for the right version of Go, needed by TinyGo (supports go 1.20 - 1.24) 41 | if (command_exists go); then 42 | compat=0 43 | for v in `seq 20 24`; do 44 | if (go version | grep -q "go1.$v"); then 45 | compat=1 46 | fi 47 | done 48 | 49 | if [ $compat -eq 0 ]; then 50 | echo "❌ Supported Go version is not installed. Must be Go 1.20 - 1.24." 51 | echo "" 52 | fi 53 | fi 54 | 55 | ARCH=$(arch) 56 | 57 | # Check for TinyGo and its version 58 | if ! (command_exists tinygo); then 59 | missing_deps=1 60 | echo "❌ TinyGo is not installed." 61 | echo "" 62 | echo "To install TinyGo, visit the official download page:" 63 | echo "👉 https://tinygo.org/getting-started/install/" 64 | echo "" 65 | echo "Or install it using a package manager:" 66 | echo "" 67 | echo "🔹 macOS (Homebrew):" 68 | echo " brew tap tinygo-org/tools" 69 | echo " brew install tinygo" 70 | echo "" 71 | echo "🔹 Ubuntu/Debian:" 72 | echo " wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_$ARCH.deb" 73 | echo " sudo dpkg -i tinygo_0.34.0_$ARCH.deb" 74 | echo "" 75 | echo "🔹 Arch Linux:" 76 | echo " pacman -S extra/tinygo" 77 | echo "" 78 | echo "🔹 Windows:" 79 | echo " scoop install tinygo" 80 | echo "" 81 | else 82 | # Check TinyGo version 83 | tinygo_version=$(tinygo version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n1) 84 | if version_lt "$tinygo_version" "0.34.0"; then 85 | missing_deps=1 86 | echo "❌ TinyGo version must be >= 0.34.0 (current version: $tinygo_version)" 87 | echo "Please update TinyGo to a newer version." 88 | echo "" 89 | fi 90 | fi 91 | 92 | go install golang.org/x/tools/cmd/goimports@latest 93 | -------------------------------------------------------------------------------- /servlets/tenor-gifs/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "tenor-gifs" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "mkdir -p dist && bash build.sh" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "go fmt && go mod tidy && goimports -w main.go" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "sh prepare.sh && go get ./..." 18 | 19 | [[test]] 20 | name = "basic tests" 21 | with = "../../test/testsuite/dist/test.wasm" -------------------------------------------------------------------------------- /servlets/text-to-speech/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasip1" 3 | -------------------------------------------------------------------------------- /servlets/text-to-speech/.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target 3 | *.mp3 4 | -------------------------------------------------------------------------------- /servlets/text-to-speech/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "text-to-speech" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | extism-pdk = "1.1.0" 12 | chrono = { version = "0.4", features = ["serde"] } 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | base64-serde = "0.7" 16 | base64 = "0.21" 17 | 18 | [workspace] 19 | -------------------------------------------------------------------------------- /servlets/text-to-speech/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to check if a command exists 4 | command_exists () { 5 | command -v "$1" >/dev/null 2>&1 6 | } 7 | 8 | missing_deps=0 9 | 10 | # Check for Cargo 11 | if ! (command_exists cargo); then 12 | missing_deps=1 13 | echo "❌ Cargo/rust is not installed." 14 | echo "" 15 | echo "To install Rust, visit the official download page:" 16 | echo "👉 https://www.rust-lang.org/tools/install" 17 | echo "" 18 | echo "Or install it using a package manager:" 19 | echo "" 20 | echo "🔹 macOS (Homebrew):" 21 | echo " brew install cargo" 22 | echo "" 23 | echo "🔹 Ubuntu/Debian:" 24 | echo " sudo apt-get install -y cargo" 25 | echo "" 26 | echo "🔹 Arch Linux:" 27 | echo " sudo pacman -S rust" 28 | echo "" 29 | fi 30 | 31 | if ! (command_exists rustup); then 32 | missing_deps=1 33 | echo "❌ rustup is missing. Check your rust installation." 34 | echo "" 35 | fi 36 | 37 | # Exit with a bad exit code if any dependencies are missing 38 | if [ "$missing_deps" -ne 0 ]; then 39 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 40 | # TODO: remove sleep when cli bug is fixed 41 | sleep 2 42 | exit 1 43 | fi 44 | 45 | if ! (rustup target list --installed | grep -q '^wasm32-wasip1$'); then 46 | if ! (rustup target add wasm32-wasip1); then 47 | echo "❌ error encountered while adding target \"wasm32-wasip1\"" 48 | echo "" 49 | echo "Update rustup with:" 50 | echo "👉 rustup update" 51 | echo "" 52 | exit 1 53 | fi 54 | fi 55 | 56 | if ! (rustup target list --installed | grep -q '^wasm32-unknown-unknown$'); then 57 | rustup target add wasm32-unknown-unknown 58 | fi 59 | -------------------------------------------------------------------------------- /servlets/text-to-speech/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "target/wasm32-wasip1/release/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "text-to-speech" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "cargo build --release --target wasm32-wasip1" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/time/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasip1" 3 | -------------------------------------------------------------------------------- /servlets/time/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | # RustRover 17 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 18 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 19 | # and can be added to the global gitignore or merged into this file. For a more nuclear 20 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 21 | #.idea/ 22 | -------------------------------------------------------------------------------- /servlets/time/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "time" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | extism-pdk = "1.1.0" 12 | chrono = { version = "0.4", features = ["serde"] } 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | base64-serde = "0.7" 16 | base64 = "0.21" -------------------------------------------------------------------------------- /servlets/time/README.md: -------------------------------------------------------------------------------- 1 | # Time Servlet 2 | 3 | Time operations plugin. It provides the following operations: 4 | 5 | - `get_time_utc`: Returns the current time in the UTC timezone. Takes no parameters. 6 | - `parse_time`: Takes a `time` string in RFC2822 format and returns the timestamp in UTC timezone. 7 | - `time_offset`: Takes integer `time` and `offset` parameters. Adds a time offset to a given timestamp and returns the new timestamp in UTC timezone. 8 | 9 | ## Examples 10 | 11 | Get current time: 12 | 13 | ```typescript 14 | { 15 | `name`: `get_time_utc` 16 | } 17 | // returns: 18 | { 19 | "utc_time" : "1734085548", 20 | "utc_time_rfc2822" : "Fri, 13 Dec 2024 10:25:48 +0000" 21 | } 22 | ``` 23 | 24 | What would be last Sunday? 25 | 26 | ```typescript 27 | { 28 | `name`: `time_offset`, 29 | `time`: 1734085548, 30 | `offset`: -432000 31 | } 32 | // returns: 33 | { 34 | "utc_time" : "1733653548", 35 | "utc_time_rfc2822" : "Sun, 8 Dec 2024 10:25:48 +0000" 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /servlets/time/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | missing_deps=0 10 | 11 | # Check for Cargo 12 | if ! (command_exists cargo); then 13 | missing_deps=1 14 | echo "❌ Cargo/rust is not installed." 15 | echo "" 16 | echo "To install Rust, visit the official download page:" 17 | echo "👉 https://www.rust-lang.org/tools/install" 18 | echo "" 19 | echo "Or install it using a package manager:" 20 | echo "" 21 | echo "🔹 macOS (Homebrew):" 22 | echo " brew install cargo" 23 | echo "" 24 | echo "🔹 Ubuntu/Debian:" 25 | echo " sudo apt-get install -y cargo" 26 | echo "" 27 | echo "🔹 Arch Linux:" 28 | echo " sudo pacman -S rust" 29 | echo "" 30 | fi 31 | 32 | if ! (command_exists rustup); then 33 | missing_deps=1 34 | echo "❌ rustup is missing. Check your rust installation." 35 | echo "" 36 | fi 37 | 38 | # Exit with a bad exit code if any dependencies are missing 39 | if [ "$missing_deps" -ne 0 ]; then 40 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 41 | # TODO: remove sleep when cli bug is fixed 42 | sleep 2 43 | exit 1 44 | fi 45 | 46 | if ! (rustup target list --installed | grep -q '^wasm32-wasip1$'); then 47 | if ! (rustup target add wasm32-wasip1); then 48 | echo "❌ error encountered while adding target \"wasm32-wasip1\"" 49 | echo "" 50 | echo "Update rustup with:" 51 | echo "👉 rustup update" 52 | echo "" 53 | exit 1 54 | fi 55 | fi 56 | 57 | if ! (rustup target list --installed | grep -q '^wasm32-unknown-unknown$'); then 58 | rustup target add wasm32-unknown-unknown 59 | fi 60 | -------------------------------------------------------------------------------- /servlets/time/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "target/wasm32-wasip1/release/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "time" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "cargo build --release --target wasm32-wasip1" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/trello/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm -------------------------------------------------------------------------------- /servlets/trello/go.mod: -------------------------------------------------------------------------------- 1 | module trello 2 | 3 | go 1.22.1 4 | 5 | require github.com/extism/go-pdk v1.0.5 6 | -------------------------------------------------------------------------------- /servlets/trello/go.sum: -------------------------------------------------------------------------------- 1 | github.com/extism/go-pdk v1.0.5 h1:5d5yYkWBweBP84Z+H3DP5DsD0fwvf2anWXyypCXpSW8= 2 | github.com/extism/go-pdk v1.0.5/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 3 | -------------------------------------------------------------------------------- /servlets/trello/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | # Function to compare version numbers for "less than" 10 | version_lt() { 11 | test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" = "$1" && test "$1" != "$2" 12 | } 13 | 14 | missing_deps=0 15 | 16 | # Check for Go 17 | if ! (command_exists go); then 18 | missing_deps=1 19 | echo "❌ Go (supported version between 1.20 - 1.24) is not installed." 20 | echo "" 21 | echo "To install Go, visit the official download page:" 22 | echo "👉 https://go.dev/dl/" 23 | echo "" 24 | echo "Or install it using a package manager:" 25 | echo "" 26 | echo "🔹 macOS (Homebrew):" 27 | echo " brew install go" 28 | echo "" 29 | echo "🔹 Ubuntu/Debian:" 30 | echo " sudo apt-get -y install golang-go" 31 | echo "" 32 | echo "🔹 Arch Linux:" 33 | echo " sudo pacman -S go" 34 | echo "" 35 | echo "🔹 Windows:" 36 | echo " scoop install go" 37 | echo "" 38 | fi 39 | 40 | # Check for the right version of Go, needed by TinyGo (supports go 1.20 - 1.24) 41 | if (command_exists go); then 42 | compat=0 43 | for v in `seq 20 24`; do 44 | if (go version | grep -q "go1.$v"); then 45 | compat=1 46 | fi 47 | done 48 | 49 | if [ $compat -eq 0 ]; then 50 | echo "❌ Supported Go version is not installed. Must be Go 1.20 - 1.24." 51 | echo "" 52 | fi 53 | fi 54 | 55 | ARCH=$(arch) 56 | 57 | # Check for TinyGo and its version 58 | if ! (command_exists tinygo); then 59 | missing_deps=1 60 | echo "❌ TinyGo is not installed." 61 | echo "" 62 | echo "To install TinyGo, visit the official download page:" 63 | echo "👉 https://tinygo.org/getting-started/install/" 64 | echo "" 65 | echo "Or install it using a package manager:" 66 | echo "" 67 | echo "🔹 macOS (Homebrew):" 68 | echo " brew tap tinygo-org/tools" 69 | echo " brew install tinygo" 70 | echo "" 71 | echo "🔹 Ubuntu/Debian:" 72 | echo " wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_$ARCH.deb" 73 | echo " sudo dpkg -i tinygo_0.34.0_$ARCH.deb" 74 | echo "" 75 | echo "🔹 Arch Linux:" 76 | echo " pacman -S extra/tinygo" 77 | echo "" 78 | echo "🔹 Windows:" 79 | echo " scoop install tinygo" 80 | echo "" 81 | else 82 | # Check TinyGo version 83 | tinygo_version=$(tinygo version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n1) 84 | if version_lt "$tinygo_version" "0.34.0"; then 85 | missing_deps=1 86 | echo "❌ TinyGo version must be >= 0.34.0 (current version: $tinygo_version)" 87 | echo "Please update TinyGo to a newer version." 88 | echo "" 89 | fi 90 | fi 91 | 92 | go install golang.org/x/tools/cmd/goimports@latest 93 | -------------------------------------------------------------------------------- /servlets/trello/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "trello" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "mkdir -p dist && tinygo build -target wasi -o dist/plugin.wasm ." 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "go fmt && go mod tidy && goimports -w main.go" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "sh prepare.sh && go get ./..." 18 | -------------------------------------------------------------------------------- /servlets/twilio/.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | 11 | pids 12 | logs 13 | results 14 | tmp 15 | 16 | # Build 17 | public/css/main.css 18 | 19 | # Coverage reports 20 | coverage 21 | 22 | # API keys and secrets 23 | .env 24 | 25 | # Dependency directory 26 | node_modules 27 | bower_components 28 | 29 | # Editors 30 | .idea 31 | *.iml 32 | 33 | # OS metadata 34 | .DS_Store 35 | Thumbs.db 36 | 37 | # Ignore built ts files 38 | dist/**/* 39 | 40 | # ignore yarn.lock 41 | yarn.lock 42 | 43 | -------------------------------------------------------------------------------- /servlets/twilio/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .git 4 | 5 | -------------------------------------------------------------------------------- /servlets/twilio/.prettierrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dylibso/mcp.run-servlets/006e737a53ae666dec24655874d74ecf6d381f5c/servlets/twilio/.prettierrc -------------------------------------------------------------------------------- /servlets/twilio/esbuild.js: -------------------------------------------------------------------------------- 1 | const esbuild = require('esbuild'); 2 | 3 | esbuild 4 | .build({ 5 | entryPoints: ['src/index.ts'], 6 | outdir: 'dist', 7 | bundle: true, 8 | sourcemap: true, 9 | minify: false, // might want to use true for production build 10 | format: 'cjs', // needs to be CJS for now 11 | target: ['es2020'], // don't go over es2020 because quickjs doesn't support it 12 | }) 13 | -------------------------------------------------------------------------------- /servlets/twilio/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twilio", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.ts", 6 | "scripts": { 7 | "build": "npx tsc --noEmit && node esbuild.js && extism-js dist/index.js -i src/index.d.ts -o dist/plugin.wasm", 8 | "format": "npx prettier --write \"src/**/*.{ts,tsx}\" --plugin=prettier-plugin-organize-imports" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "private": true, 13 | "license": "UNLICENSED", 14 | "devDependencies": { 15 | "@extism/js-pdk": "^1.0.1", 16 | "esbuild": "^0.19.6", 17 | "typescript": "^5.3.2", 18 | "prettier": "^3.3.2", 19 | "prettier-plugin-organize-imports": "^4.1.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /servlets/twilio/src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "main" { 2 | export function call(): I32; 3 | export function describe(): I32; 4 | } 5 | -------------------------------------------------------------------------------- /servlets/twilio/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as main from "./main"; 2 | 3 | import { CallToolRequest, CallToolResult, ListToolsResult } from "./pdk"; 4 | 5 | export function call(): number { 6 | const untypedInput = JSON.parse(Host.inputString()); 7 | const input = CallToolRequest.fromJson(untypedInput); 8 | 9 | const output = main.callImpl(input); 10 | 11 | const untypedOutput = CallToolResult.toJson(output); 12 | Host.outputString(JSON.stringify(untypedOutput)); 13 | 14 | return 0; 15 | } 16 | 17 | export function describe(): number { 18 | const output = main.describeImpl(); 19 | 20 | const untypedOutput = ListToolsResult.toJson(output); 21 | Host.outputString(JSON.stringify(untypedOutput)); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /servlets/twilio/src/main.ts: -------------------------------------------------------------------------------- 1 | import { CallToolRequest, CallToolResult, ContentType, ListToolsResult } from "./pdk"; 2 | 3 | export function callImpl(input: CallToolRequest): CallToolResult { 4 | const { to, from, body } = input.params.arguments || {}; 5 | 6 | if (!to || !from || !body) { 7 | throw new Error("Arguments 'to', 'from', and 'body' must be provided"); 8 | } 9 | 10 | const accountSid = Config.get('TWILIO_ACCOUNT_SID') 11 | const authToken = Config.get('TWILIO_AUTH_TOKEN') 12 | 13 | if (!accountSid || !authToken) { 14 | throw new Error("Twilio credentials not configured"); 15 | } 16 | 17 | const auth = Host.arrayBufferToBase64((new TextEncoder()).encode(`${accountSid}:${authToken}`).buffer); 18 | const url = `https://api.twilio.com/2010-04-01/Accounts/${accountSid}/Messages.json`; 19 | 20 | const response = Http.request({ 21 | url, 22 | method: 'POST', 23 | headers: { 24 | 'Authorization': `Basic ${auth}`, 25 | 'Content-Type': 'application/x-www-form-urlencoded' 26 | }, 27 | }, 28 | new URLSearchParams({ 29 | To: to, 30 | From: from, 31 | Body: body 32 | }).toString() 33 | ) 34 | 35 | return { 36 | content: [{ 37 | type: ContentType.Text, 38 | text: response.body 39 | }] 40 | }; 41 | } 42 | 43 | export function describeImpl(): ListToolsResult { 44 | return { 45 | tools: [{ 46 | name: "send_sms", 47 | description: "Send an SMS message via Twilio", 48 | inputSchema: { 49 | type: "object", 50 | properties: { 51 | to: { 52 | type: "string", 53 | description: "The destination phone number" 54 | }, 55 | from: { 56 | type: "string", 57 | description: "The sender phone number (must be a Twilio number)" 58 | }, 59 | body: { 60 | type: "string", 61 | description: "The message content" 62 | } 63 | }, 64 | required: ["to", "from", "body"] 65 | } 66 | }] 67 | }; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /servlets/twilio/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", // Specify ECMAScript target version 4 | "module": "commonjs", // Specify module code generation 5 | "lib": [ 6 | "es2020" 7 | ], // Specify a list of library files to be included in the compilation 8 | "types": [ 9 | "@extism/js-pdk", 10 | "./src/index.d.ts" 11 | ], // Specify a list of type definition files to be included in the compilation 12 | "strict": true, // Enable all strict type-checking options 13 | "esModuleInterop": true, // Enables compatibility with Babel-style module imports 14 | "skipLibCheck": true, // Skip type checking of declaration files 15 | "allowJs": true, // Allow JavaScript files to be compiled 16 | "noEmit": true // Do not emit outputs (no .js or .d.ts files) 17 | }, 18 | "include": [ 19 | "src/**/*.ts" // Include all TypeScript files in src directory 20 | ], 21 | "exclude": [ 22 | "node_modules" // Exclude the node_modules directory 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /servlets/twilio/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "twilio" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "bash prepare.sh && npm run build" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "npm run format" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/unsplash/.gitignore: -------------------------------------------------------------------------------- 1 | zig-out/ 2 | .zig-cache/** 3 | -------------------------------------------------------------------------------- /servlets/unsplash/README.md: -------------------------------------------------------------------------------- 1 | # Unsplash Servlet 2 | 3 | [Unsplash](https://unsplash.com) is a collection of high-quality photos. 4 | This servlet allows you to search and retrieve pictures from the archive. 5 | Use in conjuction with the `fetch` servlet to fetch and display the URLs. 6 | 7 | The servlet serves also as a tutorial for Zig support. 8 | 9 | ## Config 10 | 11 | `API_KEY`: Your "Access Key" on https://unsplash.com/oauth/applications 12 | 13 | ## Hosts 14 | 15 | - You should allow access to `api.unsplash.com`. 16 | 17 | ## Example: 18 | 19 | 20 | fetch a photo of Milan, Piazza Duomo 21 | 22 | > I'll help you fetch a photo of Milan's Piazza del Duomo using the Unsplash API 23 | > 24 | >> (uses `unsplash`) 25 | > 26 | > Let me fetch this specific photo to show you: 27 | > 28 | >> (uses `fetch`) 29 | > 30 | > This is a stunning aerial view of Milan's Piazza del Duomo, taken from one of the upper levels of the Cathedral (Duomo di Milano). The image captures the intricate Gothic architecture of the Duomo on the left, with its elaborate spires and statues, while showing the expansive square below filled with people. On the right side, you can see the elegant Galleria Vittorio Emanuele II, one of the world's oldest shopping galleries, with its distinctive neoclassical architecture. The photo provides a great perspective on how this historic square serves as the heart of Milan, where Gothic architecture meets classical design and modern city life. 31 | 32 | The retrieved image: https://unsplash.com/photos/people-on-street-near-concrete-buildings-BBigUtobEYo 33 | -------------------------------------------------------------------------------- /servlets/unsplash/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | // if you're not using WASI, change this to .freestanding 4 | const BUILD_TARGET_OS = .wasi; 5 | 6 | pub fn build(b: *std.Build) !void { 7 | const optimize = b.standardOptimizeOption(.{}); 8 | const target = b.standardTargetOptions(.{ 9 | .default_target = .{ .abi = .musl, .os_tag = BUILD_TARGET_OS, .cpu_arch = .wasm32 }, 10 | }); 11 | const pdk_module = b.dependency("extism-pdk", .{ .target = target, .optimize = optimize }).module("extism-pdk"); 12 | 13 | var plugin = b.addExecutable(.{ 14 | .name = "plugin", 15 | .root_source_file = b.path("src/pdk.zig"), 16 | .target = target, 17 | .optimize = optimize, 18 | }); 19 | if (BUILD_TARGET_OS == .wasi) { 20 | plugin.wasi_exec_model = .reactor; 21 | } 22 | plugin.rdynamic = true; 23 | plugin.entry = .disabled; // or add an empty `pub fn main() void {}` to your code 24 | plugin.root_module.addImport("extism-pdk", pdk_module); 25 | b.installArtifact(plugin); 26 | } 27 | -------------------------------------------------------------------------------- /servlets/unsplash/build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = "unsplash", 3 | // This is a [Semantic Version](https://semver.org/). 4 | // In a future version of Zig it will be used for package deduplication. 5 | .version = "0.0.0", 6 | 7 | // This field is optional. 8 | // This is currently advisory only; Zig does not yet do anything 9 | // with this value. 10 | //.minimum_zig_version = "0.11.0", 11 | 12 | // This field is optional. 13 | // Each dependency must either provide a `url` and `hash`, or a `path`. 14 | // `zig build --fetch` can be used to fetch all dependencies of a package, recursively. 15 | // Once all dependencies are fetched, `zig build` no longer requires 16 | // internet connectivity. 17 | .dependencies = .{ 18 | .@"extism-pdk" = .{ 19 | .url = "https://github.com/extism/zig-pdk/archive/refs/tags/v1.3.0.tar.gz", 20 | .hash = "1220d21f918a4e96d7ccea385d7609d97c39430d027997f82121e3fbae273e4d4c06", 21 | }, 22 | }, 23 | .paths = .{ 24 | // This makes *all* files, recursively, included in this package. It is generally 25 | // better to explicitly list the files and directories instead, to insure that 26 | // fetching from tarballs, file system paths, and version control all result 27 | // in the same contents hash. 28 | "", 29 | // For example... 30 | //"build.zig", 31 | //"build.zig.zon", 32 | //"src", 33 | //"LICENSE", 34 | //"README.md", 35 | }, 36 | } 37 | -------------------------------------------------------------------------------- /servlets/unsplash/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "zig-out/bin/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "unsplash" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "zig build" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "zig fmt ." 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "" 18 | -------------------------------------------------------------------------------- /servlets/wolfram-alpha/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-wasip1" 3 | -------------------------------------------------------------------------------- /servlets/wolfram-alpha/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /servlets/wolfram-alpha/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wolfram-alpha" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "plugin" 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | extism-pdk = "1.1.0" 12 | chrono = { version = "0.4", features = ["serde"] } 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | base64-serde = "0.7" 16 | base64 = "0.21" 17 | url = "2.5.4" -------------------------------------------------------------------------------- /servlets/wolfram-alpha/README.md: -------------------------------------------------------------------------------- 1 | # Wolfram Alpha LLM Tool 2 | 3 | A simple tool that interfaces with Wolfram Alpha's LLM API to get AI-powered responses to queries. 4 | 5 | ## Description 6 | 7 | This tool sends queries to Wolfram Alpha's Large Language Model API and returns the responses. It provides a straightforward way to access Wolfram Alpha's AI capabilities through a simple interface. 8 | 9 | ## Usage 10 | 11 | You can invoke the tool with a query parameter: 12 | 13 | ```json 14 | { 15 | "query": "What is the speed of light?" 16 | } 17 | ``` 18 | 19 | The tool will return the response from Wolfram Alpha's LLM in plain text format. 20 | 21 | -------------------------------------------------------------------------------- /servlets/wolfram-alpha/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | missing_deps=0 10 | 11 | # Check for Cargo 12 | if ! (command_exists cargo); then 13 | missing_deps=1 14 | echo "❌ Cargo/rust is not installed." 15 | echo "" 16 | echo "To install Rust, visit the official download page:" 17 | echo "👉 https://www.rust-lang.org/tools/install" 18 | echo "" 19 | echo "Or install it using a package manager:" 20 | echo "" 21 | echo "🔹 macOS (Homebrew):" 22 | echo " brew install cargo" 23 | echo "" 24 | echo "🔹 Ubuntu/Debian:" 25 | echo " sudo apt-get install -y cargo" 26 | echo "" 27 | echo "🔹 Arch Linux:" 28 | echo " sudo pacman -S rust" 29 | echo "" 30 | fi 31 | 32 | if ! (command_exists rustup); then 33 | missing_deps=1 34 | echo "❌ rustup is missing. Check your rust installation." 35 | echo "" 36 | fi 37 | 38 | # Exit with a bad exit code if any dependencies are missing 39 | if [ "$missing_deps" -ne 0 ]; then 40 | echo "Install the missing dependencies and ensure they are on your path. Then run this command again." 41 | # TODO: remove sleep when cli bug is fixed 42 | sleep 2 43 | exit 1 44 | fi 45 | 46 | if ! (rustup target list --installed | grep -q '^wasm32-wasip1$'); then 47 | if ! (rustup target add wasm32-wasip1); then 48 | echo "❌ error encountered while adding target \"wasm32-wasip1\"" 49 | echo "" 50 | echo "Update rustup with:" 51 | echo "👉 rustup update" 52 | echo "" 53 | exit 1 54 | fi 55 | fi 56 | 57 | if ! (rustup target list --installed | grep -q '^wasm32-unknown-unknown$'); then 58 | rustup target add wasm32-unknown-unknown 59 | fi 60 | -------------------------------------------------------------------------------- /servlets/wolfram-alpha/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod pdk; 2 | use extism_pdk::*; 3 | use pdk::*; 4 | use url::form_urlencoded; 5 | 6 | pub(crate) fn call(input: types::CallToolRequest) -> Result { 7 | let query = input 8 | .params 9 | .arguments 10 | .as_ref() 11 | .and_then(|args| args.get("query")) 12 | .and_then(|query| query.as_str()) 13 | .ok_or_else(|| Error::msg("Argument `query` must be provided"))?; 14 | 15 | let app_id = config::get("WOLFRAM_APP_ID")? 16 | .ok_or_else(|| Error::msg("config WOLFRAM_APP_ID must be set"))?; 17 | 18 | let url = format!( 19 | "https://www.wolframalpha.com/api/v1/llm-api?appid={}&input={}", 20 | form_urlencoded::byte_serialize(app_id.as_bytes()).collect::(), 21 | form_urlencoded::byte_serialize(query.as_bytes()).collect::(), 22 | ); 23 | 24 | let req = HttpRequest::new(&url).with_method("GET"); 25 | let res = http::request::<()>(&req, None)?; 26 | 27 | if res.status_code() != 200 { 28 | return Err(Error::msg(format!( 29 | "Wolfram Alpha API returned status code: {}", 30 | res.status() 31 | ))); 32 | } 33 | 34 | // Get response body as string 35 | let response_text = String::from_utf8(res.body().to_vec()) 36 | .map_err(|e| Error::msg(format!("Failed to parse response: {}", e)))?; 37 | 38 | Ok(types::CallToolResult { 39 | content: vec![types::Content { 40 | r#type: types::ContentType::Text, 41 | text: Some(response_text), 42 | annotations: None, 43 | data: None, 44 | mime_type: None, 45 | }], 46 | is_error: None, 47 | }) 48 | } 49 | 50 | pub(crate) fn describe() -> Result { 51 | Ok(types::ToolDescription { 52 | name: "wolfram_llm".to_string(), 53 | description: "Query the Wolfram Alpha LLM API".to_string(), 54 | input_schema: serde_json::json!({ 55 | "type": "object", 56 | "properties": { 57 | "query": { 58 | "type": "string", 59 | "description": "the question or prompt to send to Wolfram Alpha's LLM" 60 | } 61 | }, 62 | "required": ["query"] 63 | }) 64 | .as_object() 65 | .unwrap() 66 | .clone(), 67 | }) 68 | } 69 | -------------------------------------------------------------------------------- /servlets/wolfram-alpha/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "target/wasm32-wasip1/release/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "wolfram-alpha" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "cargo build --release --target wasm32-wasip1" 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "cargo fmt" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "bash prepare.sh" 18 | -------------------------------------------------------------------------------- /servlets/wordpress/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | test.sh 3 | dev/** -------------------------------------------------------------------------------- /servlets/wordpress/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: run clean 2 | 3 | # Build target with caching - only rebuilds if source files change 4 | dist/plugin.wasm: $(shell find . -name '*.go') 5 | xtp plugin build 6 | 7 | # Run the WordPress categories list command 8 | run: dist/plugin.wasm 9 | ./test.sh 10 | 11 | # Clean built files 12 | clean: 13 | rm -f dist/plugin.wasm 14 | 15 | # Default target 16 | .DEFAULT_GOAL := run -------------------------------------------------------------------------------- /servlets/wordpress/go.mod: -------------------------------------------------------------------------------- 1 | module wordpress 2 | 3 | go 1.22.1 4 | 5 | require github.com/extism/go-pdk v1.0.5 6 | -------------------------------------------------------------------------------- /servlets/wordpress/go.sum: -------------------------------------------------------------------------------- 1 | github.com/extism/go-pdk v1.0.5 h1:5d5yYkWBweBP84Z+H3DP5DsD0fwvf2anWXyypCXpSW8= 2 | github.com/extism/go-pdk v1.0.5/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 3 | -------------------------------------------------------------------------------- /servlets/wordpress/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | # Function to check if a command exists 5 | command_exists () { 6 | command -v "$1" >/dev/null 2>&1 7 | } 8 | 9 | # Function to compare version numbers for "less than" 10 | version_lt() { 11 | test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" = "$1" && test "$1" != "$2" 12 | } 13 | 14 | missing_deps=0 15 | 16 | # Check for Go 17 | if ! (command_exists go); then 18 | missing_deps=1 19 | echo "❌ Go (supported version between 1.20 - 1.24) is not installed." 20 | echo "" 21 | echo "To install Go, visit the official download page:" 22 | echo "👉 https://go.dev/dl/" 23 | echo "" 24 | echo "Or install it using a package manager:" 25 | echo "" 26 | echo "🔹 macOS (Homebrew):" 27 | echo " brew install go" 28 | echo "" 29 | echo "🔹 Ubuntu/Debian:" 30 | echo " sudo apt-get -y install golang-go" 31 | echo "" 32 | echo "🔹 Arch Linux:" 33 | echo " sudo pacman -S go" 34 | echo "" 35 | echo "🔹 Windows:" 36 | echo " scoop install go" 37 | echo "" 38 | fi 39 | 40 | # Check for the right version of Go, needed by TinyGo (supports go 1.20 - 1.24) 41 | if (command_exists go); then 42 | compat=0 43 | for v in `seq 20 24`; do 44 | if (go version | grep -q "go1.$v"); then 45 | compat=1 46 | fi 47 | done 48 | 49 | if [ $compat -eq 0 ]; then 50 | echo "❌ Supported Go version is not installed. Must be Go 1.20 - 1.24." 51 | echo "" 52 | fi 53 | fi 54 | 55 | ARCH=$(arch) 56 | 57 | # Check for TinyGo and its version 58 | if ! (command_exists tinygo); then 59 | missing_deps=1 60 | echo "❌ TinyGo is not installed." 61 | echo "" 62 | echo "To install TinyGo, visit the official download page:" 63 | echo "👉 https://tinygo.org/getting-started/install/" 64 | echo "" 65 | echo "Or install it using a package manager:" 66 | echo "" 67 | echo "🔹 macOS (Homebrew):" 68 | echo " brew tap tinygo-org/tools" 69 | echo " brew install tinygo" 70 | echo "" 71 | echo "🔹 Ubuntu/Debian:" 72 | echo " wget https://github.com/tinygo-org/tinygo/releases/download/v0.34.0/tinygo_0.34.0_$ARCH.deb" 73 | echo " sudo dpkg -i tinygo_0.34.0_$ARCH.deb" 74 | echo "" 75 | echo "🔹 Arch Linux:" 76 | echo " pacman -S extra/tinygo" 77 | echo "" 78 | echo "🔹 Windows:" 79 | echo " scoop install tinygo" 80 | echo "" 81 | else 82 | # Check TinyGo version 83 | tinygo_version=$(tinygo version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -n1) 84 | if version_lt "$tinygo_version" "0.34.0"; then 85 | missing_deps=1 86 | echo "❌ TinyGo version must be >= 0.34.0 (current version: $tinygo_version)" 87 | echo "Please update TinyGo to a newer version." 88 | echo "" 89 | fi 90 | fi 91 | 92 | go install golang.org/x/tools/cmd/goimports@latest 93 | -------------------------------------------------------------------------------- /servlets/wordpress/xtp.toml: -------------------------------------------------------------------------------- 1 | app_id = "app_01je4dgpcyfvgrz8f1ys3pbxas" 2 | 3 | # This is where 'xtp plugin push' expects to find the wasm file after the build script has run. 4 | bin = "dist/plugin.wasm" 5 | extension_point_id = "ext_01je4jj1tteaktf0zd0anm8854" 6 | name = "wordpress" 7 | 8 | [scripts] 9 | 10 | # xtp plugin build runs this script to generate the wasm file 11 | build = "mkdir -p dist && tinygo build -target wasi -o dist/plugin.wasm ." 12 | 13 | # xtp plugin init runs this script to format the plugin code 14 | format = "go fmt && go mod tidy && goimports -w main.go" 15 | 16 | # xtp plugin init runs this script before running the format script 17 | prepare = "sh prepare.sh && go get ./..." 18 | -------------------------------------------------------------------------------- /simulations/describe-output/.gitignore: -------------------------------------------------------------------------------- 1 | plugin.wasm 2 | -------------------------------------------------------------------------------- /simulations/describe-output/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2024, Extism 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /simulations/describe-output/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | tinygo build -target wasi -o plugin.wasm main.go 3 | 4 | test: 5 | extism call plugin.wasm greet --input "world" --wasi 6 | -------------------------------------------------------------------------------- /simulations/describe-output/README.md: -------------------------------------------------------------------------------- 1 | # Extism Go PDK Plugin 2 | 3 | See more documentation at https://github.com/extism/go-pdk and 4 | [join us on Discord](https://extism.org/discord) for more help. 5 | 6 | -------------------------------------------------------------------------------- /simulations/describe-output/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/extism/go-pdk-template 2 | 3 | go 1.22.1 4 | 5 | toolchain go1.23.3 6 | 7 | require github.com/extism/go-pdk v1.0.2 8 | 9 | require github.com/dylibso/xtp-test-go v0.0.2 // indirect 10 | -------------------------------------------------------------------------------- /simulations/describe-output/go.sum: -------------------------------------------------------------------------------- 1 | github.com/dylibso/xtp-test-go v0.0.2 h1:CW+Wl7JY/l30WA4nMZhZrwYC4cZbTvA+5cdJoPV3+Uc= 2 | github.com/dylibso/xtp-test-go v0.0.2/go.mod h1:YBGHZkaFOWNH3geVBx3/byJmd5XPa+Nz8XNwKahnT3Q= 3 | github.com/extism/go-pdk v1.0.2 h1:UB7oTW3tw2zoMlsUdBEDAAbhQg9OudzgNeyCwQYZ730= 4 | github.com/extism/go-pdk v1.0.2/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 5 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm -------------------------------------------------------------------------------- /test/testsuite/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/dylibso/mcp.run-servlets/test/testsuite 2 | 3 | go 1.23 4 | 5 | require ( 6 | github.com/dylibso/xtp-test-go v0.0.2 // indirect 7 | github.com/extism/go-pdk v1.0.2 // indirect 8 | ) 9 | -------------------------------------------------------------------------------- /test/testsuite/go.sum: -------------------------------------------------------------------------------- 1 | github.com/dylibso/xtp-test-go v0.0.2 h1:CW+Wl7JY/l30WA4nMZhZrwYC4cZbTvA+5cdJoPV3+Uc= 2 | github.com/dylibso/xtp-test-go v0.0.2/go.mod h1:YBGHZkaFOWNH3geVBx3/byJmd5XPa+Nz8XNwKahnT3Q= 3 | github.com/extism/go-pdk v1.0.2 h1:UB7oTW3tw2zoMlsUdBEDAAbhQg9OudzgNeyCwQYZ730= 4 | github.com/extism/go-pdk v1.0.2/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4= 5 | -------------------------------------------------------------------------------- /test/testsuite/pdk.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "encoding/json" 4 | 5 | type ListToolsResult struct { 6 | Tools []ToolDescription `json:"tools"` 7 | } 8 | 9 | type ToolDescription struct { 10 | Description string `json:"description"` 11 | InputSchema interface{} `json:"inputSchema"` 12 | Name string `json:"name"` 13 | } 14 | 15 | func parseToolListResult(data []byte) (ListToolsResult, error) { 16 | var res ListToolsResult 17 | err := json.Unmarshal(data, &res) 18 | return res, err 19 | } 20 | 21 | type CallToolRequest struct { 22 | Method *string `json:"method,omitempty"` 23 | Params Params `json:"params"` 24 | } 25 | 26 | func (c *CallToolRequest) Marshal() ([]byte, error) { 27 | return json.Marshal(c) 28 | } 29 | 30 | type Params struct { 31 | Arguments *map[string]interface{} `json:"arguments,omitempty"` 32 | Name string `json:"name"` 33 | } 34 | 35 | func parseCallToolResult(data []byte) (CallToolResult, error) { 36 | var res CallToolResult 37 | err := json.Unmarshal(data, &res) 38 | return res, err 39 | } 40 | 41 | type CallToolResult struct { 42 | Content []Content `json:"content"` 43 | IsError *bool `json:"isError,omitempty"` 44 | } 45 | 46 | type ContentType string 47 | 48 | const ( 49 | ContentTypeText ContentType = "text" 50 | ContentTypeImage ContentType = "image" 51 | ContentTypeResource ContentType = "resource" 52 | ) 53 | 54 | type Content struct { 55 | Data *string `json:"data,omitempty"` 56 | MimeType *string `json:"mimeType,omitempty"` 57 | Resource *ResourceContents `json:"resource,omitempty"` 58 | Text *string `json:"text,omitempty"` 59 | Type ContentType `json:"type"` 60 | } 61 | 62 | type ResourceContents struct { 63 | Blob *string `json:"blob,omitempty"` 64 | MimeType *string `json:"mimeType,omitempty"` 65 | Text *string `json:"text,omitempty"` 66 | Uri string `json:"uri"` 67 | } 68 | -------------------------------------------------------------------------------- /test/testsuite/xtp.toml: -------------------------------------------------------------------------------- 1 | bin = "dist/test.wasm" 2 | 3 | [scripts] 4 | build = "mkdir -p dist && tinygo build -o dist/test.wasm -target wasi ." --------------------------------------------------------------------------------