This project demonstrates a Model Context Protocol (MCP) server and client for weather data, built with Node.js/TypeScript. It provides a clean, modular implementation of the MCP protocol with proper error handling and type safety.
- MCP Server: Provides weather tools via the MCP protocol over stdio.
get-alerts: Get active weather alerts for a US state (e.g.,CA,NY).get-forecast: Get weather forecast for a given latitude and longitude.- Input validation with Zod.
- Integration with the US National Weather Service (NWS) API.
- MCP Client: A robust TypeScript client that:
- Manages server lifecycle
- Provides type-safe tool execution
- Handles errors gracefully
- Supports async/await operations
- Configurable through a clean interface
- In-memory caching with TTL support
.
├── server/ # MCP Server implementation
│ ├── src/
│ │ ├── domain/ # Domain models and interfaces
│ │ ├── infrastructure/# External API services (NWS)
│ │ ├── application/ # Business logic and data formatting
│ │ ├── interface/ # MCP tool controllers and validation
│ │ └── main.ts # Server entry point
│ └── build/ # Compiled JavaScript
│
├── client/ # MCP Client implementation
│ ├── src/
│ │ └── client.ts # Main client implementation
│ └── build/ # Compiled JavaScript
│
├── LICENSE # GNU GPL v3.0
├── CONTRIBUTING.md # Contribution guidelines
└── CHANGELOG.md # Project changelog
Clone the repository and install dependencies for both server and client:
git clone <REPOSITORY_URL>
cd server
npm install
npm run build
cd ../client
npm install
npm run buildAfter building, you can run the server directly:
cd server
npm startThe client can be used in two ways:
- As a standalone application:
cd client
npm start- As a library in your own project:
import { MCPClient } from './src/client';
const client = new MCPClient({
// Optional configuration
timeout: 30000,
clientInfo: {
name: 'my-app',
version: '1.0.0'
},
cacheConfig: {
enabled: true,
ttl: 300000
}
});
try {
// Execute a tool
const result = await client.executeTool('get-alerts', { state: 'CA' });
if (result.success) {
console.log('Weather alerts:', result.data);
} else {
console.error('Error:', result.error);
}
} catch (error) {
console.error('Failed to execute tool:', error);
} finally {
client.cleanup();
}The MCPClient constructor accepts an optional configuration object:
interface ClientConfig {
serverPath?: string; // Path to the server executable
timeout?: number; // Timeout in milliseconds (default: 30000)
clientInfo?: { // Client information
name: string;
version: string;
};
cacheConfig?: { // Caching configuration
enabled: boolean; // Enable/disable caching
ttl: number; // Time-to-live in milliseconds (default: 5 minutes)
};
}cd server
npm run build # Build the server
npm start # Run the servercd client
npm run dev # Run in development mode with ts-node
npm run build # Build the client
npm start # Run the built clientPlease read CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
See CHANGELOG.md for a list of changes and improvements.
- Uses @modelcontextprotocol/sdk
- Input validation with Zod
- Weather data from the US National Weather Service (NWS) API
The client includes an in-memory caching layer that can be enabled through the cacheConfig option. When enabled:
- Tool execution results are cached based on the tool name and parameters
- Cache entries expire after the configured TTL (default: 5 minutes)
- Cache is automatically cleared when the client is cleaned up
- Cache keys are generated consistently regardless of parameter order
Example with caching:
const client = new MCPClient({
cacheConfig: {
enabled: true,
ttl: 300000 // 5 minutes
}
});
// First call will hit the server
const result1 = await client.executeTool('get-forecast', {
latitude: 37.7749,
longitude: -122.4194
});
// Subsequent calls with same parameters within TTL will use cache
const result2 = await client.executeTool('get-forecast', {
latitude: 37.7749,
longitude: -122.4194
}); // Returns cached result
// Different parameters will still hit the server
const result3 = await client.executeTool('get-forecast', {
latitude: 34.0522,
longitude: -118.2437
}); // Hits serverRetrieves weather alerts for a specified state.
Parameters:
state(string): Two-letter state code (e.g., 'CA', 'NY')
Retrieves weather forecast for specified coordinates.
Parameters:
latitude(number): Latitude coordinatelongitude(number): Longitude coordinate
The client provides structured error responses:
interface ErrorResponse {
success: false;
error: {
code: string;
message: string;
details?: string;
};
}