@duckmind/deepquark-darwin-arm64 0.1.0
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/.deepquark/skills/bundled/data-storytelling/SKILL.md +453 -0
- package/.deepquark/skills/bundled/docx/LICENSE.txt +30 -0
- package/.deepquark/skills/bundled/docx/SKILL.md +481 -0
- package/.deepquark/skills/bundled/docx/scripts/__init__.py +1 -0
- package/.deepquark/skills/bundled/docx/scripts/accept_changes.py +135 -0
- package/.deepquark/skills/bundled/docx/scripts/comment.py +318 -0
- package/.deepquark/skills/bundled/docx/scripts/office/helpers/__init__.py +0 -0
- package/.deepquark/skills/bundled/docx/scripts/office/helpers/merge_runs.py +199 -0
- package/.deepquark/skills/bundled/docx/scripts/office/helpers/simplify_redlines.py +197 -0
- package/.deepquark/skills/bundled/docx/scripts/office/pack.py +159 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/mce/mc.xsd +75 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/.deepquark/skills/bundled/docx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/.deepquark/skills/bundled/docx/scripts/office/soffice.py +183 -0
- package/.deepquark/skills/bundled/docx/scripts/office/unpack.py +132 -0
- package/.deepquark/skills/bundled/docx/scripts/office/validate.py +111 -0
- package/.deepquark/skills/bundled/docx/scripts/office/validators/__init__.py +15 -0
- package/.deepquark/skills/bundled/docx/scripts/office/validators/base.py +847 -0
- package/.deepquark/skills/bundled/docx/scripts/office/validators/docx.py +446 -0
- package/.deepquark/skills/bundled/docx/scripts/office/validators/pptx.py +275 -0
- package/.deepquark/skills/bundled/docx/scripts/office/validators/redlining.py +247 -0
- package/.deepquark/skills/bundled/docx/scripts/templates/comments.xml +3 -0
- package/.deepquark/skills/bundled/docx/scripts/templates/commentsExtended.xml +3 -0
- package/.deepquark/skills/bundled/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/.deepquark/skills/bundled/docx/scripts/templates/commentsIds.xml +3 -0
- package/.deepquark/skills/bundled/docx/scripts/templates/people.xml +3 -0
- package/.deepquark/skills/bundled/drawio-architect/SKILL.md +300 -0
- package/.deepquark/skills/bundled/drawio-architect/references/architecture-patterns.md +236 -0
- package/.deepquark/skills/bundled/drawio-architect/references/branding.md +180 -0
- package/.deepquark/skills/bundled/drawio-architect/references/cloud-icons.md +493 -0
- package/.deepquark/skills/bundled/drawio-architect/references/style-guide.md +268 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/ARCHITECTURE_REVIEW.md +495 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/AUTONOMY_VERIFICATION.md +420 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/COMPETITIVE_ANALYSIS.md +179 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/CONTEXT_OPTIMIZATION.md +293 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/QUICK_START.md +167 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/README.md +259 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/SKILL.md +754 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/WORD_PRECISION_AUDIT.md +476 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/reference/methodology.md +384 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/requirements.txt +10 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/scripts/citation_manager.py +177 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/scripts/md_to_html.py +330 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/scripts/research_engine.py +578 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/scripts/source_evaluator.py +292 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/scripts/validate_report.py +354 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/scripts/verify_citations.py +430 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/scripts/verify_html.py +220 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/templates/mckinsey_report_template.html +443 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/templates/report_template.md +414 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/tests/fixtures/invalid_report.md +27 -0
- package/.deepquark/skills/bundled/duckmind-deep-research/tests/fixtures/valid_report.md +114 -0
- package/.deepquark/skills/bundled/duckmind-multimodal/SKILL.md +171 -0
- package/.deepquark/skills/bundled/duckmind-multimodal/references/image-generation.md +131 -0
- package/.deepquark/skills/bundled/duckmind-multimodal/references/pdf-processing.md +120 -0
- package/.deepquark/skills/bundled/duckmind-transcribe/SKILL.md +70 -0
- package/.deepquark/skills/bundled/duckmind-transcribe/scripts/transcribe.sh +134 -0
- package/.deepquark/skills/bundled/excel-analysis/SKILL.md +247 -0
- package/.deepquark/skills/bundled/knowledge-graph/SKILL.md +385 -0
- package/.deepquark/skills/bundled/knowledge-graph/STANDARDS.md +461 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/cli.ts +588 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/config.ts +630 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/connection-profile.ts +629 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/container.ts +756 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/mcp-client.ts +1310 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/output-formatter.ts +997 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/token-metrics.ts +335 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/transformation-log.ts +137 -0
- package/.deepquark/skills/bundled/knowledge-graph/lib/wrapper-config.ts +113 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/.env.example +129 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/compare-embeddings.ts +175 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/config-falkordb.yaml +108 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/config-neo4j.yaml +111 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/diagnose.ts +483 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-falkordb-dev.yml +146 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-falkordb.yml +151 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-neo4j-dev-local.yml +161 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-neo4j-dev.yml +161 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-neo4j.yml +169 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-production.yml +128 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose-test.yml +10 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/docker-compose.yml +84 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/entrypoint.sh +40 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/install.ts +2054 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/podman-compose-falkordb.yml +78 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/podman-compose-neo4j.yml +88 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/podman-compose.yml +83 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-all-llms-mcp.ts +387 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-embedding-models.ts +201 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-embedding-providers.ts +641 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-graphiti-model.ts +217 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-grok-correct.ts +141 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-grok-llms-mcp.ts +386 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-grok-models.ts +173 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-llama-extraction.ts +188 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-mcp-final.ts +240 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-mcp-live.ts +187 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-mcp-session.ts +127 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-model-combinations.ts +316 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-ollama-models.ts +228 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-openrouter-models.ts +460 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-real-life-mcp.ts +311 -0
- package/.deepquark/skills/bundled/knowledge-graph/server/test-search-debug.ts +199 -0
- package/.deepquark/skills/bundled/knowledge-graph/tools/Install.md +104 -0
- package/.deepquark/skills/bundled/knowledge-graph/tools/README.md +120 -0
- package/.deepquark/skills/bundled/knowledge-graph/tools/knowledge-cli.ts +996 -0
- package/.deepquark/skills/bundled/knowledge-graph/tools/server-cli.ts +531 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/BulkImport.md +514 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/CaptureEpisode.md +242 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/ClearGraph.md +392 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/GetRecent.md +352 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/GetStatus.md +373 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/HealthReport.md +212 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/InvestigateEntity.md +142 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/OntologyManagement.md +201 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/RunMaintenance.md +302 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/SearchByDate.md +255 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/SearchFacts.md +382 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/SearchKnowledge.md +374 -0
- package/.deepquark/skills/bundled/knowledge-graph/workflows/StixImport.md +212 -0
- package/.deepquark/skills/bundled/pdf/LICENSE.txt +30 -0
- package/.deepquark/skills/bundled/pdf/SKILL.md +314 -0
- package/.deepquark/skills/bundled/pdf/forms.md +294 -0
- package/.deepquark/skills/bundled/pdf/reference.md +612 -0
- package/.deepquark/skills/bundled/pdf/scripts/check_bounding_boxes.py +65 -0
- package/.deepquark/skills/bundled/pdf/scripts/check_fillable_fields.py +11 -0
- package/.deepquark/skills/bundled/pdf/scripts/convert_pdf_to_images.py +33 -0
- package/.deepquark/skills/bundled/pdf/scripts/create_validation_image.py +37 -0
- package/.deepquark/skills/bundled/pdf/scripts/extract_form_field_info.py +122 -0
- package/.deepquark/skills/bundled/pdf/scripts/extract_form_structure.py +115 -0
- package/.deepquark/skills/bundled/pdf/scripts/fill_fillable_fields.py +98 -0
- package/.deepquark/skills/bundled/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
- package/.deepquark/skills/bundled/perplexity-search/SKILL.md +447 -0
- package/.deepquark/skills/bundled/perplexity-search/assets/.env.example +16 -0
- package/.deepquark/skills/bundled/perplexity-search/references/model_comparison.md +386 -0
- package/.deepquark/skills/bundled/perplexity-search/references/openrouter_setup.md +454 -0
- package/.deepquark/skills/bundled/perplexity-search/references/search_strategies.md +258 -0
- package/.deepquark/skills/bundled/perplexity-search/scripts/perplexity_search.py +277 -0
- package/.deepquark/skills/bundled/perplexity-search/scripts/setup_env.py +171 -0
- package/.deepquark/skills/bundled/pptx/LICENSE.txt +30 -0
- package/.deepquark/skills/bundled/pptx/SKILL.md +232 -0
- package/.deepquark/skills/bundled/pptx/editing.md +205 -0
- package/.deepquark/skills/bundled/pptx/pptxgenjs.md +420 -0
- package/.deepquark/skills/bundled/pptx/scripts/__init__.py +0 -0
- package/.deepquark/skills/bundled/pptx/scripts/add_slide.py +195 -0
- package/.deepquark/skills/bundled/pptx/scripts/clean.py +286 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/helpers/__init__.py +0 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/helpers/merge_runs.py +199 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/helpers/simplify_redlines.py +197 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/pack.py +159 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/mce/mc.xsd +75 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/soffice.py +183 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/unpack.py +132 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/validate.py +111 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/validators/__init__.py +15 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/validators/base.py +847 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/validators/docx.py +446 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/validators/pptx.py +275 -0
- package/.deepquark/skills/bundled/pptx/scripts/office/validators/redlining.py +247 -0
- package/.deepquark/skills/bundled/pptx/scripts/thumbnail.py +289 -0
- package/.deepquark/skills/bundled/text-to-pdf-automation/SKILL.md +91 -0
- package/.deepquark/skills/bundled/web-fetch/SKILL.md +56 -0
- package/.deepquark/skills/bundled/web-fetch/scripts/fetch.sh +54 -0
- package/.deepquark/skills/bundled/xlsx/LICENSE.txt +30 -0
- package/.deepquark/skills/bundled/xlsx/SKILL.md +292 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/helpers/__init__.py +0 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/helpers/merge_runs.py +199 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/helpers/simplify_redlines.py +197 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/pack.py +159 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/mce/mc.xsd +75 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/soffice.py +183 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/unpack.py +132 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/validate.py +111 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/validators/__init__.py +15 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/validators/base.py +847 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/validators/docx.py +446 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/validators/pptx.py +275 -0
- package/.deepquark/skills/bundled/xlsx/scripts/office/validators/redlining.py +247 -0
- package/.deepquark/skills/bundled/xlsx/scripts/recalc.py +184 -0
- package/.deepquark/skills/bundled/youtube-downloader/SKILL.md +99 -0
- package/.deepquark/skills/bundled/youtube-downloader/scripts/download_video.py +145 -0
- package/.deepquark/skills/bundled/youtube-transcribe-skill/SKILL.md +116 -0
- package/LICENSE +21 -0
- package/bin/deepquark +0 -0
- package/package.json +16 -0
|
@@ -0,0 +1,1310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Client Library
|
|
3
|
+
*
|
|
4
|
+
* HTTP client for communicating with the Graphiti MCP server.
|
|
5
|
+
* Handles JSON-RPC 2.0 requests for all MCP tools.
|
|
6
|
+
*
|
|
7
|
+
* NOTE: Lucene sanitization is now handled server-side by the Python patch
|
|
8
|
+
* (falkordb_lucene.py). The TypeScript client passes values directly to the server.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// Import profile loading function for connection profiles
|
|
12
|
+
import { loadProfileWithOverrides } from './connection-profile.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* MCP tool names (Graphiti MCP server)
|
|
16
|
+
*
|
|
17
|
+
* Note: The Graphiti MCP server tools:
|
|
18
|
+
* - add_memory: Add episodes to the knowledge graph
|
|
19
|
+
* - search_nodes: Search for entities/nodes
|
|
20
|
+
* - search_memory_facts: Search for relationships/facts
|
|
21
|
+
* - get_episodes: Retrieve recent episodes
|
|
22
|
+
* - delete_episode, delete_entity_edge: Deletion operations
|
|
23
|
+
* - clear_graph: Clear all data
|
|
24
|
+
* - get_status: Server health check
|
|
25
|
+
*
|
|
26
|
+
* TypeScript methods use Graphiti-native terminology (Episode, Node, Fact)
|
|
27
|
+
* while calling the actual MCP tool names.
|
|
28
|
+
*/
|
|
29
|
+
export const MCP_TOOLS = {
|
|
30
|
+
// Knowledge capture (adds an "episode" to memory)
|
|
31
|
+
ADD_EPISODE: 'add_memory',
|
|
32
|
+
// Entity search (searches "nodes")
|
|
33
|
+
SEARCH_NODES: 'search_nodes',
|
|
34
|
+
// Relationship search (searches "facts" in memory)
|
|
35
|
+
SEARCH_FACTS: 'search_memory_facts',
|
|
36
|
+
// Episode retrieval
|
|
37
|
+
GET_EPISODES: 'get_episodes',
|
|
38
|
+
// System operations
|
|
39
|
+
GET_STATUS: 'get_status',
|
|
40
|
+
CLEAR_GRAPH: 'clear_graph',
|
|
41
|
+
DELETE_EPISODE: 'delete_episode',
|
|
42
|
+
DELETE_ENTITY_EDGE: 'delete_entity_edge',
|
|
43
|
+
GET_ENTITY_EDGE: 'get_entity_edge',
|
|
44
|
+
// Feature 009: Memory decay scoring
|
|
45
|
+
GET_KNOWLEDGE_HEALTH: 'get_knowledge_health',
|
|
46
|
+
RUN_DECAY_MAINTENANCE: 'run_decay_maintenance',
|
|
47
|
+
CLASSIFY_MEMORY: 'classify_memory',
|
|
48
|
+
RECOVER_SOFT_DELETED: 'recover_soft_deleted',
|
|
49
|
+
// Feature 018: OSINT/CTI Ontology support
|
|
50
|
+
LIST_ONTOLOGY_TYPES: 'list_ontology_types',
|
|
51
|
+
VALIDATE_ONTOLOGY: 'validate_ontology',
|
|
52
|
+
RELOAD_ONTOLOGY: 'reload_ontology',
|
|
53
|
+
// Feature 018: STIX 2.1 import
|
|
54
|
+
IMPORT_STIX_BUNDLE: 'import_stix_bundle',
|
|
55
|
+
GET_IMPORT_STATUS: 'get_import_status',
|
|
56
|
+
RESUME_IMPORT: 'resume_import',
|
|
57
|
+
// Feature 020: Investigative search
|
|
58
|
+
INVESTIGATE_ENTITY: 'investigate_entity',
|
|
59
|
+
} as const;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* MCP tool parameters
|
|
63
|
+
*/
|
|
64
|
+
export interface AddEpisodeParams {
|
|
65
|
+
name: string;
|
|
66
|
+
episode_body: string;
|
|
67
|
+
source?: string;
|
|
68
|
+
reference_timestamp?: string;
|
|
69
|
+
source_description?: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface SearchNodesParams {
|
|
73
|
+
query: string;
|
|
74
|
+
/** Maximum number of nodes to return (maps to max_nodes on server) */
|
|
75
|
+
limit?: number;
|
|
76
|
+
group_ids?: string[];
|
|
77
|
+
/** Filter by entity type names (e.g., ["Preference", "Procedure"]) */
|
|
78
|
+
entity_types?: string[];
|
|
79
|
+
/** Return nodes created after this date (ISO 8601 or relative: "today", "7d", "1 week ago") */
|
|
80
|
+
since?: string;
|
|
81
|
+
/** Return nodes created before this date (ISO 8601 or relative) */
|
|
82
|
+
until?: string;
|
|
83
|
+
/** Apply weighted scoring (60% semantic + 25% recency + 15% importance) */
|
|
84
|
+
include_weighted_scores?: boolean;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface SearchFactsParams {
|
|
88
|
+
query: string;
|
|
89
|
+
limit?: number;
|
|
90
|
+
group_ids?: string[];
|
|
91
|
+
max_facts?: number;
|
|
92
|
+
/** Filter by entity type (e.g., "Preference", "Procedure", "Learning", "Research", "Decision") */
|
|
93
|
+
entity?: string;
|
|
94
|
+
/** Center the search on a specific entity UUID */
|
|
95
|
+
center_node_uuid?: string;
|
|
96
|
+
/** Return facts created after this date (ISO 8601 or relative: "today", "7d", "1 week ago") */
|
|
97
|
+
since?: string;
|
|
98
|
+
/** Return facts created before this date (ISO 8601 or relative) */
|
|
99
|
+
until?: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface GetEpisodesParams {
|
|
103
|
+
/** Maximum number of episodes to return (maps to max_episodes on server) */
|
|
104
|
+
limit?: number;
|
|
105
|
+
/** Single group ID (will be converted to group_ids array) */
|
|
106
|
+
group_id?: string;
|
|
107
|
+
/** Multiple group IDs */
|
|
108
|
+
group_ids?: string[];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export type GetStatusParams = Record<string, never>;
|
|
112
|
+
|
|
113
|
+
export type ClearGraphParams = Record<string, never>;
|
|
114
|
+
|
|
115
|
+
export interface DeleteEpisodeParams {
|
|
116
|
+
uuid: string;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface DeleteEntityEdgeParams {
|
|
120
|
+
uuid: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface GetEntityEdgeParams {
|
|
124
|
+
uuid: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Feature 009: Memory decay scoring parameters
|
|
128
|
+
export interface GetKnowledgeHealthParams {
|
|
129
|
+
group_id?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface RunDecayMaintenanceParams {
|
|
133
|
+
dry_run?: boolean;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface ClassifyMemoryParams {
|
|
137
|
+
content: string;
|
|
138
|
+
source_description?: string;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface RecoverSoftDeletedParams {
|
|
142
|
+
uuid: string;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Feature 020: Investigative search parameters
|
|
147
|
+
*/
|
|
148
|
+
export interface InvestigateEntityParams {
|
|
149
|
+
entity_name: string;
|
|
150
|
+
max_depth?: number;
|
|
151
|
+
relationship_types?: string[];
|
|
152
|
+
group_ids?: string[];
|
|
153
|
+
include_attributes?: boolean;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* JSON-RPC 2.0 request
|
|
158
|
+
*/
|
|
159
|
+
export interface JSONRPCRequest {
|
|
160
|
+
jsonrpc: '2.0';
|
|
161
|
+
id: number | string;
|
|
162
|
+
method: string;
|
|
163
|
+
params: {
|
|
164
|
+
name: string;
|
|
165
|
+
arguments: Record<string, unknown>;
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* JSON-RPC 2.0 response
|
|
171
|
+
*/
|
|
172
|
+
export interface JSONRPCResponse {
|
|
173
|
+
jsonrpc: '2.0';
|
|
174
|
+
id: number | string;
|
|
175
|
+
result?: unknown;
|
|
176
|
+
error?: {
|
|
177
|
+
code: number;
|
|
178
|
+
message: string;
|
|
179
|
+
data?: unknown;
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* MCP client response
|
|
185
|
+
*/
|
|
186
|
+
export interface MCPClientResponse<T = unknown> {
|
|
187
|
+
success: boolean;
|
|
188
|
+
data?: T;
|
|
189
|
+
error?: string;
|
|
190
|
+
code?: number;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* TLS/SSL configuration for HTTPS connections
|
|
195
|
+
*/
|
|
196
|
+
export interface TLSConfig {
|
|
197
|
+
/** Enable certificate verification (default: true) */
|
|
198
|
+
verify?: boolean;
|
|
199
|
+
/** Path to CA certificate file (PEM format) */
|
|
200
|
+
ca?: string;
|
|
201
|
+
/** Path to client certificate file (PEM format) */
|
|
202
|
+
cert?: string;
|
|
203
|
+
/** Path to client private key file (PEM format) */
|
|
204
|
+
key?: string;
|
|
205
|
+
/** Minimum TLS protocol version (default: TLSv1.2) */
|
|
206
|
+
minVersion?: 'TLSv1.2' | 'TLSv1.3';
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* MCP Client configuration
|
|
211
|
+
*/
|
|
212
|
+
export interface MCPClientConfig {
|
|
213
|
+
/** Base URL for MCP server (deprecated: use protocol+host+port+basePath) */
|
|
214
|
+
baseURL?: string;
|
|
215
|
+
/** Protocol: http or https (default: http) */
|
|
216
|
+
protocol?: 'http' | 'https';
|
|
217
|
+
/** Hostname or IP address (default: localhost) */
|
|
218
|
+
host?: string;
|
|
219
|
+
/** TCP port (default: 8001) */
|
|
220
|
+
port?: number;
|
|
221
|
+
/** URL path prefix (default: /mcp) */
|
|
222
|
+
basePath?: string;
|
|
223
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
224
|
+
timeout?: number;
|
|
225
|
+
/** Custom headers */
|
|
226
|
+
headers?: Record<string, string>;
|
|
227
|
+
/** TLS configuration (required if protocol=https) */
|
|
228
|
+
tls?: TLSConfig;
|
|
229
|
+
/** Connection profile name (loads from file) */
|
|
230
|
+
profile?: string;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Default timeout for requests
|
|
235
|
+
*/
|
|
236
|
+
const DEFAULT_TIMEOUT = 30000; // 30 seconds
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Simple LRU Cache for search results
|
|
240
|
+
*/
|
|
241
|
+
interface CacheEntry<T> {
|
|
242
|
+
data: T;
|
|
243
|
+
timestamp: number;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
class LRUCache<T> {
|
|
247
|
+
private cache: Map<string, CacheEntry<T>>;
|
|
248
|
+
private maxSize: number;
|
|
249
|
+
private ttlMs: number;
|
|
250
|
+
|
|
251
|
+
constructor(maxSize = 100, ttlMs: number = 5 * 60 * 1000) {
|
|
252
|
+
this.cache = new Map();
|
|
253
|
+
this.maxSize = maxSize;
|
|
254
|
+
this.ttlMs = ttlMs;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
get(key: string): T | undefined {
|
|
258
|
+
const entry = this.cache.get(key);
|
|
259
|
+
if (!entry) return undefined;
|
|
260
|
+
|
|
261
|
+
// Check TTL
|
|
262
|
+
if (Date.now() - entry.timestamp > this.ttlMs) {
|
|
263
|
+
this.cache.delete(key);
|
|
264
|
+
return undefined;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Move to end (most recently used)
|
|
268
|
+
this.cache.delete(key);
|
|
269
|
+
this.cache.set(key, entry);
|
|
270
|
+
return entry.data;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
set(key: string, data: T): void {
|
|
274
|
+
// Evict oldest if at capacity
|
|
275
|
+
if (this.cache.size >= this.maxSize) {
|
|
276
|
+
const oldestKey = this.cache.keys().next().value;
|
|
277
|
+
if (oldestKey) this.cache.delete(oldestKey);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
this.cache.set(key, { data, timestamp: Date.now() });
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
clear(): void {
|
|
284
|
+
this.cache.clear();
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
size(): number {
|
|
288
|
+
return this.cache.size;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Extended MCP Client configuration with caching options
|
|
294
|
+
*/
|
|
295
|
+
export interface MCPClientConfigExtended extends MCPClientConfig {
|
|
296
|
+
enableCache?: boolean;
|
|
297
|
+
cacheMaxSize?: number;
|
|
298
|
+
cacheTtlMs?: number;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Create HTTPS agent with custom TLS options for Bun/Node.js fetch
|
|
303
|
+
*
|
|
304
|
+
* T021 [P] [US2]: Create HTTPS agent factory with custom TLS options
|
|
305
|
+
* T022 [US2]: Implement TLS certificate verification logic
|
|
306
|
+
*/
|
|
307
|
+
function createHTTPSOptions(tls?: TLSConfig): RequestInit {
|
|
308
|
+
const options: RequestInit = {};
|
|
309
|
+
|
|
310
|
+
if (!tls) {
|
|
311
|
+
return options;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// For Bun, we use a different approach with custom agent
|
|
315
|
+
// Bun's fetch doesn't directly support https.Agent, but we can pass
|
|
316
|
+
// TLS configuration through the request context
|
|
317
|
+
|
|
318
|
+
// T022 [US2]: Implement TLS certificate verification logic
|
|
319
|
+
// Default is to verify certificates (secure by default)
|
|
320
|
+
const verify = tls.verify !== false;
|
|
321
|
+
|
|
322
|
+
// For development/testing: allow self-signed certificates
|
|
323
|
+
if (!verify) {
|
|
324
|
+
// Bun doesn't have a direct way to disable verification in fetch
|
|
325
|
+
// This is a known limitation - users should use valid certificates
|
|
326
|
+
// or configure their system to trust the self-signed certificate
|
|
327
|
+
if (process.env.DEBUG === '1') {
|
|
328
|
+
console.warn('TLS certificate verification is DISABLED. This is not secure for production.');
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// T024 [US2]: Add MADEINOZ_KNOWLEDGE_TLS_CA environment variable support
|
|
333
|
+
// T023 [US2]: Add MADEINOZ_KNOWLEDGE_TLS_VERIFY environment variable support
|
|
334
|
+
// Note: Bun's fetch API doesn't directly support custom CA certificates
|
|
335
|
+
// Users need to configure system-level certificate trust or use a proxy
|
|
336
|
+
if (tls.ca && process.env.DEBUG === '1') {
|
|
337
|
+
console.warn(`Custom CA certificate specified: ${tls.ca}`);
|
|
338
|
+
console.warn('Bun fetch requires system-level certificate configuration. Use NODE_OPTIONS=--use-openssl-ca or configure certificate trust at OS level.');
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Client certificate authentication (mTLS)
|
|
342
|
+
if (tls.cert && tls.key && process.env.DEBUG === '1') {
|
|
343
|
+
console.warn(`Client certificates specified: cert=${tls.cert}, key=${tls.key}`);
|
|
344
|
+
console.warn('Bun fetch does not directly support client certificates. Consider using Node.js for mTLS support.');
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return options;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* MCP Client class with session management and optional response caching
|
|
352
|
+
*/
|
|
353
|
+
export class MCPClient {
|
|
354
|
+
private baseURL: string;
|
|
355
|
+
private timeout: number;
|
|
356
|
+
private headers: Record<string, string>;
|
|
357
|
+
private requestId: number;
|
|
358
|
+
private cache: LRUCache<unknown> | null;
|
|
359
|
+
private sessionId: string | null = null;
|
|
360
|
+
private initializePromise: Promise<void> | null = null;
|
|
361
|
+
private tlsConfig: TLSConfig | undefined;
|
|
362
|
+
|
|
363
|
+
constructor(config: MCPClientConfigExtended = {}) {
|
|
364
|
+
// Construct baseURL from protocol+host+port+basePath if baseURL not provided
|
|
365
|
+
if (config.baseURL) {
|
|
366
|
+
// Backward compatibility: use explicit baseURL
|
|
367
|
+
this.baseURL = config.baseURL;
|
|
368
|
+
} else {
|
|
369
|
+
// Construct from individual components
|
|
370
|
+
const protocol = config.protocol || 'http';
|
|
371
|
+
const host = config.host || 'localhost';
|
|
372
|
+
const port = config.port || 8001;
|
|
373
|
+
const basePath = config.basePath || '/mcp';
|
|
374
|
+
this.baseURL = `${protocol}://${host}:${port}${basePath}`;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
this.timeout = config.timeout || DEFAULT_TIMEOUT;
|
|
378
|
+
this.headers = {
|
|
379
|
+
'Content-Type': 'application/json',
|
|
380
|
+
Accept: 'application/json, text/event-stream',
|
|
381
|
+
...config.headers,
|
|
382
|
+
};
|
|
383
|
+
this.requestId = 1;
|
|
384
|
+
|
|
385
|
+
// Store TLS configuration for HTTPS connections
|
|
386
|
+
this.tlsConfig = config.tls;
|
|
387
|
+
|
|
388
|
+
// TLS configuration is active - file paths are not logged for security
|
|
389
|
+
// To debug TLS issues, temporarily enable: DEBUG=1 bun run ...
|
|
390
|
+
if (this.baseURL.startsWith('https://')) {
|
|
391
|
+
const verify = this.tlsConfig?.verify !== false;
|
|
392
|
+
if (process.env.DEBUG === '1' && !verify) {
|
|
393
|
+
console.warn('[MCPClient] TLS verification disabled - not secure for production');
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Initialize cache if enabled (default: enabled for search operations)
|
|
398
|
+
if (config.enableCache !== false) {
|
|
399
|
+
this.cache = new LRUCache<unknown>(
|
|
400
|
+
config.cacheMaxSize || 100,
|
|
401
|
+
config.cacheTtlMs || 5 * 60 * 1000 // 5 minutes default
|
|
402
|
+
);
|
|
403
|
+
} else {
|
|
404
|
+
this.cache = null;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Initialize MCP session and get session ID
|
|
410
|
+
*/
|
|
411
|
+
private async initializeSession(): Promise<void> {
|
|
412
|
+
if (this.sessionId) return;
|
|
413
|
+
if (this.initializePromise) return this.initializePromise;
|
|
414
|
+
|
|
415
|
+
this.initializePromise = (async () => {
|
|
416
|
+
const request = {
|
|
417
|
+
jsonrpc: '2.0',
|
|
418
|
+
id: this.requestId++,
|
|
419
|
+
method: 'initialize',
|
|
420
|
+
params: {
|
|
421
|
+
protocolVersion: '2024-11-05',
|
|
422
|
+
capabilities: {},
|
|
423
|
+
clientInfo: { name: 'mcp-wrapper', version: '1.0.0' },
|
|
424
|
+
},
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
// T021 [P] [US2]: Apply TLS configuration for HTTPS requests
|
|
428
|
+
const tlsOptions = createHTTPSOptions(this.tlsConfig);
|
|
429
|
+
|
|
430
|
+
const response = await fetch(this.baseURL, {
|
|
431
|
+
method: 'POST',
|
|
432
|
+
headers: this.headers,
|
|
433
|
+
body: JSON.stringify(request),
|
|
434
|
+
...tlsOptions,
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
if (!response.ok) {
|
|
438
|
+
throw new Error(`Failed to initialize session: HTTP ${response.status}`);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Get session ID from header
|
|
442
|
+
const sessionId = response.headers.get('Mcp-Session-Id');
|
|
443
|
+
if (!sessionId) {
|
|
444
|
+
throw new Error('Server did not return session ID');
|
|
445
|
+
}
|
|
446
|
+
this.sessionId = sessionId;
|
|
447
|
+
|
|
448
|
+
// Consume the SSE response body
|
|
449
|
+
await response.text();
|
|
450
|
+
|
|
451
|
+
// Send initialized notification (required by FastMCP HTTP transport)
|
|
452
|
+
const notifyRequest = {
|
|
453
|
+
jsonrpc: '2.0',
|
|
454
|
+
method: 'notifications/initialized',
|
|
455
|
+
};
|
|
456
|
+
await fetch(this.baseURL, {
|
|
457
|
+
method: 'POST',
|
|
458
|
+
headers: {
|
|
459
|
+
...this.headers,
|
|
460
|
+
'Mcp-Session-Id': this.sessionId,
|
|
461
|
+
},
|
|
462
|
+
body: JSON.stringify(notifyRequest),
|
|
463
|
+
});
|
|
464
|
+
})();
|
|
465
|
+
|
|
466
|
+
await this.initializePromise;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Parse SSE response to extract JSON-RPC result
|
|
471
|
+
*/
|
|
472
|
+
private parseSSEResponse(text: string): unknown {
|
|
473
|
+
// SSE format: "event: message\ndata: {...}\n\n"
|
|
474
|
+
const lines = text.split('\n');
|
|
475
|
+
for (const line of lines) {
|
|
476
|
+
if (line.startsWith('data: ')) {
|
|
477
|
+
const jsonStr = line.substring(6);
|
|
478
|
+
try {
|
|
479
|
+
const parsed = JSON.parse(jsonStr);
|
|
480
|
+
// Extract result from the MCP response format
|
|
481
|
+
if (parsed.result) {
|
|
482
|
+
// Handle structured Pydantic responses from FastMCP (NodeSearchResponse, etc.)
|
|
483
|
+
// These have direct fields (nodes, facts, episodes, status) not wrapped in content array
|
|
484
|
+
if (parsed.result.nodes && Array.isArray(parsed.result.nodes)) {
|
|
485
|
+
// NodeSearchResponse - return as-is with nodes array
|
|
486
|
+
return parsed.result;
|
|
487
|
+
}
|
|
488
|
+
if (parsed.result.facts && Array.isArray(parsed.result.facts)) {
|
|
489
|
+
// FactSearchResponse - return as-is with facts array
|
|
490
|
+
return parsed.result;
|
|
491
|
+
}
|
|
492
|
+
if (parsed.result.episodes && Array.isArray(parsed.result.episodes)) {
|
|
493
|
+
// EpisodeSearchResponse - return as-is with episodes array
|
|
494
|
+
return parsed.result;
|
|
495
|
+
}
|
|
496
|
+
if (parsed.result.status !== undefined) {
|
|
497
|
+
// StatusResponse - return as-is
|
|
498
|
+
return parsed.result;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Handle tool call response format (content array)
|
|
502
|
+
if (parsed.result.content && Array.isArray(parsed.result.content)) {
|
|
503
|
+
// Check for structuredContent first (preferred)
|
|
504
|
+
if (parsed.result.structuredContent) {
|
|
505
|
+
const sc = parsed.result.structuredContent;
|
|
506
|
+
// Unwrap Graphiti's result wrapper if present
|
|
507
|
+
if (sc.result && typeof sc.result === 'object') {
|
|
508
|
+
return sc.result;
|
|
509
|
+
}
|
|
510
|
+
return sc;
|
|
511
|
+
}
|
|
512
|
+
// Fall back to text content
|
|
513
|
+
const textContent = parsed.result.content.find(
|
|
514
|
+
(c: { type: string }) => c.type === 'text'
|
|
515
|
+
);
|
|
516
|
+
if (textContent?.text) {
|
|
517
|
+
try {
|
|
518
|
+
const textParsed = JSON.parse(textContent.text);
|
|
519
|
+
// Unwrap Graphiti's result wrapper if present
|
|
520
|
+
if (textParsed.result && typeof textParsed.result === 'object') {
|
|
521
|
+
return textParsed.result;
|
|
522
|
+
}
|
|
523
|
+
return textParsed;
|
|
524
|
+
} catch {
|
|
525
|
+
return textContent.text;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return parsed.result;
|
|
530
|
+
}
|
|
531
|
+
if (parsed.error) {
|
|
532
|
+
throw new Error(parsed.error.message || 'Unknown error');
|
|
533
|
+
}
|
|
534
|
+
return parsed;
|
|
535
|
+
} catch (e) {
|
|
536
|
+
if (e instanceof SyntaxError) continue;
|
|
537
|
+
throw e;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
throw new Error('No valid SSE data found in response');
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Generate cache key for a tool call
|
|
546
|
+
*/
|
|
547
|
+
private getCacheKey(toolName: string, args: Record<string, unknown>): string {
|
|
548
|
+
return `${toolName}:${JSON.stringify(args)}`;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Clear the response cache
|
|
553
|
+
*/
|
|
554
|
+
clearCache(): void {
|
|
555
|
+
this.cache?.clear();
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Get cache statistics
|
|
560
|
+
*/
|
|
561
|
+
getCacheStats(): { enabled: boolean; size: number } {
|
|
562
|
+
return {
|
|
563
|
+
enabled: this.cache !== null,
|
|
564
|
+
size: this.cache?.size() || 0,
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Call an MCP tool
|
|
570
|
+
*/
|
|
571
|
+
async callTool<T = unknown>(
|
|
572
|
+
toolName: string,
|
|
573
|
+
arguments_: Record<string, unknown>
|
|
574
|
+
): Promise<MCPClientResponse<T>> {
|
|
575
|
+
try {
|
|
576
|
+
// Ensure session is initialized
|
|
577
|
+
await this.initializeSession();
|
|
578
|
+
|
|
579
|
+
const request: JSONRPCRequest = {
|
|
580
|
+
jsonrpc: '2.0',
|
|
581
|
+
id: this.requestId++,
|
|
582
|
+
method: 'tools/call',
|
|
583
|
+
params: {
|
|
584
|
+
name: toolName,
|
|
585
|
+
arguments: arguments_,
|
|
586
|
+
},
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
const controller = new AbortController();
|
|
590
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
591
|
+
|
|
592
|
+
// T021 [P] [US2]: Create HTTPS agent factory with custom TLS options
|
|
593
|
+
// Apply TLS configuration for HTTPS requests
|
|
594
|
+
const tlsOptions = createHTTPSOptions(this.tlsConfig);
|
|
595
|
+
|
|
596
|
+
const response = await fetch(this.baseURL, {
|
|
597
|
+
method: 'POST',
|
|
598
|
+
headers: {
|
|
599
|
+
...this.headers,
|
|
600
|
+
'Mcp-Session-Id': this.sessionId!,
|
|
601
|
+
},
|
|
602
|
+
body: JSON.stringify(request),
|
|
603
|
+
signal: controller.signal,
|
|
604
|
+
...tlsOptions,
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
clearTimeout(timeoutId);
|
|
608
|
+
|
|
609
|
+
if (!response.ok) {
|
|
610
|
+
return {
|
|
611
|
+
success: false,
|
|
612
|
+
error: `HTTP ${response.status}: ${response.statusText}`,
|
|
613
|
+
code: response.status,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Parse SSE response
|
|
618
|
+
const text = await response.text();
|
|
619
|
+
const data = this.parseSSEResponse(text);
|
|
620
|
+
|
|
621
|
+
return {
|
|
622
|
+
success: true,
|
|
623
|
+
data: data as T,
|
|
624
|
+
};
|
|
625
|
+
} catch (error: unknown) {
|
|
626
|
+
if (error instanceof Error) {
|
|
627
|
+
if (error.name === 'AbortError') {
|
|
628
|
+
return {
|
|
629
|
+
success: false,
|
|
630
|
+
error: `Request timeout after ${this.timeout}ms`,
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// T026 [US2]: Add TLS certificate error handling with clear messages
|
|
635
|
+
const errorMsg = error.message.toLowerCase();
|
|
636
|
+
if (
|
|
637
|
+
errorMsg.includes('certificate') ||
|
|
638
|
+
errorMsg.includes('tls') ||
|
|
639
|
+
errorMsg.includes('ssl') ||
|
|
640
|
+
errorMsg.includes('handshake') ||
|
|
641
|
+
errorMsg.includes('certificate verify failed')
|
|
642
|
+
) {
|
|
643
|
+
const suggestions: string[] = [];
|
|
644
|
+
if (this.tlsConfig?.ca) {
|
|
645
|
+
suggestions.push(`Verify CA certificate path exists: ${this.tlsConfig.ca}`);
|
|
646
|
+
}
|
|
647
|
+
if (this.tlsConfig?.verify === false) {
|
|
648
|
+
suggestions.push('TLS verification is disabled but certificate error still occurred');
|
|
649
|
+
} else {
|
|
650
|
+
suggestions.push('Try setting MADEINOZ_KNOWLEDGE_TLS_VERIFY=false for self-signed certificates (not recommended for production)');
|
|
651
|
+
suggestions.push('Ensure the server certificate is valid and trusted');
|
|
652
|
+
}
|
|
653
|
+
return {
|
|
654
|
+
success: false,
|
|
655
|
+
error: `TLS Certificate Error: ${error.message}${suggestions.length > 0 ? '\nSuggestions:\n - ' + suggestions.join('\n - ') : ''}`,
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Host unreachable errors
|
|
660
|
+
if (
|
|
661
|
+
errorMsg.includes('econnrefused') ||
|
|
662
|
+
errorMsg.includes('connection refused') ||
|
|
663
|
+
errorMsg.includes('econnreset')
|
|
664
|
+
) {
|
|
665
|
+
return {
|
|
666
|
+
success: false,
|
|
667
|
+
error: `Connection Error: Unable to reach server at ${this.baseURL}\n - Verify the server is running\n - Check firewall settings\n - Verify host and port are correct`,
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
return {
|
|
672
|
+
success: false,
|
|
673
|
+
error: error.message,
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
return {
|
|
677
|
+
success: false,
|
|
678
|
+
error: 'Unknown error occurred',
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Add an episode to the knowledge graph
|
|
685
|
+
*/
|
|
686
|
+
async addEpisode(params: AddEpisodeParams): Promise<MCPClientResponse<{ uuid: string }>> {
|
|
687
|
+
return await this.callTool<{ uuid: string }>(MCP_TOOLS.ADD_EPISODE, params as unknown as Record<string, unknown>);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Search for nodes (entities) in the knowledge graph
|
|
692
|
+
* Results are cached for repeated queries
|
|
693
|
+
*/
|
|
694
|
+
async searchNodes(params: SearchNodesParams): Promise<MCPClientResponse<unknown[]>> {
|
|
695
|
+
// Build server params with correct field names
|
|
696
|
+
// Sanitization is handled server-side by falkordb_lucene.py patch
|
|
697
|
+
const serverParams: Record<string, unknown> = {
|
|
698
|
+
query: params.query,
|
|
699
|
+
};
|
|
700
|
+
if (params.limit !== undefined) {
|
|
701
|
+
serverParams.max_nodes = params.limit;
|
|
702
|
+
}
|
|
703
|
+
if (params.group_ids) {
|
|
704
|
+
serverParams.group_ids = params.group_ids;
|
|
705
|
+
}
|
|
706
|
+
if (params.entity_types) {
|
|
707
|
+
serverParams.entity_types = params.entity_types;
|
|
708
|
+
}
|
|
709
|
+
// Temporal filters (Madeinoz Patch)
|
|
710
|
+
if (params.since) {
|
|
711
|
+
serverParams.created_after = params.since;
|
|
712
|
+
}
|
|
713
|
+
if (params.until) {
|
|
714
|
+
serverParams.created_before = params.until;
|
|
715
|
+
}
|
|
716
|
+
// Weighted scoring (Feature 009)
|
|
717
|
+
if (params.include_weighted_scores !== undefined) {
|
|
718
|
+
serverParams.include_weighted_scores = params.include_weighted_scores;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// Check cache first
|
|
722
|
+
if (this.cache) {
|
|
723
|
+
const cacheKey = this.getCacheKey(MCP_TOOLS.SEARCH_NODES, serverParams);
|
|
724
|
+
const cached = this.cache.get(cacheKey);
|
|
725
|
+
if (cached) {
|
|
726
|
+
return { success: true, data: cached as unknown[] };
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Fetch and cache
|
|
730
|
+
const result = await this.callTool<unknown[]>(MCP_TOOLS.SEARCH_NODES, serverParams);
|
|
731
|
+
if (result.success && result.data) {
|
|
732
|
+
this.cache.set(cacheKey, result.data);
|
|
733
|
+
}
|
|
734
|
+
return result;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
return await this.callTool<unknown[]>(MCP_TOOLS.SEARCH_NODES, serverParams);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Search for facts (relationships) in the knowledge graph
|
|
742
|
+
* Results are cached for repeated queries
|
|
743
|
+
*
|
|
744
|
+
* NOTE: Sanitization is handled server-side by falkordb_lucene.py patch
|
|
745
|
+
*/
|
|
746
|
+
async searchFacts(params: SearchFactsParams): Promise<MCPClientResponse<unknown[]>> {
|
|
747
|
+
// Server-side sanitization handles Lucene escaping
|
|
748
|
+
const serverParams: Record<string, unknown> = {
|
|
749
|
+
query: params.query,
|
|
750
|
+
};
|
|
751
|
+
if (params.max_facts !== undefined) {
|
|
752
|
+
serverParams.max_facts = params.max_facts;
|
|
753
|
+
}
|
|
754
|
+
if (params.group_ids) {
|
|
755
|
+
serverParams.group_ids = params.group_ids;
|
|
756
|
+
}
|
|
757
|
+
if (params.center_node_uuid) {
|
|
758
|
+
serverParams.center_node_uuid = params.center_node_uuid;
|
|
759
|
+
}
|
|
760
|
+
// Temporal filters (Madeinoz Patch)
|
|
761
|
+
if (params.since) {
|
|
762
|
+
serverParams.created_after = params.since;
|
|
763
|
+
}
|
|
764
|
+
if (params.until) {
|
|
765
|
+
serverParams.created_before = params.until;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// Check cache first
|
|
769
|
+
if (this.cache) {
|
|
770
|
+
const cacheKey = this.getCacheKey(MCP_TOOLS.SEARCH_FACTS, serverParams);
|
|
771
|
+
const cached = this.cache.get(cacheKey);
|
|
772
|
+
if (cached) {
|
|
773
|
+
return { success: true, data: cached as unknown[] };
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Fetch and cache
|
|
777
|
+
const result = await this.callTool<unknown[]>(MCP_TOOLS.SEARCH_FACTS, serverParams);
|
|
778
|
+
if (result.success && result.data) {
|
|
779
|
+
this.cache.set(cacheKey, result.data);
|
|
780
|
+
}
|
|
781
|
+
return result;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
return await this.callTool<unknown[]>(MCP_TOOLS.SEARCH_FACTS, serverParams);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Get recent episodes from the knowledge graph
|
|
789
|
+
*
|
|
790
|
+
* NOTE: Sanitization is handled server-side by falkordb_lucene.py patch
|
|
791
|
+
*/
|
|
792
|
+
async getEpisodes(params: GetEpisodesParams = {}): Promise<MCPClientResponse<unknown[]>> {
|
|
793
|
+
// Build server params with correct field names
|
|
794
|
+
// Server-side sanitization handles Lucene escaping
|
|
795
|
+
const serverParams: Record<string, unknown> = {};
|
|
796
|
+
if (params.limit !== undefined) {
|
|
797
|
+
serverParams.max_episodes = params.limit;
|
|
798
|
+
}
|
|
799
|
+
// Support both group_id (single) and group_ids (multiple)
|
|
800
|
+
if (params.group_ids) {
|
|
801
|
+
serverParams.group_ids = params.group_ids;
|
|
802
|
+
} else if (params.group_id) {
|
|
803
|
+
// Server-side sanitization handles Lucene escaping
|
|
804
|
+
serverParams.group_ids = [params.group_id];
|
|
805
|
+
}
|
|
806
|
+
return await this.callTool<unknown[]>(MCP_TOOLS.GET_EPISODES, serverParams);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* Get the status of the knowledge graph
|
|
811
|
+
*/
|
|
812
|
+
async getStatus(): Promise<
|
|
813
|
+
MCPClientResponse<{
|
|
814
|
+
entity_count: number;
|
|
815
|
+
episode_count: number;
|
|
816
|
+
last_updated: string;
|
|
817
|
+
}>
|
|
818
|
+
> {
|
|
819
|
+
return await this.callTool<{
|
|
820
|
+
entity_count: number;
|
|
821
|
+
episode_count: number;
|
|
822
|
+
last_updated: string;
|
|
823
|
+
}>(MCP_TOOLS.GET_STATUS, {});
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Clear all data from the knowledge graph
|
|
828
|
+
*/
|
|
829
|
+
async clearGraph(): Promise<MCPClientResponse<{ success: boolean }>> {
|
|
830
|
+
return await this.callTool<{ success: boolean }>(MCP_TOOLS.CLEAR_GRAPH, {});
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* Delete an episode from the knowledge graph
|
|
835
|
+
*/
|
|
836
|
+
async deleteEpisode(
|
|
837
|
+
params: DeleteEpisodeParams
|
|
838
|
+
): Promise<MCPClientResponse<{ success: boolean }>> {
|
|
839
|
+
return await this.callTool<{ success: boolean }>(MCP_TOOLS.DELETE_EPISODE, params as unknown as Record<string, unknown>);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Delete an entity edge from the knowledge graph
|
|
844
|
+
*/
|
|
845
|
+
async deleteEntityEdge(
|
|
846
|
+
params: DeleteEntityEdgeParams
|
|
847
|
+
): Promise<MCPClientResponse<{ success: boolean }>> {
|
|
848
|
+
return await this.callTool<{ success: boolean }>(MCP_TOOLS.DELETE_ENTITY_EDGE, params as unknown as Record<string, unknown>);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Get an entity edge from the knowledge graph
|
|
853
|
+
*/
|
|
854
|
+
async getEntityEdge(params: GetEntityEdgeParams): Promise<MCPClientResponse<unknown>> {
|
|
855
|
+
return await this.callTool<unknown>(MCP_TOOLS.GET_ENTITY_EDGE, params as unknown as Record<string, unknown>);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Feature 009: Get knowledge graph health metrics
|
|
860
|
+
*/
|
|
861
|
+
async getKnowledgeHealth(
|
|
862
|
+
params: GetKnowledgeHealthParams = {}
|
|
863
|
+
): Promise<MCPClientResponse<unknown>> {
|
|
864
|
+
const serverParams: Record<string, unknown> = {};
|
|
865
|
+
if (params.group_id) {
|
|
866
|
+
serverParams.group_id = params.group_id;
|
|
867
|
+
}
|
|
868
|
+
return await this.callTool<unknown>(MCP_TOOLS.GET_KNOWLEDGE_HEALTH, serverParams);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
/**
|
|
872
|
+
* Feature 009: Run decay maintenance cycle
|
|
873
|
+
*/
|
|
874
|
+
async runDecayMaintenance(
|
|
875
|
+
params: RunDecayMaintenanceParams = {}
|
|
876
|
+
): Promise<MCPClientResponse<unknown>> {
|
|
877
|
+
const serverParams: Record<string, unknown> = {
|
|
878
|
+
dry_run: params.dry_run ?? false,
|
|
879
|
+
};
|
|
880
|
+
return await this.callTool<unknown>(MCP_TOOLS.RUN_DECAY_MAINTENANCE, serverParams);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Feature 009: Classify memory importance and stability
|
|
885
|
+
*/
|
|
886
|
+
async classifyMemory(
|
|
887
|
+
params: ClassifyMemoryParams
|
|
888
|
+
): Promise<MCPClientResponse<unknown>> {
|
|
889
|
+
const serverParams: Record<string, unknown> = {
|
|
890
|
+
content: params.content,
|
|
891
|
+
};
|
|
892
|
+
if (params.source_description) {
|
|
893
|
+
serverParams.source_description = params.source_description;
|
|
894
|
+
}
|
|
895
|
+
return await this.callTool<unknown>(MCP_TOOLS.CLASSIFY_MEMORY, serverParams);
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
/**
|
|
899
|
+
* Feature 009: Recover soft-deleted memory
|
|
900
|
+
*/
|
|
901
|
+
async recoverSoftDeleted(
|
|
902
|
+
params: RecoverSoftDeletedParams
|
|
903
|
+
): Promise<MCPClientResponse<unknown>> {
|
|
904
|
+
return await this.callTool<unknown>(MCP_TOOLS.RECOVER_SOFT_DELETED, {
|
|
905
|
+
uuid: params.uuid,
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* Feature 018: List ontology types (entity and relationship types)
|
|
911
|
+
*/
|
|
912
|
+
async listOntologyTypes(): Promise<
|
|
913
|
+
MCPClientResponse<{
|
|
914
|
+
entity_types: string[];
|
|
915
|
+
relationship_types: string[];
|
|
916
|
+
entity_type_count: number;
|
|
917
|
+
relationship_type_count: number;
|
|
918
|
+
}>
|
|
919
|
+
> {
|
|
920
|
+
return await this.callTool<{
|
|
921
|
+
entity_types: string[];
|
|
922
|
+
relationship_types: string[];
|
|
923
|
+
entity_type_count: number;
|
|
924
|
+
relationship_type_count: number;
|
|
925
|
+
}>(MCP_TOOLS.LIST_ONTOLOGY_TYPES, {});
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* Feature 018: Validate ontology configuration
|
|
930
|
+
*/
|
|
931
|
+
async validateOntology(): Promise<
|
|
932
|
+
MCPClientResponse<{
|
|
933
|
+
valid: boolean;
|
|
934
|
+
errors: string[];
|
|
935
|
+
warnings: string[];
|
|
936
|
+
breaking_changes: string[];
|
|
937
|
+
}>
|
|
938
|
+
> {
|
|
939
|
+
return await this.callTool<{
|
|
940
|
+
valid: boolean;
|
|
941
|
+
errors: string[];
|
|
942
|
+
warnings: string[];
|
|
943
|
+
breaking_changes: string[];
|
|
944
|
+
}>(MCP_TOOLS.VALIDATE_ONTOLOGY, {});
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* Feature 018: Reload ontology configuration
|
|
949
|
+
*/
|
|
950
|
+
async reloadOntology(): Promise<
|
|
951
|
+
MCPClientResponse<{
|
|
952
|
+
success: boolean;
|
|
953
|
+
message: string;
|
|
954
|
+
entity_types: string[];
|
|
955
|
+
relationship_types: string[];
|
|
956
|
+
entity_type_count: number;
|
|
957
|
+
relationship_type_count: number;
|
|
958
|
+
version: string;
|
|
959
|
+
name: string;
|
|
960
|
+
breaking_changes: string[];
|
|
961
|
+
}>
|
|
962
|
+
> {
|
|
963
|
+
return await this.callTool<{
|
|
964
|
+
success: boolean;
|
|
965
|
+
message: string;
|
|
966
|
+
entity_types: string[];
|
|
967
|
+
relationship_types: string[];
|
|
968
|
+
entity_type_count: number;
|
|
969
|
+
relationship_type_count: number;
|
|
970
|
+
version: string;
|
|
971
|
+
name: string;
|
|
972
|
+
breaking_changes: string[];
|
|
973
|
+
}>(MCP_TOOLS.RELOAD_ONTOLOGY, {});
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
* Feature 018: Import STIX 2.1 bundle
|
|
978
|
+
*/
|
|
979
|
+
async importStixBundle(params: {
|
|
980
|
+
bundle_data: Record<string, unknown>;
|
|
981
|
+
batch_size?: number;
|
|
982
|
+
continue_on_error?: boolean;
|
|
983
|
+
}): Promise<
|
|
984
|
+
MCPClientResponse<{
|
|
985
|
+
session_id: string;
|
|
986
|
+
entities_imported: number;
|
|
987
|
+
relationships_imported: number;
|
|
988
|
+
errors: number;
|
|
989
|
+
warnings: string[];
|
|
990
|
+
}>
|
|
991
|
+
> {
|
|
992
|
+
return await this.callTool<{
|
|
993
|
+
session_id: string;
|
|
994
|
+
entities_imported: number;
|
|
995
|
+
relationships_imported: number;
|
|
996
|
+
errors: number;
|
|
997
|
+
warnings: string[];
|
|
998
|
+
}>(MCP_TOOLS.IMPORT_STIX_BUNDLE, params as unknown as Record<string, unknown>);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Feature 018: Get STIX import status
|
|
1003
|
+
*/
|
|
1004
|
+
/**
|
|
1005
|
+
* Feature 018: Get STIX import status
|
|
1006
|
+
*/
|
|
1007
|
+
async getImportStatus(params: { import_id: string }): Promise<
|
|
1008
|
+
MCPClientResponse<{
|
|
1009
|
+
import_id: string;
|
|
1010
|
+
source_file: string;
|
|
1011
|
+
started_at: string;
|
|
1012
|
+
completed_at: string | null;
|
|
1013
|
+
status: string;
|
|
1014
|
+
total_objects: number;
|
|
1015
|
+
imported_count: number;
|
|
1016
|
+
failed_count: number;
|
|
1017
|
+
failed_object_ids: string[];
|
|
1018
|
+
error_messages: string[];
|
|
1019
|
+
}>
|
|
1020
|
+
> {
|
|
1021
|
+
return await this.callTool<{
|
|
1022
|
+
import_id: string;
|
|
1023
|
+
source_file: string;
|
|
1024
|
+
started_at: string;
|
|
1025
|
+
completed_at: string | null;
|
|
1026
|
+
status: string;
|
|
1027
|
+
total_objects: number;
|
|
1028
|
+
imported_count: number;
|
|
1029
|
+
failed_count: number;
|
|
1030
|
+
failed_object_ids: string[];
|
|
1031
|
+
error_messages: string[];
|
|
1032
|
+
}>(MCP_TOOLS.GET_IMPORT_STATUS, params as unknown as Record<string, unknown>);
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* Feature 020: Investigate an entity and return all connected relationships
|
|
1037
|
+
*/
|
|
1038
|
+
async investigateEntity(
|
|
1039
|
+
params: InvestigateEntityParams
|
|
1040
|
+
): Promise<
|
|
1041
|
+
MCPClientResponse<{
|
|
1042
|
+
entity: {
|
|
1043
|
+
uuid: string;
|
|
1044
|
+
name: string;
|
|
1045
|
+
labels: string[];
|
|
1046
|
+
summary?: string;
|
|
1047
|
+
created_at?: string;
|
|
1048
|
+
group_id?: string;
|
|
1049
|
+
};
|
|
1050
|
+
connections: Array<{
|
|
1051
|
+
relationship: string;
|
|
1052
|
+
direction: string;
|
|
1053
|
+
hop_distance: number;
|
|
1054
|
+
target_entity: {
|
|
1055
|
+
uuid: string;
|
|
1056
|
+
name: string;
|
|
1057
|
+
labels: string[];
|
|
1058
|
+
summary?: string;
|
|
1059
|
+
created_at?: string;
|
|
1060
|
+
group_id?: string;
|
|
1061
|
+
};
|
|
1062
|
+
fact?: string;
|
|
1063
|
+
confidence?: number;
|
|
1064
|
+
}>;
|
|
1065
|
+
metadata: {
|
|
1066
|
+
depth_explored: number;
|
|
1067
|
+
total_connections_explored: number;
|
|
1068
|
+
connections_returned: number;
|
|
1069
|
+
cycles_detected: number;
|
|
1070
|
+
cycles_pruned: number;
|
|
1071
|
+
entities_skipped: number;
|
|
1072
|
+
query_duration_ms: number;
|
|
1073
|
+
max_connections_exceeded?: boolean;
|
|
1074
|
+
};
|
|
1075
|
+
warning?: string;
|
|
1076
|
+
}>
|
|
1077
|
+
> {
|
|
1078
|
+
const serverParams: Record<string, unknown> = {
|
|
1079
|
+
entity_name: params.entity_name,
|
|
1080
|
+
};
|
|
1081
|
+
if (params.max_depth !== undefined) {
|
|
1082
|
+
serverParams.max_depth = params.max_depth;
|
|
1083
|
+
}
|
|
1084
|
+
if (params.relationship_types) {
|
|
1085
|
+
serverParams.relationship_types = params.relationship_types;
|
|
1086
|
+
}
|
|
1087
|
+
if (params.group_ids) {
|
|
1088
|
+
serverParams.group_ids = params.group_ids;
|
|
1089
|
+
}
|
|
1090
|
+
if (params.include_attributes !== undefined) {
|
|
1091
|
+
serverParams.include_attributes = params.include_attributes;
|
|
1092
|
+
}
|
|
1093
|
+
return await this.callTool(MCP_TOOLS.INVESTIGATE_ENTITY, serverParams);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* Test the connection to the MCP server
|
|
1098
|
+
*/
|
|
1099
|
+
async testConnection(): Promise<MCPClientResponse<{ status: string }>> {
|
|
1100
|
+
// Test mode: return mock response without connecting
|
|
1101
|
+
// Used by integration tests to avoid network calls
|
|
1102
|
+
if (process.env.MADEINOZ_KNOWLEDGE_TEST_MODE === 'true') {
|
|
1103
|
+
return {
|
|
1104
|
+
success: true,
|
|
1105
|
+
data: { status: 'ok' },
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
try {
|
|
1110
|
+
const controller = new AbortController();
|
|
1111
|
+
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout for health check
|
|
1112
|
+
|
|
1113
|
+
// T021 [P] [US2]: Apply TLS configuration for HTTPS requests
|
|
1114
|
+
const tlsOptions = createHTTPSOptions(this.tlsConfig);
|
|
1115
|
+
|
|
1116
|
+
const response = await fetch(`${this.baseURL.replace(/\/mcp\/?$/, '')}/health`, {
|
|
1117
|
+
method: 'GET',
|
|
1118
|
+
signal: controller.signal,
|
|
1119
|
+
...tlsOptions,
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
clearTimeout(timeoutId);
|
|
1123
|
+
|
|
1124
|
+
if (!response.ok) {
|
|
1125
|
+
return {
|
|
1126
|
+
success: false,
|
|
1127
|
+
error: `HTTP ${response.status}: ${response.statusText}`,
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
const data = await response.json();
|
|
1132
|
+
return {
|
|
1133
|
+
success: true,
|
|
1134
|
+
data: data as { status: string },
|
|
1135
|
+
};
|
|
1136
|
+
} catch (error: unknown) {
|
|
1137
|
+
if (error instanceof Error) {
|
|
1138
|
+
// T018 [US1]: Implement connection error handling with actionable messages
|
|
1139
|
+
// T026 [US2]: Add TLS certificate error handling with clear messages
|
|
1140
|
+
const errorMsg = error.message.toLowerCase();
|
|
1141
|
+
const suggestions: string[] = [];
|
|
1142
|
+
|
|
1143
|
+
// TLS/SSL certificate errors
|
|
1144
|
+
if (
|
|
1145
|
+
errorMsg.includes('certificate') ||
|
|
1146
|
+
errorMsg.includes('tls') ||
|
|
1147
|
+
errorMsg.includes('ssl') ||
|
|
1148
|
+
errorMsg.includes('handshake')
|
|
1149
|
+
) {
|
|
1150
|
+
suggestions.push('Check that the server certificate is valid');
|
|
1151
|
+
suggestions.push('Try MADEINOZ_KNOWLEDGE_TLS_VERIFY=false for self-signed certificates (not recommended for production)');
|
|
1152
|
+
if (this.tlsConfig?.ca) {
|
|
1153
|
+
suggestions.push(`Verify CA certificate path exists: ${this.tlsConfig.ca}`);
|
|
1154
|
+
}
|
|
1155
|
+
return {
|
|
1156
|
+
success: false,
|
|
1157
|
+
error: `TLS Certificate Error: ${error.message}\nSuggestions:\n - ${suggestions.join('\n - ')}`,
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
// Host unreachable / DNS resolution errors
|
|
1162
|
+
if (
|
|
1163
|
+
errorMsg.includes('econnrefused') ||
|
|
1164
|
+
errorMsg.includes('connection refused') ||
|
|
1165
|
+
errorMsg.includes('econnreset') ||
|
|
1166
|
+
errorMsg.includes('enotfound') ||
|
|
1167
|
+
errorMsg.includes('getaddrinfo')
|
|
1168
|
+
) {
|
|
1169
|
+
suggestions.push('Verify the MCP server is running (bun run server status)');
|
|
1170
|
+
suggestions.push('Check firewall settings allow connections');
|
|
1171
|
+
suggestions.push('Verify the host and port are correct');
|
|
1172
|
+
if (this.baseURL.includes('localhost') || this.baseURL.includes('127.0.0.1')) {
|
|
1173
|
+
suggestions.push('If running in Docker, ensure ports are properly mapped');
|
|
1174
|
+
}
|
|
1175
|
+
return {
|
|
1176
|
+
success: false,
|
|
1177
|
+
error: `Connection Error: Unable to reach server at ${this.baseURL}\nSuggestions:\n - ${suggestions.join('\n - ')}`,
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
// Network timeout errors
|
|
1182
|
+
if (
|
|
1183
|
+
errorMsg.includes('timeout') ||
|
|
1184
|
+
errorMsg.includes('timed out') ||
|
|
1185
|
+
error.name === 'AbortError'
|
|
1186
|
+
) {
|
|
1187
|
+
suggestions.push('The request took too long to complete');
|
|
1188
|
+
suggestions.push('Check if the server is under heavy load');
|
|
1189
|
+
suggestions.push('Try increasing MADEINOZ_KNOWLEDGE_TIMEOUT (currently ${this.timeout}ms)');
|
|
1190
|
+
return {
|
|
1191
|
+
success: false,
|
|
1192
|
+
error: `Connection Timeout: ${error.message}\nSuggestions:\n - ${suggestions.join('\n - ')}`,
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
// Invalid protocol errors
|
|
1197
|
+
if (errorMsg.includes('invalid protocol') || errorMsg.includes('unsupported protocol')) {
|
|
1198
|
+
suggestions.push('Check MADEINOZ_KNOWLEDGE_PROTOCOL is "http" or "https"');
|
|
1199
|
+
return {
|
|
1200
|
+
success: false,
|
|
1201
|
+
error: `Protocol Error: ${error.message}\nSuggestions:\n - ${suggestions.join('\n - ')}`,
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// Generic error with message
|
|
1206
|
+
return {
|
|
1207
|
+
success: false,
|
|
1208
|
+
error: error.message,
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
return {
|
|
1212
|
+
success: false,
|
|
1213
|
+
error: 'Unknown error occurred',
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
/**
|
|
1220
|
+
* Create an MCP client instance with configuration from environment variables or profiles
|
|
1221
|
+
*
|
|
1222
|
+
* T015 [US1]: Update createMCPClient() to accept extended config
|
|
1223
|
+
* T016 [US1]: Add environment variable parsing
|
|
1224
|
+
* T023 [US2]: Add MADEINOZ_KNOWLEDGE_TLS_VERIFY environment variable support
|
|
1225
|
+
* T024 [US2]: Add MADEINOZ_KNOWLEDGE_TLS_CA environment variable support
|
|
1226
|
+
*
|
|
1227
|
+
* Priority order (highest to lowest):
|
|
1228
|
+
* 1. Explicit config parameter
|
|
1229
|
+
* 2. Individual environment variables (MADEINOZ_KNOWLEDGE_HOST, etc.)
|
|
1230
|
+
* 3. Profile from MADEINOZ_KNOWLEDGE_PROFILE environment variable
|
|
1231
|
+
* 4. Default profile from YAML file
|
|
1232
|
+
* 5. Code defaults (localhost:8001, http)
|
|
1233
|
+
*
|
|
1234
|
+
* Environment variables (MADEINOZ_KNOWLEDGE_* prefix):
|
|
1235
|
+
* - MADEINOZ_KNOWLEDGE_PROFILE: Profile name to load from YAML file
|
|
1236
|
+
* - MADEINOZ_KNOWLEDGE_PROTOCOL: http or https (default: http)
|
|
1237
|
+
* - MADEINOZ_KNOWLEDGE_HOST: hostname or IP address (default: localhost)
|
|
1238
|
+
* - MADEINOZ_KNOWLEDGE_PORT: TCP port (default: 8001)
|
|
1239
|
+
* - MADEINOZ_KNOWLEDGE_BASE_PATH: URL path prefix (default: /mcp)
|
|
1240
|
+
* - MADEINOZ_KNOWLEDGE_TLS_VERIFY: true or false (default: true)
|
|
1241
|
+
* - MADEINOZ_KNOWLEDGE_TLS_CA: Path to CA certificate file
|
|
1242
|
+
* - MADEINOZ_KNOWLEDGE_TLS_CERT: Path to client certificate file
|
|
1243
|
+
* - MADEINOZ_KNOWLEDGE_TLS_KEY: Path to client private key file
|
|
1244
|
+
*/
|
|
1245
|
+
export function createMCPClient(config?: MCPClientConfig): MCPClient {
|
|
1246
|
+
// If explicit config provided with all necessary fields, use it directly
|
|
1247
|
+
if (config && (config.baseURL || (config.host && config.port))) {
|
|
1248
|
+
return new MCPClient(config);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
// Build extended config from environment variables
|
|
1252
|
+
const envConfig: MCPClientConfigExtended = {
|
|
1253
|
+
protocol: (process.env.MADEINOZ_KNOWLEDGE_PROTOCOL as 'http' | 'https') || undefined,
|
|
1254
|
+
host: process.env.MADEINOZ_KNOWLEDGE_HOST || undefined,
|
|
1255
|
+
port: process.env.MADEINOZ_KNOWLEDGE_PORT ? Number.parseInt(process.env.MADEINOZ_KNOWLEDGE_PORT, 10) : undefined,
|
|
1256
|
+
basePath: process.env.MADEINOZ_KNOWLEDGE_BASE_PATH || undefined,
|
|
1257
|
+
tls: {
|
|
1258
|
+
// T023 [US2]: Add MADEINOZ_KNOWLEDGE_TLS_VERIFY environment variable support
|
|
1259
|
+
verify: process.env.MADEINOZ_KNOWLEDGE_TLS_VERIFY ? process.env.MADEINOZ_KNOWLEDGE_TLS_VERIFY !== 'false' : undefined,
|
|
1260
|
+
// T024 [US2]: Add MADEINOZ_KNOWLEDGE_TLS_CA environment variable support
|
|
1261
|
+
ca: process.env.MADEINOZ_KNOWLEDGE_TLS_CA || undefined,
|
|
1262
|
+
cert: process.env.MADEINOZ_KNOWLEDGE_TLS_CERT || undefined,
|
|
1263
|
+
key: process.env.MADEINOZ_KNOWLEDGE_TLS_KEY || undefined,
|
|
1264
|
+
},
|
|
1265
|
+
...config,
|
|
1266
|
+
};
|
|
1267
|
+
|
|
1268
|
+
// Remove undefined TLS config to avoid overriding defaults
|
|
1269
|
+
if (!envConfig.tls?.ca && !envConfig.tls?.cert && !envConfig.tls?.key && envConfig.tls?.verify === undefined) {
|
|
1270
|
+
delete envConfig.tls;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// If no explicit config and no environment variables, try loading from profile
|
|
1274
|
+
if (!config && !process.env.MADEINOZ_KNOWLEDGE_HOST && !process.env.MADEINOZ_KNOWLEDGE_PORT) {
|
|
1275
|
+
try {
|
|
1276
|
+
// Load profile from config file (imported at top of file)
|
|
1277
|
+
const profileConfig = loadProfileWithOverrides();
|
|
1278
|
+
|
|
1279
|
+
// Convert profile config to MCPClientConfig format
|
|
1280
|
+
const profileBasedConfig: MCPClientConfigExtended = {
|
|
1281
|
+
protocol: profileConfig.protocol as 'http' | 'https',
|
|
1282
|
+
host: profileConfig.host,
|
|
1283
|
+
port: profileConfig.port,
|
|
1284
|
+
basePath: profileConfig.basePath,
|
|
1285
|
+
timeout: profileConfig.timeout,
|
|
1286
|
+
tls: profileConfig.tls,
|
|
1287
|
+
profile: profileConfig.name,
|
|
1288
|
+
};
|
|
1289
|
+
|
|
1290
|
+
// Profile settings as base, environment variables override (only defined values)
|
|
1291
|
+
// Note: envConfig must come first so undefined values don't override profile values
|
|
1292
|
+
const finalConfig = { ...envConfig, ...profileBasedConfig };
|
|
1293
|
+
return new MCPClient(finalConfig);
|
|
1294
|
+
} catch (_error) {
|
|
1295
|
+
// If profile loading fails, fall back to environment config or defaults
|
|
1296
|
+
// This ensures backward compatibility
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
return new MCPClient(envConfig);
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
/**
|
|
1304
|
+
* Quick health check function
|
|
1305
|
+
*/
|
|
1306
|
+
export async function checkHealth(baseURL?: string): Promise<boolean> {
|
|
1307
|
+
const client = new MCPClient({ baseURL });
|
|
1308
|
+
const result = await client.testConnection();
|
|
1309
|
+
return result.success;
|
|
1310
|
+
}
|