@nuwa-ai/mcp-server-proxy
v0.6.9
Published
MCP Server Proxy with DIDAuth support for Nuwa ecosystem
Readme
MCP Server Proxy
MCP Server Proxy is a streamlined MCP service that provides upstream forwarding and payment capabilities. It uses FastMcpStarter to provide a single /mcp endpoint with JSON-RPC over HTTP/SSE.
This implementation follows the V2 design (see PROPOSAL_V2_SINGLE_UPSTREAM_PAYMENT.md) which simplifies the architecture to focus on per-call payment and tool execution.
🚀 Quick Start (NPM Package)
The easiest way to get started is using the published npm package:
# Install globally
npm install -g @nuwa-ai/mcp-server-proxy
# Create a simple config file
echo "port: 8088
endpoint: /mcp
serviceId: my-service" > config.yaml
# Set your service key
export SERVICE_KEY=your_service_key_here
# Start the server
mcp-server-proxy --config config.yamlOr use without installation:
# Run directly with npx
npx @nuwa-ai/mcp-server-proxy --port 8088 --service-id my-serviceFeatures
- Single MCP Endpoint: Provides
/mcpendpoint with JSON-RPC over streamable HTTP - Upstream Forwarding: Automatically forwards all upstream tools to clients
- Per-call Payment: Integrated with Nuwa Payment Kit for tool-level billing
- Pure Proxy: Clean architecture focused on forwarding and payment, no built-in test tools
Quick Start
1. Installation
You have two options to use MCP Server Proxy:
Option A: Use Published NPM Package (Recommended)
Install the published package globally or locally:
# Install globally (recommended for easy CLI usage)
npm install -g @nuwa-ai/mcp-server-proxy
# Or install locally in your project
npm install @nuwa-ai/mcp-server-proxyThen you can run it directly:
# Run with global installation
mcp-server-proxy --help
# Run with local installation
npx @nuwa-ai/mcp-server-proxy --helpOption B: Build from Source
If you want to modify the source code or contribute to development:
cd nuwa-services/mcp-server-proxy
pnpm install2. Configuration
Create a config.yaml file for your proxy configuration. You can start with the provided example:
# Copy the example configuration
curl -o config.yaml https://raw.githubusercontent.com/rooch-network/nuwa/main/nuwa-services/mcp-server-proxy/config.yaml.example
# Or if you have the source code:
cp config.yaml.example config.yamlThen edit config.yaml to match your needs. Here are some examples:
Example 1: Basic Configuration (No Upstream)
# Server settings
port: 8088
endpoint: "/mcp"
# Payment configuration
serviceId: "my-mcp-service"
network: "test"
rpcUrl: "https://test-seed.rooch.network:443"
defaultPricePicoUSD: "100000000" # 0.0001 USD - Default price for all toolsExample 2: With HTTP Upstream
# Server settings
port: 8088
endpoint: "/mcp"
# Upstream MCP server
upstream:
type: "httpStream"
url: "https://api.example.com/mcp?key=${API_KEY}"
# Payment configuration
serviceId: "my-mcp-service"
network: "test"
rpcUrl: "${ROOCH_RPC_URL}"
defaultPricePicoUSD: "100000000" # 0.0001 USD - Default price for all tools
# Tool pricing configuration (optional)
register:
tools:
- name: "example.tool"
pricePicoUSD: "200000000" # 0.0002 USD - Explicit price, overrides default
- name: "free.tool"
pricePicoUSD: "0" # Free toolExample 3: With Stdio Upstream
# Server settings
port: 8088
endpoint: "/mcp"
# Stdio upstream MCP server
upstream:
type: "stdio"
command: ["npx", "@example/mcp-server"]
env:
API_KEY: "${API_KEY}"
# stderr: "inherit" # Default: child process errors are visible (recommended for debugging)
# stderr: "ignore" # Suppress child process error output
# stderr: "pipe" # Capture stderr (advanced usage)
# Payment configuration
serviceId: "my-mcp-service"
network: "test"
defaultPricePicoUSD: "100000000"Note:
- Stdio upstream automatically inherits all environment variables from the parent process, then merges any custom environment variables specified in the
envsection. This ensures that child processes have access to system variables likePATH,HOME, etc., as well as any custom variables you specify. - The
stderroption controls how child process error output is handled:inherit(default): Error messages from the child process are displayed in the proxy's console, making debugging easierignore: Suppresses error output from the child processpipe: Captures stderr for advanced processing (not commonly needed)
Important: In stdio mode, the child process uses:
- stdin/stdout: For MCP JSON-RPC protocol communication (handled automatically by the SDK)
- stderr: For debug output, error messages, and logging (visible in proxy console with
stderr: inherit)
Never write non-MCP content to stdout in your MCP server, as this will break protocol communication. Use console.error() for debug output instead of console.log().
Set any required environment variables:
export API_KEY=your_secret_key
export ROOCH_RPC_URL=https://test-seed.rooch.network:4433. Running the Server
Using NPM Package
If you installed via npm, you can run the server directly:
# Show help and available options
mcp-server-proxy --help
# Start with default configuration (looks for config.yaml in current directory)
mcp-server-proxy
# Start with custom port and debug
mcp-server-proxy --port 3000 --debug
# Start with custom config file
mcp-server-proxy --config ./custom-config.yaml
# Start with payment configuration
mcp-server-proxy --service-id my-service --network test --default-price-pico-usd 100000000
# Use with npx (no global installation needed)
npx @nuwa-ai/mcp-server-proxy --config ./my-config.yamlFrom Source Code
If you're building from source:
Development mode (with hot-reloading):
pnpm devProduction mode:
# 1. Build the project pnpm build # 2. Start the server pnpm startWith command line arguments:
# Show help and available options pnpm run help # Start with custom port and debug node dist/index.js --port 3000 --debug # Start with custom config file node dist/index.js --config ./custom-config.yaml # Start with payment configuration node dist/index.js --service-id my-service --network test --default-price-pico-usd 100000000
Configuration
The server supports multiple configuration methods with the following priority (high to low):
- Command line arguments (highest priority)
- Environment variables
- Configuration file
- Default values (lowest priority)
Command Line Options
Options:
-p, --port <number> Server port (default: 8088)
-e, --endpoint <string> MCP endpoint path (default: /mcp)
-c, --config <path> Config file path (default: config.yaml)
--service-id <string> Payment service ID
-n, --network <string> Network (local|dev|test|main)
--rpc-url <url> Rooch RPC URL
--default-asset-id <string> Default asset ID
--default-price-pico-usd <num> Default price in picoUSD
-d, --debug Enable debug logging
-h, --help Show help messageEnvironment Variables
PORT=8088
ENDPOINT=/mcp
CONFIG_PATH=./config.yaml # Can be local file path or remote URL
SERVICE_ID=my-service
SERVICE_KEY=your-service-key
ROOCH_NETWORK=test
DEFAULT_PRICE_PICO_USD=100000000
DEBUG=true4. Remote Configuration Support
MCP Server Proxy now supports loading configuration from remote URLs, making Docker deployments much more convenient.
Remote Configuration Examples
# Load config from remote URL
export CONFIG_PATH=https://your-config-server.com/configs/amap-proxy.yaml
mcp-server-proxy
# Or use command line argument
mcp-server-proxy --config https://your-config-server.com/configs/context7-proxy.yaml
# Docker with remote config
docker run -d -p 8088:8088 \
-e SERVICE_KEY="your_service_key" \
-e CONFIG_PATH="https://your-config-server.com/configs/my-proxy.yaml" \
--name mcp-server-proxy \
ghcr.io/nuwa-protocol/mcp-server-proxy:latestRemote Configuration Benefits
- Centralized Management: Store all proxy configurations in one place
- Easy Updates: Update configurations without rebuilding Docker images
- Environment-specific Configs: Use different URLs for dev/test/prod environments
- Version Control: Track configuration changes through your config server
- Dynamic Configuration: Update proxy behavior without container restarts
Supported URL Schemes
https://- HTTPS URLs (recommended for production)http://- HTTP URLs (for development/internal networks)
Configuration Server Requirements
Your configuration server should:
- Serve YAML files with proper
Content-Type: text/yamlortext/plainheaders - Support HTTPS for production deployments
- Have appropriate CORS headers if accessed from browsers
- Implement proper authentication/authorization if needed
5. Local Development Examples
Using Pre-configured Instances
You can directly use the pre-configured instances for local development:
Using NPM Package:
# Run Amap proxy locally
export AMAP_API_KEY=your_amap_api_key_here
export SERVICE_KEY=your_service_key_here # Required for ServiceDID and payment channels
export PORT=8088
# Use the pre-configured amap instance
mcp-server-proxy --config https://raw.githubusercontent.com/nuwa-protocol/nuwa/main/nuwa-services/mcp-server-proxy/deployments/instances/amap-proxy/config.yaml# Run Context7 proxy locally
export SERVICE_KEY=your_service_key_here # Required for ServiceDID and payment channels
export PORT=8089
# Use the pre-configured context7 instance
mcp-server-proxy --config https://raw.githubusercontent.com/nuwa-protocol/nuwa/main/nuwa-services/mcp-server-proxy/deployments/instances/context7-proxy/config.yamlFrom Source Code:
# Run Amap proxy locally
export AMAP_API_KEY=your_amap_api_key_here
export SERVICE_KEY=your_service_key_here # Required for ServiceDID and payment channels
export PORT=8088
# Use the pre-configured amap instance
node dist/index.js --config ./deployments/instances/amap-proxy/config.yaml# Run Context7 proxy locally
export SERVICE_KEY=your_service_key_here # Required for ServiceDID and payment channels
export PORT=8089
# Use the pre-configured context7 instance
node dist/index.js --config ./deployments/instances/context7-proxy/config.yamlQuick Development Scripts
We provide ready-to-use scripts for local development:
# Run Amap proxy (requires AMAP_API_KEY and SERVICE_KEY)
export AMAP_API_KEY=your_amap_api_key_here
export SERVICE_KEY=your_service_key_here
./examples/run-amap-local.sh
# Run Context7 proxy (requires SERVICE_KEY)
export SERVICE_KEY=your_service_key_here
./examples/run-context7-local.shTesting the Proxies
E2E Testing
Run the comprehensive E2E tests:
# Run E2E tests (requires Rooch node and PAYMENT_E2E=1)
PAYMENT_E2E=1 pnpm test:e2e:local5. Testing
# Run unit tests and basic integration tests
pnpm test
# Run E2E tests with payment functionality (requires Rooch node)
pnpm test:e2e:local
# Run E2E tests with custom node URL
ROOCH_NODE_URL=https://test-seed.rooch.network:443 pnpm test:e2eNote: E2E tests require:
- A running Rooch node (local or remote)
- The
PAYMENT_E2E=1environment variable - Sufficient test tokens for payment channel operations
Deployment
For production deployment, we provide a comprehensive multi-instance deployment system:
Quick Deployment
# List available instances
./deployments/scripts/manage.sh list
# Create a new instance
./deployments/scripts/manage.sh create my-proxy httpStream
# Deploy to Railway
./deployments/scripts/manage.sh deploy my-proxy
# Check status
./deployments/scripts/manage.sh status my-proxyPre-configured Instances
- amap-proxy: Amap Maps MCP proxy
- context7-proxy: Context7 documentation library proxy
See deployments/QUICKSTART.md for detailed deployment instructions.
Docker
Using Pre-built Images (Recommended)
Pull and run the official Docker image from GitHub Container Registry:
# Pull the latest image
docker pull ghcr.io/nuwa-protocol/mcp-server-proxy:latest
# Run with environment variables
docker run -d -p 8088:8088 \
-e SERVICE_KEY="your_service_key" \
-e UPSTREAM_API_KEY="your_upstream_api_key" \
--name mcp-server-proxy \
ghcr.io/nuwa-protocol/mcp-server-proxy:latest
# Run with mounted configuration file
docker run -d -p 8088:8088 \
-v $(pwd)/config.yaml:/app/config/config.yaml \
-e CONFIG_PATH="/app/config/config.yaml" \
--name mcp-server-proxy \
ghcr.io/nuwa-protocol/mcp-server-proxy:latestAvailable Tags
latest- Latest stable version from main branchv0.6.x- Specific version tagsmain- Latest development version
Environment Variables
| Variable | Description | Required |
|----------|-------------|----------|
| SERVICE_KEY | Service private key for DID signing | ✅ |
| CONFIG_PATH | Path to configuration file | ❌ |
| PORT | Server port (default: 8088) | ❌ |
| ENDPOINT | MCP endpoint path (default: /mcp) | ❌ |
| DEBUG | Enable debug logging | ❌ |
| UPSTREAM_API_KEY | API key for upstream services | ⚠️ |
Docker Compose
Use the provided docker-compose.yml file in the repository for easy deployment:
# Clone the repository and navigate to the service directory
git clone https://github.com/nuwa-protocol/nuwa.git
cd nuwa/nuwa-services/mcp-server-proxy
# Set up your environment variables
export SERVICE_KEY="your_service_key"
export UPSTREAM_API_KEY="your_upstream_api_key" # If needed for your upstream service
# Start the services
docker-compose up -dThe docker-compose.yml file includes:
- ✅ Complete configuration with all environment variables
- ✅ Health checks for service monitoring
- ✅ Multiple proxy instances examples (Amap, Context7)
- ✅ Flexible upstream configuration for different services
For detailed configuration options, see the docker-compose.yml file in the repository.
Building from Source
If you need to build the image locally:
# Clone the repository
git clone https://github.com/nuwa-protocol/nuwa.git
cd nuwa/nuwa-services/mcp-server-proxy
# Build the image
docker build -t mcp-server-proxy .
# Run the container
docker run -d -p 8088:8088 \
-e SERVICE_KEY="your_service_key" \
--name mcp-server-proxy \
mcp-server-proxy