Passage Data — cited environmental limits
Cited US, Canadian, EU limits (discharge, drinking water, soil, air); species status; DwC archives
我该使用它吗
质量与安全性
发现(3)
- HIGH
- LOW在 build_dwc_archive 中
- LOW在 fetch 中
基于对工具定义和协议合规性的自动分析。
上下文开销
这是每次将服务器的工具加载到模型上下文窗口时所消耗的大致 token 数。数值越高,可用于其他任务的注意力就越少。
安装
一键安装
将以下内容添加到你的 `claude_desktop_config.json` 文件中:
{
"mcpServers": {
"passage-data": {
"url": "https://passage-data.com/mcp"
}
}
}远程端点
https://passage-data.com/mcpstreamable-http它能做什么
工具清单
工具(23)
🟢find_limits(parameter, place, medium, statistic, kind, ...)
What is the limit for a substance in a place (an effluent, a river, drinking water, soil), as the regulation itself prints it? Numeric limits and guidelines for one substance or measure, read from the regulations themselves (US federal effluent guidelines, the rules of 31 states and DC, Canadian federal and all 13 provinces' and territories' rules, German, French, Italian and EU instruments), drinking-water standards (US 40 CFR 141 and 143, EU Directive 2020/2184, Quebec, PFAS in Germany, France, Italy and Canada) and soil and groundwater screening values (EPA RSLs, California ESLs, Ontario, Quebec, British Columbia, CCME, Italy, German and Italian PFAS). Each row gives value, unit, statistic, the conditions it applies under, and a `cite` block (instrument, edition, section or page, the quoted text, source URL and sha256). When nothing is held the answer is a `refused` block naming every instrument searched: say that our sources hold no such row, never that the law has no limit.
输入模式
{
"type": "object",
"properties": {
"parameter": {
"type": "string",
"description": "The substance or measure as a regulation names it (ammonia, copper, TSS, pH, BOD5, benzene) or its CAS number (7440-50-8)."
},
"place": {
"type": "string",
"description": "ISO 3166 code of where the rule binds: a country (US, CA, DE, FR, IT), a state or province (US-OH, CA-QC), or EU. A place also searches every place above it: US-OH searches US-OH and US; DE searches DE and EU. Omit to search everywhere."
},
"medium": {
"type": "string",
"enum": [
"water_discharge",
"surface_water",
"groundwater",
"drinking_water",
"soil",
"ambient_air",
"air_emission",
"sediment",
"leachate"
],
"description": "What the limit governs: an effluent (water_discharge), the receiving water (surface_water), groundwater, drinking water as supplied (drinking_water; EPA's tap-water screening levels too), soil, air."
},
"statistic": {
"type": "string",
"description": "Only rows under this statistic: daily_max, monthly_avg, thirty_day_avg, four_day_avg, annual_avg, hourly_avg, instant, ..."
},
"kind": {
"type": "string",
"enum": [
"limit",
"guideline",
"benchmark",
"threshold",
"objective",
"acceptance",
"printed_reference"
],
"description": "limit = binding on a discharger; guideline = a quality criterion or objective."
},
"max_rows": {
"type": "integer",
"minimum": 1,
"maximum": 200,
"default": 50
},
"offset": {
"type": "integer",
"minimum": 0,
"default": 0,
"description": "Where the next page starts (the answer's next_offset)."
}
},
"required": [
"parameter"
],
"additionalProperties": false
}🟢check_value(parameter, value, unit, place, medium, ...)
Is a measured value over the limits we hold? Give a parameter, a number and its unit (and a place, medium or statistic to narrow). Every row find_limits would return comes back with a verdict: over, within, under (below a floor or a band's bottom), or not_comparable with a `why` (a unit of another family or one we never convert, a number that depends on the water's hardness, pH or temperature, an equation or narrative, a value printed for reference, a row under a longer parameter name). Units convert exactly within a family (µg/L to mg/L); no limit is summed or inferred. `counts` totals the verdicts over all rows. Quote each row's `cite`; whether its statistic and conditions are yours is for you to say.
输入模式
{
"type": "object",
"properties": {
"parameter": {
"type": "string",
"description": "The substance or measure as a regulation names it (copper, ammonia, pH) or its CAS number."
},
"value": {
"type": "number",
"description": "The measured value, one number (0.15). A decimal string is read too, with a point or one decimal comma (0,15); 1,500 is refused as ambiguous."
},
"unit": {
"type": "string",
"description": "The value's unit: mg/L, µg/L (or ug/L, mg L-1), ng/L, mg/kg, µg/m³, pH (or SU) ..."
},
"place": {
"type": "string",
"description": "ISO 3166 code of where the rule binds: a country (US, CA, DE, FR, IT), a state or province (US-OH, CA-QC), or EU. A place also searches every place above it: US-OH searches US-OH and US; DE searches DE and EU. Omit to search everywhere."
},
"medium": {
"type": "string",
"enum": [
"water_discharge",
"surface_water",
"groundwater",
"drinking_water",
"soil",
"ambient_air",
"air_emission",
"sediment",
"leachate"
],
"description": "What the limit governs: an effluent (water_discharge), the receiving water (surface_water), groundwater, air."
},
"statistic": {
"type": "string",
"description": "Only rows under this statistic: daily_max, monthly_avg, instant, composite, ..."
},
"max_rows": {
"type": "integer",
"minimum": 1,
"maximum": 200,
"default": 50
},
"offset": {
"type": "integer",
"minimum": 0,
"default": 0,
"description": "Where the next page starts (the answer's next_offset); rows come over first, then under, within, not_comparable."
}
},
"required": [
"parameter",
"value",
"unit"
],
"additionalProperties": false
}🟢check_values(place, rows, medium, statistic, max_rows)
Which results in a lab table are over the limit? A lab table in one call: up to 200 rows of parameter, value and unit, checked against the limits held for one place (and a medium or statistic). Each row is answered by check_value itself: its verdicts (over, within, under, not_comparable with a `why`), `counts` and `says`, or its own coded refusal (an unknown parameter, a value below detection such as <0.005, an ambiguous unit). Each held limit is sent once, in `limits`, and a verdict names it by index: joined, they are check_value's row, with its `cite`. `summary` counts the rows over a limit, under a floor, within every limit, with no comparable limit, and refused by code. `max_rows` pages each row's verdicts (over first); ask check_value with `offset` for more.
输入模式
{
"type": "object",
"properties": {
"place": {
"type": "string",
"description": "ISO 3166 code of where the rule binds: a country (US, CA, DE, FR, IT), a state or province (US-OH, CA-QC), or EU. A place also searches every place above it: US-OH searches US-OH and US; DE searches DE and EU. One place for the whole table."
},
"rows": {
"type": "array",
"minItems": 1,
"maxItems": 200,
"description": "The table's rows, in order; the answer keeps the order.",
"items": {
"type": "object",
"required": [
"parameter",
"value",
"unit"
],
"additionalProperties": false,
"properties": {
"parameter": {
"type": "string",
"description": "The substance or measure as a regulation names it (copper, ammonia, pH) or its CAS number."
},
"value": {
"type": [
"number",
"string"
],
"description": "The measured value as the table prints it (0.15, \"0,15\"); a result below detection (\"<0.005\") is refused for that row, never compared."
},
"unit": {
"type": "string",
"description": "The value's unit: mg/L, µg/L, ng/L, mg/kg, pH ..."
}
}
}
},
"medium": {
"type": "string",
"enum": [
"water_discharge",
"surface_water",
"groundwater",
"drinking_water",
"soil",
"ambient_air",
"air_emission",
"sediment",
"leachate"
],
"description": "What the limits govern: an effluent (water_discharge), the receiving water (surface_water), groundwater, ..."
},
"statistic": {
"type": "string",
"description": "Only limits under this statistic: daily_max, monthly_avg, instant, ..."
},
"max_rows": {
"type": "integer",
"minimum": 1,
"maximum": 200,
"default": 50,
"description": "Verdicts returned for each row (its counts cover all)."
}
},
"required": [
"place",
"rows"
],
"additionalProperties": false
}🟢read_certificate(content_base64, file_url, filename, place, medium, ...)
What does a laboratory certificate report, and is any result over the limit? The rows a laboratory certificate prints, read by rules (no AI writes a row): a PDF certificate, or the laboratory's own export as XLSX, XLS or CSV. Each row gives the sample, the parameter, the value as printed, its unit, a qualifier (<, >, ND), the detection limit, and the page (or sheet) it was read from; a sample's date, matrix and lab ID are in `samples`. Give a `place` (and best a `medium`) and every row with a value is checked by check_values itself: `exceedances` lists the rows over a limit or under a floor, each limit once in `limits` with its `cite`; a result below detection is not compared and says so. `summary` counts the rows by outcome. Rows page by `max_rows` and `offset`. Anything but a PDF, XLSX, XLS or CSV is refused `format.not_handled` before it is read. The file is read and discarded: it is not kept, and nothing is learned from it. Each caller has 3 free reads a UTC day; past that a read costs 0.10 USDC on Base Sepolia, a testnet (eip155:84532), paid by x402 version 2: the call answers HTTP 402 (over MCP an error result) with the requirements, and the same call carrying the payment is read. A refused read is never charged.
输入模式
{
"type": "object",
"properties": {
"content_base64": {
"type": "string",
"description": "The file's bytes, base64-encoded (at most 10 MB). Give this or file_url."
},
"file_url": {
"type": "string",
"description": "An https address the file can be fetched from (not a private network). Give this or content_base64."
},
"filename": {
"type": "string",
"description": "Optional: the file's name, as the laboratory sent it."
},
"place": {
"type": "string",
"description": "ISO 3166 code of where the rule binds: a country (US, CA, DE, FR, IT), a state or province (US-OH, CA-QC), or EU. A place also searches every place above it: US-OH searches US-OH and US; DE searches DE and EU. Omit to read the rows without checking them."
},
"medium": {
"type": "string",
"enum": [
"water_discharge",
"surface_water",
"groundwater",
"drinking_water",
"soil",
"ambient_air",
"air_emission",
"sediment",
"leachate"
],
"description": "What the sample is checked as: an effluent (water_discharge), the receiving water (surface_water), groundwater, soil, ... Omit to compare against every medium held."
},
"statistic": {
"type": "string",
"description": "Only limits under this statistic: daily_max, monthly_avg, instant, ..."
},
"max_rows": {
"type": "integer",
"minimum": 1,
"maximum": 500,
"default": 100,
"description": "Certificate rows on this page (the summary and exceedances cover every row)."
},
"offset": {
"type": "integer",
"minimum": 0,
"default": 0,
"description": "Where the next page starts (the answer's next_offset); the file is read again."
},
"call_id": {
"type": "string",
"description": "Only after a `read.pending` answer: its call_id, to collect the reading without sending the file again."
}
},
"additionalProperties": false
}🟢verify_claim(parameter, value, unit, place, medium, ...)
Does a limit we hold say what a claim says? Give the claim as read from a sentence (an AI's answer, a report): parameter, value and unit, and the place, medium and statistic when the sentence gives them. The verdict: confirmed (a held row prints the same number, in that unit or one that converts exactly, under that statistic: quote its `cite`); contradicted (rows are held and none prints it: `held_otherwise` gives the number each prints, with its cite); not_held (a coded `refused` block naming every instrument searched and its edition: say that our sources hold no such row, never that the claim is false or that the place has no limit); not_comparable (rows held, none comparable with one number, each with its `why`). Equal is equal as exact decimals: a rounded number is another number. Each row's conditions ride with it, and a row printing another number under other conditions (another kind of facility, another hardness) may be why a claim is contradicted: say whose conditions are the claim's. Optionally give the `sentence` the claim came from: the answer says whether it prints the claim's number and unit. The sentence is never kept.
输入模式
{
"type": "object",
"properties": {
"parameter": {
"type": "string",
"description": "The substance or measure the claim names (copper, ammonia, pH) or its CAS number."
},
"value": {
"type": "number",
"description": "The number the claim states (0.10). A decimal string is read too, with a point or one decimal comma (0,10)."
},
"unit": {
"type": "string",
"description": "The claim's unit: mg/L, µg/L (or ug/L, mg L-1), ng/L, mg/kg, µg/m³, pH ..."
},
"place": {
"type": "string",
"description": "ISO 3166 code of where the rule binds: a country (US, CA, DE, FR, IT), a state or province (US-OH, CA-QC), or EU. A place also searches every place above it: US-OH searches US-OH and US; DE searches DE and EU. Omit to search everywhere."
},
"medium": {
"type": "string",
"enum": [
"water_discharge",
"surface_water",
"groundwater",
"drinking_water",
"soil",
"ambient_air",
"air_emission",
"sediment",
"leachate"
],
"description": "What the claimed limit governs: an effluent (water_discharge), the receiving water (surface_water), groundwater, drinking_water, soil, air."
},
"statistic": {
"type": "string",
"description": "The claim's statistic as a row code: monthly_avg (a monthly mean or average), thirty_day_avg (an average over 30 days, as a standard prints it), daily_max, daily_avg, weekly_avg, annual_avg, hourly_avg, four_day_avg, instant (a grab sample, at any time), composite, qualified_grab, ... An unknown code is refused with the list. Omit it and every row is set beside the claim."
},
"sentence": {
"type": "string",
"maxLength": 2000,
"description": "Optional: the sentence the claim was read from. Read for the claim's number and unit, never kept."
}
},
"required": [
"parameter",
"value",
"unit"
],
"additionalProperties": false
}🟢list_sources(place, medium)
Which regulations, and which editions, does an answer for a place rest on? Every regulation, guideline or permit table we hold for a place: title, issuer, edition, what it governs, how many rows were read from it, and the source URL and sha256. Use it to say what an answer was searched against.
输入模式
{
"type": "object",
"properties": {
"place": {
"type": "string",
"description": "ISO 3166 code of where the rule binds: a country (US, CA, DE, FR, IT), a state or province (US-OH, CA-QC), or EU. A place also searches every place above it: US-OH searches US-OH and US; DE searches DE and EU. Omit to search everywhere."
},
"medium": {
"type": "string",
"enum": [
"water_discharge",
"surface_water",
"groundwater",
"drinking_water",
"soil",
"ambient_air",
"air_emission",
"sediment",
"leachate"
]
}
},
"additionalProperties": false
}🟢get_permit(permit)
What are a US facility's discharge permit limits, when is its renewal due, and has it gone over a limit lately? One US NPDES discharge permit as EPA's national file (ECHO / ICIS-NPDES) holds it: facility, place, every limit by outfall, parameter, statistic and months, the renewal due date, and the last 12 months' record of values over a limit. When its renewal is near, overdue or the permit has expired, `renewal_check` names a free renewal check a person can order on the permit's page.
输入模式
{
"type": "object",
"properties": {
"permit": {
"type": "string",
"description": "The NPDES permit number: two letters and seven letters or digits, e.g. PA0228061."
}
},
"required": [
"permit"
],
"additionalProperties": false
}🟢list_permits(state, industry, sic, offset)
Which facilities in a US state hold a discharge permit, and which of them are in one industry (paper mills, meat packing, sewage treatment)? The state's individual NPDES permits with limits, as EPA's national file (ECHO / ICIS-NPDES) lists them, in one call: each permit's number, facility name, whether EPA rates it major, its primary SIC code and the words EPA prints for it, and the addresses of its page and of get_permit's answer. `industry` keeps the permits whose SIC description holds every word given; `sic` the codes that start with the digits given. A permit EPA's file gives no SIC never matches a filter: `without_industry` says how many. Then call get_permit for each permit's limits and record.
输入模式
{
"type": "object",
"properties": {
"state": {
"type": "string",
"description": "The state or territory's two-letter code, e.g. WI."
},
"industry": {
"type": "string",
"description": "Words of EPA's SIC description, e.g. paper, pulp, sausages, sewerage. Optional."
},
"sic": {
"type": "string",
"description": "A SIC code or its first digits, e.g. 26 or 2621. Optional."
},
"offset": {
"type": "integer",
"minimum": 0,
"description": "Where the page starts when more than 1000 match. Optional."
}
},
"required": [
"state"
],
"additionalProperties": false
}🟢check_dmr(permit, period_end, values, netdmr)
Will EPA flag this period's Discharge Monitoring Report (DMR)? A US NPDES permit's Discharge Monitoring Report for one period, checked before it is filed: each value you send (outfall, parameter, statistic, value, unit) is set beside the permit's own limit for that period, from EPA's national limits file (ICIS-NPDES), with EPA's violation rule's verdict: flagged (EPA records a violation), ok, undecidable (a less-than result against a lower limit: EPA does not flag it, nor does it show compliance), no_data (a NODI code), not_graded (an alert or stayed limit), unreadable. A row we cannot place on one value due is refused by its code (outfall.not_in_permit, parameter.not_limited, statistic.not_limited, unit.not_on_form, period.not_due, row.ambiguous with the candidates), never put on the nearest limit. Every value due this period is in `limits` once with its limit_value_id (the cite into EPA's file); `not_sent` lists those you did not send, which EPA records as missing (D90) when filed blank. `headline` and `tally` are the forms as filed with exactly the values placed. `netdmr: true` adds the NetDMR "Import DMRs" file as text (not yet validated by NetDMR's own import check). The values reach our server to be checked and are not kept: only how many were sent, flagged and refused is counted.
输入模式
{
"type": "object",
"properties": {
"permit": {
"type": "string",
"description": "The NPDES permit number, e.g. PA0228061."
},
"period_end": {
"type": "string",
"description": "The reporting period: its month (2026-09) or its last day (2026-09-30). A quarterly form is due on the period ending its quarter."
},
"values": {
"type": "array",
"minItems": 1,
"maxItems": 500,
"description": "The period's values, one a row, as the DMR prints them.",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"outfall": {
"type": "string",
"description": "The outfall (permitted feature): 001, 1, 002A ..."
},
"parameter": {
"type": "string",
"description": "EPA's parameter code (get_permit's parameter_code: 00530, WEP6L) or its name (Solids, total suspended; TSS; ammonia)."
},
"statistic": {
"type": "string",
"description": "EPA's statistical base code (MK, DD, WA, IA ...) or get_permit's words (monthly average, daily maximum, weekly average)."
},
"value": {
"type": [
"number",
"string"
],
"description": "The number as filed: 12, 0.5, or a censored result as a string: \"<0.10\"."
},
"qualifier": {
"type": "string",
"enum": [
"<",
"<=",
">",
">=",
"="
],
"description": "Optional: the value's qualifier, when the value is a bare number."
},
"unit": {
"type": "string",
"description": "The value's unit, which must be the form's: mg/L, ug/L, lb/d, MGD, SU, #/100mL ... It separates a concentration from a loading."
},
"location": {
"type": "string",
"description": "Optional: the monitoring location, EPA's code (1 effluent gross, G raw sewage influent, K percent removal) or its name."
},
"form": {
"type": "string",
"description": "Optional: the DMR form (limit set) when two forms carry the parameter: its designator (A, Q) or name (001 Monthly)."
},
"season": {
"type": "string",
"description": "Optional: the limit's season number when seasonal limits overlap (1, 2)."
},
"nodi": {
"type": "string",
"description": "A no-data code in place of a value: C no discharge, B below detection, 9 conditional monitoring ..."
},
"limit_value_id": {
"type": "string",
"description": "Optional: the limit's id from an earlier check_dmr or fill_dmr answer, in place of outfall, parameter, statistic and unit."
}
}
}
},
"netdmr": {
"type": "boolean",
"default": false,
"description": "Also return the NetDMR \"Import DMRs\" file (CSV text) for the values placed."
}
},
"required": [
"permit",
"period_end",
"values"
],
"additionalProperties": false
}🟢fill_dmr(permit, period_end, rows, table, nd_rule, ...)
What numbers go on a permit's DMR this period, computed from the plant's own daily results? The numbers a US NPDES permit's Discharge Monitoring Report asks for in one period, computed from the plant's own raw results (daily samples, flows): for each value due on the period's forms (EPA's national limits file) its statistic as EPA defines it (monthly average, daily maximum, weekly average over EPA's Sunday-to-Saturday weeks, geometric mean, loadings in lb/d from concentration x flow x 8.34, percent removal), the rows it was computed from, and EPA's violation rule's verdict against the limit. A value the rows cannot give is refused with its code (fill.no_column, fill.unit, fill.ambiguous, dmr.nd_rule_missing ...): a number the rows do not hold is never supplied. Send `rows` as JSON (date, parameter, value, unit, point) or `table` as the file's text (a laboratory's long export, or a sheet of days with one column per parameter); include the previous month's last days when a weekly average is due. A result below detection enters an average by `nd_rule` (zero, half, dl, dl_lt), else by the state's written rule. `netdmr: true` adds the NetDMR "Import DMRs" file as text (not yet validated by NetDMR's own import check). The rows reach our server to be computed and are not kept: only how many rows were sent and values filled is counted.
输入模式
{
"type": "object",
"properties": {
"permit": {
"type": "string",
"description": "The NPDES permit number, e.g. PA0228061."
},
"period_end": {
"type": "string",
"description": "The reporting period: its month (2026-09) or its last day (2026-09-30)."
},
"rows": {
"type": "array",
"maxItems": 20000,
"description": "The plant's results, one a row (send rows or table).",
"items": {
"type": "object",
"required": [
"date",
"parameter",
"value"
],
"additionalProperties": false,
"properties": {
"date": {
"type": "string",
"description": "The sample's day: 2026-09-01 or 9/1/2026."
},
"parameter": {
"type": "string",
"description": "As the plant's log names it (TSS, CBOD5, Ammonia-N, Flow, pH, E. coli, Copper ...), or EPA's parameter code or name as get_permit prints them (01032; Chromium, hexavalent [as Cr]). A row whose parameter or date is not read is counted in `read.unread`."
},
"value": {
"type": [
"number",
"string"
],
"description": "The result: 12, or \"<0.5\" below detection, or \"ND\" with a detection_limit."
},
"unit": {
"type": "string",
"description": "mg/L, ug/L, MGD, SU, #/100mL ..."
},
"point": {
"type": "string",
"description": "Where it was sampled, as the plant names it: Influent, Effluent, Outfall 002 ..."
},
"outfall": {
"type": "string",
"description": "Optional: the outfall the sample belongs to, read with the point."
},
"qualifier": {
"type": "string",
"description": "Optional: <, >, or ND."
},
"detection_limit": {
"type": [
"number",
"string"
],
"description": "Optional: the detection or reporting limit of an ND result."
}
}
}
},
"table": {
"type": [
"string",
"array"
],
"items": {
"type": "array"
},
"description": "The plant's file as text (CSV, TSV or semicolons; at most 2000000 characters) or as lines of cells (send rows or table)."
},
"nd_rule": {
"type": "string",
"enum": [
"zero",
"half",
"dl",
"dl_lt"
],
"description": "How a result below detection enters an average: as zero, half the limit, the limit (dl), or the limit reported as less-than (dl_lt). Default: the state's written rule, else none (such a statistic is refused)."
},
"netdmr": {
"type": "boolean",
"default": false,
"description": "Also return the NetDMR \"Import DMRs\" file (CSV text) for the values filled."
}
},
"required": [
"permit",
"period_end"
],
"additionalProperties": false
}🟢map_to_darwin_core(columns, sample_rows)
Which Darwin Core term does each column of a species file map to, before it goes to GBIF? Which Darwin Core term each column of a species occurrence or checklist file maps to, by the header rules our file-to-archive converter runs before it checks values: for each column the term, the rule that decided it (exact name or alias, a word of the name, a packed coordinate pair, a grid reference), the alias that matched and where it came from, or a coded `refused` block saying why it stays unmapped (no term or alias matches, several columns tie for one term, another column holds the term, blank in the sample). Also names the terms GBIF requires of an occurrence or a checklist dataset that no column carries. Values are not checked here: each mapped column names the value check it must still pass.
输入模式
{
"type": "object",
"properties": {
"columns": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"maxItems": 500,
"description": "The file's header names, in order, exactly as written."
},
"sample_rows": {
"type": "array",
"maxItems": 400,
"items": {
"type": [
"array",
"object"
]
},
"description": "Optional data rows, each an array aligned with `columns` or an object keyed by header: a column blank in every row is skipped as the converter skips it, and a column of distinct codes is named an identifier."
}
},
"required": [
"columns"
],
"additionalProperties": false
}🟢find_designations(species, place)
Is a species protected or at risk, and under which act, list and edition? What the species registers we hold say about one species: its status under each list that names it (the US Endangered Species Act lists, Canada's Species at Risk Act and COSEWIC, provincial acts, the IUCN Red List, CITES, CMS, the EU Habitats and Birds Directives' annexes, UK schedules). Each row gives the status as printed, an `outcome` (listed, listed_qualified = only under a population or subspecies you must confirm, watch_listed, assessed_not_listed, ...) and a `cite` block (instrument, edition, the line the register prints, source URL and sha256). Registers searched that do not name the species are in `silent`, each with what its silence means. When none names it the answer is a `refused` block naming every register searched and its edition: say that these registers do not name it, never that the species is unprotected.
输入模式
{
"type": "object",
"properties": {
"species": {
"type": "string",
"description": "A scientific name (Myotis lucifugus, Rana draytonii; authorship allowed) or a common name exactly as a register prints it (little brown myotis, caribou)."
},
"place": {
"type": "string",
"description": "ISO 3166 code of where the species is: a country (US, CA, GB, FR) or a state or province (US-CA, CA-ON, GB-SCT). Only the registers that reach it are searched, with the global ones (IUCN, CITES, and CMS where the country is a Party). Omit to search every register."
}
},
"required": [
"species"
],
"additionalProperties": false
}🟢screen_species(species, place)
Which species on a list are protected or at risk? A species list in one call: up to 500 names, each answered by find_designations itself, for one place or everywhere: its designations with their cites and the registers searched that are `silent` on it with what each one's silence means, or its own coded refusal (`designations.none_held` = no register searched names it; `species.ambiguous` with candidates). A register's instrument, edition, source URL and sha256 are sent once, in `registers`. `summary` counts the names listed, listed only under a population or subspecies, watch-listed, named but not listed, named by no register, ambiguous and refused, and how many names each register lists. A name no register names is a statement about these registers, never that the species is unprotected.
输入模式
{
"type": "object",
"properties": {
"species": {
"type": "array",
"minItems": 1,
"maxItems": 500,
"items": {
"type": "string"
},
"description": "The names, as the list prints them: scientific names (authorship allowed) or common names exactly as a register prints them."
},
"place": {
"type": "string",
"description": "ISO 3166 code of where the species are: a country (US, CA, GB, FR) or a state or province (US-CA, CA-ON, GB-SCT). Omit to search every register."
}
},
"required": [
"species"
],
"additionalProperties": false
}🟢cite_document(url, find)
A public document sent here is kept in our library, to be indexed and read into cited rows; a link on a file-sharing host or carrying a signature or token is read and never kept (`kept` says which, and why). Cite numbers or phrases from a public document by page: give its address (a PDF, a web page or plain text, up to 40 MiB) and what to find, as the document prints it. Each find comes back with every page it is printed on (`n_hits`, the first 5 with their `quote`), the quoted text around it, and a `cite` naming the page, the address, the document's sha256 and the day it was read: the citation an answer can carry. Matching is exact as typed: a number as printed (0.10 is not 0.1; a decimal comma reads as a point), spaces optional, letters in any case, µg read as ug. A find not printed on the pages read is in `not_found`, with any pages not read; a scan with no text layer is refused, not read by OCR. A document may print a provision twice, as it stood and as amended: say which page you quote. `held_as` names the instruments this server already reads rows from when the document is one of them.
输入模式
{
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "The document's public address (http or https): a regulation, a permit, a guideline, a report."
},
"find": {
"type": "array",
"minItems": 1,
"maxItems": 10,
"items": {
"type": "string",
"maxLength": 120
},
"description": "What to cite, as the document prints it: a number with its unit (0.10 mg/L), a table or section name (Table 2, 445A.1237), a phrase."
}
},
"required": [
"url",
"find"
],
"additionalProperties": false
}🟡build_dwc_archive(file_url, content_base64, filename, species, core, ...)
A file this tool reads, sent or fetched from the address given, is read as one dropped on our website: what the read finds (column headings, the shape of its rows, the terms they became, refusal codes) is kept so the reader learns, never the file or its values. Names and contacts are dropped or replaced by a code, and protected species' locations are made coarser. How do I publish a species file on GBIF? A Darwin Core archive (DwC-A) for GBIF, built from a species occurrence or checklist file (CSV, TSV, Excel, a zipped shapefile, ...) given as `file_url` (a public https address the door fetches) or `content_base64`, or from a list of names (`species`: a checklist). The converter is the one behind map_to_darwin_core: it maps every column, checks every value and writes occurrence.txt (or taxon.txt), meta.xml and eml.xml. The answer: `archive` (core, records, rows read and lost, terms, bytes, sha256, `publishable` with what GBIF still needs); the zip itself, as an embedded resource when it is at most 32 KB (a larger one comes whole, as base64, from POST /api/v1/dwc/archive with the same arguments); `could_not_read` = each thing the converter would not guess, coded (a column no term carries, a row with no date or position, a 0,0 coordinate, a name the naming authority does not match, repeated rows), with what it costs; and `notices` (records of species a conservation register lists, at the precision filed). GBIF indexes an archive only with a title, an abstract, a licence and a creator and a contact (given name, surname, organisation, email): give them in `metadata`, nothing is filled in. `chapman_category` (1-4: the data holder's own sensitivity category under Chapman 2020) coarsens the coordinates of listed species and says so in the archive. `columns` names the column for a term where your user decided it (map_to_darwin_core's reading, corrected); the converter still checks the values and refuses what they contradict. Our counter keeps how the file came, the core and the counts. When your user confirmed `columns` and you send columns_confirmed_by_user: true, each confirmed column's words and its term (never a value) are also read as a label to teach the converter, and the answer's `learned` says so. Large files take a minute.
输入模式
{
"type": "object",
"properties": {
"file_url": {
"type": "string",
"description": "A public https address of the file; the door fetches it (at most 10 MB). Not with content_base64 or species."
},
"content_base64": {
"type": "string",
"description": "The file's bytes as base64 (at most 10 MB decoded). Not with file_url or species."
},
"filename": {
"type": "string",
"maxLength": 200,
"description": "The file's name with its extension (survey.xlsx, sites.zip): it tells the converter how to read the bytes. Taken from file_url when omitted."
},
"species": {
"type": "array",
"minItems": 1,
"maxItems": 5000,
"items": {
"type": "string"
},
"description": "Instead of a file: scientific names, one an entry, for a checklist archive (Taxon core)."
},
"core": {
"type": "string",
"enum": [
"occurrence",
"checklist"
],
"description": "occurrence (default for a file: one row an observation) or checklist (one row a taxon; the default for species)."
},
"metadata": {
"type": "object",
"additionalProperties": false,
"description": "The dataset's metadata for eml.xml, as the data holder states it.",
"properties": {
"title": {
"type": "string"
},
"abstract": {
"type": "string",
"description": "What the dataset is: where, when, how it was collected."
},
"license": {
"type": "string",
"enum": [
"CC0-1.0",
"CC-BY-4.0",
"CC-BY-NC-4.0"
],
"description": "The licences GBIF indexes."
},
"creator": {
"type": "object",
"additionalProperties": false,
"description": "The person and organisation who made the dataset. GBIF needs given, sur, organization and email.",
"properties": {
"given": {
"type": "string"
},
"sur": {
"type": "string"
},
"organization": {
"type": "string"
},
"email": {
"type": "string"
},
"position": {
"type": "string"
},
"country": {
"type": "string"
},
"url": {
"type": "string"
}
}
},
"contact": {
"type": "object",
"additionalProperties": false,
"description": "Whom to ask about it. GBIF needs given, sur, organization and email.",
"properties": {
"given": {
"type": "string"
},
"sur": {
"type": "string"
},
"organization": {
"type": "string"
},
"email": {
"type": "string"
},
"position": {
"type": "string"
},
"country": {
"type": "string"
},
"url": {
"type": "string"
}
}
}
}
},
"chapman_category": {
"type": "integer",
"minimum": 1,
"maximum": 4,
"description": "Optional: your sensitivity category under Chapman 2020 (1 = least, 4 = most withheld). Coordinates of species a conservation register lists are generalised to its grid, and the archive says so in dataGeneralizations."
},
"columns": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Optional, with a file: {Darwin Core term: the column that carries it} where your user decided (e.g. {\"scientificName\": \"Espèce\", \"eventDate\": \"Date relevé\"}). A choice, not an order: the values are still checked."
},
"columns_confirmed_by_user": {
"type": "boolean",
"description": "true only when your user read and confirmed every entry of `columns` themselves (not your own reading). Each confirmed column's words and term are then kept to teach the converter; nothing else of the file is."
}
},
"additionalProperties": false
}🟢audit_archive(gbif_dataset, url, content_base64, filename, annex, ...)
A file this tool reads, sent or fetched from the address given, is read as one dropped on our website: what the read finds (column headings, the shape of its rows, the terms they became, refusal codes) is kept so the reader learns, never the file or its values. Names and contacts are dropped or replaced by a code, and protected species' locations are made coarser. What is wrong with a Darwin Core archive already published on GBIF? The defects in a published Darwin Core archive, found by the audit our website runs on an archive dropped on it: give a GBIF dataset key (the archive is fetched from the endpoint GBIF's registry lists), the archive's address, or the archive itself as base64. Each defect is coded (FS_...), with the check that found it (each check's words once, in `checks`; a finding names it by index), its count over the rows read, and the file and lines it stands on (at most 5 lines a finding; `not_located` says why when a check names neither a cell nor a row). `bdq` names every test of TDWG's BDQ TG2 suite: ran, with compliant and not_compliant counts and lines, or not run under a code (bdq.terms_absent, bdq.authority_absent, bdq.does_not_reproduce, bdq.not_implemented): a test not run is not a test passed. `annex: true` adds the audit as a markdown document to attach to a report. A large archive answers `pending` with a `call_id`: call again with only that call_id to collect it. Refusals are coded: dataset.not_found, dataset.no_archive, archive.unreachable, archive.not_dwca, archive.too_large, url.refused.
输入模式
{
"type": "object",
"properties": {
"gbif_dataset": {
"type": "string",
"description": "A GBIF dataset key (a UUID, as in gbif.org/dataset/<key>)."
},
"url": {
"type": "string",
"description": "The http(s) address of a Darwin Core archive: an IPT's archive.do?r=..., a .zip (up to 200 MB)."
},
"content_base64": {
"type": "string",
"description": "The archive's bytes, base64-encoded (at most 10 MB of zip; a larger one by its url)."
},
"filename": {
"type": "string",
"description": "With content_base64: the archive's file name."
},
"annex": {
"type": "boolean",
"default": false,
"description": "Also return the audit as a markdown document (a data quality annex)."
},
"call_id": {
"type": "string",
"description": "Only after a `pending` answer: its call_id, to collect the audit without naming the archive again."
}
},
"additionalProperties": false
}🟢screen_exposure(records, place, determinations)
Do these occurrence records publish where a listed species lives too precisely? Occurrence records in one call, up to 5000: each record's species name and coordinates as published, optionally coordinateUncertaintyInMeters, a place, and what the file declares about the point (dataGeneralizations, informationWithheld, the eventID, locationID or locality it shares with other records, an iNaturalist export's coordinates_obscured, geoprivacy, public_positional_accuracy). Our engine's names screen answers as it answers a file dropped on passage-data.com: for each species a register lists, `listed_by` gives which register lists it (its status, whether it applies where the records are, the line the register prints) and `exposure` how many of its records sit at a coordinate finer than a 0.01 degree grid (about 1.1 km, precise enough to walk to), and how many of those a rounding would not protect because another record states the same position (withhold those). `treatment` is Chapman 2020's, GBIF's best practice for sensitive species: the category the data holder's documented answers to its questions reach (send them as `determinations`) with its grid, the Darwin Core terms to fill and how many records it would round and withhold; without answers, a coded refusal (sensitivity.criteria_unevaluated) naming the next question, beside what each category would do. A listing is not that determination. Every register screened is named with its edition: a species no register lists is a statement about those registers, never that it is unprotected. Nothing sent is kept.
输入模式
{
"type": "object",
"properties": {
"records": {
"type": "array",
"minItems": 1,
"maxItems": 5000,
"description": "The occurrence records, in order. Fields other than these are not read (their names are listed back in `query.fields_ignored`).",
"items": {
"type": "object",
"required": [
"scientificName"
],
"properties": {
"scientificName": {
"type": "string",
"description": "The species as the file prints it (authorship allowed): Myotis lucifugus (Le Conte, 1831)."
},
"decimalLatitude": {
"type": [
"number",
"string"
],
"description": "The latitude as published, WGS84 decimal degrees."
},
"decimalLongitude": {
"type": [
"number",
"string"
],
"description": "The longitude as published, WGS84 decimal degrees."
},
"coordinateUncertaintyInMeters": {
"type": [
"number",
"string"
]
},
"place": {
"type": "string",
"description": "ISO 3166 code of where this record is, when it is not the call's place (CA-QC, US-CA, FR)."
},
"dataGeneralizations": {
"type": "string"
},
"informationWithheld": {
"type": "string"
},
"eventID": {
"type": "string"
},
"locationID": {
"type": "string"
},
"locality": {
"type": "string"
},
"coordinates_obscured": {
"type": [
"boolean",
"string"
]
},
"geoprivacy": {
"type": "string"
},
"taxon_geoprivacy": {
"type": "string"
},
"public_positional_accuracy": {
"type": [
"number",
"string"
]
}
}
}
},
"place": {
"type": "string",
"description": "ISO 3166 code of where the records are: a country (CA, US, FR, GB) or a subdivision (CA-QC, US-CA, GB-SCT). Omit it and the screen places them by their own points against public boundaries, and says so."
},
"determinations": {
"type": "object",
"additionalProperties": {
"type": "boolean"
},
"description": "The data holder's documented answers to Chapman 2020's questions, by number: {\"1.1\": true, \"1.2\": false, ...}. An answer without them lists every question in `treatment.questions`."
}
},
"required": [
"records"
],
"additionalProperties": false
}🟢search(query)
Search everything this server holds by free text: a substance and a place (copper effluent Québec, ammonia Ohio, a CAS number), a species and a place (Myotis lucifugus Ontario, little brown myotis), an instrument's title (Metal and Diamond Mining Effluent Regulations, 40 CFR 423) or a US NPDES permit number. The query is read by exact matches against what is held — a place's ISO code or name, a parameter name as a regulation prints it, a scientific name or a common name a register prints — never guessed. Each result is an `id` to pass to fetch, a `title` saying what it holds, and the `url` of the page with the same rows, to cite. `searched` says how the query was read and what was read but is not held.
输入模式
{
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Free text: a substance or measure and a place, a species and a place, an instrument's title, or an NPDES permit number."
}
},
"required": [
"query"
],
"additionalProperties": false
}输出模式
{
"type": "object",
"properties": {
"results": {
"type": "array",
"items": {
"type": "object",
"required": [
"id",
"title",
"url"
],
"properties": {
"id": {
"type": "string"
},
"title": {
"type": "string"
},
"url": {
"type": "string"
}
}
}
}
},
"required": [
"results"
]
}🟢fetch(id)
One document search returned, as text: limits/<place>/<parameter> = every cited row for that parameter there (value, unit, statistic, conditions, and each row's instrument, edition, section or page, quoted text and source URL); species/<name>[/<place>] = what each species register says about it, and each register searched that is silent; place/<place> = the instruments and parameters held there; source/<instrument> = one instrument's edition and source; permit/<NPDES number> = one US NPDES permit's limits by outfall. `url` is the page to cite; `metadata.json` the same rows as JSON.
输入模式
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "An id from search: limits/CA-QC/copper, species/Myotis lucifugus/CA-ON, place/US-OH, source/ca_mdmer, permit/PA0228061."
}
},
"required": [
"id"
],
"additionalProperties": false
}输出模式
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"title": {
"type": "string"
},
"text": {
"type": "string"
},
"url": {
"type": "string"
},
"metadata": {
"type": "object"
}
},
"required": [
"id",
"title",
"text",
"url"
]
}🟢list_sites(offset)
The sites of the signed-in account: id, name, status, when made, and how many documents each holds and how many of them are read. A site holds a project's documents (permits, studies, lab reports, tables); ask_site answers a question from them, cited to the page.
输入模式
{
"type": "object",
"properties": {
"offset": {
"type": "integer",
"minimum": 0,
"default": 0,
"description": "Where the next page of 50 starts (the answer's next_offset)."
}
},
"additionalProperties": false
}🟡create_site(name)
A new site in the account, with its name only: it is placed on a map later, on its page. Each call makes one more site, so look for the site with list_sites first.
输入模式
{
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 120,
"description": "The site's name, as its people call it (a mine, a plant, a project)."
}
},
"required": [
"name"
],
"additionalProperties": false
}🟡add_document(site, filename, content_base64, text)
One file held on a site and read, as a file dropped on the site's page is: its text layer page by page, its summary and, for a laboratory table, its result rows, all kept in the account and searched by ask_site. Give the file as `content_base64`, or a text as `text`. The same bytes added twice are one document. The answer gives the document's id, its state (read, or refused with a code and why), its pages, and `not_done`: each step of the read not made in this call. At most 8 MiB a file here; a larger one goes on the site's page (up to 200 MiB).
输入模式
{
"type": "object",
"properties": {
"site": {
"type": "string",
"description": "The site: its id (from list_sites), or a part of its name that names one site only."
},
"filename": {
"type": "string",
"minLength": 1,
"maxLength": 200,
"description": "The file's name with its extension (permit.pdf, results.xlsx, notes.txt): it says what kind of file it is."
},
"content_base64": {
"type": "string",
"description": "The file's bytes, base64. Give this or `text`."
},
"text": {
"type": "string",
"description": "The document as text, kept as a UTF-8 file under `filename`. Give this or `content_base64`."
}
},
"required": [
"site",
"filename"
],
"additionalProperties": false
}🟢ask_site(site, question, skip_pages)
What do a project's own documents say about a question, cited to the page? A question answered from one site's own read documents, by Claude, and checked before it is shown: every statement carries quotes, each quote is found again on the page it names, and a statement whose quote or number is not on its page is cut and counted (`n_cut`). `quotes` give the document, its id and the page; `reasoning` is Claude's own and not from the documents; `not_searched` names the documents not read yet. Priced before any call and refused over $0.25 a question (`ask.over_cap`); an account asks at most 100 questions and spends at most $5 with Claude a UTC day (`ask.over_ceiling`, `spend.daily_cap`). `cost` says what the answer spent; the same question over the same pages is answered from memory at $0.
输入模式
{
"type": "object",
"properties": {
"site": {
"type": "string",
"description": "The site: its id (from list_sites), or a part of its name that names one site only."
},
"question": {
"type": "string",
"minLength": 1,
"maxLength": 2000,
"description": "The question, in any language; numbered parts (1. … 2. …) are answered part by part."
},
"skip_pages": {
"type": "integer",
"minimum": 0,
"maximum": 200,
"default": 0,
"description": "Read the next pages instead: the number of best-ranked pages an earlier answer already read (its `searched.read`)."
}
},
"required": [
"site",
"question"
],
"additionalProperties": false
}社区
证据