Skip to content

adrianwit/mcp_introduction

Repository files navigation

MCP Guide (Go) — Walkthrough with Examples

This guide walks through building MCP servers in Go using this repository, from a minimal tool to resources, prompts, elicitation, and client-side sampling. The examples are packaged for clarity (usecase/server/cmd) so domain logic is separated from transport wiring.

Quick Start

package main

import (
    "context"
    "encoding/json"
    "log"

    "github.com/viant/jsonrpc"
    proto "github.com/viant/mcp-protocol/server"
    "github.com/viant/mcp-protocol/schema"
    "github.com/viant/mcp/server"
)

func main() {
    // Define a simple tool I/O
    type AddIn struct {
        A int // json:"a"
        B int // json:"b"
        Note *string // json:"note,omitempty" description:"Optional note"
    }
    type AddOut struct { Sum int /* json:"sum" */ }

    // Configure handler and register the tool
    newHandler := proto.WithDefaultHandler(context.Background(), func(h *proto.DefaultHandler) error {
        return proto.RegisterTool[*AddIn, *AddOut](
            h.Registry,
            "add",
            "Add two integers",
            func(ctx context.Context, in *AddIn) (*schema.CallToolResult, *jsonrpc.Error) {
                data, _ := json.Marshal(&AddOut{Sum: in.A + in.B})
                return &schema.CallToolResult{
                    Content: []schema.CallToolResultContentElem{{Text: string(data)}},
                }, nil
            },
        )
    })

    srv, err := server.New(
        server.WithNewHandler(newHandler),
        server.WithImplementation(schema.Implementation{Name: "example", Version: "1.0"}),
    )
    if err != nil { log.Fatal(err) }

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

MCP Inspector

npx @modelcontextprotocol/inspector

Contents

  • Project structure pattern
  • Example matrix (ports + features)
  • Run transports (stdio, HTTP SSE/streaming)
  • Example 1: Tools (basic)
  • Annotation options (schema tags)
  • Example 2: Tools (advanced) with elicitation
  • Example 3: Resources
  • Example 4: Prompts
  • Example 5: Full server
  • Example 6: Tools using client sampling (CreateMessage)
  • Example 7: HTTP-level Authentication
  • Next steps and references

Project Structure Pattern

Each example uses the same separation:

  • usecase: business logic, DTOs, validation-like tags
  • server: MCP wiring that registers tools/resources/prompts and delegates to usecase
  • cmd/server: entrypoint that instantiates usecase, builds the server, and starts a transport

Why: this keeps your protocol layer thin and reusable, with business logic independent of transport and schema details.

Run Transports

  • Stdio (typical for editor integrations):

    stdioSrv := srv.Stdio(ctx)
    log.Fatal(stdioSrv.ListenAndServe())
  • HTTP SSE (default):

    httpSrv := srv.HTTP(ctx, ":4981")
    log.Fatal(httpSrv.ListenAndServe())
  • HTTP Streaming:

    srv.UseStreaming(true)
    httpSrv := srv.HTTP(ctx, ":4981")
    log.Fatal(httpSrv.ListenAndServe())

Note: In this repo’s HTTP server, the JSON-RPC endpoint is mounted at /.


Example Matrix

Example Path Prefix Port Features
Tools (basic) docs/guide/tools_basic 4981 Typed tool, auto-derived schemas
Resources docs/guide/resources 4982 Readable resource /hello
Prompts docs/guide/prompts 4983 Prompt welcome with arguments
Full docs/guide/full 4984 Tools + Resources + Prompts
Tools (advanced) docs/guide/tools_advanced 4985 Rich tags + elicitation adapter
Tools (sampling) docs/guide/tools_sampling 4986 Client-side CreateMessage (translator)
Auth (HTTP-level) docs/guide/auth_http 4987 OAuth2/OIDC at HTTP middleware

Example 1: Tools (Basic)

Example path:

  • Usecase: docs/guide/tools_basic/usecase
  • Server: docs/guide/tools_basic/server
  • Main: docs/guide/tools_basic/cmd/server
  • Run: go run ./docs/guide/tools_basic/cmd/server (listens on :4981)

What it does:

  • Exposes a typed add tool
  • Schemas for input/output are auto-derived from Go structs

Call shape (tools/call params):

{
  "method": "tools/call",
  "jsonrpc": "2.0",
  "id": 1,
  "params": {
    "name": "add",
    "arguments": { "a": 2, "b": 3 }
  }
}

The result is a text payload containing JSON like { "sum": 5 }.

JSON-RPC snippet (tools/list):

{ "method": "tools/list", "jsonrpc": "2.0", "id": 2 }

Annotation Options (Schema Tags)

These tags on your struct fields influence the generated JSON Schema for tools:

  • json:"name": renames field; json:"-" excludes it
  • omitempty: optional when combined with non-pointer types
  • required:"true": forces required
  • required:"false" or optional: forces optional
  • description:"...": human-readable description
  • format:"email", format:"uri", format:"date-time", etc.
  • choice:"val": may appear multiple times to build an enum
  • internal:"true": omits the field completely from the schema
  • Nullability: pointer types are treated as nullable by default

Required vs optional

  • Non-pointer + no omitempty → required
  • Pointer or omitempty → optional
  • Overridable with required tag

Nested types, arrays, and maps are supported and mapped to JSON Schema accordingly.


Example 2: Tools (Advanced) with Elicitation

Example path:

  • Usecase: docs/guide/tools_advanced/usecase
  • Server: docs/guide/tools_advanced/server
  • Adapter: docs/guide/tools_advanced/adapter (elicitation helper)
  • Main: docs/guide/tools_advanced/cmd/server
  • Run: go run ./docs/guide/tools_advanced/cmd/server (listens on :4985)

What it shows:

  • Tool 1: register_user uses rich tags (choice, email, uri, description, required, internal)
  • Tool 2: enrich_profile requests missing fields via elicitation (elicitation/create)

Elicitation flow (server → client):

  1. Inspect input, build a minimal requested schema (field name → type/title, required list)
  2. Call client.Elicit(...) with message and schema
  3. If user accepts with content, merge values into input and proceed; otherwise, return the action

The advanced example encapsulates this in adapter.ElicitAndMerge, keeping the handler clean.

JSON-RPC snippet (register_user):

{
  "method": "tools/call",
  "jsonrpc": "2.0",
  "id": 10,
  "params": {
    "name": "register_user",
    "arguments": {
      "name": "Alice",
      "email": "alice@example.com",
      "role": "user",
      "country": "US"
    }
  }
}

JSON-RPC snippet (enrich_profile – triggers elicitation when fields are missing):

{
  "method": "tools/call",
  "jsonrpc": "2.0",
  "id": 11,
  "params": {
    "name": "enrich_profile",
    "arguments": { "userId": "user-alice-user" }
  }
}

Example 3: Resources

Example path:

  • Usecase: docs/guide/resources/usecase
  • Server: docs/guide/resources/server
  • Main: docs/guide/resources/cmd/server
  • Run: go run ./docs/guide/resources/cmd/server (listens on :4982)

What it does:

  • Registers a readable resource at /hello
  • Returns text content and URI
  • You can extend it to notify updates (send resources/updated notifications)

Read shape (resources/read params):

{
  "method": "resources/read",
  "jsonrpc": "2.0",
  "id": 2,
  "params": { "uri": "/hello" }
}

Example 4: Prompts

Example path:

  • Usecase: docs/guide/prompts/usecase
  • Server: docs/guide/prompts/server
  • Main: docs/guide/prompts/cmd/server
  • Run: go run ./docs/guide/prompts/cmd/server (listens on :4983)

What it does:

  • Registers a welcome prompt with required argument name
  • prompts/list shows available prompts
  • prompts/get resolves messages with arguments

Get shape (prompts/get params):

{
  "method": "prompts/get",
  "jsonrpc": "2.0",
  "id": 3,
  "params": {
    "name": "welcome",
    "arguments": { "name": "Alice" }
  }
}

Example 5: Full Server

Example path:

  • Usecase: docs/guide/full/usecase
  • Server: docs/guide/full/server
  • Main: docs/guide/full/cmd/server
  • Run: go run ./docs/guide/full/cmd/server (listens on :4984)

What it does:

  • Combines a resource (/hello), a tool (add), and a prompt (welcome)
  • Toggle streaming with srv.UseStreaming(true) if desired

JSON-RPC snippet (tools/call add):

{
  "method": "tools/call",
  "jsonrpc": "2.0",
  "id": 20,
  "params": {
    "name": "add",
    "arguments": { "a": 7, "b": 8 }
  }
}

Example 6: Tools Using Client Sampling (CreateMessage)

Example path:

  • Usecase: docs/guide/tools_sampling/usecase
  • Server: docs/guide/tools_sampling/server
  • Main: docs/guide/tools_sampling/cmd/server
  • Run: go run ./docs/guide/tools_sampling/cmd/server (listens on :4986)

What it does:

  • Tool translate asks the client to sample via sampling/createMessage
  • Server composes a SystemPrompt and a single user text message
  • Returns the sampled text as the tool result

Notes:

  • The client must advertise the sampling capability
  • If using auth and remote LLMs, see the Authentication guide

JSON-RPC snippet (tools/call translate):

{
  "method": "tools/call",
  "jsonrpc": "2.0",
  "id": 30,
  "params": {
    "name": "translate",
    "arguments": { "text": "Guten Tag", "target": "en", "formality": "less" }
  }
}

Example 7: HTTP-level Authentication

Example path:

  • Usecase: docs/guide/auth_http/usecase
  • Server: docs/guide/auth_http/server
  • Main: docs/guide/auth_http/cmd/server
  • Run: go run ./docs/guide/auth_http/cmd/server (listens on :4987)

What it does:

  • Demonstrates OAuth2/OIDC protection at HTTP middleware level only
  • Configures a Policy.Global with protected resource metadata (RFC 9728)
  • Wires server.WithProtectedResourcesHandler and server.WithAuthorizer

Client notes:

  • Use the auth RoundTripper in github.com/viant/mcp/client/auth/transport to handle WWW-Authenticate challenges and fetch tokens, or include Authorization: Bearer <token> directly. See the Authentication guide for details and flows.

JSON-RPC snippet (tools/call secure_add) — include HTTP header:

POST / HTTP/1.1
Host: localhost:4987
Authorization: Bearer <access-token>
Content-Type: application/json

{
  "method": "tools/call",
  "jsonrpc": "2.0",
  "id": 40,
  "params": {
    "name": "secure_add",
    "arguments": { "a": 1, "b": 2 }
  }
}

Next Steps & References

  • Starting a server: see this guide’s examples and /docs/howto.md
  • Creating clients: see /docs/client.md
  • Server features: tools/resources/prompts overview in /docs/server_guide.md
  • Authentication/OIDC: /docs/authentication.md
  • Bridge (proxy) for stdio/HTTP: /docs/bridge.md

Tips

  • Keep transport and domain logic separated (usecase/server)
  • Use tags to drive schemas; leverage pointers + omitempty for optional fields
  • For elicitation and sampling, encapsulate patterns (adapters) to keep handlers small

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages