1. Conduid
  2. Developer Tools
  3. Go SDK
MCP server · Developer Tools

Go SDK

MCP server with Opentelemetry support

Unclaimed last commit 6 months ago mcpobservabilitydevtoolsgoai
54Fair

Scored 20 hours ago · breakdown

About Go SDK

Go SDK is an MCP server published by last9 in the Developer Tools category: mCP server with Opentelemetry support. It has been installed 0 times through Conduid.

The repository has 4 stars and 0 forks, with the last commit 6 months ago. Six months or more without a commit doesn't mean the server is broken, but check the open issues (0) before depending on it in production.

Install

Install
npx mcp-go-sdk

This server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.

Ask AI

Ask AI about Go SDK

Powered by Claude · Grounded in docs

I know everything about Go SDK. Ask me about installation, configuration, usage, or troubleshooting.

Security checks

  • ·README presentNot checked yet.
  • ·License declaredNot checked yet.
  • ·Tests presentNot checked yet.
  • ·Dependencies pinnedNot checked yet.
  • ·No dynamic code executionNot checked yet.
  • !Scoped permissionsDoesn't declare a permission scope. Assume it can do anything its process can.

Releases

v0.1.4v0.1.4 · 14 Aug 2026Changelog 11e5cfd8e2b487da695d6c2aadb9050503dfcabb fix: isolate anonymous stateless MCP clients (#30)
v0.1.3v0.1.3 · 29 Jul 2026Changelog 6a8d55213d6814b3ab7a954159e553009a324b82 chore(deps): bump go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp (#16) 7d65864b56a6ac3b5e0772d235dcd414badae68e chore(deps): bump…
v0.1.2v0.1.2 · 24 Apr 2026Changelog c458f18b81923e544a19f72ec67cfc9ab98948e9 fix(logs): start initialize span before session create for trace_id in logs
v0.1.1v0.1.1 · 24 Apr 2026Changelog 129f68a35144ac0a0eb7df755b591d1760afd661 feat: comprehensive OTel observability for Go MCP servers d60e088716a66621cbb80ca3b1157fb78f358501 fix(logs): thread context through logger calls for trace/span ID correlation…
v0.1.0v0.1.0 · 24 Apr 2026Changelog 9a424fb42b9f7f4c565cf125803429bf5df5ccdb Bump github.com/modelcontextprotocol/go-sdk from 0.3.1 to 1.4.1 (#6) b5176460753a253a21481d0f58b4ac6a3dacc444 Bump github.com/modelcontextprotocol/go-sdk in /examples/http…

README

mcp-go-sdk

MCP servers are black boxes. You ship one, an LLM starts calling it, and you have no idea what's happening inside — which tools fire, how long they take, what fails, why. That's not acceptable in production.

This library fixes it. Wrap your server or client with two lines and get full OpenTelemetry observability: traces, metrics, structured logs — all correlated, all standard.

server, err := mcp.NewServer("my-server", "1.0.0")
client, err := mcp.NewClient("my-agent", "1.0.0")

Set OTEL_EXPORTER_OTLP_ENDPOINT and you're done. No configuration files, no boilerplate, no instrumentation scattered across your handlers.

Installation

go get github.com/last9/mcp-go-sdk

The thirty-second version

package main

import (
    "context"
    "log"

    sdkmcp "github.com/modelcontextprotocol/go-sdk/mcp"
    mcp "github.com/last9/mcp-go-sdk/mcp"
)

type SearchArgs struct {
    Query string `json:"query"`
    Limit int    `json:"limit,omitempty"`
}

func main() {
    server, err := mcp.NewServer("search-server", "1.0.0")
    if err != nil {
        log.Fatal(err)
    }
    defer server.Shutdown(context.Background())

    tool := &sdkmcp.Tool{
        Name:        "search",
        Description: "Search the knowledge base",
    }

    mcp.RegisterInstrumentedTool(server, tool, func(ctx context.Context, req *sdkmcp.CallToolRequest, args SearchArgs) (*sdkmcp.CallToolResult, any, error) {
        // your logic here — untouched, unmodified
        return &sdkmcp.CallToolResult{
            Content: []sdkmcp.Content{&sdkmcp.TextContent{Text: "results..."}},
        }, nil, nil
    })

    if err := server.Serve(context.Background(), &sdkmcp.StdioTransport{}); err != nil {
        log.Fatal(err)
    }
}

Your business logic stays exactly as it was. The instrumentation happens around it, not inside it.

What you actually get

Every tools/call, resources/read, prompts/get, and sampling/createMessage produces a span named after the operation — mcp tools/call search, mcp resources/read, and so on — with attributes that follow the OpenTelemetry GenAI semantic conventions:

gen_ai.system            = mcp
gen_ai.operation.name    = tools/call
gen_ai.tool.name         = search
mcp.tool.name            = search
mcp.server.transport     = stdio
mcp.client.name          = claude-desktop
mcp.operation.status     = success | error

These aren't made-up attribute names. They're the emerging standard for AI observability, which means your traces compose with whatever else you're already shipping to your backend.

Query correlation

When Claude calls three tools in a single reasoning turn, those are three separate RPC calls arriving at your server. Without correlation, you get three unrelated traces. That's useless.

We track the query across calls. All tools invoked during the same LLM turn share a root mcp user_query span. One trace = one reasoning cycle. You see the whole sequence together, in order, with relative timing. That's how you actually debug what an LLM is doing.

Metrics

Metric Type Description
mcp.tool.calls.total Counter Tool invocations
mcp.tool.call.duration.seconds Histogram Tool latency
mcp.tool.errors.total Counter Tool failures
mcp.resource.reads.total Counter Resource reads
mcp.resource.read.duration.seconds Histogram Resource read latency
mcp.prompt.gets.total Counter Prompt fetches
mcp.prompt.get.duration.seconds Histogram Prompt fetch latency
mcp.sampling.creates.total Counter Sampling calls
mcp.sampling.create.duration.seconds Histogram Sampling latency
mcp.server.request.duration.seconds Histogram All operations
mcp.active.sessions Gauge Connected clients right now

Flushed every 10 seconds. Histogram buckets are set to sensible defaults for LLM workloads — not the generic OTel defaults that make P99 charts useless.

Logs

Every log line emitted through log/slog automatically carries trace_id and span_id pulled from context. When a tool fails, you don't grep through logs trying to figure out which trace it belonged to. You click the span, open the correlated logs, and you're there.

Environment variables

# Where to send everything (one endpoint if your collector handles all signals)
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318

# Or per-signal if you need it
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://localhost:4318/v1/metrics
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://localhost:4318/v1/logs

# Who you are
OTEL_SERVICE_NAME=my-mcp-server
OTEL_SERVICE_VERSION=1.0.0
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production

Standard OTel conventions throughout. No proprietary configuration.

Options

The defaults are good. You shouldn't need most of these. But they're here when you do.

server, err := mcp.NewServerWithOptions("my-server", "1.0.0",
    // Strip arguments and URIs from spans — right call for PII-sensitive deployments
    mcp.WithDisableArgCapture(),
    mcp.WithDisableResourceCapture(),
    mcp.WithDisablePromptCapture(),
    mcp.WithDisableSamplingCapture(),

    // Skip entire operation families you don't use
    mcp.WithDisableResources(),
    mcp.WithDisablePrompts(),
    mcp.WithDisableSampling(),

    // Your app already initialized OTel — don't let us clobber it
    mcp.WithSkipProviderInit(),

    // How long before we consider a session or query dead
    mcp.WithSessionTimeout(15 * time.Minute),
    mcp.WithQueryTimeout(5 * time.Minute),

    // Minimum severity that gets exported to OTel Logs
    mcp.WithLogLevel(slog.LevelWarn),
)

WithSkipProviderInit deserves a call-out. If your application already calls otel.SetTracerProvider, use this option. Without it we register our own global providers and you end up with two pipelines fighting each other. With it, we pick up yours and everything goes through one place.

Outbound HTTP

Your tools probably make HTTP calls. Those calls should be children of the tool span, not invisible gaps in your trace. Pass the context and wrap the client:

func handleSearch(ctx context.Context, req *sdkmcp.CallToolRequest, args SearchArgs) (*sdkmcp.CallToolResult, any, error) {
    client := mcp.WithHTTPTracing(&http.Client{Timeout: 10 * time.Second})

    httpReq, _ := http.NewRequestWithContext(ctx, "GET", "https://api.example.com/search", nil)
    resp, err := client.Do(httpReq)
    // ...
}

The full call chain — LLM reasoning turn → tool call → HTTP request — appears as one connected trace. That's what you need to find real latency bottlenecks.

Client instrumentation

Building an agent or orchestrator that calls MCP servers? Instrument the client the same way:

client, err := mcp.NewClient("my-agent", "1.0.0")
if err != nil {
    log.Fatal(err)
}
defer client.Shutdown(context.Background())

session, err := client.Connect(ctx, &sdkmcp.StdioTransport{}, nil)
if err != nil {
    log.Fatal(err)
}

// Every call through the session is automatically traced
result, err := session.CallTool(ctx, &sdkmcp.CallToolParams{
    Name:      "search",
    Arguments: args,
})

Client spans measure total round-trip latency — not just server processing time. Server name and version are populated automatically from the MCP initialize handshake. The same options apply:

client, err := mcp.NewClientWithOptions("my-agent", "1.0.0",
    mcp.WithDisableArgCapture(),
    mcp.WithSkipProviderInit(),
)

If your app already has OTel

Common case for mature services. Hand off your existing providers and we use them:

otel.SetTracerProvider(yourTracerProvider)
otel.SetMeterProvider(yourMeterProvider)

server, err := mcp.NewServerWithOptions("my-server", "1.0.0",
    mcp.WithSkipProviderInit(),
)

No duplicate pipelines. No surprise exporter registrations. Your observability stack stays under your control.

Claude Desktop setup

Point your server binary at a collector by setting env vars in the MCP config (~/Library/Application Support/Claude/claude_desktop_config.json):

{
    "mcpServers": {
        "my-server": {
            "command": "/path/to/your/binary",
            "env": {
                "OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318",
                "OTEL_SERVICE_NAME": "my-mcp-server"
            }
        }
    }
}

Examples

  • stdio server — calculator, data processor, random generator, outbound HTTP
  • HTTP server — streamable HTTP transport with weather, news, and database tools

License

MIT

README mirrored from the source repository 20 hours ago. The original is authoritative.

Questions

About Go SDK

How do I install Go SDK?

Run npx mcp-go-sdk, then add the server to your MCP client's configuration. Conduid has recorded 0 installs, so the command is known to work with current clients.

Is Go SDK safe to use with an AI agent?

Its trust score is 54 out of 100 (fair). It passes 0 of 1 static security checks; the failures are listed above. It has no ConduID identity yet, so agent calls to it are not receipted.

Is Go SDK still maintained?

Yes — the latest release is v0.1.4 (14 Aug 2026), and the last commit was 6 months ago. The repository has 4 stars and 0 open issues.