{"_id":"@duynh0308/patronus-mcp","_rev":"2-e93d3018f63cbc167bbede07d4cc3044","name":"@duynh0308/patronus-mcp","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@duynh0308/patronus-mcp","version":"1.0.0","keywords":["mcp","patronus","rag","knowledge-gateway","sdk","typescript"],"author":{"name":"Patronus Team"},"license":"ISC","_id":"@duynh0308/patronus-mcp@1.0.0","maintainers":[{"name":"duynh0308","email":"nguyenhoangduy1997@gmail.com"}],"dist":{"shasum":"354a0392bd1b8188ab74db7f3b20d14e96fb655d","tarball":"https://registry.npmjs.org/@duynh0308/patronus-mcp/-/patronus-mcp-1.0.0.tgz","fileCount":22,"integrity":"sha512-BnOuIrbpfKT0cKA6KcoFJPgSsDsKADiCTnZVSeRGONxIC2CKgvceKrXc57+iW6gLH4XTx80VaC+KtjPNTkUzKg==","signatures":[{"sig":"MEYCIQCVNPY0VWQPU6OuzLDEGIGB/UIJzRsdCnK7cZFnCYcuDAIhAOudJ/iImteWpSCXxhhjI0oQc7TiZgqsYTpENjAQA07L","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":65896},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"}},"gitHead":"7cae5a0642239c11f7be15d5b03a2d8352eae39d","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts","test":"jest","build":"tsc","clean":"rimraf dist","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"pnpm build"},"_npmUser":{"name":"duynh0308","email":"nguyenhoangduy1997@gmail.com"},"_npmVersion":"10.9.8","description":"MCP Client SDK for Patronus Knowledge Gateway","directories":{},"sideEffects":false,"_nodeVersion":"22.22.3","dependencies":{"axios":"^1.6.0","eventsource":"^2.0.2"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.57.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","typescript":"^5.4.5","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/eventsource":"^1.1.15","axios-mock-adapter":"^1.22.0","@typescript-eslint/parser":"^7.0.0","@typescript-eslint/eslint-plugin":"^7.0.0"},"_npmOperationalInternal":{"tmp":"tmp/patronus-mcp_1.0.0_1781505151105_0.36499099005709223","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@duynh0308/patronus-mcp","version":"1.0.1","description":"MCP Client SDK for Patronus Knowledge Gateway","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"require":"./dist/index.js","import":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"build":"tsc","dev":"tsc --watch","prepublishOnly":"pnpm build","test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","lint":"eslint src --ext .ts","clean":"rimraf dist"},"keywords":["mcp","patronus","rag","knowledge-gateway","sdk","typescript"],"author":{"name":"Patronus Team"},"license":"ISC","dependencies":{"axios":"^1.6.0","eventsource":"^2.0.2"},"devDependencies":{"@types/node":"^20.0.0","@types/eventsource":"^1.1.15","typescript":"^5.4.5","jest":"^29.7.0","@types/jest":"^29.5.0","ts-jest":"^29.1.0","axios-mock-adapter":"^1.22.0","rimraf":"^5.0.0","@typescript-eslint/eslint-plugin":"^7.0.0","@typescript-eslint/parser":"^7.0.0","eslint":"^8.57.0"},"engines":{"node":">=18.0.0"},"sideEffects":false,"_id":"@duynh0308/patronus-mcp@1.0.1","gitHead":"7cae5a0642239c11f7be15d5b03a2d8352eae39d","_nodeVersion":"22.22.3","_npmVersion":"10.9.8","dist":{"integrity":"sha512-l7PnsxNeEOl2Frqn07pQBowF9WownCbHnyhm9KTViBIvDOSzBpUhdVCLVV7QtReKdHC1n58X5tEyrJwtVSBj6g==","shasum":"2de0c107df22fe55a19ac7a1ca44e26431552ac1","tarball":"https://registry.npmjs.org/@duynh0308/patronus-mcp/-/patronus-mcp-1.0.1.tgz","fileCount":22,"unpackedSize":65923,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCWDLtfPlm8GRoYt4qP7sQ2FLn7uSXtCjn+VRv3eiac8AIgcegcs8re/1WNixll/upoKVqg7x7jKSKS3oUWD4RG+ng="}]},"_npmUser":{"name":"duynh0308","email":"nguyenhoangduy1997@gmail.com"},"directories":{},"maintainers":[{"name":"duynh0308","email":"nguyenhoangduy1997@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/patronus-mcp_1.0.1_1781505235185_0.415091067522372"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-15T06:32:30.966Z","modified":"2026-06-15T06:33:55.416Z","1.0.0":"2026-06-15T06:32:31.246Z","1.0.1":"2026-06-15T06:33:55.313Z"},"author":{"name":"Patronus Team"},"license":"ISC","keywords":["mcp","patronus","rag","knowledge-gateway","sdk","typescript"],"description":"MCP Client SDK for Patronus Knowledge Gateway","maintainers":[{"name":"duynh0308","email":"nguyenhoangduy1997@gmail.com"}],"readme":"# @duynh0308/patronus-mcp\n\n[![npm version](https://img.shields.io/npm/v/@duynh0308/patronus-mcp.svg)](https://www.npmjs.com/package/@duynh0308/patronus-mcp)\n[![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)\n[![Node >=18](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](https://nodejs.org)\n\n**MCP Client SDK for Patronus Knowledge Gateway** – TypeScript-first library for AI agents, custom scripts, and integrations that need semantic search, RAG, and document management via Personal Access Tokens (PATs).\n\n---\n\n## Features\n\n- 🔍 **Semantic Search** – vector search across one or more projects\n- 🤖 **RAG** – retrieval-augmented generation with citations\n- 📡 **Streaming RAG** – real-time token-by-token answers\n- 📁 **Document Management** – upload, list, delete, wait-for-indexing\n- 🔁 **Auto-retry** – exponential back-off on transient errors\n- 🔒 **PAT Auth** – secure Personal Access Token authentication\n- 💪 **Full TypeScript** – complete type definitions, no `any` in public API\n\n---\n\n## Installation\n\n```bash\nnpm install @duynh0308/patronus-mcp\n# or\npnpm add @duynh0308/patronus-mcp\n# or\nyarn add @duynh0308/patronus-mcp\n```\n\n**Requirements:** Node.js ≥ 18 (uses native `fetch` for streaming).\n\n---\n\n## Quick Start\n\n```typescript\nimport { PatronusMcpClient } from '@duynh0308/patronus-mcp';\n\nconst client = new PatronusMcpClient({\n  serverUrl: 'http://localhost:3000',\n  pat: 'patronus_pat_xxxxx',\n});\n\n// List accessible projects\nconst projects = await client.listProjects();\nconsole.log(projects.map(p => p.name));\n\n// Semantic search\nconst results = await client.search({\n  query: 'how to deploy to production',\n  projectIds: projects.map(p => p.id),\n  topK: 10,\n});\n\n// RAG query\nconst { answer, citations } = await client.rag({\n  query: 'What is the refund policy?',\n  projectIds: [projects[0].id],\n});\nconsole.log(answer);\nconsole.log('Sources:', citations.map(c => c.filename));\n```\n\n---\n\n## API Reference\n\n### `new PatronusMcpClient(config)`\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `serverUrl` | `string` | — | Base URL of the Patronus server |\n| `pat` | `string` | — | Personal Access Token |\n| `timeout` | `number` | `60000` | Request timeout in ms |\n| `maxRetries` | `number` | `3` | Max retry attempts on transient errors |\n| `retryDelay` | `number` | `1000` | Base delay between retries (exponential) |\n\n---\n\n### `client.listProjects()`\n\nList all projects accessible with the PAT token.\n\n```typescript\nconst projects: Project[] = await client.listProjects();\n```\n\n---\n\n### `client.search(params)`\n\nSemantic search across one or more projects.\n\n```typescript\nconst response: SearchResponse = await client.search({\n  query: string,           // search query\n  projectIds: string[],   // project IDs to search\n  topK?: number,          // max results (default: 10)\n  scoreThreshold?: number // min similarity score 0–1 (default: 0)\n});\n```\n\n---\n\n### `client.rag(params)`\n\nRAG query – retrieves context and generates an AI-grounded answer.\n\n```typescript\nconst response: RagResponse = await client.rag({\n  query: string,           // question to answer\n  projectIds: string[],   // context projects\n  topK?: number,          // context chunks (default: 5)\n  temperature?: number,   // LLM temperature (default: 0.7)\n  model?: string,         // override LLM model\n});\n\nconsole.log(response.answer);\nconsole.log(response.citations);   // Citation[]\nconsole.log(response.modelUsed);\n```\n\n---\n\n### `client.ragStream(params, onChunk, onDone?)`\n\nStreaming RAG – receive answer tokens as they are generated.\n\n```typescript\nawait client.ragStream(\n  {\n    query: 'Explain the architecture in detail',\n    projectIds: ['proj_abc'],\n    topK: 5,\n    temperature: 0.7,\n  },\n  (chunk: StreamChunk) => {\n    process.stdout.write(chunk.content);\n  },\n  () => console.log('\\n[Done]'),\n);\n```\n\n---\n\n### `client.uploadDocument(params)`\n\nUpload a document (text, Buffer, or URL) to a project. Indexing happens asynchronously.\n\n```typescript\nconst { id } = await client.uploadDocument({\n  projectId: string,      // target project\n  filename: string,       // display filename\n  content: string | Buffer, // file content or URL\n  isUrl?: boolean,        // if true, content is a URL\n});\n```\n\n---\n\n### `client.listDocuments(projectId, limit?)`\n\nList documents in a project.\n\n```typescript\nconst docs: Document[] = await client.listDocuments('proj_abc', 50);\n```\n\n---\n\n### `client.deleteDocument(projectId, documentId)`\n\nDelete a document and all its embeddings.\n\n```typescript\nawait client.deleteDocument('proj_abc', 'doc_xyz');\n```\n\n---\n\n### `client.getDocument(projectId, documentId)`\n\nFind a single document by ID. Returns `null` if not found.\n\n```typescript\nconst doc: Document | null = await client.getDocument('proj_abc', 'doc_xyz');\n```\n\n---\n\n### `client.waitForIndexing(projectId, documentId, intervalMs?, timeoutMs?)`\n\nPoll until a document reaches `INDEXED` or `FAILED` status.\n\n```typescript\nconst { id } = await client.uploadDocument({ ... });\nconst doc = await client.waitForIndexing('proj_abc', id);\nif (doc.status === 'INDEXED') {\n  console.log('Ready to search!');\n}\n```\n\n---\n\n### `client.healthCheck()`\n\nCheck if the server is reachable with the provided credentials.\n\n```typescript\nconst ok: boolean = await client.healthCheck();\n```\n\n---\n\n## Error Handling\n\nAll errors extend `PatronusError`:\n\n```typescript\nimport {\n  PatronusError,\n  AuthenticationError,  // 401 – invalid/expired PAT\n  PermissionError,      // 403 – access denied\n  NotFoundError,        // 404 – resource not found\n  RateLimitError,       // 429 – too many requests\n  McpError,             // MCP JSON-RPC error\n  NetworkError,         // network/timeout error\n  MaxRetriesExceededError, // all retries failed\n} from '@duynh0308/patronus-mcp';\n\ntry {\n  await client.listProjects();\n} catch (error) {\n  if (error instanceof AuthenticationError) {\n    console.error('Invalid or expired PAT');\n  } else if (error instanceof PermissionError) {\n    console.error('No access to this resource');\n  } else if (error instanceof RateLimitError) {\n    console.error('Slow down! Rate limit hit.');\n  } else if (error instanceof PatronusError) {\n    console.error(`Error ${error.statusCode}: ${error.message}`);\n  }\n}\n```\n\n---\n\n## Complete Example\n\n```typescript\nimport { PatronusMcpClient, AuthenticationError } from '@duynh0308/patronus-mcp';\nimport * as fs from 'fs';\n\nasync function main() {\n  const client = new PatronusMcpClient({\n    serverUrl: process.env.PATRONUS_URL ?? 'http://localhost:3000',\n    pat: process.env.PATRONUS_PAT ?? '',\n    maxRetries: 3,\n  });\n\n  // Health check\n  if (!(await client.healthCheck())) {\n    throw new Error('Cannot reach Patronus server');\n  }\n\n  // Get projects\n  const projects = await client.listProjects();\n  const projectIds = projects.map(p => p.id);\n  console.log(`Loaded ${projects.length} projects`);\n\n  // Upload a document\n  const { id: docId } = await client.uploadDocument({\n    projectId: projectIds[0],\n    filename: 'guide.md',\n    content: fs.readFileSync('guide.md'),\n  });\n\n  // Wait for indexing\n  const doc = await client.waitForIndexing(projectIds[0], docId);\n  console.log(`Document status: ${doc.status}`);\n\n  // Search\n  const { results, total } = await client.search({\n    query: 'getting started guide',\n    projectIds,\n    topK: 5,\n  });\n  console.log(`Found ${total} results`);\n\n  // RAG with streaming\n  console.log('\\nStreaming answer:\\n');\n  await client.ragStream(\n    { query: 'How do I get started?', projectIds, topK: 3 },\n    (chunk) => process.stdout.write(chunk.content),\n    () => console.log('\\n[Done]'),\n  );\n}\n\nmain().catch(console.error);\n```\n\n---\n\n## Examples\n\nSee the [`examples/`](../../examples/typescript/) directory:\n\n- [`basic-usage.ts`](../../examples/typescript/basic-usage.ts) – search, RAG, document management\n- [`rag-streaming.ts`](../../examples/typescript/rag-streaming.ts) – real-time streaming RAG\n- [`custom-agent.ts`](../../examples/typescript/custom-agent.ts) – simple Q&A agent\n\n---\n\n## License\n\nISC © Patronus Team\n","readmeFilename":"README.md"}