OpenPublica

Search US local-government meetings: AI summaries, transcripts, and adopted plan documents.

¿Debería usar esto?

Calidad y seguridad

A
Calidad de la descripción
100%
Integridad del esquema
90%
Calidad de los nombres
99%
Riesgo de envenenamiento
100%
Coincidencia de permisos
100%
Cumplimiento del protocolo
100%

Basado en el análisis automatizado de las definiciones de herramientas y el cumplimiento del protocolo.

Costo de contexto

~4,301Tokens (definiciones de herramientas)
~2.0 KBTamaño de respuesta típico
Impacto significativo en la atención (3.36% del contexto de 128k)

Este es el número aproximado de tokens que se consumen cada vez que las herramientas del servidor se cargan en el contexto de un modelo. Los recuentos más altos reducen la atención disponible para otras tareas.

Instalar

Instalación con un clic

Agrega esto a tu archivo `claude_desktop_config.json`:

{
  "mcpServers": {
    "civic-meetings": {
      "url": "https://api.openpublica.com/mcp"
    }
  }
}

Puntos de conexión remotos

https://api.openpublica.com/mcpstreamable-http

Qué puede hacer

Inventario de herramientas

Herramientas (15)

🟢 Solo lectura🟡 Escritura🔴 Eliminación⚪ Desconocido
🟢search_meetings_semantic(query, government_id, government_ids, start_date, end_date, ...)

Search OpenPublica meeting summaries by meaning, exact terms, or both. The best default tool for "what has been said/decided about X" questions. Results carry a `relevance_score` (semantic, 0-1) and/or `keyword_score` (BM25) plus `highlights`, so you can triage matches by confidence. If the response sets `degraded_to_vector`, the keyword index was unavailable and results are semantic-only — do NOT treat them as exact-term matches. Narrow with `category_tag`/`topic` (get valid values from `discover_meeting_vocabulary`), a date range, or one or more governments. Returns a summary preview; call `get_meeting` with a returned `meeting_id` for the full summary or transcript.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "query": {
      "description": "What to search for in plain language, e.g. 'short-term rental regulations' or 'police budget overtime'.",
      "title": "Query",
      "type": "string"
    },
    "government_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional account_id (from find_local_governments) to restrict the search to one government.",
      "title": "Government Id"
    },
    "government_ids": {
      "anyOf": [
        {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional list of account_ids to search across several governments at once (e.g. to compare cities). Overrides government_id.",
      "title": "Government Ids"
    },
    "start_date": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional earliest meeting date, MM-DD-YYYY.",
      "title": "Start Date"
    },
    "end_date": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional latest meeting date, MM-DD-YYYY.",
      "title": "End Date"
    },
    "category_tag": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional meeting-type filter — an opaque category_tag from discover_meeting_vocabulary (not a guessable slug).",
      "title": "Category Tag"
    },
    "topic": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional topic filter — a topic name from discover_meeting_vocabulary, e.g. 'Affordable Housing'. Restricts to meetings that discussed it.",
      "title": "Topic"
    },
    "match_type": {
      "anyOf": [
        {
          "enum": [
            "semantic",
            "keyword",
            "hybrid"
          ],
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "How to match: 'semantic' (default, by meaning — best for concepts/paraphrases), 'keyword' (exact terms — best for names, ordinance numbers, quoted phrases), or 'hybrid' (both, rank-fused). Use keyword/hybrid when the query has a literal string an embedding might miss.",
      "title": "Match Type"
    },
    "min_score": {
      "anyOf": [
        {
          "maximum": 1,
          "minimum": 0,
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional semantic relevance floor 0-1 (default 0.4). Raise to return only strong matches; lower to widen recall. Applies to semantic matching only — keyword (BM25) hits are not filtered by it.",
      "title": "Min Score"
    },
    "limit": {
      "default": 10,
      "description": "Max meetings to return (1-25).",
      "maximum": 25,
      "minimum": 1,
      "title": "Limit",
      "type": "integer"
    }
  },
  "required": [
    "query"
  ],
  "title": "search_meetings_semanticArguments"
}

Esquema de salida

{
  "type": "object",
  "additionalProperties": true,
  "title": "search_meetings_semanticDictOutput"
}
🟢list_recent_meetings(government_id, category_tag, topic, start_date, end_date, ...)

Browse meetings newest-first, optionally filtered by government, type, topic, or date. Use this for "what are the most recent meetings" or to page through a government's history. For topical questions, prefer `search_meetings_semantic`.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "government_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "account_id to list meetings for (from find_local_governments). Omit to list across all governments.",
      "title": "Government Id"
    },
    "category_tag": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional meeting-type filter — an opaque category_tag from discover_meeting_vocabulary (not a guessable slug; don't invent it).",
      "title": "Category Tag"
    },
    "topic": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional topic filter — a topic name from discover_meeting_vocabulary, e.g. 'Affordable Housing'.",
      "title": "Topic"
    },
    "start_date": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional earliest date, MM-DD-YYYY.",
      "title": "Start Date"
    },
    "end_date": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional latest date, MM-DD-YYYY.",
      "title": "End Date"
    },
    "limit": {
      "default": 10,
      "description": "Meetings per page (1-25).",
      "maximum": 25,
      "minimum": 1,
      "title": "Limit",
      "type": "integer"
    },
    "page": {
      "default": 1,
      "description": "1-based page number for older results.",
      "minimum": 1,
      "title": "Page",
      "type": "integer"
    }
  },
  "title": "list_recent_meetingsArguments"
}

Esquema de salida

{
  "type": "object",
  "additionalProperties": true,
  "title": "list_recent_meetingsDictOutput"
}
🟢get_meeting(meeting_id, include_transcript)

Get a single meeting's full AI summary and topics. Set `include_transcript=true` to also retrieve the complete transcript text for direct quotation. Returns an error object if the meeting is not found.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "meeting_id": {
      "description": "The meeting_id returned by a search/list tool.",
      "title": "Meeting Id",
      "type": "string"
    },
    "include_transcript": {
      "default": false,
      "description": "If true, also fetch the full meeting transcript (can be long). Default false.",
      "title": "Include Transcript",
      "type": "boolean"
    }
  },
  "required": [
    "meeting_id"
  ],
  "title": "get_meetingArguments"
}

Esquema de salida

{
  "type": "object",
  "additionalProperties": true,
  "title": "get_meetingDictOutput"
}
🟢search_meeting_transcript(meeting_id, query, max_passages, context_chars)

Find exact quotes/passages inside one meeting's transcript. Use this to pull direct quotations without loading a whole (often very long) transcript: it fetches the transcript server-side, scans it, and returns only the matching passages with approximate `start`/`end` timecodes when available. Exact matches rank first, with a fuzzy fallback. Prefer this over `get_meeting(include_transcript=true)` when you only need specific quotes.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "meeting_id": {
      "description": "The meeting_id (from a search/list tool) whose transcript to search.",
      "title": "Meeting Id",
      "type": "string"
    },
    "query": {
      "description": "The phrase or terms to find in the transcript, e.g. 'rent stabilization' or a speaker's exact words.",
      "title": "Query",
      "type": "string"
    },
    "max_passages": {
      "default": 5,
      "description": "Max matched passages to return (1-20).",
      "maximum": 20,
      "minimum": 1,
      "title": "Max Passages",
      "type": "integer"
    },
    "context_chars": {
      "default": 300,
      "description": "Characters of surrounding context per side of a match (0-2000).",
      "maximum": 2000,
      "minimum": 0,
      "title": "Context Chars",
      "type": "integer"
    }
  },
  "required": [
    "meeting_id",
    "query"
  ],
  "title": "search_meeting_transcriptArguments"
}

Esquema de salida

{
  "type": "object",
  "additionalProperties": true,
  "title": "search_meeting_transcriptDictOutput"
}
🟢find_local_governments(longitude, latitude, limit)

Discover which governments OpenPublica tracks near a coordinate. Returns nearby governments with their `account_id`, which you can pass to the other tools to scope results to a specific city or board. Note OpenPublica only covers a limited set of US localities; an empty result means none are tracked near that point yet.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "longitude": {
      "description": "Longitude of the location of interest.",
      "maximum": 180,
      "minimum": -180,
      "title": "Longitude",
      "type": "number"
    },
    "latitude": {
      "description": "Latitude of the location of interest.",
      "maximum": 90,
      "minimum": -90,
      "title": "Latitude",
      "type": "number"
    },
    "limit": {
      "default": 10,
      "description": "Max governments to return (1-50).",
      "maximum": 50,
      "minimum": 1,
      "title": "Limit",
      "type": "integer"
    }
  },
  "required": [
    "longitude",
    "latitude"
  ],
  "title": "find_local_governmentsArguments"
}

Esquema de salida

{
  "type": "object",
  "additionalProperties": true,
  "title": "find_local_governmentsDictOutput"
}
🟢find_governments_by_name(query, limit)

Resolve a place *name* to the governments OpenPublica tracks there. Use this when you know a city/state name but not its coordinates — it returns matching governments with their `account_id` (prefix matches first), which you then pass to the search/list tools. Prefer this over `find_local_governments` when starting from a name rather than a latitude/longitude.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "query": {
      "description": "A place name to search for, e.g. 'Sacramento', 'San Francisco, CA', or a state like 'Texas'.",
      "title": "Query",
      "type": "string"
    },
    "limit": {
      "default": 10,
      "description": "Max governments to return (1-50).",
      "maximum": 50,
      "minimum": 1,
      "title": "Limit",
      "type": "integer"
    }
  },
  "required": [
    "query"
  ],
  "title": "find_governments_by_nameArguments"
}

Esquema de salida

{
  "type": "object",
  "additionalProperties": true,
  "title": "find_governments_by_nameDictOutput"
}
🟢find_governments_by_zip(postal_code, limit)

Resolve a ZIP code to nearby tracked governments. Convenience wrapper: geocodes the ZIP, then finds the governments OpenPublica tracks nearest that point. Returns their `account_id`s plus the resolved location. An empty `governments` list means none are tracked near that ZIP yet.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "postal_code": {
      "description": "A US ZIP code, e.g. '95814'.",
      "title": "Postal Code",
      "type": "string"
    },
    "limit": {
      "default": 10,
      "description": "Max governments to return (1-50).",
      "maximum": 50,
      "minimum": 1,
      "title": "Limit",
      "type": "integer"
    }
  },
  "required": [
    "postal_code"
  ],
  "title": "find_governments_by_zipArguments"
}

Esquema de salida

{
  "type": "object",
  "additionalProperties": true,
  "title": "find_governments_by_zipDictOutput"
}
🟢get_government_info(government_id, include_weekly_summary)

Get a tracked government's profile: name, location, and meeting categories.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "government_id": {
      "description": "The account_id of the government.",
      "title": "Government Id",
      "type": "string"
    },
    "include_weekly_summary": {
      "default": false,
      "description": "If true, include the AI-generated weekly digest (markdown). Default false.",
      "title": "Include Weekly Summary",
      "type": "boolean"
    }
  },
  "required": [
    "government_id"
  ],
  "title": "get_government_infoArguments"
}

Esquema de salida

{
  "type": "object",
  "additionalProperties": true,
  "title": "get_government_infoDictOutput"
}
🟢get_government_stats(government_id, days)

Get meeting-activity stats for a government over a recent window. Returns total meeting count, a per-day activity map, and a breakdown of meeting categories — useful for "how active has X been lately?" questions.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "government_id": {
      "description": "account_id of the government, or 'all' for corpus-wide stats.",
      "title": "Government Id",
      "type": "string"
    },
    "days": {
      "default": 30,
      "description": "Look-back window in days (1-365).",
      "maximum": 365,
      "minimum": 1,
      "title": "Days",
      "type": "integer"
    }
  },
  "required": [
    "government_id"
  ],
  "title": "get_government_statsArguments"
}

Esquema de salida

{
  "type": "object",
  "additionalProperties": true,
  "title": "get_government_statsDictOutput"
}
🟢discover_meeting_vocabulary(government_id, government_ids, start_date, end_date, topic_limit)

Discover the valid category and topic filter values before filtering a search. Meeting `category_tag`s are opaque UUIDs and topics have no fixed list, so you cannot guess them. Call this first to get the real values, then pass a returned `category_tag` (from `categories[].tags`) or `topic` string into `search_meetings_semantic` / `list_recent_meetings`. Scope with a government and/or date range; calls without explicit dates default to a recent window (returned as `default_window_days`).

Esquema de entrada

{
  "type": "object",
  "properties": {
    "government_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional account_id to scope the vocabulary to one government.",
      "title": "Government Id"
    },
    "government_ids": {
      "anyOf": [
        {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional list of account_ids to scope to several governments. Overrides government_id.",
      "title": "Government Ids"
    },
    "start_date": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional earliest date, MM-DD-YYYY.",
      "title": "Start Date"
    },
    "end_date": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional latest date, MM-DD-YYYY.",
      "title": "End Date"
    },
    "topic_limit": {
      "default": 50,
      "description": "Max topics to return, most common first (1-200).",
      "maximum": 200,
      "minimum": 1,
      "title": "Topic Limit",
      "type": "integer"
    }
  },
  "title": "discover_meeting_vocabularyArguments"
}

Esquema de salida

{
  "type": "object",
  "additionalProperties": true,
  "title": "discover_meeting_vocabularyDictOutput"
}
🟢list_government_documents(government_id, include_superseded)

List a government's adopted plan and budget documents. Each entry carries `covers` — every general-plan element that document answers for. A city that publishes one bound general plan satisfies all eight with the same PDF, so do not conclude an element is unpublished because no entry is named after it. `status` says what the entry offers: `converted` is searchable and readable; `superseded` is a retired edition, still stored but not searchable; and **`failed` means we hold this document and could not read it — it is not evidence the city published nothing.** Cite `source_url` in that case; it is always the city's own copy. An `availability` block appears ONLY when something is wrong with a document, and `availability.reason` says what. No `availability` key means there is nothing to report.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "government_id": {
      "description": "account_id from find_local_governments.",
      "title": "Government Id",
      "type": "string"
    },
    "include_superseded": {
      "default": false,
      "description": "Also include prior editions retired by a newer document.",
      "title": "Include Superseded",
      "type": "boolean"
    }
  },
  "required": [
    "government_id"
  ],
  "title": "list_government_documentsArguments"
}
🟢get_document(document_id)

One document's metadata. Use read_document_pages to read it. If an `availability` key is present, read it before quoting figures: its `problems` are transcription-lint findings, most often a footnote marker that may have been merged into the number it annotates. No such key means the document transcribed cleanly.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "document_id": {
      "description": "Document id from list_government_documents or search_documents.",
      "title": "Document Id",
      "type": "string"
    }
  },
  "required": [
    "document_id"
  ],
  "title": "get_documentArguments"
}
🟢read_document_pages(document_id, first_page, last_page)

Read a page range of a document as markdown. Pages are transcribed from rendered pixels, so tables and scanned text come through as text. A page that could not be transcribed appears as a marked hole rather than being silently dropped — if you see one, say so instead of reading past it. Text is assembled from page windows, so `covered` may be slightly wider than what you asked for; cite the page numbers in `covered`, not `requested`.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "document_id": {
      "description": "Document id from list_government_documents or search_documents.",
      "title": "Document Id",
      "type": "string"
    },
    "first_page": {
      "description": "First page to read (1-based, as the PDF renders).",
      "minimum": 1,
      "title": "First Page",
      "type": "integer"
    },
    "last_page": {
      "description": "Last page to read. Spans longer than 40 pages are clamped to 40 from first_page.",
      "minimum": 1,
      "title": "Last Page",
      "type": "integer"
    }
  },
  "required": [
    "document_id",
    "first_page",
    "last_page"
  ],
  "title": "read_document_pagesArguments"
}
🟢search_documents(query, government_id, limit)

Search adopted plan and budget documents, returning page-cited excerpts. Each hit's `text` is a short passage around the match, not the full page — call read_document_pages with the hit's `first_page` to read it in context. Every hit carries `first_page`/`last_page` and `source_url`. Quote those when citing: the page number is what makes the claim checkable against the city's own copy. This is word matching, not semantic search — try the terms a plan would actually use. Only currently-served documents are searchable, so an empty result is not evidence the government has no such policy; check list_government_documents for what is held and what could not be read. A hit with `document_complete: false` comes from a document with transcription findings. Verify it against `source_url` before quoting a number from it.

Esquema de entrada

{
  "type": "object",
  "properties": {
    "query": {
      "description": "Words to find in plan and budget text, e.g. 'accessory dwelling unit parking'.",
      "title": "Query",
      "type": "string"
    },
    "government_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional account_id to restrict the search to one government.",
      "title": "Government Id"
    },
    "limit": {
      "default": 10,
      "description": "Maximum excerpts to return.",
      "maximum": 50,
      "minimum": 1,
      "title": "Limit",
      "type": "integer"
    }
  },
  "required": [
    "query"
  ],
  "title": "search_documentsArguments"
}
🟢get_coverage_overview

Get OpenPublica's overall coverage: total governments, states, and meetings indexed. DC is tracked but is not a state, so it is reported separately as `includes_dc` — read the pair as "N states and DC".

Esquema de entrada

{
  "type": "object",
  "properties": {},
  "title": "get_coverage_overviewArguments"
}

Esquema de salida

{
  "type": "object",
  "additionalProperties": true,
  "title": "get_coverage_overviewDictOutput"
}

Comunidad

Califica este servidor

Evidencia

Observaciones recientes

verificadoversión no registrada15 herramientas
verificadoversión no registrada15 herramientas