Ir al contenido
mcpd
sin daemon
Código

Inicio rápido

Daemon en marcha, agente instrumentado, traza en pantalla. Nada a lo que registrarse y nada que instalar al lado.

1. Ejecuta el daemon

Todavía no hay una versión publicada.

La imagen, el chart y los paquetes que nombran los comandos de este sitio son la distribución prevista. Ninguno se ha publicado. Lo que funciona hoy es compilar desde el código fuente, para lo que hacen falta Rust y Node:

Compilar y ejecutar

git clone https://github.com/mcpd/mcpd && cd mcpd && make build && ./target/release/mcpd demo

mcpd es un solo proceso con el almacenamiento compilado dentro. No hay base de datos que levantar ni archivo de configuración que escribir.

docker run -p 4317:4317 -v mcpd-data:/data ghcr.io/mcpd/mcpd

El volumen es opcional, pero conviene añadirlo: sin él, las trazas desaparecen cuando desaparece el contenedor. ¿Prefieres un binario? Instálalo directamente.

lo que deberías ver
$ docker run -p 4317:4317 ghcr.io/mcpd/mcpdWARN listening on 0.0.0.0:4317 with open ingest. Anyone who can reach this port can write to it. Set --ingest-key (or MCPD_INGEST_KEYS) before exposing it.WARN listening on 0.0.0.0:4317 with an open read API. Stored prompts and completions are readable by anyone who can reach this port. Set --read-key to require a key.WARN listening on 0.0.0.0:4317 with an open run surface. Anyone who can reach this port can start runs and claim steps. Set --execute-key and --worker-key before exposing it.INFO mcpd 0.1.0 listening on http://0.0.0.0:4317INFO   interface   http://0.0.0.0:4317/INFO   OTLP        http://0.0.0.0:4317/v1/tracesINFO   native      http://0.0.0.0:4317/v1/ingestINFO   runs        http://0.0.0.0:4317/v1/api/runsINFO   storage     sqlite at /data/mcpd.db

Los avisos salen primero, y son deliberados. En tu portátil no importan. Antes de que este puerto quede al alcance de cualquier otra cosa, lee Despliegue.

2. Envíale algo

Hay dos formas de entrar, y no tienes que elegir la nuestra. Si tu agente ya emite OpenTelemetry, apúntalo a mcpd y no escribas ni una línea de código nueva:

export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317

Si no, instala el SDK de tu lenguaje. No tiene dependencias obligatorias, y registrar un span nunca bloquea ni lanza excepciones.

conectar

import { Mcpd } from '@mcpd/sdk'

// Every field here also reads an environment variable, so the same code runs
// unchanged in development and in production. With no arguments at all this
// talks to a daemon on http://localhost:4317.
const mcpd = new Mcpd({
  project: 'support',
  environment: 'development',
  serviceName: 'support-agent',
  serviceVersion: '1.4.0',
})

3. Instrumenta una ejecución

Envuelve el trabajo que hace tu agente. Un span registra qué entró, qué salió, cuánto tardó y cuánto costó; los hijos se anidan dentro de él solos, así que una llamada a una herramienta hecha dentro del bloque cae en el lugar correcto del árbol sin que nadie le diga a dónde pertenece.

registrar una ejecución

/**
 * One ticket, one trace.
 *
 * `withSpan` opens the span, keeps it active for everything the callback
 * starts, and ends it when the callback settles. Nothing inside has to be
 * passed a handle to be nested under it.
 */
async function handleTicket(ticket: Ticket): Promise<{ answer: string; traceId: string }> {
  let traceId = ''
  const answer = await mcpd.withSpan('support_agent', async (run) => {
    // Keep the id: a score or a piece of feedback that arrives later attaches
    // to this run by it.
    traceId = run.traceId
    // Tags label the whole run, so the trace list can filter on them.
    run.setTags(['support', 'tier-1'])
    run.setCorrelation({ sessionId: ticket.id, userId: ticket.customerId })
    run.setInput({ question: ticket.question })

    const order = await lookUpOrder(ticket)
    const answer = await draftAnswer(ticket, order)

    run.setOutput({ answer })
    return answer
  })
  return { answer, traceId }
}

4. Léela

Abre localhost:4317. Tu ejecución está en la lista. Ábrela y tienes el árbol entero: cada llamada al modelo con su prompt y su completion, cada llamada a una herramienta con sus argumentos y su resultado, tiempos, tokens y costo.

Trace b3d9e71a Fault
0ms 2.1s 4.2s 6.3s 8.4s
  1. agent support_agent fail
  2. model chat
  3. tool returns_policy
  4. model chat
  5. tool returns_policy
  6. model chat
  7. tool returns_policy

The model called one tool three times and never answered. That is visible in four seconds here, and invisible in a log file.

5. Encuentra la que interesa

No es en la lista donde vas a pasar el tiempo, sino en la búsqueda. mcpd indexa cada prompt y cada completion, así que puedes ir directo a la ejecución donde el modelo dijo aquello de lo que se quejó un cliente:

buscar y analizar

// The same client reads. This is the query that finds bad answers: every run
// that a scorer put below the bar.
const suspect = await mcpd.listTraces({
  hasScore: 'answer_relevance',
  scoreBelow: 0.5,
  limit: 10,
})
console.log(`runs scoring under 0.5: ${suspect.traces.length}`)

const recent = await mcpd.listTraces({ limit: 5, sort: 'start_time', order: 'desc' })
for (const trace of recent.traces) {
  const seconds = ((trace.durationNs ?? 0) / 1e9).toFixed(2)
  console.log(
    `${trace.traceId.slice(0, 8)}  ${trace.name.padEnd(16)} ${trace.status.padEnd(6)} ` +
      `${seconds}s  ${trace.spanCount} spans  $${(trace.cost?.totalCost ?? 0).toFixed(6)}`,
  )
}

// One run, with every span in it, ordered so a waterfall renders directly.
const detail = await mcpd.getTrace(traceId, { include: ['scores', 'feedback'] })
for (const span of detail.spans) {
  console.log(`  ${span.kind.padEnd(18)} ${span.name}`)
}

Adónde ir después

Ya tienes el ciclo completo. Las páginas que conviene leer ahora dependen de lo que estés haciendo: