diff --git a/mcp-joke-server/README.md b/mcp-joke-server/README.md new file mode 100644 index 0000000..b2c3cc5 --- /dev/null +++ b/mcp-joke-server/README.md @@ -0,0 +1,27 @@ + +## About + +This project is a simple command-line tool that fetches a random joke from the Chuck Norris API. + +## Setup + +1. Clone this repository. +2. Install the necessary dependencies by running `npm install`. +3. Build the project by running `npm run build`. +4. Run the project with `npm start`. + +## Usage + +To get a joke, run the following command: + +```bash +node index.js +``` + +## Contributing + +Contributions are welcome. Please open an issue to discuss what you would like to change. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. \ No newline at end of file diff --git a/mcp-joke-server/apprunner.yaml b/mcp-joke-server/apprunner.yaml new file mode 100644 index 0000000..2ccd84f --- /dev/null +++ b/mcp-joke-server/apprunner.yaml @@ -0,0 +1,11 @@ +version: 1.0 +runtime: nodejs18 +build: + commands: + build: + - npm install + - npm run build +run: + command: npm start + network: + port: 8080 \ No newline at end of file diff --git a/mcp-joke-server/package.json b/mcp-joke-server/package.json new file mode 100644 index 0000000..92bc164 --- /dev/null +++ b/mcp-joke-server/package.json @@ -0,0 +1,42 @@ +{ + "name": "mcp-get-joke", + "version": "0.1.3", + "description": "MCP server for getting joke", + "license": "MIT", + "keywords": [ + "modelcontextprotocol", + "mcp", + "mcp-server", + "get-joke" + ], + "author": "", + "type": "module", + "engines": { + "node": ">=18" + }, + "bin": { + "mcp-get-joke": "dist/index.js" + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsc && shx chmod +x dist/*.js", + "watch": "tsc --watch", + "clean": "git clean -fdxn -e .env && read -p 'OK?' && git clean -fdx -e .env", + "do-publish": "npm run clean && npm install && npm publish --access=public", + "publish-dry-run": "npm run clean && npm install && npm publish --access=public --dry-run", + "start": "node dist/index.js" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.0.3", + "express": "^5.1.0", + "zod": "^3.24.1" + }, + "devDependencies": { + "@types/express": "^5.0.1", + "@types/node": "^22", + "shx": "^0.3.4", + "typescript": "^5.7.2" + } +} diff --git a/mcp-joke-server/src/index.ts b/mcp-joke-server/src/index.ts new file mode 100644 index 0000000..84f499d --- /dev/null +++ b/mcp-joke-server/src/index.ts @@ -0,0 +1,178 @@ +#!/usr/bin/env node + +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; +import { + CallToolRequestSchema, + ListToolsRequestSchema, +} from "@modelcontextprotocol/sdk/types.js"; +import { z } from "zod"; +import express, { Request, Response } from "express"; + +const PORT_NUMBER = 8080; + +// Zod schema for joke tool (no input required) +const JokeArgumentsSchema = z.object({}); + +// Create MCP Server +const server = new Server( + { + name: "joke-server", + version: "1.0.0", + }, + { + capabilities: { + tools: {}, + }, + } +); + +// Define available tools +server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [ + { + name: "get-joke", + description: "Get a random programming joke", + inputSchema: { + type: "object", + properties: {}, + required: [], + }, + }, + ], + }; +}); + +// Handle tool execution +server.setRequestHandler(CallToolRequestSchema, async (request) => { + const { name, arguments: args } = request.params; + + try { + if (name === "get-joke") { + JokeArgumentsSchema.parse(args); + + const jokeUrl = "https://official-joke-api.appspot.com/jokes/programming/random"; + const response = await fetch(jokeUrl); + const jokeData = await response.json(); + + const joke = jokeData?.[0]; + if (!joke) { + return { + content: [{ type: "text", text: "No joke found!" }], + }; + } + + return { + content: [ + { + type: "text", + text: `Here's a programming joke:\n\n${joke.setup}\n${joke.punchline}`, + }, + ], + }; + } else { + throw new Error(`Unknown tool: ${name}`); + } + } catch (error) { + if (error instanceof z.ZodError) { + throw new Error( + `Invalid arguments: ${error.errors + .map((e) => `${e.path.join(".")}: ${e.message}`) + .join(", ")}` + ); + } + throw error; + } +}); + +// Setup Express and SSE +const app = express(); +const transports: { [sessionId: string]: SSEServerTransport } = {}; +let messageHitCount = 0; + +app.get("/", (_: Request, res: Response) => { + res.send(` + + +
+Server is running correctly!
+ +