Skip to content

Commit 1ec3e19

Browse files
Copilottoby
andcommitted
Implement create command with basic functionality
Co-authored-by: toby <[email protected]>
1 parent 776253c commit 1ec3e19

File tree

2 files changed

+231
-6
lines changed

2 files changed

+231
-6
lines changed

publisher

34.3 KB
Binary file not shown.

tools/publisher/main.go

Lines changed: 231 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,93 @@ import (
1616
"github.com/modelcontextprotocol/registry/tools/publisher/auth/github"
1717
)
1818

19+
// Server structure types for JSON generation
20+
type Repository struct {
21+
URL string `json:"url"`
22+
Source string `json:"source"`
23+
}
24+
25+
type VersionDetail struct {
26+
Version string `json:"version"`
27+
}
28+
29+
type EnvironmentVariable struct {
30+
Name string `json:"name"`
31+
Description string `json:"description"`
32+
}
33+
34+
type RuntimeArgument struct {
35+
Description string `json:"description"`
36+
IsRequired bool `json:"is_required"`
37+
Format string `json:"format"`
38+
Value string `json:"value"`
39+
Default string `json:"default"`
40+
Type string `json:"type"`
41+
ValueHint string `json:"value_hint"`
42+
}
43+
44+
type Package struct {
45+
RegistryName string `json:"registry_name"`
46+
Name string `json:"name"`
47+
Version string `json:"version"`
48+
RuntimeHint string `json:"runtime_hint,omitempty"`
49+
RuntimeArguments []RuntimeArgument `json:"runtime_arguments,omitempty"`
50+
EnvironmentVariables []EnvironmentVariable `json:"environment_variables,omitempty"`
51+
}
52+
53+
type ServerJSON struct {
54+
Name string `json:"name"`
55+
Description string `json:"description"`
56+
Repository Repository `json:"repository"`
57+
VersionDetail VersionDetail `json:"version_detail"`
58+
Packages []Package `json:"packages"`
59+
}
60+
1961
func main() {
62+
if len(os.Args) < 2 {
63+
printUsage()
64+
return
65+
}
66+
67+
command := os.Args[1]
68+
switch command {
69+
case "publish":
70+
publishCommand()
71+
case "create":
72+
createCommand()
73+
default:
74+
printUsage()
75+
}
76+
}
77+
78+
func printUsage() {
79+
fmt.Println("MCP Registry Publisher Tool")
80+
fmt.Println()
81+
fmt.Println("Usage:")
82+
fmt.Println(" mcp-publisher publish [flags] Publish a server.json file to the registry")
83+
fmt.Println(" mcp-publisher create [flags] Create a new server.json file")
84+
fmt.Println()
85+
fmt.Println("Use 'mcp-publisher <command> --help' for more information about a command.")
86+
}
87+
88+
func publishCommand() {
89+
publishFlags := flag.NewFlagSet("publish", flag.ExitOnError)
90+
2091
var registryURL string
2192
var mcpFilePath string
2293
var forceLogin bool
2394
var authMethod string
2495

2596
// Command-line flags for configuration
26-
flag.StringVar(&registryURL, "registry-url", "", "URL of the registry (required)")
27-
flag.StringVar(&mcpFilePath, "mcp-file", "", "path to the MCP file (required)")
28-
flag.BoolVar(&forceLogin, "login", false, "force a new login even if a token exists")
29-
flag.StringVar(&authMethod, "auth-method", "github-oauth", "authentication method to use (default: github-oauth)")
97+
publishFlags.StringVar(&registryURL, "registry-url", "", "URL of the registry (required)")
98+
publishFlags.StringVar(&mcpFilePath, "mcp-file", "", "path to the MCP file (required)")
99+
publishFlags.BoolVar(&forceLogin, "login", false, "force a new login even if a token exists")
100+
publishFlags.StringVar(&authMethod, "auth-method", "github-oauth", "authentication method to use (default: github-oauth)")
30101

31-
flag.Parse()
102+
publishFlags.Parse(os.Args[2:])
32103

33104
if registryURL == "" || mcpFilePath == "" {
34-
flag.Usage()
105+
publishFlags.Usage()
35106
return
36107
}
37108

@@ -79,6 +150,95 @@ func main() {
79150
log.Println("Successfully published to registry!")
80151
}
81152

153+
func createCommand() {
154+
createFlags := flag.NewFlagSet("create", flag.ExitOnError)
155+
156+
// Basic server information flags
157+
var name string
158+
var description string
159+
var version string
160+
var repoURL string
161+
var repoSource string
162+
var output string
163+
164+
// Package information flags
165+
var registryName string
166+
var packageName string
167+
var packageVersion string
168+
var runtimeHint string
169+
var execute string
170+
171+
// Repeatable flags
172+
var envVars []string
173+
174+
createFlags.StringVar(&name, "name", "", "Server name (e.g., io.github.owner/repo-name) (required)")
175+
createFlags.StringVar(&name, "n", "", "Server name (shorthand)")
176+
createFlags.StringVar(&description, "description", "", "Server description (required)")
177+
createFlags.StringVar(&description, "d", "", "Server description (shorthand)")
178+
createFlags.StringVar(&version, "version", "1.0.0", "Server version")
179+
createFlags.StringVar(&version, "v", "1.0.0", "Server version (shorthand)")
180+
createFlags.StringVar(&repoURL, "repo-url", "", "Repository URL (required)")
181+
createFlags.StringVar(&repoSource, "repo-source", "github", "Repository source")
182+
createFlags.StringVar(&output, "output", "server.json", "Output file path")
183+
createFlags.StringVar(&output, "o", "server.json", "Output file path (shorthand)")
184+
185+
createFlags.StringVar(&registryName, "registry", "npm", "Package registry name")
186+
createFlags.StringVar(&packageName, "package-name", "", "Package name (defaults to server name)")
187+
createFlags.StringVar(&packageVersion, "package-version", "", "Package version (defaults to server version)")
188+
createFlags.StringVar(&runtimeHint, "runtime-hint", "", "Runtime hint (e.g., docker)")
189+
createFlags.StringVar(&execute, "execute", "", "Command to execute the server")
190+
createFlags.StringVar(&execute, "e", "", "Command to execute the server (shorthand)")
191+
192+
// Custom flag for environment variables
193+
createFlags.Func("env-var", "Environment variable in format NAME:DESCRIPTION (can be repeated)", func(value string) error {
194+
envVars = append(envVars, value)
195+
return nil
196+
})
197+
198+
createFlags.Parse(os.Args[2:])
199+
200+
// Validate required flags
201+
if name == "" {
202+
log.Fatal("Error: --name/-n is required")
203+
}
204+
if description == "" {
205+
log.Fatal("Error: --description/-d is required")
206+
}
207+
if repoURL == "" {
208+
log.Fatal("Error: --repo-url is required")
209+
}
210+
211+
// Set defaults
212+
if packageName == "" {
213+
packageName = name
214+
}
215+
if packageVersion == "" {
216+
packageVersion = version
217+
}
218+
219+
// Create server structure
220+
server := createServerStructure(name, description, version, repoURL, repoSource, registryName, packageName, packageVersion, runtimeHint, execute, envVars)
221+
222+
// Convert to JSON
223+
jsonData, err := json.MarshalIndent(server, "", " ")
224+
if err != nil {
225+
log.Fatalf("Error marshaling JSON: %v", err)
226+
}
227+
228+
// Write to file
229+
err = os.WriteFile(output, jsonData, 0644)
230+
if err != nil {
231+
log.Fatalf("Error writing file: %v", err)
232+
}
233+
234+
log.Printf("Successfully created %s", output)
235+
log.Println("You may need to edit the file to:")
236+
log.Println(" - Add or modify package arguments")
237+
log.Println(" - Set environment variable requirements")
238+
log.Println(" - Add remote server configurations")
239+
log.Println(" - Adjust runtime arguments")
240+
}
241+
82242
// publishToRegistry sends the MCP server details to the registry with authentication
83243
func publishToRegistry(registryURL string, mcpData []byte, token string) error {
84244
// Parse the MCP JSON data
@@ -131,3 +291,68 @@ func publishToRegistry(registryURL string, mcpData []byte, token string) error {
131291
log.Println(string(body))
132292
return nil
133293
}
294+
295+
func createServerStructure(name, description, version, repoURL, repoSource, registryName, packageName, packageVersion, runtimeHint, execute string, envVars []string) ServerJSON {
296+
// Parse environment variables
297+
var environmentVariables []EnvironmentVariable
298+
for _, envVar := range envVars {
299+
parts := strings.SplitN(envVar, ":", 2)
300+
if len(parts) == 2 {
301+
environmentVariables = append(environmentVariables, EnvironmentVariable{
302+
Name: parts[0],
303+
Description: parts[1],
304+
})
305+
} else {
306+
// If no description provided, use a default
307+
environmentVariables = append(environmentVariables, EnvironmentVariable{
308+
Name: parts[0],
309+
Description: fmt.Sprintf("Environment variable for %s", parts[0]),
310+
})
311+
}
312+
}
313+
314+
// Parse execute command to create runtime arguments
315+
var runtimeArguments []RuntimeArgument
316+
if execute != "" {
317+
// Split the execute command into parts
318+
parts := strings.Fields(execute)
319+
if len(parts) > 1 {
320+
// Add each argument as a runtime argument
321+
for i, arg := range parts[1:] {
322+
runtimeArguments = append(runtimeArguments, RuntimeArgument{
323+
Description: fmt.Sprintf("Runtime argument %d", i+1),
324+
IsRequired: false,
325+
Format: "string",
326+
Value: arg,
327+
Default: arg,
328+
Type: "positional",
329+
ValueHint: arg,
330+
})
331+
}
332+
}
333+
}
334+
335+
// Create package
336+
pkg := Package{
337+
RegistryName: registryName,
338+
Name: packageName,
339+
Version: packageVersion,
340+
RuntimeHint: runtimeHint,
341+
RuntimeArguments: runtimeArguments,
342+
EnvironmentVariables: environmentVariables,
343+
}
344+
345+
// Create server structure
346+
return ServerJSON{
347+
Name: name,
348+
Description: description,
349+
Repository: Repository{
350+
URL: repoURL,
351+
Source: repoSource,
352+
},
353+
VersionDetail: VersionDetail{
354+
Version: version,
355+
},
356+
Packages: []Package{pkg},
357+
}
358+
}

0 commit comments

Comments
 (0)