Skip to main content

Overview

H.A.R.V.E.Y. (Holistic Analysis and Regulation Virtual Expert for You) is an AI agent that orchestrates pricing analysis workflows using the ReAct (Reasoning + Acting) pattern. Rather than relying solely on LLM knowledge, Harvey grounds its responses in structured data and mathematical solvers.
Harvey acts as an MCP client, launching the Pricing MCP server via stdio and calling its tools to execute pricing workflows. This architecture ensures Harvey can reason about pricing without requiring API keys in the MCP server itself.

The ReAct Pattern

ReAct is an agent architecture that interleaves reasoning and action:
1

Reason

The agent analyzes the user’s question and determines what information is needed
2

Plan

The agent creates a plan of tool invocations to gather the required data
3

Act

The agent executes the plan by calling MCP tools
4

Synthesize

The agent combines tool results with context to generate the final answer
This pattern reduces hallucinations by delegating mathematical operations and data queries to specialized systems (CSP solvers, analysis engines) while using the LLM for natural language understanding and synthesis.

How Harvey Works

Harvey’s workflow consists of two main phases:

Phase 1: Planning

When a user asks a question, Harvey:
  1. Extracts context from the question (URLs, uploaded YAML files)
  2. Fetches Pricing2Yaml content if needed (via iPricing tool)
  3. Grounds feature names by examining the actual YAML structure
  4. Constructs a plan with specific tool invocations and filters
{
  "actions": [
    "iPricing",
    {
      "name": "optimal",
      "objective": "minimize",
      "solver": "minizinc",
      "pricing_url": "https://buffer.com/pricing",
      "filters": {
        "features": ["hashtagManager"],
        "usageLimits": {
          "socialChannelsLimit": 10
        }
      }
    }
  ],
  "requires_uploaded_yaml": false,
  "use_pricing2yaml_spec": false
}
Grounding is Critical: Harvey must examine the actual YAML content to identify correct feature and usage limit names. For example, one SaaS might call SSO “Single Sign-On” while another uses “SSO”. Harvey grounds its filters in the actual schema.

Phase 2: Execution and Answer Generation

After planning, Harvey:
  1. Validates the plan (checks for required YAML uploads, valid tool names)
  2. Executes actions sequentially through MCP tool calls
  3. Collects results from each tool invocation
  4. Synthesizes an answer by combining:
    • Tool outputs (quantitative data)
    • Pricing context (YAML content for descriptions)
    • User’s original question
# From agent.py:1058-1098
async def _run_single_action(
    self,
    *,
    action: PlannedAction,
    url: Optional[str],
    objective: str,
    yaml_content: Optional[str],
) -> Dict[str, Any]:
    resolved_objective = action.objective or objective
    effective_solver = action.solver or "minizinc"
    
    if action.name == "summary":
        return await self._workflow.run_summary(
            url=url, yaml_content=yaml_content, refresh=False
        )
    if action.name == "iPricing":
        return await self._workflow.run_ipricing(
            url=url, yaml_content=yaml_content, refresh=False
        )
    if action.name == "subscriptions":
        return await self._workflow.run_subscriptions(
            url=url or "",
            filters=action.filters,
            solver=effective_solver,
            refresh=False,
            yaml_content=yaml_content,
        )
    if action.name == "validate":
        return await self._workflow.run_validate(
            url=url, yaml_content=yaml_content,
            solver=effective_solver, refresh=False
        )
    return await self._workflow.run_optimal(
        url=url or "",
        filters=action.filters,
        solver=effective_solver,
        objective=resolved_objective,
        refresh=False,
        yaml_content=yaml_content,
    )

Available Tools

Harvey can invoke five MCP tools:

iPricing

Retrieves the Pricing2Yaml document from a URL or returns uploaded content

summary

Provides high-level statistics (feature counts, plan counts, price ranges)

subscriptions

Enumerates all valid subscription configurations matching filters

optimal

Finds the best (cheapest/most expensive) configuration satisfying constraints

validate

Checks mathematical and logical consistency of a pricing model

Filter Construction

A key capability of Harvey is translating natural language requirements into structured filters.

Filter Schema

interface FilterCriteria {
  minPrice?: number;              // Minimum acceptable price
  maxPrice?: number;              // Maximum acceptable price  
  maxSubscriptionSize?: number;   // Max items (plan + add-ons)
  features?: string[];            // Required features (exact names)
  usageLimits?: Record<string, number>;  // Min values for limits
}

Natural Language to Filters

Harvey translates user requirements:
"Find the cheapest Buffer plan with hashtag management and at least 10 channels"
Grounding Example: Harvey reads Buffer’s YAML and finds:
  • Feature name is hashtagManager (not “hashtag management”)
  • Usage limit name is socialChannelsLimit (not “channels” or “channelLimit”)
Harvey uses the exact YAML keys in filters to ensure CSP solvers understand them.

Filter Semantics

minPrice
number
Lower bound on total subscription cost (plan + selected add-ons)
maxPrice
number
Upper bound on total subscription cost
maxSubscriptionSize
number
Maximum number of items in the subscription (1 plan + N add-ons). Useful for limiting complexity.
features
array
List of feature names that must be present (value = true) in the resulting subscription. Names must match feature.name from the YAML exactly.
usageLimits
object
Map of usage limit names to minimum threshold values. The subscription’s effective limit must be >= the specified value. For boolean features modeled as limits, use 1 to require them.

Multi-Context Reasoning

Harvey can reason about multiple pricing models simultaneously (e.g., comparing SaaS A vs. SaaS B).

Per-Context Grounding

When handling multiple pricings:
1

Separate Actions

Harvey creates separate actions for each pricing source
2

Context-Specific Filters

Filters for SaaS A use SaaS A’s exact feature/limit names. Filters for SaaS B use SaaS B’s names.
3

Explicit pricing_url

Each action specifies which pricing to analyze via the pricing_url field
4

Comparison

Harvey synthesizes results across contexts in the final answer
{
  "actions": [
    {
      "name": "optimal",
      "pricing_url": "https://buffer.com/pricing",
      "objective": "minimize",
      "filters": {
        "features": ["hashtagManager"],
        "usageLimits": {"socialChannelsLimit": 10}
      }
    },
    {
      "name": "optimal",
      "pricing_url": "https://hootsuite.com/pricing",
      "objective": "minimize",
      "filters": {
        "features": ["bulkScheduling"],
        "usageLimits": {"socialProfiles": 10}
      }
    }
  ]
}
Never assume two SaaS platforms use the same schema. Harvey examines each pricing model independently and constructs context-specific filters.

MCP Client Architecture

Harvey implements the Model Context Protocol client specification:
# From harvey_api/README.md:42-47
## MCP compliance overview

HARVEY acts as an MCP client and follows the 20250618 spec:

- Calls server tools with structured JSON arguments and expects JSON content 
  blocks in responses.
- Reads server resources using `resources/read` 
  (e.g. `resource://pricing/specification`).
- Does not advertise optional client capabilities for roots, sampling, or 
  elicitation; these can be enabled in a future iteration if servers require 
  them. Planning and LLM usage happen client‑side.
Harvey launches the MCP server as a subprocess:
# Harvey spawns the MCP server via stdio transport
import subprocess

process = subprocess.Popen(
    [python_executable, "-m", "pricing_mcp"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    env={"ANALYSIS_BASE_URL": "...", "AMINT_BASE_URL": "..."},
)

# Harvey sends JSON-RPC requests to stdin
# and reads tool results from stdout

Optimization: Reducing Hallucinations

Harvey’s design minimizes LLM hallucinations through:

Grounding

All feature names, limits, and prices come from the actual YAML, not LLM knowledge

Delegation

Mathematical operations (finding optimal plans, counting configurations) are delegated to CSP solvers

Structured Outputs

Plans and tool responses use JSON schemas, not free-form text

Verification

Harvey validates plans before execution (checks tool names, filter schemas, solver options)

Example: Why Grounding Matters

Without Grounding (Hallucination Risk):
User: "Find Buffer plans with SSO"
LLM: Generates filter {"features": ["SSO"]}
CSP Solver: ERROR - Feature "SSO" not found in YAML
With Grounding (Harvey’s Approach):
User: "Find Buffer plans with single sign-on"
Harvey: Reads Buffer YAML, finds no feature named "SSO" or "single sign-on"
Harvey: Examines descriptions, finds no authentication-related features
Harvey: Returns "Buffer's pricing model does not include SSO as a feature"

Configuration

Harvey’s behavior is controlled by environment variables:
OPENAI_API_KEY
string
required
API key for LLM access (planning and answer generation)
OPENAI_MODEL
string
default:"gpt-4o"
Model to use for reasoning (e.g., gpt-4o, gpt-5.2)
MCP_SERVER_MODULE
string
default:"pricing_mcp.mcp_server"
Python module to launch for MCP server
MCP_PYTHON_EXECUTABLE
string
Path to Python binary for MCP server subprocess
MCP_EXTRA_PYTHON_PATHS
string
Additional PYTHONPATH entries for MCP server

Usage Example

Here’s how Harvey processes a real question:
1

User Question

“What is the cheapest Buffer plan that includes 10 channels?”
2

Planning Phase

Harvey:
  1. Detects URL https://buffer.com/pricing (implicitly from context)
  2. Plans iPricing action to fetch YAML
  3. Reads YAML, finds socialChannelsLimit usage limit
  4. Plans optimal action with {"usageLimits": {"socialChannelsLimit": 10}} filter
  5. Sets objective: "minimize"
3

Execution Phase

Harvey:
  1. Calls iPricing(pricing_url="https://buffer.com/pricing")
  2. Calls optimal(pricing_url=..., filters={...}, objective="minimize")
  3. Receives result: {"optimal": {"subscription": {"plan": "AGENCY", "addOns": []}, "cost": 120.0}}
4

Answer Generation

Harvey synthesizes:“The cheapest Buffer plan that includes 10 channels is the AGENCY plan at **120/month(or120/month** (or 100/month if paid annually). The AGENCY plan includes 10 channels by default, making it the most cost-effective option for your requirement. The ESSENTIALS and TEAM plans only include 1 channel each and would require 9 additional channel add-ons, making them more expensive.”

Next: CSP Analysis

Learn how constraint satisfaction solvers validate and optimize pricing configurations

Further Reading

MCP Protocol

Model Context Protocol specification

API Endpoints

Harvey’s HTTP interface

ReAct Paper

Original ReAct research

Source Code

Harvey implementation

Build docs developers (and LLMs) love