Initial commit
This commit is contained in:
222
scripts/init-mcp-server.sh
Executable file
222
scripts/init-mcp-server.sh
Executable file
@@ -0,0 +1,222 @@
|
||||
#!/bin/bash
|
||||
# Initialize a new TypeScript MCP server project
|
||||
# Usage: ./init-mcp-server.sh [project-name]
|
||||
|
||||
set -e
|
||||
|
||||
PROJECT_NAME="${1:-mcp-server}"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
TEMPLATES_DIR="$(dirname "$SCRIPT_DIR")/templates"
|
||||
|
||||
echo "==================================="
|
||||
echo "TypeScript MCP Server Setup"
|
||||
echo "==================================="
|
||||
echo ""
|
||||
|
||||
# Create project directory
|
||||
if [ -d "$PROJECT_NAME" ]; then
|
||||
echo "❌ Directory '$PROJECT_NAME' already exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$PROJECT_NAME"
|
||||
cd "$PROJECT_NAME"
|
||||
|
||||
echo "📁 Created project directory: $PROJECT_NAME"
|
||||
echo ""
|
||||
|
||||
# Ask for template choice
|
||||
echo "Select MCP server template:"
|
||||
echo "1) Basic (simple tools)"
|
||||
echo "2) Tool Server (multiple API integrations)"
|
||||
echo "3) Resource Server (data exposure)"
|
||||
echo "4) Full Server (tools + resources + prompts)"
|
||||
echo "5) Authenticated Server (with API key auth)"
|
||||
read -p "Choice [1-5]: " choice
|
||||
|
||||
case $choice in
|
||||
1) TEMPLATE="basic-mcp-server.ts" ;;
|
||||
2) TEMPLATE="tool-server.ts" ;;
|
||||
3) TEMPLATE="resource-server.ts" ;;
|
||||
4) TEMPLATE="full-server.ts" ;;
|
||||
5) TEMPLATE="authenticated-server.ts" ;;
|
||||
*) echo "Invalid choice"; exit 1 ;;
|
||||
esac
|
||||
|
||||
echo "✅ Selected: $TEMPLATE"
|
||||
echo ""
|
||||
|
||||
# Initialize package.json
|
||||
echo "📦 Creating package.json..."
|
||||
cat > package.json << 'EOF'
|
||||
{
|
||||
"name": "mcp-server",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "wrangler dev",
|
||||
"build": "tsc && vite build",
|
||||
"deploy": "wrangler deploy",
|
||||
"test": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.20.2",
|
||||
"@cloudflare/workers-types": "^4.20251011.0",
|
||||
"hono": "^4.10.1",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/vitest-pool-workers": "^0.5.29",
|
||||
"typescript": "^5.7.0",
|
||||
"vitest": "^3.0.0",
|
||||
"wrangler": "^4.43.0"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Update project name
|
||||
sed -i "s/\"name\": \"mcp-server\"/\"name\": \"$PROJECT_NAME\"/" package.json
|
||||
|
||||
# Create source directory
|
||||
mkdir -p src
|
||||
|
||||
# Copy template
|
||||
echo "📄 Copying template..."
|
||||
cp "$TEMPLATES_DIR/$TEMPLATE" src/index.ts
|
||||
|
||||
# Copy wrangler config
|
||||
echo "⚙️ Creating wrangler.jsonc..."
|
||||
cp "$TEMPLATES_DIR/wrangler.jsonc" wrangler.jsonc
|
||||
sed -i "s/\"name\": \"my-mcp-server\"/\"name\": \"$PROJECT_NAME\"/" wrangler.jsonc
|
||||
|
||||
# Create tsconfig.json
|
||||
echo "🔧 Creating tsconfig.json..."
|
||||
cat > tsconfig.json << 'EOF'
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"lib": ["ES2022"],
|
||||
"moduleResolution": "bundler",
|
||||
"types": ["@cloudflare/workers-types"],
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create .gitignore
|
||||
echo "🙈 Creating .gitignore..."
|
||||
cat > .gitignore << 'EOF'
|
||||
node_modules/
|
||||
dist/
|
||||
.wrangler/
|
||||
.dev.vars
|
||||
*.log
|
||||
.DS_Store
|
||||
EOF
|
||||
|
||||
# Create .dev.vars template
|
||||
echo "🔐 Creating .dev.vars (for local secrets)..."
|
||||
cat > .dev.vars << 'EOF'
|
||||
# Local development secrets
|
||||
# NEVER commit this file to git!
|
||||
|
||||
# Example:
|
||||
# WEATHER_API_KEY=your-key-here
|
||||
# DATABASE_URL=postgres://...
|
||||
EOF
|
||||
|
||||
# Create README
|
||||
echo "📝 Creating README.md..."
|
||||
cat > README.md << EOF
|
||||
# $PROJECT_NAME
|
||||
|
||||
TypeScript MCP server built with the official MCP SDK.
|
||||
|
||||
## Setup
|
||||
|
||||
\`\`\`bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Run locally
|
||||
npm run dev
|
||||
|
||||
# Deploy to Cloudflare Workers
|
||||
npm run deploy
|
||||
\`\`\`
|
||||
|
||||
## Testing
|
||||
|
||||
\`\`\`bash
|
||||
# Start server
|
||||
npm run dev
|
||||
|
||||
# In another terminal, test with MCP Inspector
|
||||
npx @modelcontextprotocol/inspector
|
||||
|
||||
# Connect to: http://localhost:8787/mcp
|
||||
\`\`\`
|
||||
|
||||
## Endpoints
|
||||
|
||||
- \`GET /\` - Server info
|
||||
- \`POST /mcp\` - MCP protocol endpoint
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Add secrets to Cloudflare Workers:
|
||||
|
||||
\`\`\`bash
|
||||
wrangler secret put API_KEY
|
||||
\`\`\`
|
||||
|
||||
For local development, add to \`.dev.vars\`:
|
||||
|
||||
\`\`\`
|
||||
API_KEY=your-key
|
||||
\`\`\`
|
||||
|
||||
## Deployment
|
||||
|
||||
\`\`\`bash
|
||||
# Build
|
||||
npm run build
|
||||
|
||||
# Deploy
|
||||
npm run deploy
|
||||
|
||||
# View logs
|
||||
wrangler tail
|
||||
\`\`\`
|
||||
|
||||
## Documentation
|
||||
|
||||
- MCP Specification: https://spec.modelcontextprotocol.io/
|
||||
- TypeScript SDK: https://github.com/modelcontextprotocol/typescript-sdk
|
||||
- Cloudflare Workers: https://developers.cloudflare.com/workers/
|
||||
EOF
|
||||
|
||||
# Install dependencies
|
||||
echo ""
|
||||
echo "📥 Installing dependencies..."
|
||||
npm install
|
||||
|
||||
echo ""
|
||||
echo "✅ Setup complete!"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " cd $PROJECT_NAME"
|
||||
echo " npm run dev # Start local server"
|
||||
echo " npm run deploy # Deploy to Cloudflare"
|
||||
echo ""
|
||||
echo "Test with MCP Inspector:"
|
||||
echo " npx @modelcontextprotocol/inspector"
|
||||
echo " Connect to: http://localhost:8787/mcp"
|
||||
echo ""
|
||||
154
scripts/test-mcp-connection.sh
Executable file
154
scripts/test-mcp-connection.sh
Executable file
@@ -0,0 +1,154 @@
|
||||
#!/bin/bash
|
||||
# Test MCP server connectivity and validate endpoints
|
||||
# Usage: ./test-mcp-connection.sh [URL] [API_KEY]
|
||||
|
||||
set -e
|
||||
|
||||
# Default to local dev server
|
||||
URL="${1:-http://localhost:8787/mcp}"
|
||||
API_KEY="${2:-}"
|
||||
|
||||
echo "======================================"
|
||||
echo "MCP Server Connection Test"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
echo "Testing: $URL"
|
||||
echo ""
|
||||
|
||||
# Build headers
|
||||
if [ -n "$API_KEY" ]; then
|
||||
HEADERS=(-H "Content-Type: application/json" -H "Authorization: Bearer $API_KEY")
|
||||
echo "🔐 Using API key authentication"
|
||||
else
|
||||
HEADERS=(-H "Content-Type: application/json")
|
||||
echo "⚠️ No API key provided (testing without auth)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 1: List tools
|
||||
echo "1️⃣ Testing tools/list..."
|
||||
TOOLS_RESPONSE=$(curl -s -X POST "$URL" \
|
||||
"${HEADERS[@]}" \
|
||||
-d '{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "tools/list",
|
||||
"id": 1
|
||||
}')
|
||||
|
||||
if echo "$TOOLS_RESPONSE" | jq -e '.result.tools' > /dev/null 2>&1; then
|
||||
TOOL_COUNT=$(echo "$TOOLS_RESPONSE" | jq '.result.tools | length')
|
||||
echo "✅ Success: Found $TOOL_COUNT tool(s)"
|
||||
echo "$TOOLS_RESPONSE" | jq '.result.tools[] | {name: .name, description: .description}'
|
||||
else
|
||||
echo "❌ Failed to list tools"
|
||||
echo "Response: $TOOLS_RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 2: List resources
|
||||
echo "2️⃣ Testing resources/list..."
|
||||
RESOURCES_RESPONSE=$(curl -s -X POST "$URL" \
|
||||
"${HEADERS[@]}" \
|
||||
-d '{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "resources/list",
|
||||
"id": 2
|
||||
}')
|
||||
|
||||
if echo "$RESOURCES_RESPONSE" | jq -e '.result.resources' > /dev/null 2>&1; then
|
||||
RESOURCE_COUNT=$(echo "$RESOURCES_RESPONSE" | jq '.result.resources | length')
|
||||
echo "✅ Success: Found $RESOURCE_COUNT resource(s)"
|
||||
echo "$RESOURCES_RESPONSE" | jq '.result.resources[] | {uri: .uri, name: .name}'
|
||||
elif echo "$RESOURCES_RESPONSE" | jq -e '.error' > /dev/null 2>&1; then
|
||||
echo "⚠️ No resources endpoint (some templates don't have resources)"
|
||||
else
|
||||
echo "❌ Failed to list resources"
|
||||
echo "Response: $RESOURCES_RESPONSE"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 3: List prompts
|
||||
echo "3️⃣ Testing prompts/list..."
|
||||
PROMPTS_RESPONSE=$(curl -s -X POST "$URL" \
|
||||
"${HEADERS[@]}" \
|
||||
-d '{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "prompts/list",
|
||||
"id": 3
|
||||
}')
|
||||
|
||||
if echo "$PROMPTS_RESPONSE" | jq -e '.result.prompts' > /dev/null 2>&1; then
|
||||
PROMPT_COUNT=$(echo "$PROMPTS_RESPONSE" | jq '.result.prompts | length')
|
||||
echo "✅ Success: Found $PROMPT_COUNT prompt(s)"
|
||||
echo "$PROMPTS_RESPONSE" | jq '.result.prompts[] | {name: .name, description: .description}'
|
||||
elif echo "$PROMPTS_RESPONSE" | jq -e '.error' > /dev/null 2>&1; then
|
||||
echo "⚠️ No prompts endpoint (some templates don't have prompts)"
|
||||
else
|
||||
echo "❌ Failed to list prompts"
|
||||
echo "Response: $PROMPTS_RESPONSE"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 4: Call first tool (if available)
|
||||
FIRST_TOOL=$(echo "$TOOLS_RESPONSE" | jq -r '.result.tools[0].name // empty')
|
||||
|
||||
if [ -n "$FIRST_TOOL" ]; then
|
||||
echo "4️⃣ Testing tool call: $FIRST_TOOL..."
|
||||
|
||||
# Determine arguments based on tool
|
||||
case "$FIRST_TOOL" in
|
||||
"echo")
|
||||
ARGS='{"text": "Hello, MCP!"}'
|
||||
;;
|
||||
"add")
|
||||
ARGS='{"a": 5, "b": 3}'
|
||||
;;
|
||||
"get-status")
|
||||
ARGS='{}'
|
||||
;;
|
||||
*)
|
||||
echo "⚠️ Unknown tool, skipping test"
|
||||
ARGS=""
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -n "$ARGS" ]; then
|
||||
CALL_RESPONSE=$(curl -s -X POST "$URL" \
|
||||
"${HEADERS[@]}" \
|
||||
-d "{
|
||||
\"jsonrpc\": \"2.0\",
|
||||
\"method\": \"tools/call\",
|
||||
\"params\": {
|
||||
\"name\": \"$FIRST_TOOL\",
|
||||
\"arguments\": $ARGS
|
||||
},
|
||||
\"id\": 4
|
||||
}")
|
||||
|
||||
if echo "$CALL_RESPONSE" | jq -e '.result' > /dev/null 2>&1; then
|
||||
echo "✅ Success: Tool executed"
|
||||
echo "$CALL_RESPONSE" | jq '.result'
|
||||
else
|
||||
echo "❌ Failed to call tool"
|
||||
echo "Response: $CALL_RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "4️⃣ No tools to test"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Summary
|
||||
echo "======================================"
|
||||
echo "✅ Connection test complete!"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
echo "Summary:"
|
||||
echo " Tools: $TOOL_COUNT"
|
||||
echo " Resources: ${RESOURCE_COUNT:-0}"
|
||||
echo " Prompts: ${PROMPT_COUNT:-0}"
|
||||
echo ""
|
||||
echo "Server is responding correctly! 🎉"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user