patents-mcp-server 1.0.0 → 1.0.1

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
@@ -11,6 +11,8 @@ FastMCP TypeScript patent intelligence MCP server. 55 tools across USPTO, EPO, a
11
11
  | **EPO OPS** | 8 | INPADOC patent families, legal status across ~44 offices, claims/descriptions |
12
12
  | **Google BigQuery** | 4 | Full-text search across 90M+ patents, citation networks, CPC analytics |
13
13
 
14
+ Tools only register when their required API keys are configured — no broken tools cluttering the MCP client.
15
+
14
16
  ## Quick Start
15
17
 
16
18
  ```bash
@@ -31,6 +33,27 @@ node dist/index.js
31
33
  TRANSPORT=httpStream PORT=8080 node dist/index.js
32
34
  ```
33
35
 
36
+ ### MCP Configuration (.mcp.json)
37
+
38
+ ```json
39
+ {
40
+ "mcpServers": {
41
+ "patents": {
42
+ "command": "node",
43
+ "args": ["dist/index.js"],
44
+ "env": {
45
+ "USPTO_API_KEY": "${USPTO_API_KEY}",
46
+ "PATENTSVIEW_API_KEY": "${PATENTSVIEW_API_KEY}",
47
+ "EPO_CONSUMER_KEY": "${EPO_CONSUMER_KEY}",
48
+ "EPO_CONSUMER_SECRET": "${EPO_CONSUMER_SECRET}",
49
+ "GOOGLE_APPLICATION_CREDENTIALS": "${GOOGLE_APPLICATION_CREDENTIALS}",
50
+ "GOOGLE_CLOUD_PROJECT": "${GOOGLE_CLOUD_PROJECT}"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
34
57
  ### Test with MCP Inspector
35
58
 
36
59
  ```bash
@@ -39,25 +62,31 @@ npx @modelcontextprotocol/inspector node dist/index.js
39
62
 
40
63
  ## Configuration
41
64
 
42
- Copy `.env.example` and fill in your API keys:
65
+ ### API Keys
43
66
 
44
- ```bash
45
- # USPTO Open Data Portal (required for ODP, PTAB, litigation, office actions)
46
- USPTO_API_KEY=
67
+ | Source | Env Var(s) | Where to Get |
68
+ | ----------- | --------------------------------------------------------- | -------------------------------------------------------------------------- |
69
+ | PatentsView | `PATENTSVIEW_API_KEY` | [patentsview.org/apis/keyrequest](https://patentsview.org/apis/keyrequest) |
70
+ | USPTO ODP | `USPTO_API_KEY` | [data.uspto.gov](https://data.uspto.gov/) → MyODP |
71
+ | EPO OPS | `EPO_CONSUMER_KEY` + `EPO_CONSUMER_SECRET` | [developers.epo.org](https://developers.epo.org/) |
72
+ | BigQuery | `GOOGLE_APPLICATION_CREDENTIALS` + `GOOGLE_CLOUD_PROJECT` | GCP Console (service account with BigQuery roles) |
47
73
 
48
- # PatentsView (optionalworks without key, key grants suspended March 2026)
49
- PATENTSVIEW_API_KEY=
74
+ Missing API keys disable related tools gracefully the server still starts with whatever sources are configured. Use the `check-api-status` tool to verify which sources are available.
50
75
 
51
- # EPO OPS (register at developers.epo.org)
52
- EPO_CONSUMER_KEY=
53
- EPO_CONSUMER_SECRET=
76
+ ### Credential Management with envpkt
54
77
 
55
- # Google BigQuery (requires GCP project with service account)
56
- GOOGLE_APPLICATION_CREDENTIALS= # Path to service account JSON
57
- GOOGLE_CLOUD_PROJECT= # GCP project ID
58
- ```
78
+ This project uses [envpkt](https://github.com/jordanburke/envpkt) for credential management. API keys are stored as sealed (age-encrypted) packets and non-secret config as `[env.*]` entries in `envpkt.toml`. The `.mcp.json` references env vars via `${VAR}` syntax, which are loaded by `eval "$(envpkt env export)"` in your shell profile.
59
79
 
60
- Missing API keys disable related tools gracefully — the server still starts with whatever sources are configured. Use the `check-api-status` tool to verify which sources are available.
80
+ ### Path Expansion
81
+
82
+ `GOOGLE_APPLICATION_CREDENTIALS` supports tilde (`~`) and environment variable (`$HOME`, `${HOME}`) expansion via [functype-os](https://github.com/jordanburke/functype-os). Use paths like `~/.config/gcloud/key.json` instead of absolute paths.
83
+
84
+ ### BigQuery Cost Notes
85
+
86
+ - Free tier: **1TB/month** of queries scanned
87
+ - A broad full-text search across 90M patents scans ~200-300GB per query
88
+ - Targeted queries (patent number, family, CPC with date range) scan much less
89
+ - Every query runs a dry run first; estimated cost is included in the response
61
90
 
62
91
  ## Tools
63
92
 
@@ -158,18 +187,45 @@ pnpm validate # Format + lint + typecheck + test + build
158
187
  pnpm test # Run tests
159
188
  pnpm build # Production build
160
189
  pnpm typecheck # Type check only
190
+ pnpm codegen # Regenerate Zod schemas from OpenAPI specs
191
+ pnpm fetch-specs # Re-download OpenAPI specs from upstream
192
+ ```
193
+
194
+ ### OpenAPI Codegen
195
+
196
+ Response schemas are generated from upstream OpenAPI specs using [Hey API](https://heyapi.dev/) with the Zod plugin:
197
+
198
+ ```bash
199
+ pnpm fetch-specs # Download PatentsView + USPTO ODP specs
200
+ pnpm codegen # Generate src/generated/{patentsview,odp}/zod.gen.ts
161
201
  ```
162
202
 
203
+ Generated code is committed to the repo so CI doesn't need the codegen step.
204
+
205
+ ### Testing
206
+
207
+ Integration tests run against live APIs when credentials are available:
208
+
209
+ ```bash
210
+ # Requires PATENTS_VIEW_API_KEY or PATENTSVIEW_API_KEY in env
211
+ # Requires USPTO_API_KEY in env
212
+ pnpm test
213
+ ```
214
+
215
+ Tests skip gracefully when API keys are absent.
216
+
163
217
  ## Architecture
164
218
 
165
- Built with [FastMCP](https://github.com/punkpeye/fastmcp) + [Zod](https://zod.dev/) + [ts-builds](https://github.com/jordanburke/ts-builds).
219
+ Built with [FastMCP](https://github.com/punkpeye/fastmcp) + [Zod](https://zod.dev/) + [ts-builds](https://github.com/jordanburke/ts-builds) + [functype-os](https://github.com/jordanburke/functype-os).
166
220
 
167
221
  ```
168
222
  src/
169
223
  ├── index.ts # Entry point
170
224
  ├── server.ts # FastMCP instance
171
- ├── tools/ # 55 tools across 8 modules
225
+ ├── tools/ # 55 tools across 8 modules (conditional registration)
172
226
  ├── clients/ # API clients (base, PatentsView, ODP, EPO, BigQuery)
227
+ ├── generated/ # Zod schemas from OpenAPI specs (Hey API codegen)
228
+ ├── specs/ # Local copies of OpenAPI specs
173
229
  ├── resources/ # 4 MCP resources
174
230
  ├── prompts/ # 6 prompt templates
175
231
  └── lib/ # Config, retry, errors, patent number normalization
@@ -1,8 +1,8 @@
1
- import{config as e}from"../lib/config.js";import{BigQuery as t}from"@google-cloud/bigquery";const n=`patents-public-data.patents.publications`,r=()=>new t({projectId:e.googleCloudProject}),i=e=>{let t=Number(e)/0xe8d4a51000;return t<=1?`Free (within 1 TB/month free tier)`:`~$${(t*5).toFixed(2)} (${t.toFixed(3)} TB at $5/TB)`},a=async(e,t)=>{let n=r(),[a]=await n.createQueryJob({query:e,params:t,dryRun:!0,useLegacySql:!1}),o=a.metadata?.statistics?.totalBytesProcessed??`0`,s=i(o),[c]=await n.createQueryJob({query:e,params:t,useLegacySql:!1}),[l]=await c.getQueryResults();return{rows:l,totalRows:l.length,estimatedBytesProcessed:o,estimatedCostUsd:s}},o=async(e,t=[`publication_number`,`title_localized`,`abstract_localized`,`publication_date`,`assignee_harmonized`],r=25)=>a(`
1
+ import{config as e}from"../lib/config.js";import{BigQuery as t}from"@google-cloud/bigquery";const n=`patents-public-data.patents.publications`,r=()=>new t({projectId:e.googleCloudProject,keyFilename:e.googleApplicationCredentials}),i=e=>{let t=Number(e)/0xe8d4a51000;return t<=1?`Free (within 1 TB/month free tier)`:`~$${(t*5).toFixed(2)} (${t.toFixed(3)} TB at $5/TB)`},a=async(e,t)=>{let n=r(),[a]=await n.createQueryJob({query:e,params:t,dryRun:!0,useLegacySql:!1}),o=a.metadata?.statistics?.totalBytesProcessed??`0`,s=i(o),[c]=await n.createQueryJob({query:e,params:t,useLegacySql:!1}),[l]=await c.getQueryResults();return{rows:l,totalRows:l.length,estimatedBytesProcessed:o,estimatedCostUsd:s}},o=async(e,t=[`publication_number`,`title_localized`,`abstract_localized`,`publication_date`,`assignee_harmonized`],r=25)=>a(`
2
2
  SELECT ${t.join(`, `)}
3
3
  FROM \`${n}\`
4
- WHERE SEARCH(abstract_localized.text, @query)
5
- OR SEARCH(title_localized.text, @query)
4
+ WHERE EXISTS (SELECT 1 FROM UNNEST(abstract_localized) a WHERE SEARCH(a.text, @query))
5
+ OR EXISTS (SELECT 1 FROM UNNEST(title_localized) t WHERE SEARCH(t.text, @query))
6
6
  ORDER BY publication_date DESC
7
7
  LIMIT @limit
8
8
  `,{query:e,limit:r}),s=async e=>a(`
@@ -1 +1 @@
1
- {"version":3,"file":"bigquery.client.js","names":[],"sources":["../../src/clients/bigquery.client.ts"],"sourcesContent":["import { BigQuery } from \"@google-cloud/bigquery\"\n\nimport { config } from \"../lib/config\"\n\nconst DATASET = \"patents-public-data.patents.publications\"\n\ntype BigQueryResult = {\n rows: Record<string, unknown>[]\n totalRows: number\n estimatedBytesProcessed: string\n estimatedCostUsd: string\n}\n\nconst getBigQueryClient = (): BigQuery => {\n return new BigQuery({\n projectId: config.googleCloudProject,\n })\n}\n\nconst estimateCost = (bytes: string): string => {\n const tb = Number(bytes) / 1e12\n if (tb <= 1) return \"Free (within 1 TB/month free tier)\"\n return `~$${(tb * 5).toFixed(2)} (${tb.toFixed(3)} TB at $5/TB)`\n}\n\nconst runQuery = async (sql: string, params?: Record<string, unknown>): Promise<BigQueryResult> => {\n const client = getBigQueryClient()\n\n // Always dry run first to estimate cost\n const [dryRunJob] = await client.createQueryJob({\n query: sql,\n params,\n dryRun: true,\n useLegacySql: false,\n })\n\n const bytesProcessed = dryRunJob.metadata?.statistics?.totalBytesProcessed ?? \"0\"\n const costEstimate = estimateCost(bytesProcessed)\n\n // Execute the actual query\n const [job] = await client.createQueryJob({\n query: sql,\n params,\n useLegacySql: false,\n })\n\n const [rows] = await job.getQueryResults()\n\n return {\n rows: rows as Record<string, unknown>[],\n totalRows: rows.length,\n estimatedBytesProcessed: bytesProcessed,\n estimatedCostUsd: costEstimate,\n }\n}\n\nexport const bigqueryPatentSearch = async (\n query: string,\n fields: string[] = [\n \"publication_number\",\n \"title_localized\",\n \"abstract_localized\",\n \"publication_date\",\n \"assignee_harmonized\",\n ],\n limit = 25,\n): Promise<BigQueryResult> => {\n const selectedFields = fields.join(\", \")\n const sql = `\n SELECT ${selectedFields}\n FROM \\`${DATASET}\\`\n WHERE SEARCH(abstract_localized.text, @query)\n OR SEARCH(title_localized.text, @query)\n ORDER BY publication_date DESC\n LIMIT @limit\n `\n return runQuery(sql, { query, limit })\n}\n\nexport const bigqueryPatentFamily = async (familyId: string): Promise<BigQueryResult> => {\n const sql = `\n SELECT\n publication_number,\n country_code,\n title_localized,\n publication_date,\n grant_date,\n application_number,\n priority_date\n FROM \\`${DATASET}\\`\n WHERE family_id = @familyId\n ORDER BY publication_date\n `\n return runQuery(sql, { familyId })\n}\n\nexport const bigqueryCitationNetwork = async (publicationNumber: string, depth = 1): Promise<BigQueryResult> => {\n if (depth === 1) {\n const sql = `\n SELECT\n p.publication_number AS source,\n c.publication_number AS cited_publication,\n c.category,\n c.type\n FROM \\`${DATASET}\\` p,\n UNNEST(citation) AS c\n WHERE p.publication_number = @publicationNumber\n `\n return runQuery(sql, { publicationNumber })\n }\n\n // Depth 2: citations of citations\n const sql = `\n WITH level1 AS (\n SELECT\n p.publication_number AS source,\n c.publication_number AS cited\n FROM \\`${DATASET}\\` p,\n UNNEST(citation) AS c\n WHERE p.publication_number = @publicationNumber\n ),\n level2 AS (\n SELECT\n l1.cited AS source,\n c.publication_number AS cited\n FROM level1 l1\n JOIN \\`${DATASET}\\` p ON p.publication_number = l1.cited,\n UNNEST(citation) AS c\n )\n SELECT * FROM level1\n UNION ALL\n SELECT * FROM level2\n LIMIT 500\n `\n return runQuery(sql, { publicationNumber })\n}\n\nexport const bigqueryCpcAnalytics = async (\n cpcPrefix: string,\n dateFrom?: string,\n dateTo?: string,\n): Promise<BigQueryResult> => {\n const dateFilter = [\n dateFrom ? \"AND publication_date >= @dateFrom\" : \"\",\n dateTo ? \"AND publication_date <= @dateTo\" : \"\",\n ].join(\" \")\n\n const sql = `\n SELECT\n c.code AS cpc_code,\n COUNT(*) AS patent_count,\n COUNT(DISTINCT assignee.name) AS unique_assignees,\n MIN(publication_date) AS earliest_publication,\n MAX(publication_date) AS latest_publication\n FROM \\`${DATASET}\\` p,\n UNNEST(cpc) AS c,\n UNNEST(assignee_harmonized) AS assignee\n WHERE c.code LIKE @cpcPrefix\n ${dateFilter}\n GROUP BY c.code\n ORDER BY patent_count DESC\n LIMIT 100\n `\n\n const params: Record<string, unknown> = { cpcPrefix: `${cpcPrefix}%` }\n if (dateFrom) params.dateFrom = Number(dateFrom)\n if (dateTo) params.dateTo = Number(dateTo)\n\n return runQuery(sql, params)\n}\n"],"mappings":"4FAIA,MAAM,EAAU,2CASV,MACG,IAAI,EAAS,CAClB,UAAW,EAAO,mBACnB,CAAC,CAGE,EAAgB,GAA0B,CAC9C,IAAM,EAAK,OAAO,EAAM,CAAG,aAE3B,OADI,GAAM,EAAU,qCACb,MAAM,EAAK,GAAG,QAAQ,EAAE,CAAC,IAAI,EAAG,QAAQ,EAAE,CAAC,gBAG9C,EAAW,MAAO,EAAa,IAA8D,CACjG,IAAM,EAAS,GAAmB,CAG5B,CAAC,GAAa,MAAM,EAAO,eAAe,CAC9C,MAAO,EACP,SACA,OAAQ,GACR,aAAc,GACf,CAAC,CAEI,EAAiB,EAAU,UAAU,YAAY,qBAAuB,IACxE,EAAe,EAAa,EAAe,CAG3C,CAAC,GAAO,MAAM,EAAO,eAAe,CACxC,MAAO,EACP,SACA,aAAc,GACf,CAAC,CAEI,CAAC,GAAQ,MAAM,EAAI,iBAAiB,CAE1C,MAAO,CACC,OACN,UAAW,EAAK,OAChB,wBAAyB,EACzB,iBAAkB,EACnB,EAGU,EAAuB,MAClC,EACA,EAAmB,CACjB,qBACA,kBACA,qBACA,mBACA,sBACD,CACD,EAAQ,KAWD,EARK;aADW,EAAO,KAAK,KAAK,CAEd;aACf,EAAQ;;;;;IAME,CAAE,QAAO,QAAO,CAAC,CAG3B,EAAuB,KAAO,IAclC,EAbK;;;;;;;;;aASD,EAAQ;;;IAIE,CAAE,WAAU,CAAC,CAGvB,EAA0B,MAAO,EAA2B,EAAQ,IAYtE,EAXL,IAAU,EACA;;;;;;eAMD,EAAQ;;;MAQT;;;;;eAKC,EAAQ;;;;;;;;;eASR,EAAQ;;;;;;;IAlBE,CAAE,oBAAmB,CAAC,CA6BlC,EAAuB,MAClC,EACA,EACA,IAC4B,CAM5B,IAAM,EAAM;;;;;;;aAOD,EAAQ;;;;QAZA,CACjB,EAAW,oCAAsC,GACjD,EAAS,kCAAoC,GAC9C,CAAC,KAAK,IAAI,CAaM;;;;IAMX,EAAkC,CAAE,UAAW,GAAG,EAAU,GAAI,CAItE,OAHI,IAAU,EAAO,SAAW,OAAO,EAAS,EAC5C,IAAQ,EAAO,OAAS,OAAO,EAAO,EAEnC,EAAS,EAAK,EAAO"}
1
+ {"version":3,"file":"bigquery.client.js","names":[],"sources":["../../src/clients/bigquery.client.ts"],"sourcesContent":["import { BigQuery } from \"@google-cloud/bigquery\"\n\nimport { config } from \"../lib/config\"\n\nconst DATASET = \"patents-public-data.patents.publications\"\n\ntype BigQueryResult = {\n rows: Record<string, unknown>[]\n totalRows: number\n estimatedBytesProcessed: string\n estimatedCostUsd: string\n}\n\nconst getBigQueryClient = (): BigQuery => {\n return new BigQuery({\n projectId: config.googleCloudProject,\n keyFilename: config.googleApplicationCredentials,\n })\n}\n\nconst estimateCost = (bytes: string): string => {\n const tb = Number(bytes) / 1e12\n if (tb <= 1) return \"Free (within 1 TB/month free tier)\"\n return `~$${(tb * 5).toFixed(2)} (${tb.toFixed(3)} TB at $5/TB)`\n}\n\nconst runQuery = async (sql: string, params?: Record<string, unknown>): Promise<BigQueryResult> => {\n const client = getBigQueryClient()\n\n // Always dry run first to estimate cost\n const [dryRunJob] = await client.createQueryJob({\n query: sql,\n params,\n dryRun: true,\n useLegacySql: false,\n })\n\n const bytesProcessed = dryRunJob.metadata?.statistics?.totalBytesProcessed ?? \"0\"\n const costEstimate = estimateCost(bytesProcessed)\n\n // Execute the actual query\n const [job] = await client.createQueryJob({\n query: sql,\n params,\n useLegacySql: false,\n })\n\n const [rows] = await job.getQueryResults()\n\n return {\n rows: rows as Record<string, unknown>[],\n totalRows: rows.length,\n estimatedBytesProcessed: bytesProcessed,\n estimatedCostUsd: costEstimate,\n }\n}\n\nexport const bigqueryPatentSearch = async (\n query: string,\n fields: string[] = [\n \"publication_number\",\n \"title_localized\",\n \"abstract_localized\",\n \"publication_date\",\n \"assignee_harmonized\",\n ],\n limit = 25,\n): Promise<BigQueryResult> => {\n const selectedFields = fields.join(\", \")\n const sql = `\n SELECT ${selectedFields}\n FROM \\`${DATASET}\\`\n WHERE EXISTS (SELECT 1 FROM UNNEST(abstract_localized) a WHERE SEARCH(a.text, @query))\n OR EXISTS (SELECT 1 FROM UNNEST(title_localized) t WHERE SEARCH(t.text, @query))\n ORDER BY publication_date DESC\n LIMIT @limit\n `\n return runQuery(sql, { query, limit })\n}\n\nexport const bigqueryPatentFamily = async (familyId: string): Promise<BigQueryResult> => {\n const sql = `\n SELECT\n publication_number,\n country_code,\n title_localized,\n publication_date,\n grant_date,\n application_number,\n priority_date\n FROM \\`${DATASET}\\`\n WHERE family_id = @familyId\n ORDER BY publication_date\n `\n return runQuery(sql, { familyId })\n}\n\nexport const bigqueryCitationNetwork = async (publicationNumber: string, depth = 1): Promise<BigQueryResult> => {\n if (depth === 1) {\n const sql = `\n SELECT\n p.publication_number AS source,\n c.publication_number AS cited_publication,\n c.category,\n c.type\n FROM \\`${DATASET}\\` p,\n UNNEST(citation) AS c\n WHERE p.publication_number = @publicationNumber\n `\n return runQuery(sql, { publicationNumber })\n }\n\n // Depth 2: citations of citations\n const sql = `\n WITH level1 AS (\n SELECT\n p.publication_number AS source,\n c.publication_number AS cited\n FROM \\`${DATASET}\\` p,\n UNNEST(citation) AS c\n WHERE p.publication_number = @publicationNumber\n ),\n level2 AS (\n SELECT\n l1.cited AS source,\n c.publication_number AS cited\n FROM level1 l1\n JOIN \\`${DATASET}\\` p ON p.publication_number = l1.cited,\n UNNEST(citation) AS c\n )\n SELECT * FROM level1\n UNION ALL\n SELECT * FROM level2\n LIMIT 500\n `\n return runQuery(sql, { publicationNumber })\n}\n\nexport const bigqueryCpcAnalytics = async (\n cpcPrefix: string,\n dateFrom?: string,\n dateTo?: string,\n): Promise<BigQueryResult> => {\n const dateFilter = [\n dateFrom ? \"AND publication_date >= @dateFrom\" : \"\",\n dateTo ? \"AND publication_date <= @dateTo\" : \"\",\n ].join(\" \")\n\n const sql = `\n SELECT\n c.code AS cpc_code,\n COUNT(*) AS patent_count,\n COUNT(DISTINCT assignee.name) AS unique_assignees,\n MIN(publication_date) AS earliest_publication,\n MAX(publication_date) AS latest_publication\n FROM \\`${DATASET}\\` p,\n UNNEST(cpc) AS c,\n UNNEST(assignee_harmonized) AS assignee\n WHERE c.code LIKE @cpcPrefix\n ${dateFilter}\n GROUP BY c.code\n ORDER BY patent_count DESC\n LIMIT 100\n `\n\n const params: Record<string, unknown> = { cpcPrefix: `${cpcPrefix}%` }\n if (dateFrom) params.dateFrom = Number(dateFrom)\n if (dateTo) params.dateTo = Number(dateTo)\n\n return runQuery(sql, params)\n}\n"],"mappings":"4FAIA,MAAM,EAAU,2CASV,MACG,IAAI,EAAS,CAClB,UAAW,EAAO,mBAClB,YAAa,EAAO,6BACrB,CAAC,CAGE,EAAgB,GAA0B,CAC9C,IAAM,EAAK,OAAO,EAAM,CAAG,aAE3B,OADI,GAAM,EAAU,qCACb,MAAM,EAAK,GAAG,QAAQ,EAAE,CAAC,IAAI,EAAG,QAAQ,EAAE,CAAC,gBAG9C,EAAW,MAAO,EAAa,IAA8D,CACjG,IAAM,EAAS,GAAmB,CAG5B,CAAC,GAAa,MAAM,EAAO,eAAe,CAC9C,MAAO,EACP,SACA,OAAQ,GACR,aAAc,GACf,CAAC,CAEI,EAAiB,EAAU,UAAU,YAAY,qBAAuB,IACxE,EAAe,EAAa,EAAe,CAG3C,CAAC,GAAO,MAAM,EAAO,eAAe,CACxC,MAAO,EACP,SACA,aAAc,GACf,CAAC,CAEI,CAAC,GAAQ,MAAM,EAAI,iBAAiB,CAE1C,MAAO,CACC,OACN,UAAW,EAAK,OAChB,wBAAyB,EACzB,iBAAkB,EACnB,EAGU,EAAuB,MAClC,EACA,EAAmB,CACjB,qBACA,kBACA,qBACA,mBACA,sBACD,CACD,EAAQ,KAWD,EARK;aADW,EAAO,KAAK,KAAK,CAEd;aACf,EAAQ;;;;;IAME,CAAE,QAAO,QAAO,CAAC,CAG3B,EAAuB,KAAO,IAclC,EAbK;;;;;;;;;aASD,EAAQ;;;IAIE,CAAE,WAAU,CAAC,CAGvB,EAA0B,MAAO,EAA2B,EAAQ,IAYtE,EAXL,IAAU,EACA;;;;;;eAMD,EAAQ;;;MAQT;;;;;eAKC,EAAQ;;;;;;;;;eASR,EAAQ;;;;;;;IAlBE,CAAE,oBAAmB,CAAC,CA6BlC,EAAuB,MAClC,EACA,EACA,IAC4B,CAM5B,IAAM,EAAM;;;;;;;aAOD,EAAQ;;;;QAZA,CACjB,EAAW,oCAAsC,GACjD,EAAS,kCAAoC,GAC9C,CAAC,KAAK,IAAI,CAaM;;;;IAMX,EAAkC,CAAE,UAAW,GAAG,EAAU,GAAI,CAItE,OAHI,IAAU,EAAO,SAAW,OAAO,EAAS,EAC5C,IAAQ,EAAO,OAAS,OAAO,EAAO,EAEnC,EAAS,EAAK,EAAO"}
@@ -662,8 +662,8 @@ declare const zRange: z$1.ZodObject<{
662
662
  declare const zSort: z$1.ZodObject<{
663
663
  field: z$1.ZodOptional<z$1.ZodString>;
664
664
  order: z$1.ZodOptional<z$1.ZodEnum<{
665
- asc: "asc";
666
665
  Asc: "Asc";
666
+ asc: "asc";
667
667
  Desc: "Desc";
668
668
  desc: "desc";
669
669
  }>>;
@@ -689,8 +689,8 @@ declare const zPatentSearchRequest: z$1.ZodObject<{
689
689
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
690
690
  field: z$1.ZodOptional<z$1.ZodString>;
691
691
  order: z$1.ZodOptional<z$1.ZodEnum<{
692
- asc: "asc";
693
692
  Asc: "Asc";
693
+ asc: "asc";
694
694
  Desc: "Desc";
695
695
  desc: "desc";
696
696
  }>>;
@@ -716,8 +716,8 @@ declare const zPatentDownloadRequest: z$1.ZodObject<{
716
716
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
717
717
  field: z$1.ZodOptional<z$1.ZodString>;
718
718
  order: z$1.ZodOptional<z$1.ZodEnum<{
719
- asc: "asc";
720
719
  Asc: "Asc";
720
+ asc: "asc";
721
721
  Desc: "Desc";
722
722
  desc: "desc";
723
723
  }>>;
@@ -936,8 +936,8 @@ declare const zPetitionDecisionRange: z$1.ZodObject<{
936
936
  declare const zPetitionDecisionSort: z$1.ZodObject<{
937
937
  field: z$1.ZodOptional<z$1.ZodString>;
938
938
  order: z$1.ZodOptional<z$1.ZodEnum<{
939
- asc: "asc";
940
939
  Asc: "Asc";
940
+ asc: "asc";
941
941
  Desc: "Desc";
942
942
  desc: "desc";
943
943
  }>>;
@@ -978,8 +978,8 @@ declare const zPetitionDecisionSearchRequest: z$1.ZodObject<{
978
978
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
979
979
  field: z$1.ZodOptional<z$1.ZodString>;
980
980
  order: z$1.ZodOptional<z$1.ZodEnum<{
981
- asc: "asc";
982
981
  Asc: "Asc";
982
+ asc: "asc";
983
983
  Desc: "Desc";
984
984
  desc: "desc";
985
985
  }>>;
@@ -1005,8 +1005,8 @@ declare const zPetitionDecisionDownloadRequest: z$1.ZodObject<{
1005
1005
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
1006
1006
  field: z$1.ZodOptional<z$1.ZodString>;
1007
1007
  order: z$1.ZodOptional<z$1.ZodEnum<{
1008
- asc: "asc";
1009
1008
  Asc: "Asc";
1009
+ asc: "asc";
1010
1010
  Desc: "Desc";
1011
1011
  desc: "desc";
1012
1012
  }>>;
@@ -1446,8 +1446,8 @@ declare const zSearchRequest: z$1.ZodObject<{
1446
1446
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
1447
1447
  field: z$1.ZodOptional<z$1.ZodString>;
1448
1448
  order: z$1.ZodOptional<z$1.ZodEnum<{
1449
- asc: "asc";
1450
1449
  Asc: "Asc";
1450
+ asc: "asc";
1451
1451
  Desc: "Desc";
1452
1452
  desc: "desc";
1453
1453
  }>>;
@@ -1473,8 +1473,8 @@ declare const zDownloadRequest: z$1.ZodObject<{
1473
1473
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
1474
1474
  field: z$1.ZodOptional<z$1.ZodString>;
1475
1475
  order: z$1.ZodOptional<z$1.ZodEnum<{
1476
- asc: "asc";
1477
1476
  Asc: "Asc";
1477
+ asc: "asc";
1478
1478
  Desc: "Desc";
1479
1479
  desc: "desc";
1480
1480
  }>>;
@@ -2675,8 +2675,8 @@ declare const zPostApiV1PatentApplicationsSearchData: z$1.ZodObject<{
2675
2675
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2676
2676
  field: z$1.ZodOptional<z$1.ZodString>;
2677
2677
  order: z$1.ZodOptional<z$1.ZodEnum<{
2678
- asc: "asc";
2679
2678
  Asc: "Asc";
2679
+ asc: "asc";
2680
2680
  Desc: "Desc";
2681
2681
  desc: "desc";
2682
2682
  }>>;
@@ -3314,8 +3314,8 @@ declare const zPostApiV1PatentApplicationsSearchDownloadData: z$1.ZodObject<{
3314
3314
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
3315
3315
  field: z$1.ZodOptional<z$1.ZodString>;
3316
3316
  order: z$1.ZodOptional<z$1.ZodEnum<{
3317
- asc: "asc";
3318
3317
  Asc: "Asc";
3318
+ asc: "asc";
3319
3319
  Desc: "Desc";
3320
3320
  desc: "desc";
3321
3321
  }>>;
@@ -4645,8 +4645,8 @@ declare const zPostApiV1PetitionDecisionsSearchData: z$1.ZodObject<{
4645
4645
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
4646
4646
  field: z$1.ZodOptional<z$1.ZodString>;
4647
4647
  order: z$1.ZodOptional<z$1.ZodEnum<{
4648
- asc: "asc";
4649
4648
  Asc: "Asc";
4649
+ asc: "asc";
4650
4650
  Desc: "Desc";
4651
4651
  desc: "desc";
4652
4652
  }>>;
@@ -4854,8 +4854,8 @@ declare const zPostApiV1PetitionDecisionsSearchDownloadData: z$1.ZodObject<{
4854
4854
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
4855
4855
  field: z$1.ZodOptional<z$1.ZodString>;
4856
4856
  order: z$1.ZodOptional<z$1.ZodEnum<{
4857
- asc: "asc";
4858
4857
  Asc: "Asc";
4858
+ asc: "asc";
4859
4859
  Desc: "Desc";
4860
4860
  desc: "desc";
4861
4861
  }>>;
@@ -5098,8 +5098,8 @@ declare const zPostApiV1PatentTrialsProceedingsSearchData: z$1.ZodObject<{
5098
5098
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
5099
5099
  field: z$1.ZodOptional<z$1.ZodString>;
5100
5100
  order: z$1.ZodOptional<z$1.ZodEnum<{
5101
- asc: "asc";
5102
5101
  Asc: "Asc";
5102
+ asc: "asc";
5103
5103
  Desc: "Desc";
5104
5104
  desc: "desc";
5105
5105
  }>>;
@@ -5262,8 +5262,8 @@ declare const zPostApiV1PatentTrialsProceedingsSearchDownloadData: z$1.ZodObject
5262
5262
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
5263
5263
  field: z$1.ZodOptional<z$1.ZodString>;
5264
5264
  order: z$1.ZodOptional<z$1.ZodEnum<{
5265
- asc: "asc";
5266
5265
  Asc: "Asc";
5266
+ asc: "asc";
5267
5267
  Desc: "Desc";
5268
5268
  desc: "desc";
5269
5269
  }>>;
@@ -5521,8 +5521,8 @@ declare const zPostApiV1PatentTrialsDecisionsSearchData: z$1.ZodObject<{
5521
5521
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
5522
5522
  field: z$1.ZodOptional<z$1.ZodString>;
5523
5523
  order: z$1.ZodOptional<z$1.ZodEnum<{
5524
- asc: "asc";
5525
5524
  Asc: "Asc";
5525
+ asc: "asc";
5526
5526
  Desc: "Desc";
5527
5527
  desc: "desc";
5528
5528
  }>>;
@@ -5739,8 +5739,8 @@ declare const zPostApiV1PatentTrialsDecisionsSearchDownloadData: z$1.ZodObject<{
5739
5739
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
5740
5740
  field: z$1.ZodOptional<z$1.ZodString>;
5741
5741
  order: z$1.ZodOptional<z$1.ZodEnum<{
5742
- asc: "asc";
5743
5742
  Asc: "Asc";
5743
+ asc: "asc";
5744
5744
  Desc: "Desc";
5745
5745
  desc: "desc";
5746
5746
  }>>;
@@ -6145,8 +6145,8 @@ declare const zPostApiV1PatentTrialsDocumentsSearchData: z$1.ZodObject<{
6145
6145
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
6146
6146
  field: z$1.ZodOptional<z$1.ZodString>;
6147
6147
  order: z$1.ZodOptional<z$1.ZodEnum<{
6148
- asc: "asc";
6149
6148
  Asc: "Asc";
6149
+ asc: "asc";
6150
6150
  Desc: "Desc";
6151
6151
  desc: "desc";
6152
6152
  }>>;
@@ -6363,8 +6363,8 @@ declare const zPostApiV1PatentTrialsDocumentsSearchDownloadData: z$1.ZodObject<{
6363
6363
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
6364
6364
  field: z$1.ZodOptional<z$1.ZodString>;
6365
6365
  order: z$1.ZodOptional<z$1.ZodEnum<{
6366
- asc: "asc";
6367
6366
  Asc: "Asc";
6367
+ asc: "asc";
6368
6368
  Desc: "Desc";
6369
6369
  desc: "desc";
6370
6370
  }>>;
@@ -6726,8 +6726,8 @@ declare const zPostApiV1PatentAppealsDecisionsSearchData: z$1.ZodObject<{
6726
6726
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
6727
6727
  field: z$1.ZodOptional<z$1.ZodString>;
6728
6728
  order: z$1.ZodOptional<z$1.ZodEnum<{
6729
- asc: "asc";
6730
6729
  Asc: "Asc";
6730
+ asc: "asc";
6731
6731
  Desc: "Desc";
6732
6732
  desc: "desc";
6733
6733
  }>>;
@@ -6857,8 +6857,8 @@ declare const zPostApiV1PatentAppealsDecisionsSearchDownloadData: z$1.ZodObject<
6857
6857
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
6858
6858
  field: z$1.ZodOptional<z$1.ZodString>;
6859
6859
  order: z$1.ZodOptional<z$1.ZodEnum<{
6860
- asc: "asc";
6861
6860
  Asc: "Asc";
6861
+ asc: "asc";
6862
6862
  Desc: "Desc";
6863
6863
  desc: "desc";
6864
6864
  }>>;
@@ -7110,8 +7110,8 @@ declare const zPostApiV1PatentInterferencesDecisionsSearchData: z$1.ZodObject<{
7110
7110
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
7111
7111
  field: z$1.ZodOptional<z$1.ZodString>;
7112
7112
  order: z$1.ZodOptional<z$1.ZodEnum<{
7113
- asc: "asc";
7114
7113
  Asc: "Asc";
7114
+ asc: "asc";
7115
7115
  Desc: "Desc";
7116
7116
  desc: "desc";
7117
7117
  }>>;
@@ -7280,8 +7280,8 @@ declare const zPostApiV1PatentInterferencesDecisionsSearchDownloadData: z$1.ZodO
7280
7280
  sort: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
7281
7281
  field: z$1.ZodOptional<z$1.ZodString>;
7282
7282
  order: z$1.ZodOptional<z$1.ZodEnum<{
7283
- asc: "asc";
7284
7283
  Asc: "Asc";
7284
+ asc: "asc";
7285
7285
  Desc: "Desc";
7286
7286
  desc: "desc";
7287
7287
  }>>;
@@ -1,2 +1,2 @@
1
- const e=e=>{let t=process.env[e];return t!==void 0&&t!==``?t:void 0},t=(e,t)=>process.env[e]??t,n=(e,t)=>{let n=process.env[e];if(n===void 0||n===``)return t;let r=parseInt(n,10);return isNaN(r)?t:r},r=e=>e===`httpStream`?`httpStream`:`stdio`,i=e=>{let t=e.toUpperCase();return t===`DEBUG`||t===`INFO`||t===`WARN`||t===`ERROR`?t:`INFO`},a=()=>({usptoApiKey:e(`USPTO_API_KEY`),patentsViewApiKey:e(`PATENTSVIEW_API_KEY`),epoConsumerKey:e(`EPO_CONSUMER_KEY`),epoConsumerSecret:e(`EPO_CONSUMER_SECRET`),googleApplicationCredentials:e(`GOOGLE_APPLICATION_CREDENTIALS`),googleCloudProject:e(`GOOGLE_CLOUD_PROJECT`),transport:r(t(`TRANSPORT`,`stdio`)),port:n(`PORT`,8080),logLevel:i(t(`LOG_LEVEL`,`INFO`)),requestTimeout:n(`REQUEST_TIMEOUT`,3e4),maxRetries:n(`MAX_RETRIES`,3),retryMinWait:n(`RETRY_MIN_WAIT`,2e3),retryMaxWait:n(`RETRY_MAX_WAIT`,1e4)}),o=e=>[{name:`USPTO ODP`,configured:e.usptoApiKey!==void 0,healthy:!1},{name:`PatentsView`,configured:e.patentsViewApiKey!==void 0,healthy:!1},{name:`EPO OPS`,configured:e.epoConsumerKey!==void 0&&e.epoConsumerSecret!==void 0,healthy:!1},{name:`Google BigQuery`,configured:e.googleApplicationCredentials!==void 0&&e.googleCloudProject!==void 0,healthy:!1}],s=a();export{s as config,o as getAvailableSources,a as loadConfig};
1
+ import{expandPath as e}from"functype-os";const t=e=>{let t=process.env[e];return t!==void 0&&t!==``?t:void 0},n=n=>{let r=t(n);if(!r)return;let i=e(r);return i.isRight()?i.value:r},r=(e,t)=>process.env[e]??t,i=(e,t)=>{let n=process.env[e];if(n===void 0||n===``)return t;let r=parseInt(n,10);return isNaN(r)?t:r},a=e=>e===`httpStream`?`httpStream`:`stdio`,o=e=>{let t=e.toUpperCase();return t===`DEBUG`||t===`INFO`||t===`WARN`||t===`ERROR`?t:`INFO`},s=()=>({usptoApiKey:t(`USPTO_API_KEY`),patentsViewApiKey:t(`PATENTSVIEW_API_KEY`),epoConsumerKey:t(`EPO_CONSUMER_KEY`),epoConsumerSecret:t(`EPO_CONSUMER_SECRET`),googleApplicationCredentials:n(`GOOGLE_APPLICATION_CREDENTIALS`),googleCloudProject:t(`GOOGLE_CLOUD_PROJECT`),transport:a(r(`TRANSPORT`,`stdio`)),port:i(`PORT`,8080),logLevel:o(r(`LOG_LEVEL`,`INFO`)),requestTimeout:i(`REQUEST_TIMEOUT`,3e4),maxRetries:i(`MAX_RETRIES`,3),retryMinWait:i(`RETRY_MIN_WAIT`,2e3),retryMaxWait:i(`RETRY_MAX_WAIT`,1e4)}),c=e=>[{name:`USPTO ODP`,configured:e.usptoApiKey!==void 0,healthy:!1},{name:`PatentsView`,configured:e.patentsViewApiKey!==void 0,healthy:!1},{name:`EPO OPS`,configured:e.epoConsumerKey!==void 0&&e.epoConsumerSecret!==void 0,healthy:!1},{name:`Google BigQuery`,configured:e.googleApplicationCredentials!==void 0&&e.googleCloudProject!==void 0,healthy:!1}],l=s();export{l as config,c as getAvailableSources,s as loadConfig};
2
2
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","names":[],"sources":["../../src/lib/config.ts"],"sourcesContent":["import type { ApiStatus, LogLevel, TransportType } from \"./types\"\n\ntype AppConfig = {\n usptoApiKey: string | undefined\n patentsViewApiKey: string | undefined\n epoConsumerKey: string | undefined\n epoConsumerSecret: string | undefined\n googleApplicationCredentials: string | undefined\n googleCloudProject: string | undefined\n transport: TransportType\n port: number\n logLevel: LogLevel\n requestTimeout: number\n maxRetries: number\n retryMinWait: number\n retryMaxWait: number\n}\n\nconst envOrUndefined = (key: string): string | undefined => {\n const value = process.env[key]\n return value !== undefined && value !== \"\" ? value : undefined\n}\n\nconst envOrDefault = (key: string, defaultValue: string): string => process.env[key] ?? defaultValue\n\nconst envIntOrDefault = (key: string, defaultValue: number): number => {\n const value = process.env[key]\n if (value === undefined || value === \"\") return defaultValue\n const parsed = parseInt(value, 10)\n return isNaN(parsed) ? defaultValue : parsed\n}\n\nconst parseTransport = (value: string): TransportType => {\n if (value === \"httpStream\") return \"httpStream\"\n return \"stdio\"\n}\n\nconst parseLogLevel = (value: string): LogLevel => {\n const upper = value.toUpperCase()\n if (upper === \"DEBUG\" || upper === \"INFO\" || upper === \"WARN\" || upper === \"ERROR\") {\n return upper\n }\n return \"INFO\"\n}\n\nexport const loadConfig = (): AppConfig => ({\n usptoApiKey: envOrUndefined(\"USPTO_API_KEY\"),\n patentsViewApiKey: envOrUndefined(\"PATENTSVIEW_API_KEY\"),\n epoConsumerKey: envOrUndefined(\"EPO_CONSUMER_KEY\"),\n epoConsumerSecret: envOrUndefined(\"EPO_CONSUMER_SECRET\"),\n googleApplicationCredentials: envOrUndefined(\"GOOGLE_APPLICATION_CREDENTIALS\"),\n googleCloudProject: envOrUndefined(\"GOOGLE_CLOUD_PROJECT\"),\n transport: parseTransport(envOrDefault(\"TRANSPORT\", \"stdio\")),\n port: envIntOrDefault(\"PORT\", 8080),\n logLevel: parseLogLevel(envOrDefault(\"LOG_LEVEL\", \"INFO\")),\n requestTimeout: envIntOrDefault(\"REQUEST_TIMEOUT\", 30000),\n maxRetries: envIntOrDefault(\"MAX_RETRIES\", 3),\n retryMinWait: envIntOrDefault(\"RETRY_MIN_WAIT\", 2000),\n retryMaxWait: envIntOrDefault(\"RETRY_MAX_WAIT\", 10000),\n})\n\nexport const getAvailableSources = (cfg: AppConfig): ApiStatus[] => [\n {\n name: \"USPTO ODP\",\n configured: cfg.usptoApiKey !== undefined,\n healthy: false,\n },\n {\n name: \"PatentsView\",\n configured: cfg.patentsViewApiKey !== undefined,\n healthy: false,\n },\n {\n name: \"EPO OPS\",\n configured: cfg.epoConsumerKey !== undefined && cfg.epoConsumerSecret !== undefined,\n healthy: false,\n },\n {\n name: \"Google BigQuery\",\n configured: cfg.googleApplicationCredentials !== undefined && cfg.googleCloudProject !== undefined,\n healthy: false,\n },\n]\n\nexport const config = loadConfig()\n"],"mappings":"AAkBA,MAAM,EAAkB,GAAoC,CAC1D,IAAM,EAAQ,QAAQ,IAAI,GAC1B,OAAO,IAAU,IAAA,IAAa,IAAU,GAAK,EAAQ,IAAA,IAGjD,GAAgB,EAAa,IAAiC,QAAQ,IAAI,IAAQ,EAElF,GAAmB,EAAa,IAAiC,CACrE,IAAM,EAAQ,QAAQ,IAAI,GAC1B,GAAI,IAAU,IAAA,IAAa,IAAU,GAAI,OAAO,EAChD,IAAM,EAAS,SAAS,EAAO,GAAG,CAClC,OAAO,MAAM,EAAO,CAAG,EAAe,GAGlC,EAAkB,GAClB,IAAU,aAAqB,aAC5B,QAGH,EAAiB,GAA4B,CACjD,IAAM,EAAQ,EAAM,aAAa,CAIjC,OAHI,IAAU,SAAW,IAAU,QAAU,IAAU,QAAU,IAAU,QAClE,EAEF,QAGI,OAA+B,CAC1C,YAAa,EAAe,gBAAgB,CAC5C,kBAAmB,EAAe,sBAAsB,CACxD,eAAgB,EAAe,mBAAmB,CAClD,kBAAmB,EAAe,sBAAsB,CACxD,6BAA8B,EAAe,iCAAiC,CAC9E,mBAAoB,EAAe,uBAAuB,CAC1D,UAAW,EAAe,EAAa,YAAa,QAAQ,CAAC,CAC7D,KAAM,EAAgB,OAAQ,KAAK,CACnC,SAAU,EAAc,EAAa,YAAa,OAAO,CAAC,CAC1D,eAAgB,EAAgB,kBAAmB,IAAM,CACzD,WAAY,EAAgB,cAAe,EAAE,CAC7C,aAAc,EAAgB,iBAAkB,IAAK,CACrD,aAAc,EAAgB,iBAAkB,IAAM,CACvD,EAEY,EAAuB,GAAgC,CAClE,CACE,KAAM,YACN,WAAY,EAAI,cAAgB,IAAA,GAChC,QAAS,GACV,CACD,CACE,KAAM,cACN,WAAY,EAAI,oBAAsB,IAAA,GACtC,QAAS,GACV,CACD,CACE,KAAM,UACN,WAAY,EAAI,iBAAmB,IAAA,IAAa,EAAI,oBAAsB,IAAA,GAC1E,QAAS,GACV,CACD,CACE,KAAM,kBACN,WAAY,EAAI,+BAAiC,IAAA,IAAa,EAAI,qBAAuB,IAAA,GACzF,QAAS,GACV,CACF,CAEY,EAAS,GAAY"}
1
+ {"version":3,"file":"config.js","names":[],"sources":["../../src/lib/config.ts"],"sourcesContent":["import { expandPath } from \"functype-os\"\n\nimport type { ApiStatus, LogLevel, TransportType } from \"./types\"\n\ntype AppConfig = {\n usptoApiKey: string | undefined\n patentsViewApiKey: string | undefined\n epoConsumerKey: string | undefined\n epoConsumerSecret: string | undefined\n googleApplicationCredentials: string | undefined\n googleCloudProject: string | undefined\n transport: TransportType\n port: number\n logLevel: LogLevel\n requestTimeout: number\n maxRetries: number\n retryMinWait: number\n retryMaxWait: number\n}\n\nconst envOrUndefined = (key: string): string | undefined => {\n const value = process.env[key]\n return value !== undefined && value !== \"\" ? value : undefined\n}\n\nconst envPathOrUndefined = (key: string): string | undefined => {\n const value = envOrUndefined(key)\n if (!value) return undefined\n const result = expandPath(value)\n return result.isRight() ? result.value : value\n}\n\nconst envOrDefault = (key: string, defaultValue: string): string => process.env[key] ?? defaultValue\n\nconst envIntOrDefault = (key: string, defaultValue: number): number => {\n const value = process.env[key]\n if (value === undefined || value === \"\") return defaultValue\n const parsed = parseInt(value, 10)\n return isNaN(parsed) ? defaultValue : parsed\n}\n\nconst parseTransport = (value: string): TransportType => {\n if (value === \"httpStream\") return \"httpStream\"\n return \"stdio\"\n}\n\nconst parseLogLevel = (value: string): LogLevel => {\n const upper = value.toUpperCase()\n if (upper === \"DEBUG\" || upper === \"INFO\" || upper === \"WARN\" || upper === \"ERROR\") {\n return upper\n }\n return \"INFO\"\n}\n\nexport const loadConfig = (): AppConfig => ({\n usptoApiKey: envOrUndefined(\"USPTO_API_KEY\"),\n patentsViewApiKey: envOrUndefined(\"PATENTSVIEW_API_KEY\"),\n epoConsumerKey: envOrUndefined(\"EPO_CONSUMER_KEY\"),\n epoConsumerSecret: envOrUndefined(\"EPO_CONSUMER_SECRET\"),\n googleApplicationCredentials: envPathOrUndefined(\"GOOGLE_APPLICATION_CREDENTIALS\"),\n googleCloudProject: envOrUndefined(\"GOOGLE_CLOUD_PROJECT\"),\n transport: parseTransport(envOrDefault(\"TRANSPORT\", \"stdio\")),\n port: envIntOrDefault(\"PORT\", 8080),\n logLevel: parseLogLevel(envOrDefault(\"LOG_LEVEL\", \"INFO\")),\n requestTimeout: envIntOrDefault(\"REQUEST_TIMEOUT\", 30000),\n maxRetries: envIntOrDefault(\"MAX_RETRIES\", 3),\n retryMinWait: envIntOrDefault(\"RETRY_MIN_WAIT\", 2000),\n retryMaxWait: envIntOrDefault(\"RETRY_MAX_WAIT\", 10000),\n})\n\nexport const getAvailableSources = (cfg: AppConfig): ApiStatus[] => [\n {\n name: \"USPTO ODP\",\n configured: cfg.usptoApiKey !== undefined,\n healthy: false,\n },\n {\n name: \"PatentsView\",\n configured: cfg.patentsViewApiKey !== undefined,\n healthy: false,\n },\n {\n name: \"EPO OPS\",\n configured: cfg.epoConsumerKey !== undefined && cfg.epoConsumerSecret !== undefined,\n healthy: false,\n },\n {\n name: \"Google BigQuery\",\n configured: cfg.googleApplicationCredentials !== undefined && cfg.googleCloudProject !== undefined,\n healthy: false,\n },\n]\n\nexport const config = loadConfig()\n"],"mappings":"yCAoBA,MAAM,EAAkB,GAAoC,CAC1D,IAAM,EAAQ,QAAQ,IAAI,GAC1B,OAAO,IAAU,IAAA,IAAa,IAAU,GAAK,EAAQ,IAAA,IAGjD,EAAsB,GAAoC,CAC9D,IAAM,EAAQ,EAAe,EAAI,CACjC,GAAI,CAAC,EAAO,OACZ,IAAM,EAAS,EAAW,EAAM,CAChC,OAAO,EAAO,SAAS,CAAG,EAAO,MAAQ,GAGrC,GAAgB,EAAa,IAAiC,QAAQ,IAAI,IAAQ,EAElF,GAAmB,EAAa,IAAiC,CACrE,IAAM,EAAQ,QAAQ,IAAI,GAC1B,GAAI,IAAU,IAAA,IAAa,IAAU,GAAI,OAAO,EAChD,IAAM,EAAS,SAAS,EAAO,GAAG,CAClC,OAAO,MAAM,EAAO,CAAG,EAAe,GAGlC,EAAkB,GAClB,IAAU,aAAqB,aAC5B,QAGH,EAAiB,GAA4B,CACjD,IAAM,EAAQ,EAAM,aAAa,CAIjC,OAHI,IAAU,SAAW,IAAU,QAAU,IAAU,QAAU,IAAU,QAClE,EAEF,QAGI,OAA+B,CAC1C,YAAa,EAAe,gBAAgB,CAC5C,kBAAmB,EAAe,sBAAsB,CACxD,eAAgB,EAAe,mBAAmB,CAClD,kBAAmB,EAAe,sBAAsB,CACxD,6BAA8B,EAAmB,iCAAiC,CAClF,mBAAoB,EAAe,uBAAuB,CAC1D,UAAW,EAAe,EAAa,YAAa,QAAQ,CAAC,CAC7D,KAAM,EAAgB,OAAQ,KAAK,CACnC,SAAU,EAAc,EAAa,YAAa,OAAO,CAAC,CAC1D,eAAgB,EAAgB,kBAAmB,IAAM,CACzD,WAAY,EAAgB,cAAe,EAAE,CAC7C,aAAc,EAAgB,iBAAkB,IAAK,CACrD,aAAc,EAAgB,iBAAkB,IAAM,CACvD,EAEY,EAAuB,GAAgC,CAClE,CACE,KAAM,YACN,WAAY,EAAI,cAAgB,IAAA,GAChC,QAAS,GACV,CACD,CACE,KAAM,cACN,WAAY,EAAI,oBAAsB,IAAA,GACtC,QAAS,GACV,CACD,CACE,KAAM,UACN,WAAY,EAAI,iBAAmB,IAAA,IAAa,EAAI,oBAAsB,IAAA,GAC1E,QAAS,GACV,CACD,CACE,KAAM,kBACN,WAAY,EAAI,+BAAiC,IAAA,IAAa,EAAI,qBAAuB,IAAA,GACzF,QAAS,GACV,CACF,CAEY,EAAS,GAAY"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patents-mcp-server",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "FastMCP TypeScript patent intelligence MCP server — 55 tools across USPTO, EPO, and BigQuery",
5
5
  "keywords": [
6
6
  "mcp",
@@ -17,11 +17,27 @@
17
17
  "type": "git",
18
18
  "url": "https://github.com/sapientsai/patents-mcp-server"
19
19
  },
20
+ "scripts": {
21
+ "validate": "ts-builds validate",
22
+ "format": "ts-builds format",
23
+ "format:check": "ts-builds format:check",
24
+ "lint": "ts-builds lint",
25
+ "lint:check": "ts-builds lint:check",
26
+ "typecheck": "ts-builds typecheck",
27
+ "test": "ts-builds test",
28
+ "test:watch": "ts-builds test:watch",
29
+ "test:coverage": "ts-builds test:coverage",
30
+ "build": "ts-builds build",
31
+ "dev": "ts-builds dev",
32
+ "codegen": "openapi-ts",
33
+ "fetch-specs": "curl -s https://search.patentsview.org/static/openapi.json > src/specs/patentsview.json && gh api repos/patent-dev/uspto-odp/contents/swagger_fixed.yaml --jq '.content' | base64 -d > src/specs/uspto-odp.yaml",
34
+ "prepublishOnly": "pnpm validate"
35
+ },
20
36
  "devDependencies": {
21
37
  "@hey-api/openapi-ts": "^0.94.1",
22
38
  "@types/node": "^24.12.0",
23
39
  "ts-builds": "^2.5.2",
24
- "tsdown": "^0.21.2"
40
+ "tsdown": "^0.21.3"
25
41
  },
26
42
  "bin": {
27
43
  "patents-mcp-server": "./dist/index.js"
@@ -42,26 +58,13 @@
42
58
  "dist"
43
59
  ],
44
60
  "prettier": "ts-builds/prettier",
61
+ "packageManager": "pnpm@10.32.1+sha512.a706938f0e89ac1456b6563eab4edf1d1faf3368d1191fc5c59790e96dc918e4456ab2e67d613de1043d2e8c81f87303e6b40d4ffeca9df15ef1ad567348f2be",
45
62
  "dependencies": {
46
63
  "@google-cloud/bigquery": "^8.1.1",
47
64
  "fast-xml-parser": "^5.5.5",
48
65
  "fastmcp": "^3.34.0",
49
66
  "functype": "^0.49.0",
67
+ "functype-os": "^0.3.0",
50
68
  "zod": "^4.3.6"
51
- },
52
- "scripts": {
53
- "validate": "ts-builds validate",
54
- "format": "ts-builds format",
55
- "format:check": "ts-builds format:check",
56
- "lint": "ts-builds lint",
57
- "lint:check": "ts-builds lint:check",
58
- "typecheck": "ts-builds typecheck",
59
- "test": "ts-builds test",
60
- "test:watch": "ts-builds test:watch",
61
- "test:coverage": "ts-builds test:coverage",
62
- "build": "ts-builds build",
63
- "dev": "ts-builds dev",
64
- "codegen": "openapi-ts",
65
- "fetch-specs": "curl -s https://search.patentsview.org/static/openapi.json > src/specs/patentsview.json && gh api repos/patent-dev/uspto-odp/contents/swagger_fixed.yaml --jq '.content' | base64 -d > src/specs/uspto-odp.yaml"
66
69
  }
67
- }
70
+ }