This guide walks you through setting up and running the simple MCP server example. Perfect for beginners who want to understand the basics without complexity.
- Deno 2.0+: Install Deno (tested with v2.5.x)
- Text Editor: VS Code, Vim, or your preferred editor
- Terminal/Command Line: Bash, Zsh, PowerShell, or similar
- Git: For version control and collaboration
- Beyond Better CLI: For testing MCP client integration
- Postman/curl: For HTTP transport testing
- Basic TypeScript/JavaScript understanding
- Command line familiarity
- Basic understanding of environment variables
# From the bb-mcp-server root directory
cd examples/1-simple
# Verify you're in the right place
ls -la
# You should see: main.ts, src/, README.md, etc.# Install required dependencies (Deno v2+)
deno add jsr:@std/assert@^1.0.0
deno add jsr:@std/testing@^1.0.0
deno add npm:zod@^3.22.4
# Verify dependencies are installed
cat deno.jsonc | grep -A 10 "imports"# Copy the environment template
cp .env.example .env
# View the configuration options
cat .env.exampleKey Configuration Options:
MCP_TRANSPORT: Choose 'stdio' (default) or 'http'LOG_LEVEL: Set to 'debug' for learning, 'info' for normal usePLUGINS_DISCOVERY_PATHS: Where to find plugins (default: ./src/plugins)
For Learning (recommended settings in .env):
# Enable debug logging to see what's happening
LOG_LEVEL=debug
LOG_FORMAT=text
# Use STDIO transport for MCP client integration
MCP_TRANSPORT=stdio
# Enable development mode
DEV_MODE=true# Explore the project structure
tree -I 'node_modules|.git'
# or
find . -type f -name '*.ts' -o -name '*.md' -o -name '*.json*' | sortKey Files:
main.ts: Entry point with minimal AppServer setupsrc/plugins/SimplePlugin.ts: Self-contained plugin with 3 tools.env.example: Configuration templatedeno.jsonc: Deno configuration and tasks
# Look at the main entry point
cat main.ts
# Examine the plugin structure
cat src/plugins/SimplePlugin.tsUnderstanding the Plugin:
- Plugin Definition: Metadata and initialization
- Tool Registration: Three utility tools
- Parameter Validation: Zod schemas for type safety
- Error Handling: Consistent error patterns
- Response Formatting: MCP-compliant responses
# Run with default settings
deno run --allow-all main.ts
# OR use the task shortcut
deno task start
# OR with debug logging
deno task start:debugWhat You'll See:
🔧 Initializing SimplePlugin...
✅ SimplePlugin initialized with 3 tools
🎉 Simple MCP Server started successfully!
📝 Available tools: current_datetime, get_system_info, validate_json
🔄 Transport: stdio
STDIO Mode: The server reads from stdin and writes to stdout, following the MCP protocol. It's ready for MCP client integration.
# Run with HTTP transport
MCP_TRANSPORT=http deno run --allow-all main.ts
# OR use the task shortcut
deno task start:httpWhat You'll See:
🔧 Initializing SimplePlugin...
✅ SimplePlugin initialized with 3 tools
🎉 Simple MCP Server started successfully!
📝 Available tools: current_datetime, get_system_info, validate_json
🔄 Transport: http
🌐 HTTP server listening on http://localhost:3000
HTTP Mode: The server runs as a web service. You can:
- View server status at:
http://localhost:3000 - Test tools via HTTP requests
- Use browser dev tools for debugging
-
Start the server in HTTP mode:
deno task start:http
-
Test the current_datetime tool:
curl -X POST http://localhost:3000/tools/current_datetime \ -H "Content-Type: application/json" \ -d '{}'
With parameters:
curl -X POST http://localhost:3000/tools/current_datetime \ -H "Content-Type: application/json" \ -d '{"format": "human", "timezone": "America/New_York"}'
-
Test the get_system_info tool:
curl -X POST http://localhost:3000/tools/get_system_info \ -H "Content-Type: application/json" \ -d '{"detail": "detailed", "includeMemory": true}'
-
Test the validate_json tool:
curl -X POST http://localhost:3000/tools/validate_json \ -H "Content-Type: application/json" \ -d '{"json_string": "{\"name\": \"test\", \"value\": 42}"}'
Test with invalid JSON:
curl -X POST http://localhost:3000/tools/validate_json \ -H "Content-Type: application/json" \ -d '{"json_string": "{invalid json}"}'
For STDIO testing, you'll need an MCP client. Here's a simple test:
# Start the server
deno run --allow-all main.ts
# In another terminal, send MCP protocol messages
echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' | deno run --allow-all main.ts# Run all tests
deno test --allow-all tests/
# Run specific tool tests
deno test --allow-all tests/tools/
# Run in watch mode for development
deno task test:watch# Set debug level in .env
LOG_LEVEL=debug
# Or run with debug flag
LOG_LEVEL=debug deno task startDebug Output Shows:
- Plugin discovery and loading
- Tool registration process
- Request/response details
- Error stack traces
- Performance metrics
# Error: Permission denied
# Solution: Use --allow-all flag
deno run --allow-all main.ts
# Or specific permissions
deno run --allow-net --allow-read --allow-write --allow-env main.ts# Error: Plugin discovery failed
# Check: Plugin discovery path in .env
PLUGINS_DISCOVERY_PATHS=./src/plugins
# Verify: Plugin file exists
ls -la src/plugins/SimplePlugin.ts
# Check: Plugin syntax
deno check src/plugins/SimplePlugin.ts# Error: Address already in use
# Solution: Use different port
HTTP_PORT=3001 deno task start:http
# Or find what's using the port
lsof -i :3000# Error: Parameter validation failed
# Check: Parameter names and types match Zod schema
# Example: current_datetime expects 'timezone', not 'tz'
# Debug: Enable debug logging to see validation details
LOG_LEVEL=debug# Error: Configuration not loaded
# Check: .env file exists and is readable
ls -la .env
cat .env
# Verify: Environment variables are loaded
echo $MCP_TRANSPORT- Enable debug logging:
LOG_LEVEL=debug - Check file permissions:
ls -la - Verify syntax:
deno check main.ts - Test configuration:
deno task start:debug - Isolate issues: Test one tool at a time
- Check logs: Look for error messages and stack traces
-
Test different datetime formats:
# ISO format (default) {"format": "iso"} # Human readable {"format": "human"} # Unix timestamp {"format": "unix"} # Different timezones {"timezone": "UTC"} {"timezone": "America/Los_Angeles"} {"timezone": "Europe/London"}
-
Explore system info levels:
# Basic info {"detail": "basic"} # Detailed info {"detail": "detailed", "includeMemory": true, "includeEnvironment": true}
-
Test JSON validation:
# Valid JSON {"json_string": "{\"valid\": true}"} # Invalid JSON {"json_string": "{invalid}"} # Complex nested JSON {"json_string": "{\"user\": {\"name\": \"test\", \"prefs\": [1,2,3]}}"}
-
Add a new tool (e.g., random number generator):
function registerRandomNumberTool(registry: ToolRegistry): void { const parameterSchema = z.object({ min: z.number().default(0), max: z.number().default(100), }); registry.registerTool('random_number', { title: 'Random Number Generator', description: 'Generate a random number within specified range', category: 'utility', tags: ['math', 'random'], inputSchema: parameterSchema, }, async (args) => { const params = parameterSchema.parse(args); const randomNum = Math.floor(Math.random() * (params.max - params.min + 1)) + params.min; return { content: [{ type: 'text', text: JSON.stringify({ number: randomNum, min: params.min, max: params.max }), }], }; }); }
-
Register the new tool in the plugin initialization
-
Test the new tool:
deno task start:http curl -X POST http://localhost:3000/tools/random_number \ -H "Content-Type: application/json" \ -d '{"min": 1, "max": 10}'
-
Try different log levels:
LOG_LEVEL=error(minimal logging)LOG_LEVEL=debug(verbose logging)LOG_FORMAT=json(structured logs)
-
Switch between transports:
- Test STDIO mode:
MCP_TRANSPORT=stdio - Test HTTP mode:
MCP_TRANSPORT=http - Compare behavior and use cases
- Test STDIO mode:
-
Plugin configuration:
- Try disabling autoload:
PLUGINS_AUTOLOAD=false - Experiment with allow/block lists
- Test different discovery paths
- Try disabling autoload:
After completing this example:
- Review the code: Understand every line in main.ts and SimplePlugin.ts
- Run all tests: See the testing patterns in action
- Modify tools: Add parameters, change behavior, create new tools
- Experiment: Try different configurations and observe behavior
- Master this example: Complete all activities and exercises
- Move to 2-plugin-workflows: Learn about multi-step processes
- Study 3-plugin-api-auth: Understand external API integration
- Explore 4-manual-deps: Gain complete infrastructure control
- Plugin Architecture: Self-contained, discoverable plugins
- Tool Development: Parameter validation, error handling, response formatting
- Configuration Management: Environment-driven, flexible configuration
- Testing Patterns: How to test tools and plugins effectively
- MCP Protocol: Understanding the underlying communication protocol
🎯 Success Criteria: You've successfully completed this example when you can:
- Run the server in both STDIO and HTTP modes
- Test all three tools with various parameters
- Debug issues using log output and error messages
- Modify the plugin to add new functionality
- Explain how plugin discovery and tool registration work
- Configure the server for different use cases
Ready for the next level? Proceed to 2-plugin-workflows to learn about multi-step processes!