Qt MCP is a Qt-based implementation of the Model Context Protocol, providing client and server libraries for applications that talk to language models and AI tooling.
Qt MCP is developed by Signal Slot Inc. and is not part of the official Qt framework. The recommended way to consume it is through its own CMake package and namespace:
find_package(QtMcp REQUIRED)
target_link_libraries(app PRIVATE QtMcp::Server) # or QtMcp::Client / QtMcp::CommonThe library is built with Qt's module build system, so the same modules are
also reachable as Qt::McpCommon/Qt::McpClient/Qt::McpServer via
find_package(Qt6 COMPONENTS McpServer). That spelling keeps working, but
new code should prefer the QtMcp:: namespace — the library behaves like a
Qt add-on module, but it is maintained independently.
- Supported Protocol Revisions
- Transports
- Requirements
- Building from Source
- Getting Started
- Features
- Project Structure
- Testing
- License
- Contributing
Qt MCP implements every published MCP protocol revision. A server negotiates the revision per session, so a single server can talk to clients of different revisions at the same time; messages are serialized in the wire format of the negotiated revision.
| Revision | Highlights | Status |
|---|---|---|
| 2024-11-05 | Initial protocol | ✅ |
| 2025-03-26 | Audio content, annotations, model hints | ✅ |
| 2025-06-18 | Elicitation, structured tool output, resource links, title/_meta |
✅ |
| 2025-11-25 | Icons, URL mode elicitation, select-style enum schemas, tool calls in sampling | ✅ |
| 2026-07-28 | Stateless lifecycle, server/discover, MRTR, subscriptions/listen, required resultType |
✅ |
The official schemas of all revisions are kept in spec/.
Also implemented:
- Multi Round-Trip Requests (MRTR, 2026-07-28) — a handler that needs
more input calls
QMcpServerSession::requireInput()and answers with aninput_requiredinterim result; the client retries withinputResponses. On the client an interim result raisesQMcpClient::inputRequired. - Tasks extension (
io.modelcontextprotocol/tasks) — enable withQMcpServer::setTasksExtensionEnabled()/QMcpClient::setTasksExtensionEnabled(); long-running tool calls then return a durable task handle polled viatasks/get.
Both the client and the server load their transport as a plugin, selected by name in the constructor:
| Plugin key | Transport | Notes |
|---|---|---|
stdio |
Standard input/output | Server runs as a subprocess of the client |
streamablehttp |
Streamable HTTP | Current HTTP transport; supports both the sessionful (2025-03-26 – 2025-11-25, Mcp-Session-Id) and sessionless (2026-07-28, header validation, subscriptions/listen streams) generations |
sse |
HTTP+SSE | Legacy 2024-11-05 transport, deprecated by the spec since 2025-03-26; kept for compatibility |
- Qt 6.8 or later
- CMake 3.16.0 or later
- C++20 compatible compiler
- Qt Core
- Qt BuildInternals
- Qt Network (for the HTTP transports)
- Qt Gui (for QImage tool results)
- Qt Widgets (for GUI examples)
- Clone the repository:
git clone https://github.com/signal-slot/qtmcp.git
cd qtmcp- Configure and build:
cmake -S . -B build -G Ninja \
-DCMAKE_PREFIX_PATH=/path/to/qt \
-DQT_BUILD_EXAMPLES=ON \
-DQT_BUILD_TESTS=ON
cmake --build build --parallel- Optionally run the tests and install:
ctest --test-dir build --output-on-failure
cmake --install buildA tool is just a Q_INVOKABLE method on your QMcpServer subclass; the
input schema is generated from the method's signature:
#include <QtMcpServer/QMcpServer>
class McpServer : public QMcpServer
{
Q_OBJECT
public:
explicit McpServer(const QString &backend = "stdio", QObject *parent = nullptr)
: QMcpServer(backend, parent) {}
Q_INVOKABLE QString echo(const QString &message) const {
return message;
}
QHash<QString, QString> toolDescriptions() const override {
return { { "echo"_L1, "Echoes back the input"_L1 }
, { "echo/message"_L1, "Message to echo"_L1 } };
}
};
// stdio:
McpServer server("stdio");
server.start();
// or Streamable HTTP:
McpServer server("streamablehttp");
server.start("127.0.0.1:8000");Tools returning QFuture run asynchronously; returning QImage produces
image content. See examples/mcpserver/ for complete programs.
#include <QtMcpClient/QMcpClient>
#include <QtMcpCommon>
QMcpClient client("stdio");
client.start("npx -y @modelcontextprotocol/server-everything");
QMcpInitializeRequest request;
client.request(request, [&](const QMcpInitializeResult &result,
const QMcpJSONRPCErrorError *error) {
// negotiated revision: result.protocolVersion()
client.notify(QMcpInitializedNotification());
});On 2026-07-28 the initialize handshake is no longer part of the protocol;
requests carry the protocol version in their _meta automatically and a
server session initializes itself on first contact.
examples/mcpclient/inspector/— GUI client for exploring servers: connect over any transport, pick a protocol revision, list/call tools, browse resources and prompts.examples/mcpserver/echo/— minimal stdio/HTTP echo server.examples/mcpserver/window/— exposes screenshots and cursor control as tools (QImage results).examples/mcpserver/texteditor/— a QMainWindow text editor controlled via MCP.
- Tools from
Q_INVOKABLEmethods (sync orQFuture-async) with generated JSON schemas, plus resources, resource templates, prompts and subscriptions - Per-session protocol revision negotiation, including the 2026-07-28
stateless lifecycle and
server/discover - Change notifications, gated by
subscriptions/listenopt-ins on 2026-07-28 (tagged with the subscription id) - Elicitation (
QMcpServerSession::elicit(), 2025-06-18 – 2025-11-25) and MRTR (requireInput(), 2026-07-28) - Tasks extension for long-running tool calls
- Typed request/response API over any transport
- Automatic version negotiation and
MCP-Protocol-Versionheader handling - Server-initiated requests (sampling, elicitation) via registered handlers,
or the
inputRequiredsignal on 2026-07-28 x-mcp-headerparameter mirroring on Streamable HTTP
- All 150+ protocol types as implicitly shared Qt gadgets with reflection-based JSON serialization
- Revision-aware serialization: one type definition serves every revision; fields that do not exist in the negotiated revision are dropped on output and ignored on input
.
├── src/
│ ├── mcpcommon/ # Protocol types and revision-aware serialization
│ ├── mcpclient/ # QMcpClient
│ ├── mcpserver/ # QMcpServer, QMcpServerSession
│ └── plugins/
│ ├── mcpclientbackend/ # stdio / sse / streamablehttp
│ └── mcpserverbackend/ # stdio / sse / streamablehttp
├── examples/
├── tests/auto/ # Unit and integration tests
├── spec/ # Official MCP schemas (all revisions)
└── docs/ # Implementation plans and notes
ctest --test-dir build --output-on-failureThe suite covers per-type serialization round trips for every revision, version negotiation, the stateless 2026-07-28 lifecycle, both Streamable HTTP generations, MRTR round trips and task polling. CI runs on Linux, macOS and Windows against Qt 6.8 and the latest Qt release.
Copyright (C) 2025 Signal Slot Inc. Licensed under:
- LGPL-3.0-only OR
- GPL-2.0-only OR
- GPL-3.0-only
Issues and pull requests are welcome on GitHub. For commercial support, contact Signal Slot Inc.
Contributions are covered by the Contributor License Agreement. You accept it once: a check on your first pull request adds a checkbox to the description, and the check passes when you tick it. Later pull requests find that record by themselves.