diff --git a/azure-ai-search/.env.example b/azure-ai-search/.env.example
new file mode 100644
index 0000000..ad2f609
--- /dev/null
+++ b/azure-ai-search/.env.example
@@ -0,0 +1,6 @@
+# Azure Search Configuration
+AZURE_SEARCH_ENDPOINT=--your-azure-search-endpoint--
+AZURE_SEARCH_API_KEY=--your-azure-search-api-key--
+
+# Alternative: Using Managed Identity (set service name instead of API key)
+# AZURE_SEARCH_SERVICE_NAME=your-search-service
diff --git a/azure-ai-search/.gitignore b/azure-ai-search/.gitignore
new file mode 100644
index 0000000..b8245aa
--- /dev/null
+++ b/azure-ai-search/.gitignore
@@ -0,0 +1,3 @@
+/dist
+/node_modules
+.env
\ No newline at end of file
diff --git a/azure-ai-search/.npmignore b/azure-ai-search/.npmignore
new file mode 100644
index 0000000..c81ba65
--- /dev/null
+++ b/azure-ai-search/.npmignore
@@ -0,0 +1,8 @@
+src/
+tools/
+prompts/
+type.ts
+server.ts
+tsconfig.json
+pnpm-lock.yaml
+node_modules/
\ No newline at end of file
diff --git a/azure-ai-search/CLAUDE.md b/azure-ai-search/CLAUDE.md
new file mode 100644
index 0000000..4a9e966
--- /dev/null
+++ b/azure-ai-search/CLAUDE.md
@@ -0,0 +1,123 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Development Commands
+
+- **Build**: `pnpm build` - Compiles TypeScript to JavaScript using Rollup
+- **Start Development**: `pnpm start` - Runs the server directly with ts-node
+- **Start Production**: `pnpm start:prod` - Runs the built server from dist/
+- **Inspect**: `pnpm inspect` - Runs the MCP inspector for debugging
+
+## Architecture Overview
+
+This is an MCP (Model Context Protocol) server that provides Azure AI Search integration. Currently implements Phase 1 of the roadmap focusing on document retrieval and search functionality.
+
+### Current Implementation Status
+
+** Phase 1.1 - Configuration & Authentication**
+- Azure Search Documents SDK integrated (`@azure/search-documents`)
+- Dual authentication support (API key + Managed Identity)
+- Environment variables: `AZURE_SEARCH_ENDPOINT`, `AZURE_SEARCH_API_KEY`
+
+** Phase 1.2 - Core Search Tools (Retrieval)**
+- `search-documents` - Full-text search with filtering, faceting, highlighting
+- `get-document` - Retrieve specific document by key
+- `suggest` - Search suggestions using configured suggesters
+- `autocomplete` - Auto-completion for partial search terms
+
+**✅ Phase 2.1 - Index Management & Discovery**
+- `list-indexes` - List all available search indexes
+- `get-index-schema` - Get complete index schema and field definitions
+- `get-index-statistics` - Get index usage statistics and document counts
+
+**✅ Phase 2.2 - Dynamic Resources**
+- Auto-discovery of available indexes at startup
+- Dynamic resources for each index: schema, statistics, sample documents
+- Resource URIs: `azure-search://indexes`, `azure-search://index/{name}/schema`, etc.
+
+**✅ Phase 3.1 - Document Management (COMPLETE)**
+- `upload-documents` - Upload/create documents (batch operations up to 1000)
+- `merge-documents` - Partial update of existing documents
+- `delete-documents` - Delete documents by key values (batch operations)
+
+**✅ Phase 4.1 - Vector Search (COMPLETE)**
+- `vector-search` - Pure vector similarity search using k-nearest neighbors
+- `hybrid-search` - Combined text and vector search for enhanced relevance
+- Support for multiple vector queries and exhaustive search modes
+
+**✅ Phase 4.2 - Semantic Search (COMPLETE)**
+- `semantic-search` - Azure AI semantic search with natural language understanding
+- Semantic answers extraction from search results
+- Semantic captions with highlighting support
+- Integration with Azure's semantic configurations
+
+### Core Components
+
+- **server.ts** - Main MCP server entry point with tool registration
+- **lib/azure-search-client.ts** - Azure Search client wrapper with error handling
+- **tools/search-tools.ts** - Search tool implementations with validation
+- **tools/index-tools.ts** - Index management tool implementations
+- **resources/index-resources.ts** - Dynamic resource registration for discovered indexes
+- **types.ts** - Zod schemas for Azure AI Search parameters and responses
+
+### Key Architecture Patterns
+
+1. **Lazy Loading**: Azure Search clients instantiated only when first accessed
+2. **Client Caching**: Search clients cached per index name for efficiency
+3. **Dual Authentication**: Supports both API key and DefaultAzureCredential
+4. **Type Safety**: All parameters validated with Zod schemas
+5. **Error Handling**: Consistent success/error response format
+
+### Configuration
+
+#### Environment Variables
+```env
+AZURE_SEARCH_ENDPOINT=https://your-service.search.windows.net
+AZURE_SEARCH_API_KEY=your-api-key
+```
+
+#### Alternative: Managed Identity
+```env
+AZURE_SEARCH_ENDPOINT=https://your-service.search.windows.net
+# No API key needed - uses DefaultAzureCredential
+```
+
+### Available Tools
+
+#### Core Search Tools
+- **search-documents** - Full-text search with filtering, faceting, highlighting
+- **get-document** - Retrieve specific document by primary key
+- **suggest** - Search suggestions using configured suggester with fuzzy matching
+- **autocomplete** - Auto-complete partial search terms with multiple modes
+
+#### Index Management Tools
+- **list-indexes** - List all available search indexes
+- **get-index-schema** - Get complete index schema and field definitions
+- **get-index-statistics** - Get index usage statistics and document counts
+
+#### Document Management Tools
+- **upload-documents** - Upload/create documents (batch operations up to 1000)
+- **merge-documents** - Partial update of existing documents
+- **delete-documents** - Delete documents by key values (batch operations)
+
+#### Vector Search Tools (Phase 4)
+- **vector-search** - Pure vector similarity search using k-nearest neighbors
+- **hybrid-search** - Combined text and vector search for enhanced relevance
+
+#### Semantic Search Tools (Phase 4)
+- **semantic-search** - Azure AI semantic search with natural language understanding
+
+### Build System
+
+Uses Rollup with TypeScript compilation. External dependencies are not bundled to reduce size. Some TypeScript warnings exist but don't affect functionality.
+
+### Next Steps (Roadmap)
+
+See `ROADMAP.md` for complete implementation plan:
+- ✅ **Phase 1**: Core search and retrieval (COMPLETE)
+- ✅ **Phase 2**: Index management and discovery (COMPLETE)
+- ✅ **Phase 3**: Document upload/management (COMPLETE)
+- ✅ **Phase 4**: Vector and semantic search (COMPLETE)
+- 🎯 **Phase 5**: Advanced index operations (create/update/delete indexes)
+- 📊 **Phase 6**: Analytics and performance monitoring
\ No newline at end of file
diff --git a/azure-ai-search/LICENSE b/azure-ai-search/LICENSE
new file mode 100644
index 0000000..2fc98ed
--- /dev/null
+++ b/azure-ai-search/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 IgnitionAI
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/azure-ai-search/ROADMAP.md b/azure-ai-search/ROADMAP.md
new file mode 100644
index 0000000..2432943
--- /dev/null
+++ b/azure-ai-search/ROADMAP.md
@@ -0,0 +1,181 @@
+# Azure AI Search MCP - Roadmap
+
+## ✅ État Actuel - PHASES 1-4 COMPLÈTES !
+Le serveur MCP Azure AI Search est maintenant **fonctionnel et complet** pour toutes les opérations avancées :
+- ✅ Search & Retrieval (Phase 1)
+- ✅ Index Management & Discovery (Phase 2)
+- ✅ Document Management (Phase 3)
+- ✅ Vector & Semantic Search (Phase 4)
+
+---
+
+## ✅ Phase 1: Foundation & Retrieval (COMPLÈTE) 🔍
+
+### ✅ 1.1 Configuration & Authentication
+- ✅ Dépendance `@azure/search-documents` ajoutée
+- ✅ types.ts nettoyé avec schémas Zod pour Azure AI Search
+- ✅ Authentication dual (API key + Managed Identity)
+- ✅ Variables d'env: `AZURE_SEARCH_ENDPOINT`, `AZURE_SEARCH_API_KEY`
+
+### ✅ 1.2 Core Search Tools (Retrieval)
+- ✅ **search-documents** - Recherche complète avec filtres, facettes, highlighting
+- ✅ **get-document** - Récupération de document par clé
+- ✅ **suggest** - Suggestions de recherche avec fuzzy matching
+- ✅ **autocomplete** - Auto-complétion de termes
+
+### ✅ 1.3 Index Discovery Resources
+- ✅ **list-indexes** - Liste tous les index disponibles
+- ✅ **get-index-schema** - Récupère le schéma complet d'un index
+- ✅ Resources dynamiques pour chaque index découvert
+
+---
+
+## ✅ Phase 2: Index Management & Discovery (COMPLÈTE) ⚙️
+
+### ✅ 2.1 Index Operations
+- ✅ **get-index-statistics** - Statistiques et usage d'un index
+- ✅ **get-index-schema** - Schéma détaillé avec fields, analyzers, etc.
+- ✅ Dynamic resource registration au démarrage
+
+### ✅ 2.2 Dynamic Resources
+- ✅ Auto-discovery des index au startup
+- ✅ Resources MCP créées automatiquement :
+ - `azure-search://indexes` - Liste complète
+ - `azure-search://index/{name}/schema` - Schéma par index
+ - `azure-search://index/{name}/statistics` - Stats par index
+ - `azure-search://index/{name}/sample` - Documents échantillons
+
+---
+
+## ✅ Phase 3: Document Management (COMPLÈTE) 📄
+
+### ✅ 3.1 Document Operations
+- ✅ **upload-documents** - Upload/création de documents (batch 1000 max)
+- ✅ **merge-documents** - Mise à jour partielle de documents existants
+- ✅ **delete-documents** - Suppression de documents par clés (batch 1000 max)
+
+### ✅ 3.2 Document Processing
+- ✅ Validation complète des documents selon schémas Zod
+- ✅ Gestion d'erreurs batch avec détails par document
+- ✅ Support des types Azure AI Search (text, vector, etc.)
+
+## ✅ Phase 4: Vector & Semantic Search (COMPLÈTE) 🤖
+
+### ✅ 4.1 Vector Search Enhancement
+- ✅ **vector-search** - Recherche vectorielle native avec K-NN
+- ✅ **hybrid-search** - Recherche hybride (text + vector)
+- ✅ **knn-search** - Intégré dans vector-search (paramètre k)
+- ✅ **vector-filtering** - Support des filtres OData sur résultats vectoriels
+
+### ✅ 4.2 Semantic Search
+- ✅ **semantic-search** - Recherche sémantique Azure avec configuration
+- ✅ **semantic-answers** - Réponses sémantiques extraites automatiquement
+- ✅ **semantic-captions** - Légendes sémantiques avec highlighting
+- ✅ **semantic-ranking** - Classement sémantique intégré
+
+## Phase 5: Advanced Index Operations (Utile) ⚙️
+
+### 5.1 Index Lifecycle
+- [ ] **create-index** - Création d'index avec schéma complet
+- [ ] **update-index** - Mise à jour schéma d'index existant
+- [ ] **delete-index** - Suppression d'index
+- [ ] **index-aliases** - Gestion des alias d'index
+
+### 5.2 Skillsets & Enrichment
+- [ ] **list-skillsets** - Liste des skillsets disponibles
+- [ ] **get-skillset** - Détails d'un skillset
+- [ ] **run-indexer** - Exécution d'un indexer
+- [ ] **indexer-status** - Statut des indexers
+
+## Phase 6: Analytics & Performance (Optionnel) 📊
+
+### 6.1 Search Analytics
+- [ ] **search-analytics** - Métriques de recherche
+- [ ] **query-performance** - Performance des requêtes
+- [ ] **index-health** - Santé des index
+- [ ] **usage-statistics** - Statistiques d'utilisation
+
+### 6.2 Monitoring Tools
+- [ ] **connection-health** - Test de connectivité
+- [ ] **quota-usage** - Utilisation des quotas
+- [ ] **service-statistics** - Statistiques du service
+
+## Architecture Technique
+
+### Structure des Fichiers
+```
+azure-ai-search/
+├── server.ts # Point d'entrée MCP
+├── types.ts # Schémas Zod pour AI Search
+├── lib/
+│ └── azure-search-client.ts # Client Azure AI Search
+├── tools/
+│ ├── search-tools.ts # Outils de recherche
+│ ├── index-tools.ts # Gestion des index
+│ ├── document-tools.ts # Gestion des documents
+│ └── analytics-tools.ts # Analytics (Phase 4)
+├── resources/
+│ ├── index-resources.ts # Resources dynamiques des index
+│ └── search-resources.ts # Resources de recherche
+└── prompts/
+ └── search-prompts.ts # Prompts pour la recherche
+```
+
+### Patterns Architecturaux
+- **Lazy Loading**: Client Azure Search instancié à la demande
+- **Dynamic Resources**: Découverte automatique des index
+- **Error Handling**: Format de réponse cohérent avec success/error
+- **Authentication**: Support API Key + Managed Identity
+- **Validation**: Schémas Zod stricts pour tous les paramètres
+
+### Configuration Environnement
+```env
+AZURE_SEARCH_ENDPOINT=https://myservice.search.windows.net
+AZURE_SEARCH_API_KEY=your-api-key
+# OU pour Managed Identity:
+AZURE_SEARCH_SERVICE_NAME=myservice
+```
+
+## 🎯 Recommandations pour la Suite
+
+### Phase 4 Prioritaire: Vector & Semantic Search
+Le **Vector Search** est la prochaine étape logique car :
+- **Tendance forte** dans l'IA générative et RAG
+- **Value-add majeur** pour les applications d'IA
+- **Déjà supporté** par Azure AI Search
+- **Complémentaire** aux fonctionnalités existantes
+
+### Phase 5 Utile: Index Operations
+Création et gestion d'index directement depuis MCP :
+- **Workflow complet** de A à Z
+- **Productivité** pour les développeurs
+- **Gestion de cycle de vie** des index
+
+### Phase 6 Optionnel: Analytics
+Monitoring et métriques pour optimisation :
+- **Debug** et troubleshooting
+- **Performance tuning**
+- **Usage insights**
+
+## Priorités de Développement
+
+1. ✅ **Phase 1** (COMPLETE): Retrieval fonctionnel
+2. ✅ **Phase 2** (COMPLETE): Gestion basique des index
+3. ✅ **Phase 3** (COMPLETE): Gestion des documents
+4. 🎯 **Phase 4** (Recommandé): Vector & Semantic Search
+5. ⚙️ **Phase 5** (Utile): Advanced Index Operations
+6. 📊 **Phase 6** (Optionnel): Analytics & Performance
+
+## Critères de Succès
+
+### Phase 1 (MVP)
+- [ ] Recherche simple fonctionnelle sur index existants
+- [ ] Auto-discovery des index disponibles
+- [ ] Gestion d'erreurs robuste
+- [ ] Documentation clara avec exemples
+
+### Phases Suivantes
+- [ ] Gestion complète du cycle de vie des index
+- [ ] Support des opérations batch performantes
+- [ ] Intégration avec les outils d'IA générative
+- [ ] Métriques et monitoring intégrés
\ No newline at end of file
diff --git a/azure-ai-search/TESTS_PHASE4.md b/azure-ai-search/TESTS_PHASE4.md
new file mode 100644
index 0000000..304e728
--- /dev/null
+++ b/azure-ai-search/TESTS_PHASE4.md
@@ -0,0 +1,150 @@
+# Tests Phase 4 - Vector & Semantic Search
+## Index Elite Dangerous RAG: `rag-1753386801239`
+
+Voici les tests à effectuer pour valider la Phase 4 sur ton index Elite Dangerous.
+
+## Configuration Index Découverte
+- **Champ vector**: `text_vector` (1536 dimensions)
+- **Config sémantique**: `rag-1753386801239-semantic-configuration`
+- **Champs searchables**: `chunk`, `title`, `header_1`, `header_2`, `header_3`
+- **Profil vectoriel**: `rag-1753386801239-azureOpenAi-text-profile`
+
+---
+
+## Test 1: 📖 Search Documents Classique
+**Tool**: `search-documents`
+```json
+{
+ "indexName": "rag-1753386801239",
+ "searchText": "thargoid combat",
+ "top": 5,
+ "highlightFields": ["chunk", "title"],
+ "highlightPreTag": "",
+ "highlightPostTag": ""
+}
+```
+
+**Résultat attendu**: Articles/guides sur le combat contre les Thargoids avec highlighting.
+
+---
+
+## Test 2: 🔍 Vector Search
+**Tool**: `vector-search`
+```json
+{
+ "indexName": "rag-1753386801239",
+ "vectorQueries": [
+ {
+ "vector": [0.001, 0.002, 0.001, ...répéter 1536 fois...],
+ "fields": "text_vector",
+ "k": 5,
+ "exhaustive": false
+ }
+ ],
+ "top": 5
+}
+```
+
+**Note**: Pour un vrai test, il faudrait un embedding généré par OpenAI text-embedding-3-small pour un concept comme "ship combat" ou "exploration".
+
+---
+
+## Test 3: 🧠 Semantic Search avec Réponses
+**Tool**: `semantic-search`
+```json
+{
+ "indexName": "rag-1753386801239",
+ "searchText": "Comment combattre efficacement les Thargoids dans Elite Dangerous ?",
+ "semanticConfiguration": "rag-1753386801239-semantic-configuration",
+ "answers": {
+ "answerType": "extractive",
+ "count": 3,
+ "threshold": 0.7
+ },
+ "captions": {
+ "captionType": "extractive",
+ "maxTextRecordsToProcess": 1000,
+ "highlight": true
+ },
+ "top": 5
+}
+```
+
+**Résultat attendu**:
+- Réponses extraites directement du contenu
+- Captions avec highlighting
+- Ranking sémantique amélioré
+
+---
+
+## Test 4: 🔥 Hybrid Search (Text + Vector)
+**Tool**: `hybrid-search`
+```json
+{
+ "indexName": "rag-1753386801239",
+ "searchText": "ship loadout",
+ "vectorQueries": [
+ {
+ "vector": [... embedding pour "ship loadout" ...],
+ "fields": "text_vector",
+ "k": 10
+ }
+ ],
+ "searchMode": "any",
+ "top": 5
+}
+```
+
+**Résultat attendu**: Combinaison optimale de pertinence textuelle et vectorielle.
+
+---
+
+## Autres Tests Utiles
+
+### Test index management
+```json
+// Tool: list-indexes
+{}
+
+// Tool: get-index-schema
+{
+ "indexName": "rag-1753386801239"
+}
+```
+
+### Test recherche spécialisée Elite Dangerous
+```json
+// Tool: search-documents
+{
+ "indexName": "rag-1753386801239",
+ "searchText": "guardian technology ruins",
+ "searchFields": ["chunk", "title"],
+ "filter": null,
+ "top": 10
+}
+```
+
+---
+
+## Instructions de Test
+
+1. **Lance l'inspecteur MCP** : `pnpm inspect`
+2. **Ouvre** http://localhost:3000 dans le navigateur
+3. **Teste chaque tool** avec les exemples ci-dessus
+4. **Vérifie** les résultats pour :
+ - ✅ Pas d'erreurs de connexion
+ - ✅ Réponses bien formatées
+ - ✅ Contenu pertinent Elite Dangerous
+ - ✅ Nouvelles fonctionnalités (semantic answers, vector similarity)
+
+## Résultats Attendus
+
+### ✅ Phase 4 Validée Si:
+- [ ] `search-documents` fonctionne avec highlighting
+- [ ] `vector-search` s'exécute sans erreur (même avec dummy vector)
+- [ ] `semantic-search` retourne des réponses et captions
+- [ ] `hybrid-search` combine text et vector
+- [ ] Tous les outils gèrent les erreurs proprement
+- [ ] Performance acceptable (<2s par requête)
+
+**🎯 Objectif**: Valider que toutes les fonctionnalités Phase 4 (Vector & Semantic Search) sont opérationnelles sur ton index RAG Elite Dangerous !
\ No newline at end of file
diff --git a/azure-ai-search/lib/azure-search-client.ts b/azure-ai-search/lib/azure-search-client.ts
new file mode 100644
index 0000000..7828c8d
--- /dev/null
+++ b/azure-ai-search/lib/azure-search-client.ts
@@ -0,0 +1,662 @@
+import { SearchClient, SearchIndexClient, AzureKeyCredential } from "@azure/search-documents";
+import { DefaultAzureCredential } from "@azure/identity";
+import dotenv from "dotenv";
+import type {
+ AzureSearchConfig,
+ SearchResult,
+ DocumentResult,
+ SuggestResult,
+ AutocompleteResult,
+ IndexResult,
+ BatchResult,
+ VectorSearchResult,
+ SemanticSearchResult,
+ VectorQuery
+} from "../types.js";
+
+dotenv.config();
+
+export class AzureSearchTools {
+ private indexClient: SearchIndexClient | null = null;
+ private searchClients: Map> = new Map();
+ private config: AzureSearchConfig;
+
+ constructor(config?: Partial) {
+ this.config = {
+ endpoint: config?.endpoint || process.env.AZURE_SEARCH_ENDPOINT || "",
+ apiKey: config?.apiKey || process.env.AZURE_SEARCH_API_KEY,
+ apiVersion: config?.apiVersion || "2023-11-01",
+ };
+
+ if (!this.config.endpoint) {
+ throw new Error("Azure Search endpoint is required. Set AZURE_SEARCH_ENDPOINT environment variable or provide it in config.");
+ }
+ }
+
+ private getIndexClient(): SearchIndexClient {
+ if (!this.indexClient) {
+ const credential = this.config.apiKey
+ ? new AzureKeyCredential(this.config.apiKey)
+ : new DefaultAzureCredential();
+
+ this.indexClient = new SearchIndexClient(this.config.endpoint, credential);
+ }
+ return this.indexClient;
+ }
+
+ private getSearchClient(indexName: string): SearchClient {
+ if (!this.searchClients.has(indexName)) {
+ const credential = this.config.apiKey
+ ? new AzureKeyCredential(this.config.apiKey)
+ : new DefaultAzureCredential();
+
+ const client = new SearchClient(this.config.endpoint, indexName, credential);
+ this.searchClients.set(indexName, client);
+ }
+ return this.searchClients.get(indexName)!;
+ }
+
+ // Search Operations
+ async searchDocuments(params: {
+ indexName: string;
+ searchText: string;
+ searchMode?: "any" | "all";
+ searchFields?: string[];
+ select?: string[];
+ filter?: string;
+ orderBy?: string[];
+ top?: number;
+ skip?: number;
+ includeTotalCount?: boolean;
+ facets?: string[];
+ highlightFields?: string[];
+ highlightPreTag?: string;
+ highlightPostTag?: string;
+ minimumCoverage?: number;
+ queryType?: "simple" | "full";
+ }): Promise {
+ try {
+ const client = this.getSearchClient(params.indexName);
+
+ const searchOptions: any = {
+ searchMode: params.searchMode,
+ searchFields: params.searchFields,
+ select: params.select,
+ filter: params.filter,
+ orderBy: params.orderBy,
+ top: params.top,
+ skip: params.skip,
+ includeTotalCount: params.includeTotalCount,
+ facets: params.facets,
+ highlightFields: params.highlightFields?.join(','), // Convert array to comma-separated string
+ highlightPreTag: params.highlightPreTag,
+ highlightPostTag: params.highlightPostTag,
+ minimumCoverage: params.minimumCoverage,
+ queryType: params.queryType,
+ };
+
+ const response = await client.search(params.searchText, searchOptions);
+
+ const results = [];
+ for await (const result of response.results) {
+ results.push(result);
+ }
+
+ return {
+ success: true,
+ data: {
+ results,
+ count: response.count,
+ facets: response.facets,
+ coverage: response.coverage,
+ // nextPageParameters: response.nextPageParameters, // Property doesn't exist in current API
+ },
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+
+ async getDocument(params: {
+ indexName: string;
+ key: string;
+ select?: string[];
+ }): Promise {
+ try {
+ const client = this.getSearchClient(params.indexName);
+
+ const result = await client.getDocument(params.key, {
+ selectedFields: params.select,
+ });
+
+ return {
+ success: true,
+ data: result,
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+
+ async suggest(params: {
+ indexName: string;
+ searchText: string;
+ suggesterName: string;
+ fuzzy?: boolean;
+ highlightPreTag?: string;
+ highlightPostTag?: string;
+ minimumCoverage?: number;
+ orderBy?: string[];
+ searchFields?: string[];
+ select?: string[];
+ top?: number;
+ filter?: string;
+ }): Promise {
+ try {
+ const client = this.getSearchClient(params.indexName);
+
+ const response = await client.suggest(params.searchText, params.suggesterName, {
+ useFuzzyMatching: params.fuzzy,
+ highlightPreTag: params.highlightPreTag,
+ highlightPostTag: params.highlightPostTag,
+ minimumCoverage: params.minimumCoverage,
+ orderBy: params.orderBy,
+ searchFields: params.searchFields,
+ select: params.select,
+ top: params.top,
+ filter: params.filter,
+ });
+
+ return {
+ success: true,
+ data: {
+ results: response.results.map(r => ({
+ text: r.text,
+ document: r.document,
+ })),
+ coverage: response.coverage,
+ },
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+
+ async autocomplete(params: {
+ indexName: string;
+ searchText: string;
+ suggesterName: string;
+ autocompleteMode?: "oneTerm" | "twoTerms" | "oneTermWithContext";
+ fuzzy?: boolean;
+ highlightPreTag?: string;
+ highlightPostTag?: string;
+ minimumCoverage?: number;
+ searchFields?: string[];
+ top?: number;
+ filter?: string;
+ }): Promise {
+ try {
+ const client = this.getSearchClient(params.indexName);
+
+ const response = await client.autocomplete(params.searchText, params.suggesterName, {
+ autocompleteMode: params.autocompleteMode,
+ useFuzzyMatching: params.fuzzy,
+ highlightPreTag: params.highlightPreTag,
+ highlightPostTag: params.highlightPostTag,
+ minimumCoverage: params.minimumCoverage,
+ searchFields: params.searchFields,
+ top: params.top,
+ filter: params.filter,
+ });
+
+ return {
+ success: true,
+ data: {
+ results: response.results.map(r => ({
+ text: r.text,
+ queryPlusText: r.queryPlusText,
+ })),
+ coverage: response.coverage,
+ },
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+
+ // Index Management
+ async listIndexes(params?: { select?: string[] }): Promise {
+ try {
+ console.error("=== DEBUG: Starting listIndexes ===");
+ console.error("Config:", {
+ endpoint: this.config.endpoint,
+ hasApiKey: !!this.config.apiKey,
+ apiKeyPrefix: this.config.apiKey?.substring(0, 10) + "..."
+ });
+
+ const client = this.getIndexClient();
+ console.error("=== DEBUG: IndexClient created successfully ===");
+
+ const response = await client.listIndexes();
+ console.error("=== DEBUG: listIndexes response received ===");
+ console.error("Response type:", typeof response);
+ console.error("Response constructor:", response.constructor.name);
+
+ const indexes = [];
+ let count = 0;
+ for await (const index of response) {
+ count++;
+ console.error(`=== DEBUG: Processing index #${count} ===`);
+ console.error("Index type:", typeof index);
+ console.error("Index keys:", Object.keys(index));
+ console.error("Index name:", index.name);
+ console.error("Raw index object:", JSON.stringify(index, null, 2));
+
+ if (params?.select && params.select.length > 0) {
+ const filteredIndex: any = {};
+ for (const field of params.select) {
+ if (field in index) {
+ filteredIndex[field] = (index as any)[field];
+ }
+ }
+ indexes.push(filteredIndex);
+ } else {
+ // Debug: Include raw data in response for troubleshooting
+ const debugInfo = {
+ indexType: typeof index,
+ indexKeys: Object.keys(index),
+ indexName: index.name,
+ indexConstructor: index.constructor?.name
+ };
+
+ // Try multiple approaches to get the data
+ let simplifiedIndex;
+
+ try {
+ // Approach 1: Manual property extraction
+ simplifiedIndex = {
+ _debug: debugInfo,
+ name: index.name || "unknown",
+ etag: index.etag || null,
+ fieldsCount: (index.fields?.length) || 0,
+ fields: index.fields ? index.fields.map((field: any) => ({
+ name: field.name || "unknown",
+ type: field.type || "unknown",
+ key: Boolean(field.key),
+ searchable: Boolean(field.searchable),
+ filterable: Boolean(field.filterable),
+ facetable: Boolean(field.facetable),
+ sortable: Boolean(field.sortable),
+ vectorSearchDimensions: field.vectorSearchDimensions || null
+ })) : [],
+ suggesters: index.suggesters ? index.suggesters.map((s: any) => ({
+ name: s.name || "unknown",
+ searchMode: s.searchMode || null,
+ sourceFields: s.sourceFields || []
+ })) : [],
+ scoringProfiles: index.scoringProfiles ? index.scoringProfiles.map((sp: any) => sp.name || "unknown") : [],
+ hasSemanticSearch: Boolean(index.semanticSearch?.configurations?.length),
+ hasVectorSearch: Boolean(index.vectorSearch?.profiles?.length),
+ corsOptions: index.corsOptions ? {
+ allowedOrigins: index.corsOptions.allowedOrigins || [],
+ maxAgeInSeconds: index.corsOptions.maxAgeInSeconds || 0
+ } : null
+ };
+ } catch (error) {
+ // Fallback: just return basic info
+ simplifiedIndex = {
+ _error: "Failed to parse index object",
+ _debug: debugInfo,
+ _rawIndex: JSON.stringify(index, null, 2).substring(0, 500) + "..."
+ };
+ }
+
+ indexes.push(simplifiedIndex);
+ }
+ }
+
+ console.error(`=== DEBUG: Processed ${count} indexes total ===`);
+ console.error("Final indexes array length:", indexes.length);
+
+ return {
+ success: true,
+ data: indexes,
+ };
+ } catch (error) {
+ console.error("=== DEBUG: Error in listIndexes ===");
+ console.error("Error:", error);
+ console.error("Error message:", error instanceof Error ? error.message : "Unknown error");
+ console.error("Error stack:", error instanceof Error ? error.stack : "No stack");
+
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+
+ async getIndex(indexName: string): Promise {
+ try {
+ const client = this.getIndexClient();
+ const index = await client.getIndex(indexName);
+
+ // Return a clean, serializable version of the index
+ const cleanIndex = JSON.parse(JSON.stringify(index));
+
+ return {
+ success: true,
+ data: cleanIndex,
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+
+ async getIndexStatistics(indexName: string): Promise {
+ try {
+ const client = this.getIndexClient();
+ const stats = await client.getIndexStatistics(indexName);
+
+ return {
+ success: true,
+ data: stats,
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+
+ // Document Management
+ async uploadDocuments(params: {
+ indexName: string;
+ documents: any[];
+ }): Promise {
+ try {
+ const client = this.getSearchClient(params.indexName);
+ const response = await client.uploadDocuments(params.documents);
+
+ return {
+ success: true,
+ data: {
+ results: response.results.map(r => ({
+ key: r.key,
+ status: r.succeeded,
+ errorMessage: r.errorMessage,
+ })),
+ },
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+
+ async mergeDocuments(params: {
+ indexName: string;
+ documents: any[];
+ }): Promise {
+ try {
+ const client = this.getSearchClient(params.indexName);
+ const response = await client.mergeDocuments(params.documents);
+
+ return {
+ success: true,
+ data: {
+ results: response.results.map(r => ({
+ key: r.key,
+ status: r.succeeded,
+ errorMessage: r.errorMessage,
+ })),
+ },
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+
+ async deleteDocuments(params: {
+ indexName: string;
+ keyField: string;
+ keyValues: string[];
+ }): Promise {
+ try {
+ const client = this.getSearchClient(params.indexName);
+
+ // Convert key values to documents for deletion
+ const documentsToDelete = params.keyValues.map(key => ({
+ [params.keyField]: key,
+ }));
+
+ const response = await client.deleteDocuments(documentsToDelete);
+
+ return {
+ success: true,
+ data: {
+ results: response.results.map(r => ({
+ key: r.key,
+ status: r.succeeded,
+ errorMessage: r.errorMessage,
+ })),
+ },
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+
+ // Phase 4: Vector Search Operations
+ async vectorSearch(params: {
+ indexName: string;
+ vectorQueries: VectorQuery[];
+ select?: string[];
+ filter?: string;
+ top?: number;
+ skip?: number;
+ }): Promise {
+ try {
+ const client = this.getSearchClient(params.indexName);
+
+ const searchOptions: any = {
+ vectorQueries: params.vectorQueries.map(vq => ({
+ vector: vq.vector,
+ fields: vq.fields,
+ k: vq.k,
+ exhaustive: vq.exhaustive,
+ })),
+ select: params.select,
+ filter: params.filter,
+ top: params.top,
+ skip: params.skip,
+ };
+
+ const response = await client.search("*", searchOptions);
+
+ const results = [];
+ for await (const result of response.results) {
+ results.push(result);
+ }
+
+ return {
+ success: true,
+ data: {
+ results,
+ count: response.count,
+ },
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+
+ async hybridSearch(params: {
+ indexName: string;
+ searchText: string;
+ vectorQueries: VectorQuery[];
+ searchMode?: "any" | "all";
+ searchFields?: string[];
+ select?: string[];
+ filter?: string;
+ orderBy?: string[];
+ top?: number;
+ skip?: number;
+ queryType?: "simple" | "full";
+ }): Promise {
+ try {
+ const client = this.getSearchClient(params.indexName);
+
+ const searchOptions: any = {
+ searchMode: params.searchMode,
+ searchFields: params.searchFields,
+ vectorQueries: params.vectorQueries.map(vq => ({
+ vector: vq.vector,
+ fields: vq.fields,
+ k: vq.k,
+ exhaustive: vq.exhaustive,
+ })),
+ select: params.select,
+ filter: params.filter,
+ orderBy: params.orderBy,
+ top: params.top,
+ skip: params.skip,
+ queryType: params.queryType,
+ };
+
+ const response = await client.search(params.searchText, searchOptions);
+
+ const results = [];
+ for await (const result of response.results) {
+ results.push(result);
+ }
+
+ return {
+ success: true,
+ data: {
+ results,
+ count: response.count,
+ facets: response.facets,
+ coverage: response.coverage,
+ },
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+
+ // Phase 4: Semantic Search Operations
+ async semanticSearch(params: {
+ indexName: string;
+ searchText: string;
+ semanticConfiguration: string;
+ searchFields?: string[];
+ select?: string[];
+ filter?: string;
+ orderBy?: string[];
+ top?: number;
+ skip?: number;
+ answers?: {
+ answerType: "extractive";
+ count?: number;
+ threshold?: number;
+ };
+ captions?: {
+ captionType: "extractive";
+ maxTextRecordsToProcess?: number;
+ highlight?: boolean;
+ };
+ }): Promise {
+ try {
+ const client = this.getSearchClient(params.indexName);
+
+ const searchOptions: any = {
+ queryType: "semantic",
+ semanticConfiguration: params.semanticConfiguration,
+ searchFields: params.searchFields,
+ select: params.select,
+ filter: params.filter,
+ orderBy: params.orderBy,
+ top: params.top,
+ skip: params.skip,
+ };
+
+ // Add semantic answers if configured
+ if (params.answers) {
+ searchOptions.answers = {
+ answerType: params.answers.answerType,
+ count: params.answers.count,
+ threshold: params.answers.threshold,
+ };
+ }
+
+ // Add semantic captions if configured
+ if (params.captions) {
+ searchOptions.captions = {
+ captionType: params.captions.captionType,
+ maxTextRecordsToProcess: params.captions.maxTextRecordsToProcess,
+ highlight: params.captions.highlight,
+ };
+ }
+
+ const response = await client.search(params.searchText, searchOptions);
+
+ const results = [];
+ for await (const result of response.results) {
+ results.push(result);
+ }
+
+ return {
+ success: true,
+ data: {
+ results,
+ count: response.count,
+ answers: (response as any).answers?.map((answer: any) => ({
+ key: answer.key || "",
+ text: answer.text || "",
+ highlights: answer.highlights || "",
+ score: answer.score || 0,
+ })),
+ captions: (response as any).captions?.map((caption: any) => ({
+ text: caption.text || "",
+ highlights: caption.highlights || "",
+ })),
+ },
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error occurred",
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/azure-ai-search/manual-test.js b/azure-ai-search/manual-test.js
new file mode 100644
index 0000000..e9f850f
--- /dev/null
+++ b/azure-ai-search/manual-test.js
@@ -0,0 +1,106 @@
+#!/usr/bin/env node
+
+// Test manuel simple pour Phase 4
+import dotenv from 'dotenv';
+import { AzureSearchTools } from './lib/azure-search-client.js';
+
+dotenv.config();
+
+const tools = new AzureSearchTools();
+const indexName = "rag-1753386801239";
+
+console.log("🚀 Test Phase 4 - Elite Dangerous RAG");
+console.log("=====================================\n");
+
+// Test 1: Recherche classique Thargoids
+console.log("📖 Test 1: Recherche classique 'thargoid'");
+try {
+ const result = await tools.searchDocuments({
+ indexName,
+ searchText: "thargoid",
+ top: 2,
+ highlightFields: ["chunk", "title"]
+ });
+
+ if (result.success) {
+ console.log(`✅ Trouvé ${result.data.results.length} résultats`);
+ if (result.data.results.length > 0) {
+ const first = result.data.results[0];
+ console.log(`📄 Premier: "${first.document?.title || 'Sans titre'}" (score: ${first.score || 'N/A'})`);
+ }
+ } else {
+ console.log("❌ Erreur:", result.error);
+ }
+} catch (error) {
+ console.log("❌ Exception:", error.message);
+}
+
+console.log("\n" + "=".repeat(50));
+
+// Test 2: Recherche vectorielle avec un vecteur simulé
+console.log("🔍 Test 2: Vector Search (simulé)");
+try {
+ // Vecteur aléatoire pour test (en production il faudrait un vrai embedding)
+ const dummyVector = Array(1536).fill(0).map(() => Math.random() * 0.001);
+
+ const result = await tools.vectorSearch({
+ indexName,
+ vectorQueries: [{
+ vector: dummyVector,
+ fields: "text_vector",
+ k: 2
+ }]
+ });
+
+ if (result.success) {
+ console.log(`✅ Vector search OK: ${result.data.results.length} résultats`);
+ if (result.data.results.length > 0) {
+ const first = result.data.results[0];
+ console.log(`📄 Premier: "${first.document?.title || 'Sans titre'}" (score: ${first.score || 'N/A'})`);
+ }
+ } else {
+ console.log("❌ Vector search erreur:", result.error);
+ }
+} catch (error) {
+ console.log("❌ Vector search exception:", error.message);
+}
+
+console.log("\n" + "=".repeat(50));
+
+// Test 3: Recherche sémantique
+console.log("🧠 Test 3: Semantic Search");
+try {
+ const result = await tools.semanticSearch({
+ indexName,
+ searchText: "Comment combattre les Thargoids efficacement ?",
+ semanticConfiguration: "rag-1753386801239-semantic-configuration",
+ answers: {
+ answerType: "extractive",
+ count: 2,
+ threshold: 0.6
+ },
+ captions: {
+ captionType: "extractive",
+ highlight: true
+ },
+ top: 3
+ });
+
+ if (result.success) {
+ console.log(`✅ Semantic search OK: ${result.data.results.length} résultats`);
+ console.log(`📝 Réponses extraites: ${result.data.answers?.length || 0}`);
+ console.log(`💬 Captions: ${result.data.captions?.length || 0}`);
+
+ // Afficher la première réponse si disponible
+ if (result.data.answers && result.data.answers.length > 0) {
+ const answer = result.data.answers[0];
+ console.log(`🎯 Première réponse (score ${answer.score}): ${answer.text.substring(0, 100)}...`);
+ }
+ } else {
+ console.log("❌ Semantic search erreur:", result.error);
+ }
+} catch (error) {
+ console.log("❌ Semantic search exception:", error.message);
+}
+
+console.log("\n✅ Tests Phase 4 terminés !");
\ No newline at end of file
diff --git a/azure-ai-search/package.json b/azure-ai-search/package.json
new file mode 100644
index 0000000..4cc105a
--- /dev/null
+++ b/azure-ai-search/package.json
@@ -0,0 +1,72 @@
+{
+ "name": "@ignitionai/azure-ai-search-mcp",
+ "version": "1.0.0",
+ "description": "Complete Azure AI Search MCP server",
+ "type": "module",
+ "bin": {
+ "azure-ai-search-mcp": "dist/server.js"
+ },
+ "main": "dist/server.js",
+ "scripts": {
+ "build": "rollup -c",
+ "start": "node --loader ts-node/esm server.ts",
+ "start:prod": "node dist/server.js",
+ "inspect": "npx @modelcontextprotocol/inspector node dist/server.js",
+ "prepublishOnly": "pnpm build",
+ "test": "echo \"No tests yet\" && exit 0"
+ },
+ "keywords": [
+ "azure",
+ "ai",
+ "search",
+ "rag",
+ "mcp",
+ "model-context-protocol",
+ "claude",
+ "ai",
+ "database",
+ "nosql",
+ "crud",
+ "batch-operations",
+ "schema-validation",
+ "typescript"
+ ],
+ "author": "Salim Laimeche ",
+ "license": "MIT",
+ "homepage": "https://github.com/IgnitionAI/azure-ai-search-mcp#readme",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/IgnitionAI/azure-ai-search-mcp.git"
+ },
+ "bugs": {
+ "url": "https://github.com/IgnitionAI/azure-ai-search-mcp/issues"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "files": [
+ "dist",
+ "README.md",
+ "CLAUDE.md",
+ "LICENSE"
+ ],
+ "dependencies": {
+ "@azure/identity": "^4.10.2",
+ "@azure/search-documents": "^12.1.0",
+ "@modelcontextprotocol/sdk": "^1.12.1",
+ "dotenv": "^16.5.0",
+ "zod": "^3.25.42"
+ },
+ "devDependencies": {
+ "@rollup/plugin-commonjs": "^28.0.3",
+ "@rollup/plugin-json": "^6.1.0",
+ "@rollup/plugin-node-resolve": "^16.0.1",
+ "@rollup/plugin-typescript": "^12.1.2",
+ "rollup": "^4.42.0",
+ "rollup-plugin-preserve-shebang": "^1.0.1",
+ "ts-node": "^10.9.1",
+ "tslib": "^2.8.1",
+ "typescript": "^5.0.0"
+ },
+ "packageManager": "pnpm@10.11.1+sha512.e519b9f7639869dc8d5c3c5dfef73b3f091094b0a006d7317353c72b124e80e1afd429732e28705ad6bfa1ee879c1fce46c128ccebd3192101f43dd67c667912"
+}
diff --git a/azure-ai-search/pnpm-lock.yaml b/azure-ai-search/pnpm-lock.yaml
new file mode 100644
index 0000000..a8422a1
--- /dev/null
+++ b/azure-ai-search/pnpm-lock.yaml
@@ -0,0 +1,1724 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ '@azure/identity':
+ specifier: ^4.10.2
+ version: 4.10.2
+ '@azure/search-documents':
+ specifier: ^12.1.0
+ version: 12.1.0
+ '@modelcontextprotocol/sdk':
+ specifier: ^1.12.1
+ version: 1.16.0
+ dotenv:
+ specifier: ^16.5.0
+ version: 16.6.1
+ zod:
+ specifier: ^3.25.42
+ version: 3.25.76
+ devDependencies:
+ '@rollup/plugin-commonjs':
+ specifier: ^28.0.3
+ version: 28.0.6(rollup@4.45.1)
+ '@rollup/plugin-json':
+ specifier: ^6.1.0
+ version: 6.1.0(rollup@4.45.1)
+ '@rollup/plugin-node-resolve':
+ specifier: ^16.0.1
+ version: 16.0.1(rollup@4.45.1)
+ '@rollup/plugin-typescript':
+ specifier: ^12.1.2
+ version: 12.1.4(rollup@4.45.1)(tslib@2.8.1)(typescript@5.8.3)
+ rollup:
+ specifier: ^4.42.0
+ version: 4.45.1
+ rollup-plugin-preserve-shebang:
+ specifier: ^1.0.1
+ version: 1.0.1
+ ts-node:
+ specifier: ^10.9.1
+ version: 10.9.2(@types/node@24.1.0)(typescript@5.8.3)
+ tslib:
+ specifier: ^2.8.1
+ version: 2.8.1
+ typescript:
+ specifier: ^5.0.0
+ version: 5.8.3
+
+packages:
+
+ '@azure/abort-controller@2.1.2':
+ resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==}
+ engines: {node: '>=18.0.0'}
+
+ '@azure/core-auth@1.10.0':
+ resolution: {integrity: sha512-88Djs5vBvGbHQHf5ZZcaoNHo6Y8BKZkt3cw2iuJIQzLEgH4Ox6Tm4hjFhbqOxyYsgIG/eJbFEHpxRIfEEWv5Ow==}
+ engines: {node: '>=20.0.0'}
+
+ '@azure/core-client@1.10.0':
+ resolution: {integrity: sha512-O4aP3CLFNodg8eTHXECaH3B3CjicfzkxVtnrfLkOq0XNP7TIECGfHpK/C6vADZkWP75wzmdBnsIA8ksuJMk18g==}
+ engines: {node: '>=20.0.0'}
+
+ '@azure/core-http-compat@2.3.0':
+ resolution: {integrity: sha512-qLQujmUypBBG0gxHd0j6/Jdmul6ttl24c8WGiLXIk7IHXdBlfoBqW27hyz3Xn6xbfdyVSarl1Ttbk0AwnZBYCw==}
+ engines: {node: '>=18.0.0'}
+
+ '@azure/core-paging@1.6.2':
+ resolution: {integrity: sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==}
+ engines: {node: '>=18.0.0'}
+
+ '@azure/core-rest-pipeline@1.22.0':
+ resolution: {integrity: sha512-OKHmb3/Kpm06HypvB3g6Q3zJuvyXcpxDpCS1PnU8OV6AJgSFaee/covXBcPbWc6XDDxtEPlbi3EMQ6nUiPaQtw==}
+ engines: {node: '>=20.0.0'}
+
+ '@azure/core-tracing@1.3.0':
+ resolution: {integrity: sha512-+XvmZLLWPe67WXNZo9Oc9CrPj/Tm8QnHR92fFAFdnbzwNdCH1h+7UdpaQgRSBsMY+oW1kHXNUZQLdZ1gHX3ROw==}
+ engines: {node: '>=20.0.0'}
+
+ '@azure/core-util@1.13.0':
+ resolution: {integrity: sha512-o0psW8QWQ58fq3i24Q1K2XfS/jYTxr7O1HRcyUE9bV9NttLU+kYOH82Ixj8DGlMTOWgxm1Sss2QAfKK5UkSPxw==}
+ engines: {node: '>=20.0.0'}
+
+ '@azure/identity@4.10.2':
+ resolution: {integrity: sha512-Uth4vz0j+fkXCkbvutChUj03PDCokjbC6Wk9JT8hHEUtpy/EurNKAseb3+gO6Zi9VYBvwt61pgbzn1ovk942Qg==}
+ engines: {node: '>=20.0.0'}
+
+ '@azure/logger@1.3.0':
+ resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==}
+ engines: {node: '>=20.0.0'}
+
+ '@azure/msal-browser@4.16.0':
+ resolution: {integrity: sha512-yF8gqyq7tVnYftnrWaNaxWpqhGQXoXpDfwBtL7UCGlIbDMQ1PUJF/T2xCL6NyDNHoO70qp1xU8GjjYTyNIefkw==}
+ engines: {node: '>=0.8.0'}
+
+ '@azure/msal-common@15.9.0':
+ resolution: {integrity: sha512-lbz/D+C9ixUG3hiZzBLjU79a0+5ZXCorjel3mwXluisKNH0/rOS/ajm8yi4yI9RP5Uc70CAcs9Ipd0051Oh/kA==}
+ engines: {node: '>=0.8.0'}
+
+ '@azure/msal-node@3.6.4':
+ resolution: {integrity: sha512-jMeut9UQugcmq7aPWWlJKhJIse4DQ594zc/JaP6BIxg55XaX3aM/jcPuIQ4ryHnI4QSf03wUspy/uqAvjWKbOg==}
+ engines: {node: '>=16'}
+
+ '@azure/search-documents@12.1.0':
+ resolution: {integrity: sha512-IzD+hfqGqFtXymHXm4RzrZW2MsSH2M7RLmZsKaKVi7SUxbeYTUeX+ALk8gVzkM8ykb7EzlDLWCNErKfAa57rYQ==}
+ engines: {node: '>=18.0.0'}
+
+ '@cspotcode/source-map-support@0.8.1':
+ resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
+ engines: {node: '>=12'}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.4':
+ resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==}
+
+ '@jridgewell/trace-mapping@0.3.9':
+ resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
+
+ '@modelcontextprotocol/sdk@1.16.0':
+ resolution: {integrity: sha512-8ofX7gkZcLj9H9rSd50mCgm3SSF8C7XoclxJuLoV0Cz3rEQ1tv9MZRYYvJtm9n1BiEQQMzSmE/w2AEkNacLYfg==}
+ engines: {node: '>=18'}
+
+ '@rollup/plugin-commonjs@28.0.6':
+ resolution: {integrity: sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==}
+ engines: {node: '>=16.0.0 || 14 >= 14.17'}
+ peerDependencies:
+ rollup: ^2.68.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
+ '@rollup/plugin-json@6.1.0':
+ resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
+ '@rollup/plugin-node-resolve@16.0.1':
+ resolution: {integrity: sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^2.78.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
+ '@rollup/plugin-typescript@12.1.4':
+ resolution: {integrity: sha512-s5Hx+EtN60LMlDBvl5f04bEiFZmAepk27Q+mr85L/00zPDn1jtzlTV6FWn81MaIwqfWzKxmOJrBWHU6vtQyedQ==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^2.14.0||^3.0.0||^4.0.0
+ tslib: '*'
+ typescript: '>=3.7.0'
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+ tslib:
+ optional: true
+
+ '@rollup/pluginutils@5.2.0':
+ resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
+ '@rollup/rollup-android-arm-eabi@4.45.1':
+ resolution: {integrity: sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.45.1':
+ resolution: {integrity: sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.45.1':
+ resolution: {integrity: sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.45.1':
+ resolution: {integrity: sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.45.1':
+ resolution: {integrity: sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.45.1':
+ resolution: {integrity: sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.45.1':
+ resolution: {integrity: sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.45.1':
+ resolution: {integrity: sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.45.1':
+ resolution: {integrity: sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-musl@4.45.1':
+ resolution: {integrity: sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.45.1':
+ resolution: {integrity: sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.45.1':
+ resolution: {integrity: sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.45.1':
+ resolution: {integrity: sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-musl@4.45.1':
+ resolution: {integrity: sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.45.1':
+ resolution: {integrity: sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-gnu@4.45.1':
+ resolution: {integrity: sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-musl@4.45.1':
+ resolution: {integrity: sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-win32-arm64-msvc@4.45.1':
+ resolution: {integrity: sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.45.1':
+ resolution: {integrity: sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.45.1':
+ resolution: {integrity: sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@tsconfig/node10@1.0.11':
+ resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
+
+ '@tsconfig/node12@1.0.11':
+ resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
+
+ '@tsconfig/node14@1.0.3':
+ resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
+
+ '@tsconfig/node16@1.0.4':
+ resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
+
+ '@types/estree@1.0.8':
+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+
+ '@types/node@24.1.0':
+ resolution: {integrity: sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==}
+
+ '@types/resolve@1.20.2':
+ resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
+
+ '@typespec/ts-http-runtime@0.3.0':
+ resolution: {integrity: sha512-sOx1PKSuFwnIl7z4RN0Ls7N9AQawmR9r66eI5rFCzLDIs8HTIYrIpH9QjYWoX0lkgGrkLxXhi4QnK7MizPRrIg==}
+ engines: {node: '>=20.0.0'}
+
+ accepts@2.0.0:
+ resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
+ engines: {node: '>= 0.6'}
+
+ acorn-walk@8.3.4:
+ resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
+ engines: {node: '>=0.4.0'}
+
+ acorn@8.15.0:
+ resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ agent-base@7.1.4:
+ resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
+ engines: {node: '>= 14'}
+
+ ajv@6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+
+ arg@4.1.3:
+ resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
+
+ body-parser@2.2.0:
+ resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==}
+ engines: {node: '>=18'}
+
+ buffer-equal-constant-time@1.0.1:
+ resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
+
+ bundle-name@4.1.0:
+ resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
+ engines: {node: '>=18'}
+
+ bytes@3.1.2:
+ resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
+ engines: {node: '>= 0.8'}
+
+ call-bind-apply-helpers@1.0.2:
+ resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
+ engines: {node: '>= 0.4'}
+
+ call-bound@1.0.4:
+ resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
+ engines: {node: '>= 0.4'}
+
+ commondir@1.0.1:
+ resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
+
+ content-disposition@1.0.0:
+ resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==}
+ engines: {node: '>= 0.6'}
+
+ content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
+
+ cookie-signature@1.2.2:
+ resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
+ engines: {node: '>=6.6.0'}
+
+ cookie@0.7.2:
+ resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
+ engines: {node: '>= 0.6'}
+
+ cors@2.8.5:
+ resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
+ engines: {node: '>= 0.10'}
+
+ create-require@1.1.1:
+ resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
+
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+ engines: {node: '>= 8'}
+
+ debug@4.4.1:
+ resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ deepmerge@4.3.1:
+ resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
+ engines: {node: '>=0.10.0'}
+
+ default-browser-id@5.0.0:
+ resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==}
+ engines: {node: '>=18'}
+
+ default-browser@5.2.1:
+ resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==}
+ engines: {node: '>=18'}
+
+ define-lazy-prop@3.0.0:
+ resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
+ engines: {node: '>=12'}
+
+ depd@2.0.0:
+ resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+ engines: {node: '>= 0.8'}
+
+ diff@4.0.2:
+ resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
+ engines: {node: '>=0.3.1'}
+
+ dotenv@16.6.1:
+ resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
+ engines: {node: '>=12'}
+
+ dunder-proto@1.0.1:
+ resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
+ engines: {node: '>= 0.4'}
+
+ ecdsa-sig-formatter@1.0.11:
+ resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
+
+ ee-first@1.1.1:
+ resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+
+ encodeurl@2.0.0:
+ resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
+ engines: {node: '>= 0.8'}
+
+ es-define-property@1.0.1:
+ resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ es-object-atoms@1.1.1:
+ resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
+ engines: {node: '>= 0.4'}
+
+ escape-html@1.0.3:
+ resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+
+ estree-walker@2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+ etag@1.8.1:
+ resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
+ engines: {node: '>= 0.6'}
+
+ events@3.3.0:
+ resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
+ engines: {node: '>=0.8.x'}
+
+ eventsource-parser@3.0.3:
+ resolution: {integrity: sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA==}
+ engines: {node: '>=20.0.0'}
+
+ eventsource@3.0.7:
+ resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
+ engines: {node: '>=18.0.0'}
+
+ express-rate-limit@7.5.1:
+ resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==}
+ engines: {node: '>= 16'}
+ peerDependencies:
+ express: '>= 4.11'
+
+ express@5.1.0:
+ resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==}
+ engines: {node: '>= 18'}
+
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+ fdir@6.4.6:
+ resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ finalhandler@2.1.0:
+ resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==}
+ engines: {node: '>= 0.8'}
+
+ forwarded@0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+
+ fresh@2.0.0:
+ resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
+ engines: {node: '>= 0.8'}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ get-intrinsic@1.3.0:
+ resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
+ engines: {node: '>= 0.4'}
+
+ get-proto@1.0.1:
+ resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+ engines: {node: '>= 0.4'}
+
+ gopd@1.2.0:
+ resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
+ engines: {node: '>= 0.4'}
+
+ has-symbols@1.1.0:
+ resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+ engines: {node: '>= 0.4'}
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ http-errors@2.0.0:
+ resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
+ engines: {node: '>= 0.8'}
+
+ http-proxy-agent@7.0.2:
+ resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
+ engines: {node: '>= 14'}
+
+ https-proxy-agent@7.0.6:
+ resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
+ engines: {node: '>= 14'}
+
+ iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+
+ inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ ipaddr.js@1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+
+ is-core-module@2.16.1:
+ resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
+ engines: {node: '>= 0.4'}
+
+ is-docker@3.0.0:
+ resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ hasBin: true
+
+ is-inside-container@1.0.0:
+ resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
+ engines: {node: '>=14.16'}
+ hasBin: true
+
+ is-module@1.0.0:
+ resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
+
+ is-promise@4.0.0:
+ resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
+
+ is-reference@1.2.1:
+ resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
+
+ is-wsl@3.1.0:
+ resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==}
+ engines: {node: '>=16'}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+ jsonwebtoken@9.0.2:
+ resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
+ engines: {node: '>=12', npm: '>=6'}
+
+ jwa@1.4.2:
+ resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==}
+
+ jws@3.2.2:
+ resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
+
+ lodash.includes@4.3.0:
+ resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
+
+ lodash.isboolean@3.0.3:
+ resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
+
+ lodash.isinteger@4.0.4:
+ resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
+
+ lodash.isnumber@3.0.3:
+ resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
+
+ lodash.isplainobject@4.0.6:
+ resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
+
+ lodash.isstring@4.0.1:
+ resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
+
+ lodash.once@4.1.1:
+ resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
+
+ magic-string@0.25.9:
+ resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
+
+ magic-string@0.30.17:
+ resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+
+ make-error@1.3.6:
+ resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
+
+ math-intrinsics@1.1.0:
+ resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
+ engines: {node: '>= 0.4'}
+
+ media-typer@1.1.0:
+ resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
+ engines: {node: '>= 0.8'}
+
+ merge-descriptors@2.0.0:
+ resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
+ engines: {node: '>=18'}
+
+ mime-db@1.54.0:
+ resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@3.0.1:
+ resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==}
+ engines: {node: '>= 0.6'}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ negotiator@1.0.0:
+ resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
+ engines: {node: '>= 0.6'}
+
+ object-assign@4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+
+ object-inspect@1.13.4:
+ resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
+ engines: {node: '>= 0.4'}
+
+ on-finished@2.4.1:
+ resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
+ engines: {node: '>= 0.8'}
+
+ once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+
+ open@10.2.0:
+ resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==}
+ engines: {node: '>=18'}
+
+ parseurl@1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ path-to-regexp@8.2.0:
+ resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
+ engines: {node: '>=16'}
+
+ picomatch@4.0.3:
+ resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
+ engines: {node: '>=12'}
+
+ pkce-challenge@5.0.0:
+ resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==}
+ engines: {node: '>=16.20.0'}
+
+ proxy-addr@2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+
+ punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+
+ qs@6.14.0:
+ resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
+ engines: {node: '>=0.6'}
+
+ range-parser@1.2.1:
+ resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+ engines: {node: '>= 0.6'}
+
+ raw-body@3.0.0:
+ resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==}
+ engines: {node: '>= 0.8'}
+
+ resolve@1.22.10:
+ resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
+ engines: {node: '>= 0.4'}
+ hasBin: true
+
+ rollup-plugin-preserve-shebang@1.0.1:
+ resolution: {integrity: sha512-gk7ExGBqvUinhgrvldKHkAKXXwRkWMXMZymNkrtn50uBgHITlhRjhnKmbNGwAIc4Bzgl3yLv7/8Fhi/XeHhFKg==}
+
+ rollup@4.45.1:
+ resolution: {integrity: sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ router@2.2.0:
+ resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
+ engines: {node: '>= 18'}
+
+ run-applescript@7.0.0:
+ resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==}
+ engines: {node: '>=18'}
+
+ safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+ semver@7.7.2:
+ resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ send@1.2.0:
+ resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==}
+ engines: {node: '>= 18'}
+
+ serve-static@2.2.0:
+ resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
+ engines: {node: '>= 18'}
+
+ setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ side-channel-list@1.0.0:
+ resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-map@1.0.1:
+ resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-weakmap@1.0.2:
+ resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
+ engines: {node: '>= 0.4'}
+
+ side-channel@1.1.0:
+ resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
+ engines: {node: '>= 0.4'}
+
+ sourcemap-codec@1.4.8:
+ resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
+ deprecated: Please use @jridgewell/sourcemap-codec instead
+
+ statuses@2.0.1:
+ resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
+ engines: {node: '>= 0.8'}
+
+ statuses@2.0.2:
+ resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
+ engines: {node: '>= 0.8'}
+
+ supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
+ toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+
+ ts-node@10.9.2:
+ resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
+ hasBin: true
+ peerDependencies:
+ '@swc/core': '>=1.2.50'
+ '@swc/wasm': '>=1.2.50'
+ '@types/node': '*'
+ typescript: '>=2.7'
+ peerDependenciesMeta:
+ '@swc/core':
+ optional: true
+ '@swc/wasm':
+ optional: true
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ type-is@2.0.1:
+ resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
+ engines: {node: '>= 0.6'}
+
+ typescript@5.8.3:
+ resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ undici-types@7.8.0:
+ resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==}
+
+ unpipe@1.0.0:
+ resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
+ engines: {node: '>= 0.8'}
+
+ uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+ uuid@8.3.2:
+ resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
+ hasBin: true
+
+ v8-compile-cache-lib@3.0.1:
+ resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
+
+ vary@1.1.2:
+ resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+ engines: {node: '>= 0.8'}
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+ wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+ wsl-utils@0.1.0:
+ resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==}
+ engines: {node: '>=18'}
+
+ yn@3.1.1:
+ resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
+ engines: {node: '>=6'}
+
+ zod-to-json-schema@3.24.6:
+ resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==}
+ peerDependencies:
+ zod: ^3.24.1
+
+ zod@3.25.76:
+ resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
+
+snapshots:
+
+ '@azure/abort-controller@2.1.2':
+ dependencies:
+ tslib: 2.8.1
+
+ '@azure/core-auth@1.10.0':
+ dependencies:
+ '@azure/abort-controller': 2.1.2
+ '@azure/core-util': 1.13.0
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@azure/core-client@1.10.0':
+ dependencies:
+ '@azure/abort-controller': 2.1.2
+ '@azure/core-auth': 1.10.0
+ '@azure/core-rest-pipeline': 1.22.0
+ '@azure/core-tracing': 1.3.0
+ '@azure/core-util': 1.13.0
+ '@azure/logger': 1.3.0
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@azure/core-http-compat@2.3.0':
+ dependencies:
+ '@azure/abort-controller': 2.1.2
+ '@azure/core-client': 1.10.0
+ '@azure/core-rest-pipeline': 1.22.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@azure/core-paging@1.6.2':
+ dependencies:
+ tslib: 2.8.1
+
+ '@azure/core-rest-pipeline@1.22.0':
+ dependencies:
+ '@azure/abort-controller': 2.1.2
+ '@azure/core-auth': 1.10.0
+ '@azure/core-tracing': 1.3.0
+ '@azure/core-util': 1.13.0
+ '@azure/logger': 1.3.0
+ '@typespec/ts-http-runtime': 0.3.0
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@azure/core-tracing@1.3.0':
+ dependencies:
+ tslib: 2.8.1
+
+ '@azure/core-util@1.13.0':
+ dependencies:
+ '@azure/abort-controller': 2.1.2
+ '@typespec/ts-http-runtime': 0.3.0
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@azure/identity@4.10.2':
+ dependencies:
+ '@azure/abort-controller': 2.1.2
+ '@azure/core-auth': 1.10.0
+ '@azure/core-client': 1.10.0
+ '@azure/core-rest-pipeline': 1.22.0
+ '@azure/core-tracing': 1.3.0
+ '@azure/core-util': 1.13.0
+ '@azure/logger': 1.3.0
+ '@azure/msal-browser': 4.16.0
+ '@azure/msal-node': 3.6.4
+ open: 10.2.0
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@azure/logger@1.3.0':
+ dependencies:
+ '@typespec/ts-http-runtime': 0.3.0
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@azure/msal-browser@4.16.0':
+ dependencies:
+ '@azure/msal-common': 15.9.0
+
+ '@azure/msal-common@15.9.0': {}
+
+ '@azure/msal-node@3.6.4':
+ dependencies:
+ '@azure/msal-common': 15.9.0
+ jsonwebtoken: 9.0.2
+ uuid: 8.3.2
+
+ '@azure/search-documents@12.1.0':
+ dependencies:
+ '@azure/core-auth': 1.10.0
+ '@azure/core-client': 1.10.0
+ '@azure/core-http-compat': 2.3.0
+ '@azure/core-paging': 1.6.2
+ '@azure/core-rest-pipeline': 1.22.0
+ '@azure/core-tracing': 1.3.0
+ '@azure/core-util': 1.13.0
+ '@azure/logger': 1.3.0
+ events: 3.3.0
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@cspotcode/source-map-support@0.8.1':
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.9
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.4': {}
+
+ '@jridgewell/trace-mapping@0.3.9':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.4
+
+ '@modelcontextprotocol/sdk@1.16.0':
+ dependencies:
+ ajv: 6.12.6
+ content-type: 1.0.5
+ cors: 2.8.5
+ cross-spawn: 7.0.6
+ eventsource: 3.0.7
+ eventsource-parser: 3.0.3
+ express: 5.1.0
+ express-rate-limit: 7.5.1(express@5.1.0)
+ pkce-challenge: 5.0.0
+ raw-body: 3.0.0
+ zod: 3.25.76
+ zod-to-json-schema: 3.24.6(zod@3.25.76)
+ transitivePeerDependencies:
+ - supports-color
+
+ '@rollup/plugin-commonjs@28.0.6(rollup@4.45.1)':
+ dependencies:
+ '@rollup/pluginutils': 5.2.0(rollup@4.45.1)
+ commondir: 1.0.1
+ estree-walker: 2.0.2
+ fdir: 6.4.6(picomatch@4.0.3)
+ is-reference: 1.2.1
+ magic-string: 0.30.17
+ picomatch: 4.0.3
+ optionalDependencies:
+ rollup: 4.45.1
+
+ '@rollup/plugin-json@6.1.0(rollup@4.45.1)':
+ dependencies:
+ '@rollup/pluginutils': 5.2.0(rollup@4.45.1)
+ optionalDependencies:
+ rollup: 4.45.1
+
+ '@rollup/plugin-node-resolve@16.0.1(rollup@4.45.1)':
+ dependencies:
+ '@rollup/pluginutils': 5.2.0(rollup@4.45.1)
+ '@types/resolve': 1.20.2
+ deepmerge: 4.3.1
+ is-module: 1.0.0
+ resolve: 1.22.10
+ optionalDependencies:
+ rollup: 4.45.1
+
+ '@rollup/plugin-typescript@12.1.4(rollup@4.45.1)(tslib@2.8.1)(typescript@5.8.3)':
+ dependencies:
+ '@rollup/pluginutils': 5.2.0(rollup@4.45.1)
+ resolve: 1.22.10
+ typescript: 5.8.3
+ optionalDependencies:
+ rollup: 4.45.1
+ tslib: 2.8.1
+
+ '@rollup/pluginutils@5.2.0(rollup@4.45.1)':
+ dependencies:
+ '@types/estree': 1.0.8
+ estree-walker: 2.0.2
+ picomatch: 4.0.3
+ optionalDependencies:
+ rollup: 4.45.1
+
+ '@rollup/rollup-android-arm-eabi@4.45.1':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.45.1':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.45.1':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.45.1':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.45.1':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.45.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.45.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.45.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.45.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.45.1':
+ optional: true
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.45.1':
+ optional: true
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.45.1':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.45.1':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.45.1':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.45.1':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.45.1':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.45.1':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.45.1':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.45.1':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.45.1':
+ optional: true
+
+ '@tsconfig/node10@1.0.11': {}
+
+ '@tsconfig/node12@1.0.11': {}
+
+ '@tsconfig/node14@1.0.3': {}
+
+ '@tsconfig/node16@1.0.4': {}
+
+ '@types/estree@1.0.8': {}
+
+ '@types/node@24.1.0':
+ dependencies:
+ undici-types: 7.8.0
+
+ '@types/resolve@1.20.2': {}
+
+ '@typespec/ts-http-runtime@0.3.0':
+ dependencies:
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - supports-color
+
+ accepts@2.0.0:
+ dependencies:
+ mime-types: 3.0.1
+ negotiator: 1.0.0
+
+ acorn-walk@8.3.4:
+ dependencies:
+ acorn: 8.15.0
+
+ acorn@8.15.0: {}
+
+ agent-base@7.1.4: {}
+
+ ajv@6.12.6:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+
+ arg@4.1.3: {}
+
+ body-parser@2.2.0:
+ dependencies:
+ bytes: 3.1.2
+ content-type: 1.0.5
+ debug: 4.4.1
+ http-errors: 2.0.0
+ iconv-lite: 0.6.3
+ on-finished: 2.4.1
+ qs: 6.14.0
+ raw-body: 3.0.0
+ type-is: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
+ buffer-equal-constant-time@1.0.1: {}
+
+ bundle-name@4.1.0:
+ dependencies:
+ run-applescript: 7.0.0
+
+ bytes@3.1.2: {}
+
+ call-bind-apply-helpers@1.0.2:
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+
+ call-bound@1.0.4:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ get-intrinsic: 1.3.0
+
+ commondir@1.0.1: {}
+
+ content-disposition@1.0.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ content-type@1.0.5: {}
+
+ cookie-signature@1.2.2: {}
+
+ cookie@0.7.2: {}
+
+ cors@2.8.5:
+ dependencies:
+ object-assign: 4.1.1
+ vary: 1.1.2
+
+ create-require@1.1.1: {}
+
+ cross-spawn@7.0.6:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ debug@4.4.1:
+ dependencies:
+ ms: 2.1.3
+
+ deepmerge@4.3.1: {}
+
+ default-browser-id@5.0.0: {}
+
+ default-browser@5.2.1:
+ dependencies:
+ bundle-name: 4.1.0
+ default-browser-id: 5.0.0
+
+ define-lazy-prop@3.0.0: {}
+
+ depd@2.0.0: {}
+
+ diff@4.0.2: {}
+
+ dotenv@16.6.1: {}
+
+ dunder-proto@1.0.1:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-errors: 1.3.0
+ gopd: 1.2.0
+
+ ecdsa-sig-formatter@1.0.11:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ ee-first@1.1.1: {}
+
+ encodeurl@2.0.0: {}
+
+ es-define-property@1.0.1: {}
+
+ es-errors@1.3.0: {}
+
+ es-object-atoms@1.1.1:
+ dependencies:
+ es-errors: 1.3.0
+
+ escape-html@1.0.3: {}
+
+ estree-walker@2.0.2: {}
+
+ etag@1.8.1: {}
+
+ events@3.3.0: {}
+
+ eventsource-parser@3.0.3: {}
+
+ eventsource@3.0.7:
+ dependencies:
+ eventsource-parser: 3.0.3
+
+ express-rate-limit@7.5.1(express@5.1.0):
+ dependencies:
+ express: 5.1.0
+
+ express@5.1.0:
+ dependencies:
+ accepts: 2.0.0
+ body-parser: 2.2.0
+ content-disposition: 1.0.0
+ content-type: 1.0.5
+ cookie: 0.7.2
+ cookie-signature: 1.2.2
+ debug: 4.4.1
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ finalhandler: 2.1.0
+ fresh: 2.0.0
+ http-errors: 2.0.0
+ merge-descriptors: 2.0.0
+ mime-types: 3.0.1
+ on-finished: 2.4.1
+ once: 1.4.0
+ parseurl: 1.3.3
+ proxy-addr: 2.0.7
+ qs: 6.14.0
+ range-parser: 1.2.1
+ router: 2.2.0
+ send: 1.2.0
+ serve-static: 2.2.0
+ statuses: 2.0.2
+ type-is: 2.0.1
+ vary: 1.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ fast-deep-equal@3.1.3: {}
+
+ fast-json-stable-stringify@2.1.0: {}
+
+ fdir@6.4.6(picomatch@4.0.3):
+ optionalDependencies:
+ picomatch: 4.0.3
+
+ finalhandler@2.1.0:
+ dependencies:
+ debug: 4.4.1
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ statuses: 2.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ forwarded@0.2.0: {}
+
+ fresh@2.0.0: {}
+
+ fsevents@2.3.3:
+ optional: true
+
+ function-bind@1.1.2: {}
+
+ get-intrinsic@1.3.0:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ function-bind: 1.1.2
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-symbols: 1.1.0
+ hasown: 2.0.2
+ math-intrinsics: 1.1.0
+
+ get-proto@1.0.1:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-object-atoms: 1.1.1
+
+ gopd@1.2.0: {}
+
+ has-symbols@1.1.0: {}
+
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ http-errors@2.0.0:
+ dependencies:
+ depd: 2.0.0
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 2.0.1
+ toidentifier: 1.0.1
+
+ http-proxy-agent@7.0.2:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.1
+ transitivePeerDependencies:
+ - supports-color
+
+ https-proxy-agent@7.0.6:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.1
+ transitivePeerDependencies:
+ - supports-color
+
+ iconv-lite@0.6.3:
+ dependencies:
+ safer-buffer: 2.1.2
+
+ inherits@2.0.4: {}
+
+ ipaddr.js@1.9.1: {}
+
+ is-core-module@2.16.1:
+ dependencies:
+ hasown: 2.0.2
+
+ is-docker@3.0.0: {}
+
+ is-inside-container@1.0.0:
+ dependencies:
+ is-docker: 3.0.0
+
+ is-module@1.0.0: {}
+
+ is-promise@4.0.0: {}
+
+ is-reference@1.2.1:
+ dependencies:
+ '@types/estree': 1.0.8
+
+ is-wsl@3.1.0:
+ dependencies:
+ is-inside-container: 1.0.0
+
+ isexe@2.0.0: {}
+
+ json-schema-traverse@0.4.1: {}
+
+ jsonwebtoken@9.0.2:
+ dependencies:
+ jws: 3.2.2
+ lodash.includes: 4.3.0
+ lodash.isboolean: 3.0.3
+ lodash.isinteger: 4.0.4
+ lodash.isnumber: 3.0.3
+ lodash.isplainobject: 4.0.6
+ lodash.isstring: 4.0.1
+ lodash.once: 4.1.1
+ ms: 2.1.3
+ semver: 7.7.2
+
+ jwa@1.4.2:
+ dependencies:
+ buffer-equal-constant-time: 1.0.1
+ ecdsa-sig-formatter: 1.0.11
+ safe-buffer: 5.2.1
+
+ jws@3.2.2:
+ dependencies:
+ jwa: 1.4.2
+ safe-buffer: 5.2.1
+
+ lodash.includes@4.3.0: {}
+
+ lodash.isboolean@3.0.3: {}
+
+ lodash.isinteger@4.0.4: {}
+
+ lodash.isnumber@3.0.3: {}
+
+ lodash.isplainobject@4.0.6: {}
+
+ lodash.isstring@4.0.1: {}
+
+ lodash.once@4.1.1: {}
+
+ magic-string@0.25.9:
+ dependencies:
+ sourcemap-codec: 1.4.8
+
+ magic-string@0.30.17:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.4
+
+ make-error@1.3.6: {}
+
+ math-intrinsics@1.1.0: {}
+
+ media-typer@1.1.0: {}
+
+ merge-descriptors@2.0.0: {}
+
+ mime-db@1.54.0: {}
+
+ mime-types@3.0.1:
+ dependencies:
+ mime-db: 1.54.0
+
+ ms@2.1.3: {}
+
+ negotiator@1.0.0: {}
+
+ object-assign@4.1.1: {}
+
+ object-inspect@1.13.4: {}
+
+ on-finished@2.4.1:
+ dependencies:
+ ee-first: 1.1.1
+
+ once@1.4.0:
+ dependencies:
+ wrappy: 1.0.2
+
+ open@10.2.0:
+ dependencies:
+ default-browser: 5.2.1
+ define-lazy-prop: 3.0.0
+ is-inside-container: 1.0.0
+ wsl-utils: 0.1.0
+
+ parseurl@1.3.3: {}
+
+ path-key@3.1.1: {}
+
+ path-parse@1.0.7: {}
+
+ path-to-regexp@8.2.0: {}
+
+ picomatch@4.0.3: {}
+
+ pkce-challenge@5.0.0: {}
+
+ proxy-addr@2.0.7:
+ dependencies:
+ forwarded: 0.2.0
+ ipaddr.js: 1.9.1
+
+ punycode@2.3.1: {}
+
+ qs@6.14.0:
+ dependencies:
+ side-channel: 1.1.0
+
+ range-parser@1.2.1: {}
+
+ raw-body@3.0.0:
+ dependencies:
+ bytes: 3.1.2
+ http-errors: 2.0.0
+ iconv-lite: 0.6.3
+ unpipe: 1.0.0
+
+ resolve@1.22.10:
+ dependencies:
+ is-core-module: 2.16.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
+ rollup-plugin-preserve-shebang@1.0.1:
+ dependencies:
+ magic-string: 0.25.9
+
+ rollup@4.45.1:
+ dependencies:
+ '@types/estree': 1.0.8
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.45.1
+ '@rollup/rollup-android-arm64': 4.45.1
+ '@rollup/rollup-darwin-arm64': 4.45.1
+ '@rollup/rollup-darwin-x64': 4.45.1
+ '@rollup/rollup-freebsd-arm64': 4.45.1
+ '@rollup/rollup-freebsd-x64': 4.45.1
+ '@rollup/rollup-linux-arm-gnueabihf': 4.45.1
+ '@rollup/rollup-linux-arm-musleabihf': 4.45.1
+ '@rollup/rollup-linux-arm64-gnu': 4.45.1
+ '@rollup/rollup-linux-arm64-musl': 4.45.1
+ '@rollup/rollup-linux-loongarch64-gnu': 4.45.1
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.45.1
+ '@rollup/rollup-linux-riscv64-gnu': 4.45.1
+ '@rollup/rollup-linux-riscv64-musl': 4.45.1
+ '@rollup/rollup-linux-s390x-gnu': 4.45.1
+ '@rollup/rollup-linux-x64-gnu': 4.45.1
+ '@rollup/rollup-linux-x64-musl': 4.45.1
+ '@rollup/rollup-win32-arm64-msvc': 4.45.1
+ '@rollup/rollup-win32-ia32-msvc': 4.45.1
+ '@rollup/rollup-win32-x64-msvc': 4.45.1
+ fsevents: 2.3.3
+
+ router@2.2.0:
+ dependencies:
+ debug: 4.4.1
+ depd: 2.0.0
+ is-promise: 4.0.0
+ parseurl: 1.3.3
+ path-to-regexp: 8.2.0
+ transitivePeerDependencies:
+ - supports-color
+
+ run-applescript@7.0.0: {}
+
+ safe-buffer@5.2.1: {}
+
+ safer-buffer@2.1.2: {}
+
+ semver@7.7.2: {}
+
+ send@1.2.0:
+ dependencies:
+ debug: 4.4.1
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ fresh: 2.0.0
+ http-errors: 2.0.0
+ mime-types: 3.0.1
+ ms: 2.1.3
+ on-finished: 2.4.1
+ range-parser: 1.2.1
+ statuses: 2.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ serve-static@2.2.0:
+ dependencies:
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ parseurl: 1.3.3
+ send: 1.2.0
+ transitivePeerDependencies:
+ - supports-color
+
+ setprototypeof@1.2.0: {}
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ side-channel-list@1.0.0:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+
+ side-channel-map@1.0.1:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+
+ side-channel-weakmap@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-map: 1.0.1
+
+ side-channel@1.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-list: 1.0.0
+ side-channel-map: 1.0.1
+ side-channel-weakmap: 1.0.2
+
+ sourcemap-codec@1.4.8: {}
+
+ statuses@2.0.1: {}
+
+ statuses@2.0.2: {}
+
+ supports-preserve-symlinks-flag@1.0.0: {}
+
+ toidentifier@1.0.1: {}
+
+ ts-node@10.9.2(@types/node@24.1.0)(typescript@5.8.3):
+ dependencies:
+ '@cspotcode/source-map-support': 0.8.1
+ '@tsconfig/node10': 1.0.11
+ '@tsconfig/node12': 1.0.11
+ '@tsconfig/node14': 1.0.3
+ '@tsconfig/node16': 1.0.4
+ '@types/node': 24.1.0
+ acorn: 8.15.0
+ acorn-walk: 8.3.4
+ arg: 4.1.3
+ create-require: 1.1.1
+ diff: 4.0.2
+ make-error: 1.3.6
+ typescript: 5.8.3
+ v8-compile-cache-lib: 3.0.1
+ yn: 3.1.1
+
+ tslib@2.8.1: {}
+
+ type-is@2.0.1:
+ dependencies:
+ content-type: 1.0.5
+ media-typer: 1.1.0
+ mime-types: 3.0.1
+
+ typescript@5.8.3: {}
+
+ undici-types@7.8.0: {}
+
+ unpipe@1.0.0: {}
+
+ uri-js@4.4.1:
+ dependencies:
+ punycode: 2.3.1
+
+ uuid@8.3.2: {}
+
+ v8-compile-cache-lib@3.0.1: {}
+
+ vary@1.1.2: {}
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
+ wrappy@1.0.2: {}
+
+ wsl-utils@0.1.0:
+ dependencies:
+ is-wsl: 3.1.0
+
+ yn@3.1.1: {}
+
+ zod-to-json-schema@3.24.6(zod@3.25.76):
+ dependencies:
+ zod: 3.25.76
+
+ zod@3.25.76: {}
diff --git a/azure-ai-search/quick-test.mjs b/azure-ai-search/quick-test.mjs
new file mode 100644
index 0000000..c2c8cdf
--- /dev/null
+++ b/azure-ai-search/quick-test.mjs
@@ -0,0 +1,64 @@
+// Test simple avec MCP Client
+import { Client } from '@modelcontextprotocol/sdk/client/index.js';
+import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
+import { spawn } from 'child_process';
+
+console.log("🚀 Test rapide Phase 4 - Elite Dangerous");
+
+const serverProcess = spawn('node', ['dist/server.js'], {
+ stdio: ['pipe', 'pipe', 'inherit'],
+});
+
+const transport = new StdioClientTransport({
+ process: serverProcess,
+});
+
+const client = new Client(
+ { name: 'test-client', version: '1.0.0' },
+ { capabilities: {} }
+);
+
+try {
+ await client.connect(transport);
+ console.log("✅ Connecté au serveur MCP");
+
+ // Test 1: Search classique
+ console.log("\n📖 Test search-documents...");
+ const searchResult = await client.request(
+ { method: 'tools/call' },
+ {
+ name: 'search-documents',
+ arguments: {
+ indexName: 'rag-1753386801239',
+ searchText: 'thargoid',
+ top: 2
+ }
+ }
+ );
+ console.log("Résultat search:", searchResult.content[0].text.substring(0, 200) + "...");
+
+ // Test 2: Semantic search
+ console.log("\n🧠 Test semantic-search...");
+ const semanticResult = await client.request(
+ { method: 'tools/call' },
+ {
+ name: 'semantic-search',
+ arguments: {
+ indexName: 'rag-1753386801239',
+ searchText: 'Comment combattre les Thargoids ?',
+ semanticConfiguration: 'rag-1753386801239-semantic-configuration',
+ answers: { count: 2, threshold: 0.6 },
+ top: 3
+ }
+ }
+ );
+ console.log("Résultat semantic:", semanticResult.content[0].text.substring(0, 200) + "...");
+
+ console.log("\n✅ Tests terminés avec succès !");
+
+} catch (error) {
+ console.error("❌ Erreur:", error.message);
+} finally {
+ await client.close();
+ serverProcess.kill();
+}
\ No newline at end of file
diff --git a/azure-ai-search/resources/index-resources.ts b/azure-ai-search/resources/index-resources.ts
new file mode 100644
index 0000000..99dced8
--- /dev/null
+++ b/azure-ai-search/resources/index-resources.ts
@@ -0,0 +1,103 @@
+import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { getAzureSearchTools } from "../tools/search-tools.js";
+
+export class AzureSearchIndexResources {
+ constructor(
+ private server: McpServer,
+ private searchTools: ReturnType
+ ) {}
+
+ async registerDynamicResources() {
+ try {
+ // Get list of available indexes
+ const indexesResult = await this.searchTools.listIndexes();
+
+ if (!indexesResult.success || !indexesResult.data) {
+ console.error("Failed to fetch indexes for resource registration:", indexesResult.error);
+ return;
+ }
+
+ const indexes = indexesResult.data;
+ console.error(`Registering resources for ${indexes.length} indexes`);
+
+ // Register a resource for the indexes list
+ this.server.resource(
+ "indexes-list",
+ new ResourceTemplate("azure-search://indexes", { list: undefined }),
+ async () => ({
+ contents: [
+ {
+ type: "text",
+ text: JSON.stringify(indexes, null, 2),
+ },
+ ],
+ })
+ );
+
+ // Register individual index resources
+ for (const index of indexes) {
+ const indexName = index.name;
+
+ // Resource for index schema
+ this.server.resource(
+ `index-schema-${indexName}`,
+ new ResourceTemplate(`azure-search://index/${indexName}/schema`, { list: undefined }),
+ async () => {
+ const schemaResult = await this.searchTools.getIndex(indexName);
+ return {
+ contents: [
+ {
+ type: "text",
+ text: JSON.stringify(schemaResult, null, 2),
+ },
+ ],
+ };
+ }
+ );
+
+ // Resource for index statistics
+ this.server.resource(
+ `index-stats-${indexName}`,
+ new ResourceTemplate(`azure-search://index/${indexName}/statistics`, { list: undefined }),
+ async () => {
+ const statsResult = await this.searchTools.getIndexStatistics(indexName);
+ return {
+ contents: [
+ {
+ type: "text",
+ text: JSON.stringify(statsResult, null, 2),
+ },
+ ],
+ };
+ }
+ );
+
+ // Resource for sample documents from the index
+ this.server.resource(
+ `index-sample-${indexName}`,
+ new ResourceTemplate(`azure-search://index/${indexName}/sample`, { list: undefined }),
+ async () => {
+ const searchResult = await this.searchTools.searchDocuments({
+ indexName,
+ searchText: "*",
+ top: 5, // Get first 5 documents as sample
+ });
+ return {
+ contents: [
+ {
+ type: "text",
+ text: JSON.stringify(searchResult, null, 2),
+ },
+ ],
+ };
+ }
+ );
+ }
+
+ console.error(`Successfully registered ${indexes.length * 3 + 1} resources`);
+
+ } catch (error) {
+ console.error("Error registering dynamic resources:", error);
+ }
+ }
+}
\ No newline at end of file
diff --git a/azure-ai-search/rollup.config.js b/azure-ai-search/rollup.config.js
new file mode 100644
index 0000000..49a0ad6
--- /dev/null
+++ b/azure-ai-search/rollup.config.js
@@ -0,0 +1,28 @@
+import resolve from '@rollup/plugin-node-resolve';
+import commonjs from '@rollup/plugin-commonjs';
+import typescript from '@rollup/plugin-typescript';
+import json from '@rollup/plugin-json';
+import shebang from 'rollup-plugin-preserve-shebang';
+
+export default {
+ input: 'server.ts',
+ output: {
+ dir: 'dist',
+ format: 'esm',
+ entryFileNames: 'server.js'
+ },
+ plugins: [
+ shebang(), // <- pour le #!/usr/bin/env node
+ resolve(),
+ commonjs(),
+ json(),
+ typescript({ tsconfig: './tsconfig.json' })
+ ],
+ external: [
+ "@modelcontextprotocol/sdk",
+ "@azure/search-documents",
+ "@azure/identity",
+ "zod",
+ "dotenv",
+ ]
+};
diff --git a/azure-ai-search/server.ts b/azure-ai-search/server.ts
new file mode 100644
index 0000000..c73dba6
--- /dev/null
+++ b/azure-ai-search/server.ts
@@ -0,0 +1,475 @@
+#!/usr/bin/env node
+import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
+import dotenv from "dotenv";
+import {
+ SearchDocumentsSchema,
+ GetDocumentSchema,
+ SuggestSchema,
+ AutocompleteSchema,
+ ListIndexesSchema,
+ GetIndexSchema,
+ GetIndexStatisticsSchema,
+ UploadDocumentsSchema,
+ MergeDocumentsSchema,
+ DeleteDocumentsSchema,
+ VectorSearchSchema,
+ HybridSearchSchema,
+ SemanticSearchSchema,
+} from "./types.js";
+import {
+ searchDocuments,
+ getDocument,
+ suggest,
+ autocomplete,
+} from "./tools/search-tools.js";
+import {
+ listIndexes,
+ getIndexSchema,
+ getIndexStatistics,
+} from "./tools/index-tools.js";
+import {
+ uploadDocuments,
+ mergeDocuments,
+ deleteDocuments,
+} from "./tools/document-tools.js";
+import {
+ vectorSearch,
+ hybridSearch,
+ semanticSearch,
+} from "./tools/vector-tools.js";
+import { getAzureSearchTools } from "./tools/search-tools.js";
+import { AzureSearchIndexResources } from "./resources/index-resources.js";
+
+dotenv.config();
+
+// Create server instance
+const server = new McpServer({
+ name: "AzureAISearchMCP",
+ version: "1.0.0",
+ description: "MCP server for interacting with Azure AI Search"
+});
+
+// Register search tools
+server.tool(
+ "search-documents",
+ "Search documents in an Azure AI Search index with comprehensive filtering and faceting options",
+ SearchDocumentsSchema.shape,
+ async (params) => {
+ try {
+ const result = await searchDocuments(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error searching documents: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+server.tool(
+ "get-document",
+ "Retrieve a specific document by its key from an Azure AI Search index",
+ GetDocumentSchema.shape,
+ async (params) => {
+ try {
+ const result = await getDocument(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error retrieving document: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+server.tool(
+ "suggest",
+ "Get search suggestions using a configured suggester in Azure AI Search",
+ SuggestSchema.shape,
+ async (params) => {
+ try {
+ const result = await suggest(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error getting suggestions: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+server.tool(
+ "autocomplete",
+ "Get autocomplete suggestions for partial search terms using Azure AI Search",
+ AutocompleteSchema.shape,
+ async (params) => {
+ try {
+ const result = await autocomplete(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error getting autocomplete: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+// Register index management tools
+server.tool(
+ "list-indexes",
+ "List all available search indexes in the Azure AI Search service",
+ ListIndexesSchema.shape,
+ async (params) => {
+ try {
+ const result = await listIndexes(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error listing indexes: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+server.tool(
+ "get-index-schema",
+ "Get the schema definition of a specific search index including fields, analyzers, and configuration",
+ GetIndexSchema.shape,
+ async (params) => {
+ try {
+ const result = await getIndexSchema(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error getting index schema: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+server.tool(
+ "get-index-statistics",
+ "Get statistics and usage information for a specific search index",
+ GetIndexStatisticsSchema.shape,
+ async (params) => {
+ try {
+ const result = await getIndexStatistics(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error getting index statistics: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+// Register document management tools
+server.tool(
+ "upload-documents",
+ "Upload new documents to an Azure AI Search index. Documents will be added or updated if they already exist.",
+ UploadDocumentsSchema.shape,
+ async (params) => {
+ try {
+ const result = await uploadDocuments(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error uploading documents: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+server.tool(
+ "merge-documents",
+ "Merge or update existing documents in an Azure AI Search index. Only provided fields will be updated.",
+ MergeDocumentsSchema.shape,
+ async (params) => {
+ try {
+ const result = await mergeDocuments(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error merging documents: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+server.tool(
+ "delete-documents",
+ "Delete documents from an Azure AI Search index by their key values.",
+ DeleteDocumentsSchema.shape,
+ async (params) => {
+ try {
+ const result = await deleteDocuments(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error deleting documents: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+// Register vector and semantic search tools (Phase 4)
+server.tool(
+ "vector-search",
+ "Perform pure vector similarity search using k-nearest neighbors on vector fields in Azure AI Search",
+ VectorSearchSchema.shape,
+ async (params) => {
+ try {
+ const result = await vectorSearch(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error in vector search: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+server.tool(
+ "hybrid-search",
+ "Perform hybrid search combining traditional text search with vector similarity search for enhanced relevance",
+ HybridSearchSchema.shape,
+ async (params) => {
+ try {
+ const result = await hybridSearch(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error in hybrid search: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+server.tool(
+ "semantic-search",
+ "Perform semantic search using Azure AI Search semantic capabilities with answers and captions",
+ SemanticSearchSchema.shape,
+ async (params) => {
+ try {
+ const result = await semanticSearch(params);
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(result, null, 2),
+ },
+ ],
+ isError: !result.success,
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error in semantic search: ${error instanceof Error ? error.message : "Unknown error"}`,
+ },
+ ],
+ isError: true,
+ };
+ }
+ }
+);
+
+// Start the server
+async function main() {
+ // Register dynamic resources for discovered indexes
+ const searchTools = getAzureSearchTools();
+ const indexResourceManager = new AzureSearchIndexResources(server, searchTools);
+ await indexResourceManager.registerDynamicResources();
+
+ const transport = new StdioServerTransport();
+ await server.connect(transport);
+ console.error("Azure AI Search MCP Server running on stdio");
+}
+
+main().catch((error) => {
+ console.error("Fatal error in main():", error);
+ process.exit(1);
+});
diff --git a/azure-ai-search/test-phase4.js b/azure-ai-search/test-phase4.js
new file mode 100644
index 0000000..89a3517
--- /dev/null
+++ b/azure-ai-search/test-phase4.js
@@ -0,0 +1,82 @@
+#!/usr/bin/env node
+
+// Test script pour les nouvelles fonctionnalités Phase 4
+// Vector Search et Semantic Search sur l'index Elite Dangerous
+
+import { searchDocuments } from './dist/tools/search-tools.js';
+import { vectorSearch, semanticSearch } from './dist/tools/vector-tools.js';
+
+const indexName = "rag-1753386801239";
+
+console.log("🚀 Test Phase 4 - Vector & Semantic Search sur Elite Dangerous RAG");
+console.log("================================================================\n");
+
+// Test 1: Recherche classique sur les Thargoids
+console.log("📖 Test 1: Recherche classique - 'thargoid combat'");
+try {
+ const classicResult = await searchDocuments({
+ indexName,
+ searchText: "thargoid combat",
+ top: 3,
+ highlightFields: ["chunk", "title"]
+ });
+
+ console.log("Résultats:", classicResult.success ? classicResult.data.results.length : "Erreur");
+ if (classicResult.success && classicResult.data.results.length > 0) {
+ console.log("Premier résultat:", classicResult.data.results[0]?.document?.title || "N/A");
+ }
+ console.log("---");
+} catch (error) {
+ console.log("Erreur test 1:", error.message);
+}
+
+// Test 2: Recherche vectorielle pure (nécessite un vrai embedding)
+console.log("🔍 Test 2: Vector Search - simulation");
+try {
+ // Vector simulé - en vrai il faudrait un embedding d'OpenAI pour "thargoid combat"
+ const dummyVector = Array(1536).fill(0).map(() => Math.random() * 0.1);
+
+ const vectorResult = await vectorSearch({
+ indexName,
+ vectorQueries: [{
+ vector: dummyVector,
+ fields: "text_vector",
+ k: 3
+ }],
+ top: 3
+ });
+
+ console.log("Résultats vector:", vectorResult.success ? "OK" : vectorResult.error);
+} catch (error) {
+ console.log("Erreur test 2:", error.message);
+}
+
+// Test 3: Recherche sémantique avec réponses
+console.log("🧠 Test 3: Semantic Search avec réponses");
+try {
+ const semanticResult = await semanticSearch({
+ indexName,
+ searchText: "Comment combattre efficacement les Thargoids dans Elite Dangerous ?",
+ semanticConfiguration: "rag-1753386801239-semantic-configuration",
+ answers: {
+ answerType: "extractive",
+ count: 2,
+ threshold: 0.6
+ },
+ captions: {
+ captionType: "extractive",
+ highlight: true
+ },
+ top: 5
+ });
+
+ console.log("Résultats semantic:", semanticResult.success ? "OK" : semanticResult.error);
+ if (semanticResult.success) {
+ console.log("Réponses trouvées:", semanticResult.data?.answers?.length || 0);
+ console.log("Captions trouvées:", semanticResult.data?.captions?.length || 0);
+ }
+} catch (error) {
+ console.log("Erreur test 3:", error.message);
+}
+
+console.log("\n✅ Tests Phase 4 terminés !");
\ No newline at end of file
diff --git a/azure-ai-search/tools/document-tools.ts b/azure-ai-search/tools/document-tools.ts
new file mode 100644
index 0000000..fd70fbd
--- /dev/null
+++ b/azure-ai-search/tools/document-tools.ts
@@ -0,0 +1,109 @@
+import {
+ UploadDocumentsSchema,
+ MergeDocumentsSchema,
+ DeleteDocumentsSchema,
+} from "../types.js";
+
+// Reuse the same singleton instance
+import { getAzureSearchTools } from "./search-tools.js";
+
+export async function uploadDocuments(params: any) {
+ try {
+ console.error("=== DEBUG uploadDocuments tool: params received ===", {
+ indexName: params.indexName,
+ documentsCount: params.documents?.length,
+ firstDocKeys: params.documents?.[0] ? Object.keys(params.documents[0]) : []
+ });
+
+ const validatedParams = UploadDocumentsSchema.parse(params);
+ console.error("=== DEBUG uploadDocuments tool: validated params ===", {
+ indexName: validatedParams.indexName,
+ documentsCount: validatedParams.documents.length
+ });
+
+ const tools = getAzureSearchTools();
+ const result = await tools.uploadDocuments(validatedParams as any);
+
+ console.error("=== DEBUG uploadDocuments tool: result ===", {
+ success: result.success,
+ resultsCount: result.data?.results?.length,
+ error: result.error
+ });
+
+ return result;
+ } catch (error) {
+ console.error("=== DEBUG uploadDocuments tool: error ===", error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error in uploadDocuments tool"
+ };
+ }
+}
+
+export async function mergeDocuments(params: any) {
+ try {
+ console.error("=== DEBUG mergeDocuments tool: params received ===", {
+ indexName: params.indexName,
+ documentsCount: params.documents?.length,
+ firstDocKeys: params.documents?.[0] ? Object.keys(params.documents[0]) : []
+ });
+
+ const validatedParams = MergeDocumentsSchema.parse(params);
+ console.error("=== DEBUG mergeDocuments tool: validated params ===", {
+ indexName: validatedParams.indexName,
+ documentsCount: validatedParams.documents.length
+ });
+
+ const tools = getAzureSearchTools();
+ const result = await tools.mergeDocuments(validatedParams as any);
+
+ console.error("=== DEBUG mergeDocuments tool: result ===", {
+ success: result.success,
+ resultsCount: result.data?.results?.length,
+ error: result.error
+ });
+
+ return result;
+ } catch (error) {
+ console.error("=== DEBUG mergeDocuments tool: error ===", error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error in mergeDocuments tool"
+ };
+ }
+}
+
+export async function deleteDocuments(params: any) {
+ try {
+ console.error("=== DEBUG deleteDocuments tool: params received ===", {
+ indexName: params.indexName,
+ keyField: params.keyField,
+ keyValuesCount: params.keyValues?.length,
+ keyValues: params.keyValues
+ });
+
+ const validatedParams = DeleteDocumentsSchema.parse(params);
+ console.error("=== DEBUG deleteDocuments tool: validated params ===", {
+ indexName: validatedParams.indexName,
+ keyField: validatedParams.keyField,
+ keyValuesCount: validatedParams.keyValues.length
+ });
+
+ const tools = getAzureSearchTools();
+ const result = await tools.deleteDocuments(validatedParams as any);
+
+ console.error("=== DEBUG deleteDocuments tool: result ===", {
+ success: result.success,
+ resultsCount: result.data?.results?.length,
+ error: result.error
+ });
+
+ return result;
+ } catch (error) {
+ console.error("=== DEBUG deleteDocuments tool: error ===", error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error in deleteDocuments tool"
+ };
+ }
+}
\ No newline at end of file
diff --git a/azure-ai-search/tools/index-tools.ts b/azure-ai-search/tools/index-tools.ts
new file mode 100644
index 0000000..2c84677
--- /dev/null
+++ b/azure-ai-search/tools/index-tools.ts
@@ -0,0 +1,47 @@
+import {
+ ListIndexesSchema,
+ GetIndexSchema,
+ GetIndexStatisticsSchema,
+} from "../types.js";
+
+// Reuse the same singleton instance
+import { getAzureSearchTools } from "./search-tools.js";
+
+export async function listIndexes(params: any) {
+ try {
+ console.error("=== DEBUG listIndexes tool: params received ===", params);
+
+ // Handle empty params case
+ const validatedParams = params ? ListIndexesSchema.parse(params) : {};
+ console.error("=== DEBUG listIndexes tool: validated params ===", validatedParams);
+
+ const tools = getAzureSearchTools();
+ const result = await tools.listIndexes(validatedParams as any);
+
+ console.error("=== DEBUG listIndexes tool: result ===", {
+ success: result.success,
+ dataLength: result.data?.length,
+ error: result.error
+ });
+
+ return result;
+ } catch (error) {
+ console.error("=== DEBUG listIndexes tool: error ===", error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error in listIndexes tool"
+ };
+ }
+}
+
+export async function getIndexSchema(params: any) {
+ const validatedParams = GetIndexSchema.parse(params);
+ const tools = getAzureSearchTools();
+ return await tools.getIndex(validatedParams.indexName);
+}
+
+export async function getIndexStatistics(params: any) {
+ const validatedParams = GetIndexStatisticsSchema.parse(params);
+ const tools = getAzureSearchTools();
+ return await tools.getIndexStatistics(validatedParams.indexName);
+}
\ No newline at end of file
diff --git a/azure-ai-search/tools/search-tools.ts b/azure-ai-search/tools/search-tools.ts
new file mode 100644
index 0000000..8934b3a
--- /dev/null
+++ b/azure-ai-search/tools/search-tools.ts
@@ -0,0 +1,41 @@
+import { AzureSearchTools } from "../lib/azure-search-client.js";
+import {
+ SearchDocumentsSchema,
+ GetDocumentSchema,
+ SuggestSchema,
+ AutocompleteSchema,
+} from "../types.js";
+
+// Singleton instance with lazy loading
+let azureSearchTools: AzureSearchTools | null = null;
+
+export function getAzureSearchTools(): AzureSearchTools {
+ if (!azureSearchTools) {
+ azureSearchTools = new AzureSearchTools();
+ }
+ return azureSearchTools;
+}
+
+export async function searchDocuments(params: any) {
+ const validatedParams = SearchDocumentsSchema.parse(params);
+ const tools = getAzureSearchTools();
+ return await tools.searchDocuments(validatedParams as any);
+}
+
+export async function getDocument(params: any) {
+ const validatedParams = GetDocumentSchema.parse(params);
+ const tools = getAzureSearchTools();
+ return await tools.getDocument(validatedParams as any);
+}
+
+export async function suggest(params: any) {
+ const validatedParams = SuggestSchema.parse(params);
+ const tools = getAzureSearchTools();
+ return await tools.suggest(validatedParams as any);
+}
+
+export async function autocomplete(params: any) {
+ const validatedParams = AutocompleteSchema.parse(params);
+ const tools = getAzureSearchTools();
+ return await tools.autocomplete(validatedParams as any);
+}
\ No newline at end of file
diff --git a/azure-ai-search/tools/vector-tools.ts b/azure-ai-search/tools/vector-tools.ts
new file mode 100644
index 0000000..9925948
--- /dev/null
+++ b/azure-ai-search/tools/vector-tools.ts
@@ -0,0 +1,50 @@
+import {
+ VectorSearchSchema,
+ HybridSearchSchema,
+ SemanticSearchSchema,
+} from "../types.js";
+
+// Reuse the same singleton instance
+import { getAzureSearchTools } from "./search-tools.js";
+
+export async function vectorSearch(params: any) {
+ try {
+ const validatedParams = VectorSearchSchema.parse(params);
+ const tools = getAzureSearchTools();
+ const result = await tools.vectorSearch(validatedParams as any);
+ return result;
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error in vectorSearch tool"
+ };
+ }
+}
+
+export async function hybridSearch(params: any) {
+ try {
+ const validatedParams = HybridSearchSchema.parse(params);
+ const tools = getAzureSearchTools();
+ const result = await tools.hybridSearch(validatedParams as any);
+ return result;
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error in hybridSearch tool"
+ };
+ }
+}
+
+export async function semanticSearch(params: any) {
+ try {
+ const validatedParams = SemanticSearchSchema.parse(params);
+ const tools = getAzureSearchTools();
+ const result = await tools.semanticSearch(validatedParams as any);
+ return result;
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "Unknown error in semanticSearch tool"
+ };
+ }
+}
\ No newline at end of file
diff --git a/azure-ai-search/tsconfig.json b/azure-ai-search/tsconfig.json
new file mode 100644
index 0000000..c026f96
--- /dev/null
+++ b/azure-ai-search/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "compilerOptions": {
+ "outDir": "./dist",
+ "module": "ESNext",
+ "target": "ES2020",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "declaration": true,
+ "skipLibCheck": true,
+ "sourceMap": false,
+ "removeComments": false
+ },
+ "include": ["server.ts", "tools/**/*.ts", "resources/**/*.ts", "prompts/**/*.ts", "types.ts"]
+ }
+
\ No newline at end of file
diff --git a/azure-ai-search/types.ts b/azure-ai-search/types.ts
new file mode 100644
index 0000000..a71d8b0
--- /dev/null
+++ b/azure-ai-search/types.ts
@@ -0,0 +1,270 @@
+import { z } from "zod";
+
+// Azure AI Search Configuration
+export const AzureSearchConfigSchema = z.object({
+ endpoint: z.string().url().describe("Azure Search service endpoint"),
+ apiKey: z.string().optional().describe("Azure Search API key"),
+ apiVersion: z.string().optional().default("2023-11-01").describe("Azure Search API version"),
+});
+
+export type AzureSearchConfig = z.infer;
+
+// Search Query Parameters
+export const SearchDocumentsSchema = z.object({
+ indexName: z.string().min(1).describe("Name of the search index"),
+ searchText: z.string().describe("Text to search for (use '*' for all documents)"),
+ searchMode: z.enum(["any", "all"]).optional().default("any").describe("Search mode: any (OR) or all (AND)"),
+ searchFields: z.array(z.string()).optional().describe("Fields to search in"),
+ select: z.array(z.string()).optional().describe("Fields to include in results"),
+ filter: z.string().optional().describe("OData filter expression"),
+ orderBy: z.array(z.string()).optional().describe("Sort order (field asc/desc)"),
+ top: z.number().min(1).max(1000).optional().default(50).describe("Number of results to return (1-1000)"),
+ skip: z.number().min(0).optional().describe("Number of results to skip"),
+ includeTotalCount: z.boolean().optional().default(false).describe("Include total count in response"),
+ facets: z.array(z.string()).optional().describe("Facet fields"),
+ highlightFields: z.array(z.string()).optional().describe("Fields to highlight"),
+ highlightPreTag: z.string().optional().default("").describe("Pre-tag for highlighting"),
+ highlightPostTag: z.string().optional().default("").describe("Post-tag for highlighting"),
+ minimumCoverage: z.number().min(0).max(100).optional().describe("Minimum coverage percentage"),
+ queryType: z.enum(["simple", "full"]).optional().default("simple").describe("Query type: simple or full (Lucene)"),
+});
+
+export type SearchDocumentsParams = z.infer;
+
+// Get Document Parameters
+export const GetDocumentSchema = z.object({
+ indexName: z.string().min(1).describe("Name of the search index"),
+ key: z.string().describe("Document key"),
+ select: z.array(z.string()).optional().describe("Fields to include in result"),
+});
+
+export type GetDocumentParams = z.infer;
+
+// Suggest Parameters
+export const SuggestSchema = z.object({
+ indexName: z.string().min(1).describe("Name of the search index"),
+ searchText: z.string().describe("Text to get suggestions for"),
+ suggesterName: z.string().describe("Name of the suggester to use"),
+ fuzzy: z.boolean().optional().default(false).describe("Enable fuzzy matching"),
+ highlightPreTag: z.string().optional().default("").describe("Pre-tag for highlighting"),
+ highlightPostTag: z.string().optional().default("").describe("Post-tag for highlighting"),
+ minimumCoverage: z.number().min(0).max(100).optional().describe("Minimum coverage percentage"),
+ orderBy: z.array(z.string()).optional().describe("Sort order"),
+ searchFields: z.array(z.string()).optional().describe("Fields to search in"),
+ select: z.array(z.string()).optional().describe("Fields to include in results"),
+ top: z.number().min(1).max(100).optional().default(5).describe("Number of suggestions to return"),
+ filter: z.string().optional().describe("OData filter expression"),
+});
+
+export type SuggestParams = z.infer;
+
+// Autocomplete Parameters
+export const AutocompleteSchema = z.object({
+ indexName: z.string().min(1).describe("Name of the search index"),
+ searchText: z.string().describe("Text to autocomplete"),
+ suggesterName: z.string().describe("Name of the suggester to use"),
+ autocompleteMode: z.enum(["oneTerm", "twoTerms", "oneTermWithContext"]).optional().default("oneTerm").describe("Autocomplete mode"),
+ fuzzy: z.boolean().optional().default(false).describe("Enable fuzzy matching"),
+ highlightPreTag: z.string().optional().default("").describe("Pre-tag for highlighting"),
+ highlightPostTag: z.string().optional().default("").describe("Post-tag for highlighting"),
+ minimumCoverage: z.number().min(0).max(100).optional().describe("Minimum coverage percentage"),
+ searchFields: z.array(z.string()).optional().describe("Fields to search in"),
+ top: z.number().min(1).max(100).optional().default(5).describe("Number of autocomplete terms to return"),
+ filter: z.string().optional().describe("OData filter expression"),
+});
+
+export type AutocompleteParams = z.infer;
+
+// Index Management
+export const ListIndexesSchema = z.object({
+ select: z.array(z.string()).optional().describe("Fields to include in results"),
+});
+
+export type ListIndexesParams = z.infer;
+
+export const GetIndexSchema = z.object({
+ indexName: z.string().min(1).describe("Name of the index"),
+});
+
+export type GetIndexParams = z.infer;
+
+export const GetIndexStatisticsSchema = z.object({
+ indexName: z.string().min(1).describe("Name of the index"),
+});
+
+export type GetIndexStatisticsParams = z.infer;
+
+// Document Management
+export const UploadDocumentsSchema = z.object({
+ indexName: z.string().min(1).describe("Name of the search index"),
+ documents: z.array(z.record(z.any())).min(1).max(1000).describe("Documents to upload (max 1000)"),
+});
+
+export type UploadDocumentsParams = z.infer;
+
+export const MergeDocumentsSchema = z.object({
+ indexName: z.string().min(1).describe("Name of the search index"),
+ documents: z.array(z.record(z.any())).min(1).max(1000).describe("Documents to merge (max 1000)"),
+});
+
+export type MergeDocumentsParams = z.infer;
+
+export const DeleteDocumentsSchema = z.object({
+ indexName: z.string().min(1).describe("Name of the search index"),
+ keyField: z.string().describe("Name of the key field"),
+ keyValues: z.array(z.string()).min(1).max(1000).describe("Key values of documents to delete (max 1000)"),
+});
+
+export type DeleteDocumentsParams = z.infer;
+
+// Response Types
+export interface SearchResult {
+ success: boolean;
+ data?: {
+ results: T[];
+ count?: number;
+ facets?: Record;
+ coverage?: number;
+ nextPageParameters?: any;
+ };
+ error?: string;
+}
+
+export interface DocumentResult {
+ success: boolean;
+ data?: T;
+ error?: string;
+}
+
+export interface SuggestResult {
+ success: boolean;
+ data?: {
+ results: Array<{
+ text: string;
+ document: any;
+ }>;
+ coverage?: number;
+ };
+ error?: string;
+}
+
+export interface AutocompleteResult {
+ success: boolean;
+ data?: {
+ results: Array<{
+ text: string;
+ queryPlusText: string;
+ }>;
+ coverage?: number;
+ };
+ error?: string;
+}
+
+export interface IndexResult {
+ success: boolean;
+ data?: any;
+ error?: string;
+}
+
+export interface BatchResult {
+ success: boolean;
+ data?: {
+ results: Array<{
+ key: string;
+ status: boolean;
+ errorMessage?: string;
+ }>;
+ };
+ error?: string;
+}
+
+// Phase 4: Vector Search Schemas
+export const VectorQuerySchema = z.object({
+ vector: z.array(z.number()).describe("Vector values for similarity search"),
+ fields: z.string().describe("Vector field name to search"),
+ k: z.number().min(1).max(1000).optional().default(50).describe("Number of nearest neighbors to return"),
+ exhaustive: z.boolean().optional().default(false).describe("Use exhaustive search for higher accuracy"),
+});
+
+export type VectorQuery = z.infer;
+
+export const VectorSearchSchema = z.object({
+ indexName: z.string().min(1).describe("Name of the search index"),
+ vectorQueries: z.array(VectorQuerySchema).min(1).describe("Vector queries to execute"),
+ select: z.array(z.string()).optional().describe("Fields to include in results"),
+ filter: z.string().optional().describe("OData filter expression"),
+ top: z.number().min(1).max(1000).optional().default(50).describe("Number of results to return"),
+ skip: z.number().min(0).optional().describe("Number of results to skip"),
+});
+
+export type VectorSearchParams = z.infer;
+
+export const HybridSearchSchema = z.object({
+ indexName: z.string().min(1).describe("Name of the search index"),
+ searchText: z.string().describe("Text query for hybrid search"),
+ vectorQueries: z.array(VectorQuerySchema).min(1).describe("Vector queries for hybrid search"),
+ searchMode: z.enum(["any", "all"]).optional().default("any").describe("Text search mode"),
+ searchFields: z.array(z.string()).optional().describe("Text fields to search in"),
+ select: z.array(z.string()).optional().describe("Fields to include in results"),
+ filter: z.string().optional().describe("OData filter expression"),
+ orderBy: z.array(z.string()).optional().describe("Sort order"),
+ top: z.number().min(1).max(1000).optional().default(50).describe("Number of results to return"),
+ skip: z.number().min(0).optional().describe("Number of results to skip"),
+ queryType: z.enum(["simple", "full"]).optional().default("simple").describe("Text query type"),
+});
+
+export type HybridSearchParams = z.infer;
+
+// Phase 4: Semantic Search Schemas
+export const SemanticSearchSchema = z.object({
+ indexName: z.string().min(1).describe("Name of the search index"),
+ searchText: z.string().describe("Text to search semantically"),
+ semanticConfiguration: z.string().describe("Name of the semantic configuration to use"),
+ searchFields: z.array(z.string()).optional().describe("Fields to search in"),
+ select: z.array(z.string()).optional().describe("Fields to include in results"),
+ filter: z.string().optional().describe("OData filter expression"),
+ orderBy: z.array(z.string()).optional().describe("Sort order"),
+ top: z.number().min(1).max(1000).optional().default(50).describe("Number of results to return"),
+ skip: z.number().min(0).optional().describe("Number of results to skip"),
+ answers: z.object({
+ answerType: z.enum(["extractive"]).default("extractive"),
+ count: z.number().min(1).max(10).optional().default(3).describe("Number of answers to generate"),
+ threshold: z.number().min(0).max(1).optional().default(0.7).describe("Confidence threshold for answers"),
+ }).optional().describe("Semantic answers configuration"),
+ captions: z.object({
+ captionType: z.enum(["extractive"]).default("extractive"),
+ maxTextRecordsToProcess: z.number().min(1).max(1000).optional().default(1000),
+ highlight: z.boolean().optional().default(true).describe("Enable highlighting in captions"),
+ }).optional().describe("Semantic captions configuration"),
+});
+
+export type SemanticSearchParams = z.infer;
+
+// Phase 4: Response Types for Vector and Semantic Search
+export interface VectorSearchResult {
+ success: boolean;
+ data?: {
+ results: T[];
+ count?: number;
+ };
+ error?: string;
+}
+
+export interface SemanticSearchResult {
+ success: boolean;
+ data?: {
+ results: T[];
+ count?: number;
+ answers?: Array<{
+ key: string;
+ text: string;
+ highlights: string;
+ score: number;
+ }>;
+ captions?: Array<{
+ text: string;
+ highlights: string;
+ }>;
+ };
+ error?: string;
+}
\ No newline at end of file