mirror of
https://github.com/fatedier/frp.git
synced 2026-05-15 08:05:49 -06:00
[PR #5301] plugin/client: add mcp_stdio plugin #5235
Labels
No labels
In Progress
WIP
WaitingForInfo
bug
doc
duplicate
easy
enhancement
future
help wanted
invalid
lifecycle/stale
need-issue-template
need-usage-help
no plan
proposal
pull-request
question
todo
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: github-starred/frp#5235
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/fatedier/frp/pull/5301
Author: @ailenshen
Created: 4/29/2026
Status: 🔄 Open
Base:
dev← Head:feature/mcp-stdio-plugin📝 Commits (3)
5822468plugin/client: add mcp_stdio plugin1f3d55aplugin/client: refactor mcp_stdio to use worker goroutine for child I/O85e9150plugin/client: address mcp_stdio review findings📊 Changes
6 files changed (+665 additions, -1 deletions)
View changed files
📝
README.md(+1 -1)📝
conf/frpc_full_example.toml(+16 -0)📝
pkg/config/v1/proxy_plugin.go(+27 -0)📝
pkg/config/v1/validation/plugin.go(+12 -0)➕
pkg/plugin/client/mcp_stdio.go(+443 -0)➕
pkg/plugin/client/mcp_stdio_test.go(+166 -0)📄 Description
WHY
Most MCP (Model Context Protocol) servers in the wild ship as stdio
binaries —
npx -y @org/mcp-...,uvx ...and similar — and onlyknow how to speak JSON-RPC over stdin/stdout. To make them reachable
by remote MCP clients like Claude Desktop or the Anthropic API today,
you have to run a separate stdio↔HTTP translator (e.g.
mcp-proxy)locally alongside frpc.
This PR adds an
mcp_stdioclient plugin that folds that translationinto frpc itself, so a single frpc process is enough to expose any
number of stdio MCP servers as remote Streamable HTTP endpoints — no
extra translator process and no new runtime dependencies.
What it does
the child's stdin and returns the next stdout line as the HTTP
response. Notifications (frames without an
id) are accepted withHTTP 202 and produce no stdio output.
idleTimeoutSeconds: kill the child after N seconds ofinactivity. The MCP
initializehandshake is cached and replayedwhen the child is respawned, so sessions stay healthy across reaps
and the next spawn picks up any updated package version on its own
(useful with
@lateststyle npx commands).Configuration
```toml
proxies
name = "apple-notes"
type = "tcp"
remotePort = 3101
[proxies.plugin]
type = "mcp_stdio"
command = ["npx", "-y", "@modelcontextprotocol/server-everything"]
idleTimeoutSeconds = 300
```
Tested with
public frps, reachable from Claude Desktop and claude.ai.
and the respawn-with-replay path.
passes.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.