v0.x: the mcp feature is a link, and a tool without it ships without go/mcp¶
Spec 0202, the extraction spec 0201's OQ1 deferred.
What changed¶
pkg/cmd/root no longer registers the mcp command. The mcp feature is
a link kind, like keychain: pkg/mcp declares it and contributes the command
to the root when a main blank-imports the package, and nothing else in the
framework imports go/mcp. A binary without the import has no mcp command,
no mcp feature, and neither gitlab.com/phpboyscout/go/mcp nor
github.com/modelcontextprotocol/go-sdk in its build (go version -m on the
binary shows the difference). A tool that links a chat provider still carries
the SDK through go/chat-mcptools, the chat side's tool bridge; that is the
chat module's, not the mcp link's.
The feature defaults on. A manifest that says nothing about mcp still
means MCP is on, as it did before; mcp: false now removes the import rather
than rendering props.Disable(props.McpCmd).
Two smaller changes to the framework's API:
Props.LogLevel(read throughGetLogLevel) is the*slog.LevelVarthe root moves for--debugand the config'slog.level. The root used to keep it privately and pass it to the MCP constructor.setup.SlotRootCommand,setup.RootCommandProviderandsetup.RegisterRootCommandslet any feature hand the root a top-level command;setup.MarkProtocolStdoutmarks a command whose stdout carries a wire protocol, which the root uses to withhold interactive prompts. The root's private feature match for themcpsubtree is gone.
What you need to do¶
A generated project: run gtb regenerate project. It writes
cmd/<name>/mcp.go for a project whose manifest does not disable mcp, and
stops rendering the Disable for one that does. Until you regenerate, the
tool builds but has no mcp command.
A hand-wired tool: add the blank import beside your main:
Omit it deliberately for a build that must carry no MCP surface.
A tool that enables the feature explicitly (props.Enable(props.McpCmd))
must link it too: enabling a feature the binary did not declare is a
construction error (spec 0199 OQ2). Disabling one it did not declare is
ignored, so an existing props.Disable(props.McpCmd) keeps compiling and
doctor lists it as ignored.
A host that called mcp.NewCmdMCP itself is unchanged: the constructor and
its options keep their signatures. Pass p.GetLogLevel() where you passed the
root's level before.
Verifying a build without MCP¶
prints nothing for a binary built without the import.