@keoki/agent-tracking
v0.0.3
Published
Track AI agent interactions (MCP tool calls and more) with Keoki analytics.
Downloads
256
Maintainers
Readme
@keoki/agent-tracking
Track AI agent interactions with Keoki.
Wrap your MCP server's transport and every JSON-RPC method (tool calls, discovery, and more) is reported to your Keoki analytics. One line, transport-agnostic.
Install
npm install @keoki/agent-tracking@modelcontextprotocol/sdk is a peer dependency — you already have it in your MCP server.
Usage
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { withKeoki } from "@keoki/agent-tracking";
const server = new McpServer({ name: "my-server", version: "1.0.0" });
// ... register your tools ...
await server.connect(
withKeoki(new StdioServerTransport(), {
serverId: process.env.KEOKI_SERVER_ID!,
apiKey: process.env.KEOKI_API_KEY!,
}),
);withKeoki is transport-agnostic — the same call works for stdio, HTTP/SSE, or any custom transport.
Tracking is fire-and-forget: reports are sent in the background and a failed POST never throws into or blocks your server. Pass onError if you want to log failures.
AI SDK model tracking
Wrap your AI SDK language model the same way you wrapped your transport, and every model call is reported as a conversation turn — token usage, latency, finish reason, message counts, tool-call names.
import { anthropic } from "@ai-sdk/anthropic";
import { withKeoki } from "@keoki/agent-tracking/ai";
const model = withKeoki(anthropic("claude-sonnet-5"));Conversations are grouped automatically — the adapter recognizes each call's
prompt as the continuation of a history it has seen. For exact continuity
across server instances or restarts, pass your own id: per wrapper
({ conversationId: chat.id }) or per call, without re-wrapping:
await generateText({
model,
messages,
providerOptions: { keoki: { conversationId: chat.id } },
});By default, message content never leaves your process. Only conversation structure is reported: counts by role, token usage, and a one-way hash identifying the turn. Prompts and completions are not read, stored, or transmitted.
To also capture transcripts for conversation search, opt in with content: true. Secrets are redacted before send, and each distinct message is transmitted once:
const model = withKeoki(anthropic("claude-sonnet-5"), { content: true });Composing with other middleware? Use the middleware form instead:
import { wrapLanguageModel } from "ai";
import { keokiMiddleware } from "@keoki/agent-tracking/ai";
const model = wrapLanguageModel({
model: anthropic("claude-sonnet-5"),
middleware: keokiMiddleware(),
});Works with any AI SDK v5 provider. No extra dependencies.
Options
All options fall back to environment variables, so both wrappers can be called with no options at all.
| Option | Required | Description |
| ---------------- | -------- | --------------------------------------------------------------------------------- |
| serverId | Yes* | Your Keoki server ID. Env: KEOKI_SERVER_ID |
| apiKey | Yes* | API key with access to the server. Env: KEOKI_API_KEY |
| apiUrl | No | Override the ingestion host (defaults to production). Env: KEOKI_API_URL |
| onError | No | Called when an ingest POST fails. |
| conversationId | No | AI wrapper only — overrides automatic conversation inference. Use the same value as your MCP sessionId to correlate turns with tool calls, or pass per call via providerOptions: { keoki: { conversationId } }. |
* Required, but may come from the environment instead of options.
Docs
Full documentation at keoki.ai/docs.
