GASP

AI Tools

The GASP Standard ships as an MCP server, so Claude, Cursor or any other MCP client can look up the canonical definition of a metric, its formula and the data it needs. Ask it for a definition, a formula, the fields a metric needs or the SQL to compute it against your warehouse.

Quick Start

Install the MCP server with a single command:

Claude Code

claude mcp add gasp-standard -- npx -y gasp-standard-mcp

Claude Desktop / Cursor

Add to your MCP config file:

{
  "mcpServers": {
    "gasp-standard": {
      "command": "npx",
      "args": ["-y", "gasp-standard-mcp"]
    }
  }
}

Restart your MCP client after adding the config.

The package bundles the standard, so it runs offline. Release notes for each version are in the changelog.

MCP Server

A Model Context Protocol server that serves the whole standard as tools. Claude Code, Claude Desktop or an integration you write yourself can call them for metrics, formulas, relationships and definitions.

Tools

lookup_metric name: string

Full metric details: definition, the canonical GASP grammar formula, Operating and Market forms, the Adjusted variant where one exists, benchmarks, signal type, recommended sensitivity tier and access scope, common mistakes, sources and page URL. A name several departments share returns each candidate with its department. Falls back to glossary terms when no metric matches.

lookup_definition term: string

Glossary terms such as Signal Type, Sensitivity Tier, Access Scope and Metric Owner: full definition, reference link and page URL.

list_metrics department?: string, signalType?: string

List all metrics grouped by department and category, optionally filtered by department or signal type (outcome, leading, efficiency or operational).

get_formula metric: string

The canonical formula in the GASP formula grammar, with its unit, Operating and Market forms, named variants and breakdowns, the metrics, fields and datasets each form reads and the enum filters each form applies. Metrics that cannot be computed carry the reason.

get_relationships metric: string

Upstream (what drives it) and downstream (what it drives) connections from the GASP relationship graph, for a metric, an entity or a concept. For an entity it also lists every metric whose formula reads the entity's data.

get_data_requirements metric?: string, department?: string, breakdown?: string, dialect?: string

Data requirements for a metric or a department dashboard: each field the canonical formula reads with its type and the GASP dataset it comes from, whether the metric needs a staged dataset, reporting grain, source system and example SQL. Pass a breakdown the metric declares for one row per value, or a dialect for the SQL in your warehouse's syntax.

search query: string

Whole-word search over metric names, aliases, definitions and formulas, glossary terms and the fields each metric needs. Returns up to 10 results, one per metric or term, with name and alias hits ranked first and each hit's page URL. A misspelling returns the closest names as "Did you mean".

generate_query metric: string, adapter: string, semantic_model?: string, breakdown?: string, dialect?: string

Compile SQL for a metric from its canonical formula and your adapter mapping: one subquery per aggregate, each on the table you mapped to its GASP dataset. The dialect follows your adapter's warehouse (Postgres, Snowflake, BigQuery or Databricks; Postgres SQL also runs on Redshift) unless you pass one. Fields you have not mapped stay as {{field@dataset}} placeholders naming the dataset the column must come from. A breakdown returns one row per value.

validate_mapping adapter: string, semantic_model?: string

Validate a warehouse mapping in either format: a GASP adapter (JSON) or an Apache Ossie mapping document over your semantic model. An adapter is converted on load into an Ossie mapping. The report comes in layers: the schema, the cross-document checks against the GASP ontology, then coverage: unknown fields and datasets, fields mapped to a dataset that lacks them, datasets whose fields point at different tables, every metric scored as fully covered, partially covered or not covered, enum fields mapped without a transform, covered metrics with no declared owner and the next mappings to add. validate_adapter is the same tool under its original name.

compile_model adapter: string, semantic_model?: string, dialect?: string, metrics?: string, department?: string, period_spine?: string, output?: 'model' | 'report'

Compile the GASP metrics your mapping covers into your Apache Ossie semantic model. Same input as validate_mapping; returns your model with a gasp_ metric for every covered formula entry: a direct expression over your datasets and fields where the expression language can state it, else a staged per-period dataset whose source is the compiled SQL over your tables in your warehouse dialect, reading a period spine table you name. Entries with unmapped fields are listed with what they need, and recompiling replaces the earlier additions.

score_drift adapter: string, semantic_model: string, matches?: string, metrics?: string, output?: 'report' | 'json'

Score how far your own metrics drift from the canonical definitions, by result. Each metric in your semantic model is matched to a GASP metric by exact name, by the synonyms in its ai_context or by a pair you pass; near names are listed for review and never scored on a guess. The canonical metric is compiled into your dataset and field names and both run on the GASP synthetic SaaS dataset for six monthly periods, in an in-process Postgres. Where the numbers differ you get both values per period and the likely cause read from the canonical formula: a null on one side (a sum over no rows that is NULL in your SQL and 0 in GASP's), a cohort or opening value the expression cannot state, a filter one side applies, a dataset one side reads or an aggregate with no equal on the other side.

profile_schema schema: string, statistics?: string, organization?: string, output?: 'report' | 'model' | 'json' | 'statistics'

Profile your warehouse schema into a minimal Ossie semantic model, the first step towards a mapping. Pass the rows of information_schema.columns (JSON or CSV), a tables list or CREATE TABLE statements, read through your own warehouse MCP or from a dump, and optionally statistics per column; output: statistics returns the query that gathers them. Every table gets a key, a time field and a kind (snapshot, event, fact or reference) with the evidence and a confidence, plus the relationships the columns imply. What the names cannot settle is listed as a question for you rather than guessed. The model comes back as YAML to pass on as semantic_model.

propose_mapping semantic_model?: string, schema?: string, statistics?: string, organization?: string, output?: 'report' | 'mapping' | 'model' | 'adapter' | 'json'

Propose a GASP mapping from the model profile_schema returned, your own Ossie model or a schema profiled on the way in. Every table is scored against the GASP datasets on its columns, its profiled kind, key and time field and its name; every column of a proposed table against the dataset's fields by name, structural role, a short synonym list, word order and near names, checked against the type and the listed values. A column in cents gets a divide-by-100 transform and values the standard does not use a CASE recode when one is known. High-confidence pairs become an Ossie mapping over the model, ready for validate_mapping; medium ones are listed as candidates with their evidence and what would settle them.

record_decision semantic_model: string, mapping: string, decisions?: string, output?: 'report' | 'mapping' | 'model' | 'json'

Record the decisions people make on a proposed mapping, each named by content with its owner and date: a profiler question answered (the key, the time field, the kind or a datatype, written into the model), a candidate accepted or rejected (a table as a GASP dataset with its columns matched as the proposer would, a column as a GASP field with an optional transform), a metric owner (the slot validate_mapping reads) or a judgement call GASP cannot apply, such as the reporting currency or what date marks churn. Every decision lands in the mapping's GASP extension; a later one on the same subject replaces it. With no decisions it lists what is still open and whether readiness level 2 is reached.

derive_cel adapter: string, currency: string, semantic_model?: string, dialect?: string, first_snapshot?: 'opening' | 'steps', output?: 'report' | 'sql'

SQL that derives CEL Revenue_Event rows from your subscription ledger, by the rules in the CEL. Most billing systems hold subscriptions, not events: the subscription dataset your mapping covers, as snapshots at any cadence or a version history, becomes one event per movement, with the customer's prior_mrr and new_mrr chained so the row identity holds, the event type read from the customer's MRR around the step and the ATL lifecycle tag set. The ledger cannot say what kind of expansion it was, so expansion_classification stays empty for your amendment records to fill. Same mapping input as generate_query, plus the ledger's currency; the dialect comes from the request or your warehouse, and unmapped fields are listed.

generate_checks adapter: string, semantic_model?: string, dialect?: string, window?: number, as_of?: string, results?: string, output?: 'report' | 'sql' | 'json'

The readiness checks the standard states, as SQL over the datasets your mapping covers: CEL row identity, MRR continuity, unique event ids, the three ATL tags, customer identity both ways and freshness per dataset, one statement with one row per check. GASP has no warehouse access, so you run it and paste the rows back as results; the tool then reports pass or fail per check and per metric, each check naming the metrics whose formulas read what it covers. Same mapping input as generate_query.

plan_fixes adapter: string, semantic_model?: string, dialect?: string, results?: string, limit?: number, output?: 'report' | 'json'

The ranked fix list: every unmapped field and every failing check, ordered by Core metrics unlocked, then all metrics unlocked, with an effort class (small, medium, large) shown and used only as a tiebreak. A fix unlocks a metric when it is the last thing between that metric and covered-and-passing. Pass the results from generate_checks to rank data fixes beside mapping gaps.

infer_drivers metric: string, direction: 'up' | 'down', maxDepth?: number

Diagnose what could explain an observed metric movement. Walks the graph in reverse and returns ranked upstream candidates with full path and per-step edge classifications. A metric read only as a baseline (at period start, as MRR is in NRR) is listed as a component and the walk stops there. It reasons from the graph's structure and makes no numeric forecast.

explain_path from: string, to: string, maxDepth?: number

Enumerate up to five forward edge chains from one metric or node to another, with the edge type and classification (metric_signal, structural, lifecycle, behavioral, assignment or generative) of each step.

coverage_gap metrics: string[]

Audit a metric set: one-hop upstream and downstream metrics missing from the set, plus metrics with no path to it. Run it before instrumenting a dashboard.

Use Cases

Data Engineer

"What fields and types do I need to track Net Revenue Retention (NRR)?"

Use get_data_requirements to get the exact field schema, types, grain and starter SQL for any metric or department.

Analyst

"How is Customer Acquisition Cost (CAC) Payback calculated?"

Use get_formula and lookup_metric to get the canonical formula, benchmark ranges and common calculation mistakes to avoid.

Team Lead

"What metrics should my CS team track?"

Use list_metrics to see every metric for a department, then get_data_requirements to plan the implementation.

RevOps Lead

"Annual Recurring Revenue (ARR) is down this month. Why?"

Use infer_drivers to get a ranked list of upstream candidates whose movement is consistent with the observation, then explain_path to check each link in the chain.

Example Output

What get_data_requirements returns for NRR, with the description, staged and URL lines left out. The table lists each field with the GASP dataset it is read from, one row per pair, as the tool does. The fields, grain and SQL are compiled from the canonical NRR formula. The table names in the SQL are GASP datasets, which generate_query swaps for your own tables.

### Net Revenue Retention (NRR)
Field Dataset Type
customer_idcustomerstring
customer_idrevenue_eventstring
customer_idsubscriptionstring
customer_statuscustomerstring
event_daterevenue_eventdate
event_typerevenue_eventstring
mrrsubscriptiondecimal
mrr_changerevenue_eventdecimal
snapshot_datecustomerdate
snapshot_datesubscriptiondate
subscription_statussubscriptionstring
Grain: Customer cohort at period start   Frequency: Monthly   Source: Billing
Example SQL
SELECT (CAST((((((SELECT COALESCE(SUM(mrr), 0) FROM subscription WHERE snapshot_date = :period_start AND subscription_status = 'active' AND customer_id IN (SELECT customer_id FROM customer WHERE snapshot_date = :period_start AND customer_status = 'active'))) + ((SELECT COALESCE(SUM(mrr_change), 0) FROM revenue_event WHERE event_date >= :period_start AND event_date <= :period_end AND event_type = 'expansion' AND customer_id IN (SELECT customer_id FROM customer WHERE snapshot_date = :period_start AND customer_status = 'active')))) - ((-(SELECT COALESCE(SUM(mrr_change), 0) FROM revenue_event WHERE event_date >= :period_start AND event_date <= :period_end AND event_type = 'contraction' AND customer_id IN (SELECT customer_id FROM customer WHERE snapshot_date = :period_start AND customer_status = 'active'))))) - ((-(SELECT COALESCE(SUM(mrr_change), 0) FROM revenue_event WHERE event_date >= :period_start AND event_date <= :period_end AND event_type = 'churn' AND customer_id IN (SELECT customer_id FROM customer WHERE snapshot_date = :period_start AND customer_status = 'active'))))) AS DOUBLE PRECISION) / NULLIF(((SELECT COALESCE(SUM(mrr), 0) FROM subscription WHERE snapshot_date = :period_start AND subscription_status = 'active' AND customer_id IN (SELECT customer_id FROM customer WHERE snapshot_date = :period_start AND customer_status = 'active'))), 0)) AS nrr

MCP data at a glance

306
Metrics
94
Definitions
279
Data reqs
100
Nodes
200
Edges

Knowledge Graph

Underneath the metric pages the GASP Standard is a model of a SaaS business: the metrics, the business entities they measure, the data fields they read and the source systems those fields come from. You can download the model as a Cypher file and import it into Neo4j or any property graph database.

What's in the graph

65
Metric nodes
28
Entity nodes
52
Dataset nodes
268
Field nodes
22
Source categories

Node types

The graph contains six types of nodes:

:Metric 65 nodes

A metric in the relationship graph, with its definition, canonical formula, department, signal type, level and reporting period.

:Entity 28 nodes

A canonical business object such as Customer, Subscription, Opportunity, Ticket, Invoice or Incident (28 in all). A metric points at the entity it tracks with a MEASURES edge.

:Concept 7 nodes

An aggregation or classification that sits between entities and metrics, such as Revenue, Bookings, Cohort or Pipeline.

:Dataset 52 nodes

A logical table (event, snapshot or fact) with a date field and a key field. The five event tables behind the Commercial Event Ledger also carry their CEL class. Each Field BELONGS_TO a Dataset.

:Field 268 nodes

A canonical data field (e.g., customer_id, mrr_start). Your warehouse columns map to these.

:SourceCategory 22 nodes

A kind of source system, such as Billing, CRM or Product Analytics, named without a vendor so "Billing" can be Stripe, Chargebee or Zuora.

Metric node properties

Every metric node includes:

Property Type Description
idstringUnique identifier (snake_case)
namestringGASP canonical display name
departmentstringGASP department (Core, Sales, Marketing, ...)
signalTypestringoutcome, leading, efficiency or operational
definitionstringCanonical GASP definition text
levelintegerPosition in the metric hierarchy (1 is the top)
formulastringCanonical formula in the GASP formula grammar
grainstringReporting grain (e.g. end-of-month snapshot)
frequencystringHow often the metric is refreshed
periodstringReporting period the formula covers
urlstringLink to full definition on gaspwiki.com

Relationship types

21 canonical types used in both the interactive graph (lowercase) and the Cypher file (UPPERCASE). The Cypher file also includes SOURCED_FROM for Field → SourceCategory data lineage edges.

Metric signal
DRIVES A positively influences B. Improving A improves B
REDUCES A negatively influences B. A going up causes B to go down
PREDICTS A is a leading indicator of B. Changes in A forecast changes in B
COMPONENT_OF A is a mathematical input to B's formula
MEASURES Metric tracks the state or behaviour of a business entity. "Logo Churn MEASURES Customer"
Entity lifecycle
CONVERTS_TO Entity transitions through a funnel stage. Lead → Opportunity → Customer
PARENT_OF Hierarchical containment. Parent account contains child accounts
BELONGS_TO Entity is a member of a group or classification. Customer belongs to Cohort or Segment
Entity ownership and access
OWNS Customer owns Subscription
GRANTS Subscription grants License
PRICED_BY Determined by a Plan
Entity interactions
MANAGES Employee manages Customer
SERVES Project serves Customer
ENGAGES_VIA Customer engages via User
SUBMITS Customer submits Ticket
REPRESENTED_BY Customer represented by Contact
SOURCES Partner sources Opportunity. Campaign sources Lead
Entity financial flows
GENERATES Subscription generates Revenue or Invoice
PRODUCES Opportunity produces Bookings or TCV
CONTRIBUTES_TO Opportunity contributes to Pipeline
INCURS Subscription incurs COGS

Import into Neo4j

Download the Cypher file and import it via the Neo4j Browser or cypher-shell:

cat gasp-knowledge-graph.cypher | cypher-shell -u neo4j -p password

Or paste the file contents directly into the Neo4j Browser query editor.

Example queries

What drives ARR?
MATCH (driver)-[:DRIVES|COMPONENT_OF*1..3]->(arr:Metric {id: 'arr'})
RETURN driver.name, driver.department
What does churn affect?
MATCH (churn:Metric {id: 'logo_churn_rate'})-[r]->(affected)
RETURN type(r), affected.name, affected.department
Leading indicators for outcomes
MATCH (leading:Metric {signalType: 'leading'})-[:PREDICTS]->(outcome)
RETURN leading.name, outcome.name
Metrics that measure Customers
MATCH (m:Metric)-[:MEASURES]->(e:Entity {id: 'customer'})
RETURN m.name, m.department, m.signalType
Fields sourced from Billing
MATCH (f:Field)-[:SOURCED_FROM]->(s:SourceCategory {id: 'billing'})
RETURN f.id, s.name

Apache Ossie export

The standard is also published as Apache Ossie (incubating) files: the ontology, a reference semantic model and the mapping, validated against the upstream Apache Ossie validator in CI. A coverage report lists which metrics the semantic model expresses directly and which need a staged dataset. The downloads page describes each file, the counts and how to run the validator.

Adapter

The GASP Adapter is a JSON mapping file that connects your warehouse columns to the 268 canonical GASP fields. Name the warehouse table behind each GASP dataset and the column for each field, then validate to see which metrics you can compute.

Start from the template and schema below, then run the validate_adapter MCP tool to check your coverage.

Try searching for:

↑↓navigate↵select