Skip to main content
Glama
J-X0

barrowman-associates-timeseries-mcp

by J-X0

barrowman-associates-timeseries-mcp

Project Oxbow. Timeseries anomaly analysis for fleet telemetry, delivered as an MCP server. Changepoint detection runs over every series for free; explaining a changepoint costs money, and each tenant has a hard monthly spend cap. The cap decides how many anomalies get explained.

The constraint drives the design

Operating spend is capped per tenant per month. That single rule shapes the pipeline:

  • Detection is free. detect_changepoints is pure-Python robust CUSUM. It runs over the full series for every tenant and never touches the budget.

  • Explanation is metered. Asking a model to explain a changepoint goes through ExplanationProvider, which quotes a per-call price in cents.

  • The budget rations explanation. The pipeline ranks changepoints most-severe first and explains them in order, charging each call against the tenant's remaining monthly balance in SpendLedger. When the balance can no longer cover a call, the rest are recorded as deferred -- never explained, never charged. The "anomaly budget" is exactly remaining_cents // price.

  • Every decision is auditable. AnomalyReport.audit has one row per changepoint: escalated or deferred, what it cost, and the remaining balance after.

Money is integer cents everywhere. Month buckets are UTC (YYYY-MM) so a cap boundary never moves with server timezone.

Related MCP server: MCP Server for vmanomaly

Layout

oxbowtimeseries/
  types.py          domain types (Point, Changepoint, Anomaly, AnomalyReport, TenantBudget)
  changepoint.py    robust CUSUM detector
  budget.py         SpendLedger, BudgetExceeded, month_key, refund -- the spend cap
  pipeline.py       AnomalyPipeline: detect -> rank -> ration -> audit
  validation.py     input validation at the tool boundary (ValidationError)
  config.py         JSON config load + validation, tenant caps (ConfigError)
  obs.py            structured JSON logging and timing
  service.py        AnalysisService: validate -> analyse -> log -> degrade
  server.py         FastMCP entry point exposing the analyze_series tool
  providers/
    base.py         ExplanationProvider interface, ExplanationRequest
    stub.py         deterministic offline provider (used by all tests)
    real.py         Anthropic-backed provider (optional 'real' extra)
tests/
config.example.json

Install and test

make venv
make install
make test

make test runs the whole suite offline against StubProvider; no API key is required. Override the interpreter with make test PY=/path/to/python.

Using the core library

Runnable as-is (a step from level 1 to level 40 halfway through the series):

from oxbowtimeseries import SpendLedger, TenantBudget, AnomalyPipeline, Point
from oxbowtimeseries.providers import StubProvider

ledger = SpendLedger()
pipeline = AnomalyPipeline(StubProvider(cost_cents=5), ledger)
# cap covers exactly one explanation at 5 cents/call
budget = TenantBudget("acme-fleet", monthly_cap_cents=5, cost_per_investigation_cents=5)

values = [1.0] * 20 + [40.0] * 20
series = [Point(t=1_772_323_200.0 + i * 60, value=v) for i, v in enumerate(values)]
report = pipeline.analyze(budget, "fuel_l_per_100km", series)

print(report.escalated_count, "explained,", report.deferred_count, "deferred")
for row in report.audit:
    print(row)

Running the server

The server speaks the MCP protocol over stdio and is driven by a JSON config file. config.example.json is a working starting point:

make run                      # uses config.example.json
# or
OXBOW_CONFIG=my.json .venv/bin/oxbow-timeseries
.venv/bin/oxbow-timeseries --config my.json

Config controls the provider, detector parameters, per-analysis limits, and every tenant's monthly cap. Caps live in config so they change without a redeploy. A malformed config fails at startup with a specific message and a non-zero exit code, not at request time.

The server exposes one tool, analyze_series(tenant_id, metric, points, month?), where points is a list of [unix_timestamp, value] pairs sorted by time. It returns the anomaly report (see AnomalyReport.to_dict) including the audit trail. Logs are single-line JSON on stderr (stdout is reserved for the MCP channel); set OXBOW_LOG_LEVEL to change verbosity.

Failure handling and degradation

  • Unknown tenant, bad points (wrong shape, NaN/inf, unsorted, over the point limit) are rejected at the boundary with a clear error.

  • Missing or invalid config exits non-zero at startup.

  • Provider outage degrades to a detection-only report: the reserved spend is refunded, the changepoints are still returned, and the audit rows read provider_error. The tenant is never billed for a call that produced nothing.

  • Concurrent analyses for one tenant cannot overspend: the ledger charges atomically and refuses once the cap is reached.

Configuration reference

The config is a JSON object. Unknown keys are ignored; every key below is validated at load time.

Key

Type

Required

Default

Notes

provider.kind

"stub" | "real"

yes

--

real needs ANTHROPIC_API_KEY and the real extra

provider.cost_cents

int ≥ 0

no

5

price charged per explanation

provider.model

string

no

claude-3-5-haiku-latest

used only by the real provider

tenants

object

yes

--

must be non-empty; keys are tenant ids

tenants.<id>.monthly_cap_cents

int ≥ 0

yes

--

the hard monthly spend cap

tenants.<id>.cost_per_investigation_cents

int ≥ 0

no

provider.cost_cents

per-tenant price override

detector.threshold

float > 0

no

5.0

CUSUM alarm level in robust sigmas

detector.drift

float ≥ 0

no

0.5

slack; smallest shift worth flagging is ~2*drift sigmas

limits.max_points

int > 0

no

100000

per-analysis point cap

Environment variables: OXBOW_CONFIG (config path, alternative to --config), OXBOW_LOG_LEVEL (default INFO), ANTHROPIC_API_KEY (real provider only).

Known limitations

  • Ledger is in-process. Spend state lives in memory and resets on restart. A restart mid-month gives every tenant a fresh cap. See ADR-0004 for why this was deferred and what replaces it (a shared store keyed by tenant+month).

  • One metric per call. The tool analyses a single named series; batching many metrics is left to the caller.

  • Detection favours sustained level shifts, not slow trends or seasonality. A gradual drift under 2*drift sigmas will not alarm. This is deliberate (ADR-0002); a metric with strong daily seasonality should be deseasonalised before analysis.

  • Ranking uses detection magnitude as the severity proxy. A large but operationally benign shift can outrank a small critical one; the budget then spends on the wrong anomaly. Severity weighting by metric is future work.

  • No retry on provider failure. A failed explanation refunds and defers rather than retrying, to keep spend bounded and latency predictable.

Architecture decisions

The contested calls are recorded as ADRs under docs/adr/:

  • ADR-0001 -- ration the expensive stage instead of refusing service at the cap

  • ADR-0002 -- robust CUSUM with a re-anchored baseline over PELT / Bayesian methods

  • ADR-0003 -- reserve-then-refund around provider calls

  • ADR-0004 -- in-process ledger for the first release

The real provider

RealProvider calls the Anthropic API and is never imported by the tests. Install it with the extra and set a key:

pip install -e ".[real]"
export ANTHROPIC_API_KEY=sk-...

Then pass RealProvider(...) where the example passes StubProvider().

Status

Detection, budget, pipeline, providers, config, validation, logging, the application service, and the FastMCP stdio server are implemented and tested. The ledger is in-process for now; persisting it to SQLite so caps survive a restart is the remaining known gap (see the budget.py module docstring).


Barrowman Associates is an illustrative client; this repository is a self-directed reference implementation built to work end to end.

Available Tools

1 tool
analyze_seriesA

Detect changepoints in a fleet metric and explain the most severe ones within the tenant's remaining monthly spend budget.

points is a list of [unix_timestamp, value] pairs sorted by time. Returns the anomaly report including a per-changepoint audit trail.

ParametersJSON Schema
NameRequiredDescriptionDefault
monthNo
metricYes
pointsYes
tenant_idYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It explains the input format (points as sorted [timestamp, value] pairs) and the output shape (anomaly report with per-changepoint audit trail), and hints at budget constraints affecting the analysis. This goes beyond a mere restatement of the tool name, though it does not discuss side effects like budget deduction or error behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the core purpose, followed by a necessary input format detail and a clear statement of the return value. Every sentence adds useful information, and there is no filler or repetition of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity, lack of annotations, and absent output schema, the description covers the main function, the points format, and the return type, but it leaves important contextual gaps unexplained: what 'spend budget' means in concrete terms, how severity is determined, and the exact structure of the anomaly report. It is viable but not fully complete for an agent making correct invocation decisions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description coverage is 0%, so the description must compensate for undocumented parameters. It explicitly explains the 'points' parameter and loosely ties 'metric' to 'fleet metric', but it provides no real semantics for 'tenant_id' or 'month', leaving two parameters underdocumented. This partial compensation is not sufficient for a four-parameter tool with no inline schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific action phrase 'Detect changepoints in a fleet metric' and details what makes this tool distinct: explaining the most severe changepoints subject to a spend budget. It names the resource (fleet metric) and the expected output (anomaly report with audit trail), so an agent can understand the tool's core function without ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies the tool is for changepoint detection within a cost-aware budget context, but it does not explicitly state when to choose this tool over alternatives or mention when not to use it. With no sibling tools listed, some of this pressure is relieved, but clear usage context such as prerequisites or complementary workflows is missing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev0.1.0
    • First observedanalyze_series

TDQS

A3.7/5.0

Scored across 1 tool

Disambiguation5/5

With only a single tool, there is no possibility of confusion between tool purposes. The analyze_series tool has a clear, specific mandate to detect and explain changepoints.

Naming Consistency5/5

The sole tool follows a clear verb_noun convention (analyze_series). No conflicting naming styles exist since there is only one tool.

Tool Count2/5

A single tool feels too few for a server branded as a timeseries MCP. The broader domain typically requires multiple operations, making the tool count significantly under-scoped.

Completeness2/5

The server offers only changepoint analysis and lacks supporting operations such as data retrieval, transformation, or lifecycle management. This creates significant gaps for workflows that require more than the single analysis.

Maintenance

ActivityInactive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    An MCP server that exposes GPU-accelerated anomaly detection to AI assistants via the Model Context Protocol. Provides two MCP tools: waveguard_scan (send training + test data in one call, returns per-sample anomaly scores and top explanatory features) and waveguard_health (check API and GPU status). Works on time series, JSON, numbers, text, and images — fully stateless.
    3
    4
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Exposes live industrial IoT telemetry to any MCP client, streaming simulated sensor data from a fleet of machines and detecting anomalies, with the ability to inject faults on demand.
    4
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables incident detection and analysis by identifying anomalies in metric time series and surfacing root-cause candidates and recommended actions. Supports both mock (synthetic) and VictoriaMetrics backends with identical MCP tool contracts for seamless development-to-production switching.
    MIT