Skip to content

Repository files navigation

event-contract-builder

An MCP server (with an underlying TypeScript schema library) for turning a free-form event description into trader-facing prediction market display questions and precise term definitions — the first steps of drafting an event contract for prediction markets.

Status

Early development; the public API and tool set may change before v1.0.0.

The MCP server is the working, demonstrable part of this project today. The schema library (src/schema) models a complete event-contract specification, but nothing in this repo yet turns a server-drafted question into one of those specs — see Library (schema) below.

MCP server

server/ runs a stateless HTTP MCP server exposing tools that draft display questions and definitions from free-form text.

Run it

bun install
bun run dev:server

This starts the server at http://localhost:8787/mcp and restarts on file changes.

Inspect it locally with the MCP Inspector:

bun run dev:server:inspect

To connect an external client (e.g. ChatGPT developer mode) to your local server, expose it over HTTPS:

bun run dev:server:tunnel

Tools

Tool Purpose
draft_display_questions Turn a free-form event description into binary/scalar/categorical display questions.
submit_drafted_questions Validate and register the drafted questions, organized into units, after they've been shown to the user.
define_terms Identify ambiguous terms in a selected question and propose precise definitions for each.
submit_defined_terms Validate and register the definitions for a selected question.

Two prompts, draft-display-questions and define-terms, expose the same guidance as inspectable prompt templates.

Workflow

  1. Draft — call draft_display_questions with a free-form event description, e.g. "CPI year-over-year inflation might exceed 3 percent in June 2026". The response groups the drafted questions by market type:

    **Scalar market**
    
    - Will CPI YoY be below 3 percent in June 2026?
    - Will CPI YoY be at least 3 percent in June 2026?
  2. Submit — call submit_drafted_questions with the same draft as structured units, to validate and register it:

    {
      "units": [
        {
          "type": "scalar",
          "questions": [
            "Will CPI YoY be below 3 percent in June 2026?",
            "Will CPI YoY be at least 3 percent in June 2026?"
          ]
        }
      ],
      "followUp": "Which unit should we use for further specification?"
    }
  3. Select and define — once the user picks a unit, call define_terms with that unit to get proposed definitions for its ambiguous terms (e.g. "CPI YoY", "June 2026").

  4. Submit definitions — call submit_defined_terms with the selected unit and the agreed definitions to validate and register them.

Library (schema)

src/schema models a complete event-contract specification — meta, underlying event, outcome, trading parameters, resolution, payout, integrity assessment, and compliance posture — as zod schemas, published as an npm package.

This library has no consumer in this repo yet. The MCP server above only drafts display questions and term definitions; nothing currently assembles those into a full EventContractSpec. Treat the example below as a standalone demonstration of the schema, not a description of an existing pipeline.

Installation

npm install event-contract-builder

Product name

Every contract has a trader-facing product name — a free-form question string (10–200 characters, ending with ?). Names are typically authored by agents/LLMs via prompt guidance rather than assembled from fixed slots, so the schema imposes only length and punctuation constraints.

const productName = "Will CPI YoY be at least 3 percent?";

Build and validate a full contract spec

A complete spec includes meta (with product name), underlying event, outcome, trading parameters, resolution, payout, integrity assessment, and compliance posture. The canonicalStatement is rendered from structured resolution fields — hand-written statements that drift from the structured terms fail validation.

The example below is condensed for readability: a few required blocks (scheduledResolutionTime, calculationMethodologyControls, fallbackControls, forceMajeure) are omitted where marked. See the schema for the full set of required fields.

import {
  EventContractSpec,
  renderCanonicalStatement,
  type EventContractSpecT,
} from "event-contract-builder";

const spec: EventContractSpecT = {
  dsl: "event-contract-cnl/0.1",
  meta: {
    ticker: "CPI-26JUN-T3.0",
    productName: "Will CPI YoY be at least 3 percent?",
    title: "CPI Year-over-Year Rate >= 3.0% (June 2026)",
    category: "economic-indicator",
    specVersion: "1.0.0",
    status: "draft",
    lastUpdated: "2026-06-18",
    authors: ["Product Team"],
  },
  underlying: {
    eventDefinition:
      "The U.S. Consumer Price Index for All Urban Consumers year-over-year percent change for the reference month of June 2026.",
    commodityClassification: {
      hypothesis: "excluded-commodity",
      rationale:
        "CPI is an occurrence beyond the parties' control with clear economic consequence, fitting CEA section 1a(19)(iv).",
    },
    underlyingMarketDescription:
      "The CPI is published monthly by the U.S. Bureau of Labor Statistics. It measures the average change over time in prices paid by urban consumers for a market basket of consumer goods and services. It is widely followed as the primary gauge of U.S. consumer inflation.",
    enumeratedActivityScreen: {
      activities: {
        unlawfulUnderFederalOrStateLaw: {
          settlementDeterminedByActivity: false,
          note: "",
        },
        terrorism: { settlementDeterminedByActivity: false, note: "" },
        assassination: { settlementDeterminedByActivity: false, note: "" },
        war: { settlementDeterminedByActivity: false, note: "" },
        gaming: { settlementDeterminedByActivity: false, note: "" },
        commissionDesignatedSimilarActivity: {
          settlementDeterminedByActivity: false,
          note: "",
        },
      },
      settlementOccurrenceAnalysis:
        "Settlement is determined by the value of a government-published economic indicator, which is a lawful measurement activity.",
      anyEnumeratedActivityInvolved: false,
    },
  },
  outcome: { type: "binary", values: ["Yes", "No"] },
  trading: {
    quotation: "cents-0-100",
    minTick: 1,
    tradingHours: "08:00-22:00 America/New_York, Mon-Fri",
    lastTradingTime: "2027-01-15T16:00:00-05:00",
    positionLimits: { mode: "position-limit", contracts: 25000 },
    settlementTiming:
      "Settlement occurs within two business days after final resolution is confirmed.",
  },
  resolution: {
    criterion: {
      kind: "threshold",
      metric: {
        name: "US CPI year-over-year rate",
        unit: "percent",
        extraction:
          "Read the annual percent change from the CPI-U all-items series (CUSR0000SA0) in the BLS CPI Summary table.",
        revisionPolicy: "first-published-value",
      },
      comparator: "greater-than-or-equal",
      threshold: 3,
    },
    canonicalStatement: "", // filled below by renderCanonicalStatement
    observationWindow: {
      start: "2026-01-01T00:00:00Z",
      end: "2026-12-31T23:59:59Z",
      timezone: "UTC",
    },
    sources: [
      {
        id: "bls-cpi",
        rank: 1, // unique, contiguous from 1; the rank-1 source must be primarySourceId
        controlsFor: ["headline value", "publication timing"],
        name: "Consumer Price Index",
        publisher: "U.S. Bureau of Labor Statistics",
        url: "https://www.bls.gov/cpi/",
        datasetId: "CUSR0000SA0",
        publicationSchedule:
          "Published monthly, typically around the 10th-14th of the following month.",
        publiclyAccessible: true,
        independenceNote:
          "The BLS is a principal federal statistical agency independent of market participants.",
      },
    ],
    primarySourceId: "bls-cpi",
    fallbacks: [],
    requiredPublicEvidence: [
      "The official BLS CPI Summary table for the reference month is published and publicly accessible.",
    ],
    correctionOrRevisionPolicy:
      "Apply only official BLS corrections published before the resolution deadline; revisions published after the deadline are disregarded.",
    materiality: {
      minimumQualifyingThreshold:
        "Only an official BLS CPI-U all-items release covering the full reference period qualifies as the settlement value.",
      deMinimisExclusions: [
        "Preliminary, flash, or unofficial CPI estimates from non-BLS aggregators do not qualify.",
      ],
    },
    exclusions: {
      prohibitedFeatures: [],
      nonQualifyingCases: [
        "A CPI value published by any source other than the BLS does not qualify.",
      ],
      antiRebrandingRule:
        "Classify the series by its published methodology and identifier, not by any renamed or successor label.",
    },
    resolutionDeadline: "2027-01-31T23:59:59Z",
    earlyResolution: { allowed: false },
    terminalAmbiguityPolicy: "void-and-refund",
    edgeCases: [
      {
        scenario:
          "If the BLS retracts the first published value before the resolution deadline.",
        disposition:
          "Use the corrected value published before the resolution deadline.",
      },
      {
        scenario:
          "If no CPI value is published before the resolution deadline.",
        disposition:
          "Apply the terminal ambiguity policy and void the contract.",
      },
      {
        scenario:
          "If the BLS renames the CPI series without changing methodology.",
        disposition:
          "Use the renamed successor series as the primary data source.",
      },
    ],
    disputeWindowHours: 24,
    // Omitted for brevity: scheduledResolutionTime, calculationMethodologyControls,
    // fallbackControls, forceMajeure — all required by the schema.
  },
  payout: {
    type: "binary",
    currency: "USD",
    contractSize: 1,
    yesPays: 1,
    noPays: 0,
  },
  integrity: {
    outcomeInfluenceAnalysis:
      "The CPI is computed from tens of thousands of sampled prices. No single participant can meaningfully influence the aggregate index.",
    informationAsymmetryAnalysis:
      "BLS employees are subject to federal confidentiality requirements. No private party receives advance access.",
    sourceRobustnessAnalysis:
      "The CPI has been published continuously since 1913 with publicly documented methodology resistant to short-term manipulation.",
    surveillanceConsiderations: [
      "Monitor for unusual position-building before CPI release dates.",
      "Watch for correlated trading across CPI-linked contracts on multiple venues.",
    ],
    overallSusceptibility: "low",
    mitigations: [],
  },
  compliance: {
    intendedVenue: "cftc-designated-contract-market",
    anticipatedListingPath: "part-40.2-self-certification",
    draftDisclaimer:
      "DRAFT for internal and counsel review only. Not a CFTC filing, not a Part 40 self-certification, and not legal advice.",
    openQuestionsForCounsel: [
      "Confirm excluded-commodity classification under CEA section 1a(19)(iv).",
    ],
    reviewedAgainst: ["17 CFR Part 38 Appendix C", "CEA 5c(c)(5)(C)"],
  },
};

// Render the canonical statement, then validate (once the omitted required
// blocks above are supplied, EventContractSpec.parse returns the typed spec).
const canonicalStatement = renderCanonicalStatement(spec);
const validated = EventContractSpec.parse({
  ...spec,
  resolution: { ...spec.resolution, canonicalStatement },
});

console.log(validated.meta.productName);
// → "Will CPI YoY be at least 3 percent?"

console.log(validated.resolution.canonicalStatement);
// → "This contract resolves YES if US CPI year-over-year rate, as published by
//    U.S. Bureau of Labor Statistics (Consumer Price Index), measured over the
//    period from 2026-01-01T00:00:00Z to 2026-12-31T23:59:59Z (UTC), is greater
//    than or equal to 3 percent, applying the first published value as of the
//    resolution deadline; otherwise it resolves NO."

Disclaimer

See DISCLAIMER.md for important information about the legal and regulatory status of outputs produced by this tooling.

License

Copyright © 2026 Christopher Maximilian Altmann. Licensed under the Apache License, Version 2.0.

About

MCP server for generating, validating, and converting YAML and JSON event contract specifications for prediction markets.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages