UNPKG

trademark-mcp-server

Version:

A Model Context Protocol (MCP) server that provides tools for searching and retrieving USPTO trademark information using the TSDR API.

289 lines (262 loc) 10.9 kB
"use strict"; // src/index.ts var import_fastmcp = require("fastmcp"); var import_zod = require("zod"); var server = new import_fastmcp.FastMCP({ name: "trademark-mcp-server", version: "1.0.0", instructions: ` This MCP server provides tools for searching and retrieving USPTO trademark information using the TSDR API. Available tools: - trademark_search_by_serial: Search for trademarks by 8-digit serial number - trademark_search_by_registration: Search for trademarks by 7-8 digit registration number - trademark_status: Get detailed status information for a specific trademark - trademark_image: Retrieve trademark image URLs - trademark_documents: Get document bundle URLs for a trademark The server uses the USPTO TSDR (Trademark Status & Document Retrieval) API to provide real-time trademark data. Rate limits: 60 requests per minute for general API calls, 4 requests per minute for PDF/ZIP downloads. IMPORTANT: An API key is required to access the USPTO TSDR API (since October 2020). Set the USPTO_API_KEY environment variable with your API key from https://developer.uspto.gov/ ` }); var TSDR_BASE_URL = "https://tsdrapi.uspto.gov/ts/cd"; var API_KEY = process.env.USPTO_API_KEY; function getHeaders() { const headers = { "User-Agent": "trademark-mcp-server/1.0.0" }; if (API_KEY) { headers["USPTO-API-KEY"] = API_KEY; } return headers; } function checkApiKey() { if (!API_KEY) { return "\u274C USPTO API key not configured. Please set the USPTO_API_KEY environment variable with your API key from https://account.uspto.gov/api-manager/"; } return null; } server.addTool({ name: "trademark_search_by_serial", description: "Search for trademark information using a serial number", parameters: import_zod.z.object({ serialNumber: import_zod.z.string().min(8).max(8).describe("8-digit trademark serial number"), format: import_zod.z.enum(["json", "xml"]).default("json").describe("Response format") }), annotations: { title: "Trademark Search by Serial Number", readOnlyHint: true, openWorldHint: true }, execute: async (args) => { const apiKeyError = checkApiKey(); if (apiKeyError) { return apiKeyError; } try { const fileExtension = args.format === "json" ? "json" : "xml"; const url = `${TSDR_BASE_URL}/casestatus/sn${args.serialNumber}/info.${fileExtension}`; const response = await fetch(url, { headers: getHeaders() }); if (!response.ok) { const errorText = await response.text(); if (errorText.includes("need to register for an API key")) { throw new Error(`\u{1F511} USPTO API Authentication Issue The USPTO TSDR API is rejecting our API key. This could be due to: 1. **API Key Activation Delay**: New keys may need 24-48 hours to activate 2. **Endpoint Restrictions**: Individual record endpoints may be temporarily disabled 3. **Authentication Method**: The API might require a different authentication format **Your API Key**: ${API_KEY ? `${API_KEY.substring(0, 8)}...` : "Not set"} **Next Steps**: \u2022 Contact USPTO support: APIhelp@uspto.gov \u2022 Include your API key and this error message \u2022 Ask specifically about individual record endpoint access **Alternative**: Try bulk data download endpoints if available.`); } throw new Error(`USPTO API returned ${response.status}: ${response.statusText}. Error: ${errorText}`); } if (args.format === "json") { const jsonData = await response.json(); return JSON.stringify(jsonData, null, 2); } else { const xmlData = await response.text(); return xmlData; } } catch (error) { return `Error fetching trademark data: ${error instanceof Error ? error.message : String(error)}`; } } }); server.addTool({ name: "trademark_status", description: "Get comprehensive status information for a trademark by serial number", parameters: import_zod.z.object({ serialNumber: import_zod.z.string().min(8).max(8).describe("8-digit trademark serial number") }), annotations: { title: "Trademark Status Lookup", readOnlyHint: true, openWorldHint: true }, execute: async (args) => { const apiKeyError = checkApiKey(); if (apiKeyError) { return apiKeyError; } try { const url = `${TSDR_BASE_URL}/casestatus/sn${args.serialNumber}/content`; const response = await fetch(url, { headers: getHeaders() }); if (!response.ok) { const errorText = await response.text(); if (errorText.includes("need to register for an API key")) { throw new Error(`\u{1F511} USPTO API Authentication Issue The USPTO TSDR API is rejecting our API key. This could be due to: 1. **API Key Activation Delay**: New keys may need 24-48 hours to activate 2. **Endpoint Restrictions**: Individual record endpoints may be temporarily disabled 3. **Authentication Method**: The API might require a different authentication format **Your API Key**: ${API_KEY ? `${API_KEY.substring(0, 8)}...` : "Not set"} **Next Steps**: \u2022 Contact USPTO support: APIhelp@uspto.gov \u2022 Include your API key and this error message \u2022 Ask specifically about individual record endpoint access **Alternative**: Try bulk data download endpoints if available.`); } throw new Error(`USPTO API returned ${response.status}: ${response.statusText}. Error: ${errorText}`); } const htmlContent = await response.text(); const titleMatch = htmlContent.match(/<title>(.*?)<\/title>/i); const title = titleMatch ? titleMatch[1] : "No title found"; return `Trademark Status Report for Serial Number: ${args.serialNumber} Title: ${title} Full HTML content available at: ${url} Note: This tool returns the HTML content from the USPTO. For structured data, use trademark_search_by_serial instead.`; } catch (error) { return `Error fetching trademark status: ${error instanceof Error ? error.message : String(error)}`; } } }); server.addTool({ name: "trademark_image", description: "Get the image URL for a trademark by serial number", parameters: import_zod.z.object({ serialNumber: import_zod.z.string().min(8).max(8).describe("8-digit trademark serial number") }), annotations: { title: "Trademark Image Retrieval", readOnlyHint: true, openWorldHint: true }, execute: async (args) => { const apiKeyError = checkApiKey(); if (apiKeyError) { return apiKeyError; } try { const imageUrl = `${TSDR_BASE_URL}/rawImage/${args.serialNumber}`; const response = await fetch(imageUrl, { method: "HEAD", headers: getHeaders() }); if (!response.ok) { return `No image found for trademark serial number: ${args.serialNumber}`; } return `Trademark image URL for serial number ${args.serialNumber}: ${imageUrl} You can view this image by opening the URL in a web browser.`; } catch (error) { return `Error retrieving trademark image: ${error instanceof Error ? error.message : String(error)}`; } } }); server.addTool({ name: "trademark_documents", description: "Get the document bundle URL for a trademark by serial number", parameters: import_zod.z.object({ serialNumber: import_zod.z.string().min(8).max(8).describe("8-digit trademark serial number") }), annotations: { title: "Trademark Documents Bundle", readOnlyHint: true, openWorldHint: true }, execute: async (args) => { const apiKeyError = checkApiKey(); if (apiKeyError) { return apiKeyError; } try { const documentsUrl = `${TSDR_BASE_URL}/casedocs/bundle.pdf?sn=${args.serialNumber}`; return `Document bundle URL for trademark serial number ${args.serialNumber}: ${documentsUrl} This URL provides a PDF containing all documents related to this trademark application. Note: Document downloads are rate-limited to 4 requests per minute per API key.`; } catch (error) { return `Error generating document bundle URL: ${error instanceof Error ? error.message : String(error)}`; } } }); server.addTool({ name: "trademark_search_by_registration", description: "Search for trademark information using a registration number", parameters: import_zod.z.object({ registrationNumber: import_zod.z.string().min(7).max(8).describe("7-8 digit trademark registration number"), format: import_zod.z.enum(["json", "xml"]).default("json").describe("Response format") }), annotations: { title: "Trademark Search by Registration Number", readOnlyHint: true, openWorldHint: true }, execute: async (args) => { const apiKeyError = checkApiKey(); if (apiKeyError) { return apiKeyError; } try { const fileExtension = args.format === "json" ? "json" : "xml"; const url = `${TSDR_BASE_URL}/casestatus/rn${args.registrationNumber}/info.${fileExtension}`; const response = await fetch(url, { headers: getHeaders() }); if (!response.ok) { const errorText = await response.text(); if (errorText.includes("need to register for an API key")) { throw new Error(`\u{1F511} USPTO API Authentication Issue The USPTO TSDR API is rejecting our API key. This could be due to: 1. **API Key Activation Delay**: New keys may need 24-48 hours to activate 2. **Endpoint Restrictions**: Individual record endpoints may be temporarily disabled 3. **Authentication Method**: The API might require a different authentication format **Your API Key**: ${API_KEY ? `${API_KEY.substring(0, 8)}...` : "Not set"} **Next Steps**: \u2022 Contact USPTO support: APIhelp@uspto.gov \u2022 Include your API key and this error message \u2022 Ask specifically about individual record endpoint access **Alternative**: Try bulk data download endpoints if available.`); } throw new Error(`USPTO API returned ${response.status}: ${response.statusText}. Error: ${errorText}`); } if (args.format === "json") { const jsonData = await response.json(); return JSON.stringify(jsonData, null, 2); } else { const xmlData = await response.text(); return xmlData; } } catch (error) { return `Error fetching trademark data by registration number: ${error instanceof Error ? error.message : String(error)}`; } } }); var src_default = server; // src/server.ts var port = process.env.PORT ? parseInt(process.env.PORT) : 8080; src_default.start({ transportType: "httpStream", httpStream: { port } }); console.log(`\u{1F680} Trademark MCP Server running on http://localhost:${port}`); console.log(`\u{1F4CB} Health check: http://localhost:${port}/health`); console.log(`\u{1F50D} MCP endpoint: http://localhost:${port}/mcp`);