Skip to content

Add Pi coding agent as a supported MCP client #6736

Description

@hannesro

Add Pi coding agent as a supported MCP client

Summary

Please add Pi, an open-source terminal coding agent, as a supported client for thv client register / thv client setup and the desktop app's Manage Clients dialog.

Since Pi 0.99.0, MCP support is built in. Pi reads servers from a standard mcpServers JSON file, so it fits ToolHive's existing client model with no new config logic. It would be configured much like Cursor, Claude Code and Kimi CLI are today.

Pi's MCP configuration

Docs: https://pi.dev/docs/latest/mcp

  • User config: ~/.pi/agent/mcp.json. The directory can be overridden with PI_CODING_AGENT_DIR.
  • Project config: .pi/mcp.json. Pi only reads it after the user trusts the project.
  • Format: a top-level mcpServers object, the same shape Claude Desktop, Claude Code and Cursor use:
{
  "mcpServers": {
    "fetch": {
      "type": "http",
      "url": "http://127.0.0.1:12345/mcp"
    }
  }
}
  • Transports:
    • stdio (command/args) and streamable HTTP (url).
    • type is optional. When present, it must be stdio, http, or streamable-http.
    • Legacy SSE is not supported. "type": "sse" is rejected and the entry is skipped.
  • Reloading: servers are loaded at session start and on /reload. pi mcp list validates the file and connects to every enabled server, which makes it a handy way to verify a registration.
  • Skills:
    • Pi's own locations: ~/.pi/agent/skills/ (user) and .pi/skills/ (project).
    • Pi also reads the shared Agent Skills locations: ~/.agents/skills/ and .agents/skills/.
  • Binary: pi (npm package @earendil-works/pi-coding-agent).

Proposed clientAppConfig entry

// Pi represents the Pi coding agent.
Pi ClientApp = "pi"

{
    ClientType:           Pi,
    Description:          "Pi coding agent",
    SettingsFile:         "mcp.json",
    MCPServersPathPrefix: "/mcpServers",
    RelPath:              []string{".pi", "agent"},
    Extension:            JSON,
    SupportedTransportTypesMap: map[types.TransportType]string{
        types.TransportTypeStdio:          "http",
        types.TransportTypeStreamableHTTP: "http",
        // SSE intentionally omitted: Pi rejects "type": "sse"
    },
    IsTransportTypeFieldSupported: true,
    MCPServersUrlLabelMap: map[types.TransportType]string{
        types.TransportTypeStdio:          defaultURLFieldName,
        types.TransportTypeSSE:            defaultURLFieldName,
        types.TransportTypeStreamableHTTP: defaultURLFieldName,
    },
    SupportsSkills:    true,
    SkillsGlobalPath:  []string{".pi", "agent", skillsDirName},
    SkillsProjectPath: []string{".pi", skillsDirName},
},

Installation detection would work through the existing IsClientInstalled check, since ~/.pi/agent exists once Pi has been run.

Open questions / notes

  1. SSE workloads: with SSE left out of the transport map, an SSE workload would be written without a type field. Pi would then treat it as streamable HTTP and fail to connect. Should ToolHive skip SSE workloads for this client, or is it acceptable to document that Pi only supports stdio and streamable-HTTP workloads?
  2. Missing config file: ~/.pi/agent/mcp.json doesn't exist until the user adds a server. Is creating it on registration (as {}) the expected behavior, or should users create it first?
  3. PI_CODING_AGENT_DIR: ToolHive could respect this override if set. Other clients don't seem to handle env overrides, so it's probably fine to leave out at first.
  4. MCP-replacing extensions: a Pi extension that registers its own /mcp command (for example the older pi-mcp-adapter) replaces the built-in MCP support, and Pi then ignores mcp.json. This is worth a note in the client compatibility docs.

Scope

This would follow the pattern of #4788 (Kimi CLI) and #2489 (OpenCode):

  • pkg/client/config.go: the new ClientApp constant and config entry.
  • pkg/client/config_test.go and skills_test.go.
  • Regenerated CLI docs (thv_client_register.md, thv_client_remove.md), swagger/OpenAPI, and the Go SDK.
  • A row in the client compatibility page (docs-website).

I'm happy to open the PR if this approach looks good.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageIssue needs initial triage by a maintainer

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions