mcpkit

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 19, 2026 License: MIT Imports: 0 Imported by: 0

README

MCPKit

Build Status Lint Status Go Report Card Docs Visualization License

A toolkit for building MCP (Model Context Protocol) applications in Go.

Overview

MCPKit wraps the official MCP Go SDK to provide focused packages for building MCP servers:

  • runtime: Core MCP server runtime with tools, prompts, resources, and multiple transport options (stdio, HTTP, SSE)
  • oauth2: OAuth 2.1 Authorization Server with PKCE support for MCP authentication (required by ChatGPT.com)

The runtime package provides a unified API where tools, prompts, and resources are defined once and can be invoked either:

  • Library mode: Direct in-process function calls without JSON-RPC overhead
  • Server mode: Standard MCP transports (stdio, HTTP, SSE)

Installation

go get github.com/agentplexus/mcpkit

Quick Start

Library Mode Example

Use tools directly in your application without MCP transport overhead:

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/agentplexus/mcpkit/runtime"
    "github.com/modelcontextprotocol/go-sdk/mcp"
)

type AddInput struct {
    A int `json:"a"`
    B int `json:"b"`
}

type AddOutput struct {
    Sum int `json:"sum"`
}

func main() {
    rt := runtime.New(&mcp.Implementation{
        Name:    "calculator",
        Version: "v1.0.0",
    }, nil)

    runtime.AddTool(rt, &mcp.Tool{
        Name:        "add",
        Description: "Add two numbers",
    }, func(ctx context.Context, req *mcp.CallToolRequest, in AddInput) (*mcp.CallToolResult, AddOutput, error) {
        return nil, AddOutput{Sum: in.A + in.B}, nil
    })

    // Call tool directly - no JSON-RPC, no transport
    result, err := rt.CallTool(context.Background(), "add", map[string]any{"a": 1, "b": 2})
    if err != nil {
        log.Fatal(err)
    }

    text := result.Content[0].(*mcp.TextContent).Text
    fmt.Println(text) // Output: {"sum":3}
}
Server Mode Example (stdio)

Expose the same tools as an MCP server for Claude Desktop or other MCP clients:

package main

import (
    "context"
    "log"

    "github.com/agentplexus/mcpkit/runtime"
    "github.com/modelcontextprotocol/go-sdk/mcp"
)

type AddInput struct {
    A int `json:"a"`
    B int `json:"b"`
}

type AddOutput struct {
    Sum int `json:"sum"`
}

func main() {
    rt := runtime.New(&mcp.Implementation{
        Name:    "calculator",
        Version: "v1.0.0",
    }, nil)

    runtime.AddTool(rt, &mcp.Tool{
        Name:        "add",
        Description: "Add two numbers",
    }, func(ctx context.Context, req *mcp.CallToolRequest, in AddInput) (*mcp.CallToolResult, AddOutput, error) {
        return nil, AddOutput{Sum: in.A + in.B}, nil
    })

    // Run as MCP server over stdio
    if err := rt.ServeStdio(context.Background()); err != nil {
        log.Fatal(err)
    }
}
Server Mode Example (HTTP)

Expose tools over HTTP with SSE for server-to-client messages:

package main

import (
    "log"
    "net/http"

    "github.com/agentplexus/mcpkit/runtime"
    "github.com/modelcontextprotocol/go-sdk/mcp"
)

func main() {
    rt := runtime.New(&mcp.Implementation{
        Name:    "calculator",
        Version: "v1.0.0",
    }, nil)

    // Register tools...

    http.Handle("/mcp", rt.StreamableHTTPHandler(nil))
    log.Println("MCP server listening on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
HTTP Server with OAuth 2.1 Authentication

For public MCP servers that need authentication (required by ChatGPT.com):

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/agentplexus/mcpkit/runtime"
    "github.com/modelcontextprotocol/go-sdk/mcp"
)

func main() {
    rt := runtime.New(&mcp.Implementation{
        Name:    "my-server",
        Version: "v1.0.0",
    }, nil)

    // Register tools...

    ctx := context.Background()
    result, err := rt.ServeHTTP(ctx, &runtime.HTTPServerOptions{
        Addr: ":8080",
        OAuth2: &runtime.OAuth2Options{
            Users: map[string]string{"admin": "password"},
        },
        OnReady: func(r *runtime.HTTPServerResult) {
            fmt.Printf("MCP endpoint: %s\n", r.LocalURL)
            fmt.Printf("OAuth2 Client ID: %s\n", r.OAuth2.ClientID)
            fmt.Printf("OAuth2 Client Secret: %s\n", r.OAuth2.ClientSecret)
        },
    })
    if err != nil {
        log.Fatal(err)
    }
    _ = result
}

Design Philosophy

MCP (Model Context Protocol) is fundamentally a client-server protocol based on JSON-RPC. However, many use cases benefit from invoking MCP capabilities directly in-process:

  • Unit testing without mocking transports
  • Embedding agent capabilities in applications
  • Building local pipelines
  • Serverless runtimes

MCPKit treats MCP as an "edge protocol" while providing a library-first internal API. Tools registered with MCPKit use the exact same handler signatures as the MCP SDK, ensuring behavior is identical regardless of execution mode.

Key Features

Same Handlers, Two Modes

Tools, prompts, and resources are defined once using MCP SDK types:

// Register tool
runtime.AddTool(rt, &mcp.Tool{Name: "calculate"}, handler)

// Library mode
result, err := rt.CallTool(ctx, "calculate", args)

// Server mode
rt.ServeStdio(ctx)
Full MCP SDK Compatibility
  • Uses mcp.Tool, mcp.Prompt, mcp.Resource types directly
  • Typed handlers with automatic schema inference via AddTool[In, Out]
  • All MCP transports supported (stdio, HTTP, SSE)
Transport Adapters
// Stdio (subprocess)
rt.ServeStdio(ctx)

// HTTP/SSE
http.Handle("/mcp", rt.StreamableHTTPHandler(nil))

// In-memory (testing)
_, clientSession, _ := rt.InMemorySession(ctx)

Feature Comparison: Library vs Server Mode

Feature Library Mode Server Mode Notes
Tools Yes Yes Full parity
Prompts Yes Yes Full parity
Static Resources Yes Yes Full parity
Resource Templates No Yes See below
JSON-RPC overhead None Yes Library mode is faster
MCP client required No Yes Library mode is standalone
Static vs Dynamic Resource Templates

Static resources have fixed URIs and work identically in both modes:

rt.AddResource(&mcp.Resource{
    URI:  "config://app/settings",
    Name: "settings",
}, handler)

// Library mode
rt.ReadResource(ctx, "config://app/settings")

// Server mode - same handler, MCP protocol

Dynamic resource templates use RFC 6570 URI Template syntax for pattern matching:

rt.AddResourceTemplate(&mcp.ResourceTemplate{
    URITemplate: "file:///{+path}",  // {+path} can contain /
}, handler)

// Matches: file:///docs/readme.md, file:///src/main.go, etc.

Resource templates are registered with the MCP server and work in server mode. Library-mode dispatch (ReadResource) currently supports exact URI matches only. For template matching in library mode, use MCPServer() directly.

Important: The URI scheme (e.g., file:///) is just an identifier—it doesn't mean the resource is on the filesystem. Your handler determines what content is returned:

// This "file:///" resource returns computed content, not filesystem data
rt.AddResourceTemplate(&mcp.ResourceTemplate{
    URITemplate: "file:///{+path}",
}, func(ctx context.Context, req *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
    // You decide: read from disk, database, return hardcoded data, etc.
    return &mcp.ReadResourceResult{
        Contents: []*mcp.ResourceContents{{
            URI:  req.Params.URI,
            Text: "This content is computed, not from a file",
        }},
    }, nil
})

MCP Feature Adoption

Based on MCP ecosystem patterns, feature adoption varies significantly:

Feature Adoption Recommendation
Tools ~80% of servers Primary focus
Static Resources ~50% Use when needed
Prompts ~10-20% Optional
Resource Templates Rare Usually unnecessary

Why tools dominate: Tools perform actions and return results—they cover most use cases. Resources are better suited for data that clients may cache or subscribe to.

Why templates are uncommon:

  1. Tools with parameters are simpler - Instead of file:///{+path}, use a read_file tool with a path parameter
  2. Static resources usually suffice - A few fixed URIs cover most configuration/data needs
  3. Added complexity - Template matching and URI parsing add overhead for little benefit

When to use resource templates:

  • File browsers where URI semantics matter to the client
  • REST-like resource hierarchies
  • When clients need resource-specific features (subscriptions, caching hints)

Package Structure

github.com/agentplexus/mcpkit
├── runtime/     # Core MCP server runtime
│   ├── Runtime type (New, CallTool, ServeStdio, ServeHTTP, etc.)
│   ├── Tool, Prompt, Resource registration
│   └── OAuth options for HTTP serving
├── oauth2/      # OAuth 2.1 Authorization Server
│   ├── Authorization Code Flow with PKCE (RFC 7636)
│   ├── Dynamic Client Registration (RFC 7591)
│   └── Authorization Server Metadata (RFC 8414)
└── doc.go       # Package documentation

API Reference

Runtime Creation
rt := runtime.New(impl *mcp.Implementation, opts *runtime.Options)
Tool Registration
// Generic (with schema inference)
runtime.AddTool(rt, tool *mcp.Tool, handler ToolHandlerFor[In, Out])

// Low-level
rt.AddToolHandler(tool *mcp.Tool, handler mcp.ToolHandler)
Library Mode Invocation
result, err := rt.CallTool(ctx, name string, args any)
result, err := rt.GetPrompt(ctx, name string, args map[string]string)
result, err := rt.ReadResource(ctx, uri string)
Server Mode
rt.ServeStdio(ctx)
rt.ServeIO(ctx, reader, writer)
rt.Serve(ctx, transport)
rt.ServeHTTP(ctx, opts *runtime.HTTPServerOptions) // blocks until context cancelled
rt.StreamableHTTPHandler(opts) // returns http.Handler
rt.SSEHandler(opts)            // returns http.Handler
Inspection
rt.ListTools() []*mcp.Tool
rt.ListPrompts() []*mcp.Prompt
rt.ListResources() []*mcp.Resource
rt.HasTool(name) bool
rt.ToolCount() int

License

MIT License - see LICENSE file for details.

Documentation

Overview

Package mcpkit provides a toolkit for building MCP (Model Context Protocol) applications in Go.

MCPKit is organized into focused subpackages:

  • runtime: Core MCP server runtime with tools, prompts, resources, and multiple transport options (stdio, HTTP, SSE)
  • oauth2: OAuth 2.1 Authorization Server with PKCE support for MCP authentication

Quick Start

For building MCP servers, import the runtime package:

import "github.com/agentplexus/mcpkit/runtime"

rt := runtime.New(&mcp.Implementation{
    Name:    "my-server",
    Version: "1.0.0",
}, nil)

// Add tools, prompts, resources
runtime.AddTool(rt, tool, handler)

// Library mode: call directly
result, err := rt.CallTool(ctx, "add", map[string]any{"a": 1, "b": 2})

// Server mode: serve via HTTP
rt.ServeHTTP(ctx, &runtime.HTTPServerOptions{
    Addr: ":8080",
})

For OAuth 2.1 authentication with PKCE (required by ChatGPT.com and other MCP clients):

import "github.com/agentplexus/mcpkit/oauth2"

srv, err := oauth2.New(&oauth2.Config{
    Issuer: "https://example.com",
    Users:  map[string]string{"admin": "password"},
})

See the individual package documentation for detailed usage.

Design Philosophy

MCP (Model Context Protocol) is fundamentally a client-server protocol based on JSON-RPC. However, many use cases benefit from invoking MCP capabilities directly in-process without the overhead of transport serialization:

  • Unit testing tools without mocking transports
  • Embedding agent capabilities in applications
  • Building local pipelines
  • Serverless runtimes

mcpkit treats MCP as an "edge protocol" while providing a library-first internal API. Tools registered with mcpkit use the exact same handler signatures as the MCP SDK, ensuring behavior is identical regardless of execution mode.

Directories

Path Synopsis
Package oauth2 provides a standalone OAuth 2.1 Authorization Server with PKCE support, designed for MCP server authentication.
Package oauth2 provides a standalone OAuth 2.1 Authorization Server with PKCE support, designed for MCP server authentication.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL