<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Chen Kun</title>
    <description>The latest articles on DEV Community by Chen Kun (@chen_kun).</description>
    <link>https://dev.to/chen_kun</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3979323%2F41f6770c-02c2-4c87-9611-20506cff5fb9.jpg</url>
      <title>DEV Community: Chen Kun</title>
      <link>https://dev.to/chen_kun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chen_kun"/>
    <language>en</language>
    <item>
      <title>Turn Existing C++ Functions into Claude-Callable MCP Tools</title>
      <dc:creator>Chen Kun</dc:creator>
      <pubDate>Thu, 11 Jun 2026 12:09:05 +0000</pubDate>
      <link>https://dev.to/chen_kun/turn-c-functions-into-claude-callable-mcp-tools-from-prototype-to-production-4m1f</link>
      <guid>https://dev.to/chen_kun/turn-c-functions-into-claude-callable-mcp-tools-from-prototype-to-production-4m1f</guid>
      <description>&lt;h1&gt;
  
  
  Turn Existing C++ Functions into Claude-Callable MCP Tools
&lt;/h1&gt;

&lt;p&gt;Most C++ teams already have valuable business logic: file processing, schedulers, rule engines, protocol handlers, and performance-critical modules.&lt;/p&gt;

&lt;p&gt;When LLM integration starts, many teams add Python/Node wrappers around existing C++ code. That works for demos, but it creates long-term maintenance problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Duplicate implementations across languages&lt;/li&gt;
&lt;li&gt;Behavioral drift between wrappers and native code&lt;/li&gt;
&lt;li&gt;Harder performance tuning and debugging&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This article shows a cleaner path: keep logic in C++, expose it as Claude-callable tools through MCP, and harden the stack for production.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Idea
&lt;/h2&gt;

&lt;p&gt;Do not rewrite your backend.&lt;/p&gt;

&lt;p&gt;Build a thin runtime layer that gives you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Function registration&lt;/li&gt;
&lt;li&gt;JSON invocation&lt;/li&gt;
&lt;li&gt;Tool schema export&lt;/li&gt;
&lt;li&gt;Stateful object lifecycle (&lt;code&gt;create -&amp;gt; method -&amp;gt; destroy&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Concurrency control&lt;/li&gt;
&lt;li&gt;MCP transport (stdio/HTTP)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  30-Second Tool Contract Example
&lt;/h2&gt;

&lt;p&gt;This is more than "JSON calling a function".&lt;br&gt;
It shows the three things a Claude-compatible host needs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A callable tool name&lt;/li&gt;
&lt;li&gt;A JSON argument contract&lt;/li&gt;
&lt;li&gt;Exportable schema metadata
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;json_invoke/json_invoke.hpp&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;json_invoke&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;JsonInvokeAdapterThreadSafe&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;registerFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;json_invoke&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FunctionMetadata&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;"left"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"right"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="s"&gt;"Add two integers."&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s"&gt;"left"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"right"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"result: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getToolSchemaJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Output excerpt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;result: 5

{
    "function": {
        "name": "add",
        "description": "Add two integers.",
        "parameters": {
            "type": "object",
            "properties": {
                "left": { "type": "integer" },
                "right": { "type": "integer" }
            },
            "required": ["left", "right"]
        }
    },
    "type": "function"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this proves:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your C++ logic is callable as a named tool&lt;/li&gt;
&lt;li&gt;Invocation uses stable JSON arguments (not positional ad-hoc payloads)&lt;/li&gt;
&lt;li&gt;Schema is exported for host-side discovery and validation&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How Claude Uses Exported Schema Through MCP
&lt;/h2&gt;

&lt;p&gt;After registration and schema export, the runtime and host interaction typically looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+------------------------------+    +------------------------------+    +------------------------------+
|  Native C++ Tool Runtime     |    |        MCP Server            |    |       LLM Host/Client        |
|  (your existing functions)   |    |  (stdio or HTTP transport)   |    |  (Claude Desktop / Agent)    |
+------------------------------+    +------------------------------+    +------------------------------+

                |                                   |                                   |
                |--(0) register tools + export schema ---------------------&amp;gt;|           |
                |&amp;lt;-(0) MCP tool surface ready (name/args/schema) ----------|            |
                |                                   |                                   |
                |                                   |&amp;lt;--(1) initialize + list_tools ----|
                |                                   |--(2) tool list + JSON schema ----&amp;gt;|
                |                                   |                                   |
                |&amp;lt;--(4) invoke(name,args) ----------|&amp;lt;--(3) tool call ------------------|
                |--(5) run native C++ function ----&amp;gt;|                                   |
                |&amp;lt;-(6) typed result / error --------|                                   |
                |                                   |--(7) tool result ----------------&amp;gt;|
                |                                   |                                   |
                |                                   |&amp;lt;--(8) optional next tool call ----|
                |&amp;lt;--(9) optional invoke ------------|                                   |
                |                                   |--(10) final tool-backed output --&amp;gt;|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is Step 0: how native C++ functions become MCP tools with exported JSON schema.&lt;br&gt;
Steps 1+ are mostly standard MCP host behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Move Beyond Toy Examples
&lt;/h2&gt;

&lt;p&gt;My goal is: help you move existing native C++ functions into real LLM tool workflows with minimal rewriting.&lt;/p&gt;

&lt;p&gt;With this framework, you can expose legacy or production C++ code through a consistent stack that already covers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stateless calls (simple request/response tools)&lt;/li&gt;
&lt;li&gt;Stateful calls (session handle + lifecycle)&lt;/li&gt;
&lt;li&gt;Scheduling and queueing (safe concurrency under load)&lt;/li&gt;
&lt;li&gt;Parallel execution (maximize throughput where safe)&lt;/li&gt;
&lt;li&gt;Task cancellation (stop unnecessary work cleanly)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why This Matters in Practice
&lt;/h2&gt;

&lt;p&gt;For teams shipping real systems, these are not optional extras.&lt;br&gt;
They are the difference between a demo and an operable platform.&lt;/p&gt;

&lt;p&gt;Instead of building one-off wrappers, you can quickly take existing C++ functions and expose them to LLMs through a structured interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layered Architecture You Can Adopt Incrementally
&lt;/h2&gt;

&lt;p&gt;A key strength of this project is its layered design.&lt;br&gt;
You do not need to adopt everything at once.&lt;/p&gt;

&lt;p&gt;You can use lower layers independently when you only need part of the stack, then move upward as requirements grow.&lt;/p&gt;

&lt;p&gt;Typical path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start with function registration&lt;/li&gt;
&lt;li&gt;Add JSON invocation and schema export&lt;/li&gt;
&lt;li&gt;Add session/stateful capabilities&lt;/li&gt;
&lt;li&gt;Add scheduling + concurrency control&lt;/li&gt;
&lt;li&gt;Expose via MCP transport&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This keeps integration cost low while preserving an upgrade path to production-grade behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demos That Map to Real Usage
&lt;/h2&gt;

&lt;p&gt;The repository includes detailed demos that show how each layer is used in practice, from minimal usage to advanced scenarios.&lt;/p&gt;

&lt;p&gt;This helps teams answer practical questions quickly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do I expose an existing function with minimal change?&lt;/li&gt;
&lt;li&gt;How do I model multi-step stateful workflows?&lt;/li&gt;
&lt;li&gt;How do I avoid race conditions with concurrent tool calls?&lt;/li&gt;
&lt;li&gt;How do I evolve from local JSON calls to MCP-hosted tools?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;Project repository:&lt;br&gt;
&lt;a href="https://github.com/writePerfectCode/llm_invoke_cpp" rel="noopener noreferrer"&gt;writePerfectCode/llm_invoke_cpp: Provide a framework enabling LLMs to invoke C++ functions through JSON-based interfaces.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;If your team already has valuable C++ logic, you do not need a rewrite strategy.&lt;br&gt;
You need an exposure strategy.&lt;/p&gt;

&lt;p&gt;This framework gives you that path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Expose native C++ functions quickly&lt;/li&gt;
&lt;li&gt;Keep architecture layered and composable&lt;/li&gt;
&lt;li&gt;Support stateless and stateful scenarios&lt;/li&gt;
&lt;li&gt;Handle scheduling, concurrency, and cancellation&lt;/li&gt;
&lt;li&gt;Connect to LLM hosts through MCP when ready&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is how you turn existing C++ assets into reliable LLM-callable capabilities.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cpp</category>
      <category>mcp</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
