reo-census-mcp
v0.2.0
Published
Product usage HTTP client for Reo (POST JSON to ingest.reo.dev/api/product/usage)
Maintainers
Readme
reo-census-mcp (Node.js)
This README is for teams integrating Reo into customer-facing products: you ship applications or services your customers rely on, and usage data is sent to Reo telemetry from that software.
The SDK uses Node 18+ native fetch, is non-blocking by default, so customer-facing request paths stay responsive while events reach Reo telemetry.
Install
npm install reo-census-mcpBlocking behavior (important)
blocking: false(default):logUsage()returns a boolean immediately.truemeans the request was queued, not that Reo already responded (not proof of HTTP 2xx).blocking: true:logUsage()returnsPromise<boolean>. Useawait(or.then()).truemeans HTTP 2xx after retries.
Early validation failures (opt-out, bad URL, missing API key, payload too large) return false synchronously even if you pass blocking: true.
ReoProductUsageLogger
Public options use camelCase; the JSON body still uses snake_case keys such as activity_type (see payload table below).
Two examples:
- Version 1 — required payload fields only; set
REO_API_KEYin the environment without passingapiKey. - Version 2 — every option, including
apiKeyin code for the full example.
Version 1 — required payload fields only
Merged payload must include activity_type, user_id, user_id_type, and product_id. source and environment default to PRODUCT_CLOUD and PRODUCTION when you omit them (override per call, on the constructor, or with REO_PRODUCT_USAGE_SOURCE / REO_PRODUCT_USAGE_ENVIRONMENT).
Set REO_API_KEY before constructing the logger (do not pass apiKey here—it is read from env).
import { ReoProductUsageLogger } from "reo-census-mcp";
const logger = new ReoProductUsageLogger({
activityType: "LOGIN_ACTIVITY",
userId: "https://www.linkedin.com/in/userid",
userIdType: "LINKEDIN",
productId: "reoWebApp",
});
const ok = logger.logUsage(); // non-blocking by default; booleanVersion 2 — all constructor parameters
Every supported option, including apiKey in code (Version 1 uses REO_API_KEY env only). eventId / eventAt below illustrate the full surface area—omit them in real traffic so each logUsage() auto-fills.
import { ReoProductUsageLogger } from "reo-census-mcp";
const logger = new ReoProductUsageLogger({
apiKey: "YOUR_API_KEY",
endpointUrl: "https://ingest.reo.dev/api/product/usage",
timeout: 3.0,
blocking: true,
activityType: "LOGIN_ACTIVITY",
source: "PRODUCT_CLOUD",
environment: "PRODUCTION",
userId: "https://www.linkedin.com/in/userid",
userIdType: "LINKEDIN",
ipAddr: "156.59.87.83",
productId: "reoWebApp",
userAgent: "Mozilla/5.0 ...",
meta: { property1: "value1", property2: "value2" },
eventId: 1231231232,
eventAt: 639303296,
});
const ok = await logger.logUsage();Payload fields
The SDK does not reject incomplete payloads locally; ingestion may enforce its own rules. When instrumenting customer-facing products, make sure each merged payload is complete and aligned with your privacy commitments (what you disclose to your customers’ end users, and fields like user_id / meta).
For a valid integration event, supply every required field via the ReoProductUsageLogger constructor, via logUsage, or split across both (constructor merged first — logUsage overrides overlapping keys.)
| Payload key (wire JSON) | Requirement | Notes |
| --- | --- | --- |
| activity_type | Required | e.g. LOGIN_ACTIVITY |
| source | Optional | Defaults to PRODUCT_CLOUD; override with ctor / logUsage / REO_PRODUCT_USAGE_SOURCE |
| environment | Optional | Defaults to PRODUCTION; override with ctor / logUsage / REO_PRODUCT_USAGE_ENVIRONMENT |
| user_id | Required | e.g. LinkedIn URL or stable id |
| user_id_type | Required | e.g. LINKEDIN |
| product_id | Required | e.g. reoWebApp |
| ip_addr | Optional | Omit on the customer-facing client if unknown; server-side code may fill when available |
| meta | Optional | Arbitrary JSON object |
| event_id | Auto if omitted everywhere | Omit on constructor and calls for a new id per send; only set once if you intentionally freeze it |
| event_at | Auto if omitted everywhere | Same as event_id |
| user_agent | Auto if omitted | SDK default or REO_PRODUCT_USAGE_USER_AGENT |
Constructor / logUsage option names: activityType → activity_type, userId → user_id, userIdType → user_id_type, productId → product_id, ipAddr → ip_addr, eventId → event_id, eventAt → event_at, userAgent → user_agent.
Usage
Your customer-facing Node service (web app, worker, agent, etc.) can mirror this contract. Equivalent curl:
curl --location 'https://ingest.reo.dev/api/product/usage' \
--header 'X-API-KEY: <API_KEY>' \
--header 'Content-Type: application/json' \
--data '{"payload":{...}}'Node: minimal (required fields only)
import { ReoProductUsageLogger } from "reo-census-mcp";
// REO_API_KEY in environment — omit apiKey
const logger = new ReoProductUsageLogger({
timeout: 3.0,
activityType: "LOGIN_ACTIVITY",
source: "PRODUCT_CLOUD",
environment: "PRODUCTION",
productId: "reoWebApp",
});
const ok = logger.logUsage({
userId: "https://www.linkedin.com/in/userid",
userIdType: "LINKEDIN",
});
// Omit blocking → false (non-blocking): default for customer-facing products and long-running apps.Node: full payload entirely on constructor (optional)
Use when the merged payload is fixed for this logger (REO_API_KEY env; no apiKey):
const logger = new ReoProductUsageLogger({
timeout: 3.0,
activityType: "LOGIN_ACTIVITY",
source: "PRODUCT_CLOUD",
environment: "PRODUCTION",
userId: "https://www.linkedin.com/in/userid",
userIdType: "LINKEDIN",
ipAddr: "156.59.87.83",
productId: "reoWebApp",
userAgent: "Mozilla/5.0 ...",
meta: { property1: "value1" },
});
await logger.logUsage({ blocking: true }); // or non-blocking logger.logUsage(); eventId / eventAt unset → auto-filled each sendNode: full payload (mix constructor + overrides on logUsage)
Assume you already constructed new ReoProductUsageLogger({...}) with steady product defaults:
Recommended for customer-facing products: blocking: false (omit it — that is the default). The POST runs asynchronously so you do not add latency on user-facing paths.
logger.logUsage({
activityType: "LOGIN_ACTIVITY",
source: "PRODUCT_CLOUD",
environment: "PRODUCTION",
userId: "https://www.linkedin.com/in/userid",
userIdType: "LINKEDIN",
ipAddr: "156.59.87.83",
eventId: 1231231232,
eventAt: 639303296,
productId: "reoWebApp",
userAgent: "Mozilla/5.0 ...",
meta: { property1: "value1", property2: "value2" },
});Awaited sends (blocking: true)
Only when you need the round-trip before the process exits (CLI, Cron, Lambda-style short workers, tests) — otherwise the event loop may unwind before a fire-and-forget request completes.
const logger = new ReoProductUsageLogger({ /* ... */, blocking: true });
await logger.logUsage();
// optional: synchronous one-shot on otherwise non-blocking instances
await logger.logUsage({ blocking: true });blockingon logger: Constructor sets the instance default (blocking: falsefor customer-facing throughput). OmitblockingonlogUsageto use it; passblocking: trueonlogUsageonly for one-off awaited sends.blocking: false:trueif queued,falseif opted out, invalid URL, missing API key, or body too large (not proof of HTTP 2xx).blocking: true: resolvedtrueonly after HTTP 2xx (with retries).
If you omit eventId / eventAt, they are filled automatically (event_id from a time-based integer, event_at as Unix seconds). If you omit userAgent on the call, the SDK sets a default (reo-census-mcp/<version> or REO_PRODUCT_USAGE_USER_AGENT).
API key
REO_API_KEY must be set in your deployment environment or secret manager, or you must pass a non-empty apiKey when constructing ReoProductUsageLogger. Empty or whitespace-only values are treated as missing.
Opt-out
Uses the same variables as reo-census so your customers (or admins running your customer-facing software) can turn off sending — document these in your privacy or deployment guide:
PACKAGE_TRACKER_ANALYTICS=falseDO_NOT_TRACKset to1,true, oryes(case-insensitive)
Endpoint override
export REO_CENSUS_MCP_ENDPOINT="https://your-host/api/product/usage"Only http:// and https:// URLs with a host are accepted.
Verbose logging
export PACKAGE_TRACKER_VERBOSE=truePrints send details to stderr.
