├── .prettierrc ├── worker-configuration.d.ts ├── .editorconfig ├── test ├── tsconfig.json └── index.spec.ts ├── vitest.config.mts ├── package.json ├── tsconfig.json ├── src └── index.ts ├── .gitignore └── wrangler.toml /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 140, 3 | "singleQuote": true, 4 | "semi": true, 5 | "useTabs": true 6 | } 7 | -------------------------------------------------------------------------------- /worker-configuration.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by Wrangler by running `wrangler types` 2 | 3 | interface Env { 4 | SHARED_SECRET: string; 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.yml] 12 | indent_style = space 13 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["@cloudflare/workers-types/experimental", "@cloudflare/vitest-pool-workers"] 5 | }, 6 | "include": ["./**/*.ts", "../worker-configuration.d.ts"], 7 | "exclude": [] 8 | } 9 | -------------------------------------------------------------------------------- /vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config'; 2 | 3 | export default defineWorkersConfig({ 4 | test: { 5 | poolOptions: { 6 | workers: { 7 | wrangler: { configPath: './wrangler.toml' }, 8 | }, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fireproof-basic", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "workers-mcp docgen src/index.ts && wrangler deploy", 7 | "dev": "wrangler dev", 8 | "start": "wrangler dev", 9 | "test": "vitest", 10 | "cf-typegen": "wrangler types" 11 | }, 12 | "devDependencies": { 13 | "@cloudflare/vitest-pool-workers": "^0.5.2", 14 | "@cloudflare/workers-types": "^4.20241218.0", 15 | "typescript": "^5.5.2", 16 | "vitest": "2.1.8", 17 | "wrangler": "^3.60.3" 18 | }, 19 | "dependencies": { 20 | "workers-mcp": "^0.0.13" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/index.spec.ts: -------------------------------------------------------------------------------- 1 | // test/index.spec.ts 2 | import { env, createExecutionContext, waitOnExecutionContext, SELF } from 'cloudflare:test'; 3 | import { describe, it, expect } from 'vitest'; 4 | import worker from '../src/index'; 5 | 6 | // For now, you'll need to do something like this to get a correctly-typed 7 | // `Request` to pass to `worker.fetch()`. 8 | const IncomingRequest = Request; 9 | 10 | describe('Hello World worker', () => { 11 | it('responds with Hello World! (unit style)', async () => { 12 | const request = new IncomingRequest('http://example.com'); 13 | // Create an empty context to pass to `worker.fetch()`. 14 | const ctx = createExecutionContext(); 15 | const response = await worker.fetch(request, env, ctx); 16 | // Wait for all `Promise`s passed to `ctx.waitUntil()` to settle before running test assertions 17 | await waitOnExecutionContext(ctx); 18 | expect(await response.text()).toMatchInlineSnapshot(`"Hello World!"`); 19 | }); 20 | 21 | it('responds with Hello World! (integration style)', async () => { 22 | const response = await SELF.fetch('https://example.com'); 23 | expect(await response.text()).toMatchInlineSnapshot(`"Hello World!"`); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 6 | "target": "es2021", 7 | /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 8 | "lib": ["es2021"], 9 | /* Specify what JSX code is generated. */ 10 | "jsx": "react-jsx", 11 | 12 | /* Specify what module code is generated. */ 13 | "module": "es2022", 14 | /* Specify how TypeScript looks up a file from a given module specifier. */ 15 | "moduleResolution": "Bundler", 16 | /* Specify type package names to be included without being referenced in a source file. */ 17 | "types": [ 18 | "@cloudflare/workers-types/2023-07-01" 19 | ], 20 | /* Enable importing .json files */ 21 | "resolveJsonModule": true, 22 | 23 | /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 24 | "allowJs": true, 25 | /* Enable error reporting in type-checked JavaScript files. */ 26 | "checkJs": false, 27 | 28 | /* Disable emitting files from a compilation. */ 29 | "noEmit": true, 30 | 31 | /* Ensure that each file can be safely transpiled without relying on other imports. */ 32 | "isolatedModules": true, 33 | /* Allow 'import x from y' when a module doesn't have a default export. */ 34 | "allowSyntheticDefaultImports": true, 35 | /* Ensure that casing is correct in imports. */ 36 | "forceConsistentCasingInFileNames": true, 37 | 38 | /* Enable all strict type-checking options. */ 39 | "strict": true, 40 | 41 | /* Skip type checking all .d.ts files. */ 42 | "skipLibCheck": true 43 | }, 44 | "exclude": ["test"], 45 | "include": ["worker-configuration.d.ts", "src/**/*.ts"] 46 | } 47 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { WorkerEntrypoint } from 'cloudflare:workers' 2 | import { ProxyToSelf } from 'workers-mcp' 3 | 4 | const GREETING_STYLES = [ 5 | "witty", 6 | "poetic", 7 | "philosophical", 8 | "scientific", 9 | "dramatic" 10 | ]; 11 | 12 | const PROMPTS: Record = { 13 | "clever-hello": { 14 | name: "clever-hello", 15 | description: "Generate a clever greeting message", 16 | arguments: [ 17 | { 18 | name: "name", 19 | description: "Name of the person to greet", 20 | required: true 21 | }, 22 | { 23 | name: "style", 24 | description: `Style of greeting (${GREETING_STYLES.join(", ")})`, 25 | required: false 26 | } 27 | ] 28 | } 29 | }; 30 | 31 | export default class MyWorker extends WorkerEntrypoint { 32 | /** 33 | * List available prompts 34 | */ 35 | async listPrompts() { 36 | return { 37 | prompts: Object.values(PROMPTS) 38 | }; 39 | } 40 | 41 | /** 42 | * Get a specific prompt 43 | */ 44 | async getPrompt(name: string, args: any) { 45 | const prompt = PROMPTS[name]; 46 | if (!prompt) { 47 | throw new Error(`Prompt not found: ${name}`); 48 | } 49 | 50 | if (name === "clever-hello") { 51 | const style = args?.style || GREETING_STYLES[Math.floor(Math.random() * GREETING_STYLES.length)]; 52 | const userName = args?.name; 53 | 54 | if (!userName) { 55 | throw new Error("Name argument is required"); 56 | } 57 | 58 | const stylePrompts: Record = { 59 | witty: `Create a clever and witty greeting for ${userName} that includes a playful pun or wordplay.`, 60 | poetic: `Compose a brief poetic greeting for ${userName} that uses vivid imagery or metaphor.`, 61 | philosophical: `Generate a greeting for ${userName} that includes a thought-provoking philosophical observation.`, 62 | scientific: `Formulate a greeting for ${userName} that cleverly incorporates scientific concepts or terminology.`, 63 | dramatic: `Create a theatrical, over-the-top greeting for ${userName} with dramatic flair.` 64 | }; 65 | 66 | return { 67 | messages: [ 68 | { 69 | role: "user", 70 | content: { 71 | type: "text", 72 | text: stylePrompts[style] 73 | } 74 | } 75 | ] 76 | }; 77 | } 78 | 79 | throw new Error("Prompt implementation not found"); 80 | } 81 | 82 | /** 83 | * A warm, friendly greeting from your new Workers MCP server. 84 | * @param name {string} the name of the person we are greeting. 85 | * @return {string} the contents of our greeting. 86 | */ 87 | sayHello(name: string) { 88 | return `Hello from an MCP Worker, ${name}!` 89 | } 90 | 91 | /** 92 | * @ignore 93 | */ 94 | async fetch(request: Request): Promise { 95 | return new ProxyToSelf(this).fetch(request) 96 | } 97 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | 3 | logs 4 | _.log 5 | npm-debug.log_ 6 | yarn-debug.log* 7 | yarn-error.log* 8 | lerna-debug.log* 9 | .pnpm-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | 13 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 14 | 15 | # Runtime data 16 | 17 | pids 18 | _.pid 19 | _.seed 20 | \*.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | 28 | coverage 29 | \*.lcov 30 | 31 | # nyc test coverage 32 | 33 | .nyc_output 34 | 35 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 36 | 37 | .grunt 38 | 39 | # Bower dependency directory (https://bower.io/) 40 | 41 | bower_components 42 | 43 | # node-waf configuration 44 | 45 | .lock-wscript 46 | 47 | # Compiled binary addons (https://nodejs.org/api/addons.html) 48 | 49 | build/Release 50 | 51 | # Dependency directories 52 | 53 | node_modules/ 54 | jspm_packages/ 55 | 56 | # Snowpack dependency directory (https://snowpack.dev/) 57 | 58 | web_modules/ 59 | 60 | # TypeScript cache 61 | 62 | \*.tsbuildinfo 63 | 64 | # Optional npm cache directory 65 | 66 | .npm 67 | 68 | # Optional eslint cache 69 | 70 | .eslintcache 71 | 72 | # Optional stylelint cache 73 | 74 | .stylelintcache 75 | 76 | # Microbundle cache 77 | 78 | .rpt2_cache/ 79 | .rts2_cache_cjs/ 80 | .rts2_cache_es/ 81 | .rts2_cache_umd/ 82 | 83 | # Optional REPL history 84 | 85 | .node_repl_history 86 | 87 | # Output of 'npm pack' 88 | 89 | \*.tgz 90 | 91 | # Yarn Integrity file 92 | 93 | .yarn-integrity 94 | 95 | # dotenv environment variable files 96 | 97 | .env 98 | .env.development.local 99 | .env.test.local 100 | .env.production.local 101 | .env.local 102 | 103 | # parcel-bundler cache (https://parceljs.org/) 104 | 105 | .cache 106 | .parcel-cache 107 | 108 | # Next.js build output 109 | 110 | .next 111 | out 112 | 113 | # Nuxt.js build / generate output 114 | 115 | .nuxt 116 | dist 117 | 118 | # Gatsby files 119 | 120 | .cache/ 121 | 122 | # Comment in the public line in if your project uses Gatsby and not Next.js 123 | 124 | # https://nextjs.org/blog/next-9-1#public-directory-support 125 | 126 | # public 127 | 128 | # vuepress build output 129 | 130 | .vuepress/dist 131 | 132 | # vuepress v2.x temp and cache directory 133 | 134 | .temp 135 | .cache 136 | 137 | # Docusaurus cache and generated files 138 | 139 | .docusaurus 140 | 141 | # Serverless directories 142 | 143 | .serverless/ 144 | 145 | # FuseBox cache 146 | 147 | .fusebox/ 148 | 149 | # DynamoDB Local files 150 | 151 | .dynamodb/ 152 | 153 | # TernJS port file 154 | 155 | .tern-port 156 | 157 | # Stores VSCode versions used for testing VSCode extensions 158 | 159 | .vscode-test 160 | 161 | # yarn v2 162 | 163 | .yarn/cache 164 | .yarn/unplugged 165 | .yarn/build-state.yml 166 | .yarn/install-state.gz 167 | .pnp.\* 168 | 169 | # wrangler project 170 | 171 | .dev.vars 172 | .wrangler/ 173 | -------------------------------------------------------------------------------- /wrangler.toml: -------------------------------------------------------------------------------- 1 | #:schema node_modules/wrangler/config-schema.json 2 | name = "fireproof-basic" 3 | main = "src/index.ts" 4 | compatibility_date = "2024-12-18" 5 | compatibility_flags = ["nodejs_compat"] 6 | 7 | # Workers Logs 8 | # Docs: https://developers.cloudflare.com/workers/observability/logs/workers-logs/ 9 | # Configuration: https://developers.cloudflare.com/workers/observability/logs/workers-logs/#enable-workers-logs 10 | [observability] 11 | enabled = true 12 | 13 | # Automatically place your workloads in an optimal location to minimize latency. 14 | # If you are running back-end logic in a Worker, running it closer to your back-end infrastructure 15 | # rather than the end user may result in better performance. 16 | # Docs: https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement 17 | # [placement] 18 | # mode = "smart" 19 | 20 | # Variable bindings. These are arbitrary, plaintext strings (similar to environment variables) 21 | # Docs: 22 | # - https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables 23 | # Note: Use secrets to store sensitive data. 24 | # - https://developers.cloudflare.com/workers/configuration/secrets/ 25 | # [vars] 26 | # MY_VARIABLE = "production_value" 27 | 28 | # Bind the Workers AI model catalog. Run machine learning models, powered by serverless GPUs, on Cloudflare’s global network 29 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#workers-ai 30 | # [ai] 31 | # binding = "AI" 32 | 33 | # Bind an Analytics Engine dataset. Use Analytics Engine to write analytics within your Pages Function. 34 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#analytics-engine-datasets 35 | # [[analytics_engine_datasets]] 36 | # binding = "MY_DATASET" 37 | 38 | # Bind a headless browser instance running on Cloudflare's global network. 39 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#browser-rendering 40 | # [browser] 41 | # binding = "MY_BROWSER" 42 | 43 | # Bind a D1 database. D1 is Cloudflare’s native serverless SQL database. 44 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#d1-databases 45 | # [[d1_databases]] 46 | # binding = "MY_DB" 47 | # database_name = "my-database" 48 | # database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" 49 | 50 | # Bind a dispatch namespace. Use Workers for Platforms to deploy serverless functions programmatically on behalf of your customers. 51 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#dispatch-namespace-bindings-workers-for-platforms 52 | # [[dispatch_namespaces]] 53 | # binding = "MY_DISPATCHER" 54 | # namespace = "my-namespace" 55 | 56 | # Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model. 57 | # Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps. 58 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects 59 | # [[durable_objects.bindings]] 60 | # name = "MY_DURABLE_OBJECT" 61 | # class_name = "MyDurableObject" 62 | 63 | # Durable Object migrations. 64 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#migrations 65 | # [[migrations]] 66 | # tag = "v1" 67 | # new_classes = ["MyDurableObject"] 68 | 69 | # Bind a Hyperdrive configuration. Use to accelerate access to your existing databases from Cloudflare Workers. 70 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#hyperdrive 71 | # [[hyperdrive]] 72 | # binding = "MY_HYPERDRIVE" 73 | # id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 74 | 75 | # Bind a KV Namespace. Use KV as persistent storage for small key-value pairs. 76 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#kv-namespaces 77 | # [[kv_namespaces]] 78 | # binding = "MY_KV_NAMESPACE" 79 | # id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 80 | 81 | # Bind an mTLS certificate. Use to present a client certificate when communicating with another service. 82 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#mtls-certificates 83 | # [[mtls_certificates]] 84 | # binding = "MY_CERTIFICATE" 85 | # certificate_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" 86 | 87 | # Bind a Queue producer. Use this binding to schedule an arbitrary task that may be processed later by a Queue consumer. 88 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#queues 89 | # [[queues.producers]] 90 | # binding = "MY_QUEUE" 91 | # queue = "my-queue" 92 | 93 | # Bind a Queue consumer. Queue Consumers can retrieve tasks scheduled by Producers to act on them. 94 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#queues 95 | # [[queues.consumers]] 96 | # queue = "my-queue" 97 | 98 | # Bind an R2 Bucket. Use R2 to store arbitrarily large blobs of data, such as files. 99 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#r2-buckets 100 | # [[r2_buckets]] 101 | # binding = "MY_BUCKET" 102 | # bucket_name = "my-bucket" 103 | 104 | # Bind another Worker service. Use this binding to call another Worker without network overhead. 105 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#service-bindings 106 | # [[services]] 107 | # binding = "MY_SERVICE" 108 | # service = "my-service" 109 | 110 | # Bind a Vectorize index. Use to store and query vector embeddings for semantic search, classification and other vector search use-cases. 111 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#vectorize-indexes 112 | # [[vectorize]] 113 | # binding = "MY_INDEX" 114 | # index_name = "my-index" 115 | --------------------------------------------------------------------------------