patents-mcp-server 1.0.2 → 1.0.3

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/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import{config as e}from"./lib/config.js";import{registerPrompts as t}from"./prompts/index.js";import{registerResources as n}from"./resources/index.js";import{server as r}from"./server.js";import{registerAllTools as i}from"./tools/index.js";i(r),n(r),t(r),e.transport===`httpStream`?r.start({transportType:`httpStream`,httpStream:{port:e.port,host:process.env.HOST??`0.0.0.0`}}):r.start({transportType:`stdio`});export{};
2
+ import{config as e}from"./lib/config.js";import{registerPrompts as t}from"./prompts/index.js";import{registerResources as n}from"./resources/index.js";import{resourceStore as r}from"./resources/store.js";import{registerResourceRoutes as i}from"./resources/routes.js";import{server as a}from"./server.js";import{registerAllTools as o}from"./tools/index.js";o(a),n(a),t(a),i(a),r.startSweep(),e.transport===`httpStream`?a.start({transportType:`httpStream`,httpStream:{port:e.port,host:process.env.HOST??`0.0.0.0`}}):a.start({transportType:`stdio`});export{};
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { config } from \"./lib/config\"\nimport { registerPrompts } from \"./prompts/index\"\nimport { registerResources } from \"./resources/index\"\nimport { server } from \"./server\"\nimport { registerAllTools } from \"./tools/index\"\n\nregisterAllTools(server)\nregisterResources(server)\nregisterPrompts(server)\n\nif (config.transport === \"httpStream\") {\n server.start({\n transportType: \"httpStream\",\n httpStream: {\n port: config.port,\n host: process.env.HOST ?? \"0.0.0.0\",\n },\n })\n} else {\n server.start({\n transportType: \"stdio\",\n })\n}\n"],"mappings":";gPAOA,EAAiB,CAAM,EACvB,EAAkB,CAAM,EACxB,EAAgB,CAAM,EAElB,EAAO,YAAc,aACvB,EAAO,MAAM,CACX,cAAe,aACf,WAAY,CACV,KAAM,EAAO,KACb,KAAM,QAAQ,IAAI,MAAQ,SAC5B,CACF,CAAC,EAED,EAAO,MAAM,CACX,cAAe,OACjB,CAAC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { config } from \"./lib/config\"\nimport { registerPrompts } from \"./prompts/index\"\nimport { registerResources } from \"./resources/index\"\nimport { registerResourceRoutes } from \"./resources/routes\"\nimport { resourceStore } from \"./resources/store\"\nimport { server } from \"./server\"\nimport { registerAllTools } from \"./tools/index\"\n\nregisterAllTools(server)\nregisterResources(server)\nregisterPrompts(server)\nregisterResourceRoutes(server)\nresourceStore.startSweep()\n\nif (config.transport === \"httpStream\") {\n server.start({\n transportType: \"httpStream\",\n httpStream: {\n port: config.port,\n host: process.env.HOST ?? \"0.0.0.0\",\n },\n })\n} else {\n server.start({\n transportType: \"stdio\",\n })\n}\n"],"mappings":";oWASA,EAAiB,CAAM,EACvB,EAAkB,CAAM,EACxB,EAAgB,CAAM,EACtB,EAAuB,CAAM,EAC7B,EAAc,WAAW,EAErB,EAAO,YAAc,aACvB,EAAO,MAAM,CACX,cAAe,aACf,WAAY,CACV,KAAM,EAAO,KACb,KAAM,QAAQ,IAAI,MAAQ,SAC5B,CACF,CAAC,EAED,EAAO,MAAM,CACX,cAAe,OACjB,CAAC"}
@@ -19,6 +19,9 @@ type AppConfig = {
19
19
  maxRetries: number;
20
20
  retryMinWait: number;
21
21
  retryMaxWait: number;
22
+ resourceDir: string;
23
+ resourceTtlSeconds: number;
24
+ publicBaseUrl: string;
22
25
  };
23
26
  declare const loadConfig: () => AppConfig;
24
27
  declare const getAvailableSources: (cfg: AppConfig) => ApiStatus[];
@@ -1,2 +1,2 @@
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=>{let n=t(e);if(n)try{return JSON.parse(n)}catch{return}},i=(e,t)=>process.env[e]??t,a=(e,t)=>{let n=process.env[e];if(n===void 0||n===``)return t;let r=parseInt(n,10);return isNaN(r)?t:r},o=e=>e===`httpStream`?`httpStream`:`stdio`,s=e=>{let t=e.toUpperCase();return t===`DEBUG`||t===`INFO`||t===`WARN`||t===`ERROR`?t:`INFO`},c=()=>({usptoApiKey:t(`USPTO_API_KEY`),epoConsumerKey:t(`EPO_CONSUMER_KEY`),epoConsumerSecret:t(`EPO_CONSUMER_SECRET`),googleApplicationCredentials:n(`GOOGLE_APPLICATION_CREDENTIALS`),googleCredentialsJson:r(`GOOGLE_CREDENTIALS_JSON`),googleCloudProject:t(`GOOGLE_CLOUD_PROJECT`),transport:o(i(`TRANSPORT`,`stdio`)),port:a(`PORT`,8080),logLevel:s(i(`LOG_LEVEL`,`INFO`)),requestTimeout:a(`REQUEST_TIMEOUT`,3e4),maxRetries:a(`MAX_RETRIES`,3),retryMinWait:a(`RETRY_MIN_WAIT`,2e3),retryMaxWait:a(`RETRY_MAX_WAIT`,1e4)}),l=e=>[{name:`USPTO ODP`,configured:e.usptoApiKey!==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.googleCredentialsJson!==void 0)&&e.googleCloudProject!==void 0,healthy:!1}],u=c();export{u as config,l as getAvailableSources,c 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=>{let n=t(e);if(n)try{return JSON.parse(n)}catch{return}},i=(e,t)=>process.env[e]??t,a=(e,t)=>{let n=process.env[e];if(n===void 0||n===``)return t;let r=parseInt(n,10);return isNaN(r)?t:r},o=e=>e===`httpStream`?`httpStream`:`stdio`,s=e=>{let t=e.toUpperCase();return t===`DEBUG`||t===`INFO`||t===`WARN`||t===`ERROR`?t:`INFO`},c=()=>({usptoApiKey:t(`USPTO_API_KEY`),epoConsumerKey:t(`EPO_CONSUMER_KEY`),epoConsumerSecret:t(`EPO_CONSUMER_SECRET`),googleApplicationCredentials:n(`GOOGLE_APPLICATION_CREDENTIALS`),googleCredentialsJson:r(`GOOGLE_CREDENTIALS_JSON`),googleCloudProject:t(`GOOGLE_CLOUD_PROJECT`),transport:o(i(`TRANSPORT`,`stdio`)),port:a(`PORT`,8080),logLevel:s(i(`LOG_LEVEL`,`INFO`)),requestTimeout:a(`REQUEST_TIMEOUT`,3e4),maxRetries:a(`MAX_RETRIES`,3),retryMinWait:a(`RETRY_MIN_WAIT`,2e3),retryMaxWait:a(`RETRY_MAX_WAIT`,1e4),resourceDir:i(`RESOURCE_DIR`,`/tmp/odp-cache`),resourceTtlSeconds:a(`RESOURCE_TTL_SECONDS`,600),publicBaseUrl:i(`PUBLIC_BASE_URL`,`https://patents.civala.ai`).replace(/\/+$/,``)}),l=e=>[{name:`USPTO ODP`,configured:e.usptoApiKey!==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.googleCredentialsJson!==void 0)&&e.googleCloudProject!==void 0,healthy:!1}],u=c();export{u as config,l as getAvailableSources,c as loadConfig};
2
2
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
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 GcpCredentials = {\n client_email: string\n private_key: string\n}\n\ntype AppConfig = {\n usptoApiKey: string | undefined\n epoConsumerKey: string | undefined\n epoConsumerSecret: string | undefined\n googleApplicationCredentials: string | undefined\n googleCredentialsJson: GcpCredentials | 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 envJsonOrUndefined = (key: string): GcpCredentials | undefined => {\n const value = envOrUndefined(key)\n if (!value) return undefined\n try {\n return JSON.parse(value) as GcpCredentials\n } catch {\n return undefined\n }\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 epoConsumerKey: envOrUndefined(\"EPO_CONSUMER_KEY\"),\n epoConsumerSecret: envOrUndefined(\"EPO_CONSUMER_SECRET\"),\n googleApplicationCredentials: envPathOrUndefined(\"GOOGLE_APPLICATION_CREDENTIALS\"),\n googleCredentialsJson: envJsonOrUndefined(\"GOOGLE_CREDENTIALS_JSON\"),\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: \"EPO OPS\",\n configured: cfg.epoConsumerKey !== undefined && cfg.epoConsumerSecret !== undefined,\n healthy: false,\n },\n {\n name: \"Google BigQuery\",\n configured:\n (cfg.googleApplicationCredentials !== undefined || cfg.googleCredentialsJson !== undefined) &&\n cfg.googleCloudProject !== undefined,\n healthy: false,\n },\n]\n\nexport const config = loadConfig()\n"],"mappings":"yCAyBA,MAAM,EAAkB,GAAoC,CAC1D,IAAM,EAAQ,QAAQ,IAAI,GAC1B,OAAO,IAAU,IAAA,IAAa,IAAU,GAAK,EAAQ,IAAA,EACvD,EAEM,EAAsB,GAAoC,CAC9D,IAAM,EAAQ,EAAe,CAAG,EAChC,GAAI,CAAC,EAAO,OACZ,IAAM,EAAS,EAAW,CAAK,EAC/B,OAAO,EAAO,QAAQ,EAAI,EAAO,MAAQ,CAC3C,EAEM,EAAsB,GAA4C,CACtE,IAAM,EAAQ,EAAe,CAAG,EAC3B,KACL,GAAI,CACF,OAAO,KAAK,MAAM,CAAK,CACzB,MAAQ,CACN,MACF,CACF,EAEM,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,EAAE,EACjC,OAAO,MAAM,CAAM,EAAI,EAAe,CACxC,EAEM,EAAkB,GAClB,IAAU,aAAqB,aAC5B,QAGH,EAAiB,GAA4B,CACjD,IAAM,EAAQ,EAAM,YAAY,EAIhC,OAHI,IAAU,SAAW,IAAU,QAAU,IAAU,QAAU,IAAU,QAClE,EAEF,MACT,EAEa,OAA+B,CAC1C,YAAa,EAAe,eAAe,EAC3C,eAAgB,EAAe,kBAAkB,EACjD,kBAAmB,EAAe,qBAAqB,EACvD,6BAA8B,EAAmB,gCAAgC,EACjF,sBAAuB,EAAmB,yBAAyB,EACnE,mBAAoB,EAAe,sBAAsB,EACzD,UAAW,EAAe,EAAa,YAAa,OAAO,CAAC,EAC5D,KAAM,EAAgB,OAAQ,IAAI,EAClC,SAAU,EAAc,EAAa,YAAa,MAAM,CAAC,EACzD,eAAgB,EAAgB,kBAAmB,GAAK,EACxD,WAAY,EAAgB,cAAe,CAAC,EAC5C,aAAc,EAAgB,iBAAkB,GAAI,EACpD,aAAc,EAAgB,iBAAkB,GAAK,CACvD,GAEa,EAAuB,GAAgC,CAClE,CACE,KAAM,YACN,WAAY,EAAI,cAAgB,IAAA,GAChC,QAAS,EACX,EACA,CACE,KAAM,UACN,WAAY,EAAI,iBAAmB,IAAA,IAAa,EAAI,oBAAsB,IAAA,GAC1E,QAAS,EACX,EACA,CACE,KAAM,kBACN,YACG,EAAI,+BAAiC,IAAA,IAAa,EAAI,wBAA0B,IAAA,KACjF,EAAI,qBAAuB,IAAA,GAC7B,QAAS,EACX,CACF,EAEa,EAAS,EAAW"}
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 GcpCredentials = {\n client_email: string\n private_key: string\n}\n\ntype AppConfig = {\n usptoApiKey: string | undefined\n epoConsumerKey: string | undefined\n epoConsumerSecret: string | undefined\n googleApplicationCredentials: string | undefined\n googleCredentialsJson: GcpCredentials | 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 resourceDir: string\n resourceTtlSeconds: number\n publicBaseUrl: string\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 envJsonOrUndefined = (key: string): GcpCredentials | undefined => {\n const value = envOrUndefined(key)\n if (!value) return undefined\n try {\n return JSON.parse(value) as GcpCredentials\n } catch {\n return undefined\n }\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 epoConsumerKey: envOrUndefined(\"EPO_CONSUMER_KEY\"),\n epoConsumerSecret: envOrUndefined(\"EPO_CONSUMER_SECRET\"),\n googleApplicationCredentials: envPathOrUndefined(\"GOOGLE_APPLICATION_CREDENTIALS\"),\n googleCredentialsJson: envJsonOrUndefined(\"GOOGLE_CREDENTIALS_JSON\"),\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 resourceDir: envOrDefault(\"RESOURCE_DIR\", \"/tmp/odp-cache\"),\n resourceTtlSeconds: envIntOrDefault(\"RESOURCE_TTL_SECONDS\", 600),\n publicBaseUrl: envOrDefault(\"PUBLIC_BASE_URL\", \"https://patents.civala.ai\").replace(/\\/+$/, \"\"),\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: \"EPO OPS\",\n configured: cfg.epoConsumerKey !== undefined && cfg.epoConsumerSecret !== undefined,\n healthy: false,\n },\n {\n name: \"Google BigQuery\",\n configured:\n (cfg.googleApplicationCredentials !== undefined || cfg.googleCredentialsJson !== undefined) &&\n cfg.googleCloudProject !== undefined,\n healthy: false,\n },\n]\n\nexport const config = loadConfig()\n"],"mappings":"yCA4BA,MAAM,EAAkB,GAAoC,CAC1D,IAAM,EAAQ,QAAQ,IAAI,GAC1B,OAAO,IAAU,IAAA,IAAa,IAAU,GAAK,EAAQ,IAAA,EACvD,EAEM,EAAsB,GAAoC,CAC9D,IAAM,EAAQ,EAAe,CAAG,EAChC,GAAI,CAAC,EAAO,OACZ,IAAM,EAAS,EAAW,CAAK,EAC/B,OAAO,EAAO,QAAQ,EAAI,EAAO,MAAQ,CAC3C,EAEM,EAAsB,GAA4C,CACtE,IAAM,EAAQ,EAAe,CAAG,EAC3B,KACL,GAAI,CACF,OAAO,KAAK,MAAM,CAAK,CACzB,MAAQ,CACN,MACF,CACF,EAEM,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,EAAE,EACjC,OAAO,MAAM,CAAM,EAAI,EAAe,CACxC,EAEM,EAAkB,GAClB,IAAU,aAAqB,aAC5B,QAGH,EAAiB,GAA4B,CACjD,IAAM,EAAQ,EAAM,YAAY,EAIhC,OAHI,IAAU,SAAW,IAAU,QAAU,IAAU,QAAU,IAAU,QAClE,EAEF,MACT,EAEa,OAA+B,CAC1C,YAAa,EAAe,eAAe,EAC3C,eAAgB,EAAe,kBAAkB,EACjD,kBAAmB,EAAe,qBAAqB,EACvD,6BAA8B,EAAmB,gCAAgC,EACjF,sBAAuB,EAAmB,yBAAyB,EACnE,mBAAoB,EAAe,sBAAsB,EACzD,UAAW,EAAe,EAAa,YAAa,OAAO,CAAC,EAC5D,KAAM,EAAgB,OAAQ,IAAI,EAClC,SAAU,EAAc,EAAa,YAAa,MAAM,CAAC,EACzD,eAAgB,EAAgB,kBAAmB,GAAK,EACxD,WAAY,EAAgB,cAAe,CAAC,EAC5C,aAAc,EAAgB,iBAAkB,GAAI,EACpD,aAAc,EAAgB,iBAAkB,GAAK,EACrD,YAAa,EAAa,eAAgB,gBAAgB,EAC1D,mBAAoB,EAAgB,uBAAwB,GAAG,EAC/D,cAAe,EAAa,kBAAmB,2BAA2B,EAAE,QAAQ,OAAQ,EAAE,CAChG,GAEa,EAAuB,GAAgC,CAClE,CACE,KAAM,YACN,WAAY,EAAI,cAAgB,IAAA,GAChC,QAAS,EACX,EACA,CACE,KAAM,UACN,WAAY,EAAI,iBAAmB,IAAA,IAAa,EAAI,oBAAsB,IAAA,GAC1E,QAAS,EACX,EACA,CACE,KAAM,kBACN,YACG,EAAI,+BAAiC,IAAA,IAAa,EAAI,wBAA0B,IAAA,KACjF,EAAI,qBAAuB,IAAA,GAC7B,QAAS,EACX,CACF,EAEa,EAAS,EAAW"}
@@ -0,0 +1,15 @@
1
+ import { FileStore } from "./store.js";
2
+ import { FastMCP } from "fastmcp";
3
+
4
+ //#region src/resources/routes.d.ts
5
+ /**
6
+ * Registers `GET /resources/:file`, serving transient PDFs written by `odp-download-document`.
7
+ *
8
+ * Access control is at the edge (the same gate that fronts `/mcp`); within the app the
9
+ * unguessable v4 UUID and the TTL are defense-in-depth, not the capability. Strict UUID
10
+ * validation runs before any filesystem access, so `:file` is never interpolated into a path.
11
+ */
12
+ declare const registerResourceRoutes: (server: FastMCP, store?: FileStore) => void;
13
+ //#endregion
14
+ export { registerResourceRoutes };
15
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{UUID_V4 as e,resourceStore as t}from"./store.js";import{createReadStream as n}from"node:fs";import{Readable as r}from"node:stream";const i=e=>new Response(e,{status:404}),a=(a,o=t)=>{a.getApp().get(`/resources/:file`,t=>{let a=t.req.param(`file`);if(!a.endsWith(`.pdf`))return i(`Not found`);let s=a.slice(0,-4);if(!e.test(s))return i(`Not found`);let c=o.getPath(s);if(!c)return i(`Not found or expired`);let l=r.toWeb(n(c));return new Response(l,{status:200,headers:{"content-type":`application/pdf`,"cache-control":`private, no-store`}})})};export{a as registerResourceRoutes};
2
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","names":[],"sources":["../../src/resources/routes.ts"],"sourcesContent":["import { createReadStream } from \"node:fs\"\nimport { Readable } from \"node:stream\"\n\nimport type { FastMCP } from \"fastmcp\"\n\nimport { type FileStore, resourceStore, UUID_V4 } from \"./store\"\n\nconst notFound = (message: string): Response => new Response(message, { status: 404 })\n\n/**\n * Registers `GET /resources/:file`, serving transient PDFs written by `odp-download-document`.\n *\n * Access control is at the edge (the same gate that fronts `/mcp`); within the app the\n * unguessable v4 UUID and the TTL are defense-in-depth, not the capability. Strict UUID\n * validation runs before any filesystem access, so `:file` is never interpolated into a path.\n */\nexport const registerResourceRoutes = (server: FastMCP, store: FileStore = resourceStore): void => {\n server.getApp().get(\"/resources/:file\", (c) => {\n const file = c.req.param(\"file\")\n if (!file.endsWith(\".pdf\")) return notFound(\"Not found\")\n\n const id = file.slice(0, -\".pdf\".length)\n if (!UUID_V4.test(id)) return notFound(\"Not found\")\n\n const path = store.getPath(id)\n if (!path) return notFound(\"Not found or expired\")\n\n const body = Readable.toWeb(createReadStream(path)) as unknown as ReadableStream\n return new Response(body, {\n status: 200,\n headers: {\n \"content-type\": \"application/pdf\",\n \"cache-control\": \"private, no-store\",\n },\n })\n })\n}\n"],"mappings":"0IAOA,MAAM,EAAY,GAA8B,IAAI,SAAS,EAAS,CAAE,OAAQ,GAAI,CAAC,EASxE,GAA0B,EAAiB,EAAmB,IAAwB,CACjG,EAAO,OAAO,EAAE,IAAI,mBAAqB,GAAM,CAC7C,IAAM,EAAO,EAAE,IAAI,MAAM,MAAM,EAC/B,GAAI,CAAC,EAAK,SAAS,MAAM,EAAG,OAAO,EAAS,WAAW,EAEvD,IAAM,EAAK,EAAK,MAAM,EAAG,EAAc,EACvC,GAAI,CAAC,EAAQ,KAAK,CAAE,EAAG,OAAO,EAAS,WAAW,EAElD,IAAM,EAAO,EAAM,QAAQ,CAAE,EAC7B,GAAI,CAAC,EAAM,OAAO,EAAS,sBAAsB,EAEjD,IAAM,EAAO,EAAS,MAAM,EAAiB,CAAI,CAAC,EAClD,OAAO,IAAI,SAAS,EAAM,CACxB,OAAQ,IACR,QAAS,CACP,eAAgB,kBAChB,gBAAiB,mBACnB,CACF,CAAC,CACH,CAAC,CACH"}
@@ -0,0 +1,25 @@
1
+ //#region src/resources/store.d.ts
2
+ /** Strict v4 UUID — the only shape a resource id may take. */
3
+ declare const UUID_V4: RegExp;
4
+ type FileStore = {
5
+ /** TTL the store enforces, in seconds — surfaced so callers can report `expiresInSeconds`. */readonly ttlSeconds: number; /** Writes `{id}.{ext}` and returns the generated UUID. */
6
+ put(buf: Buffer, ext: string): {
7
+ id: string;
8
+ }; /** Path for `id` if a file exists and is within TTL; otherwise unlinks-if-stale and returns null. */
9
+ getPath(id: string): string | null; /** Unlinks every file older than TTL. */
10
+ sweep(): void; /** Starts a single unref'd background sweep; idempotent across calls. */
11
+ startSweep(): void;
12
+ };
13
+ type FileStoreOptions = {
14
+ readonly dir: string;
15
+ readonly ttlSeconds: number;
16
+ };
17
+ declare const createFileStore: ({
18
+ dir,
19
+ ttlSeconds
20
+ }: FileStoreOptions) => FileStore;
21
+ /** Default store wired to env-derived config; the deployed server's transient PDF cache. */
22
+ declare const resourceStore: FileStore;
23
+ //#endregion
24
+ export { FileStore, FileStoreOptions, UUID_V4, createFileStore, resourceStore };
25
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{config as e}from"../lib/config.js";import{existsSync as t,mkdirSync as n,readdirSync as r,statSync as i,unlinkSync as a,writeFileSync as o}from"node:fs";import{randomUUID as s}from"node:crypto";import{join as c}from"node:path";const l=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,u=({dir:e,ttlSeconds:u})=>{let d=u*1e3,f=()=>{t(e)||n(e,{recursive:!0})},p=e=>Date.now()-i(e).mtimeMs>d;f();let m=!1,h=()=>{if(t(e))for(let t of r(e)){let n=c(e,t);try{p(n)&&a(n)}catch{}}};return{ttlSeconds:u,put(t,n){f();let r=s();return o(c(e,`${r}.${n}`),t),{id:r}},getPath(n){if(!l.test(n)||!t(e))return null;let i=r(e).find(e=>e.startsWith(`${n}.`));if(!i)return null;let o=c(e,i);return p(o)?(a(o),null):o},sweep:h,startSweep(){m||(m=!0,setInterval(h,d).unref())}}},d=u({dir:e.resourceDir,ttlSeconds:e.resourceTtlSeconds});export{l as UUID_V4,u as createFileStore,d as resourceStore};
2
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","names":[],"sources":["../../src/resources/store.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\"\nimport { existsSync, mkdirSync, readdirSync, statSync, unlinkSync, writeFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\n\nimport { config } from \"../lib/config\"\n\n/** Strict v4 UUID — the only shape a resource id may take. */\nexport const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/\n\nexport type FileStore = {\n /** TTL the store enforces, in seconds — surfaced so callers can report `expiresInSeconds`. */\n readonly ttlSeconds: number\n /** Writes `{id}.{ext}` and returns the generated UUID. */\n put(buf: Buffer, ext: string): { id: string }\n /** Path for `id` if a file exists and is within TTL; otherwise unlinks-if-stale and returns null. */\n getPath(id: string): string | null\n /** Unlinks every file older than TTL. */\n sweep(): void\n /** Starts a single unref'd background sweep; idempotent across calls. */\n startSweep(): void\n}\n\nexport type FileStoreOptions = {\n readonly dir: string\n readonly ttlSeconds: number\n}\n\nexport const createFileStore = ({ dir, ttlSeconds }: FileStoreOptions): FileStore => {\n const ttlMs = ttlSeconds * 1000\n\n const ensureDir = (): void => {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true })\n }\n\n const isExpired = (path: string): boolean => Date.now() - statSync(path).mtimeMs > ttlMs\n\n ensureDir()\n\n let sweepStarted = false\n\n const sweep = (): void => {\n if (!existsSync(dir)) return\n for (const name of readdirSync(dir)) {\n const path = join(dir, name)\n try {\n if (isExpired(path)) unlinkSync(path)\n } catch {\n // File was removed concurrently (read/sweep race) — nothing to clean up.\n }\n }\n }\n\n return {\n ttlSeconds,\n\n put(buf, ext) {\n ensureDir()\n const id = randomUUID()\n writeFileSync(join(dir, `${id}.${ext}`), buf)\n return { id }\n },\n\n getPath(id) {\n if (!UUID_V4.test(id)) return null\n if (!existsSync(dir)) return null\n const match = readdirSync(dir).find((name) => name.startsWith(`${id}.`))\n if (!match) return null\n const path = join(dir, match)\n if (isExpired(path)) {\n unlinkSync(path)\n return null\n }\n return path\n },\n\n sweep,\n\n startSweep() {\n if (sweepStarted) return\n sweepStarted = true\n // unref so the interval never keeps the process alive (stdio transport, tests).\n setInterval(sweep, ttlMs).unref()\n },\n }\n}\n\n/** Default store wired to env-derived config; the deployed server's transient PDF cache. */\nexport const resourceStore = createFileStore({\n dir: config.resourceDir,\n ttlSeconds: config.resourceTtlSeconds,\n})\n"],"mappings":"0OAOA,MAAa,EAAU,wEAoBV,GAAmB,CAAE,MAAK,gBAA8C,CACnF,IAAM,EAAQ,EAAa,IAErB,MAAwB,CACvB,EAAW,CAAG,GAAG,EAAU,EAAK,CAAE,UAAW,EAAK,CAAC,CAC1D,EAEM,EAAa,GAA0B,KAAK,IAAI,EAAI,EAAS,CAAI,EAAE,QAAU,EAEnF,EAAU,EAEV,IAAI,EAAe,GAEb,MAAoB,CACnB,KAAW,CAAG,EACnB,IAAK,IAAM,KAAQ,EAAY,CAAG,EAAG,CACnC,IAAM,EAAO,EAAK,EAAK,CAAI,EAC3B,GAAI,CACE,EAAU,CAAI,GAAG,EAAW,CAAI,CACtC,MAAQ,CAER,CACF,CACF,EAEA,MAAO,CACL,aAEA,IAAI,EAAK,EAAK,CACZ,EAAU,EACV,IAAM,EAAK,EAAW,EAEtB,OADA,EAAc,EAAK,EAAK,GAAG,EAAG,GAAG,GAAK,EAAG,CAAG,EACrC,CAAE,IAAG,CACd,EAEA,QAAQ,EAAI,CAEV,GADI,CAAC,EAAQ,KAAK,CAAE,GAChB,CAAC,EAAW,CAAG,EAAG,OAAO,KAC7B,IAAM,EAAQ,EAAY,CAAG,EAAE,KAAM,GAAS,EAAK,WAAW,GAAG,EAAG,EAAE,CAAC,EACvE,GAAI,CAAC,EAAO,OAAO,KACnB,IAAM,EAAO,EAAK,EAAK,CAAK,EAK5B,OAJI,EAAU,CAAI,GAChB,EAAW,CAAI,EACR,MAEF,CACT,EAEA,QAEA,YAAa,CACP,IACJ,EAAe,GAEf,YAAY,EAAO,CAAK,EAAE,MAAM,EAClC,CACF,CACF,EAGa,EAAgB,EAAgB,CAC3C,IAAK,EAAO,YACZ,WAAY,EAAO,kBACrB,CAAC"}
@@ -1,7 +1,15 @@
1
+ import { OdpClient } from "../clients/odp.client.js";
2
+ import { FileStore } from "../resources/store.js";
1
3
  import { FastMCP } from "fastmcp";
2
4
 
3
5
  //#region src/tools/odp.tools.d.ts
6
+ /**
7
+ * Fetches a file-wrapper PDF from USPTO, stashes it in the transient store, and returns the
8
+ * JSON payload the tool surfaces: a fetchable URL on the server's own host (never the bytes,
9
+ * never the USPTO key). Exported for testing.
10
+ */
11
+ declare const buildDownloadResult: (client: Pick<OdpClient, "downloadDocument">, applicationNumberText: string, documentIdentifier: string, store?: FileStore, baseUrl?: string) => Promise<string>;
4
12
  declare const registerOdpTools: (server: FastMCP) => void;
5
13
  //#endregion
6
- export { registerOdpTools };
14
+ export { buildDownloadResult, registerOdpTools };
7
15
  //# sourceMappingURL=odp.tools.d.ts.map
@@ -1,2 +1,2 @@
1
- import{config as e}from"../lib/config.js";import{handleApiError as t}from"../lib/errors.js";import{OdpClient as n}from"../clients/odp.client.js";import{z as r}from"zod";const i={readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0},a=()=>{if(!e.usptoApiKey)throw Error(`USPTO_API_KEY is required for ODP tools`);return new n({apiKey:e.usptoApiKey,timeout:e.requestTimeout})},o=e=>{e.addTool({name:`odp-search-applications`,description:`Search USPTO patent applications via the Open Data Portal. Coverage: applications filed January 1, 2001 and later. Supports full-text search across application data.`,parameters:r.object({query:r.string().describe(`Search query text`),limit:r.number().int().min(1).max(100).default(25).describe(`Number of results to return (1-100)`),offset:r.number().int().min(0).default(0).describe(`Result offset for pagination`),sort:r.string().optional().describe(`Sort field and direction`)}),annotations:i,execute:async e=>{try{let t=await a().searchApplications(e.query,e.limit,e.offset,e.sort);return JSON.stringify(t)}catch(e){return t(e)}}}),e.addTool({name:`odp-get-application`,description:`Get detailed information about a specific USPTO patent application by application number. Returns filing data, status, claims, and other application details.`,parameters:r.object({applicationNumberText:r.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:i,execute:async e=>{try{let t=await a().getApplication(e.applicationNumberText);return JSON.stringify(t)}catch(e){return t(e)}}}),e.addTool({name:`odp-get-application-metadata`,description:`Get metadata for a USPTO patent application including application type, entity status, and dates.`,parameters:r.object({applicationNumberText:r.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:i,execute:async e=>{try{let t=await a().getApplicationMetadata(e.applicationNumberText);return JSON.stringify(t)}catch(e){return t(e)}}}),e.addTool({name:`odp-get-continuity`,description:`Get continuity data (parent/child relationships) for a patent application. Shows continuation, divisional, and CIP relationships.`,parameters:r.object({applicationNumberText:r.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:i,execute:async e=>{try{let t=await a().getContinuity(e.applicationNumberText);return JSON.stringify(t)}catch(e){return t(e)}}}),e.addTool({name:`odp-get-assignment`,description:`Get assignment/ownership records for a patent application. Shows current and historical assignees.`,parameters:r.object({applicationNumberText:r.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:i,execute:async e=>{try{let t=await a().getAssignment(e.applicationNumberText);return JSON.stringify(t)}catch(e){return t(e)}}}),e.addTool({name:`odp-get-adjustment`,description:`Get patent term adjustment (PTA) data for an application. Shows delays attributable to the USPTO and applicant.`,parameters:r.object({applicationNumberText:r.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:i,execute:async e=>{try{let t=await a().getAdjustment(e.applicationNumberText);return JSON.stringify(t)}catch(e){return t(e)}}}),e.addTool({name:`odp-get-attorney`,description:`Get attorney/agent information for a patent application.`,parameters:r.object({applicationNumberText:r.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:i,execute:async e=>{try{let t=await a().getAttorney(e.applicationNumberText);return JSON.stringify(t)}catch(e){return t(e)}}}),e.addTool({name:`odp-get-foreign-priority`,description:`Get foreign priority claims for a patent application.`,parameters:r.object({applicationNumberText:r.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:i,execute:async e=>{try{let t=await a().getForeignPriority(e.applicationNumberText);return JSON.stringify(t)}catch(e){return t(e)}}}),e.addTool({name:`odp-get-transactions`,description:`Get transaction history for a patent application. Shows all prosecution events in chronological order.`,parameters:r.object({applicationNumberText:r.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:i,execute:async e=>{try{let t=await a().getTransactions(e.applicationNumberText);return JSON.stringify(t)}catch(e){return t(e)}}}),e.addTool({name:`odp-get-documents`,description:`Get document listing for a patent application. Returns metadata about filed and issued documents.`,parameters:r.object({applicationNumberText:r.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:i,execute:async e=>{try{let t=await a().getDocuments(e.applicationNumberText);return JSON.stringify(t)}catch(e){return t(e)}}}),e.addTool({name:`odp-download-document`,description:`Download a patent file-wrapper document as a PDF from the USPTO Open Data Portal. Provide an application number and the documentIdentifier from odp-get-documents (downloadOptionBag). The server's USPTO_API_KEY authenticates the fetch and follows the ODP redirect; the PDF is returned as a base64 resource.`,parameters:r.object({applicationNumberText:r.string().describe(`Application number (e.g., 16/123,456 or 16123456)`),documentIdentifier:r.string().describe(`Document identifier from odp-get-documents downloadOptionBag (e.g., 'M4IR8IRKWFYGX56')`)}),annotations:i,execute:async e=>{try{let{data:t}=await a().downloadDocument(e.applicationNumberText,e.documentIdentifier);return{content:[{type:`resource`,resource:{uri:`https://api.uspto.gov/api/v1/download/applications/${e.applicationNumberText}/${e.documentIdentifier}.pdf`,mimeType:`application/pdf`,blob:Buffer.from(t).toString(`base64`)}}]}}catch(e){return t(e)}}}),e.addTool({name:`odp-search-datasets`,description:`Search USPTO bulk data datasets available through the Open Data Portal.`,parameters:r.object({query:r.string().describe(`Search query for datasets`)}),annotations:i,execute:async e=>{try{let t=await a().searchDatasets(e.query);return JSON.stringify(t)}catch(e){return t(e)}}}),e.addTool({name:`odp-get-dataset`,description:`Get details about a specific USPTO bulk data dataset by product ID.`,parameters:r.object({productId:r.string().describe(`Dataset product identifier`)}),annotations:i,execute:async e=>{try{let t=await a().getDataset(e.productId);return JSON.stringify(t)}catch(e){return t(e)}}})};export{o as registerOdpTools};
1
+ import{config as e}from"../lib/config.js";import{resourceStore as t}from"../resources/store.js";import{handleApiError as n}from"../lib/errors.js";import{OdpClient as r}from"../clients/odp.client.js";import{z as i}from"zod";const a={readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0},o=()=>{if(!e.usptoApiKey)throw Error(`USPTO_API_KEY is required for ODP tools`);return new r({apiKey:e.usptoApiKey,timeout:e.requestTimeout})},s=async(n,r,i,a=t,o=e.publicBaseUrl)=>{let{data:s}=await n.downloadDocument(r,i),{id:c}=a.put(Buffer.from(s),`pdf`);return JSON.stringify({url:`${o}/resources/${c}.pdf`,mimeType:`application/pdf`,expiresInSeconds:a.ttlSeconds})},c=e=>{e.addTool({name:`odp-search-applications`,description:`Search USPTO patent applications via the Open Data Portal. Coverage: applications filed January 1, 2001 and later. Supports full-text search across application data.`,parameters:i.object({query:i.string().describe(`Search query text`),limit:i.number().int().min(1).max(100).default(25).describe(`Number of results to return (1-100)`),offset:i.number().int().min(0).default(0).describe(`Result offset for pagination`),sort:i.string().optional().describe(`Sort field and direction`)}),annotations:a,execute:async e=>{try{let t=await o().searchApplications(e.query,e.limit,e.offset,e.sort);return JSON.stringify(t)}catch(e){return n(e)}}}),e.addTool({name:`odp-get-application`,description:`Get detailed information about a specific USPTO patent application by application number. Returns filing data, status, claims, and other application details.`,parameters:i.object({applicationNumberText:i.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:a,execute:async e=>{try{let t=await o().getApplication(e.applicationNumberText);return JSON.stringify(t)}catch(e){return n(e)}}}),e.addTool({name:`odp-get-application-metadata`,description:`Get metadata for a USPTO patent application including application type, entity status, and dates.`,parameters:i.object({applicationNumberText:i.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:a,execute:async e=>{try{let t=await o().getApplicationMetadata(e.applicationNumberText);return JSON.stringify(t)}catch(e){return n(e)}}}),e.addTool({name:`odp-get-continuity`,description:`Get continuity data (parent/child relationships) for a patent application. Shows continuation, divisional, and CIP relationships.`,parameters:i.object({applicationNumberText:i.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:a,execute:async e=>{try{let t=await o().getContinuity(e.applicationNumberText);return JSON.stringify(t)}catch(e){return n(e)}}}),e.addTool({name:`odp-get-assignment`,description:`Get assignment/ownership records for a patent application. Shows current and historical assignees.`,parameters:i.object({applicationNumberText:i.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:a,execute:async e=>{try{let t=await o().getAssignment(e.applicationNumberText);return JSON.stringify(t)}catch(e){return n(e)}}}),e.addTool({name:`odp-get-adjustment`,description:`Get patent term adjustment (PTA) data for an application. Shows delays attributable to the USPTO and applicant.`,parameters:i.object({applicationNumberText:i.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:a,execute:async e=>{try{let t=await o().getAdjustment(e.applicationNumberText);return JSON.stringify(t)}catch(e){return n(e)}}}),e.addTool({name:`odp-get-attorney`,description:`Get attorney/agent information for a patent application.`,parameters:i.object({applicationNumberText:i.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:a,execute:async e=>{try{let t=await o().getAttorney(e.applicationNumberText);return JSON.stringify(t)}catch(e){return n(e)}}}),e.addTool({name:`odp-get-foreign-priority`,description:`Get foreign priority claims for a patent application.`,parameters:i.object({applicationNumberText:i.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:a,execute:async e=>{try{let t=await o().getForeignPriority(e.applicationNumberText);return JSON.stringify(t)}catch(e){return n(e)}}}),e.addTool({name:`odp-get-transactions`,description:`Get transaction history for a patent application. Shows all prosecution events in chronological order.`,parameters:i.object({applicationNumberText:i.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:a,execute:async e=>{try{let t=await o().getTransactions(e.applicationNumberText);return JSON.stringify(t)}catch(e){return n(e)}}}),e.addTool({name:`odp-get-documents`,description:`Get document listing for a patent application. Returns metadata about filed and issued documents.`,parameters:i.object({applicationNumberText:i.string().describe(`Application number (e.g., 16/123,456 or 16123456)`)}),annotations:a,execute:async e=>{try{let t=await o().getDocuments(e.applicationNumberText);return JSON.stringify(t)}catch(e){return n(e)}}}),e.addTool({name:`odp-download-document`,description:`Download a patent file-wrapper document as a PDF from the USPTO Open Data Portal. Provide an application number and the documentIdentifier from odp-get-documents (downloadOptionBag). The server's USPTO_API_KEY authenticates the fetch and follows the ODP redirect, then caches the PDF transiently and returns a fetchable URL — JSON of the form { url, mimeType, expiresInSeconds }. Fetch the URL to retrieve the PDF; it expires after expiresInSeconds.`,parameters:i.object({applicationNumberText:i.string().describe(`Application number (e.g., 16/123,456 or 16123456)`),documentIdentifier:i.string().describe(`Document identifier from odp-get-documents downloadOptionBag (e.g., 'M4IR8IRKWFYGX56')`)}),annotations:a,execute:async e=>{try{return await s(o(),e.applicationNumberText,e.documentIdentifier)}catch(e){return n(e)}}}),e.addTool({name:`odp-search-datasets`,description:`Search USPTO bulk data datasets available through the Open Data Portal.`,parameters:i.object({query:i.string().describe(`Search query for datasets`)}),annotations:a,execute:async e=>{try{let t=await o().searchDatasets(e.query);return JSON.stringify(t)}catch(e){return n(e)}}}),e.addTool({name:`odp-get-dataset`,description:`Get details about a specific USPTO bulk data dataset by product ID.`,parameters:i.object({productId:i.string().describe(`Dataset product identifier`)}),annotations:a,execute:async e=>{try{let t=await o().getDataset(e.productId);return JSON.stringify(t)}catch(e){return n(e)}}})};export{s as buildDownloadResult,c as registerOdpTools};
2
2
  //# sourceMappingURL=odp.tools.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"odp.tools.js","names":[],"sources":["../../src/tools/odp.tools.ts"],"sourcesContent":["import type { FastMCP } from \"fastmcp\"\nimport { z } from \"zod\"\n\nimport { OdpClient } from \"../clients/odp.client\"\nimport { config } from \"../lib/config\"\nimport { handleApiError } from \"../lib/errors\"\n\nconst ODP_ANNOTATIONS = {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n} as const\n\nconst createClient = (): OdpClient => {\n if (!config.usptoApiKey) {\n throw new Error(\"USPTO_API_KEY is required for ODP tools\")\n }\n return new OdpClient({\n apiKey: config.usptoApiKey,\n timeout: config.requestTimeout,\n })\n}\n\nexport const registerOdpTools = (server: FastMCP): void => {\n server.addTool({\n name: \"odp-search-applications\",\n description:\n \"Search USPTO patent applications via the Open Data Portal. Coverage: applications filed January 1, 2001 and later. Supports full-text search across application data.\",\n parameters: z.object({\n query: z.string().describe(\"Search query text\"),\n limit: z.number().int().min(1).max(100).default(25).describe(\"Number of results to return (1-100)\"),\n offset: z.number().int().min(0).default(0).describe(\"Result offset for pagination\"),\n sort: z.string().optional().describe(\"Sort field and direction\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.searchApplications(args.query, args.limit, args.offset, args.sort)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-application\",\n description:\n \"Get detailed information about a specific USPTO patent application by application number. Returns filing data, status, claims, and other application details.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getApplication(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-application-metadata\",\n description: \"Get metadata for a USPTO patent application including application type, entity status, and dates.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getApplicationMetadata(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-continuity\",\n description:\n \"Get continuity data (parent/child relationships) for a patent application. Shows continuation, divisional, and CIP relationships.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getContinuity(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-assignment\",\n description: \"Get assignment/ownership records for a patent application. Shows current and historical assignees.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getAssignment(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-adjustment\",\n description:\n \"Get patent term adjustment (PTA) data for an application. Shows delays attributable to the USPTO and applicant.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getAdjustment(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-attorney\",\n description: \"Get attorney/agent information for a patent application.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getAttorney(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-foreign-priority\",\n description: \"Get foreign priority claims for a patent application.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getForeignPriority(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-transactions\",\n description:\n \"Get transaction history for a patent application. Shows all prosecution events in chronological order.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getTransactions(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-documents\",\n description: \"Get document listing for a patent application. Returns metadata about filed and issued documents.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getDocuments(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-download-document\",\n description:\n \"Download a patent file-wrapper document as a PDF from the USPTO Open Data Portal. Provide an application number and the documentIdentifier from odp-get-documents (downloadOptionBag). The server's USPTO_API_KEY authenticates the fetch and follows the ODP redirect; the PDF is returned as a base64 resource.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n documentIdentifier: z\n .string()\n .describe(\"Document identifier from odp-get-documents downloadOptionBag (e.g., 'M4IR8IRKWFYGX56')\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const { data } = await client.downloadDocument(args.applicationNumberText, args.documentIdentifier)\n return {\n content: [\n {\n type: \"resource\",\n resource: {\n uri: `https://api.uspto.gov/api/v1/download/applications/${args.applicationNumberText}/${args.documentIdentifier}.pdf`,\n mimeType: \"application/pdf\",\n blob: Buffer.from(data).toString(\"base64\"),\n },\n },\n ],\n }\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-search-datasets\",\n description: \"Search USPTO bulk data datasets available through the Open Data Portal.\",\n parameters: z.object({\n query: z.string().describe(\"Search query for datasets\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.searchDatasets(args.query)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-dataset\",\n description: \"Get details about a specific USPTO bulk data dataset by product ID.\",\n parameters: z.object({\n productId: z.string().describe(\"Dataset product identifier\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getDataset(args.productId)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"odp.tools.js","names":[],"sources":["../../src/tools/odp.tools.ts"],"sourcesContent":["import type { FastMCP } from \"fastmcp\"\nimport { z } from \"zod\"\n\nimport { OdpClient } from \"../clients/odp.client\"\nimport { config } from \"../lib/config\"\nimport { handleApiError } from \"../lib/errors\"\nimport { type FileStore, resourceStore } from \"../resources/store\"\n\nconst ODP_ANNOTATIONS = {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n} as const\n\nconst createClient = (): OdpClient => {\n if (!config.usptoApiKey) {\n throw new Error(\"USPTO_API_KEY is required for ODP tools\")\n }\n return new OdpClient({\n apiKey: config.usptoApiKey,\n timeout: config.requestTimeout,\n })\n}\n\n/**\n * Fetches a file-wrapper PDF from USPTO, stashes it in the transient store, and returns the\n * JSON payload the tool surfaces: a fetchable URL on the server's own host (never the bytes,\n * never the USPTO key). Exported for testing.\n */\nexport const buildDownloadResult = async (\n client: Pick<OdpClient, \"downloadDocument\">,\n applicationNumberText: string,\n documentIdentifier: string,\n store: FileStore = resourceStore,\n baseUrl: string = config.publicBaseUrl,\n): Promise<string> => {\n const { data } = await client.downloadDocument(applicationNumberText, documentIdentifier)\n const { id } = store.put(Buffer.from(data), \"pdf\")\n return JSON.stringify({\n url: `${baseUrl}/resources/${id}.pdf`,\n mimeType: \"application/pdf\",\n expiresInSeconds: store.ttlSeconds,\n })\n}\n\nexport const registerOdpTools = (server: FastMCP): void => {\n server.addTool({\n name: \"odp-search-applications\",\n description:\n \"Search USPTO patent applications via the Open Data Portal. Coverage: applications filed January 1, 2001 and later. Supports full-text search across application data.\",\n parameters: z.object({\n query: z.string().describe(\"Search query text\"),\n limit: z.number().int().min(1).max(100).default(25).describe(\"Number of results to return (1-100)\"),\n offset: z.number().int().min(0).default(0).describe(\"Result offset for pagination\"),\n sort: z.string().optional().describe(\"Sort field and direction\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.searchApplications(args.query, args.limit, args.offset, args.sort)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-application\",\n description:\n \"Get detailed information about a specific USPTO patent application by application number. Returns filing data, status, claims, and other application details.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getApplication(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-application-metadata\",\n description: \"Get metadata for a USPTO patent application including application type, entity status, and dates.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getApplicationMetadata(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-continuity\",\n description:\n \"Get continuity data (parent/child relationships) for a patent application. Shows continuation, divisional, and CIP relationships.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getContinuity(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-assignment\",\n description: \"Get assignment/ownership records for a patent application. Shows current and historical assignees.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getAssignment(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-adjustment\",\n description:\n \"Get patent term adjustment (PTA) data for an application. Shows delays attributable to the USPTO and applicant.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getAdjustment(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-attorney\",\n description: \"Get attorney/agent information for a patent application.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getAttorney(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-foreign-priority\",\n description: \"Get foreign priority claims for a patent application.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getForeignPriority(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-transactions\",\n description:\n \"Get transaction history for a patent application. Shows all prosecution events in chronological order.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getTransactions(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-documents\",\n description: \"Get document listing for a patent application. Returns metadata about filed and issued documents.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getDocuments(args.applicationNumberText)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-download-document\",\n description:\n \"Download a patent file-wrapper document as a PDF from the USPTO Open Data Portal. Provide an application number and the documentIdentifier from odp-get-documents (downloadOptionBag). The server's USPTO_API_KEY authenticates the fetch and follows the ODP redirect, then caches the PDF transiently and returns a fetchable URL — JSON of the form { url, mimeType, expiresInSeconds }. Fetch the URL to retrieve the PDF; it expires after expiresInSeconds.\",\n parameters: z.object({\n applicationNumberText: z.string().describe(\"Application number (e.g., 16/123,456 or 16123456)\"),\n documentIdentifier: z\n .string()\n .describe(\"Document identifier from odp-get-documents downloadOptionBag (e.g., 'M4IR8IRKWFYGX56')\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n return await buildDownloadResult(client, args.applicationNumberText, args.documentIdentifier)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-search-datasets\",\n description: \"Search USPTO bulk data datasets available through the Open Data Portal.\",\n parameters: z.object({\n query: z.string().describe(\"Search query for datasets\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.searchDatasets(args.query)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n\n server.addTool({\n name: \"odp-get-dataset\",\n description: \"Get details about a specific USPTO bulk data dataset by product ID.\",\n parameters: z.object({\n productId: z.string().describe(\"Dataset product identifier\"),\n }),\n annotations: ODP_ANNOTATIONS,\n execute: async (args) => {\n try {\n const client = createClient()\n const result = await client.getDataset(args.productId)\n return JSON.stringify(result)\n } catch (error) {\n return handleApiError(error)\n }\n },\n })\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patents-mcp-server",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "FastMCP TypeScript patent intelligence MCP server — 55 tools across USPTO, EPO, and BigQuery",
5
5
  "keywords": [
6
6
  "mcp",
@@ -36,7 +36,7 @@
36
36
  "devDependencies": {
37
37
  "@hey-api/openapi-ts": "^0.94.5",
38
38
  "@types/node": "^24.12.4",
39
- "ts-builds": "^2.8.1",
39
+ "ts-builds": "^2.8.2",
40
40
  "tsdown": "^0.22.1"
41
41
  },
42
42
  "bin": {
@@ -63,8 +63,8 @@
63
63
  "@google-cloud/bigquery": "^8.3.1",
64
64
  "fast-xml-parser": "^5.8.0",
65
65
  "fastmcp": "^4.0.1",
66
- "functype": "^1.0.1",
67
- "functype-os": "^1.0.1",
66
+ "functype": "^1.2.0",
67
+ "functype-os": "^1.2.0",
68
68
  "zod": "^4.4.3"
69
69
  }
70
70
  }