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 contains the shared protocol definitions and schemas for MCP. It is used by MCP, which provides the actual implementation of the MCP server and client framework.
Official Model Context Protocol Specification
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
For detailed guides on custom server implementations and authentication, see docs/implementer.md and docs/authentication.md.
MCP is built around the following components:
- 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
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
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](docs/bridge.md) for details.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{"default", "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())
}-
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.
- 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())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.
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.
- 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
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).
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.WithClient(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.
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 perform an elicitation (model completion) using provided prompts.interaction/create- Initiate a user-interaction request, allowing the server to prompt the user via the client UI.
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the Apache License 2.0.
Author: Adrian Witas
This project is maintained by Viant.