
llmqore
Updated 9d agoby Palm1r
LLMQore
Qt/C++ library for cloud and local LLM providers, MCP clients and servers, and ACP agents.
Streaming deltas arrive as Qt signals on the object's own thread, async results as
QFuture, ownership follows QObject parent-child. Links against Core, Network and
Concurrent.
What it does
- LLM REST API — cloud and local: Claude, OpenAI Chat Completions, OpenAI Responses, Google AI, Mistral, DeepSeek, Qwen, Ollama, llama.cpp; streaming or buffered, images in, reasoning out, token usage, cancellation
- Tool calling — your
BaseToolsubclass, tool loop included, gated byQFuture<bool>if you want - MCP — client and server over stdio, Streamable HTTP or legacy SSE, sharing one tool registry;
mcp-bridgeCLI puts many upstream servers behind one endpoint - Conversation — one history, translated into each provider's shape, portable between them
- ACP host — any agent in the JSON registry; ships Claude Code and Codex
LLM REST API
Ask and await the answer:
auto *client = new LLMQore::ClaudeClient(
"https://api.anthropic.com", apiKey, "claude-sonnet-4-5", this);
client->askOnce("What is Qt?").then(this, [this](const LLMQore::CompletionInfo &result) {
m_view->setPlainText(result.fullText);
});
Or watch it arrive, which is what you want in a chat panel:
connect(client, &LLMQore::BaseClient::accumulatedReceived,
this, [this](const LLMQore::RequestID &, const QString &answer) {
m_view->setPlainText(answer);
});
client->ask("What is Qt?");
accumulatedReceived carries the whole answer so far; chunkReceived carries only the new
delta. Both are emitted on the client's own thread, so a direct connection into a widget or
model is safe.
Tool calling
Expose a function over data the provider cannot see — the open document, the current selection, a local database:
client->tools()->addTool(new SearchCurrentFileTool(client));
conversation.addUser("Where do we handle the timeout?");
client->ask(conversation);
The client drives the loop: the model requests the tool, executeAsync runs, the result is
sent back, the model answers. setMaxToolContinuations() bounds it, ten rounds by default.
toolStarted and toolResultReady report progress; setExecutionGate() gates each call
behind a QFuture<bool>.
MCP
Using external tools
Tools from an MCP server enter the same registry and reach the model through the same tool-definition array:
client->tools()->addMcpServer({.name = "filesystem", .command = "npx",
.arguments = {"-y", "@modelcontextprotocol/server-filesystem", "/home/user"}});
client->tools()->loadMcpServers(QJsonDocument::fromJson(configData).object());
loadMcpServers reads the mcpServers object Claude Desktop uses and returns how many
servers it registered:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"]
}
}
}
Serving your own tools
McpServer::setToolRegistry takes the same ToolsManager the client uses, so one
registration serves both the in-process model and any MCP client that connects:
auto *server = new LLMQore::Mcp::McpServer(
new LLMQore::Mcp::McpHttpServerTransport({.port = 8080, .path = "/mcp"}, this),
cfg, this);
server->setToolRegistry(client->tools());
server->start();
The registry is shared, not copied: a tool added later reaches both sides, and the server
forwards toolsChanged as notifications/tools/list_changed.
Related servers

n8n
Updated todayby n8n-io
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.

mcp-server-fetch
OfficialUpdated 14d agoA Model Context Protocol server providing tools to fetch and convert web content for usage by LLMs

@modelcontextprotocol/server-everything
OfficialUpdated 14d agoMCP server that exercises all the features of the MCP protocol