feat: MCP Streamable HTTP server with full tool set
Wire go-sdk Streamable HTTP at /mcp with stamp, verify, hash_report, signup, login, session, create_user. Route global/CID to VeraeTime and local|shared to FileLedger; resolve Authorization bearer via authctx. Flags/env for transport, host, port, require-bearer, URLs, ledger path.
This commit is contained in:
parent
793746fcd0
commit
d379931bd1
1 changed files with 925 additions and 6 deletions
82
cmd/verae-mcp-timestamping-server/main.go
Normal file
82
cmd/verae-mcp-timestamping-server/main.go
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"git.georgelambert.org/marchon/verae-mcp-timestamping-server-go/internal/ledger"
|
||||
"git.georgelambert.org/marchon/verae-mcp-timestamping-server-go/internal/server"
|
||||
"git.georgelambert.org/marchon/verae-mcp-timestamping-server-go/internal/tools"
|
||||
"git.georgelambert.org/marchon/verae-mcp-timestamping-server-go/internal/veraetime"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
transport := flag.String("transport", "streamable-http", "MCP transport: streamable-http or stdio")
|
||||
host := flag.String("host", "127.0.0.1", "HTTP bind host")
|
||||
port := flag.Int("port", 8000, "HTTP bind port (shadow often uses 8001)")
|
||||
flag.Parse()
|
||||
|
||||
cfg := server.LoadConfig(*transport, *host, *port)
|
||||
|
||||
led, err := ledger.Open(cfg.LedgerPath)
|
||||
if err != nil {
|
||||
log.Fatalf("ledger: %v", err)
|
||||
}
|
||||
global := veraetime.NewClient(cfg.GlobalURL, veraetime.WithAuthPath(cfg.AuthPath))
|
||||
keeper := veraetime.NewKeeper(global, cfg.AuthPath)
|
||||
|
||||
switch cfg.Transport {
|
||||
case "streamable-http", "http":
|
||||
srv, err := server.New(server.Options{
|
||||
Ledger: led,
|
||||
Global: global,
|
||||
Keeper: keeper,
|
||||
AuthPath: cfg.AuthPath,
|
||||
GlobalURL: cfg.GlobalURL,
|
||||
RequireBearer: cfg.RequireBearer,
|
||||
JSONResponse: true,
|
||||
Stateless: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("server: %v", err)
|
||||
}
|
||||
handler := server.WithCORS(srv.Handler(), cfg.CORS)
|
||||
httpSrv := &http.Server{Addr: cfg.Addr(), Handler: handler}
|
||||
go func() {
|
||||
log.Printf("verae-mcp-timestamping-server listening on http://%s/mcp", cfg.Addr())
|
||||
if err := httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatalf("listen: %v", err)
|
||||
}
|
||||
}()
|
||||
waitSignal()
|
||||
_ = httpSrv.Shutdown(context.Background())
|
||||
case "stdio":
|
||||
mcpServer := tools.NewServer(&tools.Deps{
|
||||
Ledger: led,
|
||||
Global: global,
|
||||
Keeper: keeper,
|
||||
RequireBearer: cfg.RequireBearer,
|
||||
})
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
if err := mcpServer.Run(ctx, &mcp.StdioTransport{}); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "stdio: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
default:
|
||||
log.Fatalf("unknown transport %q (use streamable-http or stdio)", cfg.Transport)
|
||||
}
|
||||
}
|
||||
|
||||
func waitSignal() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
|
||||
<-ch
|
||||
}
|
||||
Loading…
Reference in a new issue