- Go 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| bridge | ||
| client | ||
| docs | ||
| example | ||
| internal | ||
| server | ||
| .gitignore | ||
| client.go | ||
| client_auth.go | ||
| client_auth_header_test.go | ||
| client_auth_test.go | ||
| client_delegated_test.go | ||
| client_http_headers_test.go | ||
| client_store_test.go | ||
| doc.go | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| NOTICE | ||
| protocol_2026_streamable_test.go | ||
| README.md | ||
| server.go | ||
| Version | ||
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:
- Transport: JSON-RPC over HTTP/SSE, streamable HTTP, or stdio
- Server: Handles incoming requests and dispatches to the protocol implementation
- Client: Makes requests to MCP-compatible servers
- 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
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 /sseandPOST /message - Streamable HTTP:
POST/GET /mcp
- SSE:
- 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
- Server Implementation Guide: docs/implementer.md
- Server Guide (Tools, Resources, Prompts): docs/server_guide.md
- Authentication Guide: docs/authentication.md
- Bridge (local proxy) Guide: docs/bridge.md
- Client Guide: docs/client.md
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.Clientwith 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.AuthServerenforces a Bearer token across all endpoints, except those excluded viaExcludeURI(e.g./sse).- Configure by creating an
auth.Servicefromauthorization.Policyand wiring it with:server.WithProtectedResourcesHandler(service.ProtectedResourcesHandler),server.WithAuthorizer(service.Middleware), andserver.WithJRPCAuthorizer(service.EnsureAuthorized). - Exposes
/.well-known/oauth-protected-resourcefor metadata discovery (RFC 9728).
-
Fine-Grained Tool/Resource Control (experimental):
- Implements
auth.AuthorizerinAuthServer.EnsureAuthorized, returning401 Unauthorizedper JSON-RPC request. - Configure per-tool/resource metadata via
Config.ToolsorConfig.Tenantsinauthorization.Policy.
- Implements
-
Fallback Token Fetching:
github.com/viant/mcp/server/auth.FallbackAuthwraps a strictAuthServer.- On
401challenge, fetches tokens viaProtectedResourceTokenSourceand optional ID tokens viaIdTokenSource, then retries. - Create with
auth.NewFallbackAuth(strictAuthServer, tokenSource, idTokenSource).
-
Client-Side Support:
- Use
github.com/viant/mcp/client/auth/transport.Newwith:WithStore(store.Store): handles client config, metadata & token caching.WithAuthFlow(flow.AuthFlow): selects interactive auth flow (e.g., browser PKCE).
- The RoundTripper automatically:
- Handles the initial
401challenge (WWW-Authenticate header). - Discovers protected resource and auth server metadata.
- Acquires tokens and retries the original request with
Authorization: Bearer <token>.
- Handles the initial
- Use
-
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 connectionping- Check server statusresources/list- List available resourcesresources/read- Read resource contentsresources/templates/list- List resource templatesresources/subscribe- Subscribe to resource updatesresources/unsubscribe- Unsubscribe from resource updatesprompts/list- List available promptsprompts/get- Get prompt detailstools/list- List available toolstools/call- Call a specific toolcomplete- Get completions from the modellogging/setLevel- Set logging level
MCP supports the following Client Side methods:
roots/list- List available rootssampling/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.