Skip to content

adrianwit/mcp_introduction

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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

 
 
 

Contributors

Languages