@pipeworx/mcp-medicare-pricing 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@ What Medicare **pays** — physician fee schedule, lab rates, and per-day unit
4
4
  limits. The companion to `medicare-coverage`, which answers whether something is
5
5
  covered but not what it is worth.
6
6
 
7
- Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to 1683+ live data sources.
7
+ Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to 1831+ live data sources. This is an independent, unofficial integration — not affiliated with, endorsed by, or published by the upstream provider.
8
8
 
9
9
  ## Tools
10
10
 
@@ -17,6 +17,7 @@ Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents
17
17
  | `medicare_code_units_limit` | "How many units of this code will they pay for in one day?" — NCCI MUE. |
18
18
  | `check_code_pair` | "Can I bill 00142 and 64474 together?" — NCCI PTP edit + modifier indicator for a code pair. |
19
19
  | `explain_ncci_edit` | "What is bundled into (or bundles into) this code?" — every recorded PTP edit for one code. |
20
+ | `medicare_fqhc_pps_rate` | "What is the FQHC PPS base rate for 2026?" — CMS's national Federally Qualified Health Center per-visit base rate, by year. |
20
21
  | `medicare_pricing_coverage` | Which vintages are loaded, including the PTP baseline vintage. |
21
22
 
22
23
  ## Auth
@@ -32,6 +33,31 @@ All from CMS, all downloadable files with no API:
32
33
  - **DMEPOS fee schedule** (durable medical equipment, prosthetics, orthotics, supplies) — quarterly (as necessary): A=Jan, B=Apr, C=Jul, D=Oct
33
34
  - **NCCI Medically Unlikely Edits** — quarterly
34
35
  - **NCCI PTP quarterly additions/deletions/revisions files** — quarterly (see below — a narrower source than the other three)
36
+ - **FQHC Prospective Payment System base payment rate** — annual (see below — a hand-maintained table, not a downloaded file)
37
+
38
+ ## FQHC PPS base payment rate — a hand-maintained table, and why
39
+
40
+ `medicare_fqhc_pps_rate` is different from the rest of this pack: it is not
41
+ backed by Supabase or a downloaded bulk file, because there is neither. CMS
42
+ publishes the FQHC PPS national base rate exactly once a year, as a single new
43
+ dollar figure inside a CMS Manual System "Recurring Update Notification"
44
+ Change Request PDF — one number, one PDF, once a year. Standing up an ingest
45
+ pipeline for that is not proportionate, so the pack carries a small table of
46
+ `{year, base_rate_usd, effective_date, market_basket_update_pct,
47
+ prior_year_rate_usd, transmittal, change_request, publication}` in
48
+ `src/index.ts` (`FQHC_PPS_BASE_RATES`), five rows (CY2022–CY2026), each read
49
+ directly off its own primary CMS transmittal.
50
+
51
+ This is the national BASE rate only — before the per-FQHC Geographic
52
+ Adjustment Factor (GAF) CMS applies on top. The GAF table itself is not
53
+ loaded; an agent that needs the GAF-adjusted dollar amount for a specific FQHC
54
+ still needs that separately.
55
+
56
+ **Refresh**: CMS issues the following year's transmittal in Nov/Dec (the
57
+ CY2026 update was dated 2025-12-05 for a Jan 1, 2026 effective date). Add a
58
+ row to `FQHC_PPS_BASE_RATES` each year once it posts — search CMS's own
59
+ transmittals (Pub 100-04 Medicare Claims Processing, or Pub 100-02 Medicare
60
+ Benefit Policy) for "FQHC PPS Calendar Year".
35
61
 
36
62
  ## ADLT list — brand name to billing code
37
63
 
@@ -311,7 +337,7 @@ directly, instead of just this one's:
311
337
  }
312
338
  ```
313
339
 
314
- Both URLs reach the same gateway and the same 1683+ data sources. The
340
+ Both URLs reach the same gateway and the same 1831+ data sources. The
315
341
  only difference is which pack's tools are listed **directly**; `ask_pipeworx`
316
342
  reaches all of them from either one.
317
343
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pipeworx/mcp-medicare-pricing",
3
- "version": "0.1.3",
4
- "description": "What does Medicare PAY — physician fee schedule, lab rates, and per-day unit",
3
+ "version": "0.1.4",
4
+ "description": "What does Medicare PAY — physician fee schedule, lab rates, and per-day unit limits.",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "types": "src/index.ts",
@@ -26,7 +26,7 @@
26
26
  "@cloudflare/workers-types": "^4.20260405.1"
27
27
  },
28
28
  "pipeworx": {
29
- "sourceHash": "v1-4bc045e1de966c1a9bd8a24cb7841ad9803cdfe842f2b6db807b64562639bc33",
30
- "sourceCommit": "6fe8fb3e01138dfc4ebe7d5c246503aab9278d06"
29
+ "sourceHash": "v1-65f2f81a2d58d5024e9845e0238d0a24b75f7fa653f412494f5054bb6cfc84dd",
30
+ "sourceCommit": "514e3efb42b8d81082c07e01d3ae7654bbf91f52"
31
31
  }
32
32
  }
package/server.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
3
  "name": "io.github.pipeworx-io/medicare-pricing",
4
4
  "title": "Medicare Pricing",
5
- "description": "What does Medicare PAY — physician fee schedule, lab rates, and per-day unit",
6
- "version": "0.1.3",
5
+ "description": "What does Medicare PAY — physician fee schedule, lab rates, and per-day unit limits.",
6
+ "version": "0.1.4",
7
7
  "websiteUrl": "https://pipeworx.io/packs/medicare-pricing",
8
8
  "repository": {
9
9
  "url": "https://github.com/pipeworx-io/mcp-medicare-pricing",
package/src/index.ts CHANGED
@@ -864,6 +864,94 @@ const STATUS: Record<string, string> = {
864
864
  X: 'Statutorily excluded from the fee schedule',
865
865
  };
866
866
 
867
+ // ── FQHC PPS base payment rate (fleet #3241) ──────────────────────────────
868
+ //
869
+ // CMS publishes this ONE number a year, in a CMS Manual System TRANSMITTAL
870
+ // (a "Recurring Update Notification" Change Request PDF) — there is no API
871
+ // and no bulk file, just a yearly PDF with a single new figure in it. A
872
+ // hand-maintained table of a handful of values is the documented shape for
873
+ // that case (house rule for fleet #3241: "a PDF fact sheet with one number
874
+ // per year... a tiny dated table is acceptable"), not a Supabase ingest
875
+ // pipeline for five numbers. Every row below was read directly off its own
876
+ // primary CMS transmittal (not a summary site) — see transmittal/change
877
+ // request/pub per row.
878
+ //
879
+ // REFRESH: CMS issues the next year's transmittal in Nov/Dec for the
880
+ // following Jan 1 (the CY2026 one was dated 2025-12-05) — add a row here
881
+ // each year when it posts. Search "FQHC PPS Calendar Year" among CMS's own
882
+ // transmittals (Pub 100-04 Medicare Claims Processing or Pub 100-02 Medicare
883
+ // Benefit Policy) to find the next one.
884
+ interface FqhcPpsRow {
885
+ year: number;
886
+ base_rate_usd: number;
887
+ effective_date: string;
888
+ market_basket_update_pct: number;
889
+ prior_year_rate_usd: number;
890
+ transmittal: string;
891
+ change_request: string;
892
+ publication: string;
893
+ }
894
+ const FQHC_PPS_BASE_RATES: FqhcPpsRow[] = [
895
+ { year: 2022, base_rate_usd: 180.16, effective_date: '2022-01-01', market_basket_update_pct: 2.1, prior_year_rate_usd: 176.45, transmittal: 'Transmittal 11057', change_request: 'CR 12490', publication: 'Pub 100-04 Medicare Claims Processing' },
896
+ { year: 2023, base_rate_usd: 187.19, effective_date: '2023-01-01', market_basket_update_pct: 3.9, prior_year_rate_usd: 180.16, transmittal: 'Transmittal 11677', change_request: 'CR 12961', publication: 'Pub 100-04 Medicare Claims Processing' },
897
+ { year: 2024, base_rate_usd: 195.99, effective_date: '2024-01-01', market_basket_update_pct: 4.7, prior_year_rate_usd: 187.19, transmittal: 'Transmittal 12267', change_request: 'CR 13398', publication: 'Pub 100-04 Medicare Claims Processing' },
898
+ { year: 2025, base_rate_usd: 202.65, effective_date: '2025-01-01', market_basket_update_pct: 3.4, prior_year_rate_usd: 195.99, transmittal: 'Transmittal 12951', change_request: 'CR 13867', publication: 'Pub 100-04 Medicare Claims Processing' },
899
+ { year: 2026, base_rate_usd: 207.72, effective_date: '2026-01-01', market_basket_update_pct: 2.5, prior_year_rate_usd: 202.65, transmittal: 'Transmittal 13506', change_request: 'CR 14309', publication: 'Pub 100-02 Medicare Benefit Policy' },
900
+ ];
901
+ const FQHC_SOURCE = 'Centers for Medicare & Medicaid Services (CMS), Federally Qualified Health Center (FQHC) Prospective Payment System base payment rate';
902
+
903
+ function fqhcStatement(r: FqhcPpsRow): string {
904
+ return `CMS FQHC PPS base payment rate for CY ${r.year}: $${r.base_rate_usd.toFixed(2)}, effective ${r.effective_date} — a ${r.market_basket_update_pct}% FQHC market basket increase over CY ${r.year - 1}'s $${r.prior_year_rate_usd.toFixed(2)} (${r.transmittal}, ${r.change_request}, ${r.publication}). This is the national base rate before any per-FQHC Geographic Adjustment Factor (GAF).`;
905
+ }
906
+
907
+ function fqhcPpsRate(args: Record<string, unknown>) {
908
+ const askedYear = typeof args.year === 'number' ? Math.floor(args.year) : null;
909
+ const rows = FQHC_PPS_BASE_RATES;
910
+ if (askedYear == null) {
911
+ const latest = rows[rows.length - 1];
912
+ return {
913
+ found: true,
914
+ source: FQHC_SOURCE,
915
+ year: latest.year,
916
+ year_was_defaulted: true,
917
+ base_rate_usd: latest.base_rate_usd,
918
+ effective_date: latest.effective_date,
919
+ market_basket_update_pct: latest.market_basket_update_pct,
920
+ prior_year_rate_usd: latest.prior_year_rate_usd,
921
+ transmittal: latest.transmittal,
922
+ change_request: latest.change_request,
923
+ publication: latest.publication,
924
+ statement: fqhcStatement(latest),
925
+ per_visit_not_per_code: 'This is a per-DAY encounter rate (lesser of actual charges or this PPS rate), not a fee per HCPCS/CPT code.',
926
+ history: rows,
927
+ };
928
+ }
929
+ const row = rows.find((r) => r.year === askedYear);
930
+ if (!row) {
931
+ return {
932
+ found: false,
933
+ reason: 'year_not_loaded',
934
+ loaded_years: rows.map((r) => r.year),
935
+ hint: `No FQHC PPS base payment rate loaded for CY ${askedYear}. Loaded years: ${rows.map((r) => r.year).join(', ')}.`,
936
+ };
937
+ }
938
+ return {
939
+ found: true,
940
+ source: FQHC_SOURCE,
941
+ year: row.year,
942
+ year_was_defaulted: false,
943
+ base_rate_usd: row.base_rate_usd,
944
+ effective_date: row.effective_date,
945
+ market_basket_update_pct: row.market_basket_update_pct,
946
+ prior_year_rate_usd: row.prior_year_rate_usd,
947
+ transmittal: row.transmittal,
948
+ change_request: row.change_request,
949
+ publication: row.publication,
950
+ statement: fqhcStatement(row),
951
+ per_visit_not_per_code: 'This is a per-DAY encounter rate (lesser of actual charges or this PPS rate), not a fee per HCPCS/CPT code.',
952
+ };
953
+ }
954
+
867
955
  const tools: McpToolExport['tools'] = [
868
956
  {
869
957
  name: 'medicare_physician_payment',
@@ -967,6 +1055,18 @@ const tools: McpToolExport['tools'] = [
967
1055
  required: ['code'],
968
1056
  },
969
1057
  },
1058
+ {
1059
+ name: 'medicare_fqhc_pps_rate',
1060
+ description:
1061
+ 'What does Medicare pay a Federally Qualified Health Center (FQHC) per visit? Returns the CMS FQHC Prospective Payment System (PPS) national BASE payment rate for a calendar year — the figure CMS publishes once a year, before any per-FQHC Geographic Adjustment Factor (GAF) is applied. Answers "what is the FQHC PPS base rate", "how much does Medicare pay an FQHC per encounter", "FQHC PPS rate for 2025 vs 2026". '
1062
+ + 'Medicare pays an FQHC the LESSER of its actual charges or this PPS rate for all FQHC services furnished to a beneficiary on a day with a qualifying face-to-face visit — it is a per-DAY encounter rate, not a fee per procedure code (unlike medicare_physician_payment/medicare_lab_rate). This tool does NOT compute the GAF-adjusted, FQHC-specific amount — only the national base rate before that adjustment; the GAF table is not loaded here. Omit year for the newest loaded year plus the full known history (small — CMS publishes one number a year); pass year for one row.',
1063
+ inputSchema: {
1064
+ type: 'object' as const,
1065
+ properties: {
1066
+ year: { type: 'number', description: 'Calendar year, e.g. 2026. Omit to get the newest loaded year AND the full history table.' },
1067
+ },
1068
+ },
1069
+ },
970
1070
  {
971
1071
  name: 'medicare_pricing_coverage',
972
1072
  description:
@@ -1042,6 +1142,12 @@ async function resolveLocality(cfg: Cfg, q: unknown, year: number): Promise<{ ch
1042
1142
  }
1043
1143
 
1044
1144
  async function callTool(name: string, args: Record<string, unknown>): Promise<unknown> {
1145
+ // FQHC PPS is a hand-maintained constant table (see FQHC_PPS_BASE_RATES
1146
+ // above) — not Supabase-backed like the rest of this pack — so it is
1147
+ // dispatched before the credential check below, which every OTHER tool
1148
+ // here needs.
1149
+ if (name === 'medicare_fqhc_pps_rate') return fqhcPpsRate(args);
1150
+
1045
1151
  const url = (args._supabaseUrl as string | undefined)?.trim();
1046
1152
  const key = (args._supabaseKey as string | undefined)?.trim();
1047
1153
  if (!url || !key) {
@@ -1430,6 +1536,7 @@ async function callTool(name: string, args: Record<string, unknown>): Promise<un
1430
1536
  geographic_localities: gpciN.length ? { year: gpciN[0].year } : null,
1431
1537
  clinical_lab_fee_schedule: clfsN.length ? { year: clfsN[0].year, quarter: clfsN[0].quarter } : null,
1432
1538
  dmepos_fee_schedule: dmeN.length ? { year: dmeN[0].year, release: dmeN[0].release, release_month: DME_RELEASE_MONTH[dmeN[0].release] ?? null, priced_by: 'state (not Medicare locality), with separate rural/non-rural amounts' } : null,
1539
+ fqhc_pps_base_rate: { newest_loaded_year: FQHC_PPS_BASE_RATES[FQHC_PPS_BASE_RATES.length - 1].year, loaded_years: FQHC_PPS_BASE_RATES.map((r) => r.year), source: FQHC_SOURCE },
1433
1540
  medically_unlikely_edits: mueN.length ? { effective_from: mueN[0].effective_date } : null,
1434
1541
  procedure_to_procedure_edits: ptpRange.length ? {
1435
1542
  baseline_vintage: '2026q3 (v322r0, effective 2026-07-01) — CMS\'s FULL NCCI PTP edit baseline, AMA-CPT-licence-gated; licence accepted on the company\'s behalf by Bruce, 2026-09-07 (fleet #1293)',
@@ -1439,7 +1546,7 @@ async function callTool(name: string, args: Record<string, unknown>): Promise<un
1439
1546
  refresh_cadence: 'Physician fee schedule annually (with intra-year releases); lab fee schedule, DMEPOS fee schedule, MUE units edits, and PTP pair-edit changes all quarterly (as necessary).',
1440
1547
  no_descriptions_note:
1441
1548
  'CPT procedure descriptions (physician fee schedule, lab schedule) are not returned — American Medical Association copyright. DMEPOS is the exception: it uses HCPCS Level II codes, which CMS itself maintains, so medicare_dmepos_rate DOES return the code description.',
1442
- source: 'CMS Physician Fee Schedule, Clinical Laboratory Fee Schedule, DMEPOS fee schedule, and National Correct Coding Initiative (MUE + PTP quarterly change files)',
1549
+ source: 'CMS Physician Fee Schedule, Clinical Laboratory Fee Schedule, DMEPOS fee schedule, FQHC PPS base payment rate, and National Correct Coding Initiative (MUE + PTP quarterly change files)',
1443
1550
  };
1444
1551
  }
1445
1552
 
package/src/server.ts CHANGED
@@ -8,8 +8,9 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
8
8
  import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
9
9
  import pack from './index.js';
10
10
 
11
+
11
12
  const server = new Server(
12
- { name: '@pipeworx/mcp-medicare-pricing', version: '0.1.3' },
13
+ { name: '@pipeworx/mcp-medicare-pricing', version: '0.1.4' },
13
14
  { capabilities: { tools: {} } },
14
15
  );
15
16
 
@@ -24,7 +25,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
24
25
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
25
26
  const { name, arguments: args } = request.params;
26
27
  try {
27
- const result = await pack.callTool(name, (args ?? {}) as Record<string, unknown>);
28
+ const callArgs = { ...((args ?? {}) as Record<string, unknown>) };
29
+
30
+ const result = await pack.callTool(name, callArgs);
28
31
  return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
29
32
  } catch (err) {
30
33
  return {