🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@dcprotocol/relay

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@dcprotocol/relay

Encrypted message relay for DCP - enables cloud MCP clients to reach local vaults

Source
npmnpm
Version
0.2.0
Version published
Weekly downloads
20
-39.39%
Maintainers
1
Weekly downloads
 
Created
Source

@dcprotocol/relay

Encrypted message relay for DCP - enables cloud MCP clients to securely communicate with local vaults.

This is the same relay software used for the default public relay at wss://relay.dcp.1ly.store. Running your own relay is fully supported.

Overview

The DCP Relay is a message bus that routes encrypted requests between cloud MCP clients (like Claude.ai, ChatGPT) and local DCP vaults. The relay never sees plaintext data - it only handles routing of opaque encrypted payloads.

Features

  • WebSocket Primary: Real-time bidirectional communication
  • HTTP Long-Poll Fallback: For environments where WebSocket isn't available
  • Heartbeat: 30-second keep-alive interval
  • Message TTL: Messages expire after 5 minutes
  • Idempotency: Duplicate requests handled via request_id
  • Zero Knowledge: Relay sees only routing metadata, never plaintext
  • Rate Limiting: Configurable per-vault rate limits (default: 60 req/min)
  • Prometheus Metrics: /metrics endpoint for monitoring

Installation

npm install @dcprotocol/relay

Quick Start

As a Server

# Start relay on default port (8421)
npx -y @dcprotocol/relay

# With options
npx -y @dcprotocol/relay --port 9000 --debug

If you self-host, point Desktop, @dcprotocol/client, dcp connect, or @dcprotocol/proxy at your own relay URL instead of the public one.

As a Library

import { RelayServer } from '@dcprotocol/relay';

const relay = new RelayServer({
  port: 8421,
  host: '0.0.0.0',
  debug: true,
  enableLongPoll: true,
});

await relay.start();
console.log('Relay running on port 8421');

// Graceful shutdown
process.on('SIGINT', () => relay.stop());

Protocol

Relay Envelope

All messages follow this envelope format:

{
  "version": "1",
  "vault_id": "vault_abc123",
  "request_id": "req_xyz789",
  "action_type": "sign",
  "encrypted_payload": "<base64-encoded-hpke-ciphertext>",
  "expires_at": "2026-03-05T12:00:00Z"
}

Action Types

  • sign - Signing operations (tx, message, x402, typed data)
  • read - Read operations
  • write - Write operations
  • budget - Budget checks

WebSocket Messages

// Register vault (authenticated)
{
  type: 'register',
  payload: {
    vault_id: string,
    public_key: string,
    signing_public_key: string,
    timestamp: string,
    nonce: string,
    signature: string,
    pairing_token?: string,
  }
}

// Heartbeat
{ type: 'heartbeat', payload: { vault_id: string } }

// Request (relay -> vault)
{ type: 'request', payload: RelayEnvelope }

// Response (vault -> relay)
{ type: 'response', payload: RelayResponseEnvelope }

HTTP Endpoints

EndpointMethodDescription
/healthGETHealth check
/statsGETRelay statistics
/metricsGETDetailed metrics (JSON or Prometheus format)
/relay/requestPOSTSubmit request to vault (requires pairing token when enabled)
/relay/response/:requestIdGETPoll for response
/relay/pollPOSTLong-poll for vault (fallback)
/relay/respondPOSTSubmit response (fallback)

WebSocket Endpoints

EndpointDescription
/wsVault connections (authenticated)
/ws-clientClient/agent connections

Security

  • End-to-End Encryption: All payloads are HPKE-encrypted (X25519 + ChaCha20-Poly1305)
  • No Plaintext: Relay never sees method names, amounts, or business logic
  • Relay Authentication: Vault registration is signed (Ed25519) and pairing tokens are validated when required
  • Transport-Level Errors Only: RELAY_UNAVAILABLE, RELAY_TIMEOUT, RELAY_UNAUTHORIZED

Request Authentication

When pairing tokens are enabled, clients must include one of:

  • Authorization: Bearer <pairing_token>
  • X-DCP-PAIRING-TOKEN: <pairing_token>

Configuration

interface RelayConfig {
  port: number;              // Default: 8421
  host: string;              // Default: '0.0.0.0'
  enableLongPoll: boolean;   // Default: true
  heartbeatIntervalMs: number; // Default: 30000
  messageTtlMs: number;      // Default: 300000 (5 minutes)
  maxPendingMessages: number; // Default: 100 per vault
  debug: boolean;            // Default: false
  rateLimitPerMinute: number; // Default: 60 requests per vault per minute
  rateLimitWindowMs: number;  // Default: 60000 (1 minute)
}

Environment Variables

VariableDescriptionDefault
DCP_RELAY_PORTPort to listen on8421
DCP_RELAY_HOSTHost to bind to0.0.0.0
DCP_RELAY_DEBUGEnable debug loggingfalse
DCP_RELAY_RATE_LIMITMax requests per vault per minute60

Error Codes

CodeDescription
RELAY_UNAVAILABLERelay server not available
RELAY_TIMEOUTRequest timed out
RELAY_UNAUTHORIZEDNot authorized
RELAY_INVALID_ENVELOPEInvalid message format
RELAY_VAULT_NOT_CONNECTEDTarget vault not connected
RELAY_DUPLICATE_REQUESTDuplicate request_id
RELAY_MESSAGE_EXPIREDMessage TTL exceeded
RELAY_RATE_LIMITEDToo many requests (429)

Rate Limiting

The relay enforces per-vault rate limits to prevent abuse. When a vault exceeds its limit, subsequent requests receive a 429 response with:

{
  "error": {
    "code": "RELAY_RATE_LIMITED",
    "message": "Rate limit exceeded for vault vault_abc123. Try again in 45 seconds.",
    "details": {
      "vault_id": "vault_abc123",
      "limit": 60,
      "window_ms": 60000,
      "retry_after_ms": 45000
    }
  }
}

Rate limit headers are included in all responses:

  • X-RateLimit-Limit: Max requests per window
  • X-RateLimit-Remaining: Remaining requests
  • X-RateLimit-Reset: Seconds until reset (on 429)
  • Retry-After: Seconds to wait before retry (on 429)

Monitoring

Metrics Endpoint

The /metrics endpoint provides detailed relay statistics:

# JSON format (default)
curl http://localhost:8421/metrics

# Prometheus format
curl http://localhost:8421/metrics?format=prometheus

Prometheus Metrics

dcp_relay_messages_total
dcp_relay_messages_pending
dcp_relay_messages_delivered
dcp_relay_vaults_connected
dcp_relay_vaults_tracked
dcp_relay_rate_limit_max
dcp_relay_ws_clients

Deployment

Docker

FROM node:20-alpine
WORKDIR /app
RUN npm install -g @dcprotocol/relay
EXPOSE 8421
CMD ["dcp-relay", "--host", "0.0.0.0"]

Docker Compose

version: '3.8'
services:
  relay:
    image: node:20-alpine
    working_dir: /app
    command: npx -y @dcprotocol/relay
    ports:
      - "8421:8421"
    environment:
      - DCP_RELAY_PORT=8421
      - DCP_RELAY_RATE_LIMIT=60
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:8421/health"]
      interval: 30s
      timeout: 5s
      retries: 3

Systemd Service

[Unit]
Description=DCP Relay Server
After=network.target

[Service]
Type=simple
User=dcp
ExecStart=/usr/bin/npx -y @dcprotocol/relay --port 8421
Restart=always
RestartSec=5
Environment=NODE_ENV=production
Environment=DCP_RELAY_RATE_LIMIT=60

[Install]
WantedBy=multi-user.target

Production Checklist

  • TLS/SSL: Run behind a reverse proxy (nginx, Caddy) with TLS termination
  • Rate Limiting: Adjust DCP_RELAY_RATE_LIMIT based on expected traffic
  • Monitoring: Scrape /metrics?format=prometheus with Prometheus
  • Health Checks: Use /health endpoint for load balancer health checks
  • Logging: Enable --debug for troubleshooting, disable in production

Nginx Configuration

upstream dcp_relay {
    server 127.0.0.1:8421;
}

server {
    listen 443 ssl http2;
    server_name relay.dcp.1ly.store;

    ssl_certificate /etc/letsencrypt/live/relay.dcp.1ly.store/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/relay.dcp.1ly.store/privkey.pem;

    location / {
        proxy_pass http://dcp_relay;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}

License

Apache-2.0

Keywords

relay

FAQs

Package last updated on 18 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts