Skip to main content
Glama
WillHsiaoNYC

NYC Open Data Capital Projects MCP Server

by WillHsiaoNYC

project_portfolio

Read-onlyIdempotent

Filter NYC capital projects by category, borough, agency, or lifecycle status, then list them by nearest completion with schedule and budget summaries.

Instructions

Cross-section listing of projects (PIDs): filter by category (see list_categories), borough, community_board, lifecycle_status ('in_progress'|'completed'|'cancelled'), and/or agency (+agency_role lens); rows ordered by nearest completion date (NULLs last). Each row carries schedule state + attributed_budget; summary covers the FULL filtered set and reports BOTH budget bases (per-PID attributed vs deduped line_budget_total). Borough matches the PID's boroughs LIST, so multi-borough projects are found by any of their boroughs. Rows carry forecast_past_due — a forecast already past as of the observation period (never true for completed/cancelled). population_scope 'latest_known' (default) uses each PID's own latest row; 'current' uses values at the selected complete snapshot. Rows expose reporting_period and current-snapshot presence. category_scope 'current' uses current links; 'all_history' includes former category links.

Interpretation rules:

  • [relationships] "Project" is ambiguous: PID identifies a SCHEDULE; FMS ID identifies a BUDGET. They are MANY-TO-MANY: a budget can fund several PIDs and a PID can have several budgets. LIST ALL linked counterparts; never silently select one. One linked counterpart does not establish a 1:1 relationship in the reverse direction. A budget without a PID is normal before Design and for lines that do not require schedules; absence alone does not establish missing data. Source-only schedules can also lack dashboard funding links.

  • [population] Listings/rankings default to population_scope='latest_known' (each entity's own latest observation). Use population_scope='current' for the selected complete snapshot. State the population_scope and observation period; respect present_in_current_snapshot. Detail tools use latest-known state and each anchor's latest available link period; these links are not proof of presence in the current complete snapshot.

  • [presence] Presence in a selected reporting snapshot means reportable at that period. There is no separate active flag. Historical presence or a latest-known row does not prove presence in the current complete snapshot. A completed project can retain an open budget line for years; presence does not mean construction is in progress.

  • [agency_roles] Agency attribution is role-aware: an agency's projects mean its sponsor (owner) view, except DDC/DCAS/EDC default to managing (builder). State the returned agency_scope. managing_agency is the executor on schedules and the budget-holder on budgets; a budget-only holder is not a schedule executor. list_agencies exposes is_schedule_executor. For sponsor-scoped budget totals, use a semi-join to fms_sponsor; a value-bearing join can multiply lines. Co-owner totals can overlap and must not be added together.

  • [categories] Classify with the curated category_dim, not project-name searches: specific ten-year labels/FMS prefixes precede sponsor routing, then generic facility keywords and Other. Categories key on (managing_agency, fms_id); institution owner rules can use all-history ownership. Schedule category_scope='current' uses each PID's current funding links; 'all_history' includes former links. A PID can count in multiple categories, so schedule category counts are non-additive; each budget line has one category.

  • [funding_totals] attributed_budget counts a funding line fully on every PID it funds; it is not an allocated share or an independent project cost. Summing it across PIDs can double-count shared funding. For the portfolio's distinct funding total use summary.line_budget_total, which counts each (managing_agency, fms_id) once. State which budget basis is reported.

  • [lifecycle] Lifecycle: Pre-Design -> Design -> Construction Procurement -> Construction -> Close-out. Schedule progression is reported from Design through Construction. Forecasts and most actual milestones can be suppressed outside those phases; actual_construction_end is the exception and means substantial completion. NULL milestones need not mean missing data. Budget spend%=100 does not prove completion. forecast_past_due is evaluated as of the observation period, not today's date.

  • [location] Location belongs to the BUDGET LINE, represented by fms_location. A PID inherits its funding-line boroughs: one specific borough takes precedence over Citywide, multiple specific boroughs yield 'Multiple', and only Citywide lines yield 'Citywide'. Preserve the boroughs list when several boroughs apply.

  • [signed_values] Report neutral, SIGNED changes: "moved 45 days later" or "budget decreased $2M". Do not echo loaded terms in the answer. "slippage" means positive schedule change and "overrun" means positive budget growth; neither includes the decreasing side. Preserve the returned direction and metric basis.

  • [schedule_coverage] Schedule totals and cumulative variance use dashboard-aligned schedule_history. source_schedule_history retains native observations absent from that population; schedule_source_coverage reconciles them. State the schedule universe and cumulative basis. Parenthesized phases are no-schedule reasons. Respect excluded variance artifacts and missing/invalid-duration counts; forward duration statistics exclude reversed dates.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nNo
agencyNo
boroughNo
categoryNo
agency_roleNoauto
category_scopeNocurrent
community_boardNo
lifecycle_statusNo
population_scopeNolatest_known

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
rowsYes
notesYes
summaryYes
truncatedYes
provenanceYes
interpretation_rulesYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed7 schema fields changedv0.1.1
    • addedInput schema / properties / agency_role / enum
      Added value: +[
      +  "auto",
      +  "sponsor",
      +  "managing"
      +]
    • addedInput schema / properties / category_scope
      Added value: +{
      +  "default": "current",
      +  "enum": [
      +    "current",
      +    "all_history"
      +  ],
      +  "title": "Category Scope",
      +  "type": "string"
      +}
    • changedInput schema / properties / lifecycle_status / anyOf
      Previous value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "enum": [
      +      "in_progress",
      +      "completed",
      +      "cancelled"
      +    ],
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • addedInput schema / properties / n / maximum
      Added value: +500
    • addedInput schema / properties / n / minimum
      Added value: +1
    • addedInput schema / properties / population_scope
      Added value: +{
      +  "default": "latest_known",
      +  "enum": [
      +    "latest_known",
      +    "current"
      +  ],
      +  "title": "Population Scope",
      +  "type": "string"
      +}
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$defs": {
      +    "InterpretationRule": {
      +      "properties": {
      +        "id": {
      +          "description": "Stable identifier of the domain rule.",
      +          "title": "Id",
      +          "type": "string"
      +        },
      +        "text": {
      +          "description": "Guidance for interpreting and reporting this tool's result.",
      +          "title": "Text",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "id",
      +        "text"
      +      ],
      +      "title": "InterpretationRule",
      +      "type": "object"
      +    }
      +  },
      +  "additionalProperties": true,
      +  "properties": {
      +    "interpretation_rules": {
      +      "items": {
      +        "$ref": "#/$defs/InterpretationRule"
      +      },
      +      "title": "Interpretation Rules",
      +      "type": "array"
      +    },
      +    "notes": {
      +      "items": {
      +        "type": "string"
      +      },
      +      "title": "Notes",
      +      "type": "array"
      +    },
      +    "provenance": {
      +      "additionalProperties": true,
      +      "title": "Provenance",
      +      "type": "object"
      +    },
      +    "rows": {
      +      "items": {
      +        "additionalProperties": true,
      +        "type": "object"
      +      },
      +      "title": "Rows",
      +      "type": "array"
      +    },
      +    "summary": {
      +      "additionalProperties": true,
      +      "title": "Summary",
      +      "type": "object"
      +    },
      +    "truncated": {
      +      "title": "Truncated",
      +      "type": "boolean"
      +    }
      +  },
      +  "required": [
      +    "provenance",
      +    "interpretation_rules",
      +    "rows",
      +    "summary",
      +    "truncated",
      +    "notes"
      +  ],
      +  "title": "PortfolioResult",
      +  "type": "object"
      +}
  2. First observedv0.1.0

TDQS

A4.5/5.0
Behavior5/5

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

Annotations only cover safety (readOnly, idempotent, non-open-world; no destructiveHint). The description goes far beyond that, disclosing double-counting semantics of attributed_budget, that summary covers the FULL filtered set under two budget bases, the forecast_past_due definition, multi-borough matching, signed-value reporting conventions, and suppression rules for milestones. This is unusually deep behavioral disclosure for a read-only tool.

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

Conciseness3/5

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

The purpose and parameter semantics are front-loaded effectively, but the body is nine dense interpretation blocks, much of which reads as dataset-wide doctrine rather than tool-specific guidance, and some of it restates itself (population_scope and presence are covered across three separate blocks). Justified by complexity, yet well past the point where every sentence clearly earns its place.

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

Completeness5/5

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

An output schema exists, so return values need not be enumerated, and the description still identifies the key returned fields (schedule state, attributed_budget, forecast_past_due, reporting_period, current-snapshot presence). Given 9 parameters, 0% schema coverage, and a highly relational domain (PID vs FMS ID many-to-many), the interpretation rules close the gaps an agent would otherwise hit.

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

Parameters4/5

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

Schema coverage is 0%, so the schema contributes no meaning at all and the description must carry it. It explains borough (matches the PID's boroughs LIST, Citywide/Multiple precedence), category_scope, population_scope, agency + agency_role lens, and lifecycle_status enum values, but leaves 'community_board' as a bare filter name and says nothing about 'n' (row cap, max 500).

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 first clause states a specific verb+resource ('Cross-section listing of projects (PIDs)') and enumerates the exact filters the agent can apply. It explicitly routes the reader elsewhere for enumerations ('see list_categories', 'list_agencies exposes is_schedule_executor') and implicitly contrasts with 'Detail tools' used for single-anchor lookups, so it is distinguishable from siblings such as rank_projects and get_project_schedule.

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

Usage Guidelines4/5

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

Rich contextual guidance: it names default population_scope, when to switch to 'current', the two category_scope modes, and how to obtain distinct totals (summary.line_budget_total vs summing attributed_budget). What it does not do is say explicitly when to choose this tool over rank_projects or schedule_breakdown, so the when-to-use-vs-sibling story is inferred rather than stated.

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