OpenPublica

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

我该使用它吗

质量与安全性

A
描述质量
100%
模式完整度
90%
命名质量
99%
投毒风险
100%
权限匹配度
100%
协议合规性
100%

基于对工具定义和协议合规性的自动分析。

上下文开销

~4,301token 数(工具定义)
~2.0 KB典型响应大小
对注意力有显著影响(占 128k 上下文窗口的 3.36%)

这是每次将服务器的工具加载到模型上下文窗口时所消耗的大致 token 数。数值越高,可用于其他任务的注意力就越少。

安装

一键安装

将以下内容添加到你的 `claude_desktop_config.json` 文件中:

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

远程端点

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

它能做什么

工具清单

工具(15)

🟢 只读🟡 写入🔴 删除⚪ 未知
🟢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.

输入模式

{
  "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"
}

输出模式

{
  "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`.

输入模式

{
  "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"
}

输出模式

{
  "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.

输入模式

{
  "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"
}

输出模式

{
  "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.

输入模式

{
  "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"
}

输出模式

{
  "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.

输入模式

{
  "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"
}

输出模式

{
  "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.

输入模式

{
  "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"
}

输出模式

{
  "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.

输入模式

{
  "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"
}

输出模式

{
  "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.

输入模式

{
  "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"
}

输出模式

{
  "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.

输入模式

{
  "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"
}

输出模式

{
  "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`).

输入模式

{
  "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"
}

输出模式

{
  "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.

输入模式

{
  "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.

输入模式

{
  "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`.

输入模式

{
  "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.

输入模式

{
  "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".

输入模式

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

输出模式

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

社区

评价此服务器

证据

最近观测

已验证未记录版本15 个工具
已验证未记录版本15 个工具