Production-grade MCP (Model Context Protocol) server and client library for Go.
Docs site · Examples · Conformance report · Capabilities · Changelog · Quick Start
import (
"time"
"github.com/panyam/mcpkit/core"
"github.com/panyam/mcpkit/server"
)
srv := server.NewServer(
core.ServerInfo{Name: "my-server", Version: "0.1.0"},
server.WithToolTimeout(30 * time.Second),
)
srv.RegisterTool(core.ToolDef{
Name: "greet", Description: "Say hello",
InputSchema: map[string]any{"type": "object", "properties": map[string]any{"name": map[string]any{"type": "string"}}},
}, func(ctx core.ToolContext, req core.ToolRequest) (core.ToolResponse, error) {
var args struct{ Name string `json:"name"` }
req.Bind(&args)
return core.TextResult("Hello, " + args.Name + "!"), nil
})
srv.Run(":8787") // Streamable HTTP — blocksRun blocks. When you start it in a goroutine, wait for Ready() instead of
sleeping — it closes once the listener is bound and the port is accepting:
go srv.Run(":8787")
<-srv.Ready()
// safe to connect; srv.Addr() has the bound address (useful with ":0")A client mirrors it. Every method that talks to the server takes a context:
ctx := context.Background()
c := client.NewClient("http://localhost:8787/mcp",
core.ClientInfo{Name: "my-client", Version: "0.1.0"},
)
if err := c.Connect(ctx); err != nil { // bounds the handshake, not the session
log.Fatal(err)
}
defer c.Close()
out, err := c.ToolCall(ctx, "greet", map[string]any{"name": "world"})| Package | Import | What |
|---|---|---|
| core | github.com/panyam/mcpkit/core |
Protocol types (Request, ToolDef, Content, Claims) + tool-handler APIs (Sample, Elicit, EmitLog) |
| server | github.com/panyam/mcpkit/server |
Server, Dispatcher, transports (SSE + Streamable HTTP), middleware |
| client | github.com/panyam/mcpkit/client |
Client, HTTP/stdio/command transports, reconnection, logging |
| ext/auth | github.com/panyam/mcpkit/ext/auth |
Separate module: JWT, PRM, OAuth discovery, DCR, CIMD |
| ext/ui | github.com/panyam/mcpkit/ext/ui |
Separate module: MCP Apps extension (UIExtension, RegisterAppTool) |
| ext/tasks | github.com/panyam/mcpkit/ext/tasks |
Separate module: SEP-2663 v2 tasks (long-running / async tool calls) |
| ext/otel | github.com/panyam/mcpkit/ext/otel |
Separate module: SEP-414 OpenTelemetry tracing adapter |
| ext/skills | github.com/panyam/mcpkit/ext/skills |
Separate module: SEP-2640 skills (data-only, served over resource primitives) |
| experimental/ext/events | github.com/panyam/mcpkit/experimental/ext/events |
Separate module: MCP Events protocol (webhooks, polling, streaming) |
| testutil | github.com/panyam/mcpkit/testutil |
TestClient wrapper for e2e tests |
mcpkit passes the official MCP conformance suite for the base protocol and the conformance scenarios for a long list of draft/recent SEPs — the "batteries" that set it apart from a minimal SDK:
| Suite | Spec | Result |
|---|---|---|
| Server (base protocol) | MCP 2025-11-25 | 30/30 scenarios |
| Auth | MCP authorization | 14/14 scenarios |
| MCP Apps | ext-apps | 21 tests |
| Tasks v1 (frozen) | — | 26/27 (1 skipped — SDK-client limitation) |
| Tasks v2 | SEP-2663 | 47/47 (upstream) |
| MRTR | SEP-2322 | 3/3 negative (upstream) |
| Stateless wire | SEP-2575 | 30/30 (upstream) |
| List-TTL | SEP-2549 | 5/5 |
| File-Inputs | SEP-2356 (withdrawn upstream, see below) | 7/7 |
| Skills | SEP-2640 | fixture-driven |
| Keycloak interop | — | 12/12 |
Tasks v2, MRTR, and the SEP-2575 stateless wire all run against modelcontextprotocol/conformance main directly (merged upstream). The full per-SEP rollup is published at panyam.github.io/mcpkit/conformance.
On SEP-2356: the working group closed it on 2026-06-26 in favour of SEP-2631 (File Objects and Transfer), which is still in draft. The file-input surface mcpkit ships and the scenarios above continue to work and are still exercised in CI; the row is kept so the behaviour stays covered, not as a claim of conformance to a live proposal. Migration to SEP-2631 is tracked in issue 827.
Three artifacts describe mcpkit's conformance posture at increasing granularity:
CONFORMANCE.md— auto-generated per-SEP rollup (regenerated on every PR; CI-gated for staleness). Live site.conformance/UPSTREAM_AUDIT.md— per-scenario pass/fail against upstream's full test set (just testconf-upstream-audit). Live site.conformance/AUTH_SPEC_COVERAGE.md— hand-curated per-clause traceability for the auth surface: every MUST/SHOULD → mcpkit impl file:line → test that proves it.
make is the supported task runner and the only one CI uses, so make is
preinstalled everywhere and needs no setup step.
make test # Unit tests (200+ across core/server/client)
make testall # ALL tests + Keycloak + conformance + HTML report
make testconf # MCP conformance suite
make testconfauth # Auth conformance
make test-e2e # E2E tests (auth + apps)
make test-apps-playwright # ext-apps Playwright suite (needs Node.js)Justfiles mirroring the same target names also exist and are kept as an
experiment. They are not used by CI, and make is authoritative when the two
disagree.
| Doc | What |
|---|---|
| Examples gallery | Runnable, batteries-included examples (auth, tasks, apps, tracing, events, skills) — each a guided two-terminal walkthrough. Source under examples/ |
| CHANGELOG.md | Release notes (Keep a Changelog / SemVer); fuller write-ups in docs/releases/ |
| CONTRIBUTING.md | How to build, test, and contribute |
| CLAUDE.md | Quick reference: commands, package structure, gotchas |
| docs/ARCHITECTURE.md | Transport design, type definitions, protocol details |
| docs/PROMPTS.md | Prompts: arguments, content types, listing |
| docs/ELICITATION.md | Elicitation: schemas, SEP-1034 defaults, enums, URL mode |
| docs/COMPLETIONS.md | Argument completion for prompt arguments and resource URI templates |
| ext/auth/docs/DESIGN.md | Auth architecture, spec compliance (C1-C23, X1-X5) |
| docs/APPS_DESIGN.md | MCP Apps extension design, protocol flows, conformance strategy |
Spawn and manage subprocess MCP servers with CommandTransport:
c := client.NewClient("", info,
client.WithCommandTransport("python", []string{"my_server.py"},
client.WithEnv("DEBUG=1"),
client.WithShutdownTimeout(10*time.Second),
),
client.WithMaxRetries(3), // auto-restart on crash
)
c.Connect()
defer c.Close()Inject headers into all outgoing HTTP requests:
c := client.NewClient(url, info,
client.WithModifyRequest(func(req *http.Request) {
req.Header.Set("X-Tenant-ID", "acme")
req.Header.Set("X-Request-ID", uuid.New().String())
}),
)For best performance, configure your authorization server to use ES256 (ECDSA P-256) instead of RS256. ES256 verification is ~10x faster, with smaller keys and tokens. See auth design doc for details.
servicekitv0.1.3 — SSE hub, graceful shutdown, HTTP error typesoneauthv0.1.31 — JWT/OIDC (only viaext/authsub-module)
If mcpkit is useful to you, starring the repo is the cheapest way to help — it's the main signal we use to prioritize what to ship next.