registry/tools/publisher/main.go
Mingyong Chen d16328e8c1
Rename mcp.json to server.json (#106)
<!-- Provide a brief summary of your changes -->
Rename mcp.json to server.json
## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->

## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->

## Breaking Changes
<!-- Will users need to update their code or configurations? -->

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->
Related to #86

Co-authored-by: Avinash Sridhar <sridharavinash@users.noreply.github.com>
2025-06-03 18:52:46 +00:00

133 lines
3.5 KiB
Go

package main
import (
"bytes"
"context"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
"github.com/modelcontextprotocol/registry/tools/publisher/auth"
"github.com/modelcontextprotocol/registry/tools/publisher/auth/github"
)
func main() {
var registryURL string
var mcpFilePath string
var forceLogin bool
var authMethod string
// Command-line flags for configuration
flag.StringVar(&registryURL, "registry-url", "", "URL of the registry (required)")
flag.StringVar(&mcpFilePath, "mcp-file", "", "path to the MCP file (required)")
flag.BoolVar(&forceLogin, "login", false, "force a new login even if a token exists")
flag.StringVar(&authMethod, "auth-method", "github-oauth", "authentication method to use (default: github-oauth)")
flag.Parse()
if registryURL == "" || mcpFilePath == "" {
flag.Usage()
return
}
// Read MCP file
mcpData, err := os.ReadFile(mcpFilePath)
if err != nil {
log.Printf("Error reading MCP file: %s\n", err.Error())
return
}
var authProvider auth.Provider // Determine the authentication method
switch authMethod {
case "github-oauth":
log.Println("Using GitHub OAuth for authentication")
authProvider = github.NewOAuthProvider(forceLogin, registryURL)
default:
log.Printf("Unsupported authentication method: %s\n", authMethod)
return
}
// Check if login is needed and perform authentication
ctx := context.Background()
if authProvider.NeedsLogin() {
err := authProvider.Login(ctx)
if err != nil {
log.Printf("Failed to authenticate with %s: %s\n", authProvider.Name(), err.Error())
return
}
}
// Get the token
token, err := authProvider.GetToken(ctx)
if err != nil {
log.Printf("Error getting token from %s: %s\n", authProvider.Name(), err.Error())
return
}
// Publish to registry
err = publishToRegistry(registryURL, mcpData, token)
if err != nil {
log.Printf("Failed to publish to registry: %s\n", err.Error())
return
}
log.Println("Successfully published to registry!")
}
// publishToRegistry sends the MCP server details to the registry with authentication
func publishToRegistry(registryURL string, mcpData []byte, token string) error {
// Parse the MCP JSON data
var mcpDetails map[string]interface{}
err := json.Unmarshal(mcpData, &mcpDetails)
if err != nil {
return fmt.Errorf("error parsing server.json file: %w", err)
}
// Create the publish request payload (without authentication)
publishReq := mcpDetails
// Convert the request to JSON
jsonData, err := json.Marshal(publishReq)
if err != nil {
return fmt.Errorf("error serializing request: %w", err)
}
// Ensure the URL ends with the publish endpoint
if !strings.HasSuffix(registryURL, "/") {
registryURL += "/"
}
publishURL := registryURL + "v0/publish"
// Create and send the request
req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, publishURL, bytes.NewBuffer(jsonData))
if err != nil {
return fmt.Errorf("error creating request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("error sending request: %w", err)
}
defer resp.Body.Close()
// Read and check the response
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("error reading response: %w", err)
}
if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
return fmt.Errorf("publication failed with status %d: %s", resp.StatusCode, body)
}
log.Println(string(body))
return nil
}