An extensible meta search engine for Windows that can search multiple data sources simultaneously. The application supports both built-in connectors and custom plugins.
- Feature Overview
- Installation
- User Interface
- AI Search
- Connectors and Data Sources
- Plugin Development
- API Reference
- Examples
- Multi-Source Search: Search multiple data sources simultaneously
- Data Source Groups: Organize your data sources into logical groups
- Label System: Tag search results with keywords for later reference
- Saved Queries: Save and load frequently used searches
- Extensible: Add custom connectors via script or as compiled plugins
| Connector | Description |
|---|---|
| File System | Searches local files and folders by filename |
| Find In Files | Searches for text content inside files with regex support |
| Microsoft 365 | Searches Calendar, ToDo, Emails, and OneNote via Microsoft Graph API |
| DuckDuckGo | Performs web searches using DuckDuckGo |
| SQL Database | Searches SQL databases (MySQL, MSSQL, PostgreSQL) |
| OpenAI API | Queries OpenAI-compatible AI APIs (ChatGPT, local LLMs) |
| Generic API | Connects to any REST API with flexible authentication |
| IMAP Email | Searches emails via IMAP (Gmail, Outlook, Yahoo, private servers) |
| Mock Database | Demo connector for testing purposes |
- Windows 10/11
- .NET 10 Runtime
git clone <repository-url>
cd MSCC
dotnet build
dotnet runThe main window is divided into three areas:
- Left Sidebar: Manage groups and data sources
- Center: Search results and detail view
- Right Sidebar: Labels and saved queries
- Click + next to "Data Sources"
- Select a connector type
- Enter a name and configuration
- Click Save
- Enable the desired data sources (checkbox)
- Enter a search term
- Press Enter or click Search
The AI Search feature allows you to analyze your search results using an AI language model. Instead of manually reviewing each result, you can have an AI summarize, categorize, or extract insights from your search results.
- Automatic Search Execution: If you have a search term but haven't searched yet, clicking "AI Search" will automatically perform the search first
- Customizable System Prompt: Define how the AI should analyze your results
- HTML-Formatted Output: Results are displayed in a rich HTML view with proper formatting
- WebView2 Rendering: Modern web-based display with support for tables, lists, and styled content
- Token Usage Tracking: See how many tokens were used for the request and response
Before using AI Search, you need to configure an AI API in the application settings:
- Go to File ? Settings
- Navigate to the AI Search section
- Configure the following:
| Setting | Description | Example |
|---|---|---|
| API Endpoint | The URL of your AI API | https://api.openai.com/v1/chat/completions |
| API Key | Your authentication token | sk-... |
| Model | The AI model to use | gpt-4, gpt-3.5-turbo, llama2 |
| Provider | Endpoint | Notes |
|---|---|---|
| OpenAI | https://api.openai.com/v1/chat/completions |
Requires API key from platform.openai.com |
| Azure OpenAI | https://{resource}.openai.azure.com/openai/deployments/{deployment}/chat/completions?api-version=2024-02-01 |
Use your Azure deployment |
| Ollama | http://localhost:11434/v1/chat/completions |
Free, local, no API key needed |
| LM Studio | http://localhost:1234/v1/chat/completions |
Free, local, no API key needed |
| Any OpenAI-compatible API | Varies | Must support the OpenAI chat completions format |
- Enter a search term in the search box
- Click "AI Search" (purple button next to the regular Search button)
- If no search has been performed yet, it will automatically search first
- Review the System Prompt in the dialog that appears
- The default prompt instructs the AI to output HTML-formatted results
- You can customize this prompt to change how the AI analyzes the results
- Click "Analyze with AI"
- View the results in the AI Analysis Result window
- Results are displayed with rich HTML formatting
- Use "Copy Response" to copy the raw response to clipboard
The default system prompt is designed to produce well-formatted HTML output:
You are a helpful assistant. Analyze the following search results and provide a well-structured summary.
IMPORTANT: Your response MUST be valid HTML. Use these HTML elements for formatting:
- <h2> for main section headers
- <h3> for sub-section headers
- <p> for paragraphs
- <ul> and <li> for bullet lists
- <ol> and <li> for numbered lists
- <strong> for bold/important text
- <em> for italic/emphasized text
- <code> for code or technical terms
- <blockquote> for quotes or important notes
- <table>, <tr>, <th>, <td> for tabular data
Structure your response with clear sections. Highlight the most relevant information.
Do NOT include <html>, <head>, or <body> tags - only the inner content.
You can modify the system prompt to change how the AI analyzes your results. Here are some examples:
Analyze the search results and create a brief executive summary (max 3 paragraphs).
Output as HTML with <h2> for the title and <p> for paragraphs.
Focus only on the most important findings.
Compare and contrast the search results. Create an HTML table showing:
- Key similarities
- Key differences
- Unique aspects of each result
Use <table>, <tr>, <th>, <td> tags for the comparison table.
Review the search results and extract actionable items.
Format as an HTML ordered list (<ol>, <li>) with priority levels.
Use <strong> to highlight high-priority items.
Analyze these search results from a technical perspective.
Create an HTML report with:
- <h2> for main sections
- <code> for technical terms
- <ul> for feature lists
- <table> for specifications comparison
The AI Analysis Result window displays:
| Element | Description |
|---|---|
| Title | "AI Analysis Result" |
| Model | The AI model that generated the response |
| Response | The formatted HTML response from the AI |
| Token Info | Prompt tokens, completion tokens, and total tokens used |
| Copy Response | Button to copy the raw response to clipboard |
- Be specific in your search: The more relevant your search results, the better the AI analysis
- Customize the prompt: Tailor the system prompt to get the type of analysis you need
- Use appropriate models: GPT-4 produces better analysis than GPT-3.5-turbo but costs more
- Keep result count reasonable: Too many results may exceed token limits or produce less focused analysis
- Review token usage: Monitor token consumption to manage API costs
| Issue | Solution |
|---|---|
| "No search results to analyze" | Perform a search first, or enter a search term before clicking AI Search |
| "API Error" | Check your API endpoint, API key, and model settings |
| Empty response | Verify the AI service is running and accessible |
| Timeout | The AI may be taking too long; try with fewer search results |
| Malformed output | The AI may not have followed HTML instructions; try adjusting the prompt |
| Rate limit exceeded | Wait and try again, or upgrade your API plan |
- OpenAI: Charges per token (input + output). GPT-4 is ~30x more expensive than GPT-3.5-turbo
- Azure OpenAI: Similar pricing to OpenAI
- Ollama/LM Studio: Free (runs locally on your hardware)
Monitor your usage at:
- OpenAI: platform.openai.com/usage
- Azure: Azure Portal cost management
- Connector: A plugin that can connect to a specific data source (e.g., file system, REST API, database)
- Data Source: A concrete instance of a connector with specific configuration
Example: The file system connector can create multiple data sources - one for "Documents", one for "Downloads", etc.
The File System Connector allows you to search for files and folders by their names in your local file system.
- Fast filename search: Quickly find files by name pattern
- Wildcard support: Use patterns like
*.txt,*.pdf,report* - Recursive search: Optionally include subdirectories
- File metadata: View size, dates, and file type information
| Parameter | Required | Default | Description |
|---|---|---|---|
| Base Path | Yes | - | The folder path to search in |
| Search Pattern | No | *.* |
File pattern filter (e.g., *.txt, *.pdf) |
| Include Subdirectories | No | true | Whether to search in subdirectories |
Each search result includes:
| Field | Description |
|---|---|
| Title | The file or folder name |
| Description | Full path to the file |
| Path | Complete file path |
| Size | File size in bytes |
| Created | Creation date |
| Modified | Last modification date |
| Type | File extension or "Folder" |
| Action | Description |
|---|---|
| Open | Opens the file with the default application |
| Open Folder | Opens the containing folder in Explorer |
| Copy Path | Copies the full file path to clipboard |
- Click + next to "Data Sources"
- Select File System as the connector
- Enter a name (e.g., "Documents")
- Configure:
- Base Path:
C:\Users\YourName\Documents - Search Pattern:
*.*(all files) or*.pdf(only PDFs) - Include Subdirectories: true
- Base Path:
- Click Save
- Enable the data source and start searching!
The Find In Files Connector allows you to search for text content inside files. Unlike the File System Connector which searches by filename, this connector reads file contents and finds matching text, similar to "grep" on Linux or "Find in Files" in text editors.
- Full-text search: Search inside file contents, not just filenames
- Regular expression support: Use regex patterns for advanced searches
- Case sensitivity option: Choose between case-sensitive or case-insensitive search
- Multiple file types: Search in text files, source code, logs, and more
- Match context: See the line and column where matches were found
- Match highlighting: View all matches with their surrounding context
| Parameter | Required | Default | Description |
|---|---|---|---|
| Base Path | Yes | - | The folder path to search in |
| File Pattern | No | *.* |
File pattern filter (e.g., *.txt, *.cs, *.log) |
| Include Subdirectories | No | true | Whether to search in subdirectories |
| Use Regular Expressions | No | false | Enable regex pattern matching |
| Case Sensitive | No | false | Enable case-sensitive matching |
1. Plain Text Search (Default)
When "Use Regular Expressions" is disabled, the connector performs a simple text search:
- Searches for the exact text you enter
- Case sensitivity depends on the "Case Sensitive" setting
- Fast and straightforward
Example: Searching for TODO will find all occurrences of "TODO" in files.
2. Regular Expression Search
When "Use Regular Expressions" is enabled, you can use regex patterns:
| Pattern | Description | Example Match |
|---|---|---|
\bword\b |
Whole word only | "word" but not "keyword" |
error|warning |
Either pattern | "error" or "warning" |
\d{4}-\d{2}-\d{2} |
Date pattern | "2024-01-15" |
TODO:.* |
TODO with text | "TODO: fix this bug" |
^import\s+ |
Line starting with import | "import System;" |
\.(jpg|png|gif)$ |
Image extensions | ".jpg", ".png" |
Each search result represents a file with matches:
| Field | Description |
|---|---|
| Title | Filename with match count |
| Description | First few matches with line numbers |
| Path | Full file path |
| Directory | Parent directory |
| File Name | Just the filename |
| Size | File size |
| Modified | Last modification date |
| Match Count | Total number of matches in the file |
| Matches | Detailed list of all matches with line/column |
For each match found, the connector provides:
| Field | Description |
|---|---|
| Line | Line number (1-based) |
| Column | Column position (1-based) |
| Text | The matched text |
| Context | The full line containing the match |
| Action | Description |
|---|---|
| Open | Opens the file with the default application |
| Open Folder | Opens the containing folder in Explorer |
| Copy Path | Copies the full file path to clipboard |
| Copy Matches | Copies all matches with line numbers to clipboard |
- Click + next to "Data Sources"
- Select Find In Files as the connector
- Enter a name (e.g., "TODO Finder")
- Configure:
- Base Path:
C:\Projects\MyProject - File Pattern:
*.cs(C# files only) - Include Subdirectories: true
- Use Regular Expressions: false
- Case Sensitive: false
- Base Path:
- Click Save
- Search for:
TODO
- Create a new data source named "Log Search"
- Configure:
- Base Path:
C:\Logs - File Pattern:
*.log - Include Subdirectories: true
- Use Regular Expressions: true
- Case Sensitive: false
- Base Path:
- Search for:
error|exception|failed
- Enable regex mode
- Search for:
\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b
- Enable regex mode
- Search for:
[\w.+-]+@[\w-]+\.[\w.-]+
The connector can search in any text-based file format:
| Category | Extensions |
|---|---|
| Source Code | .cs, .js, .ts, .py, .java, .cpp, .c, .h |
| Web Files | .html, .css, .xml, .json, .yaml, .yml |
| Documents | .txt, .md, .rst, .csv |
| Config Files | .config, .ini, .env, .properties |
| Log Files | .log, .trace |
| Scripts | .ps1, .sh, .bat, .cmd |
Note: Binary files (images, executables, etc.) are automatically skipped.
- Narrow your file pattern: Use specific patterns like
*.csinstead of*.* - Limit the base path: Search in specific folders rather than entire drives
- Disable subdirectories: If you only need to search the top-level folder
- Use simpler regex: Complex regex patterns are slower than plain text
- Consider file size: Very large files take longer to search
| Issue | Solution |
|---|---|
| No results found | Check that files exist and match the file pattern |
| Search is slow | Narrow the base path or file pattern |
| Regex not working | Verify your regex syntax; test with simple patterns first |
| Encoding issues | The connector uses automatic encoding detection |
| Access denied | Check folder permissions |
| Out of memory | Reduce the number of files by using a more specific file pattern |
| Feature | File System | Find In Files |
|---|---|---|
| Search by filename | ? | ? |
| Search file contents | ? | ? |
| Regex support | ? | ? |
| Case sensitivity option | ? | ? |
| Match highlighting | ? | ? |
| Speed | Faster | Slower (reads file contents) |
| Use case | Find files by name | Find text in files |
The Microsoft 365 Connector allows you to search across your Microsoft 365 data including Calendar events, ToDo tasks, Emails, and OneNote pages using the Microsoft Graph API.
Before using this connector, you need to register an application in Azure Active Directory:
-
Go to Azure Portal: Navigate to https://portal.azure.com
-
Register a new application:
- Go to Azure Active Directory ? App registrations ? New registration
- Name: e.g., "MSCC Meta Search"
- Supported account types: Choose based on your needs:
- Single tenant: Only your organization
- Multitenant: Any Azure AD directory
- Personal Microsoft accounts: For personal Outlook.com, OneDrive, etc.
- Redirect URI: Select Public client/native and enter
http://localhost - Click Register
-
Note the Application (Client) ID: Copy this value - you'll need it for configuration
-
Note the Tenant ID (optional):
- Found on the Overview page
- Or use
commonfor multi-tenant,consumersfor personal accounts only
-
Configure API Permissions:
- Go to API permissions ? Add a permission ? Microsoft Graph ? Delegated permissions
- Add the following permissions:
User.Read(required)Calendars.Read(for calendar search)Tasks.Read(for ToDo search)Mail.Read(for email search)Notes.Read(for OneNote search)
- Click Grant admin consent if you have admin privileges (optional but recommended)
-
Enable public client flows (required for interactive authentication):
- Go to Authentication
- Under Advanced settings, set Allow public client flows to Yes
- Click Save
When creating a Microsoft 365 data source in MSCC, configure the following parameters:
| Parameter | Required | Description |
|---|---|---|
| Client ID (App-ID) | Yes | The Application (Client) ID from your Azure app registration |
| Tenant ID | Yes | Your Azure AD Tenant ID, or use special values: common (any Azure AD + personal), consumers (personal accounts only), organizations (any Azure AD only) |
| Search Calendar | No | Include calendar events in search (default: true) |
| Search ToDo | No | Include ToDo tasks in search (default: true) |
| Search Mail | No | Include emails in search (default: true) |
| Search OneNote | No | Include OneNote pages in search (default: true) |
| Max Days Back | No | How many days back to search for calendar/mail (default: 30) |
When you first use the connector (either when testing the connection or performing a search):
- A browser window will open automatically
- Sign in with your Microsoft account
- Review and accept the requested permissions
- The browser will redirect to localhost (you can close it)
- MSCC will now have access to search your Microsoft 365 data
Note: The authentication token is cached, so you won't need to sign in again unless the token expires or you revoke access.
| Data Type | What's Searched | Result Details |
|---|---|---|
| Calendar | Event subject, body preview, location | Start/end time, location, organizer |
| ToDo | Task title, body content | List name, status, importance, due date |
| Full-text search via Graph API | Sender, received date, attachments, importance | |
| OneNote | Page title and content | Section name, created/modified dates |
Each search result supports the following actions:
| Action | Description |
|---|---|
| Open in Browser | Opens the item in the corresponding web app (Outlook, ToDo, OneNote) |
| Copy Link | Copies the web link to the clipboard |
- Click + next to "Data Sources"
- Select Microsoft 365 as the connector
- Enter a name (e.g., "My Microsoft 365")
- Enter your Client ID from Azure
- Enter your Tenant ID (or use
common) - Enable/disable the services you want to search
- Click Save
- Sign in when prompted
- Enable the data source and start searching!
| Issue | Solution |
|---|---|
| "AADSTS50011: Reply URL mismatch" | Ensure http://localhost is added as a redirect URI in Azure |
| "AADSTS65001: User needs to consent" | The user hasn't consented to permissions. Re-authenticate or grant admin consent |
| "AADSTS7000218: Request body must contain client_assertion" | Enable "Allow public client flows" in Azure app settings |
| No results returned | Check that the specific service (Calendar/ToDo/Mail/OneNote) is enabled in configuration |
| OneNote search fails | Ensure Notes.Read permission is granted; some organizational policies may restrict access |
- The connector uses delegated permissions, meaning it can only access data the signed-in user has access to
- No credentials are stored - authentication is handled via OAuth 2.0 with PKCE
- Tokens are cached locally and can be revoked from https://myaccount.microsoft.com
- For organizational use, consider having an admin grant consent to avoid per-user consent prompts
The SQL Database Connector allows you to search across relational databases including Microsoft SQL Server, MySQL, and PostgreSQL. It can search all text fields in specified tables or execute custom SQL queries.
| Database | Required Package |
|---|---|
| Microsoft SQL Server | Microsoft.Data.SqlClient or System.Data.SqlClient |
| MySQL | MySql.Data or MySqlConnector |
| PostgreSQL | Npgsql |
Note: Install the appropriate NuGet package for your database before using this connector.
| Parameter | Required | Default | Description |
|---|---|---|---|
| Connection String | Yes | - | Database connection string |
| Database Type | Yes | MSSQL | Type: MSSQL, MySQL, or PostgreSQL |
| Tables | No | * | Comma-separated table names, or * for all tables |
| Custom SQL Query | No | - | Custom SELECT statement with @SearchTerm placeholder |
SQL Server:
Server=localhost;Database=MyDB;User Id=sa;Password=secret;TrustServerCertificate=True;
MySQL:
Server=localhost;Database=MyDB;User=root;Password=secret;
PostgreSQL:
Host=localhost;Database=MyDB;Username=postgres;Password=secret;
1. Table Search Mode (Default)
When using table search mode, the connector will:
- Get all specified tables (or all tables if
*is specified) - For each table, search all text-like columns (VARCHAR, NVARCHAR, TEXT, etc.)
- Return matching rows with relevance scoring
Example configuration:
- Tables:
Customers, Orders, Products - Or Tables:
*(search all tables)
2. Custom Query Mode
Use a custom SQL query for more control. Use @SearchTerm as a placeholder for the search term:
SELECT * FROM Products
WHERE Name LIKE '%' + @SearchTerm + '%'
OR Description LIKE '%' + @SearchTerm + '%'For LIKE queries with wildcards, use @SearchTermWildcard which includes % wildcards:
SELECT * FROM Products WHERE Name LIKE @SearchTermWildcardEach search result includes:
| Field | Description |
|---|---|
| Title | First non-null text value from the record |
| Description | Preview of column values |
| Table Name | Source table of the record |
| Matching Columns | Columns where the search term was found |
| All Fields | Complete record data in metadata |
| Action | Description |
|---|---|
| Copy as JSON | Copies the record as formatted JSON |
| Copy as INSERT | Generates and copies a SQL INSERT statement |
-
Install required NuGet package for your database:
dotnet add package Microsoft.Data.SqlClient # or dotnet add package MySql.Data # or dotnet add package Npgsql
-
Click + next to "Data Sources"
-
Select SQL Database as the connector
-
Enter a name (e.g., "Production Database")
-
Configure:
- Connection String: Your database connection string
- Database Type: MSSQL, MySQL, or PostgreSQL
- Tables:
*or specific tables likeUsers, Products
-
Click Save
-
Enable the data source and start searching!
- Connection strings may contain sensitive credentials
- Consider using Windows Authentication for SQL Server when possible
- Use read-only database accounts for search operations
- Connection strings are stored locally in the application settings
| Issue | Solution |
|---|---|
| "Provider not found" | Install the appropriate NuGet package for your database |
| Connection timeout | Check firewall settings and ensure database is accessible |
| No results | Verify table names are correct and contain text columns |
| Access denied | Check database user permissions |
The DuckDuckGo Connector allows you to perform web searches directly from MSCC using the privacy-focused DuckDuckGo search engine.
- Privacy-focused: Uses DuckDuckGo which doesn't track your searches
- No API key required: Works out of the box without any registration
- Configurable result count: Set how many results you want (1-30)
- Region settings: Customize search results for your region
- SafeSearch support: Filter out adult content
| Parameter | Required | Default | Description |
|---|---|---|---|
| Max Results | No | 10 | Number of search results to return (1-30) |
| Region | No | wt-wt | Region code for localized results |
| SafeSearch | No | true | Enable family-friendly content filter |
| Code | Region |
|---|---|
wt-wt |
Worldwide (no region bias) |
de-de |
Germany |
at-de |
Austria |
ch-de |
Switzerland (German) |
us-en |
United States |
uk-en |
United Kingdom |
fr-fr |
France |
es-es |
Spain |
it-it |
Italy |
nl-nl |
Netherlands |
For a complete list of region codes, see the DuckDuckGo region documentation.
Each search result includes:
| Field | Description |
|---|---|
| Title | The webpage title |
| Description | Snippet/summary from the page |
| URL | Direct link to the webpage |
| Domain | The website domain |
| Position | Ranking position in search results |
| Action | Description |
|---|---|
| Open in Browser | Opens the webpage in your default browser |
| Copy URL | Copies the URL to clipboard |
| Search on DuckDuckGo | Opens full DuckDuckGo results page for this query |
- Click + next to "Data Sources"
- Select DuckDuckGo Web Search as the connector
- Enter a name (e.g., "Web Search")
- Configure:
- Max Results: 15 (or your preferred number)
- Region: de-de (for German results)
- SafeSearch: true
- Click Save
- Enable the data source and start searching!
- The connector uses DuckDuckGo's HTML Lite interface for reliable parsing
- No JavaScript execution is required
- Results are parsed from the HTML response
- Rate limiting may apply for very frequent searches
- Maximum 30 results per search (DuckDuckGo limitation)
- No image or video search (text results only)
- Some advanced DuckDuckGo features (bangs, instant answers) are not available
The OpenAI Connector allows you to query OpenAI-compatible AI APIs directly from MSCC. This includes OpenAI's ChatGPT, Azure OpenAI, and local LLM servers that implement the OpenAI API format (like Ollama, LM Studio, or llama.cpp server).
- ChatGPT Integration: Query OpenAI's GPT models directly
- Local LLM Support: Works with any OpenAI-compatible API endpoint
- Customizable System Prompt: Define the AI's behavior and context
- Token Control: Set maximum response length
- Temperature Settings: Control response creativity
For OpenAI API:
- Create an account at https://platform.openai.com
- Generate an API key in your account settings
- Ensure you have API credits available
For Local LLMs:
- Install and run a local LLM server (e.g., Ollama, LM Studio)
- Note the API endpoint URL (typically
http://localhost:11434/v1/chat/completionsfor Ollama)
| Parameter | Required | Default | Description |
|---|---|---|---|
| API Endpoint | Yes | https://api.openai.com/v1/chat/completions |
The API endpoint URL |
| API Key | Yes | - | Your API authentication token |
| Model | Yes | gpt-3.5-turbo |
The AI model to use (e.g., gpt-4, gpt-3.5-turbo, llama2) |
| System Prompt | No | You are a helpful assistant... |
Instructions that define the AI's behavior |
| Max Tokens | No | 1000 | Maximum tokens in the response (1-128000) |
| Temperature | No | 0.7 | Response creativity (0.0 = deterministic, 2.0 = very creative) |
| Service | Endpoint URL |
|---|---|
| OpenAI | https://api.openai.com/v1/chat/completions |
| Azure OpenAI | https://{resource}.openai.azure.com/openai/deployments/{deployment}/chat/completions?api-version=2024-02-01 |
| Ollama | http://localhost:11434/v1/chat/completions |
| LM Studio | http://localhost:1234/v1/chat/completions |
| llama.cpp | http://localhost:8080/v1/chat/completions |
| Provider | Model Names |
|---|---|
| OpenAI | gpt-4, gpt-4-turbo, gpt-3.5-turbo, gpt-4o, gpt-4o-mini |
| Ollama | llama2, llama3, mistral, codellama, mixtral |
| Azure OpenAI | Your deployment name |
Each query returns a single result containing:
| Field | Description |
|---|---|
| Title | First 100 characters of the AI response |
| Description | Full AI response text |
| Model | The model that generated the response |
| Prompt Tokens | Number of tokens in your query |
| Completion Tokens | Number of tokens in the response |
| Total Tokens | Total tokens used |
| Finish Reason | Why the response ended (e.g., stop, length) |
| Action | Description |
|---|---|
| Copy Response | Copies the full AI response to clipboard |
| Copy Query | Copies your original query to clipboard |
- Click + next to "Data Sources"
- Select OpenAI API as the connector
- Enter a name (e.g., "ChatGPT" or "Local Llama")
- Configure:
- API Endpoint: Your API URL
- API Key: Your API key
- Model:
gpt-3.5-turboor your preferred model - System Prompt: (optional) Customize AI behavior
- Click Save
- Enable the data source and start querying!
Code Assistant:
You are a helpful programming assistant. Provide concise code examples and explanations. Use markdown formatting for code blocks.
Research Assistant:
You are a research assistant. Provide factual, well-structured answers with sources when possible. Be concise but thorough.
Translation Assistant:
You are a translation assistant. Translate any text the user provides into English. Maintain the original meaning and tone.
| Issue | Solution |
|---|---|
| "401 Unauthorized" | Check your API key is correct and has not expired |
| "429 Too Many Requests" | You've exceeded rate limits; wait and try again |
| "Model not found" | Verify the model name is correct for your endpoint |
| Timeout errors | Increase timeout in advanced settings or reduce max tokens |
| Empty responses | Check that max tokens > 0 and the model supports your query |
- OpenAI charges per token (both input and output)
- GPT-4 is significantly more expensive than GPT-3.5-turbo
- Monitor usage at https://platform.openai.com/usage
- Local LLMs (Ollama, LM Studio) are free but require local resources
The Generic API Connector allows you to connect to any REST API with flexible authentication and search parameter configuration. This is ideal for integrating custom APIs, third-party services, or internal company APIs that don't have a dedicated connector.
- Multiple HTTP Methods: GET, POST, PUT, PATCH, DELETE
- Flexible Authentication: None, Header-based, Bearer Token, OAuth2, JWT, Query Parameter, Post Parameter
- Custom Headers: Add any custom HTTP headers
- JSON Path Navigation: Extract results from nested JSON structures
- Configurable Result Mapping: Map JSON properties to title, description, and URL
| Type | Description | Required Parameters |
|---|---|---|
| None | No authentication | - |
| Header | Custom header authentication | AuthHeaderName, AuthHeaderValue |
| Bearer | Bearer token authentication | AuthToken |
| OAuth2 | OAuth 2.0 client credentials flow | OAuth2TokenEndpoint, OAuth2ClientId, OAuth2ClientSecret |
| JWT | JWT token authentication | AuthToken (your JWT token) |
| Query | API key in query string | AuthToken (format: key=value) |
| Post | API key in POST body | AuthToken (format: key=value) |
| Parameter | Required | Default | Description |
|---|---|---|---|
| API Endpoint | Yes | - | Base URL. Use [SEARCH] as placeholder for search term |
| HTTP Method | Yes | GET | HTTP method: GET, POST, PUT, PATCH, DELETE |
| Auth Type | Yes | None | Authentication method (see above) |
| Auth Header Name | No | Authorization | Header name for Header-based auth |
| Auth Header Value | No | - | Header value for Header-based auth |
| Auth Token | No | - | Token for Bearer/JWT auth, or key=value for Query/Post auth |
| OAuth2 Token Endpoint | No | - | URL to obtain OAuth2 access token |
| OAuth2 Client ID | No | - | OAuth2 client ID |
| OAuth2 Client Secret | No | - | OAuth2 client secret |
| OAuth2 Scope | No | - | OAuth2 scope (optional) |
| Query Parameters | No | q=[SEARCH] |
URL query parameters. Use [SEARCH] for search term |
| POST Body | No | - | Request body for POST/PUT/PATCH. Use [SEARCH] for search term |
| Content Type | No | application/json | Content-Type header for request body |
| Custom Headers | No | - | Additional headers, one per line (format: Header-Name: value) |
| Result JSON Path | No | results | Path to results array in JSON (e.g., data.results) |
| Result Title Property | No | title | JSON property name for result title |
| Result Description Property | No | description | JSON property name for result description |
| Result URL Property | No | url | JSON property name for result URL |
| Timeout (seconds) | No | 30 | Request timeout (1-300 seconds) |
Use [SEARCH] anywhere in your configuration to insert the search term:
- In the API Endpoint:
https://api.example.com/search/[SEARCH] - In Query Parameters:
q=[SEARCH]&limit=10 - In POST Body:
{"query": "[SEARCH]", "maxResults": 10}
The placeholder is automatically URL-encoded when used in URLs and query parameters.
The Result JSON Path parameter supports:
- Simple paths:
results,data,items - Nested paths:
data.results,response.data.items - Array indexing:
results[0].items
Example API Response:
{
"status": "ok",
"data": {
"results": [
{"title": "Result 1", "desc": "Description 1"},
{"title": "Result 2", "desc": "Description 2"}
]
}
}Configuration:
- Result JSON Path:
data.results - Result Title Property:
title - Result Description Property:
desc
API: A weather API that uses query parameters
| Setting | Value |
|---|---|
| API Endpoint | https://api.weather.com/v1/search |
| HTTP Method | GET |
| Auth Type | Query |
| Auth Token | apikey=your-api-key-here |
| Query Parameters | q=[SEARCH]&format=json |
| Result JSON Path | locations |
| Result Title Property | name |
| Result Description Property | country |
API: A search API that requires POST requests
| Setting | Value |
|---|---|
| API Endpoint | https://api.example.com/search |
| HTTP Method | POST |
| Auth Type | Bearer |
| Auth Token | your-bearer-token |
| Content Type | application/json |
| POST Body | {"query": "[SEARCH]", "limit": 20} |
| Result JSON Path | results |
| Result Title Property | name |
| Result Description Property | summary |
| Result URL Property | link |
API: An enterprise API using OAuth2
| Setting | Value |
|---|---|
| API Endpoint | https://api.enterprise.com/v2/search |
| HTTP Method | GET |
| Auth Type | OAuth2 |
| OAuth2 Token Endpoint | https://auth.enterprise.com/oauth/token |
| OAuth2 Client ID | your-client-id |
| OAuth2 Client Secret | your-client-secret |
| OAuth2 Scope | read:search |
| Query Parameters | q=[SEARCH] |
API: An API using a custom authentication header
| Setting | Value |
|---|---|
| API Endpoint | https://api.service.com/search |
| HTTP Method | GET |
| Auth Type | Header |
| Auth Header Name | X-API-Key |
| Auth Header Value | your-api-key |
| Custom Headers | X-Request-Source: MSCC |
| Query Parameters | term=[SEARCH]&max=25 |
| Action | Description |
|---|---|
| Open URL | Opens the result URL in your default browser |
| Copy as JSON | Copies the result data as formatted JSON |
| Copy URL | Copies the result URL to clipboard |
- Click + next to "Data Sources"
- Select Generic API as the connector
- Enter a name (e.g., "Company API")
- Configure all required parameters based on your API's documentation
- Click Save
- Test with a simple search to verify configuration
- Enable the data source and start searching!
| Issue | Solution |
|---|---|
| "401 Unauthorized" | Check authentication configuration matches API requirements |
| "400 Bad Request" | Verify POST body format and Content-Type header |
| Empty results | Check Result JSON Path matches actual API response structure |
| Timeout | Increase timeout value or check API endpoint availability |
| Wrong data displayed | Verify Result Title/Description/URL properties match JSON field names |
| OAuth2 fails | Ensure token endpoint, client ID, and secret are all correct |
- Test with API tools first: Use Postman or curl to understand the API before configuring
- Check API documentation: Verify required headers, authentication, and response format
- Start simple: Begin with minimal configuration and add complexity as needed
- Use browser dev tools: Inspect network requests if the API is used by a web app
- Handle pagination: If the API returns paginated results, set appropriate limit parameters
The IMAP Connector allows you to search emails from any IMAP-compatible email server. It supports both password authentication and OAuth2, making it compatible with Gmail, Outlook.com, Yahoo Mail, and private email servers.
- Universal IMAP Support: Works with any IMAP server (Gmail, Outlook, Yahoo, private servers)
- Multiple Authentication Methods: Password or OAuth2 authentication
- Flexible Encryption: SSL/TLS, STARTTLS, or no encryption
- Folder Selection: Search in any mail folder (INBOX, Sent, Archive, custom folders)
- Date Filtering: Limit search to recent emails
- Full-Text Search: Searches subject, body, and sender
For Password Authentication:
- Your email address and password
- For Gmail: Enable "Less secure app access" or create an App Password
- For Outlook.com: Create an App Password if 2FA is enabled
For OAuth2 Authentication:
- A valid OAuth2 access token for your email provider
- The token must have IMAP access scope
| Provider | Server | Port | Encryption |
|---|---|---|---|
| Gmail | imap.gmail.com |
993 | SslTls |
| Outlook.com / Hotmail | outlook.office365.com |
993 | SslTls |
| Yahoo Mail | imap.mail.yahoo.com |
993 | SslTls |
| iCloud | imap.mail.me.com |
993 | SslTls |
| AOL | imap.aol.com |
993 | SslTls |
| Zoho Mail | imap.zoho.com |
993 | SslTls |
| GMX | imap.gmx.net |
993 | SslTls |
| Private Server | Your server hostname | 993 or 143 | Varies |
| Parameter | Required | Default | Description |
|---|---|---|---|
| IMAP Server | Yes | imap.gmail.com |
The IMAP server hostname |
| Port | Yes | 993 | IMAP port (993 for SSL/TLS, 143 for STARTTLS) |
| Email Address | Yes | - | Your email address for authentication |
| Auth Type | Yes | Password | Authentication method: Password or OAuth2 |
| Password | No | - | Your password or app password (for Password auth) |
| OAuth2 Access Token | No | - | OAuth2 access token (for OAuth2 auth) |
| Encryption | Yes | SslTls | Encryption method: SslTls, StartTls, or None |
| Folder Name | No | INBOX | Mail folder to search (e.g., INBOX, Sent, [Gmail]/All Mail) |
| Max Results | No | 50 | Maximum number of emails to return (1-500) |
| Max Days Back | No | 30 | How many days back to search (1-365) |
To use this connector with Gmail, you need to enable IMAP and create an App Password:
-
Enable IMAP in Gmail:
- Go to Gmail Settings ? See all settings ? Forwarding and POP/IMAP
- Under "IMAP access", select "Enable IMAP"
- Click "Save Changes"
-
Create an App Password (required if 2FA is enabled):
- Go to https://myaccount.google.com/apppasswords
- Sign in to your Google account
- Select "Mail" and "Windows Computer" (or other)
- Click "Generate"
- Copy the 16-character password
-
Configure the connector:
- Server:
imap.gmail.com - Port:
993 - Email Address: Your Gmail address
- Auth Type:
Password - Password: Your App Password (not your regular password)
- Encryption:
SslTls
- Server:
-
Enable IMAP (usually enabled by default):
- Go to Outlook.com ? Settings ? View all Outlook settings
- Mail ? Sync email ? POP and IMAP
- Ensure "Let devices and apps use IMAP" is set to Yes
-
Create an App Password (if 2FA is enabled):
- Go to https://account.microsoft.com/security
- Select "Advanced security options"
- Under "App passwords", click "Create a new app password"
- Copy the generated password
-
Configure the connector:
- Server:
outlook.office365.com - Port:
993 - Email Address: Your Outlook.com address
- Auth Type:
Password - Password: Your App Password
- Encryption:
SslTls
- Server:
The connector searches across:
| Field | Description |
|---|---|
| Subject | Email subject line |
| Body | Email body content (text and HTML) |
| Sender | Sender's name and email address |
Each search result includes:
| Field | Description |
|---|---|
| Title | Email subject |
| Description | Sender name and body preview |
| From | Sender's display name |
| From (Email) | Sender's email address |
| Date | When the email was received |
| Attachments | Whether the email has attachments |
| Folder | The mail folder where the email is located |
| Action | Description |
|---|---|
| Copy Body | Copies the full email body to clipboard |
| Copy Sender | Copies the sender's email address to clipboard |
- Click + next to "Data Sources"
- Select IMAP Email as the connector
- Enter a name (e.g., "Gmail" or "Work Email")
- Configure:
- IMAP Server:
imap.gmail.com - Port:
993 - Email Address:
your.email@gmail.com - Auth Type:
Password - Password: Your App Password
- Encryption:
SslTls - Folder Name:
INBOX - Max Results:
50 - Max Days Back:
30
- IMAP Server:
- Click Save
- Enable the data source and start searching!
Different email providers use different folder naming conventions:
| Provider | Sent | Trash | Drafts | All Mail |
|---|---|---|---|---|
| Gmail | [Gmail]/Sent Mail |
[Gmail]/Trash |
[Gmail]/Drafts |
[Gmail]/All Mail |
| Outlook.com | Sent |
Deleted |
Drafts |
- |
| Yahoo | Sent |
Trash |
Draft |
- |
| Generic | Sent |
Trash |
Drafts |
- |
| Issue | Solution |
|---|---|
| "Authentication failed" | Check email/password, or create an App Password if 2FA is enabled |
| "Connection refused" | Verify server hostname and port; check firewall settings |
| "Certificate error" | Try changing encryption method; some servers use StartTls on port 143 |
| "Login failed for Gmail" | Create an App Password at https://myaccount.google.com/apppasswords |
| "Folder not found" | Check folder name spelling; use full path for Gmail folders (e.g., [Gmail]/Sent Mail) |
| No results | Increase "Max Days Back" or check if the folder contains emails |
| Slow searches | Reduce "Max Days Back" and "Max Results" for faster searches |
- Passwords are stored locally in the application settings file
- Use App Passwords instead of your main account password when available
- Consider using OAuth2 for enhanced security (requires external token management)
- Connection uses encrypted TLS by default
- The connector only reads emails - it cannot modify or delete them
For OAuth2 authentication, you need to obtain an access token from your email provider. This typically involves:
- Registering an application with your email provider
- Implementing the OAuth2 flow to obtain tokens
- Providing the access token to the connector
Note: OAuth2 tokens typically expire after 1 hour. You'll need to refresh them periodically.
There are two ways to create custom connectors:
Script plugins are compiled at runtime and don't require a separate build process. Ideal for quick prototypes and simple connectors.
- Open Plugins ? Script Manager
- Enter a name and click + New Script
- Edit the generated template
- Click Compile
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MSCC.Connectors;
using MSCC.Models;
using MSCC.Scripting;
namespace MSCC.Scripts
{
public class MyConnector : ScriptedConnectorBase
{
// Unique ID for this connector
public override string Id => "my-connector";
// Display name in the UI
public override string Name => "My Connector";
// Description
public override string Description => "Description of my connector";
// Version
public override string Version => "1.0.0";
// Define configuration parameters
public override IEnumerable<ConnectorParameter> ConfigurationParameters => new[]
{
new ConnectorParameter
{
Name = "ApiUrl",
DisplayName = "API URL",
Description = "The URL of the API",
ParameterType = "string",
IsRequired = true
},
new ConnectorParameter
{
Name = "ApiKey",
DisplayName = "API Key",
Description = "Optional API key",
ParameterType = "string",
IsRequired = false
}
};
private string _apiUrl = string.Empty;
private string _apiKey = string.Empty;
// Initialization with configuration
public override Task<bool> InitializeAsync(Dictionary<string, string> configuration)
{
if (!configuration.TryGetValue("ApiUrl", out var url) || string.IsNullOrEmpty(url))
return Task.FromResult(false);
_apiUrl = url;
configuration.TryGetValue("ApiKey", out var key);
_apiKey = key ?? string.Empty;
return Task.FromResult(true);
}
// Connection test
public override Task<bool> TestConnectionAsync()
{
return Task.FromResult(!string.IsNullOrEmpty(_apiUrl));
}
// Implement search logic
public override async Task<IEnumerable<SearchResult>> SearchAsync(
string searchTerm,
int maxResults = 100,
CancellationToken cancellationToken = default)
{
var results = new List<SearchResult>();
// Implement your search logic here
// Example: Call API, query database, etc.
// Add result
results.Add(new SearchResult
{
Title = "Example Result",
Description = $"Found for: {searchTerm}",
SourceName = Name,
ConnectorId = Id,
OriginalReference = "ref-123",
RelevanceScore = 100,
Metadata = new Dictionary<string, object>
{
["Property1"] = "Value1",
["Property2"] = 42
}
});
return results;
}
}
}Scripts are saved under:
%APPDATA%\MSCC\Scripts\
Each script consists of two files:
ScriptName_<id>.cs- The source codeScriptName_<id>.cs.meta- Metadata (name, version, etc.)
When a user clicks on a search result, the detail view shows additional information. You can customize this view by overriding GetDetailViewConfiguration() and optionally ExecuteActionAsync().
The base class automatically displays all metadata properties:
public virtual DetailViewConfiguration GetDetailViewConfiguration(SearchResult result)
{
return new DetailViewConfiguration
{
ViewType = DetailViewType.Default,
DisplayProperties = result.Metadata.Keys.ToList()
};
}| ViewType | Description | Required Properties |
|---|---|---|
Default |
Standard text view with key-value pairs | DisplayProperties |
Table |
Tabular data display | TableColumns |
Chart |
Bar, Line, or Pie charts | ChartConfig |
Media |
Image/Video preview | MediaPathProperty |
Custom |
Custom WPF control | Override CreateCustomDetailView() |
public override DetailViewConfiguration GetDetailViewConfiguration(SearchResult result)
{
return new DetailViewConfiguration
{
ViewType = DetailViewType.Default,
// Which metadata properties to display
DisplayProperties = new List<string>
{
"Author",
"CreatedDate",
"FileSize",
"Category"
},
// Define available actions
Actions = new List<ResultAction>
{
new ResultAction
{
Id = "open",
Name = "Open",
Icon = "??",
Description = "Open the file in default application"
},
new ResultAction
{
Id = "copy-path",
Name = "Copy Path",
Icon = "??"
},
new ResultAction
{
Id = "open-folder",
Name = "Open Folder",
Icon = "??"
}
}
};
}
// Handle action execution
public override Task<bool> ExecuteActionAsync(SearchResult result, string actionId)
{
switch (actionId)
{
case "open":
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
{
FileName = result.OriginalReference,
UseShellExecute = true
});
return Task.FromResult(true);
case "copy-path":
System.Windows.Clipboard.SetText(result.OriginalReference);
return Task.FromResult(true);
case "open-folder":
var folder = System.IO.Path.GetDirectoryName(result.OriginalReference);
if (!string.IsNullOrEmpty(folder))
{
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
{
FileName = folder,
UseShellExecute = true
});
}
return Task.FromResult(true);
default:
return Task.FromResult(false);
}
}For displaying structured data in a table format:
public override DetailViewConfiguration GetDetailViewConfiguration(SearchResult result)
{
return new DetailViewConfiguration
{
ViewType = DetailViewType.Table,
TableColumns = new List<TableColumnDefinition>
{
new TableColumnDefinition
{
PropertyName = "Name",
Header = "Name",
Width = "*"
},
new TableColumnDefinition
{
PropertyName = "Size",
Header = "Size",
Width = "100",
Format = "{0:N0} KB"
},
new TableColumnDefinition
{
PropertyName = "Modified",
Header = "Modified",
Width = "150",
Format = "{0:yyyy-MM-dd HH:mm}"
}
},
Actions = new List<ResultAction>
{
new ResultAction { Id = "open", Name = "Open", Icon = "??" }
}
};
}For complete control over the detail view, create a custom WPF control:
public override DetailViewConfiguration GetDetailViewConfiguration(SearchResult result)
{
return new DetailViewConfiguration
{
ViewType = DetailViewType.Custom
};
}
public override FrameworkElement? CreateCustomDetailView(SearchResult result)
{
// Create a custom panel
var panel = new StackPanel { Margin = new Thickness(10) };
// Title
panel.Children.Add(new TextBlock
{
Text = result.Title,
FontWeight = FontWeights.Bold,
FontSize = 18,
Margin = new Thickness(0, 0, 0, 10)
});
// Description
panel.Children.Add(new TextBlock
{
Text = result.Description,
TextWrapping = TextWrapping.Wrap,
Margin = new Thickness(0, 0, 0, 10)
});
// Metadata as a grid
var grid = new Grid();
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
int row = 0;
foreach (var kvp in result.Metadata)
{
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
var keyText = new TextBlock
{
Text = kvp.Key + ":",
FontWeight = FontWeights.SemiBold,
Margin = new Thickness(0, 2, 10, 2)
};
Grid.SetRow(keyText, row);
Grid.SetColumn(keyText, 0);
grid.Children.Add(keyText);
var valueText = new TextBlock
{
Text = kvp.Value?.ToString() ?? "",
Margin = new Thickness(0, 2, 0, 2)
};
Grid.SetRow(valueText, row);
Grid.SetColumn(valueText, 1);
grid.Children.Add(valueText);
row++;
}
panel.Children.Add(grid);
// Action button
var button = new Button
{
Content = "Open Item",
Padding = new Thickness(20, 8, 20, 8),
Margin = new Thickness(0, 15, 0, 0),
HorizontalAlignment = HorizontalAlignment.Left
};
button.Click += async (s, e) => await ExecuteActionAsync(result, "open");
panel.Children.Add(button);
return panel;
}- Use Metadata: Store all displayable data in
SearchResult.Metadataduring search - Keep Actions Simple: Each action should have a clear, single purpose
- Handle Errors: Wrap action execution in try-catch blocks
- Use Icons: Emojis work well as icons (??, ??, ??, ??, ???)
- Consider Localization: Use constants or resources for action names
For more complex connectors, development as a compiled plugin is recommended.
- Create a new Class Library project in Visual Studio
- Target Framework: .NET 10
- Add a project reference to
MSCC.csproj
using System.Windows;
using MSCC.Connectors;
using MSCC.Models;
namespace MyPlugin
{
public class MyConnector : IDataSourceConnector
{
public string Id => "my-compiled-connector";
public string Name => "My Compiled Connector";
public string Description => "A compiled connector";
public string Version => "1.0.0";
public IEnumerable<ConnectorParameter> ConfigurationParameters => new[]
{
new ConnectorParameter
{
Name = "ConnectionString",
DisplayName = "Connection String",
ParameterType = "string",
IsRequired = true
}
};
private string _connectionString = string.Empty;
public Task<bool> InitializeAsync(Dictionary<string, string> configuration)
{
if (!configuration.TryGetValue("ConnectionString", out var cs))
return Task.FromResult(false);
_connectionString = cs;
return Task.FromResult(true);
}
public Task<bool> TestConnectionAsync()
{
// Implement connection test
return Task.FromResult(!string.IsNullOrEmpty(_connectionString));
}
public async Task<IEnumerable<SearchResult>> SearchAsync(
string searchTerm,
int maxResults = 100,
CancellationToken cancellationToken = default)
{
var results = new List<SearchResult>();
// Implement search logic here
return results;
}
public DetailViewConfiguration GetDetailViewConfiguration(SearchResult result)
{
return new DetailViewConfiguration
{
ViewType = DetailViewType.Default,
Actions = new List<ResultAction>
{
new() { Id = "open", Name = "Open", Icon = "??" }
}
};
}
public FrameworkElement? CreateCustomDetailView(SearchResult result)
{
return null; // Or return custom WPF view
}
public Task<bool> ExecuteActionAsync(SearchResult result, string actionId)
{
// Handle actions
return Task.FromResult(true);
}
public void Dispose()
{
// Release resources
}
}
}Add the connector in DataSourceManager.cs:
public void RegisterDefaultConnectors()
{
RegisterConnector(new FileSystemConnector());
RegisterConnector(new MockDatabaseConnector());
RegisterConnector(new MyConnector()); // Add here
}And in CreateConnectorInstance:
private static IDataSourceConnector? CreateConnectorInstance(IDataSourceConnector template)
{
if (template is FileSystemConnector)
return new FileSystemConnector();
if (template is MockDatabaseConnector)
return new MockDatabaseConnector();
if (template is MyConnector)
return new MyConnector();
// ... rest
}The main interface for all connectors.
| Method/Property | Description |
|---|---|
Id |
Unique identifier of the connector |
Name |
Display name |
Description |
Description |
Version |
Version number |
ConfigurationParameters |
List of configuration parameters |
InitializeAsync() |
Initializes the connector with configuration |
TestConnectionAsync() |
Tests the connection |
SearchAsync() |
Performs a search |
GetDetailViewConfiguration() |
Defines the detail view |
CreateCustomDetailView() |
Creates a custom WPF view |
ExecuteActionAsync() |
Executes an action on a result |
Represents a search result.
| Property | Type | Description |
|---|---|---|
Title |
string | Title of the result |
Description |
string | Description |
SourceName |
string | Name of the data source |
ConnectorId |
string | ID of the connector |
OriginalReference |
string | Reference to original (e.g., file path, URL) |
RelevanceScore |
int | Relevance (0-100) |
Metadata |
Dictionary | Additional properties |
Defines a configuration parameter.
| Property | Description |
|---|---|
Name |
Technical name |
DisplayName |
Display name |
Description |
Description/help text |
ParameterType |
Type: "string", "bool", "int", "path" |
IsRequired |
Required field? |
DefaultValue |
Default value |
Configures the detail view for search results.
| Property | Description |
|---|---|
ViewType |
Type of view: Default, Table, Media, Chart, Custom |
TableColumns |
Column definitions for table view |
Actions |
Available actions |
ChartConfig |
Configuration for charts |
An example of a connector that queries a REST API:
public override async Task<IEnumerable<SearchResult>> SearchAsync(
string searchTerm,
int maxResults = 100,
CancellationToken cancellationToken = default)
{
var results = new List<SearchResult>();
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}");
var response = await client.GetAsync(
$"{_apiUrl}/search?q={Uri.EscapeDataString(searchTerm)}&limit={maxResults}",
cancellationToken);
if (!response.IsSuccessStatusCode)
return results;
var json = await response.Content.ReadAsStringAsync(cancellationToken);
var data = JsonSerializer.Deserialize<ApiResponse>(json);
foreach (var item in data?.Items ?? [])
{
results.Add(new SearchResult
{
Title = item.Title,
Description = item.Summary,
SourceName = Name,
ConnectorId = Id,
OriginalReference = item.Url,
RelevanceScore = (int)(item.Score * 100),
Metadata = new Dictionary<string, object>
{
["Author"] = item.Author,
["Date"] = item.CreatedAt
}
});
}
return results;
}public override async Task<IEnumerable<SearchResult>> SearchAsync(
string searchTerm,
int maxResults = 100,
CancellationToken cancellationToken = default)
{
var results = new List<SearchResult>();
using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync(cancellationToken);
var command = new SqlCommand(
"SELECT TOP (@max) Id, Title, Description FROM Documents WHERE Title LIKE @search",
connection);
command.Parameters.AddWithValue("@max", maxResults);
command.Parameters.AddWithValue("@search", $"%{searchTerm}%");
using var reader = await command.ExecuteReaderAsync(cancellationToken);
while (await reader.ReadAsync(cancellationToken))
{
results.Add(new SearchResult
{
Title = reader.GetString(1),
Description = reader.GetString(2),
SourceName = Name,
ConnectorId = Id,
OriginalReference = reader.GetInt32(0).ToString(),
RelevanceScore = 100
});
}
return results;
}For the AI Search feature, no additional code is needed in connectors. Just ensure your AI API is configured in settings.
cd MSCC.Tests
dotnet testCurrent test coverage: 163 tests
Apache 2.0 License
Pull requests are welcome! Please create an issue first to discuss larger changes.