AssistantHub.McpServer is a standalone Voltaic-based MCP server that exposes the AssistantHub management and configuration surface as MCP tools. It connects to an upstream AssistantHub REST server with the C# SDK and uses a small REST proxy for exact REST pass-through cases such as configuration replacement, binary download wrappers, and HEAD-style existence checks.
This document is the source of truth for the MCP surface. For the underlying HTTP API, see REST_API.md. For Claude/Cursor setup guidance, see docs/CLAUDE_MCP.md.
Default transports:
| Transport | Default endpoint | Notes |
|---|---|---|
| HTTP JSON-RPC | http://127.0.0.1:8820/rpc |
Voltaic HTTP transport |
| HTTP events | http://127.0.0.1:8820/events |
Used by the HTTP MCP transport |
| TCP | tcp://127.0.0.1:8821 |
Voltaic TCP transport |
| WebSocket | ws://127.0.0.1:8822/mcp |
Voltaic WebSocket transport |
Container defaults use 0.0.0.0 for the bind host so the ports are reachable outside the container.
Build the solution:
dotnet build src/AssistantHub.slnRun AssistantHub Server:
dotnet run --project src/AssistantHub.Server/AssistantHub.Server.csprojRun the MCP server:
dotnet run --project src/AssistantHub.McpServer/AssistantHub.McpServer.csprojPreview the generated MCP configuration:
dotnet run --project src/AssistantHub.McpServer/AssistantHub.McpServer.csproj -- --showconfigInstall Claude/Cursor snippets from the built MCP server:
cd src/AssistantHub.McpServer/bin/Debug/net10.0
./AssistantHub.McpServer install --dry-run
./AssistantHub.McpServer installDefault config file: assistanthub-mcp.json
Example:
{
"AssistantHub": {
"Endpoint": "http://localhost:8800",
"ApiKey": "default"
},
"Http": {
"Hostname": "127.0.0.1",
"Port": 8820
},
"Tcp": {
"Address": "127.0.0.1",
"Port": 8821
},
"WebSocket": {
"Hostname": "127.0.0.1",
"Port": 8822
},
"Storage": {
"BackupsDirectory": "./backups/",
"TempDirectory": "./temp/",
"MaxInlineBinaryBytes": 5242880
}
}Supported environment overrides:
| Variable | Purpose |
|---|---|
ASSISTANTHUB_ENDPOINT |
Upstream AssistantHub server URL |
ASSISTANTHUB_API_KEY |
Upstream bearer token or admin API key |
MCP_HTTP_HOSTNAME |
HTTP bind host |
MCP_HTTP_PORT |
HTTP bind port |
MCP_TCP_ADDRESS |
TCP bind address |
MCP_TCP_PORT |
TCP bind port |
MCP_WS_HOSTNAME |
WebSocket bind host |
MCP_WS_PORT |
WebSocket bind port |
MCP_CONSOLE_LOGGING |
Console logging toggle |
- Tools use lowercase slash-delimited names.
- CRUD-style tools follow
domain/action. - Sub-resource tools follow
domain/subdomain/action. - HTTP
HEADexistence checks are normalized as*/exists. - Public assistant metadata helpers remain under the
assistant/*namespace.
Examples:
tenant/createassistant/settings/getassistantanalytics/overviewbucket/object/uploadrequesthistory/summaryeval/judge-prompt/default
Redaction is on by default for responses serialized through the MCP helper layer. The redactor masks these property names case-insensitively:
BearerTokenPasswordAdminPasswordDefaultAdminPasswordAdminApiKeysApiKeyApiKeyValueAccessKeySecretKeySlackAppTokenSlackBotToken
Important behaviors:
configuration/getreturns a redacted configuration by default.assistant/settings/getandassistant/settings/updatereturn redacted secret-bearing fields by default.credential/list,credential/get,credential/create, andcredential/updateredact bearer tokens by default.- Set
includeSecrets=trueonly when the caller explicitly needs the raw secret values.
Binary wrappers:
document/uploaddocument/downloadbucket/object/uploadbucket/object/download
Binary contract:
- uploads use
contentBase64 - downloads return
FileName,ContentType,Size,ContentBase64, andSource - default inline size limit is
5242880bytes (Storage.MaxInlineBinaryBytes) - oversized binary payloads return an error instead of an external URL
Streaming status:
- Eval SSE is not exposed through MCP in this release.
- Public assistant chat/generate/compact/feedback/download flows are not exposed through MCP in this release.
- Assistant public document listing is exposed as
assistant/documents/listand mirrorsGET /v1.0/assistants/{assistantId}/documents. Sending attached-document chat requests remains REST-only in this release; sendattached_document_idstoPOST /v1.0/assistants/{assistantId}/chat. - Model-directed runtime tools such as collection search, Verbex search, S3 object reads, and Tavily web search are not exposed as MCP tools for public chat users. Configure assistant tool policy, optional
ToolRoutingInferenceEndpointId, and optional default-offExposeThinkingthrough the REST API, SDKs, or dashboard. Admins can inspect redacted global Tavily readiness throughGET /v1.0/configuration/external-search/statusor the SDK status helpers. When enabled, REST assistant chat executes those tools server-side against explicit OpenAI-compatible or Ollama tool-capable completion endpoints; a dedicated tool-routing endpoint may decide tool calls whileInferenceEndpointIdstill writes final answers. Streaming REST chat can emit safe tool-progress SSE events, including heartbeat events for long-running tool calls, and can emit provider thinking deltas only when the assistant permits it, while MCP remains management-only for this release. - Use the REST API directly for these streaming or interaction-heavy routes.
| Family | Representative tools |
|---|---|
| System | system/health, system/whoami, system/openapi |
| Authentication | auth/authenticate |
| Tenants / Users / Credentials | tenant/*, user/*, credential/* |
| Storage | bucket/*, bucket/object/* |
| Collections | collection/*, collection/record/*, collection/search |
| Indices | index/*, index/record/*, index/search |
| Assistants | assistant/*, assistant/settings/*, assistant/tool-calls/* |
| Documents / Ingestion | document/*, ingestionrule/* |
| Monitoring | history/*, thread/*, requesthistory/*, assistantanalytics/* |
| Endpoint management | embeddingendpoint/*, completionendpoint/*, model/* |
| Crawl | crawlplan/*, crawloperation/* |
| Evaluation | eval/fact/*, eval/run/*, eval/result/get, eval/judge-prompt/default |
| Runtime configuration | configuration/get, configuration/update |
The crawlplan/create and crawlplan/update tools accept a planJson string containing the same CrawlPlan JSON contract used by REST and the SDKs. Supported RepositoryType values are:
| Value | Settings type | Notes |
|---|---|---|
Web |
WebCrawlRepositorySettings |
Uses StartUrl, web authentication fields, link-following settings, sitemap/robots settings, depth, parallelism, and crawl delay. |
CIFS |
CifsCrawlRepositorySettings |
Uses CifsHostname, CifsUsername, CifsPassword, CifsShareName, and IncludeSubdirectories. |
NFS |
NfsCrawlRepositorySettings |
Uses NfsHostname, NfsUserId, NfsGroupId, NfsShareName, NfsVersion, and IncludeSubdirectories. |
CIFS passwords, web passwords, bearer tokens, and API keys are secret-bearing repository settings. MCP responses are redacted by default when serialized through the helper layer; callers should keep includeSecrets=false unless raw settings are explicitly needed.
Example CIFS planJson payload:
{
"Name": "CIFS Share Crawl",
"RepositoryType": "CIFS",
"RepositorySettings": {
"RepositoryType": "CIFS",
"CifsHostname": "fileserver.example.com",
"CifsUsername": "crawler",
"CifsPassword": "secret",
"CifsShareName": "content",
"IncludeSubdirectories": true
}
}Example NFS planJson payload:
{
"Name": "NFS Export Crawl",
"RepositoryType": "NFS",
"RepositorySettings": {
"RepositoryType": "NFS",
"NfsHostname": "nfs.example.com",
"NfsUserId": 1000,
"NfsGroupId": 1000,
"NfsShareName": "/exports/content",
"NfsVersion": "V3",
"IncludeSubdirectories": true
}
}Mapped means there is an MCP tool for the route family. Deferred means the route exists in REST but is intentionally not exposed from the current MCP release.
| REST surface | MCP tools | Status | Notes |
|---|---|---|---|
GET /, HEAD /, GET /openapi.json, GET /v1.0/openapi.json, GET /v1.0/whoami |
system/health, system/openapi, system/whoami |
Mapped | Health/head collapse into system/health; both OpenAPI routes return the same document |
GET /swagger |
None | Deferred | Browser Swagger UI; use system/openapi for the OpenAPI JSON from MCP |
POST /v1.0/authenticate |
auth/authenticate |
Mapped | Useful for diagnosing upstream auth |
tenants CRUD + HEAD |
tenant/list, tenant/get, tenant/create, tenant/update, tenant/delete, tenant/exists |
Mapped | |
tenant-scoped users CRUD + HEAD |
user/list, user/get, user/create, user/update, user/delete, user/exists |
Mapped | REST path is /v1.0/tenants/{tenantId}/users... |
tenant-scoped credentials CRUD + HEAD |
credential/list, credential/get, credential/create, credential/update, credential/delete, credential/exists |
Mapped | REST path is /v1.0/tenants/{tenantId}/credentials...; includeSecrets opt-in |
buckets CRUD + HEAD |
bucket/list, bucket/get, bucket/create, bucket/delete, bucket/exists |
Mapped | |
bucket objects list/put/delete/metadata/download/upload |
bucket/object/put, bucket/object/list, bucket/object/metadata, bucket/object/delete, bucket/object/download, bucket/object/upload |
Mapped | Binary transfers use base64 |
collections CRUD + HEAD + distinct metadata |
collection/list, collection/get, collection/create, collection/update, collection/delete, collection/exists, collection/labels/distinct, collection/tags/distinct |
Mapped | |
collection records list/get/create/delete/batch-delete |
collection/record/list, collection/record/get, collection/record/create, collection/record/delete, collection/record/batch-delete |
Mapped | |
collection search |
collection/search |
Mapped | Marshals RecallDB search requests through AssistantHub |
indices CRUD + HEAD + labels/tags/custom metadata + top terms |
index/list, index/get, index/create, index/update, index/delete, index/exists, index/labels/update, index/tags/update, index/custom-metadata/update, index/terms/top |
Mapped | Marshals Verbex index requests through AssistantHub |
index records list/get/create/batch-create/delete/batch-delete/HEAD/metadata |
index/record/list, index/record/get, index/record/create, index/record/create-batch, index/record/delete, index/record/batch-delete, index/record/exists, index/record/exists-batch, index/record/labels/update, index/record/tags/update, index/record/custom-metadata/update |
Mapped | AssistantHub uses records; Verbex upstream uses documents |
index search |
index/search |
Mapped | Marshals Verbex search requests through AssistantHub |
assistants CRUD + HEAD |
assistant/list, assistant/get, assistant/create, assistant/update, assistant/delete, assistant/exists |
Mapped | |
assistant settings get/update/slack verify + tool policy helpers |
assistant/settings/get, assistant/settings/update, assistant/settings/slack/verify, assistant/settings/tools/list, assistant/settings/tools/validate, assistant/settings/tools/test |
Mapped | includeSecrets opt-in; tool validation and dry-run diagnostics return redacted policy results and stable ErrorCodes by default |
assistant analytics overview/timeseries/stages/endpoints/slowest/feedback |
assistantanalytics/overview, assistantanalytics/timeseries, assistantanalytics/stages, assistantanalytics/endpoints, assistantanalytics/slowest, assistantanalytics/feedback |
Mapped | Uses assistantId plus optional AssistantAnalyticsQuery JSON |
assistant tool-call traces list/get/delete/bulk delete |
assistant/tool-calls/list, assistant/tool-calls/get, assistant/tool-calls/delete, assistant/tool-calls/delete-bulk |
Mapped | Redacted trace records only; supports EnumerationQuery filters for trace, tool, success, denied, chat-history, request-history, and time fields |
assistant public info + public documents + labels/tags |
assistant/public/get, assistant/documents/list, assistant/labels/distinct, assistant/tags/distinct |
Mapped | Public metadata only; document list supports queryJson, text query, and contentType filters |
documents list/get/upload/delete/HEAD/log/download/bulk-delete/reindex |
document/list, document/get, document/upload, document/delete, document/exists, document/processing-log, document/download, document/bulk-delete, document/reindex, document/reindex-batch |
Mapped | Binary transfers use base64; reindex tools backfill Verbex |
ingestion-rules CRUD + HEAD |
ingestionrule/list, ingestionrule/get, ingestionrule/create, ingestionrule/update, ingestionrule/delete, ingestionrule/exists |
Mapped | |
feedback list/get/delete |
feedback/list, feedback/get, feedback/delete |
Mapped | |
history list/get/delete |
history/list, history/get, history/delete |
Mapped | |
threads list/get/create/delete |
thread/list, thread/get, thread/create, thread/delete |
Mapped | |
requesthistory list/summary/get/detail/delete/bulk-delete |
requesthistory/list, requesthistory/summary, requesthistory/get, requesthistory/detail, requesthistory/delete, requesthistory/bulk-delete |
Mapped | |
embedding endpoints CRUD + HEAD + health + test |
embeddingendpoint/list, embeddingendpoint/get, embeddingendpoint/create, embeddingendpoint/update, embeddingendpoint/delete, embeddingendpoint/exists, embeddingendpoint/health, embeddingendpoint/test |
Mapped | |
embedding endpoint load |
None | Deferred | Use REST POST /v1.0/endpoints/embedding/{endpointId}/load |
completion endpoints CRUD + HEAD + health + test |
completionendpoint/list, completionendpoint/get, completionendpoint/create, completionendpoint/update, completionendpoint/delete, completionendpoint/exists, completionendpoint/health, completionendpoint/test |
Mapped | |
completion endpoint load |
None | Deferred | Use REST POST /v1.0/endpoints/completion/{endpointId}/load |
models list/pull/pull-status/delete |
model/list, model/pull, model/pull/status, model/delete |
Mapped | |
crawlplans CRUD + HEAD + start/stop/connectivity/enumerate |
crawlplan/list, crawlplan/get, crawlplan/create, crawlplan/update, crawlplan/delete, crawlplan/exists, crawlplan/start, crawlplan/stop, crawlplan/connectivity, crawlplan/enumerate |
Mapped | |
crawl plan draft connectivity |
None | Deferred | Use REST POST /v1.0/crawlplans/connectivity to test unsaved repository settings |
crawl operations list/get/delete/statistics/enumeration |
crawloperation/list, crawloperation/get, crawloperation/delete, crawloperation/statistics, crawloperation/enumeration |
Mapped | |
eval facts CRUD |
eval/fact/list, eval/fact/get, eval/fact/create, eval/fact/update, eval/fact/delete |
Mapped | |
eval runs create/list/get/delete/results |
eval/run/create, eval/run/list, eval/run/get, eval/run/delete, eval/run/results |
Mapped | |
eval result get + judge prompt |
eval/result/get, eval/judge-prompt/default |
Mapped | |
eval stream |
None | Deferred | Use REST SSE endpoint |
configuration get/update |
configuration/get, configuration/update |
Mapped | configuration/get redacts by default |
Public assistant chat/open, chat, generate, compact, feedback, documents/{id}/download |
None | Deferred | Use REST directly; public document listing is mapped above |
Get runtime OpenAPI from MCP:
{
"tool": "system/openapi",
"arguments": {}
}Get redacted runtime configuration:
{
"tool": "configuration/get",
"arguments": {}
}Create a credential and intentionally return the bearer token:
{
"tool": "credential/create",
"arguments": {
"tenantId": "ten_123",
"credentialJson": "{\"UserId\":\"usr_123\",\"Name\":\"Automation key\",\"Active\":true}",
"includeSecrets": true
}
}Download a document through the MCP wrapper:
{
"tool": "document/download",
"arguments": {
"documentId": "adoc_123"
}
}Reindex one completed document into Verbex:
{
"tool": "document/reindex",
"arguments": {
"documentId": "adoc_123"
}
}Reindex a page of completed documents into Verbex:
{
"tool": "document/reindex-batch",
"arguments": {
"requestJson": "{\"IncludeAlreadyIndexed\":false}",
"queryJson": "{\"MaxResults\":50}"
}
}Search the default Verbex text index:
{
"tool": "index/search",
"arguments": {
"indexId": "default",
"requestJson": "{\"Query\":\"deployment reset\",\"MaxResults\":10,\"IncludeMatchedTerms\":true,\"IncludeTermDetails\":true,\"IncludeDocumentTermStats\":true}"
}
}Search a RecallDB collection:
{
"tool": "collection/search",
"arguments": {
"collectionId": "default",
"requestJson": "{\"Query\":\"deployment reset\",\"MaxResults\":10}"
}
}Focused MCP validation:
$env:ASSISTANTHUB_TEST_SUITES="mcp"
dotnet run --project src/Test.Automated/Test.Automated.csprojPreserve spawned server and MCP artifacts for investigation:
$env:ASSISTANTHUB_TEST_KEEP_ARTIFACTS="1"