-
Notifications
You must be signed in to change notification settings - Fork 117
Expand file tree
/
Copy pathregister.go
More file actions
180 lines (161 loc) · 5.05 KB
/
register.go
File metadata and controls
180 lines (161 loc) · 5.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package cmd
import (
"encoding/json"
"fmt"
"github.com/mcpjungle/mcpjungle/pkg/types"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
"io"
"os"
"path/filepath"
)
var (
registerCmdServerName string
registerCmdServerURL string
registerCmdServerDesc string
registerCmdBearerToken string
registerCmdServerConfigFilePath string
)
var registerMCPServerCmd = &cobra.Command{
Use: "register",
Short: "Register an MCP Server",
Long: "Register a MCP Server with the registry.\n" +
"The recommended way is to specify the json configuration file for your server.\n" +
"A config file is required if you want to register an stdio-based mcp server.\n" +
"The flags only allow you to register a streamable http server.\n" +
"\nNOTE: A server's name is unique across mcpjungle and must not contain\nany whitespaces, special characters or multiple consecutive underscores '__'.",
PreRunE: func(cmd *cobra.Command, args []string) error {
// Skip flag validation if config file is provided
if registerCmdServerConfigFilePath != "" {
return nil
}
// Otherwise, validate required flags
if registerCmdServerName == "" {
return fmt.Errorf("either supply a configuration file or set the required flag \"name\"")
}
if registerCmdServerURL == "" {
return fmt.Errorf("required flag \"url\" not set")
}
return nil
},
RunE: runRegisterMCPServer,
Annotations: map[string]string{
"group": string(subCommandGroupBasic),
"order": "2",
},
}
func init() {
registerMCPServerCmd.Flags().StringVar(
®isterCmdServerName,
"name",
"",
"MCP server name",
)
registerMCPServerCmd.Flags().StringVar(
®isterCmdServerURL,
"url",
"",
"URL of the streamable http MCP server (eg- http://localhost:8000/mcp)",
)
registerMCPServerCmd.Flags().StringVar(
®isterCmdServerDesc,
"description",
"",
"Server description",
)
registerMCPServerCmd.Flags().StringVar(
®isterCmdBearerToken,
"bearer-token",
"",
"If provided, MCPJungle will use this token to authenticate with the http MCP server for all requests."+
" This is useful if the MCP server requires static tokens (eg- your API token) for authentication.",
)
registerMCPServerCmd.Flags().StringVarP(
®isterCmdServerConfigFilePath,
"conf",
"c",
"",
"Path to a JSON configuration file for the MCP server.\n"+
"If provided, the mcp server will be registered using the configuration in the file.\n"+
"All other flags will be ignored.",
)
rootCmd.AddCommand(registerMCPServerCmd)
}
func readMcpServerConfig(filePath string) (types.RegisterServerInput, error) {
var input types.RegisterServerInput
f, err := os.Open(filePath)
if err != nil {
return input, fmt.Errorf("failed to open config file: %w", err)
}
defer f.Close()
ext := filepath.Ext(filePath)
switch ext {
case ".yaml", ".yml":
return readMcpServerConfigYaml(f)
case ".json":
return readMcpServerConfigJson(f)
default:
fmt.Println("Unknown server config file extension. Assuming json format.")
return readMcpServerConfigJson(f)
}
}
func readMcpServerConfigJson(reader io.Reader) (types.RegisterServerInput, error) {
var input types.RegisterServerInput
data, err := io.ReadAll(reader)
if err != nil {
return input, fmt.Errorf("failed to read config from config file: %w", err)
}
// Parse JSON config
if err := json.Unmarshal(data, &input); err != nil {
return input, fmt.Errorf("failed to parse config from config file: %w", err)
}
return input, nil
}
func readMcpServerConfigYaml(reader io.Reader) (types.RegisterServerInput, error) {
var input types.RegisterServerInput
data, err := io.ReadAll(reader)
if err != nil {
return input, fmt.Errorf("failed to read config from config file: %w", err)
}
// Parse YAML config
if err := yaml.Unmarshal(data, &input); err != nil {
return input, fmt.Errorf("failed to parse config from config file: %w", err)
}
return input, nil
}
func runRegisterMCPServer(cmd *cobra.Command, args []string) error {
var input types.RegisterServerInput
if registerCmdServerConfigFilePath == "" {
// If no config file is provided, use the flags to create the input for server registration
input = types.RegisterServerInput{
Name: registerCmdServerName,
Transport: string(types.TransportStreamableHTTP),
URL: registerCmdServerURL,
Description: registerCmdServerDesc,
BearerToken: registerCmdBearerToken,
}
} else {
// If a config file is provided, read the configuration from the file
var err error
input, err = readMcpServerConfig(registerCmdServerConfigFilePath)
if err != nil {
return err
}
}
s, err := apiClient.RegisterServer(&input)
if err != nil {
return fmt.Errorf("failed to register server: %w", err)
}
fmt.Printf("Server %s registered successfully!\n", s.Name)
tools, err := apiClient.ListTools(s.Name)
if err != nil {
// if we fail to fetch tool list, fail silently because this is not a must-have output
return nil
}
fmt.Println()
fmt.Println("The following tools are now available from this server:")
for i, tool := range tools {
fmt.Printf("%d. %s: %s\n\n", i+1, tool.Name, tool.Description)
}
return nil
}