Skip to content

Commit 8f3ee1d

Browse files
authored
Kr/mcp switch lib (#399)
* Convert to mcp-go * convert rest * fix lint * fix lint
1 parent 83f068a commit 8f3ee1d

3 files changed

Lines changed: 140 additions & 162 deletions

File tree

src/cmd/mcp.go

Lines changed: 134 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package cmd
22

33
import (
4+
"context"
45
"encoding/json"
56

6-
mcp_golang "github.com/metoro-io/mcp-golang"
7-
"github.com/metoro-io/mcp-golang/transport/stdio"
7+
"github.com/mark3labs/mcp-go/mcp"
8+
"github.com/mark3labs/mcp-go/server"
9+
"github.com/rs/zerolog/log"
810
"github.com/spf13/cobra"
911
)
1012

@@ -25,152 +27,155 @@ var mcpCmd = &cobra.Command{
2527
RunE: func(cmd *cobra.Command, args []string) error {
2628
done := make(chan struct{})
2729

28-
// transport := http.NewHTTPTransport("/mcp")
29-
// transport.WithAddr(":8080")
30-
// server := mcp_golang.NewServer(transport)
31-
server := mcp_golang.NewServer(stdio.NewStdioServerTransport())
30+
s := server.NewMCPServer(
31+
"OpsLevel",
32+
"1.0.0",
33+
)
3234

3335
// Register Teams
34-
if err := server.RegisterTool("teams", "Get all the team names, identifiers and metadata for the opslevel account. Teams are owners of other objects in opslevel. Only use this if you need to search all teams.", func(args NullArguments) (*mcp_golang.ToolResponse, error) {
35-
client := getClientGQL()
36-
resp, err := client.ListTeams(nil)
37-
if err != nil {
38-
return nil, err
39-
}
40-
data, err := json.Marshal(resp.Nodes)
41-
if err != nil {
42-
return nil, err
43-
}
44-
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(string(data))), nil
45-
}); err != nil {
46-
panic(err)
47-
}
36+
s.AddTool(
37+
mcp.NewTool("teams",
38+
mcp.WithDescription("Get all the team names, identifiers and metadata for the opslevel account. Teams are owners of other objects in opslevel. Only use this if you need to search all teams.")),
39+
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
40+
client := getClientGQL()
41+
resp, err := client.ListTeams(nil)
42+
if err != nil {
43+
return nil, err
44+
}
45+
data, err := json.Marshal(resp.Nodes)
46+
if err != nil {
47+
return nil, err
48+
}
49+
return mcp.NewToolResultText(string(data)), nil
50+
})
4851

4952
// Register Users
50-
if err := server.RegisterTool("users", "Get all the user names, e-mail addresses and metadata for the opslevel account. Users are the people in opslevel. Only use this if you need to search all users.", func(args NullArguments) (*mcp_golang.ToolResponse, error) {
51-
client := getClientGQL()
52-
resp, err := client.ListUsers(nil)
53-
if err != nil {
54-
return nil, err
55-
}
56-
data, err := json.Marshal(resp.Nodes)
57-
if err != nil {
58-
return nil, err
59-
}
60-
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(string(data))), nil
61-
}); err != nil {
62-
panic(err)
63-
}
53+
s.AddTool(
54+
mcp.NewTool("users", mcp.WithDescription("Get all the user names, e-mail addresses and metadata for the opslevel account. Users are the people in opslevel. Only use this if you need to search all users.")),
55+
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
56+
client := getClientGQL()
57+
resp, err := client.ListUsers(nil)
58+
if err != nil {
59+
return nil, err
60+
}
61+
data, err := json.Marshal(resp.Nodes)
62+
if err != nil {
63+
return nil, err
64+
}
65+
return mcp.NewToolResultText(string(data)), nil
66+
})
6467

6568
// Register Actions
66-
if err := server.RegisterTool("actions", "Get all the information about actions the user can run in the opslevel account", func(args NullArguments) (*mcp_golang.ToolResponse, error) {
67-
client := getClientGQL()
68-
resp, err := client.ListTriggerDefinitions(nil)
69-
if err != nil {
70-
return nil, err
71-
}
72-
data, err := json.Marshal(resp.Nodes)
73-
if err != nil {
74-
return nil, err
75-
}
76-
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(string(data))), nil
77-
}); err != nil {
78-
panic(err)
79-
}
69+
s.AddTool(
70+
mcp.NewTool("actions", mcp.WithDescription("Get all the information about actions the user can run in the opslevel account")),
71+
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
72+
client := getClientGQL()
73+
resp, err := client.ListTriggerDefinitions(nil)
74+
if err != nil {
75+
return nil, err
76+
}
77+
data, err := json.Marshal(resp.Nodes)
78+
if err != nil {
79+
return nil, err
80+
}
81+
return mcp.NewToolResultText(string(data)), nil
82+
})
8083

8184
// Register Filters
82-
if err := server.RegisterTool("filters", "Get all the rubric filter names and which predicates they have for the opslevel account", func(args NullArguments) (*mcp_golang.ToolResponse, error) {
83-
client := getClientGQL()
84-
resp, err := client.ListFilters(nil)
85-
if err != nil {
86-
return nil, err
87-
}
88-
data, err := json.Marshal(resp.Nodes)
89-
if err != nil {
90-
return nil, err
91-
}
92-
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(string(data))), nil
93-
}); err != nil {
94-
panic(err)
95-
}
85+
s.AddTool(
86+
mcp.NewTool("filters", mcp.WithDescription("Get all the rubric filter names and which predicates they have for the opslevel account")),
87+
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
88+
client := getClientGQL()
89+
resp, err := client.ListFilters(nil)
90+
if err != nil {
91+
return nil, err
92+
}
93+
data, err := json.Marshal(resp.Nodes)
94+
if err != nil {
95+
return nil, err
96+
}
97+
return mcp.NewToolResultText(string(data)), nil
98+
})
9699

97100
// Register Components
98-
if err := server.RegisterTool("components", "Get all the components in the opslevel account. Components are objects in opslevel that represent things like apis, libraries, services, frontends, backends, etc.", func(args NullArguments) (*mcp_golang.ToolResponse, error) {
99-
client := getClientGQL()
100-
resp, err := client.ListServices(nil)
101-
if err != nil {
102-
return nil, err
103-
}
104-
var components []LightweightComponent
105-
for _, node := range resp.Nodes {
106-
components = append(components, LightweightComponent{
107-
Id: string(node.Id),
108-
Name: node.Name,
109-
Owner: node.Owner.Alias,
110-
URL: node.HtmlURL,
111-
})
112-
}
113-
data, err := json.Marshal(components)
114-
if err != nil {
115-
return nil, err
116-
}
117-
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(string(data))), nil
118-
}); err != nil {
119-
panic(err)
120-
}
101+
s.AddTool(
102+
mcp.NewTool("components", mcp.WithDescription("Get all the components in the opslevel account. Components are objects in opslevel that represent things like apis, libraries, services, frontends, backends, etc.")),
103+
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
104+
client := getClientGQL()
105+
resp, err := client.ListServices(nil)
106+
if err != nil {
107+
return nil, err
108+
}
109+
var components []LightweightComponent
110+
for _, node := range resp.Nodes {
111+
components = append(components, LightweightComponent{
112+
Id: string(node.Id),
113+
Name: node.Name,
114+
Owner: node.Owner.Alias,
115+
URL: node.HtmlURL,
116+
})
117+
}
118+
data, err := json.Marshal(components)
119+
if err != nil {
120+
return nil, err
121+
}
122+
return mcp.NewToolResultText(string(data)), nil
123+
})
121124

122125
// Register Infra
123-
if err := server.RegisterTool("infrastructure", "Get all the infrastructure in the opslevel account. Infrastructure are objects in opslevel that represent cloud provider resources like vpc, databases, caches, networks, vms, etc.", func(args NullArguments) (*mcp_golang.ToolResponse, error) {
124-
client := getClientGQL()
125-
resp, err := client.ListInfrastructure(nil)
126-
if err != nil {
127-
return nil, err
128-
}
129-
data, err := json.Marshal(resp.Nodes)
130-
if err != nil {
131-
return nil, err
132-
}
133-
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(string(data))), nil
134-
}); err != nil {
135-
panic(err)
136-
}
126+
s.AddTool(
127+
mcp.NewTool("infrastructure", mcp.WithDescription("Get all the infrastructure in the opslevel account. Infrastructure are objects in opslevel that represent cloud provider resources like vpc, databases, caches, networks, vms, etc.")),
128+
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
129+
client := getClientGQL()
130+
resp, err := client.ListInfrastructure(nil)
131+
if err != nil {
132+
return nil, err
133+
}
134+
data, err := json.Marshal(resp.Nodes)
135+
if err != nil {
136+
return nil, err
137+
}
138+
return mcp.NewToolResultText(string(data)), nil
139+
})
137140

138141
// Register Domains
139-
if err := server.RegisterTool("domains", "Get all the domains in the opslevel account. Domains are objects in opslevel that represent a top-level abstraction used to organize and categorize software systems.", func(args NullArguments) (*mcp_golang.ToolResponse, error) {
140-
client := getClientGQL()
141-
resp, err := client.ListDomains(nil)
142-
if err != nil {
143-
return nil, err
144-
}
145-
data, err := json.Marshal(resp.Nodes)
146-
if err != nil {
147-
return nil, err
148-
}
149-
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(string(data))), nil
150-
}); err != nil {
151-
panic(err)
152-
}
142+
s.AddTool(
143+
mcp.NewTool("domains", mcp.WithDescription("Get all the domains in the opslevel account. Domains are objects in opslevel that represent a top-level abstraction used to organize and categorize software systems.")),
144+
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
145+
client := getClientGQL()
146+
resp, err := client.ListDomains(nil)
147+
if err != nil {
148+
return nil, err
149+
}
150+
data, err := json.Marshal(resp.Nodes)
151+
if err != nil {
152+
return nil, err
153+
}
154+
return mcp.NewToolResultText(string(data)), nil
155+
})
153156

154157
// Register Systems
155-
if err := server.RegisterTool("systems", "Get all the systems in the opslevel account. Systems are objects in opslevel that represent a grouping of services or components that act together to serve a business function or process.", func(args NullArguments) (*mcp_golang.ToolResponse, error) {
156-
client := getClientGQL()
157-
resp, err := client.ListSystems(nil)
158-
if err != nil {
159-
return nil, err
160-
}
161-
data, err := json.Marshal(resp.Nodes)
162-
if err != nil {
163-
return nil, err
164-
}
165-
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(string(data))), nil
166-
}); err != nil {
167-
panic(err)
168-
}
169-
170-
if err := server.Serve(); err != nil {
158+
s.AddTool(
159+
mcp.NewTool("systems", mcp.WithDescription("Get all the systems in the opslevel account. Systems are objects in opslevel that represent a grouping of services or components that act together to serve a business function or process.")),
160+
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
161+
client := getClientGQL()
162+
resp, err := client.ListSystems(nil)
163+
if err != nil {
164+
return nil, err
165+
}
166+
data, err := json.Marshal(resp.Nodes)
167+
if err != nil {
168+
return nil, err
169+
}
170+
return mcp.NewToolResultText(string(data)), nil
171+
})
172+
173+
log.Info().Msg("Starting MCP server...")
174+
if err := server.ServeStdio(s); err != nil {
171175
panic(err)
172176
}
173177
<-done
178+
174179
return nil
175180
},
176181
}

src/go.mod

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/gosimple/slug v1.15.0
1212
github.com/itchyny/gojq v0.12.17
1313
github.com/manifoldco/promptui v0.9.0
14-
github.com/metoro-io/mcp-golang v0.9.0
14+
github.com/mark3labs/mcp-go v0.21.0
1515
github.com/mitchellh/mapstructure v1.5.0
1616
github.com/open-policy-agent/opa v0.67.1
1717
github.com/opslevel/opslevel-go/v2024 v2024.12.24
@@ -32,9 +32,7 @@ require (
3232
github.com/OneOfOne/xxhash v1.2.8 // indirect
3333
github.com/ProtonMail/go-crypto v1.1.5 // indirect
3434
github.com/agnivade/levenshtein v1.1.1 // indirect
35-
github.com/bahlo/generic-list-go v0.2.0 // indirect
3635
github.com/beorn7/perks v1.0.1 // indirect
37-
github.com/buger/jsonparser v1.1.1 // indirect
3836
github.com/cespare/xxhash/v2 v2.3.0 // indirect
3937
github.com/chzyer/readline v1.5.1 // indirect
4038
github.com/cloudflare/circl v1.6.0 // indirect
@@ -61,12 +59,10 @@ require (
6159
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
6260
github.com/hasura/go-graphql-client v0.13.1 // indirect
6361
github.com/inconshreveable/mousetrap v1.1.0 // indirect
64-
github.com/invopop/jsonschema v0.12.0 // indirect
6562
github.com/itchyny/timefmt-go v0.1.6 // indirect
6663
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
6764
github.com/kevinburke/ssh_config v1.2.0 // indirect
6865
github.com/leodido/go-urn v1.4.0 // indirect
69-
github.com/mailru/easyjson v0.7.7 // indirect
7066
github.com/mattn/go-colorable v0.1.14 // indirect
7167
github.com/mattn/go-isatty v0.0.20 // indirect
7268
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@@ -88,15 +84,11 @@ require (
8884
github.com/spf13/cast v1.7.1 // indirect
8985
github.com/subosito/gotenv v1.6.0 // indirect
9086
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
91-
github.com/tidwall/gjson v1.18.0 // indirect
92-
github.com/tidwall/match v1.1.1 // indirect
93-
github.com/tidwall/pretty v1.2.1 // indirect
94-
github.com/tidwall/sjson v1.2.5 // indirect
95-
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
9687
github.com/xanzy/ssh-agent v0.3.3 // indirect
9788
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
9889
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
9990
github.com/yashtewari/glob-intersection v0.2.0 // indirect
91+
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
10092
go.opentelemetry.io/otel v1.29.0 // indirect
10193
go.opentelemetry.io/otel/metric v1.29.0 // indirect
10294
go.opentelemetry.io/otel/sdk v1.29.0 // indirect

0 commit comments

Comments
 (0)