Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

server: support MCP stdio#26062

Open
ngxson wants to merge 10 commits into
masterggml-org/llama.cpp:masterfrom
xsn/server_mcp_stdioggml-org/llama.cpp:xsn/server_mcp_stdioCopy head branch name to clipboard
Open

server: support MCP stdio#26062
ngxson wants to merge 10 commits into
masterggml-org/llama.cpp:masterfrom
xsn/server_mcp_stdioggml-org/llama.cpp:xsn/server_mcp_stdioCopy head branch name to clipboard

Conversation

@ngxson

@ngxson ngxson commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Overview

Support MCP with stdio transport; server accepts MCP JSON definition, spawns and manage subprocess. MCP tools are exposed as server tools.

Supersede #25736

Depends on #26061

Additional information

The core implementation is split into 4 separate classes:

  • server_mcp_server_config: data class, parsed version of mcp.json config file
  • server_mcp_transport: manage high-level JSON-RPC messages
  • server_mcp_stdio: manage low-level pipes and subprocess (no notions of json here, just byte streams)
  • server_mcp: manage all instances of server_mcp_transport

The behavior was designed to match #25736 , but the underlay architecture is different, notably:

  • server_mcp manages everything, even the life-cycle of transports and subprocesses
  • Separation of byte-level stream and JSON-RPC stream
  • Subprocess handling is done by subprocess.h
  • Limited uses of shared_ptr --> stricter life-cycle definition. For example: shutdown() is blocking, no pointers are leaked after going out-of-scope, never have detached threads

TODO:

Requirements

  • I have read and agree with the contributing guidelines
  • AI usage disclosure: yes, steps below:
    1. I ask it to study the behavior of server : add experimental MCP (stdio) server support #25736 (but not to study the code, the goal was to reimpl it from 0 with a clean approach)
    2. I stated existing components that we can reuse: server_pipe, subprocess.h, while introducing design constraints like no redundant shared_ptr or atomics
    3. I ask it to generate the header file first, then I manually review it
    4. Then, I ask it to implement one component at a time; only when I validate the design, that I allow it to move onto the next one

Despite the stated constraints, the model still made some bad assumptions about whether to use shared_ptr / atomic. During the development, I had to point out these and refine the design at each steps.

@pwilkin

pwilkin commented Jul 24, 2026

Copy link
Copy Markdown
Member

@ngxson added a PR (#26075) integrating your architecture with the tests and server integration + fixes for issues that turned up during my branch's testing.

pwilkin and others added 3 commits July 24, 2026 21:19
* server-mcp: harden transport and wire up the tool integration

Builds on the transport/manager architecture (server_mcp_transport + server_pipe)
with the hardening and integration the draft did not yet have.

Hardening:
* Reader and stderr pumps are polled (running-aware) instead of blocking on a read
  that only ends at EOF. subprocess_terminate() SIGKILLs only the direct child, so a
  grandchild the MCP server spawned that inherited the pipe would otherwise keep the
  write end open and hang teardown (both warmup shutdown at startup and process
  shutdown). The writer is likewise non-blocking + polled.
* Windows: resolve the command through PATHEXT so "npx" (npm ships npx.cmd, never
  npx.exe) spawns, matching POSIX's PATH search; and enumerate the parent environment
  as UTF-8 (GetEnvironmentStringsW) instead of the active code page.
* server_pipe gains an opt-in max_size (default unbounded, so the router's streaming
  use is unchanged); the MCP reply queue uses it so a server that streams unsolicited
  notifications between requests cannot grow it without bound.

Integration:
* --mcp-servers-config / --mcp-servers-json flags; enabling MCP restricts default CORS
  to localhost, same as --tools.
* MCP tools are exposed through /tools (and chat-completions) as <server>_<tool>,
  skipping names that collide with a built-in or another MCP tool.
* Manager lifecycle wired into llama_server(): warmup at start, shutdown() from the
  signal handler before the HTTP server drains, blocking teardown in clean_up().
* SIGPIPE ignored so a child dying mid-write yields EPIPE rather than killing us.

Assisted-By: Claude Opus 4.8 <noreply@anthropic.com>

* server-mcp: add MCP test suite with grandchild deadlock regression test

21 tests over the /tools endpoint: tool discovery/invocation, timeouts, crash
recovery and respawn cooldown, warmup partial failure, malformed and batched
notification+response output, tool-definition shape, and prompt shutdown during a
slow call.

The last test spawns an MCP server that leaves a grandchild inheriting its
stdout/stderr and asserts the server both starts and stops promptly. Verified it
fails (5s SIGKILL fallback on a deadlocked reader-join) when the pump is made to
ignore the running flag, and passes with the polled reader.

Assisted-By: Claude Opus 4.8 <noreply@anthropic.com>

* clean up

* clean up 2

* even stricter life cycle

* nits

* nits 2

---------

Co-authored-by: Xuan Son Nguyen <son@huggingface.co>
@ngxson
ngxson marked this pull request as ready for review July 24, 2026 19:38
@ngxson
ngxson requested review from a team as code owners July 24, 2026 19:38
Comment thread tools/server/server.cpp
}

// note: this is guaranteed to out-live ctx_http and tools
server_mcp mcp_mgr;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that the life cycle is very strict now:

  • server_mcp out live everything else
  • tool uses server_mcp, so on-going tool requests is safe while waiting for server_mcp to terminate
  • ctx_http out live tool, so req/res objects are safe to access before tool is destroyed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.