Skip to content

Commit 5841ae7

Browse files
feat: add MCP server integration and update README
1 parent a02e04e commit 5841ae7

File tree

6 files changed

+430
-0
lines changed

6 files changed

+430
-0
lines changed

.gitignore

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Binary
2+
devir
3+
4+
# Go build cache
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
*.test
11+
*.out
12+
13+
# Dependency directories
14+
vendor/
15+
16+
# IDE
17+
.idea/
18+
.vscode/
19+
*.swp
20+
*.swo
21+
*~
22+
23+
# OS
24+
.DS_Store
25+
Thumbs.db
26+
27+
# Debug
28+
debug/
29+
*.log

README.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Devir - Dev Runner CLI
2+
3+
A terminal UI for managing multiple dev services with colored logs, filtering, and MCP integration.
4+
5+
## Features
6+
7+
- **Bubble Tea TUI** - Interactive terminal UI with tabs, viewport, and status bar
8+
- **Colored Logs** - Each service has its own color for easy identification
9+
- **Service Filtering** - View logs from all services or filter by specific service
10+
- **Search** - Filter logs by text pattern
11+
- **Port Management** - Detects ports in use and offers to kill them
12+
- **MCP Server** - Integrate with Claude Code via Model Context Protocol
13+
14+
## Installation
15+
16+
```bash
17+
cd services/devir
18+
go build -o ../../devir .
19+
```
20+
21+
## Usage
22+
23+
### TUI Mode (default)
24+
25+
```bash
26+
# Start all default services
27+
./devir
28+
29+
# Start specific services
30+
./devir admin server
31+
32+
# With filters
33+
./devir --filter "error"
34+
./devir --exclude "hmr"
35+
```
36+
37+
### MCP Server Mode
38+
39+
```bash
40+
./devir --mcp
41+
```
42+
43+
### Keyboard Shortcuts
44+
45+
| Key | Action |
46+
|-----|--------|
47+
| `Tab` | Cycle through services |
48+
| `1-9` | Select specific service |
49+
| `a` | Show all services |
50+
| `/` | Search logs |
51+
| `r` | Restart current service |
52+
| `j/k` | Scroll up/down |
53+
| `q` | Quit |
54+
55+
## Configuration
56+
57+
Create `devir.yaml` in your project root:
58+
59+
```yaml
60+
services:
61+
admin:
62+
dir: apps/admin
63+
cmd: bun run dev
64+
port: 3000
65+
color: blue
66+
67+
server:
68+
dir: server
69+
cmd: bun run dev
70+
port: 3123
71+
color: magenta
72+
73+
defaults:
74+
- admin
75+
- server
76+
```
77+
78+
### Service Options
79+
80+
| Field | Description |
81+
|-------|-------------|
82+
| `dir` | Working directory (relative to config file) |
83+
| `cmd` | Command to run |
84+
| `port` | Port number (for status display) |
85+
| `color` | Log prefix color: `blue`, `green`, `yellow`, `magenta`, `cyan`, `red`, `white` |
86+
87+
## MCP Integration
88+
89+
Add to your project's `.mcp.json`:
90+
91+
```json
92+
{
93+
"mcpServers": {
94+
"devir": {
95+
"command": "/path/to/devir",
96+
"args": ["--mcp", "-c", "/path/to/devir.yaml"]
97+
}
98+
}
99+
}
100+
```
101+
102+
### Available MCP Tools
103+
104+
| Tool | Description |
105+
|------|-------------|
106+
| `devir_start` | Start services |
107+
| `devir_stop` | Stop all services |
108+
| `devir_status` | Get service status |
109+
| `devir_logs` | Get recent logs |
110+
| `devir_restart` | Restart a service |
111+
112+
## Dependencies
113+
114+
- [Bubble Tea](https://github.com/charmbracelet/bubbletea) - TUI framework
115+
- [Lip Gloss](https://github.com/charmbracelet/lipgloss) - Styling
116+
- [MCP Go SDK](https://github.com/modelcontextprotocol/go-sdk) - MCP server
117+
118+
## License
119+
120+
MIT

go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
github.com/charmbracelet/bubbles v0.21.0
77
github.com/charmbracelet/bubbletea v1.3.10
88
github.com/charmbracelet/lipgloss v1.1.0
9+
github.com/modelcontextprotocol/go-sdk v1.2.0
910
gopkg.in/yaml.v3 v3.0.1
1011
)
1112

@@ -17,6 +18,7 @@ require (
1718
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
1819
github.com/charmbracelet/x/term v0.2.1 // indirect
1920
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
21+
github.com/google/jsonschema-go v0.3.0 // indirect
2022
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
2123
github.com/mattn/go-isatty v0.0.20 // indirect
2224
github.com/mattn/go-localereader v0.0.1 // indirect
@@ -26,6 +28,8 @@ require (
2628
github.com/muesli/termenv v0.16.0 // indirect
2729
github.com/rivo/uniseg v0.4.7 // indirect
2830
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
31+
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
32+
golang.org/x/oauth2 v0.30.0 // indirect
2933
golang.org/x/sys v0.39.0 // indirect
3034
golang.org/x/text v0.3.8 // indirect
3135
)

go.sum

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQ
1818
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
1919
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
2020
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
21+
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
22+
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
23+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
24+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
25+
github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q=
26+
github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
2127
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
2228
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
2329
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -26,6 +32,8 @@ github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2J
2632
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
2733
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
2834
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
35+
github.com/modelcontextprotocol/go-sdk v1.2.0 h1:Y23co09300CEk8iZ/tMxIX1dVmKZkzoSBZOpJwUnc/s=
36+
github.com/modelcontextprotocol/go-sdk v1.2.0/go.mod h1:6fM3LCm3yV7pAs8isnKLn07oKtB0MP9LHd3DfAcKw10=
2937
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
3038
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
3139
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
@@ -37,14 +45,20 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
3745
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
3846
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
3947
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
48+
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
49+
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
4050
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
4151
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
52+
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
53+
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
4254
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4355
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4456
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
4557
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
4658
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
4759
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
60+
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
61+
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
4862
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
4963
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
5064
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

main.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ var (
1414
filter string
1515
exclude string
1616
showHelp bool
17+
mcpMode bool
1718
)
1819

1920
func init() {
2021
flag.StringVar(&configFile, "c", "", "Config file path")
2122
flag.StringVar(&filter, "filter", "", "Filter logs by pattern")
2223
flag.StringVar(&exclude, "exclude", "", "Exclude logs matching pattern")
2324
flag.BoolVar(&showHelp, "h", false, "Show help")
25+
flag.BoolVar(&mcpMode, "mcp", false, "Run as MCP server")
2426
}
2527

2628
func main() {
@@ -38,6 +40,18 @@ func main() {
3840
os.Exit(1)
3941
}
4042

43+
// MCP mode
44+
if mcpMode {
45+
mcpServer := NewMCPServer(cfg)
46+
if err := mcpServer.Run(); err != nil {
47+
fmt.Fprintf(os.Stderr, "MCP error: %v\n", err)
48+
os.Exit(1)
49+
}
50+
return
51+
}
52+
53+
// TUI mode continues below...
54+
4155
// Get services to run from args or defaults
4256
services := flag.Args()
4357
if len(services) == 0 {

0 commit comments

Comments
 (0)