Getting Started

Everything you need to start observing your AI agents in real time.

Overview

Candor is a real-time observability platform for AI agents. It works as a transparent proxy that sits between your AI agent and MCP servers, intercepting, logging, and visualizing every tool call, resource read, and response.

Think of it as Sentry for AI agents — you see exactly what your agents are doing, how much they cost, and when things go wrong.

Full Visibility
Every MCP tool call, resource read, and prompt completion logged and visualized.
Real-Time
Live event streaming via WebSocket. See agent actions as they happen.
Cost Tracking
Estimate token costs per session, per tool, per agent. No surprises.
Smart Alerts
Set rules for error rates, cost spikes, latency thresholds. Get notified via webhook.

Quick Start

Get up and running in under 60 seconds:

1
Clone the repository
Get the source code from GitHub.
2
Install dependencies
Run npm install to set up all packages.
3
Set up the database
Run Prisma migrations to initialize PostgreSQL.
4
Start the dev server
Launch the dashboard and start observing.
bash
# Clone the repository
git clone https://github.com/candordotcodes/candor.git
cd candor
# Install dependencies
npm install
# Set up the database
npx prisma migrate dev
# Start the dev server
npm run dev
# Open dashboard at http://localhost:3000

Requirements

RequirementVersionNotes
Node.js>=18.0.0LTS recommended
GitAny recentFor cloning the repository
PostgreSQL>=14Event storage (optional for dev)
MCP ClientAnyClaude Desktop, Cursor, Windsurf, etc.
Development Mode
PostgreSQL is only required for production. In dev mode, Candor uses an in-memory store for events so you can try it without any database setup.

Installation

Clone and set up Candor on your system.

Clone & Setup

bash
# Clone the repository
git clone https://github.com/candordotcodes/candor.git
cd candor
# Install dependencies
npm install
# Set up environment
cp .env.example .env
# Edit .env with your DATABASE_URL and JWT_SECRET

Verify Installation

After setup, start the development server to verify everything works:

bash
# Start the development server
npm run dev
# Dashboard available at http://localhost:3000
# Proxy available at http://localhost:3100

Configuration

Set up your proxy, routes, and environment for development or production.

Config File

Run candor init to generate a candor.config.json file in your project root. This file controls how the proxy routes MCP traffic.

candor.config.json
1{
2 "proxy": {
3 "port": 3100,
4 "dashboard": 3200,
5 "websocket": 3101
6 },
7 "upstreams": [
8 {
9 "name": "filesystem",
10 "transport": "stdio",
11 "command": "npx",
12 "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
13 },
14 {
15 "name": "github",
16 "transport": "sse",
17 "url": "https://mcp.github.com/sse"
18 }
19 ],
20 "storage": {
21 "driver": "postgres",
22 "url": "postgresql://user:pass@localhost:5432/candor"
23 },
24 "retention": {
25 "days": 7,
26 "maxEventsPerSession": 1000
27 }
28}

MCP Routing

Candor acts as a transparent proxy. You change one line in your MCP client config to route traffic through Candor instead of directly to the MCP server.

Before and After
Your MCP client connects to localhost:3100 instead of the upstream server. Candor handles forwarding, logging, and streaming the data to the dashboard.
claude_desktop_config.json
1// Claude Desktop: ~/.claude/claude_desktop_config.json
2// Before (direct connection):
3{
4 "mcpServers": {
5 "filesystem": {
6 "command": "npx",
7 "args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
8 }
9 }
10}
11
12// After (through Candor proxy):
13{
14 "mcpServers": {
15 "candor-proxy": {
16 "command": "candor",
17 "args": ["start", "--attach"]
18 }
19 }
20}

Environment Variables

VariableDefaultDescription
DATABASE_URLPostgreSQL connection string
PROXY_PORT3100Port for MCP proxy listener
DASHBOARD_PORT3200Port for web dashboard
WEBSOCKET_PORT3101Port for live event streaming
NEXT_PUBLIC_SOLANA_NETWORKmainnet-betaSolana cluster for wallet auth
NEXT_PUBLIC_SOLANA_RPC_URLhttps://api.mainnet-beta.solana.comSolana RPC endpoint
WEBHOOK_SECRETSecret for verifying webhook deliveries
LOG_RETENTION_DAYS7Days to keep event history
MAX_EVENTS_PER_SESSION1000Max events stored per session

Architecture

How Candor intercepts, stores, and visualizes MCP traffic.

Data Flow

Candor sits between your AI agent and its MCP servers as a transparent proxy layer. Every request and response passes through, gets logged, and is streamed to the dashboard in real time.

System Architecture
AI Agent
Claude, Cursor, Windsurf, etc.
MCP JSON-RPC (stdio/SSE)
Candor Proxy
localhost:3100
Forward
MCP Server(s)
Tool execution
Log
PostgreSQL
Event storage
Stream
WebSocket
:3101
Real-time feed
Dashboard
Timeline / Sessions / Costs / Alerts

Proxy Layer

The proxy layer intercepts MCP JSON-RPC messages over both stdio and SSE transports. It is completely transparent — your agents work exactly as before.

Zero Code Changes
No SDK, no imports. Just a config change to route through the proxy.
Bidirectional
Captures both requests (agent → server) and responses (server → agent).
Low Latency
Sub-millisecond overhead. Async logging ensures zero impact on agent performance.

Event Pipeline

Each intercepted MCP message goes through the following pipeline:

1
Intercept
Proxy captures the raw JSON-RPC request/response pair.
2
Enrich
Adds metadata: timestamp, session ID, latency, estimated token count.
3
Store
Writes to PostgreSQL via Prisma for persistent storage and querying.
4
Stream
Broadcasts to connected WebSocket clients for real-time dashboard updates.
5
Evaluate
Checks against alert rules. Triggers webhooks if conditions match.

CLI Reference

Complete reference for the Candor proxy CLI commands.

candor start

Start the proxy server and dashboard. This is the primary command for daily use.

bash
candor start [options]
Options:
--port <number> Proxy port (default: 3100)
--dashboard <number> Dashboard port (default: 3200)
--config <path> Path to config file (default: ./candor.config.json)
--no-dashboard Start proxy only, skip dashboard
--attach Run in attached mode (for MCP client integration)
--verbose Enable verbose logging
Examples:
candor start
candor start --port 4100 --dashboard 4200
candor start --no-dashboard
candor start --config ./custom-config.json

candor init

Generate a new configuration file with an interactive wizard.

bash
candor init [options]
Options:
--dir <path> Output directory (default: current directory)
--template <id> Use a starter template (basic, advanced)
# Interactive wizard flow:
# 1. Select MCP servers to monitor
# 2. Configure transport type (stdio/SSE)
# 3. Set storage backend (memory/postgres)
# 4. Choose dashboard port
# → Generates candor.config.json

candor status

Show the current status of the proxy, connected agents, and active sessions.

bash
candor status
# Output:
# Candor Proxy v1.0.0
# ─────────────────────────────
# Status: Running
# Proxy: localhost:3100
# Dashboard: localhost:3200
# WebSocket: localhost:3101
#
# Active Sessions: 2
# Total Events: 1,847
# Uptime: 4h 23m
#
# Connected Upstreams:
# ✓ filesystem (stdio)
# ✓ github (SSE)
# ✗ slack (disconnected)

MCP Integration

How to connect different AI agents and MCP clients through Candor.

stdio Mode

stdio is the default transport for local MCP servers. The proxy spawns the MCP server as a child process and intercepts all stdin/stdout communication.

candor.config.json
1// candor.config.json
2{
3 "upstreams": [
4 {
5 "name": "filesystem",
6 "transport": "stdio",
7 "command": "npx",
8 "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]
9 },
10 {
11 "name": "sqlite",
12 "transport": "stdio",
13 "command": "npx",
14 "args": ["-y", "@modelcontextprotocol/server-sqlite", "db.sqlite"]
15 }
16 ]
17}

SSE Mode

SSE (Server-Sent Events) transport is used for remote MCP servers. The proxy connects to the remote server and relays events to your local agent.

candor.config.json
1// candor.config.json
2{
3 "upstreams": [
4 {
5 "name": "github",
6 "transport": "sse",
7 "url": "https://mcp.github.com/sse",
8 "headers": {
9 "Authorization": "Bearer ghp_xxxxxxxxxxxx"
10 }
11 }
12 ]
13}

Supported Clients

Candor works with any MCP-compatible AI agent. Here are setup guides for popular clients:

ClientTransportConfig Location
Claude Desktopstdio~/.claude/claude_desktop_config.json
Claude Code (CLI)stdio~/.claude/claude_code_config.json
Cursorstdio.cursor/mcp.json
Windsurfstdio~/.codeium/windsurf/mcp_config.json
VS Code (Copilot)stdio.vscode/mcp.json
Custom Agentstdio / SSESee API Reference
All MCP clients that support the standard stdio transport work with Candor out of the box. No client-specific code is needed.

Dashboard

The visual interface for monitoring your AI agents.

Live Timeline

The Timeline view shows every MCP event as it happens. Events stream in real time via WebSocket and display the tool name, method, parameters, latency, and cost estimate.

Real-Time Streaming
Events appear instantly as your agent executes tool calls.
Powerful Filters
Filter by tool name, method, status, latency range, or time window.
Expandable Detail
Click any event to see full request params and response payload.

Session Explorer

Sessions group related MCP events together. Each time an agent starts a new conversation or task, Candor creates a session to track all associated tool calls.

FieldDescription
Agent IDIdentifier for the AI agent that created the session
DurationTime from first to last event in the session
EventsTotal number of MCP events in the session
CostEstimated total cost based on token usage
ErrorsNumber of failed tool calls or error responses
StatusActive (receiving events) or completed

Wallet Authentication

Candor uses Solana wallet-based authentication. Connect a Phantom or Solflare wallet to access your personal dashboard. Your wallet address serves as your account identifier.

Why Wallet Auth?
Wallet auth means no passwords, no email verification, and no centralized account storage. Your identity is your wallet — simple, secure, and decentralized.
typescript
// Supported wallets:
// - Phantom (browser extension)
// - Solflare (browser extension)
// - Any Wallet Standard compatible wallet
// The dashboard uses @solana/wallet-adapter-react
// Auth flow:
// 1. Click "Connect Wallet" → wallet popup
// 2. Approve connection → dashboard unlocks
// 3. Wallet address = account ID
// 4. Disconnect to return to demo mode

API Reference

REST endpoints and WebSocket API for programmatic access.

REST Endpoints

GET/api/sessions
GET/api/sessions/:id
GET/api/events
GET/api/stats
POST/api/alert-rules
PUT/api/alert-rules/:id
DELETE/api/alert-rules/:id
GET/api/alerts
GET/api/cost-rates
PUT/api/cost-rates/:id

WebSocket API

Connect to the WebSocket endpoint for real-time event streaming. Events are broadcast as they are intercepted by the proxy.

websocket-client.ts
1// Connect to WebSocket
2const ws = new WebSocket('ws://localhost:3101');
3
4ws.onopen = () => {
5 console.log('Connected to Candor event stream');
6
7 // Subscribe to specific sessions (optional)
8 ws.send(JSON.stringify({
9 type: 'subscribe',
10 sessionId: 'session-uuid-here'
11 }));
12};
13
14ws.onmessage = (event) => {
15 const data = JSON.parse(event.data);
16
17 switch (data.type) {
18 case 'event':
19 // New MCP event intercepted
20 console.log(data.event);
21 break;
22 case 'session:start':
23 // New session began
24 console.log('New session:', data.sessionId);
25 break;
26 case 'session:end':
27 // Session completed
28 console.log('Session ended:', data.sessionId);
29 break;
30 case 'alert':
31 // Alert rule triggered
32 console.log('Alert:', data.alert);
33 break;
34 }
35};

Event Schema

Each MCP event has the following structure:

types/event.ts
1interface MCPEvent {
2 id: string; // Unique event ID
3 sessionId: string; // Parent session ID
4 timestamp: string; // ISO 8601 timestamp
5 direction: 'request' | 'response';
6
7 // MCP fields
8 method: string; // e.g., "tools/call", "resources/read"
9 toolName?: string; // Tool name (for tool calls)
10 params?: object; // Request parameters
11 result?: object; // Response result
12
13 // Metadata
14 latencyMs?: number; // Round-trip latency
15 costEstimate?: number; // Estimated USD cost
16 tokenCount?: {
17 input: number;
18 output: number;
19 };
20 status: 'success' | 'error';
21 error?: string; // Error message (if status is 'error')
22}

Cost Tracking

Monitor and attribute costs across agents, sessions, and tools.

Cost Models

Candor estimates costs by analyzing token counts in MCP payloads and matching them against configurable rate cards for different LLM providers.

ProviderModelInput (per 1K)Output (per 1K)
AnthropicClaude Opus 4$15.00$75.00
AnthropicClaude Sonnet 4$3.00$15.00
AnthropicClaude Haiku 3.5$0.80$4.00
OpenAIGPT-4o$2.50$10.00
OpenAIGPT-4o mini$0.15$0.60

Custom Rates

Configure custom cost rates via the API or dashboard settings:

json
// Create custom cost rate
PUT /api/cost-rates/custom-model
{
"provider": "custom",
"model": "my-fine-tuned-model",
"inputPer1kTokens": 5.00,
"outputPer1kTokens": 15.00,
"currency": "USD"
}

Alerts

Define rules to get notified when things need attention.

Alert Rules

Alert rules evaluate conditions against incoming events. When a condition matches, Candor creates an alert and optionally sends a webhook notification.

json
// Create alert rule via API
POST /api/alert-rules
{
"name": "High Error Rate",
"condition": {
"type": "error_rate",
"threshold": 0.1, // 10% error rate
"window": "5m" // Over a 5-minute window
},
"webhookUrl": "https://hooks.slack.com/services/xxx",
"enabled": true
}

Webhooks

Alert notifications are sent as HTTP POST requests to your configured webhook URL. Each payload includes the alert details, triggering event, and session context.

webhook-payload.json
1// Webhook payload example
2{
3 "id": "alert-uuid",
4 "rule": "High Error Rate",
5 "severity": "warning",
6 "message": "Error rate exceeded 10% in the last 5 minutes",
7 "timestamp": "2026-02-23T14:30:00Z",
8 "session": {
9 "id": "session-uuid",
10 "agentId": "claude-desktop"
11 },
12 "event": {
13 "id": "event-uuid",
14 "method": "tools/call",
15 "toolName": "file_write",
16 "status": "error",
17 "error": "Permission denied"
18 }
19}

Condition Types

TypeDescriptionParameters
error_rateTriggers when error rate exceeds thresholdthreshold (0-1), window
latencyTriggers when p95 latency exceeds thresholdthresholdMs, window
cost_spikeTriggers when session cost exceeds budgetmaxCostUsd
tool_failureTriggers on specific tool errortoolName, errorPattern
session_durationTriggers when session exceeds time limitmaxDurationMs
event_countTriggers when events per session exceed limitmaxEvents

Deployment

Deploy Candor for team-wide or production observability.

Railway

Railway is the recommended deployment platform. Deploy the dashboard, proxy, and PostgreSQL database as connected services.

bash
# Install Railway CLI
npm install -g @railway/cli
# Login
railway login
# Initialize project
railway init
# Add PostgreSQL
railway add --plugin postgresql
# Deploy
railway up
# Set environment variables
railway variables set DATABASE_URL=<auto-provided>
railway variables set PROXY_PORT=3100
railway variables set DASHBOARD_PORT=3200

Docker

Dockerfile
1# Dockerfile
2FROM node:20-alpine AS base
3
4WORKDIR /app
5COPY package*.json ./
6RUN npm ci --production
7
8COPY . .
9RUN npm run build
10
11EXPOSE 3100 3200 3101
12
13CMD ["npm", "start"]
docker-compose.yml
1# docker-compose.yml
2services:
3 candor:
4 build: .
5 ports:
6 - "3100:3100"
7 - "3200:3200"
8 - "3101:3101"
9 environment:
10 - DATABASE_URL=postgresql://candor:secret@db:5432/candor
11 depends_on:
12 - db
13
14 db:
15 image: postgres:16-alpine
16 environment:
17 POSTGRES_DB: candor
18 POSTGRES_USER: candor
19 POSTGRES_PASSWORD: secret
20 volumes:
21 - pgdata:/var/lib/postgresql/data
22
23volumes:
24 pgdata:

Self-Hosted

For self-hosted deployments, you need Node.js 18+ and PostgreSQL 14+:

1
Clone the repository
git clone https://github.com/candordotcodes/candor.git
2
Install dependencies
npm install
3
Set up the database
Create a PostgreSQL database and set DATABASE_URL
4
Run migrations
npx prisma migrate deploy
5
Build the dashboard
npm run build
6
Start
npm start (or use PM2/systemd for process management)

Troubleshooting

Common issues and frequently asked questions.

Common Issues

Port already in use
If port 3100 is occupied, either stop the conflicting process or use candor start --port 4100 to specify an alternative port.
Wallet connection fails
Make sure you have Phantom or Solflare browser extension installed. Candor does not support hardware wallets (Ledger) due to USB dependency constraints.
Events not appearing in dashboard
Check that your MCP client is routing through the Candor proxy port (default: 3100). Use candor status to verify the proxy is running and upstreams are connected.
High memory usage
If the proxy is consuming too much memory, reduce MAX_EVENTS_PER_SESSION and LOG_RETENTION_DAYS in your environment variables.

FAQ