Pistachio MCP Server
A remote MCP (Model Context Protocol) server built with Node.js and TypeScript. This server demonstrates how to implement tool calls and prompt templates using the official @modelcontextprotocol/sdk with HTTP transport for remote access.
Features
- Tool Calls: Register and handle tools that can be invoked by AI models
- Prompt Templates: Create reusable prompt templates with argument support
- TypeScript: Full type safety with Zod schema validation
- Remote HTTP Transport: Streamable HTTP transport for remote MCP server access
- CORS Support: Built-in CORS handling for web-based clients
Installation
- Install dependencies:
npm install
- Build the project (optional, for production):
npm run build
Usage
Development Mode
Run the server in development mode with hot reload:
npm run dev
The server will start on port 3000 by default (or the port specified by the PORT environment variable).
Production Mode
Build and run the compiled server:
npm run build
node dist/index.js
Direct Execution
Run TypeScript directly without building:
npm start
Environment Variables
PORT: Port number for the HTTP server (default: 3000)
Example:
PORT=8080 npm start
Remote Access
The server exposes an MCP endpoint at /message that accepts:
- GET: Establish SSE stream for receiving messages
- POST: Send MCP requests
- OPTIONS: CORS preflight requests
The server listens on 0.0.0.0 by default, making it accessible from remote clients.
Example endpoint: http://localhost:3000/message
Project Structure
pistachio-mcp/
├── src/
│ ├── index.ts # Main server entry point
│ ├── tools/ # Tool implementations
│ │ └── example.ts # Example calculator tool
│ └── prompts/ # Prompt templates
│ └── example.ts # Example greeting prompt
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
└── README.md # This file
Adding New Tools
- Create a new file in
src/tools/(e.g.,src/tools/my-tool.ts):
import { z } from "zod";
export const myTool = {
name: "my_tool_name",
description: "Description of what the tool does",
inputSchema: z.object({
// Define your input schema using Zod
param1: z.string().describe("Parameter description"),
}),
handler: async (args: { param1: string }) => {
// Implement your tool logic
return { result: "tool output" };
},
};
- Import and register the tool in
src/index.ts:
import { myTool } from "./tools/my-tool.js";
// Add to tools/list handler
server.setRequestHandler("tools/list", async () => {
return {
tools: [
// ... existing tools
{
name: myTool.name,
description: myTool.description,
inputSchema: myTool.inputSchema,
},
],
};
});
// Add to tools/call handler
server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;
// ... existing tool handlers
if (name === myTool.name) {
const result = await myTool.handler(args as any);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
});
Adding New Prompt Templates
- Create a new file in
src/prompts/(e.g.,src/prompts/my-prompt.ts):
import { z } from "zod";
export const myPrompt = {
name: "my_prompt_name",
description: "Description of the prompt template",
arguments: z.object({
// Define your prompt arguments using Zod
arg1: z.string().describe("Argument description"),
}),
handler: async (args: { arg1: string }) => {
// Generate and return prompt messages
return [
{
role: "user" as const,
content: {
type: "text" as const,
text: `Your prompt text with ${args.arg1}`,
},
},
];
},
};
- Import and register the prompt in
src/index.ts:
import { myPrompt } from "./prompts/my-prompt.js";
// Add to prompts/list handler
server.setRequestHandler("prompts/list", async () => {
return {
prompts: [
// ... existing prompts
{
name: myPrompt.name,
description: myPrompt.description,
arguments: myPrompt.arguments,
},
],
};
});
// Add to prompts/get handler
server.setRequestHandler("prompts/get", async (request) => {
const { name, arguments: args } = request.params;
// ... existing prompt handlers
if (name === myPrompt.name) {
const messages = await myPrompt.handler(args as any);
return { messages };
}
});
Example Tools
Calculator Tool
The example calculator tool (example_calculator) performs basic arithmetic operations:
- Operations: add, subtract, multiply, divide
- Input: Two numbers and an operation
- Output: Calculation result
Example Prompts
Greeting Prompt
The example greeting prompt (greeting) generates personalized greetings:
- Arguments: name (required), language (optional: en, es, fr, de)
- Output: Localized greeting message
Remote MCP Server
This server uses the Streamable HTTP transport protocol, which allows MCP clients to connect remotely over HTTP. The transport supports:
- Server-Sent Events (SSE) for streaming responses
- Standard HTTP POST requests for sending messages
- Session management for stateful connections
- CORS support for web-based clients
Connecting from MCP Clients
To connect to this remote server from an MCP client, configure it with:
- URL:
http://your-server:3000/message - Transport: Streamable HTTP
Dependencies
@modelcontextprotocol/sdk: Official MCP SDK for Node.jszod: Schema validation library (required peer dependency)typescript: TypeScript compilertsx: TypeScript execution runtime
License
MIT