Repository navigation
feat(mcp): manage project services from an agent with the *_service tools and lich service - #1009
Merged
Merged
Conversation
…ools and lich service An agent can do to a project's services what the Services footer does: list, create, edit, delete, start, stop, force-stop and restart one, start or stop them all, and read its console as it is at the call. A service is named by its name in the project, the caller's own unless one is named; spawn.Project resolves the project to the id the services methods take. services.LiveOutput reads a running service's replay tail, leaving Output as the window reads it: nil while the service runs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
An agent, or a script, can now do to a project's services what the window's Services footer does, over MCP and the CLI.
lich service …)listlist_services(read-only)add <name> <command>create_serviceedit <service>+--name/--command/--start-with-lich[=false]edit_servicedelete <service>delete_servicestart,stop,force-stop,restart <service>start_service,stop_service,force_stop_service,restart_servicestart-all,stop-allstart_all_services,stop_all_servicesoutput <service>read_service_output(read-only)services.Savekeeps names apart. The project defaults to the caller's own, by name or directory path otherwise.spawn.Projectresolves a project the way every spawn call does and returns the id theservices.*methods take; everything else reuses the existingservices.*RPC.services.LiveOutputreturns a running service's replay tail (capped at 2 MiB) at the moment of the call.services.Outputis unchanged: nil while the service runs, which the window's console relies on. The CLI and MCP pick one by the service's state. It is one read, not a stream.Test plan
internal/cli/services_test.go: every verb and the MCP tools over the real dispatcher, with the services methods faked at the RPC boundary and the project resolved by the realspawn.Project(partial edit keeps unset fields, unknown name lists the project's services, another project's same-named service is not reached).internal/services:TestLiveOutputReadsARunningServiceon a real PTY.internal/spawn:spawn.Projectresolves the caller's own and a named project, refuses an unknown one and an unreadable workspace.api/testdata/contract.goldenupdated;TestMCPListsEveryToollists the new tools.gofmt,go vet ./...,go test ./...;-race -count=20on the live-output test;GOOS=darwin|windows go build ./....