Skip to content

LoadMcp

Go · module github.com/muthuishere/toolnexus/golang · SPEC §2 · golang/mcp.go

func LoadMcp(input any, waitFor ...func(Request) (Answer, error)) (*McpSource, error)

Reads MCP server configuration (via ParseMcpConfig), connects to every enabled server — local stdio child processes and remote streamable-HTTP/SSE servers — lists each one’s tools, and converts each into a uniform Tool. A bad server never fails the whole load: it is isolated, logged, and marked failed in McpSource.Status.

Reach for LoadMcp when you want tools from an mcp.json without the rest of the toolkit machinery — no skills, no builtins, no adapters. It is also what CreateToolkit calls internally for its McpConfig option.

All three examples load the shared examples/mcp.json fixture — the same file every port is tested against. It has one enabled local server (everything, spawned via npx, which is not reachable in a hermetic CI sandbox) and one disabled remote server (example-remote). Because npx cannot actually reach the network here, these examples deliberately do not assert that the enabled server connects — they assert what LoadMcp guarantees regardless: the disabled server is skipped, a failed connection is isolated rather than fatal, and a malformed config still errors before any connection is attempted.

1. Load the shared fixture and read per-server status

Section titled “1. Load the shared fixture and read per-server status”
package main
import (
"fmt"
"log"
"os"
"path/filepath"
toolnexus "github.com/muthuishere/toolnexus/golang"
)
func main() {
// TOOLNEXUS_REPO is set by the docs test runner; in your own code just use a path.
fixture := filepath.Join(os.Getenv("TOOLNEXUS_REPO"), "examples", "mcp.json")
src, err := toolnexus.LoadMcp(fixture)
if err != nil {
log.Fatal(err)
}
defer src.Close()
// The disabled remote server never gets a connection attempt.
if src.Status["example-remote"] != toolnexus.StatusDisabled {
log.Fatalf("expected example-remote disabled, got %v", src.Status["example-remote"])
}
// The enabled local server has SOME status — connected or failed, sandbox-dependent —
// but it is never silently absent from Status.
status, ok := src.Status["everything"]
if !ok {
log.Fatal("expected a status entry for 'everything'")
}
fmt.Println("ok: example-remote=disabled, everything=", status)
}

Two servers in one config: one that can never start (command points at a binary that does not exist) and one that is disabled. LoadMcp still returns successfully — the failure is reported per server, not as a returned error.

package main
import (
"fmt"
"log"
toolnexus "github.com/muthuishere/toolnexus/golang"
)
func main() {
config := toolnexus.McpConfig{
"broken": toolnexus.ServerConfig{
Type: "local",
Command: []string{"toolnexus-docs-does-not-exist"},
},
}
src, err := toolnexus.LoadMcp(config)
if err != nil {
log.Fatalf("LoadMcp itself should not fail: %v", err)
}
defer src.Close()
if src.Status["broken"] != toolnexus.StatusFailed {
log.Fatalf("expected 'broken' marked failed, got %v", src.Status["broken"])
}
// A failed server contributes zero tools — the load degrades, it does not abort.
if len(src.Tools) != 0 {
log.Fatalf("expected no tools from a failed server, got %d", len(src.Tools))
}
fmt.Println("ok: broken server isolated as", src.Status["broken"])
}

3. Malformed config fails fast, before any connection

Section titled “3. Malformed config fails fast, before any connection”

LoadMcp calls ParseMcpConfig first — a syntax error in the JSON never reaches the network or spawns a process.

package main
import (
"fmt"
"log"
toolnexus "github.com/muthuishere/toolnexus/golang"
)
func main() {
_, err := toolnexus.LoadMcp([]byte(`{not valid json`))
if err == nil {
log.Fatal("expected a parse error for malformed config")
}
// A well-formed input of an unsupported type is also rejected up front.
if _, err := toolnexus.LoadMcp(42); err == nil {
log.Fatal("expected an error for an unsupported input type")
}
fmt.Println("ok: malformed config rejected before connecting:", err)
}
Parameter Type What it does
input any Anything ParseMcpConfig accepts — path, raw bytes, McpConfig, or map[string]any.
waitFor ...func(Request) (Answer, error) Optional (variadic) host resolver for MCP elicitation (§10). Omit to skip.
Field Type What it holds
McpSource.Tools []Tool Every tool from every successfully connected server, namespaced server_tool.
McpSource.Status map[string]McpStatus Per-server "connected", "disabled", or "failed".
McpSource.Close() func() Disconnects every connected client. Always defer this.
  • LoadMcpWithContext — the ctx-aware load: bound connection time and cancel a slow or hung server without leaking a child process.
  • ListMcpTools — list what each configured server would expose, plus per-server status, without wiring it into a toolkit.
  • ParseMcpConfig — parse and validate config without connecting — the fast fail for a malformed or misspelled server block.
  • ElicitationToRequest — map an MCP server’s elicitation request onto the §10 suspension contract, and map the answer back.
  • CreateToolkit — the aggregator; MCP is one of several sources.