Skip to content

viant/mcp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

98 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MCP (Model Context Protocol) for Go

MCP is a Go implementation of the Model Context Protocol — a standardized way for applications to communicate with AI models. It allows developers to seamlessly bridge applications and AI models using a lightweight, JSON-RPC–based protocol.

This repository provides the Go MCP client/server runtime, bridge, and auth helpers. Protocol definitions and schemas live in mcp-protocol.

Official Model Context Protocol Specification

Overview

MCP (Model Context Protocol) is designed to provide a standardized communication layer between applications and AI models. The protocol simplifies the integration of AI capabilities into applications by offering a consistent interface for resource access, prompt management, model interaction, and tool invocation.

Key features:

  • JSON-RPC 2.0–based communication
  • Support for multiple transport protocols (HTTP/SSE, stdio)
  • Server-side features:
    • Resource management
    • Model prompting and completion
    • Tool invocation
    • Subscriptions for resource updates
    • Logging
    • Progress reporting
    • Request cancellation
  • Client-side features:
    • Roots
    • Sampling
    • Elicitation

Architecture

For detailed guides on custom server implementations and authentication, see docs/implementer.md and docs/authentication.md.

MCP is built around the following components:

  1. Transport: JSON-RPC over HTTP/SSE, streamable HTTP, or stdio
  2. Server: Handles incoming requests and dispatches to the protocol implementation
  3. Client: Makes requests to MCP-compatible servers
  4. Protocol Implementation (server.Handler): Provides the actual functionality behind each protocol method

High-Level Architecture

graph LR
    Client[MCP Client] -->|JSON-RPC / HTTP/SSE| Server[MCP Server]
    Server -->|Dispatches to| Handler[MCP Server]
    subgraph Auth[Authentication / Authorization]
      OAuth2[OAuth2 / OIDC]
    end
    Client -.->|Bearer Token| OAuth2
    Server -.->|Token Validation| OAuth2
Loading

Getting Started

Installation

go get github.com/viant/mcp

If you just need to connect existing tools to a remote MCP server you might prefer to use the standalone Bridge binary instead of embedding the Go package. See Bridge Guide for details.

Creating a Server

Quick Start: Default Server

DefaultHandler can be used to quickly set up an MCP server. It provides no-op stubs for all methods, allowing you to focus on implementing only the methods you need. Register handlers inline without writing a custom server type:

package main

import (
  "context"
  "encoding/json"
  "fmt"
  "github.com/viant/jsonrpc"
  "github.com/viant/mcp-protocol/schema"
  serverproto "github.com/viant/mcp-protocol/server"
  "github.com/viant/mcp/server"
  "log"
)

func main() {

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

  type Output struct {
    Result int
  }

  newHandler := serverproto.WithDefaultHandler(context.Background(), func(server *serverproto.DefaultHandler) error {
    // Register a simple resource
    server.RegisterResource(schema.Resource{Name: "hello", Uri: "/hello"},
      func(ctx context.Context, request *schema.ReadResourceRequest) (*schema.ReadResourceResult, *jsonrpc.Error) {
        return &schema.ReadResourceResult{Contents: []schema.ReadResourceResultContentsElem{{Text: "Hello, world!"}}}, nil
      })

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

    type Result struct {
      Result int `json:"acc"`
    }
    // Register a simple calculator tool: adds two integers
    if err := serverproto.RegisterTool[*Addition, *Result](server.Registry, "add", "Add two integers", func(ctx context.Context, input *Addition) (*schema.CallToolResult, *jsonrpc.Error) {
      sum := input.A + input.B
      out := &Result{Result: sum}
      data, err := json.Marshal(out)
      if err != nil {
        return nil, jsonrpc.NewInternalError(fmt.Sprintf("failed to marshal result: %v", err), nil)
      }
      return &schema.CallToolResult{Content: []schema.CallToolResultContentElem{{Text: string(data)}}}, nil
    }); err != nil {
      return err
    }
    return nil
  })

  srv, err := server.New(
    server.WithNewHandler(newHandler),
    server.WithImplementation(schema.Implementation{Name: "default", Version: "1.0"}),
  )
  if err != nil {
    log.Fatalf("Failed to create server: %v", err)
  }

  // Choose one transport (see below). Example: HTTP (SSE by default)
  log.Fatal(srv.HTTP(context.Background(), ":4981").ListenAndServe())

}

Starting the Server

  • Stdio (typical for editor integrations):

    stdioSrv := srv.Stdio(context.Background())
    log.Fatal(stdioSrv.ListenAndServe())
  • HTTP over SSE (default):

    httpSrv := srv.HTTP(context.Background(), ":4981")
    log.Fatal(httpSrv.ListenAndServe())
  • HTTP Streamable (toggle):

    srv.UseStreamableHTTP(true)
    httpSrv := srv.HTTP(context.Background(), ":4981")
    log.Fatal(httpSrv.ListenAndServe())

If you prefer a single configuration object, see NewServer in server.go which accepts transport options and can enable Streamable HTTP based on Transport.Type.

Endpoints and Routing

  • By default, both transports are mounted:
    • SSE: GET /sse and POST /message
    • Streamable HTTP: POST/GET /mcp
  • You can enable root redirect so "/" forwards to the active transport base:
    • WithRootRedirect(true)
  • You can also customize the endpoint paths:
    • WithStreamableURI("/api/mcp")
    • WithSSEURI("/api/sse")
    • WithSSEMessageURI("/api/rpc")

Example:

srv, _ := mcp.New(
  mcp.WithNewHandler(newHandler),
  mcp.WithStreamableURI("/api/mcp"),
  mcp.WithSSEURI("/api/sse"),
  mcp.WithSSEMessageURI("/api/rpc"),
  mcp.WithRootRedirect(true), // redirects "/" to /api/mcp if UseStreamableHTTP(true), else /api/sse
)
srv.UseStreamableHTTP(true)
httpSrv := srv.HTTP(context.Background(), ":4981")
log.Fatal(httpSrv.ListenAndServe())

Add a Resource

Register a readable resource URI and return its content from your handler.

h.RegisterResource(schema.Resource{Name: "hello", Uri: "/hello"},
  func(ctx context.Context, req *schema.ReadResourceRequest) (*schema.ReadResourceResult, *jsonrpc.Error) {
    return &schema.ReadResourceResult{Contents: []schema.ReadResourceResultContentsElem{{Text: "Hello, world!", Uri: req.Params.Uri}}}, nil
  })

To notify clients about updates, emit resources/updated via h.Notifier.

Git-backed Resources

Expose curated repository files by plugging in the resource/git helper:

import resgit "github.com/viant/mcp/resource/git"

cfg := &resgit.Config{
  Repos: []resgit.Repo{
    {
      ID:                "mcp",
      URL:               "https://github.com/viant/mcp.git",
      Roots:             []string{"docs"},
      Include:           []string{"**/*.md"},
      ReadMeOnly:        true,
      ExposeSnapshotZip: true,
    },
  },
}

proto.WithDefaultHandler(ctx, func(h *serverproto.DefaultHandler) error {
  if err := resgit.Register(ctx, h, cfg); err != nil {
    return err
  }
  return nil
})

Clients can now call resources/list to discover URIs like repo://mcp/docs/server_guide.md and resources/read or repo://mcp/snapshot.zip to fetch either trimmed files or the exact snapshot zip (MD5 included via _meta).

Add a Prompt

Expose reusable prompt templates that clients can list and resolve.

prompt := &schema.Prompt{Name: "welcome", Arguments: []schema.PromptArgument{{Name: "name", Required: ptr(true)}}}
h.RegisterPrompts(prompt, func(ctx context.Context, p *schema.GetPromptRequestParams) (*schema.GetPromptResult, *jsonrpc.Error) {
  return &schema.GetPromptResult{Messages: []schema.PromptMessage{{Role: schema.RoleAssistant, Content: schema.TextContent{Type: "text", Text: "Hello, " + p.Arguments["name"] + "!"}}}}, nil
})

See the Server Guide for deeper coverage of resources and prompts.

Further Reading

Creating a Client

You can connect to an MCP server over stdio, HTTP/SSE, or HTTP streamable.

  • SSE client (simple):

    ctx := context.Background()
    sseTransport, _ := sse.New(ctx, "http://localhost:4981/sse")
    cli := client.New("Demo", "1.0", sseTransport)
    if _, err := cli.Initialize(ctx); err != nil { log.Fatal(err) }
    tools, _ := cli.ListTools(ctx, nil)
    fmt.Println("tools:", len(tools.Tools))
  • Streamable client:

    ctx := context.Background()
    streamTransport, _ := streamable.New(ctx, "http://localhost:4981/")
    cli := client.New("Demo", "1.0", streamTransport)
    _, _ = cli.Initialize(ctx)
  • Stdio client (spawn a child process):

    stdioTransport, _ := stdio.New("./your-mcp-server-binary",
      stdio.WithArguments("--flag1", "value"))
    cli := client.New("Demo", "1.0", stdioTransport)
    _, _ = cli.Initialize(context.Background())
  • OAuth2/OIDC (optional):

    See the Authentication section below for creating an http.Client with token handling and passing it to the SSE/streamable transports.

Advanced: If you need automatic reconnect and integrated auth, use the helper mcp.NewClient(handler, *ClientOptions) from the root package, which builds the transport and wires an auth interceptor. Supply a pclient.Handler implementation if your client needs to support server-initiated calls (roots, sampling, elicitation).

Authentication & Authorization Summary

MCP supports transport-agnostic authentication and authorization (HTTP or HTTP-SSE) via OAuth2/OIDC in two modes:

  • Global Resource Protection (spec-based):

    • github.com/viant/mcp/server/auth.AuthServer enforces a Bearer token across all endpoints, except those excluded via ExcludeURI (e.g. /sse).
    • Configure by creating an auth.Service from authorization.Policy and wiring it with: server.WithProtectedResourcesHandler(service.ProtectedResourcesHandler), server.WithAuthorizer(service.Middleware), and server.WithJRPCAuthorizer(service.EnsureAuthorized).
    • Exposes /.well-known/oauth-protected-resource for metadata discovery (RFC 9728).
  • Fine-Grained Tool/Resource Control (experimental):

    • Implements auth.Authorizer in AuthServer.EnsureAuthorized, returning 401 Unauthorized per JSON-RPC request.
    • Configure per-tool/resource metadata via Config.Tools or Config.Tenants in authorization.Policy.
  • Fallback Token Fetching:

    • github.com/viant/mcp/server/auth.FallbackAuth wraps a strict AuthServer.
    • On 401 challenge, fetches tokens via ProtectedResourceTokenSource and optional ID tokens via IdTokenSource, then retries.
    • Create with auth.NewFallbackAuth(strictAuthServer, tokenSource, idTokenSource).
  • Client-Side Support:

    • Use github.com/viant/mcp/client/auth/transport.New with:
      • WithStore(store.Store): handles client config, metadata & token caching.
      • WithAuthFlow(flow.AuthFlow): selects interactive auth flow (e.g., browser PKCE).
    • The RoundTripper automatically:
      1. Handles the initial 401 challenge (WWW-Authenticate header).
      2. Discovers protected resource and auth server metadata.
      3. Acquires tokens and retries the original request with Authorization: Bearer <token>.
  • Example SSE integration:

    rt, _ := transport.New(
        transport.WithStore(myStore),
        transport.WithAuthFlow(flow.NewBrowserFlow()),
    )
    httpClient := &http.Client{Transport: rt}
    sseTransport, _ := sse.New(ctx, "https://myapp.example.com/sse", sse.WithHttpClient(httpClient))
    mcpClient := client.New("MyClient", "1.0", sseTransport, client.WithCapabilities(schema.ClientCapabilities{}))

These features are transport-agnostic and apply equally over HTTP, SSE, or other supported transports.

Protocol Methods

MCP supports the following Server Side methods:

  • initialize - Initialize the connection
  • ping - Check server status
  • resources/list - List available resources
  • resources/read - Read resource contents
  • resources/templates/list - List resource templates
  • resources/subscribe - Subscribe to resource updates
  • resources/unsubscribe - Unsubscribe from resource updates
  • prompts/list - List available prompts
  • prompts/get - Get prompt details
  • tools/list - List available tools
  • tools/call - Call a specific tool
  • complete - Get completions from the model
  • logging/setLevel - Set logging level

MCP supports the following Client Side methods:

  • roots/list - List available roots
    • sampling/createMessage - A standardized way for servers to request LLM sampling (“completions” or “generations”) from language models via clients.
    • elicitation/create - Ask the client to collect additional user input (forms or external links) and return structured content.
    • interaction/create - Initiate a user-interaction request, allowing the server to prompt the user via the client UI.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the Apache License 2.0.

Credits

Author: Adrian Witas

This project is maintained by Viant.

About

Model Context Protocol (MCP) for golang

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages