finemcp

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 19, 2026 License: MIT Imports: 17 Imported by: 0

README

FineMCP

Production-grade Model Context Protocol framework for Go
Server, client, or both—your choice. Build with 16 production middleware, streaming, resilience patterns, and selective imports—no bloat.

CI MCP Spec Go Reference Go Version Docs Go Report Card


What is FineMCP?

MCP (Model Context Protocol) is an open protocol that lets LLM applications — Claude, Cursor, VS Code Copilot, and others — discover and invoke tools, resources, and prompts exposed by a server over JSON-RPC 2.0.

FineMCP is a production-grade Go framework for building MCP servers and clients. It goes beyond protocol plumbing: it provides 16 production middleware, typed tool handlers with automatic JSON Schema generation, streaming responses, client resilience patterns (circuit breaker, load balancer, retry), OpenTelemetry observability, and a zero-network test harness — capabilities that no other MCP implementation offers in any language.

MCP Spec: 2025-11-25 with backward compatibility for 2025-06-18, 2025-03-26, and 2024-11-05.


Why FineMCP?

Most MCP libraries hand you protocol primitives and leave the rest to you. FineMCP treats the server as a system — security, observability, resilience, and correctness are built in from day one.

  • Security — RBAC per tool, token-bucket rate limiting, JSON Schema input validation, execution sandbox
  • Observability — OpenTelemetry traces and metrics, structured logging, audit log, cost tracking
  • Resilience — Circuit breaker, retry with exponential backoff, panic recovery
  • Correctness — Auto JSON Schema generation, typed generic handlers, compile-time safety
  • Testability — In-process test harness with assertion helpers and golden file diffing

🎯 Flexible Architecture

FineMCP is one framework, three use cases with zero bloat:

  • Build MCP servers — Import github.com/finemcp/finemcp (no client code in your binary)
  • Build MCP clients — Import github.com/finemcp/finemcp/client (no server overhead)
  • Build proxies/gateways — Import both (shared dependencies optimized)

Go's package system ensures you only compile what you import. A server-only binary doesn't include any client code, and vice versa. This architectural separation means you get the power of a unified framework without the cost of unused dependencies.


How FineMCP Compares

Feature FineMCP mcp-go mcp-golang official go-sdk
Middleware pipeline ✅ 16 built-in
Circuit breaker
Rate limiting
Audit log
Cost tracking
Sandbox / dry-run mode
OpenTelemetry
Client SDK ✅ full ⚠️ partial
Client resilience ✅ retry, LB, backoff
Streaming tools ✅ all transports
Multi-tenancy
WebSocket transport
Streamable HTTP
Elicitation / Sampling
Async tasks
CLI tools ✅ repl, call, inspect
Zero-network test harness
Typed handlers + auto schema
MCP spec 2025-11-25 ⚠️ partial

When to Use FineMCP

Choose FineMCP if you need:

  • Production-grade security (RBAC, rate limiting, multi-tenancy)
  • High performance — see Benchmarks for real numbers
  • Enterprise features (audit logs, cost tracking, compliance)
  • Type safety and compile-time guarantees
  • Single binary deployment

Features

Full MCP Protocol Coverage

Category Methods
Core initialize, ping, notifications/initialized, notifications/cancelled
Tools tools/list, tools/call, notifications/tools/list_changed
Resources resources/list, resources/read, resources/templates/list, resources/subscribe, resources/unsubscribe, notifications/resources/list_changed, notifications/resources/updated
Prompts prompts/list, prompts/get, notifications/prompts/list_changed
Tasks tasks/get, tasks/result, tasks/cancel, tasks/list
Completions completion/complete
Sampling sampling/createMessage
Elicitation elicitation/create
Roots roots/list, notifications/roots/list_changed
Logging logging/setLevel, notifications/message
Progress notifications/progress

Five Transports

Transport Description
Stdio Newline-delimited JSON-RPC with signal handling
HTTP Embeddable http.Handler, 204 for notifications
SSE Session management, keepalive, backpressure, auto-cleanup
Streamable HTTP MCP spec 2025-03-26+ primary transport with Mcp-Session-Id and resumability
WebSocket Full-duplex with ping/pong and graceful close

16 Built-in Middleware

Every tool call flows through an ordered, composable middleware chain:

Middleware Description
Recovery Catches panics, returns clean JSON-RPC error
Logging Structured logging — request ID, tool name, duration
Auth Bearer token and API key validation with pluggable TokenVerifier
RBAC Per-tool role-based access control
RateLimit Token-bucket rate limiter, per-tool and per-user bucketing
Validation JSON Schema validation — type, required, nested objects, arrays
Sandbox Execution timeout and output size limits
OTel OpenTelemetry spans, counters, and histograms per tool call
Async Background job execution with state machine and polling
Caching LRU result cache with TTL, input hash keying, per-tool control
CircuitBreaker Three-state machine (closed/open/half-open) with configurable thresholds
Retry Exponential backoff with jitter, context-aware sleep, custom retry classifier
AuditLog SHA-256 input hashing, per-tool include/exclude, compliance-ready trail
CostTracking Per-call cost tracking with custom cost functions and metadata
MultiTenant Per-tenant tool visibility, rate limit buckets, and RBAC policies
Simulation Dry-run mode via _meta.dryRun: true; result marked simulated: true

Custom middleware is a single func(ToolHandler) ToolHandler.

Authentication & Multi-tenancy: Use HTTPAuth transport middleware + RequireAuth protocol checker for HTTP-layer authentication. Use TenantResolver for multi-tenant tool visibility and resource isolation. See Authentication Guide.

Tool System

  • Raw handlersNewTool() with functional options (WithDescription, WithInputSchema, WithRoles, WithAnnotations)
  • Typed generic handlersNewTypedTool[In, Out]() with automatic JSON marshal/unmarshal
  • Auto JSON Schema generation — struct tags (json, description, omitempty) generate schemas automatically
  • Tool annotationsreadOnlyHint, destructiveHint, idempotentHint, openWorldHint, title
  • Tool compositionPipeline (sequential), Parallel (concurrent fan-out), FanOutFanIn (parallel + merge)
  • Bitmap name validation — O(1) per character, [A-Za-z0-9_-.]

Client SDK

FineMCP includes a production-grade MCP client SDK with resilience patterns, observability, and multi-server capabilities:

Core Client

  • Type-safe client with automatic request/response handling
  • Transport abstraction supporting stdio, HTTP, SSE, WebSocket
  • REPL for interactive debugging and testing

Resilience Patterns

  • Circuit breaker — fail fast when servers are unhealthy
  • Retry with exponential backoff — automatic retry on transient failures
  • Reconnect logic — automatic reconnection with configurable strategies
  • Load balancer — distribute requests across multiple servers (round-robin, least-connections, random)
  • Request coalescing — deduplicate identical in-flight requests

Observability

  • OpenTelemetry integration — traces, metrics, and logs for all client operations
  • Structured logging — consistent log format across all client operations

Multi-Server Patterns

  • Aggregator client — query multiple MCP servers and merge results
  • Context propagation — propagate trace context across server boundaries

Caching & Optimization

  • Response caching — cache tool/resource/prompt responses with TTL
  • Pagination helpers — automatic pagination for large result sets

Multi-Tenancy

FineMCP has first-class multi-tenancy built into the dispatch layer. A TenantResolver runs on every request to identify the tenant and apply per-tenant tool/resource visibility, rate-limit buckets, and RBAC policies — with zero application code changes.

import (
    "github.com/finemcp/finemcp"
    "github.com/finemcp/finemcp/middleware"
)

// Define per-tenant configurations
configs := map[string]*middleware.TenantConfig{
    "tenant-free": {
        ToolFilter: func(t *finemcp.Tool) bool {
            return t.Annotations != nil && t.Annotations.Title == "basic"
        },
    },
    "tenant-pro": {
        // nil filters = all tools/resources visible
    },
}

store := middleware.NewStaticTenantStore(configs)

// Identify tenant from JWT subject (or any auth header)
resolver := middleware.NewTenantResolver(
    middleware.TenantFromAuthSubject(),
    store,
    middleware.WithFallbackTenant("tenant-free"),
)

server := finemcp.NewServer("my-server", "1.0.0")
server.SetTenantResolver(resolver)

// Each request now automatically scopes tools to the caller's tenant.
// Read tenant ID in any handler or middleware:
//   tenantID := finemcp.TenantIDFromCtx(ctx)

Authentication

  • OAuth2 helpers — built-in support for OAuth2 token refresh
  • Bearer token auth — automatic token injection and refresh

Example:

import (
    "context"
    "log"

    "github.com/finemcp/finemcp/client"
    "github.com/finemcp/finemcp/client/circuitbreaker"
    "github.com/finemcp/finemcp/client/retry"
    "github.com/finemcp/finemcp/transport"
)

// Create stdio transport to MCP server
stdioTransport, err := transport.NewStdioTransport("./server-binary")
if err != nil {
    log.Fatal(err)
}

// Client with circuit breaker and retry
c, err := client.NewClient(
    client.WithTransport(stdioTransport),
    circuitbreaker.WithCircuitBreaker(),
    retry.WithRetry(retry.DefaultConfig()),
)
if err != nil {
    log.Fatal(err)
}
defer c.Close()

// Call tool on remote server
ctx := context.Background()
result, err := c.CallTool(ctx, "calculator", map[string]any{
    "expression": "2 + 2",
})
if err != nil {
    log.Fatal(err)
}

log.Printf("Result: %v", result)

For complete examples, see finemcp.dev/learn.

Streaming Tool Responses

Tool handlers can stream incremental content chunks to the client during execution via notifications/progress:

stream := finemcp.StreamFromCtx(ctx)
if stream != nil {
    stream.SendText("processing row 42…")
    stream.Send(finemcp.ImageContent{Data: img, MimeType: "image/png"})
}
return finalResult, nil
  • Backpressure: Send blocks when the buffer is full
  • Ordering: sequence numbers reflect only chunks actually delivered
  • Flush on close: all buffered chunks are flushed before close returns
  • Nil safety: typed-nil pointers are rejected with a descriptive error

Transport note: StreamFromCtx returns nil only for plain HTTP (transport/http), which has no persistent connection for notifications. Stdio, WebSocket, SSE, and Streamable HTTP all fully support streaming.

Resources & Prompts

  • Static resources (text + blob) and URI templates (RFC 6570)
  • Per-client subscription tracking with update and list-changed notifications
  • Prompt registration with named arguments, handler dispatch, and list-changed notifications

Async Tasks

  • Spec-compliant task lifecycle: pending → running → complete / failed / cancelled
  • tasks/get, tasks/result, tasks/cancel, tasks/list with ownership-based access control
  • Crypto-random task IDs, panic recovery, timeouts, cancellation, graceful shutdown drain

Protocol Highlights

  • JSON-RPC 2.0 with notification detection and request ID normalization
  • Protocol version negotiation across four spec versions
  • _meta extension on all request/result types with _meta.progressToken support
  • Cursor-based pagination for all list methods (default page size 50, max 1000)
  • Init gate (atomic.Bool) rejects pre-init requests
  • Graceful shutdown with in-flight request draining

Test Harness (mcptest)

  • NewServer(t, ...Option) — zero-network, in-process server
  • Request helpers: Initialize, CallTool, ListTools, ListResources, ReadResource, ListPrompts, GetPrompt, Notify, RawCall
  • Assertion helpers: AssertToolResult, AssertToolCount, AssertError, AssertResourceText, AssertPromptMessage
  • Fixture loading and golden file diffing

Installation

Install the FineMCP framework to build MCP servers and clients:

go get github.com/finemcp/finemcp

Go version: Go 1.25+ required (latest two stable releases supported), following the Go release policy.

Packages

Package Import Path Purpose
Core github.com/finemcp/finemcp Server, tools, protocol, middleware chain
Middleware github.com/finemcp/finemcp/middleware 16 built-in middleware (recovery, logging, RBAC, rate limiting, validation, sandbox, OpenTelemetry, async tasks, caching, circuit breaker, retry, audit logging, cost tracking, simulation, auth, multi-tenancy)
Client github.com/finemcp/finemcp/client Client SDK with 14 modules for resilience (circuit breaker, retry, load balancer, reconnect), observability (OpenTelemetry, logging), optimization (caching, coalescing, pagination), multi-server patterns (aggregator, context propagation), and authentication (OAuth2)
Transport github.com/finemcp/finemcp/transport Stdio, HTTP, SSE, Streamable HTTP, WebSocket
Test Harness github.com/finemcp/finemcp/mcptest In-process testing helpers

CLI Tools

For debugging, testing, and inspecting MCP servers, install the finemcp CLI:

Go install (recommended for Go developers):

go install github.com/finemcp/finemcp/cmd/finemcp@latest

macOS:

curl -L https://github.com/finemcp/finemcp/releases/latest/download/finemcp_darwin_amd64.tar.gz | tar xz
sudo mv finemcp /usr/local/bin/

Linux:

curl -L https://github.com/finemcp/finemcp/releases/latest/download/finemcp_linux_amd64.tar.gz | tar xz
sudo mv finemcp /usr/local/bin/

Windows (PowerShell):

# Download and extract latest release (no admin required)
$url = "https://github.com/finemcp/finemcp/releases/latest/download/finemcp_windows_amd64.zip"
Invoke-WebRequest -Uri $url -OutFile finemcp.zip
Expand-Archive finemcp.zip -DestinationPath .

# Install to user-local bin (no admin needed)
$userBin = "$env:USERPROFILE\.local\bin"
New-Item -ItemType Directory -Force -Path $userBin | Out-Null
Move-Item finemcp.exe $userBin -Force

# Add to PATH permanently (current user only)
$currentPath = [Environment]::GetEnvironmentVariable("Path", "User")
if ($currentPath -notlike "*$userBin*") {
    [Environment]::SetEnvironmentVariable("Path", "$currentPath;$userBin", "User")
}
Write-Host "Installed to $userBin - restart your terminal to use 'finemcp'"

Or system-wide (requires Administrator):

# After extracting finemcp.exe:
Move-Item finemcp.exe C:\Windows\System32\

Or download manually:
Download the .zip file from GitHub Releases, extract finemcp.exe, and add it to your PATH.

Quick test:

finemcp serve --http :8080                    # Start test server
finemcp inspect http http://localhost:8080    # Inspect server capabilities
finemcp repl http http://localhost:8080       # Interactive debugging REPL

Windows (PowerShell):

finemcp serve --http :8080                    # Start test server
finemcp inspect http http://localhost:8080    # Inspect server capabilities
finemcp repl http http://localhost:8080       # Interactive debugging REPL

💡 When to use CLI: Debug tool visibility issues with Claude/Cursor, inspect server capabilities before deploying, test connectivity, and run interactive REPL sessions for development and troubleshooting.


CLI Commands

The finemcp CLI provides essential debugging and testing utilities:

Command Description Example
serve Launch test ping server finemcp serve --http :8080
repl Interactive REPL session finemcp repl stdio ./server
list List tools/resources/prompts finemcp list http http://localhost:8080
call Call a tool and see result finemcp call http http://localhost:8080 toolName
inspect Full JSON capability dump finemcp inspect http http://localhost:8080
version Show version info finemcp version

Common use cases:

  • 🐛 Debug why Claude isn't seeing your toolsfinemcp inspect
  • 🧪 Test a server before deployingfinemcp serve then connect Claude Desktop
  • 📊 Verify tool schemasfinemcp list shows all registered capabilities
  • Quick demos without codefinemcp serve --http :8080 gives you a working server instantly
  • 🔍 Troubleshoot stdio transportfinemcp repl stdio ./myserver shows real-time communication

Run finemcp <command> --help for detailed usage.


Quick Start

Get a server running in under 10 lines:

package main

import (
	"context"
	"log"
	"github.com/finemcp/finemcp"
	"github.com/finemcp/finemcp/transport"
)

type Input struct{ Name string `json:"name"` }

func main() {
	s := finemcp.NewServer("myapp", "1.0")
	tool, _ := finemcp.NewTypedTool("greet", func(_ context.Context, in Input) (string, error) {
		return "Hello, " + in.Name + "!", nil
	})
	s.RegisterTool(tool)
	log.Fatal(transport.StartHTTP(s, ":8080"))
}
📦 Add Middleware (Intermediate)

Add safety and observability with middleware:

package main

import (
	"context"
	"log"
	"github.com/finemcp/finemcp"
	"github.com/finemcp/finemcp/middleware"
	"github.com/finemcp/finemcp/transport"
)

type appLogger struct{}
func (appLogger) Info(msg string, kv ...any)  { log.Println(append([]any{msg}, kv...)...) }
func (appLogger) Error(msg string, kv ...any) { log.Println(append([]any{"ERROR", msg}, kv...)...) }

type Input struct {
	Name string `json:"name" description:"Name to greet"`
}

func main() {
	s := finemcp.NewServer("myapp", "1.0")
	
	// Add production middleware
	s.Use(middleware.Recovery())              // Catch panics
	s.Use(middleware.Logging(appLogger{}))    // Structured logs
	s.Use(middleware.Validation())            // JSON Schema validation
	
	tool, err := finemcp.NewTypedTool("greet",
		func(_ context.Context, in Input) (string, error) {
			return "Hello, " + in.Name + "!", nil
		},
		finemcp.WithDescription("Greets someone by name"),
	)
	if err != nil {
		log.Fatal(err)
	}
	s.RegisterTool(tool)
	
	log.Fatal(transport.StartHTTP(s, ":8080"))
}
🚀 Production Ready (Advanced)

Full production setup with security, rate limiting, and observability:

package main

import (
	"context"
	"log"
	"time"
	"github.com/finemcp/finemcp"
	"github.com/finemcp/finemcp/middleware"
	"github.com/finemcp/finemcp/transport"
)

type appLogger struct{}
func (appLogger) Info(msg string, kv ...any)  { log.Println(append([]any{msg}, kv...)...) }
func (appLogger) Error(msg string, kv ...any) { log.Println(append([]any{"ERROR", msg}, kv...)...) }

type Input struct {
	Name string `json:"name" description:"Name to greet"`
}

func main() {
	s := finemcp.NewServer("myapp", "1.0")
	
	// Production middleware stack
	s.Use(middleware.Recovery())           // Panic recovery
	s.Use(middleware.Logging(appLogger{})) // Structured logging
	s.Use(middleware.RateLimit(100))       // 100 req/sec rate limit
	s.Use(middleware.RBAC())               // Role-based access (roles set per-tool with WithRoles)
	s.Use(middleware.Validation())         // Input validation
	s.Use(middleware.Sandbox(            // Timeout & output size limits
		middleware.WithTimeout(5*time.Second),
		middleware.WithMaxOutputSize(1<<20),
	))
	s.Use(middleware.OTel())   // OpenTelemetry (configure providers via WithTracerProvider/WithMeterProvider)
	s.Use(middleware.AuditLog( // Audit logging
		middleware.WithAuditSink(middleware.AuditSinkFunc(func(ctx context.Context, e middleware.AuditEntry) {
			log.Printf("[AUDIT] tool=%s duration=%v", e.ToolName, e.Duration)
		})),
	))
	
	// Register typed tool with full options
	tool, err := finemcp.NewTypedTool("greet",
		func(_ context.Context, in Input) (string, error) {
			return "Hello, " + in.Name + "!", nil
		},
		finemcp.WithDescription("Greets someone by name"),
		finemcp.WithRoles("user", "admin"),
		finemcp.WithReadOnly(),
		finemcp.WithIdempotent(),
	)
	if err != nil {
		log.Fatal(err)
	}
	s.RegisterTool(tool)
	
	log.Printf("Starting MCP server on :8080")
	log.Fatal(transport.StartHTTP(s, ":8080"))
}

💡 Tip: Start simple and add middleware as you need it. Each middleware is opt-in and composable.


Benchmarks

All numbers are from the bundled benchmark suite (go test -bench=. -benchmem ./client/...) using an in-process mock transport on Apple M1 — no real network, so actual HTTP/stdio/WebSocket throughput will vary by network and payload size.

Benchmark ns/op ops/sec Memory
CallTool_Small (100B, single goroutine) 12,617 ~79k 5 KB / 98 allocs
CallTool_Parallel (GOMAXPROCS goroutines) 4,391 ~228k 5 KB / 98 allocs
ListTools 9,019 ~111k 4 KB / 94 allocs
StdioTransport round-trip 8,477 ~118k 4 KB / 98 allocs
HTTPTransport round-trip 8,790 ~114k 4 KB / 98 allocs
WebSocketTransport round-trip 8,611 ~116k 4 KB / 98 allocs
StreamableHTTP round-trip 8,540 ~117k 4 KB / 98 allocs
CallTool_WithCaching (cache hit) 7,449 ~134k 3 KB / 78 allocs
Streaming 10 chunks 43,991 ~23k 27 KB / 438 allocs
Concurrent_100 (100 goroutines) 677k total 461 KB / 9.9k allocs

Run the benchmarks yourself:

go test -bench=. -benchmem -run='^$' ./client/...

MCP Spec Roadmap

FineMCP targets MCP spec 2025-11-25 — the current stable release. As the spec evolves we track changes here:

Spec version Status Notes
2024-11-05 ✅ Supported Legacy compat
2025-03-26 ✅ Supported
2025-06-18 ✅ Supported
2025-11-25 Current Full compliance
Future revisions 🔜 Tracked See ROADMAP.md

Protocol negotiation is handled automatically — the server advertises the highest version it supports and downgrades gracefully when a client requests an older version.


Documentation

📚 Complete Documentation — Guides, API reference, architecture, middleware, transports, and best practices

🎓 Examples & Tutorials — Working code samples and step-by-step tutorials

Document Description
Contributing Development workflow, commit guidelines, coding style
Security Security policy and vulnerability reporting

Contributing

Contributions welcome. See CONTRIBUTING.md for guidelines.


License

MIT License. See LICENSE.

Documentation

Overview

Package finemcp is a production-ready Go framework for building Model Context Protocol (MCP) servers.

FineMCP implements the full MCP specification (2025-11-25) over JSON-RPC 2.0, with backward compatibility for 2025-06-18, 2025-03-26, and 2024-11-05. It provides typed tool handlers with automatic JSON Schema generation, streaming tool responses, a composable middleware architecture, and a zero-network test harness.

Quick start

s := finemcp.NewServer("my-server", "1.0.0")

tool, _ := finemcp.NewTool("greet", func(ctx context.Context, input json.RawMessage) (*finemcp.CallToolResult, error) {
    return finemcp.NewTextResult("Hello!"), nil
}, finemcp.WithDescription("Say hello"))

s.AddTool(tool)
finemcp.ServeStdio(s)

Transports

Four built-in transports are available in the github.com/finemcp/finemcp/transport package:

  • stdio — newline-delimited JSON over stdin/stdout
  • SSE — HTTP Server-Sent Events
  • Streamable HTTP — MCP Streamable HTTP with session management
  • WebSocket — full-duplex WebSocket

Middleware

The github.com/finemcp/finemcp/middleware package provides 16 composable middleware components including authentication, RBAC, rate limiting, circuit breaking, OpenTelemetry tracing, audit logging, cost tracking, and more.

Streaming

Long-running tools can stream incremental results via ToolStream:

stream := finemcp.StreamFromCtx(ctx)
if stream != nil {
    stream.SendText("progress update…")
}

Streaming works over SSE and Streamable HTTP transports.

Testing

The github.com/finemcp/finemcp/mcptest package provides an in-memory test server that requires no network and works with the race detector.

Content types

Tool results use the sealed Content interface, implemented by TextContent, ImageContent, AudioContent, and EmbeddedResource.

For the complete documentation, see https://finemcp.dev/docs

Index

Examples

Constants

View Source
const (
	RefTypePrompt   = "ref/prompt"
	RefTypeResource = "ref/resource"
)

Ref type constants.

View Source
const (
	ErrCodeParseError     = -32700
	ErrCodeInvalidRequest = -32600
	ErrCodeMethodNotFound = -32601
	ErrCodeInvalidParams  = -32602
	ErrCodeInternalError  = -32603
)

Standard JSON-RPC 2.0 error codes.

View Source
const (
	// ErrCodeUnauthorized indicates that the request lacks valid authentication
	// credentials. Returned when an AuthChecker is configured and the request
	// context does not contain a verified identity.
	ErrCodeUnauthorized = -32001

	// ErrCodeTenantRequired indicates that tenant identification could not be
	// resolved for the request. Returned when a TenantResolver is configured
	// and the tenant ID is missing, invalid, or not found in the store.
	// The error message is intentionally generic ("tenant identification required")
	// to prevent enumeration of valid tenant IDs.
	ErrCodeTenantRequired = -32002
)

Application-level JSON-RPC error codes (reserved range: -32000 to -32099).

View Source
const (
	// DefaultMaxNotificationMethods is the default maximum number of distinct
	// notification methods that can have handlers registered. Override via
	// [WithMaxNotificationMethods] if you expect more than 1000 custom methods.
	DefaultMaxNotificationMethods = 1000

	// DefaultMaxHandlersPerMethod is the default maximum number of handlers
	// that can be registered for a single notification method. Override via
	// [WithMaxHandlersPerNotification] if you need more than 100 handlers per
	// method (uncommon: most applications use 1-5 handlers per notification;
	// event-bus or plugin-system patterns may need more).
	DefaultMaxHandlersPerMethod = 100
)

Defaults for notification handler limits.

View Source
const (
	MethodInitialize             = methodInitialize
	MethodInitialized            = methodInitialized
	MethodToolsList              = methodToolsList
	MethodToolsCall              = methodToolsCall
	MethodResourcesList          = methodResourcesList
	MethodResourcesRead          = methodResourcesRead
	MethodResourcesTemplatesList = methodResourcesTemplatesList
	MethodRootsList              = methodRootsList
	MethodPromptsList            = methodPromptsList
	MethodPromptsGet             = methodPromptsGet
	MethodPing                   = methodPing
	MethodProgress               = methodProgress
	MethodCancelled              = methodCancelled
	MethodResourcesSubscribe     = methodResourcesSubscribe
	MethodResourcesUnsubscribe   = methodResourcesUnsubscribe
	MethodCompletionComplete     = methodCompletionComplete
	MethodTasksGet               = methodTasksGet
	MethodTasksResult            = methodTasksResult
	MethodTasksCancel            = methodTasksCancel
	MethodTasksList              = methodTasksList
	MethodResourcesUpdated       = methodResourcesUpdated
	MethodToolsListChanged       = methodToolsListChanged
	MethodResourcesListChanged   = methodResourcesListChanged
	MethodPromptsListChanged     = methodPromptsListChanged
	MethodRootsListChanged       = methodRootsListChanged
	MethodSamplingCreateMessage  = methodSamplingCreateMessage
	MethodElicitationCreate      = methodElicitationCreate
	MethodLoggingSetLevel        = methodLoggingSetLevel
	MethodLoggingMessage         = methodLoggingMessage
)

Exported MCP method constants for use by the client package and external consumers.

View Source
const (
	// DefaultMaxSessionTools is the default maximum number of tools per session.
	DefaultMaxSessionTools = 100

	// DefaultMaxSessions is the default maximum number of concurrent sessions
	// that can have session tools. Prevents unbounded memory growth from
	// rogue transport connections.
	DefaultMaxSessions = 10000
)
View Source
const DefaultStreamBufferSize = 16

DefaultStreamBufferSize is the default number of content chunks buffered before Send blocks, providing backpressure to the tool handler.

View Source
const ProtocolVersion = "2025-11-25"

ProtocolVersion is the latest MCP protocol version this server supports. Format is YYYY-MM-DD (e.g., "2025-11-25"). This is the preferred version used in negotiation when the client's requested version is not in the server's supported set. Must always equal defaultSupportedVersions[0]; the init() guard below panics at program start if they drift.

Variables

View Source
var ErrStreamClosed = errors.New("stream closed")

ErrStreamClosed is returned by ToolStream.Send and ToolStream.SendText when the stream has already been closed by the framework. Tool handlers can use errors.Is(err, finemcp.ErrStreamClosed) to distinguish this from context cancellation or marshaling errors.

Functions

func BoolPtr

func BoolPtr(v bool) *bool

BoolPtr returns a pointer to the given bool value. Exported so callers can build ToolAnnotations literals without a local helper.

func DefaultSupportedVersions

func DefaultSupportedVersions() []string

DefaultSupportedVersions returns all MCP protocol versions the server supports by default, ordered from latest to oldest. The first entry is the preferred version. A fresh copy is returned each time.

func GenerateSchema

func GenerateSchema(t reflect.Type) map[string]any

GenerateSchema produces a JSON Schema (as map[string]any) from a Go reflect.Type.

For struct types it generates an "object" schema with properties derived from exported fields. Struct tags control the output:

  • json:"name" → property name
  • json:",omitempty" → field is optional (not in "required")
  • json:"-" → field is skipped
  • description:"..." → sets the property's "description"

Pointer fields are treated as optional. Nested structs, slices, and maps are recursively expanded.

For non-struct types (e.g. string, int) it returns the corresponding primitive JSON Schema.

func IsResponse

func IsResponse(data []byte) bool

IsResponse checks whether a raw JSON message is a JSON-RPC response (has "id" and either "result" or "error", but no "method"). This is used by transports to distinguish client responses from client requests.

func IsSimulatedFromCtx

func IsSimulatedFromCtx(ctx context.Context) bool

IsSimulatedFromCtx reports whether the current call is a simulation. This is only true inside the simulator and any code it calls; outer middleware should use MetaFromCtx to check for dry-run mode.

func MetaFromCtx

func MetaFromCtx(ctx context.Context) map[string]any

MetaFromCtx extracts the request _meta from the context. Returns nil if the client did not send _meta.

func ReportProgress

func ReportProgress(ctx context.Context, progress, total float64)

ReportProgress emits a notifications/progress event for the current tool call. progress is the current value (e.g. bytes processed, items completed). total is the expected final value; pass 0 for indeterminate progress.

If the transport does not support server-to-client notifications (e.g. plain HTTP), or if no reporter was injected into ctx, this call is a no-op.

On the SSE transport, progress notifications are delivered on a best-effort basis: if the session's event buffer is full the notification is silently dropped. Tool authors should not rely on every notification being delivered.

Example:

tool, _ := finemcp.NewTypedTool("process", func(ctx context.Context, in Input) (string, error) {
    for i, item := range in.Items {
        finemcp.ReportProgress(ctx, float64(i+1), float64(len(in.Items)))
        // ... process item ...
    }
    return "done", nil
})

func RequestID

func RequestID(ctx context.Context) any

RequestID extracts the JSON-RPC request ID from the context. Returns nil if not set.

func RolesFromCtx

func RolesFromCtx(ctx context.Context) []string

RolesFromCtx extracts the caller's roles from the context. Returns nil if not set.

func SetResponseMeta

func SetResponseMeta(ctx context.Context, key string, value any)

SetResponseMeta attaches a key-value pair to the response _meta. Tool, resource, and prompt handlers can call this to include custom metadata in the response without modifying the result struct directly.

This is only effective for tools/call, resources/read, and prompts/get handlers — the dispatch layer wires up the response meta holder for those methods. Calls from other contexts are a safe no-op.

Example:

func myHandler(ctx context.Context, input []byte) ([]byte, error) {
    finemcp.SetResponseMeta(ctx, "processingTimeMs", 42)
    return []byte("done"), nil
}

func SimDepthFromCtx

func SimDepthFromCtx(ctx context.Context) int

SimDepthFromCtx returns the current simulation nesting depth. Returns 0 if not inside a simulation.

func SkipValidationFromCtx

func SkipValidationFromCtx(ctx context.Context) bool

SkipValidationFromCtx reports whether input validation should be skipped. Returns false if not set.

func SubscriberIDFromCtx

func SubscriberIDFromCtx(ctx context.Context) string

SubscriberIDFromCtx extracts the subscriber/connection ID from the context. Returns "" if not set.

func TenantIDFromCtx

func TenantIDFromCtx(ctx context.Context) string

TenantIDFromCtx extracts the resolved tenant ID from the context. Returns "" if no tenant ID is set (single-tenant mode or before resolution).

func ToolName

func ToolName(ctx context.Context) string

ToolName extracts the tool name from the context. Returns "" if not set.

func ToolRolesFromCtx

func ToolRolesFromCtx(ctx context.Context) []string

ToolRolesFromCtx extracts the tool's required roles from the context. Returns nil if the tool has no role requirements. This is set internally by Server.CallTool and used by middleware like RBAC.

func ToolSchemaFromCtx

func ToolSchemaFromCtx(ctx context.Context) any

ToolSchemaFromCtx extracts the tool's InputSchema from the context. Returns nil if no schema is set. Used by validation middleware.

func WithAuthInfo

func WithAuthInfo(ctx context.Context, info AuthInfo) context.Context

WithAuthInfo returns a copy of ctx with the verified caller identity attached. The Roles slice and Meta map are defensively copied to prevent mutation.

func WithMeta

func WithMeta(ctx context.Context, meta map[string]any) context.Context

WithMeta returns a copy of ctx with the request's _meta attached. This is set by the dispatch layer when the client includes _meta in the request params. Handlers and middleware can inspect it via MetaFromCtx.

func WithNotificationSender

func WithNotificationSender(ctx context.Context, fn NotificationSender) context.Context

WithNotificationSender attaches a notification sender to the context. Transports call this before invoking HandleMessage so that tool handlers can emit mid-execution notifications via ReportProgress.

func WithRequestID

func WithRequestID(ctx context.Context, id any) context.Context

WithRequestID returns a copy of ctx with the JSON-RPC request ID attached.

func WithRequestSender

func WithRequestSender(ctx context.Context, fn RequestSender) context.Context

WithRequestSender attaches a server-to-client request sender to the context. Transports call this before invoking HandleMessage so that server methods like CreateMessage can send requests to the client and await responses.

func WithRolesCtx

func WithRolesCtx(ctx context.Context, roles []string) context.Context

WithRolesCtx returns a copy of ctx with the caller's roles attached.

func WithSimDepth

func WithSimDepth(ctx context.Context, depth int) context.Context

WithSimDepth attaches the current simulation nesting depth to the context.

func WithSimulated

func WithSimulated(ctx context.Context) context.Context

WithSimulated marks the context as a simulation (dry-run) call. The Simulation middleware calls this before invoking the simulator so that the simulator and any code it calls can detect dry-run mode via IsSimulatedFromCtx.

Note: because Go contexts are immutable, the simulated flag is only visible to the simulator and downstream calls — middleware earlier in the chain (outer wrappers) will not see it. Outer middleware that needs to detect dry-run mode should check MetaFromCtx for the "dryRun" key instead.

func WithSubscriberID

func WithSubscriberID(ctx context.Context, id string) context.Context

WithSubscriberID attaches a stable per-connection identifier to the context. Transports set this once per connection/session so the server can associate subscriptions and broadcast senders with a specific client.

func WithTenantID

func WithTenantID(ctx context.Context, id string) context.Context

WithTenantID returns a copy of ctx with the resolved tenant ID attached. This is set by the TenantResolver during request dispatch and can be read by downstream middleware (rate limiter, audit log, cost tracking) via TenantIDFromCtx.

func WithToolName

func WithToolName(ctx context.Context, name string) context.Context

WithToolName returns a copy of ctx with the tool name attached.

Types

type AudioContent

type AudioContent struct {
	// Data is the raw audio bytes. They are base64-encoded on the wire.
	Data []byte

	// MimeType is the MIME type of the audio (e.g. "audio/wav").
	// May be empty if the format is unspecified.
	MimeType string
}

AudioContent represents a base64-encoded audio clip returned by a tool. MCP wire format: {"type":"audio","data":"<base64>","mimeType":"audio/*"}. The MimeType field indicates the audio format (e.g. "audio/wav", "audio/mpeg"). MimeType may be an empty string if the format is unknown or unspecified.

func NewAudioContent

func NewAudioContent(mimeType string, data []byte) AudioContent

NewAudioContent creates an AudioContent from raw bytes and a MIME type. The bytes are stored as-is and base64-encoded when marshaled to JSON.

func (AudioContent) MarshalJSON

func (c AudioContent) MarshalJSON() ([]byte, error)

MarshalJSON encodes Data as a base64 string and includes the MCP "type" discriminator.

type AuthChecker

type AuthChecker func(ctx context.Context) error

AuthChecker validates that a request context has proper authentication. It is called by handleRequest for every JSON-RPC request (except initialize and ping) after the server is initialized. If it returns a non-nil error, the request is rejected with a JSON-RPC error response using ErrCodeUnauthorized.

Implementations should inspect the context for an AuthInfo value set by the transport-level authentication middleware.

type AuthInfo

type AuthInfo struct {
	// Subject identifies the authenticated caller (e.g. user ID, service name).
	Subject string

	// Roles contains the caller's authorization roles for RBAC.
	Roles []string

	// Meta holds additional claims from the token (e.g. JWT claims).
	// May be nil.
	Meta map[string]any
}

AuthInfo represents the verified identity of an authenticated caller. It is injected into context by the authentication layer (transport HTTP middleware) after successful credential verification.

Consumers (RBAC, audit log, logging, handlers) read it via AuthInfoFromCtx.

func AuthInfoFromCtx

func AuthInfoFromCtx(ctx context.Context) *AuthInfo

AuthInfoFromCtx extracts the verified caller identity from the context. Returns nil if no identity is set (unauthenticated request).

type CallToolParams

type CallToolParams struct {
	Name      string          `json:"name"`
	Arguments json.RawMessage `json:"arguments,omitempty"`
	Task      *TaskMetadata   `json:"task,omitempty"`
	Meta      map[string]any  `json:"_meta,omitempty"`
}

CallToolParams is the client's payload for a "tools/call" request.

type CallToolResult

type CallToolResult struct {
	Content           []Content      `json:"content"`
	IsError           bool           `json:"isError,omitempty"`
	StructuredContent any            `json:"structuredContent,omitempty"`
	Meta              map[string]any `json:"_meta,omitempty"`
}

CallToolResult is the server's response to a tools/call request.

func NewAudioResult

func NewAudioResult(mimeType string, data []byte) *CallToolResult

NewAudioResult creates a successful result containing a single audio clip. data is the raw audio bytes; mimeType should be e.g. "audio/wav" or "audio/mpeg".

func NewEmbeddedResourceResult

func NewEmbeddedResourceResult(rc ResourceContent) *CallToolResult

NewEmbeddedResourceResult creates a successful result containing a single embedded resource.

func NewErrorResult

func NewErrorResult(text string) *CallToolResult

NewErrorResult creates an error result with a single text content block. Tool errors are returned as content with IsError=true, not as protocol errors.

func NewImageResult

func NewImageResult(mimeType string, data []byte) *CallToolResult

NewImageResult creates a successful result containing a single image. data is the raw image bytes; mimeType should be e.g. "image/png" or "image/jpeg".

func NewTextResult

func NewTextResult(text string) *CallToolResult

NewTextResult creates a successful result with a single text content block.

func (*CallToolResult) UnmarshalJSON

func (r *CallToolResult) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a CallToolResult, handling the Content interface slice.

type CancelledParams

type CancelledParams struct {
	RequestID any            `json:"requestId"` // can be string or number
	Meta      map[string]any `json:"_meta,omitempty"`
}

CancelledParams is the client's payload for the "notifications/cancelled" notification.

type ClientCaps

type ClientCaps struct {
	// Sampling indicates the client supports sampling/createMessage requests.
	// When non-nil, the server may send LLM sampling requests to the client.
	Sampling *SamplingCapability `json:"sampling,omitempty"`

	// Elicitation indicates the client supports elicitation/create requests.
	// When non-nil, the server may send user prompt requests to the client.
	Elicitation *ElicitationCapability `json:"elicitation,omitempty"`
}

ClientCaps describes the client's declared capabilities.

type CompleteHandler

type CompleteHandler func(ctx context.Context, params CompleteRequest) (*CompletionResult, error)

CompleteHandler provides argument auto-completions for a prompt or resource template. The server invokes the handler when a client sends a completion/complete request, passing the reference to the prompt or template and the partial argument value typed so far.

Implementations should return a CompletionResult with matching values. Returning nil is equivalent to returning an empty result (no suggestions). The server normalizes nil Values to an empty slice before serialization, so handlers may safely return a nil slice when there are no matches.

The server enforces the MCP-recommended limit of 100 values per response. If Values contains more than 100 items, the server truncates the slice to 100 entries and sets HasMore to true automatically. Total is preserved if the handler set it; otherwise it is set to the original (pre-truncation) length.

Like other user-provided handlers, a CompleteHandler is not wrapped with panic recovery by default. For production deployments, use a recovery middleware to prevent a panicking completer from crashing the server.

type CompleteParams

type CompleteParams struct {
	Ref      CompletionRef      `json:"ref"`
	Argument CompletionArgument `json:"argument"`
	Meta     map[string]any     `json:"_meta,omitempty"`
}

CompleteParams is the client's payload for a "completion/complete" request.

type CompleteRequest

type CompleteRequest struct {
	// Ref identifies the prompt or resource template being completed.
	Ref CompletionRef

	// Argument holds the argument name and partial value.
	Argument CompletionArgument
}

CompleteRequest is the input passed to a CompleteHandler. It wraps the reference and argument from the client's request.

type CompleteResult

type CompleteResult struct {
	Completion CompletionResult `json:"completion"`
	Meta       map[string]any   `json:"_meta,omitempty"`
}

CompleteResult is the server's response to a "completion/complete" request.

type CompletionArgument

type CompletionArgument struct {
	// Name is the argument identifier.
	Name string `json:"name"`

	// Value is the partial value typed so far.
	Value string `json:"value"`
}

CompletionArgument holds the argument name and partial value for which the client is requesting completions.

type CompletionCapability

type CompletionCapability struct{}

CompletionCapability signals that the server supports completion/complete. Per the MCP spec, the capability is an empty object when present.

type CompletionRef

type CompletionRef struct {
	// Type is "ref/prompt" or "ref/resource".
	Type string `json:"type"`

	// Name is the prompt name (for ref/prompt) or the resource URI template
	// string (for ref/resource).
	Name string `json:"name,omitempty"`

	// URI is the resource template URI (for ref/resource).
	// Some clients use "uri" instead of "name" for resource references.
	URI string `json:"uri,omitempty"`
}

CompletionRef identifies the prompt or resource template being completed.

type CompletionResult

type CompletionResult struct {
	// Values is the list of completion suggestions. The server enforces the
	// MCP-recommended limit of 100 items: if the handler returns more, the
	// slice is truncated and HasMore is set to true automatically.
	Values []string `json:"values"`

	// Total is the total number of available completions (optional).
	// When set, clients can display "showing X of Y" to the user.
	// If the server truncates Values, Total is preserved when the handler
	// set it explicitly; otherwise it is set to the original length.
	Total int `json:"total,omitempty"`

	// HasMore indicates that additional completions exist beyond the
	// returned values.
	HasMore bool `json:"hasMore,omitempty"`
}

CompletionResult holds the auto-completion suggestions returned by a CompleteHandler.

type Content

type Content interface {
	// contains filtered or unexported methods
}

Content is a sealed interface for tool result content types. Implementations: TextContent, ImageContent, AudioContent, EmbeddedResource.

func DecodeContent

func DecodeContent(raw json.RawMessage) (Content, error)

DecodeContent decodes a raw JSON content block into the appropriate Content type based on the "type" discriminator field. Uses a single-pass unmarshal for efficiency.

Validation rules:

  • TextContent.Text: optional field; defaults to empty string when absent.
  • ImageContent/AudioContent.Data: required, must be a non-empty base64 string.
  • ImageContent/AudioContent.MimeType: optional; defaults to empty string.
  • ResourceContent.URI: required, must be non-empty.
  • ResourceContent.Text/Blob: exactly one must be set.

type CreateMessageParams

type CreateMessageParams struct {
	// Messages is the conversation history to send to the LLM.
	Messages []SamplingMessage `json:"messages"`

	// ModelPreferences expresses optional model selection preferences.
	ModelPreferences *ModelPreferences `json:"modelPreferences,omitempty"`

	// SystemPrompt is an optional system prompt to prepend.
	SystemPrompt string `json:"systemPrompt,omitempty"`

	// IncludeContext controls how much MCP context the client should
	// include. Valid values: "none", "thisServer", "allServers".
	IncludeContext string `json:"includeContext,omitempty"`

	// Temperature controls randomness (0–1). Optional.
	Temperature *float64 `json:"temperature,omitempty"`

	// MaxTokens is the maximum number of tokens to generate.
	MaxTokens int `json:"maxTokens"`

	// StopSequences is an optional list of sequences that stop generation.
	StopSequences []string `json:"stopSequences,omitempty"`

	// Metadata is additional provider-specific parameters.
	Metadata map[string]any `json:"metadata,omitempty"`

	// Meta holds MCP request metadata such as a progress token.
	// Clients use this to correlate progress notifications with the request.
	Meta map[string]any `json:"_meta,omitempty"`
}

CreateMessageParams is the server's payload for a "sampling/createMessage" request sent to the client.

type CreateMessageResult

type CreateMessageResult struct {
	// Role is the role of the generated message ("assistant").
	Role string `json:"role"`

	// Content is the generated content (text, image, etc.).
	Content json.RawMessage `json:"content"`

	// Model is the identifier of the model that was used.
	Model string `json:"model"`

	// StopReason indicates why generation stopped.
	// Common values: "endTurn", "stopSequence", "maxTokens".
	StopReason string `json:"stopReason,omitempty"`
}

CreateMessageResult is the client's response to a "sampling/createMessage" request.

type CreateTaskResult

type CreateTaskResult struct {
	Task Task           `json:"task"`
	Meta map[string]any `json:"_meta,omitempty"`
}

CreateTaskResult is the response to a task-augmented request (e.g., tools/call with task metadata). It wraps a Task handle.

type ElicitationCapability

type ElicitationCapability struct{}

ElicitationCapability signals that the client supports elicitation/create. Per the MCP spec, the capability is an empty object when present.

type ElicitationParams

type ElicitationParams struct {
	// Prompt is the message to display to the user.
	Prompt string `json:"prompt"`

	// Type indicates the expected response type: "text", "secret", "file", etc.
	Type string `json:"type,omitempty"`

	// Default is an optional default value to present to the user.
	Default string `json:"default,omitempty"`

	// Meta holds MCP request metadata such as a progress token.
	Meta map[string]any `json:"_meta,omitempty"`
}

ElicitationParams is the server's payload for an "elicitation/create" request sent to the client.

type ElicitationResult

type ElicitationResult struct {
	// Value is the user's input.
	Value string `json:"value"`

	// Cancelled indicates whether the user cancelled the prompt.
	Cancelled bool `json:"cancelled,omitempty"`
}

ElicitationResult is the client's response to an "elicitation/create" request.

type EmbeddedResource

type EmbeddedResource struct {
	Resource ResourceContent
}

EmbeddedResource embeds a resource directly inside a tool result, as defined by the MCP spec's "resource" content type.

func NewEmbeddedResource

func NewEmbeddedResource(rc ResourceContent) EmbeddedResource

NewEmbeddedResource wraps a ResourceContent as an EmbeddedResource content item.

func (EmbeddedResource) MarshalJSON

func (e EmbeddedResource) MarshalJSON() ([]byte, error)

MarshalJSON marshals the embedded resource with the MCP "type" discriminator.

type GetPromptParams

type GetPromptParams struct {
	Name      string            `json:"name"`
	Arguments map[string]string `json:"arguments,omitempty"`
	Meta      map[string]any    `json:"_meta,omitempty"`
}

GetPromptParams is the client's payload for a "prompts/get" request.

type GetPromptResult

type GetPromptResult struct {
	Description string          `json:"description,omitempty"`
	Messages    []PromptMessage `json:"messages"`
	Meta        map[string]any  `json:"_meta,omitempty"`
}

GetPromptResult is the server's response to a "prompts/get" request.

type Icon

type Icon struct {
	Src      string   `json:"src"`
	MimeType string   `json:"mimeType,omitempty"`
	Sizes    []string `json:"sizes,omitempty"`
}

Icon represents an icon associated with an MCP server or client. Per the MCP spec, icons can be used by clients (e.g. Claude Desktop) to display a visual representation of the server.

type ImageContent

type ImageContent struct {
	// Data is the raw image bytes. They are base64-encoded on the wire.
	Data []byte

	// MimeType is the MIME type of the image (e.g. "image/png").
	// May be empty if the format is unspecified.
	MimeType string
}

ImageContent represents a base64-encoded image returned by a tool. The MimeType field indicates the image format (e.g. "image/png", "image/jpeg"). MimeType may be an empty string if the format is unknown or unspecified.

func NewImageContent

func NewImageContent(mimeType string, data []byte) ImageContent

NewImageContent creates an ImageContent from raw bytes and a MIME type. The bytes are stored as-is and base64-encoded when marshaled to JSON.

func (ImageContent) MarshalJSON

func (c ImageContent) MarshalJSON() ([]byte, error)

MarshalJSON encodes Data as a base64 string and includes the MCP "type" discriminator.

type InitializeParams

type InitializeParams struct {
	ProtocolVersion string         `json:"protocolVersion"`
	Capabilities    ClientCaps     `json:"capabilities"`
	ClientInfo      ProcessInfo    `json:"clientInfo"`
	Meta            map[string]any `json:"_meta,omitempty"`
}

InitializeParams is the client's payload for the "initialize" request.

type InitializeResult

type InitializeResult struct {
	ProtocolVersion string             `json:"protocolVersion"`
	Capabilities    ServerCapabilities `json:"capabilities"`
	ServerInfo      ProcessInfo        `json:"serverInfo"`
	Instructions    string             `json:"instructions,omitempty"`
	Meta            map[string]any     `json:"_meta,omitempty"`
}

InitializeResult is the server's response to an "initialize" request.

type ItemFilter

type ItemFilter struct {
	// TenantID is the resolved tenant identifier. Set by the TenantResolver
	// so the dispatch layer can inject it into context via WithTenantID.
	// Empty if tenancy is not active.
	TenantID string

	// Tool returns true if the item should be visible to the caller.
	// nil means all tools are visible.
	Tool func(*Tool) bool

	// Resource returns true if the item should be visible to the caller.
	// nil means all resources are visible.
	Resource func(*Resource) bool

	// ResourceTemplate returns true if the item should be visible to the caller.
	// nil means all resource templates are visible.
	ResourceTemplate func(*ResourceTemplate) bool

	// Prompt returns true if the item should be visible to the caller.
	// nil means all prompts are visible.
	Prompt func(*Prompt) bool
}

ItemFilter controls per-request visibility of server items for multi-tenant isolation. Each function returns true to allow the item, false to hide/deny it. A nil function field means "allow all" for that item type.

Callers should use the nil-safe Allow* methods rather than calling the function fields directly.

func (*ItemFilter) AllowPrompt

func (f *ItemFilter) AllowPrompt(p *Prompt) (allowed bool)

AllowPrompt reports whether the filter permits the given prompt. Returns true when f is nil or f.Prompt is nil (allow-all). Panics in the filter function are recovered and treated as deny (fail-secure).

func (*ItemFilter) AllowResource

func (f *ItemFilter) AllowResource(r *Resource) (allowed bool)

AllowResource reports whether the filter permits the given resource. Returns true when f is nil or f.Resource is nil (allow-all). Panics in the filter function are recovered and treated as deny (fail-secure).

func (*ItemFilter) AllowResourceTemplate

func (f *ItemFilter) AllowResourceTemplate(t *ResourceTemplate) (allowed bool)

AllowResourceTemplate reports whether the filter permits the given resource template. Returns true when f is nil or f.ResourceTemplate is nil (allow-all). Panics in the filter function are recovered and treated as deny (fail-secure).

func (*ItemFilter) AllowTool

func (f *ItemFilter) AllowTool(t *Tool) (allowed bool)

AllowTool reports whether the filter permits the given tool. Returns true when f is nil or f.Tool is nil (allow-all). Panics in the filter function are recovered and treated as deny (fail-secure).

type JSONRPCError

type JSONRPCError struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Data    any    `json:"data,omitempty"`
}

JSONRPCError represents a JSON-RPC 2.0 error object.

func (*JSONRPCError) Error

func (e *JSONRPCError) Error() string

Error implements the error interface for JSONRPCError.

type JSONRPCNotification

type JSONRPCNotification struct {
	JSONRPC string `json:"jsonrpc"`
	Method  string `json:"method"`
	Params  any    `json:"params,omitempty"`
}

JSONRPCNotification is an outgoing server-to-client JSON-RPC 2.0 notification. Notifications have no "id" field and expect no response.

type JSONRPCRequest

type JSONRPCRequest struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      any             `json:"-"`
	Method  string          `json:"method"`
	Params  json.RawMessage `json:"params,omitempty"`
	// contains filtered or unexported fields
}

JSONRPCRequest represents an incoming JSON-RPC 2.0 request or notification. A notification has no "id" field; use IsNotification() to distinguish.

func (*JSONRPCRequest) IsNotification

func (r *JSONRPCRequest) IsNotification() bool

IsNotification reports whether this message is a notification (no "id" field).

func (*JSONRPCRequest) UnmarshalJSON

func (r *JSONRPCRequest) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom unmarshaling to detect whether "id" is present. JSON-RPC 2.0 distinguishes between absent id (notification) and null id (valid request).

type JSONRPCResponse

type JSONRPCResponse struct {
	JSONRPC string        `json:"jsonrpc"`
	ID      any           `json:"id"`
	Result  any           `json:"result,omitempty"`
	Error   *JSONRPCError `json:"error,omitempty"`
}

JSONRPCResponse represents an outgoing JSON-RPC 2.0 response. A response has either Result or Error, never both.

func NewErrorResponse

func NewErrorResponse(id any, code int, msg string) *JSONRPCResponse

NewErrorResponse creates an error response with the given id, code, and message.

func NewResponse

func NewResponse(id any, result any) *JSONRPCResponse

NewResponse creates a success response with the given id and result.

type Job

type Job struct {
	// ID is a unique identifier for this job.
	ID string

	// ToolName is the name of the tool that was called.
	ToolName string

	// Status is the current state of the job.
	Status JobStatus

	// Result holds the tool's output once the job is complete.
	Result *CallToolResult

	// Error holds an error message if the job failed.
	Error string

	// CreatedAt is when the job was submitted.
	CreatedAt time.Time

	// CompletedAt is when the job finished (zero if still running).
	CompletedAt time.Time
}

Job represents an asynchronous tool execution.

type JobStatus

type JobStatus string

JobStatus represents the lifecycle state of a job.

const (
	// JobStatusPending means the job is queued but not yet started.
	JobStatusPending JobStatus = "pending"

	// JobStatusRunning means the job is currently executing.
	JobStatusRunning JobStatus = "running"

	// JobStatusComplete means the job finished successfully.
	JobStatusComplete JobStatus = "complete"

	// JobStatusFailed means the job finished with an error.
	JobStatusFailed JobStatus = "failed"

	// JobStatusCancelled means the job was cancelled before completion.
	JobStatusCancelled JobStatus = "cancelled"
)

type JobStore

type JobStore struct {
	// contains filtered or unexported fields
}

JobStore manages the lifecycle and storage of asynchronous jobs. It is safe for concurrent use.

Warning: JobStore has no built-in eviction. Jobs are stored indefinitely. For long-running servers, callers should periodically call JobStore.Delete to remove completed or expired jobs and prevent unbounded memory growth.

func NewJobStore

func NewJobStore(opts ...JobStoreOption) *JobStore

NewJobStore creates a new job store.

func (*JobStore) Cancel

func (js *JobStore) Cancel(id string) error

Cancel transitions a job to cancelled status. Only jobs in pending or running state can be cancelled. Returns [errInvalidTransition] if the job is already in a terminal state.

Note: Cancel only updates the job's status in the store. It does not stop the background goroutine executing the handler (since the context is detached via context.WithoutCancel). The goroutine will run to completion but its result will be discarded because the store will reject the subsequent Complete/Fail transition. Callers who need cooperative cancellation should use the Sandbox middleware with a timeout or implement cancellation within the handler itself.

func (*JobStore) Complete

func (js *JobStore) Complete(id string, result *CallToolResult) error

Complete transitions a job from running to completed status with the given result. Returns [errInvalidTransition] if the job is not in running state. Note: The store does not deep-copy StructuredContent. If you set StructuredContent, treat it as immutable after submission to avoid exposing shared mutable state.

func (*JobStore) Delete

func (js *JobStore) Delete(id string) error

Delete removes a job from the store. Returns [errJobNotFound] if the job does not exist.

func (*JobStore) Fail

func (js *JobStore) Fail(id string, errMsg string) error

Fail transitions a job from running to failed status with the given error message. Returns [errInvalidTransition] if the job is not in running state.

func (*JobStore) Get

func (js *JobStore) Get(id string) (*Job, error)

Get returns a copy of the job to prevent data races. Note: The Content slice is deep-copied, but StructuredContent is not. If StructuredContent holds a mutable reference (map, slice, pointer), callers may observe shared state. Treat StructuredContent as immutable after submission.

func (*JobStore) List

func (js *JobStore) List() []*Job

List returns all jobs. The returned slice is a snapshot. Note: The Content slice is deep-copied, but StructuredContent is not. If StructuredContent holds a mutable reference (map, slice, pointer), callers may observe shared state. Treat StructuredContent as immutable after submission.

func (*JobStore) MarkRunning

func (js *JobStore) MarkRunning(id string) error

MarkRunning transitions a job from pending to running. Returns [errInvalidTransition] if the job is not in pending state.

func (*JobStore) Submit

func (js *JobStore) Submit(id, toolName string) (*Job, error)

Submit creates a new pending job and returns a copy. Returns [errJobIDEmpty] if id is empty and [errJobIDExists] if a job with the same ID already exists.

type JobStoreOption

type JobStoreOption func(*JobStore)

JobStoreOption configures a JobStore.

type LifespanFunc

type LifespanFunc func(ctx context.Context, s *Server) (context.Context, func(), error)

LifespanFunc is a lifecycle hook called by Server.Start before the server begins handling requests. It receives the base context and the server instance, and returns an enriched context that is passed to all handlers. The returned cleanup function is called during shutdown to release resources.

Use this to initialize shared resources (database connections, caches, etc.) that tool handlers need via context values.

Example:

finemcp.WithLifespan(func(ctx context.Context, s *finemcp.Server) (context.Context, func(), error) {
    db, err := sql.Open("postgres", dsn)
    if err != nil {
        return nil, nil, err
    }
    ctx = context.WithValue(ctx, dbKey, db)
    return ctx, func() { db.Close() }, nil
})

type ListParams

type ListParams struct {
	Cursor string         `json:"cursor,omitempty"`
	Limit  int            `json:"limit,omitempty"`
	Meta   map[string]any `json:"_meta,omitempty"`
}

ListParams contains pagination parameters for any list request (tools/list, resources/list, prompts/list, resources/templates/list).

Cursor is an opaque server-defined token identifying the starting position for the page. Limit is the maximum number of items to return per page (default 50; clamped to 1000).

Backward compatibility: when both Cursor and Limit are omitted or zero-valued (e.g., {} or null params), the server returns the full unpaginated list. To request the first page with the default size, send {"limit": 50} explicitly, or any non-zero limit without a cursor.

When pagination is active, the server returns a window of items starting at the given cursor, limited to at most Limit items, along with a nextCursor in the response when more items are available.

type ListPromptsResult

type ListPromptsResult struct {
	Prompts    []PromptInfo   `json:"prompts"`
	NextCursor string         `json:"nextCursor,omitempty"`
	Meta       map[string]any `json:"_meta,omitempty"`
}

ListPromptsResult is the server's response to a "prompts/list" request.

type ListResourceTemplatesResult

type ListResourceTemplatesResult struct {
	ResourceTemplates []ResourceTemplateInfo `json:"resourceTemplates"`
	NextCursor        string                 `json:"nextCursor,omitempty"`
	Meta              map[string]any         `json:"_meta,omitempty"`
}

ListResourceTemplatesResult is the server's response to a "resources/templates/list" request.

type ListResourcesResult

type ListResourcesResult struct {
	Resources  []ResourceInfo `json:"resources"`
	NextCursor string         `json:"nextCursor,omitempty"`
	Meta       map[string]any `json:"_meta,omitempty"`
}

ListResourcesResult is the server's response to a "resources/list" request.

type ListRootsResult

type ListRootsResult struct {
	Roots      []RootInfo     `json:"roots"`
	NextCursor string         `json:"nextCursor,omitempty"`
	Meta       map[string]any `json:"_meta,omitempty"`
}

ListRootsResult is the server's response to a "roots/list" request.

type ListTasksResult

type ListTasksResult struct {
	Tasks      []Task         `json:"tasks"`
	NextCursor string         `json:"nextCursor,omitempty"`
	Meta       map[string]any `json:"_meta,omitempty"`
}

ListTasksResult is the response for tasks/list.

type ListToolsResult

type ListToolsResult struct {
	Tools      []ToolInfo     `json:"tools"`
	NextCursor string         `json:"nextCursor,omitempty"`
	Meta       map[string]any `json:"_meta,omitempty"`
}

ListToolsResult is the server's response to a "tools/list" request.

type LogHandler

type LogHandler func(ctx context.Context, level LogLevel) error

LogHandler is called when the client sends a logging/setLevel request. The handler receives the requested log level and can adjust logging behavior.

type LogLevel

type LogLevel string

LogLevel represents the logging level for the server. Values follow RFC 5424 (syslog) severity levels as required by the MCP spec.

const (
	LogLevelDebug     LogLevel = "debug"     // RFC 5424 severity 7
	LogLevelInfo      LogLevel = "info"      // RFC 5424 severity 6
	LogLevelNotice    LogLevel = "notice"    // RFC 5424 severity 5
	LogLevelWarning   LogLevel = "warning"   // RFC 5424 severity 4
	LogLevelError     LogLevel = "error"     // RFC 5424 severity 3
	LogLevelCritical  LogLevel = "critical"  // RFC 5424 severity 2
	LogLevelAlert     LogLevel = "alert"     // RFC 5424 severity 1
	LogLevelEmergency LogLevel = "emergency" // RFC 5424 severity 0
)

LogLevel constants follow the RFC 5424 syslog severity levels as required by the MCP spec, ordered from least severe (debug) to most severe (emergency).

type LogMessageParams

type LogMessageParams struct {
	Level  LogLevel `json:"level"`
	Logger string   `json:"logger,omitempty"`
	Data   any      `json:"data"`
}

LogMessageParams is the server's payload for the "notifications/message" notification.

type LoggingCapability

type LoggingCapability struct{}

LoggingCapability signals that the server supports logging/setLevel and may emit notifications/message notifications. Per the MCP spec, the capability is an empty object when present.

type MergeFunc

type MergeFunc func(ctx context.Context, results map[string]ParallelResult) ([]byte, error)

MergeFunc receives the results of all parallel branches (keyed by handler name) and produces a single merged output. It is called in the goroutine that invoked the composed handler.

type Middleware

type Middleware func(ToolHandler) ToolHandler

Middleware wraps a ToolHandler, adding cross-cutting behaviour (logging, recovery, auth, etc.) without modifying the handler itself.

Middleware is applied in registration order: the first middleware added via Server.Use is the outermost wrapper (executes first on the way in, last on the way out).

server.Use(logging, recovery)
// call order: logging → recovery → handler → recovery → logging

type ModelHint

type ModelHint struct {
	// Name is a substring or full model identifier (e.g. "claude-4-sonnet").
	Name string `json:"name,omitempty"`
}

ModelHint is a partial or full model name hint for model selection.

type ModelPreferences

type ModelPreferences struct {
	// Hints is an ordered list of model name hints (most preferred first).
	// Each hint may contain a partial or full model name.
	Hints []ModelHint `json:"hints,omitempty"`

	// CostPriority indicates the relative importance of low cost (0–1).
	// A nil value means unset; 0.0 is a valid explicit preference.
	CostPriority *float64 `json:"costPriority,omitempty"`

	// SpeedPriority indicates the relative importance of low latency (0–1).
	// A nil value means unset; 0.0 is a valid explicit preference.
	SpeedPriority *float64 `json:"speedPriority,omitempty"`

	// IntelligencePriority indicates the relative importance of high
	// capability (0–1). A nil value means unset; 0.0 is a valid explicit preference.
	IntelligencePriority *float64 `json:"intelligencePriority,omitempty"`
}

ModelPreferences expresses the server's model selection preferences. Clients use these as hints when choosing which model to sample with.

type NamedHandler

type NamedHandler struct {
	Name    string
	Handler ToolHandler
}

NamedHandler pairs a handler with a name used as the key in the parallel result map. Names must be unique within a Parallel call.

type NotificationHandlerFunc

type NotificationHandlerFunc func(ctx context.Context, params json.RawMessage)

NotificationHandlerFunc is called when a JSON-RPC notification with the registered method name is received. The params argument is the raw JSON from the notification's "params" field (nil when absent).

Handlers are called synchronously in registration order on the dispatcher goroutine. A slow handler blocks processing of subsequent handlers and the dispatch goroutine itself. If your handler performs I/O or heavy computation, launch a goroutine:

s.OnNotification("heavy/work", func(ctx context.Context, params json.RawMessage) {
    go processAsync(ctx, params) // don't block the dispatch path
})

The context may be cancelled during handler execution. Long-running handlers should check ctx.Done() periodically and return early. Cancellation is only enforced between handlers, not mid-execution.

A panic in a handler is recovered — it does not crash the server or prevent subsequent handlers from running. If a NotificationPanicHandler is configured via WithNotificationPanicHandler, it is called with the recovered value and method name.

The handler function is retained for the lifetime of the server (or until Server.RemoveNotificationHandlers is called). Avoid capturing large objects in handler closures. If the handler needs access to large or changing state, fetch it on demand:

s.OnNotification("event", func(ctx context.Context, params json.RawMessage) {
    data := getCurrentData() // fetch on-demand, don't capture
    // ...
})

type NotificationPanicHandler

type NotificationPanicHandler func(method string, recovered any)

NotificationPanicHandler is called when a notification handler panics. The method is the notification method name and recovered is the value returned by recover(). Implementations must not panic.

The handler runs synchronously on the dispatch goroutine. Keep it fast — avoid blocking I/O. For async error reporting, launch a goroutine:

func asyncPanicHandler(method string, recovered any) {
    go uploadToErrorService(method, recovered)
}

The recovered value may contain attacker-controlled data if the panicking handler used unsanitized input. Implementations should sanitize before logging to prevent log injection:

func safePanicHandler(method string, recovered any) {
    log.Printf("panic in %s: %T", method, recovered) // log type, not raw value
}

type NotificationSender

type NotificationSender func(n *JSONRPCNotification)

NotificationSender is a function that transports implement to send server-side notifications (like notifications/progress) back to the client.

func NotificationSenderFromCtx

func NotificationSenderFromCtx(ctx context.Context) NotificationSender

NotificationSenderFromCtx extracts the NotificationSender from the context. Returns nil if the transport does not support server-side notifications.

type ParallelResult

type ParallelResult struct {
	// Output holds the raw bytes returned by the branch handler.
	// If the output is valid JSON it is embedded verbatim; otherwise it is
	// encoded as a JSON string (via toJSONValue).
	Output json.RawMessage `json:"output,omitempty"`
	Error  string          `json:"error,omitempty"`
}

ParallelResult holds the output or error for a single branch of a parallel composition.

type PendingRequests

type PendingRequests struct {
	// contains filtered or unexported fields
}

PendingRequests tracks in-flight server-to-client requests, correlating outbound requests with their responses by JSON-RPC ID. Transports embed this to implement the RequestSender callback.

Usage in a transport:

  1. Create a PendingRequests via NewPendingRequests(writeFn).
  2. Pass pr.Send as the RequestSender to WithRequestSender.
  3. When reading messages from the client, check pr.IsResponse(data) and call pr.Deliver(data) for responses; forward non-responses to HandleMessage.
  4. Call pr.CloseAll() on transport shutdown.

func NewPendingRequests

func NewPendingRequests(writeFn func(data []byte) error) *PendingRequests

NewPendingRequests creates a PendingRequests that writes outgoing requests via writeFn. The function must be safe for concurrent use.

func (*PendingRequests) CloseAll

func (pr *PendingRequests) CloseAll()

CloseAll cancels all pending requests. Called on transport shutdown. After CloseAll, Send returns an error immediately.

func (*PendingRequests) Deliver

func (pr *PendingRequests) Deliver(data []byte) bool

Deliver routes a client response to the pending request matching its ID. Returns true if the response was delivered, false if no pending request matches (e.g., the caller timed out already or the response is unexpected).

func (*PendingRequests) Send

func (pr *PendingRequests) Send(ctx context.Context, method string, params any) (*JSONRPCResponse, error)

Send implements the RequestSender signature. It assigns a unique ID to the request, writes it to the client, and blocks until the client responds or the context expires.

type ProcessInfo

type ProcessInfo struct {
	Name        string `json:"name"`
	Version     string `json:"version"`
	Title       string `json:"title,omitempty"`
	Description string `json:"description,omitempty"`
	WebsiteURL  string `json:"websiteUrl,omitempty"`
	Icons       []Icon `json:"icons,omitempty"`
}

ProcessInfo identifies an MCP endpoint (client or server).

type ProgressParams

type ProgressParams struct {
	// ProgressToken correlates the notification with the originating request.
	// When the client sends _meta.progressToken in the request, the server
	// uses that value here; otherwise it defaults to the JSON-RPC request ID.
	ProgressToken any `json:"progressToken"`

	// Progress is the current progress value (e.g. number of items processed).
	Progress float64 `json:"progress"`

	// Total is the total expected value. When > 0, clients can show a percentage.
	// Zero means indeterminate progress.
	Total float64 `json:"total,omitempty"`

	// Content holds optional content blocks embedded in this progress notification.
	// Streaming-capable servers populate this field to allow clients to surface
	// partial tool-result content before the final tools/call response arrives.
	// This field is omitted by servers that do not support streaming; existing
	// progress consumers are unaffected by its presence or absence.
	Content []json.RawMessage `json:"content,omitempty"`
}

ProgressParams is the server's payload for the "notifications/progress" notification.

type ProgressReporter

type ProgressReporter func(progress, total float64)

ProgressReporter is a function tool handlers call to emit a progress notification. progress is the current value; total is the expected final value (0 = indeterminate).

func ProgressReporterFromCtx

func ProgressReporterFromCtx(ctx context.Context) ProgressReporter

ProgressReporterFromCtx extracts the ProgressReporter from the context. Returns nil if no reporter is set (progress reporting is a no-op in that case).

type Prompt

type Prompt struct {
	// Name is the unique identifier for this prompt.
	Name string

	// Description is an optional human-readable description.
	Description string

	// Arguments defines the expected parameters for this prompt.
	Arguments []PromptArgument

	// Handler generates the prompt messages.
	Handler PromptHandler

	// Completer provides argument auto-completions for this prompt.
	// When nil, the server returns an empty completion result.
	Completer CompleteHandler
}

Prompt represents a registered MCP prompt template.

func NewPrompt

func NewPrompt(name string, handler PromptHandler, opts ...PromptOption) (*Prompt, error)

NewPrompt creates a new Prompt with the given name, handler, and options.

type PromptArgument

type PromptArgument struct {
	// Name is the argument identifier.
	Name string `json:"name"`

	// Description is an optional human-readable description.
	Description string `json:"description,omitempty"`

	// Required indicates whether this argument must be provided.
	Required bool `json:"required,omitempty"`
}

PromptArgument describes a single argument accepted by a prompt.

type PromptCapability

type PromptCapability struct {
	// ListChanged indicates whether the server will emit prompts/list_changed notifications.
	ListChanged bool `json:"listChanged,omitempty"`
}

PromptCapability describes the server's prompt-related capabilities.

type PromptHandler

type PromptHandler func(ctx context.Context, args map[string]string) ([]PromptMessage, error)

PromptHandler generates prompt messages for the given arguments. It receives the context and a map of argument values, and returns a slice of PromptMessage items.

type PromptInfo

type PromptInfo struct {
	Name        string           `json:"name"`
	Description string           `json:"description,omitempty"`
	Arguments   []PromptArgument `json:"arguments,omitempty"`
}

PromptInfo is the wire representation of a prompt in a prompts/list response.

type PromptMessage

type PromptMessage struct {
	// Role is the speaker role: "user" or "assistant".
	Role string `json:"role"`

	// Content is the message content.
	Content Content `json:"content"`
}

PromptMessage represents a single message in a prompt's output.

func NewAssistantMessage

func NewAssistantMessage(text string) PromptMessage

NewAssistantMessage creates a PromptMessage with role "assistant" and text content.

func NewUserMessage

func NewUserMessage(text string) PromptMessage

NewUserMessage creates a PromptMessage with role "user" and text content.

func (*PromptMessage) UnmarshalJSON

func (m *PromptMessage) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a PromptMessage, handling the Content interface field.

type PromptOption

type PromptOption func(*Prompt)

PromptOption is a functional option for configuring a Prompt.

func WithCompleter

func WithCompleter(handler CompleteHandler) PromptOption

WithCompleter attaches a CompleteHandler to a Prompt. When a client sends completion/complete for this prompt, the handler is invoked with the argument details.

func WithPromptArguments

func WithPromptArguments(args ...PromptArgument) PromptOption

WithPromptArguments sets the prompt's expected arguments. The provided slice is copied to avoid aliasing with the caller's data.

func WithPromptDescription

func WithPromptDescription(desc string) PromptOption

WithPromptDescription sets the prompt's human-readable description.

type ReadResourceParams

type ReadResourceParams struct {
	URI  string         `json:"uri"`
	Meta map[string]any `json:"_meta,omitempty"`
}

ReadResourceParams is the client's payload for a "resources/read" request.

type ReadResourceResult

type ReadResourceResult struct {
	Contents []ResourceContent `json:"contents"`
	Meta     map[string]any    `json:"_meta,omitempty"`
}

ReadResourceResult is the server's response to a "resources/read" request.

func ReadResourceResultFromText

func ReadResourceResultFromText(uri, text string) *ReadResourceResult

ReadResourceResultFromText is a convenience for returning a single text resource.

func (ReadResourceResult) MarshalJSON

func (r ReadResourceResult) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler. No custom logic needed, but having the method makes the intent explicit and prevents accidental breakage.

type RequestSender

type RequestSender func(ctx context.Context, method string, params any) (*JSONRPCResponse, error)

RequestSender is a function that transports implement to send a JSON-RPC request from the server to the client and wait for the client's response. This enables server-initiated requests such as sampling/createMessage.

The transport must:

  1. Assign an "id" to the outgoing request.
  2. Write the request to the client.
  3. Block until the client sends a JSON-RPC response with the matching "id".
  4. Return the response, or an error if the context expires / transport fails.

The context controls the deadline for the round-trip. Implementations should select on ctx.Done() while waiting for the client response.

func RequestSenderFromCtx

func RequestSenderFromCtx(ctx context.Context) RequestSender

RequestSenderFromCtx extracts the RequestSender from the context. Returns nil if the transport does not support server-to-client requests.

type Resource

type Resource struct {
	// URI is the unique identifier for this resource (e.g. "file:///etc/hosts").
	URI string

	// Name is a human-readable name for the resource.
	Name string

	// Description is an optional human-readable description.
	Description string

	// MimeType is the MIME type of the resource content (e.g. "text/plain").
	MimeType string

	// Handler reads the resource content.
	Handler ResourceHandler
}

Resource represents a registered MCP resource.

func NewResource

func NewResource(uri, name string, handler ResourceHandler, opts ...ResourceOption) (*Resource, error)

NewResource creates a new Resource with the given URI, name, handler, and options.

type ResourceCapability

type ResourceCapability struct {
	// Subscribe indicates whether the server supports resource subscriptions.
	Subscribe bool `json:"subscribe,omitempty"`
	// ListChanged indicates whether the server will emit resources/list_changed notifications.
	ListChanged bool `json:"listChanged,omitempty"`
}

ResourceCapability describes the server's resource-related capabilities.

type ResourceContent

type ResourceContent struct {
	// URI is the resource URI this content belongs to.
	URI string `json:"uri"`

	// MimeType is the MIME type of this content.
	MimeType string `json:"mimeType,omitempty"`

	// Text holds the text content (mutually exclusive with Blob).
	Text *string `json:"text,omitempty"`

	// Blob holds base64-encoded binary content (mutually exclusive with Text).
	Blob *string `json:"blob,omitempty"`
}

ResourceContent represents the content of a resource. Exactly one of Text or Blob must be set.

func NewBlobResourceContent

func NewBlobResourceContent(uri string, data []byte) ResourceContent

NewBlobResourceContent creates a binary resource content item. The data is base64-encoded automatically.

func NewTextResourceContent

func NewTextResourceContent(uri, text string) ResourceContent

NewTextResourceContent creates a text resource content item.

func (ResourceContent) MarshalJSON

func (c ResourceContent) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler for ResourceContent. It enforces that exactly one of Text or Blob is present in the output.

func (ResourceContent) Validate

func (c ResourceContent) Validate() error

Validate checks that the ResourceContent is well-formed: URI must be non-empty and exactly one of Text or Blob must be set.

type ResourceHandler

type ResourceHandler func(ctx context.Context, uri string) ([]ResourceContent, error)

ResourceHandler reads a resource identified by its URI. It receives the context and the resource URI, and returns a slice of ResourceContent items (text or blob).

type ResourceInfo

type ResourceInfo struct {
	URI         string `json:"uri"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	MimeType    string `json:"mimeType,omitempty"`
}

ResourceInfo is the wire representation of a resource in a resources/list response.

type ResourceOption

type ResourceOption func(*Resource)

ResourceOption is a functional option for configuring a Resource.

func WithResourceDescription

func WithResourceDescription(desc string) ResourceOption

WithResourceDescription sets the resource's human-readable description.

func WithResourceMimeType

func WithResourceMimeType(mime string) ResourceOption

WithResourceMimeType sets the resource's MIME type.

type ResourceTemplate

type ResourceTemplate struct {
	// URITemplate is an RFC 6570 URI template.
	URITemplate string

	// Name is a human-readable name for the template.
	Name string

	// Description is an optional human-readable description.
	Description string

	// MimeType is the MIME type of the resource content.
	MimeType string

	// Handler reads the resource; the URI parameter is the expanded template.
	Handler ResourceHandler

	// Completer provides argument auto-completions for this template.
	// When nil, the server returns an empty completion result.
	Completer CompleteHandler
	// contains filtered or unexported fields
}

ResourceTemplate represents a URI-template resource that can be parameterized at read time (e.g. "file:///logs/{date}.log").

When a client sends a resources/read request and no static resource matches the URI, the server tries each registered template in lexicographic URITemplate order and invokes the first matching handler with the concrete URI. Overlapping templates are not recommended; the winner depends on alphabetic order, which may be surprising.

func NewResourceTemplate

func NewResourceTemplate(uriTemplate, name string, handler ResourceHandler, opts ...ResourceTemplateOption) (*ResourceTemplate, error)

NewResourceTemplate creates a new ResourceTemplate with the given URI template, name, handler, and options. It validates the template syntax at creation time, returning errTemplateInvalid for malformed or unsupported templates.

type ResourceTemplateInfo

type ResourceTemplateInfo struct {
	URITemplate string `json:"uriTemplate"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	MimeType    string `json:"mimeType,omitempty"`
}

ResourceTemplateInfo is the wire representation in a resources/templates/list response.

type ResourceTemplateOption

type ResourceTemplateOption func(*ResourceTemplate)

ResourceTemplateOption is a functional option for configuring a ResourceTemplate.

func WithTemplateCompleter

func WithTemplateCompleter(handler CompleteHandler) ResourceTemplateOption

WithTemplateCompleter attaches a CompleteHandler to a ResourceTemplate. When a client sends completion/complete for this template, the handler is invoked with the argument details.

func WithTemplateDescription

func WithTemplateDescription(desc string) ResourceTemplateOption

WithTemplateDescription sets the template's human-readable description.

func WithTemplateMimeType

func WithTemplateMimeType(mime string) ResourceTemplateOption

WithTemplateMimeType sets the template's MIME type.

type ResourceUpdatedParams

type ResourceUpdatedParams struct {
	URI string `json:"uri"`
}

ResourceUpdatedParams is the server's payload for the "notifications/resources/updated" notification.

type Root

type Root struct {
	// URI is the unique identifier for this root (e.g. "file:///workspace/project").
	// Must not be empty.
	URI string

	// Name is an optional human-readable name for the root (e.g. "Project Name").
	// May be empty.
	Name string
}

Root represents a workspace root directory that the server is aware of. Roots provide context about the server's workspace boundaries.

func NewRoot

func NewRoot(uri string, opts ...RootOption) (*Root, error)

NewRoot creates a new Root with the given URI and options.

type RootInfo

type RootInfo struct {
	URI  string `json:"uri"`
	Name string `json:"name,omitempty"`
}

RootInfo is the wire representation of a root in a roots/list response.

type RootOption

type RootOption func(*Root)

RootOption is a functional option for configuring a Root.

func WithRootName

func WithRootName(name string) RootOption

WithRootName sets the root's human-readable name.

type SamplingCapability

type SamplingCapability struct{}

SamplingCapability signals that the client supports sampling/createMessage. Per the MCP spec, the capability is an empty object when present.

type SamplingMessage

type SamplingMessage struct {
	// Role is the speaker role: "user" or "assistant".
	Role string `json:"role"`

	// Content is the message content (text, image, or audio).
	Content Content `json:"content"`
}

SamplingMessage represents a single message in a sampling request or response. It mirrors the MCP SamplingMessage schema.

func (SamplingMessage) MarshalJSON

func (m SamplingMessage) MarshalJSON() ([]byte, error)

MarshalJSON marshals a SamplingMessage, delegating content serialization to the Content interface implementation.

func (*SamplingMessage) UnmarshalJSON

func (m *SamplingMessage) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a SamplingMessage, using DecodeContent for the polymorphic Content field.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the core MCP server that manages tool registration and dispatch. It is transport-agnostic; transports (stdio, HTTP/SSE) are layered on top.

func NewServer

func NewServer(name, version string, opts ...ServerOption) *Server

NewServer creates a new MCP server with the given implementation name, version, and options.

func (*Server) AddSender

func (s *Server) AddSender(id string, sender NotificationSender) error

AddSender registers a connection's NotificationSender for broadcasting list-changed events. It returns an error if id is empty, sender is nil, or a sender is already registered under id.

func (*Server) AddSessionTool

func (s *Server) AddSessionTool(ctx context.Context, sessionID string, tool *Tool) error

AddSessionTool registers a tool that is visible only to the given session. The sessionID should match the SubscriberID used by the transport for that connection.

The ctx parameter is used for tenant-level validation: when a TenantResolver is active, the tool is checked against the resolved tenant's filter before registration. Pass context.Background() if no tenant filtering is needed.

Session tools overlay the global tool registry: if a session tool has the same name as a global tool, the session tool takes priority for that session. When this occurs, the server's SessionToolShadowCallback (if configured via OnSessionToolShadow) is invoked.

After a successful add, a notifications/tools/list_changed notification is sent to the affected session only (other sessions are not affected).

Returns an error if:

  • the context is cancelled,
  • the session has been closed (disconnected),
  • the session ID is empty,
  • the tool is nil/invalid or its name fails validation,
  • a session tool with the same name is already registered,
  • the per-session tool limit is exceeded,
  • the tenant filter rejects the tool.

Safe for concurrent use.

func (*Server) CallTool

func (s *Server) CallTool(ctx context.Context, name string, input []byte) (*CallToolResult, error)

CallTool looks up a tool by name and executes its handler. Session-specific tools take priority over global tools for the calling session (identified by SubscriberIDFromCtx). Returns errToolNotFound if no tool with the given name is registered, or if a TenantResolver is active and the tool is filtered out for the current tenant (indistinguishable from not found to prevent enumeration).

func (*Server) CreateMessage

func (s *Server) CreateMessage(ctx context.Context, params CreateMessageParams) (*CreateMessageResult, error)

CreateMessage sends a sampling/createMessage request to the client and blocks until the client responds with an LLM-generated message.

This is a server-initiated request: the server asks the client to perform LLM inference on its behalf. The client must have declared sampling support in its capabilities during initialization.

The context controls the deadline for the entire round-trip. Tool handlers call this method when they need the LLM to make a decision mid-execution.

Prerequisites:

  • The server must be initialized (initialize handshake completed).
  • The client must have declared sampling capability (ClientCaps.Sampling != nil).
  • The transport must provide a RequestSender via context.

Like other user-facing methods, CreateMessage is not wrapped with panic recovery by default. For production deployments, use a recovery middleware.

func (*Server) ElicitUser

func (s *Server) ElicitUser(ctx context.Context, params ElicitationParams) (*ElicitationResult, error)

ElicitUser sends an elicitation/create request to the client and blocks until the user responds with input.

This is a server-initiated request: the server asks the client to prompt the user for input on its behalf. The client must have declared elicitation support in its capabilities during initialization.

The context controls the deadline for the entire round-trip.

Prerequisites:

  • The server must be initialized (initialize handshake completed).
  • The client must have declared elicitation capability (ClientCaps.Elicitation != nil).
  • The transport must provide a RequestSender via context.

func (*Server) GetPrompt

func (s *Server) GetPrompt(ctx context.Context, name string, args map[string]string) (*GetPromptResult, error)

GetPrompt looks up a prompt by name and invokes its handler. Returns errPromptNotFound if no prompt with the given name is registered or if a TenantResolver is active and the prompt is filtered out for the current tenant (indistinguishable from not found).

Security note: The maxPromptMessages limit (1000) is enforced AFTER the handler returns. Prompt handlers are trusted code and must not allocate excessive resources. This limit protects against accidental bugs in handlers, not malicious code. Handlers with prompt registration capability are part of the server's trusted computing base.

func (*Server) HandleMessage

func (s *Server) HandleMessage(ctx context.Context, data []byte) (*JSONRPCResponse, error)

HandleMessage is the single entry point for all incoming JSON-RPC messages. It parses the raw bytes, routes to the correct method handler, and returns a JSON-RPC response. For notifications it returns nil (no response required). Protocol-level errors (bad JSON, unknown method) are returned as error responses, never as Go errors. The returned error is reserved for truly unrecoverable issues.

func (*Server) ListPrompts

func (s *Server) ListPrompts() []*Prompt

ListPrompts returns a snapshot of all registered prompts, sorted by name. Sorting ensures deterministic ordering for cursor-based pagination.

func (*Server) ListResourceTemplates

func (s *Server) ListResourceTemplates() []*ResourceTemplate

ListResourceTemplates returns a snapshot of all registered resource templates, sorted by URI template. Sorting ensures deterministic ordering for cursor-based pagination.

func (*Server) ListResources

func (s *Server) ListResources() []*Resource

ListResources returns a snapshot of all registered resources, sorted by URI. Sorting ensures deterministic ordering for cursor-based pagination.

func (*Server) ListRoots

func (s *Server) ListRoots() []*Root

ListRoots returns all registered roots, sorted by URI.

func (*Server) ListTools

func (s *Server) ListTools() []*Tool

ListTools returns a snapshot of all registered tools, sorted by name. The returned slice is a copy; mutating it does not affect the server. Sorting ensures deterministic ordering for cursor-based pagination.

func (*Server) Name

func (s *Server) Name() string

Name returns the server's implementation name.

func (*Server) NegotiatedVersion

func (s *Server) NegotiatedVersion() string

NegotiatedVersion returns the protocol version agreed upon during the initialize handshake. Returns "" if the handshake has not completed.

func (*Server) NotificationStats

func (s *Server) NotificationStats() map[string]int

NotificationStats returns a point-in-time snapshot of registered notification handler counts keyed by method name. The snapshot is consistent (all counts from the same instant) but may become stale if handlers are added or removed after the call returns. The returned map is a copy and safe to mutate. Useful for debugging and monitoring.

Map iteration order is non-deterministic per Go semantics.

This is a server-wide view: in multi-tenant deployments the result includes methods from all tenants. Restrict access to trusted operators.

Allocates O(N) memory where N is the number of registered methods. Not intended for hot-path use.

func (*Server) NotifyPromptsListChanged

func (s *Server) NotifyPromptsListChanged()

NotifyPromptsListChanged broadcasts notifications/prompts/list_changed to all connected clients.

func (*Server) NotifyResourceUpdated

func (s *Server) NotifyResourceUpdated(uri string)

NotifyResourceUpdated notifies all subscribed clients that a resource has changed.

func (*Server) NotifyResourcesListChanged

func (s *Server) NotifyResourcesListChanged()

NotifyResourcesListChanged broadcasts notifications/resources/list_changed to all connected clients.

func (*Server) NotifyRootsListChanged

func (s *Server) NotifyRootsListChanged()

NotifyRootsListChanged broadcasts notifications/roots/list_changed to all connected clients.

func (*Server) NotifyToolsListChanged

func (s *Server) NotifyToolsListChanged()

NotifyToolsListChanged broadcasts notifications/tools/list_changed to all connected clients.

func (*Server) OnNotification

func (s *Server) OnNotification(method string, handler NotificationHandlerFunc)

OnNotification registers a handler for a JSON-RPC notification method. Multiple handlers can be registered for the same method — they are called in registration order. Handlers registered for built-in methods (e.g. "notifications/initialized", "notifications/cancelled") run after the server's built-in processing for that method.

Panics if method is empty, contains invalid characters, handler is nil, or the handler limit is exceeded.

Method names are validated for MCP protocol compliance. Do not use method names in file paths, shell commands, or SQL queries without additional sanitization.

Safe for concurrent use.

Example
server := NewServer("myserver", "1.0")

// Register a handler for custom notifications.
server.OnNotification("custom/event", func(ctx context.Context, params json.RawMessage) {
	var data map[string]any
	if err := json.Unmarshal(params, &data); err != nil {
		return
	}
	fmt.Printf("event: %v\n", data["type"])
})

// Multiple handlers for the same method run in registration order.
server.OnNotification("custom/event", func(ctx context.Context, params json.RawMessage) {
	fmt.Println("second handler")
})

// Check registered handlers.
stats := server.NotificationStats()
fmt.Printf("handlers for custom/event: %d\n", stats["custom/event"])
Output:
handlers for custom/event: 2

func (*Server) OnSessionToolShadow

func (s *Server) OnSessionToolShadow(cb SessionToolShadowCallback)

OnSessionToolShadow registers a callback that is invoked when a session tool shadows a global tool with the same name. This is informational only; the registration proceeds regardless. Set to nil to disable.

The callback must be safe for concurrent use and should return quickly.

Safe to call concurrently; uses atomic storage internally.

func (*Server) ReadResource

func (s *Server) ReadResource(ctx context.Context, uri string) (*ReadResourceResult, error)

ReadResource looks up a resource by URI and invokes its handler. Returns errResourceNotFound if no resource or matching template with the given URI is registered, or if a TenantResolver is active and the item is filtered out for the current tenant (indistinguishable from not found).

func (*Server) RegisterPrompt

func (s *Server) RegisterPrompt(p *Prompt) error

RegisterPrompt adds a prompt to the server's registry. Returns an error if the prompt is nil, has missing required fields, or a prompt with the same name already exists.

func (*Server) RegisterResource

func (s *Server) RegisterResource(r *Resource) error

RegisterResource adds a resource to the server's registry. Returns an error if the resource is nil, has missing required fields, or a resource with the same URI already exists.

func (*Server) RegisterResourceTemplate

func (s *Server) RegisterResourceTemplate(t *ResourceTemplate) error

RegisterResourceTemplate adds a resource template to the server's registry. Returns an error if the template is nil, has a malformed URI template, or a template with the same URI already exists.

func (*Server) RegisterRoot

func (s *Server) RegisterRoot(r *Root) error

RegisterRoot adds a root to the server's registry. Returns an error if the root is nil, URI is empty, or the URI is already registered.

func (*Server) RegisterTool

func (s *Server) RegisterTool(tool *Tool) error

RegisterTool adds a tool to the server's registry. The tool must not be nil, its name must be a valid MCP tool name (non-empty, ≤128 characters, only [A-Za-z0-9_\-.] allowed), and its Handler must not be nil.

Returns:

  • errToolNil if tool is nil
  • errToolNameEmpty, errToolNameTooLong, or errToolNameChars if the name is invalid
  • errToolHandlerNil if the handler is nil
  • errToolAlreadyExists if a tool with the same name is already registered

On success a notifications/tools/list_changed notification is broadcast to all connected clients.

func (*Server) RegisterTools

func (s *Server) RegisterTools(tools ...*Tool) error

RegisterTools registers multiple tools atomically and broadcasts a single notifications/tools/list_changed to all connected clients. Returns a validation or duplicate error on the first failing tool; on error, no tools from the batch are registered (all-or-nothing).

func (*Server) RemoveNotificationHandlers

func (s *Server) RemoveNotificationHandlers(method string) int

RemoveNotificationHandlers removes all handlers registered for the given notification method. Returns the number of handlers that were removed. This is useful for per-session cleanup patterns where handlers are registered and later torn down.

Removal is not retroactive: handlers for in-flight notifications that acquired the handler list before removal will still complete. For strict cleanup guarantees, cancel the session context before calling RemoveNotificationHandlers so that in-flight handlers observe cancellation.

Returns 0 for empty or oversized method names (which could never have been registered via Server.OnNotification).

Safe for concurrent use.

func (*Server) RemoveSender

func (s *Server) RemoveSender(id string)

RemoveSender removes a connection's NotificationSender.

func (*Server) RemoveSessionTool

func (s *Server) RemoveSessionTool(sessionID, name string) error

RemoveSessionTool removes a session-specific tool by name. Returns errSessionToolNotFound if no such session tool exists.

After a successful removal, a notifications/tools/list_changed notification is sent to the affected session only.

Safe for concurrent use.

func (*Server) RemoveSessionTools

func (s *Server) RemoveSessionTools(sessionID string)

RemoveSessionTools removes all session-specific tools for the given session and marks the session as closed. Subsequent AddSessionTool calls for this session will return errSessionClosed.

This should be called by transports when a client disconnects. It is safe to call even if the session has no tools.

Unlike Add/Remove, this does NOT send a list_changed notification since the session is being torn down.

Safe for concurrent use.

func (*Server) RemoveTool

func (s *Server) RemoveTool(name string) error

RemoveTool removes a tool from the server's registry. Returns errToolNotFound if no tool with the given name is registered. After a successful removal, a notifications/tools/list_changed notification is broadcast to all connected clients.

func (*Server) SendLogMessage

func (s *Server) SendLogMessage(ctx context.Context, level LogLevel, logger string, data any) error

SendLogMessage sends a notifications/message notification to the client with the provided log level and message data. Returns errNotInitialized if the handshake hasn't completed, since the protocol version and client capabilities are unknown until then.

func (*Server) SessionTools

func (s *Server) SessionTools(sessionID string) []*Tool

SessionTools returns a snapshot of tools registered for the given session, sorted by name. Does not include global tools. Returns nil if the session has no session-specific tools.

func (*Server) SetAuthChecker

func (s *Server) SetAuthChecker(checker AuthChecker)

SetAuthChecker registers a protocol-level authentication checker. The checker is called for ALL JSON-RPC requests (except initialize and ping) after JSON-RPC parsing but before method routing. If it returns an error, the request is rejected with a JSON-RPC error response (code -32001).

This provides defense-in-depth: the HTTP middleware layer rejects unauthenticated connections, while the auth checker ensures every protocol message is associated with a verified identity.

Safe to call concurrently; uses atomic storage internally.

Usage:

server.SetAuthChecker(middleware.RequireAuth())

func (*Server) SetLogHandler

func (s *Server) SetLogHandler(handler LogHandler)

SetLogHandler registers a handler for logging/setLevel requests. The handler is called when clients send logging/setLevel requests.

func (*Server) SetTenantResolver

func (s *Server) SetTenantResolver(resolver TenantResolver)

SetTenantResolver registers a tenant resolution hook for multi-tenant isolation. The resolver is called for ALL JSON-RPC requests (except initialize and ping) after authentication but before method routing. If it returns an error, the request is rejected with a JSON-RPC error (code -32002).

This provides multi-tenant isolation: each request is associated with a tenant, and only that tenant's permitted tools, resources, and prompts are visible through list operations and accessible through call/read/get operations.

Safe to call concurrently; uses atomic storage internally.

Usage:

server.SetTenantResolver(middleware.NewTenantResolver(
    middleware.TenantFromAuthSubject(),
    middleware.NewStaticTenantStore(configs),
))

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

Shutdown gracefully stops the server by waiting for in-flight requests to complete. If the context expires before all requests finish, it returns the context error.

Usage:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
    log.Println("shutdown timed out:", err)
}

func (*Server) Start

func (s *Server) Start(ctx context.Context, runFn func(ctx context.Context) error) error

Start runs the server's lifespan hook (if configured) and calls runFn. The lifespan hook is called before runFn to initialize shared resources; its cleanup function runs after runFn returns.

If no lifespan hook is configured, Start simply calls runFn(ctx).

This is the recommended way to run a transport with lifespan support:

server := finemcp.NewServer("app", "1.0",
    finemcp.WithLifespan(func(ctx context.Context, s *finemcp.Server) (context.Context, func(), error) {
        db, err := sql.Open("postgres", dsn)
        if err != nil {
            return nil, nil, err
        }
        return context.WithValue(ctx, dbKey, db), func() { db.Close() }, nil
    }),
)
err := server.Start(ctx, func(ctx context.Context) error {
    return transport.StartStreamable(ctx, server, ":8080")
})

func (*Server) Subscribe

func (s *Server) Subscribe(subscriberID, uri string, sender NotificationSender) error

Subscribe adds a client's subscription to a specific resource URI. It returns [errSubscriptionsDisabled] if the server was not configured with WithResourceSubscriptions.

func (*Server) Unsubscribe

func (s *Server) Unsubscribe(subscriberID, uri string)

Unsubscribe removes a client's subscription to a specific resource URI.

func (*Server) UnsubscribeAll

func (s *Server) UnsubscribeAll(subscriberID string)

UnsubscribeAll removes all subscriptions for a specific client connection. This should be called by transports when a client disconnects.

func (*Server) Use

func (s *Server) Use(mw ...Middleware)

Use appends one or more middleware to the server's chain. Middleware are applied in the order they are added. Must be called before serving requests; not safe for concurrent use with CallTool.

func (*Server) Version

func (s *Server) Version() string

Version returns the server's implementation version.

type ServerCapabilities

type ServerCapabilities struct {
	Tools       *ToolCapability       `json:"tools,omitempty"`
	Resources   *ResourceCapability   `json:"resources,omitempty"`
	Prompts     *PromptCapability     `json:"prompts,omitempty"`
	Tasks       *TaskCapability       `json:"tasks,omitempty"`
	Completions *CompletionCapability `json:"completions,omitempty"`
	Logging     *LoggingCapability    `json:"logging,omitempty"`
}

ServerCapabilities advertises what the server supports.

type ServerOption

type ServerOption func(*Server)

ServerOption is a functional option for configuring a Server.

func WithIcons

func WithIcons(icons ...Icon) ServerOption

WithIcons sets the server's icons. These are included in the serverInfo of the initialize response and can be used by clients (e.g. Claude Desktop) to display a visual representation of the server.

Panics if any icon has a Src URL with an unsafe scheme (only http, https, and data are allowed). Relative URLs and protocol-relative URLs are rejected. Data URLs must use an image/* MIME type.

func WithInstructions

func WithInstructions(instructions string) ServerOption

WithInstructions sets optional instructions for the client. These are included in the initialize response and can guide client behavior.

Panics if the instructions string exceeds 100 KB.

func WithLifespan

func WithLifespan(fn LifespanFunc) ServerOption

WithLifespan registers a lifecycle hook that is called by Server.Start before the server begins handling requests. The hook can initialize shared resources and enrich the context. The returned cleanup function is called during shutdown.

func WithMaxHandlersPerNotification

func WithMaxHandlersPerNotification(n int) ServerOption

WithMaxHandlersPerNotification sets the maximum number of handlers that can be registered for a single notification method via OnNotification. The default is DefaultMaxHandlersPerMethod (100).

func WithMaxNotificationMethods

func WithMaxNotificationMethods(n int) ServerOption

WithMaxNotificationMethods sets the maximum number of distinct notification methods that can have handlers registered via OnNotification. The default is DefaultMaxNotificationMethods (1000). Prevents unbounded memory growth from excessive handler registrations.

func WithMaxSessionTools

func WithMaxSessionTools(n int) ServerOption

WithMaxSessionTools sets the maximum number of tools a single session can register via AddSessionTool. The default is DefaultMaxSessionTools (100). Use this to tune the limit for your deployment — lower values reduce memory exposure from misbehaving clients.

func WithMaxSessions

func WithMaxSessions(n int) ServerOption

WithMaxSessions sets the maximum number of concurrent sessions that can register session tools. The default is DefaultMaxSessions (10,000). Prevents unbounded memory growth from rogue transport connections.

func WithNotificationPanicHandler

func WithNotificationPanicHandler(h NotificationPanicHandler) ServerOption

WithNotificationPanicHandler registers a callback that is invoked whenever a notification handler panics. Without this option, panics are recovered and silently discarded. The callback receives the notification method name and the recovered value.

func WithResourceSubscriptions

func WithResourceSubscriptions() ServerOption

WithResourceSubscriptions enables support for resource subscriptions. When enabled, the server advertises the "subscribe" capability, allowing clients to subscribe to resource updates.

func WithServerDescription

func WithServerDescription(desc string) ServerOption

WithServerDescription sets the server's human-readable description. This is included in the serverInfo of the initialize response.

func WithServerTitle

func WithServerTitle(title string) ServerOption

WithServerTitle sets the server's display name. This is included in the serverInfo of the initialize response and can be used by clients for display purposes.

func WithStreamBufferSize

func WithStreamBufferSize(n int) ServerOption

WithStreamBufferSize sets the number of content chunks that a ToolStream can buffer before Send blocks, providing backpressure to the tool handler. The default is DefaultStreamBufferSize (16). Use a larger value for tools that produce many small chunks rapidly.

func WithSupportedVersions

func WithSupportedVersions(versions ...string) ServerOption

WithSupportedVersions overrides the default set of MCP protocol versions that the server accepts during the initialize handshake. Versions must be in descending chronological order (latest first). The first entry is the server's preferred version and is returned when the client requests an unsupported version.

Panics if no versions are provided — at least one version is required. Panics if versions are not in descending order (YYYY-MM-DD strings). If not set, the server defaults to DefaultSupportedVersions().

func WithTaskStore

func WithTaskStore(ts *TaskStore) ServerOption

WithTaskStore enables spec-compliant task support (tasks/get, tasks/result, tasks/cancel, tasks/list) and allows task-augmented tools/call requests. Panics if ts is nil.

func WithWebsiteURL

func WithWebsiteURL(url string) ServerOption

WithWebsiteURL sets the server's website URL. This is included in the serverInfo of the initialize response.

type SessionToolShadowCallback

type SessionToolShadowCallback func(sessionID, toolName string)

SessionToolShadowCallback is called when a session tool shadows a global tool with the same name. This is informational — the registration proceeds regardless. Implementations should be lightweight and safe for concurrent use.

type SetLevelParams

type SetLevelParams struct {
	Level LogLevel `json:"level"`
}

SetLevelParams is the client's payload for the "logging/setLevel" request.

type SetLevelResult

type SetLevelResult struct{}

SetLevelResult is the server's response to a "logging/setLevel" request.

type SimulatorFunc

type SimulatorFunc func(ctx context.Context, input []byte) ([]byte, error)

SimulatorFunc is the function signature for a custom dry-run handler. It receives the same (ctx, input) as the real tool handler and should return a representative output describing what the tool would do.

A SimulatorFunc MUST NOT perform real side effects (e.g., database writes, HTTP calls to external services, file deletions). It must be safe for concurrent use — the server may invoke the same simulator from multiple goroutines simultaneously. Avoid mutable state or protect it with appropriate synchronization.

See middleware.Simulation and WithSimulator.

func ToolSimulatorFromCtx

func ToolSimulatorFromCtx(ctx context.Context) SimulatorFunc

ToolSimulatorFromCtx extracts the tool's SimulatorFunc from the context. Returns nil if the tool has no custom simulator.

type StreamChunkData

type StreamChunkData struct {
	// Content is the JSON-encoded content chunk (e.g. TextContent, ImageContent).
	Content json.RawMessage `json:"content"`
	// Sequence is the 1-based ordinal of this chunk within the stream.
	Sequence int64 `json:"sequence"`
}

StreamChunkData is the payload carried in the "data" field of a streaming progress notification. Clients that understand streaming read content chunks from this field; non-streaming clients simply ignore the extra field.

type SubscribeParams

type SubscribeParams struct {
	URI  string         `json:"uri"`
	Meta map[string]any `json:"_meta,omitempty"`
}

SubscribeParams is the client's payload for "resources/subscribe" and "resources/unsubscribe" requests.

type Task

type Task struct {
	// TaskID is the unique identifier for this task.
	TaskID string `json:"taskId"`

	// Status is the current task state.
	Status TaskStatus `json:"status"`

	// StatusMessage is an optional human-readable message describing the
	// current task state (e.g., error details for failed, reason for cancelled).
	StatusMessage *string `json:"statusMessage,omitempty"`

	// CreatedAt is an ISO 8601 timestamp when the task was created.
	CreatedAt string `json:"createdAt"`

	// LastUpdatedAt is an ISO 8601 timestamp when the task was last updated.
	LastUpdatedAt string `json:"lastUpdatedAt"`

	// TTL is the actual retention duration from creation in milliseconds.
	// nil means unlimited retention.
	TTL *int `json:"ttl"`

	// PollInterval is the suggested polling interval in milliseconds.
	PollInterval *int `json:"pollInterval,omitempty"`
}

Task is the MCP spec-compliant representation of an asynchronous task. It is returned in responses for tasks/get, tasks/cancel, tasks/list, and as part of CreateTaskResult for task-augmented tools/call.

type TaskCapability

type TaskCapability struct {
	// List indicates whether the server supports tasks/list.
	List any `json:"list,omitempty"`

	// Cancel indicates whether the server supports tasks/cancel.
	Cancel any `json:"cancel,omitempty"`

	// Requests specifies which request types can be augmented with tasks.
	Requests *TaskRequestsCapability `json:"requests,omitempty"`
}

TaskCapability describes the server's task-related capabilities.

type TaskIdParams

type TaskIdParams struct {
	TaskID string         `json:"taskId"`
	Meta   map[string]any `json:"_meta,omitempty"`
}

TaskIdParams is the wire format for requests that take a taskId (tasks/get, tasks/result, tasks/cancel).

type TaskMetadata

type TaskMetadata struct {
	TTL *int `json:"ttl,omitempty"`
}

TaskMetadata holds the parameters for creating a task, sent by the client in the "task" field of a task-augmented request.

type TaskOptions

type TaskOptions struct {
	TTL          *int   // retention duration in milliseconds; nil for unlimited
	PollInterval *int   // suggested polling interval in milliseconds
	OwnerID      string // session/connection that owns this task; used for access control
}

TaskOptions controls task creation behavior.

type TaskRequestsCapability

type TaskRequestsCapability struct {
	Tools *TaskToolsCapability `json:"tools,omitempty"`
}

TaskRequestsCapability describes which request types support task augmentation.

type TaskStatus

type TaskStatus string

TaskStatus represents the lifecycle state of a task per the MCP specification.

const (
	// TaskStatusWorking means the request is currently being processed.
	TaskStatusWorking TaskStatus = "working"

	// TaskStatusInputRequired means the task is waiting for input
	// (e.g., elicitation or sampling).
	TaskStatusInputRequired TaskStatus = "input_required"

	// TaskStatusCompleted means the request completed successfully and
	// results are available via tasks/result.
	TaskStatusCompleted TaskStatus = "completed"

	// TaskStatusFailed means the request did not complete successfully.
	TaskStatusFailed TaskStatus = "failed"

	// TaskStatusCancelled means the request was cancelled before completion.
	TaskStatusCancelled TaskStatus = "cancelled"
)

type TaskStore

type TaskStore struct {
	// contains filtered or unexported fields
}

TaskStore manages the lifecycle and storage of spec-compliant MCP tasks. It is safe for concurrent use.

Warning: TaskStore has no built-in eviction. Tasks are stored indefinitely unless manually deleted via TaskStore.Delete. For long-running servers, callers should periodically delete completed/expired tasks.

func NewTaskStore

func NewTaskStore(opts ...TaskStoreOption) *TaskStore

NewTaskStore creates a new task store.

func (*TaskStore) Cancel

func (ts *TaskStore) Cancel(id string) (*Task, error)

Cancel transitions a working task to cancelled. If a cancel function was registered (e.g., from a background goroutine), it is called to abort the in-flight work. Returns the updated task copy.

func (*TaskStore) Complete

func (ts *TaskStore) Complete(id string, result *CallToolResult) error

Complete transitions a task from working to completed with the given result.

func (*TaskStore) Delete

func (ts *TaskStore) Delete(id string) error

Delete removes a task from the store.

func (*TaskStore) Fail

func (ts *TaskStore) Fail(id string, errMsg string) error

Fail transitions a task from working to failed with the given error message.

func (*TaskStore) GenerateID

func (ts *TaskStore) GenerateID() string

GenerateID returns a unique, cryptographically random task ID. The format is "task-" followed by 32 hex characters (128 bits of entropy). Safe for concurrent use.

func (*TaskStore) Get

func (ts *TaskStore) Get(id string) (*Task, error)

Get returns a copy of the task.

func (*TaskStore) GetResult

func (ts *TaskStore) GetResult(id string) (*CallToolResult, error)

GetResult returns the result of a completed task. Returns errTaskNotCompleted if the task is not in completed state.

func (*TaskStore) List

func (ts *TaskStore) List() []Task

List returns all tasks sorted by task ID (lexicographic order). Each task is a copy.

func (*TaskStore) ListByOwner

func (ts *TaskStore) ListByOwner(ownerID string) []Task

ListByOwner returns tasks visible to the given owner, sorted by task ID. When ownerID is empty every task is returned (no filtering). A task is visible if it has no owner or its owner matches ownerID. Each task is a copy.

func (*TaskStore) Submit

func (ts *TaskStore) Submit(id string) (*Task, error)

Submit creates a new working task with default options.

func (*TaskStore) SubmitWithOptions

func (ts *TaskStore) SubmitWithOptions(id string, opts TaskOptions) (*Task, error)

SubmitWithOptions creates a new working task with the given options.

type TaskStoreOption

type TaskStoreOption func(*TaskStore)

TaskStoreOption configures a TaskStore.

func WithMaxTasks

func WithMaxTasks(n int) TaskStoreOption

WithMaxTasks sets the maximum number of tasks the store will hold. When the limit is reached, new submissions are rejected with an error. A value of 0 (the default) means unlimited.

type TaskToolsCapability

type TaskToolsCapability struct {
	Call any `json:"call,omitempty"`
}

TaskToolsCapability describes task support for tool-related requests.

type TenantResolver

type TenantResolver func(ctx context.Context) (*ItemFilter, error)

TenantResolver resolves the request context into an ItemFilter that controls what the caller can see and access. It is called once per request by the dispatch layer, after authentication but before method routing.

The resolver should:

  1. Extract a tenant identifier from the context (e.g. from AuthInfo).
  2. Look up the tenant's configuration (allowed tools, resources, etc.).
  3. Return an *ItemFilter. Return nil to allow everything (no filtering).

If the resolver returns a non-nil error, the request is rejected with a JSON-RPC error response using ErrCodeTenantRequired (-32002). Error messages are scrubbed to a generic "tenant identification required" to prevent enumeration of valid tenant IDs.

The resolver must be safe for concurrent use from multiple goroutines.

type TextContent

type TextContent struct {
	Text string `json:"text"`
}

TextContent represents text provided to or from an LLM.

func (TextContent) MarshalJSON

func (c TextContent) MarshalJSON() ([]byte, error)

MarshalJSON includes the "type" discriminator required by MCP wire format.

type Tool

type Tool struct {
	Name           string
	Description    string
	Handler        ToolHandler
	Simulator      SimulatorFunc // optional dry-run handler for simulation middleware
	Roles          []string
	InputSchema    any
	Annotations    *ToolAnnotations // optional MCP tool annotations
	SkipValidation bool             // when true, validation middleware skips this tool
}

Tool is a registered MCP tool that the server exposes to clients. Create tools via NewTool or NewTypedTool; do not construct directly.

func NewTool

func NewTool(name string, handler ToolHandler, opts ...ToolOption) (*Tool, error)

NewTool creates a Tool with the given name, handler, and options. The name must be 1–128 characters and may contain A–Z, a–z, 0–9, _, -, and . Returns an error if the name is invalid or the handler is nil. For strongly typed inputs/outputs, use NewTypedTool instead.

func NewTypedTool

func NewTypedTool[In any, Out any](name string, handler TypedHandler[In, Out], opts ...ToolOption) (*Tool, error)

NewTypedTool creates a tool with a strongly typed handler. Input is automatically deserialized from JSON; output is serialized to JSON. A JSON Schema is auto-generated from the In type's struct fields and tags.

This is the recommended way to create tools — it provides compile-time type safety, removes JSON boilerplate, and auto-documents the input schema.

The auto-generated schema uses struct tags to control output:

  • json:"name" → property name
  • json:",omitempty" → marks the field as optional
  • json:"-" → skips the field
  • description:"..." → adds a "description" to the property

If WithInputSchema is also passed, it overrides the auto-generated schema.

Usage:

type GreetInput struct {
    Name string `json:"name" description:"Name to greet"`
}

tool, err := finemcp.NewTypedTool("greet",
    func(_ context.Context, in GreetInput) (string, error) {
        return fmt.Sprintf("Hello, %s!", in.Name), nil
    },
    finemcp.WithDescription("Greets someone"),
)

type ToolAnnotations

type ToolAnnotations struct {
	// ReadOnlyHint indicates the tool does not modify any external state.
	// A true value signals that the tool is safe to call speculatively.
	ReadOnlyHint *bool `json:"readOnlyHint,omitempty"`

	// DestructiveHint indicates the tool may perform irreversible operations
	// (e.g., deleting data). Clients may use this to add confirmation prompts.
	// Only meaningful when ReadOnlyHint is false or nil.
	DestructiveHint *bool `json:"destructiveHint,omitempty"`

	// IdempotentHint indicates that calling the tool repeatedly with the
	// same arguments produces the same result. Clients may use this to
	// enable automatic retries.
	IdempotentHint *bool `json:"idempotentHint,omitempty"`

	// Title is an optional human-readable title for the tool, used for
	// display purposes (e.g., UI labels).
	//
	// This field is a common extension adopted by several MCP SDKs,
	// complementing the base readOnlyHint/destructiveHint/idempotentHint
	// triple defined in the MCP spec.
	Title string `json:"title,omitempty"`

	// OpenWorldHint indicates whether the tool accepts additional properties
	// beyond those defined in its input schema. Default interpretation when
	// nil is false (closed schema).
	//
	// This field is a common extension adopted by several MCP SDKs;
	// it is not part of the base MCP 2025-11-25 annotations specification.
	OpenWorldHint *bool `json:"openWorldHint,omitempty"`
}

ToolAnnotations contains optional hints that describe a tool's behavior to clients without affecting server-side execution. All fields use *bool so that nil ("unknown") is distinguishable from an explicit false.

Per MCP spec 2025-11-25, these are hints only — clients SHOULD NOT rely on them for correctness or security. Servers SHOULD set them accurately when the tool's behavior is known.

Note on contradictory hints: the library does not reject semantically conflicting combinations (e.g., ReadOnlyHint=true + DestructiveHint=true). It is the caller's responsibility to set consistent values; clients may exhibit undefined behavior when receiving contradictory hints.

type ToolCapability

type ToolCapability struct {
	// ListChanged indicates whether the server will emit tools/list_changed notifications.
	ListChanged bool `json:"listChanged,omitempty"`
}

ToolCapability describes the server's tool-related capabilities.

type ToolHandler

type ToolHandler func(ctx context.Context, input []byte) ([]byte, error)

ToolHandler is a low-level tool handler that receives the raw JSON-encoded input bytes and returns raw JSON-encoded output bytes. Use NewTypedTool for a typed variant that handles JSON marshaling automatically.

func FanOutFanIn

func FanOutFanIn(merge MergeFunc, handlers ...NamedHandler) ToolHandler

FanOutFanIn returns a ToolHandler that fans the input out to all named handlers concurrently, then passes all results through a merge function that produces the final output.

Like Parallel, all branches run to completion before the merge function is called. The merge function receives every branch's result (including errors) and decides how to combine them. If a handler panics, the panic is recovered and converted to an error for that branch. If the merge function panics, the panic is recovered and returned as an error.

All branches receive the same input slice. Handlers MUST NOT mutate the input bytes, as this would cause data races between goroutines.

At least one handler is required; FanOutFanIn panics otherwise.

Example:

merge := func(ctx context.Context, results map[string]ParallelResult) ([]byte, error) {
    // combine results from all APIs
    return json.Marshal(combined)
}

composed, _ := NewTool("unified_search",
    FanOutFanIn(merge,
        NamedHandler{Name: "api_a", Handler: apiA},
        NamedHandler{Name: "api_b", Handler: apiB},
    ),
    WithDescription("Query multiple APIs and merge results"),
)

func Parallel

func Parallel(handlers ...NamedHandler) ToolHandler

Parallel returns a ToolHandler that executes all named handlers concurrently on the same input. The result is a JSON object mapping each name to its ParallelResult (output or error).

All branches run to completion — errors in one branch do not cancel others. If every branch fails, the composed handler returns an error. If a handler panics, the panic is recovered and converted to an error for that branch.

All branches receive the same input slice. Handlers MUST NOT mutate the input bytes, as this would cause data races between goroutines.

At least one handler is required; Parallel panics otherwise.

Example:

composed, _ := NewTool("multi_check",
    Parallel(
        NamedHandler{Name: "spell", Handler: spellCheck},
        NamedHandler{Name: "grammar", Handler: grammarCheck},
    ),
    WithDescription("Run spell and grammar checks concurrently"),
)

func Pipeline

func Pipeline(first, second ToolHandler, rest ...ToolHandler) ToolHandler

Pipeline returns a ToolHandler that chains handlers sequentially. The output of each handler becomes the input of the next. Execution stops at the first error (fail-fast). If a handler panics, the panic is recovered and returned as an error, preventing execution of subsequent handlers.

At least two handlers are required; Pipeline panics otherwise.

Example:

fetch := fetchHandler()
transform := transformHandler()
validate := validateHandler()

composed, _ := NewTool("etl",
    Pipeline(fetch, transform, validate),
    WithDescription("Fetch → Transform → Validate"),
)

type ToolInfo

type ToolInfo struct {
	Name        string           `json:"name"`
	Description string           `json:"description,omitempty"`
	InputSchema any              `json:"inputSchema"`
	Annotations *ToolAnnotations `json:"annotations,omitempty"`
}

ToolInfo is the wire representation of a tool in a tools/list response.

type ToolOption

type ToolOption func(*Tool)

ToolOption is a functional option for configuring a Tool.

func WithAnnotations

func WithAnnotations(a ToolAnnotations) ToolOption

WithAnnotations sets the full ToolAnnotations struct on the tool. Use this when you need to set multiple annotations at once.

func WithDescription

func WithDescription(desc string) ToolOption

WithDescription sets the tool's human-readable description.

func WithDestructive

func WithDestructive() ToolOption

WithDestructive marks the tool as destructive (may perform irreversible operations). Convenience shorthand for setting DestructiveHint = true.

func WithIdempotent

func WithIdempotent() ToolOption

WithIdempotent marks the tool as idempotent (same input → same result). Convenience shorthand for setting IdempotentHint = true.

func WithInputSchema

func WithInputSchema(schema any) ToolOption

WithInputSchema sets the JSON Schema defining the tool's expected input parameters. Accepts map[string]any, json.RawMessage, or any type that marshals to valid JSON Schema.

func WithOpenWorld

func WithOpenWorld() ToolOption

WithOpenWorld marks the tool as accepting additional properties beyond those defined in its input schema.

func WithReadOnly

func WithReadOnly() ToolOption

WithReadOnly marks the tool as read-only (does not modify external state). Convenience shorthand for setting ReadOnlyHint = true.

func WithRoles

func WithRoles(roles ...string) ToolOption

WithRoles sets the roles required to execute this tool. Empty strings are silently filtered out. Roles are case-sensitive.

func WithSimulator

func WithSimulator(fn SimulatorFunc) ToolOption

WithSimulator registers a custom dry-run handler for the tool. When the Simulation middleware is active and the client sends _meta.dryRun: true, this function is called instead of the real handler.

The simulator MUST NOT perform real side effects. It should return output in the same format the real handler uses (typically JSON) so that callers can parse it consistently. The simulator must be safe for concurrent use — see SimulatorFunc for details.

func WithTitle

func WithTitle(title string) ToolOption

WithTitle sets the human-readable title annotation for display purposes.

func WithValidation

func WithValidation(enabled bool) ToolOption

WithValidation controls whether input validation is enabled for this tool. By default validation is enabled (when the Validation middleware is in the chain). Pass false to skip validation for tools that accept arbitrary JSON.

type ToolStream

type ToolStream struct {
	// contains filtered or unexported fields
}

ToolStream delivers incremental content chunks to the client during tool execution via notifications/progress. Tool handlers obtain a stream from context using StreamFromCtx and call ToolStream.Send or ToolStream.SendText to push chunks; the final result is still returned normally from the handler.

Streaming is supported on stdio, WebSocket, SSE, and Streamable HTTP transports — all of which inject a NotificationSender into the context. Plain HTTP is the only transport where StreamFromCtx returns nil, as it has no persistent server-to-client channel.

Backpressure: Send blocks when the internal buffer is full. The buffer size defaults to DefaultStreamBufferSize (16) and can be changed with WithStreamBufferSize. Context cancellation unblocks a waiting Send.

Example:

tool, _ := finemcp.NewTool("tail-logs", func(ctx context.Context, input []byte) ([]byte, error) {
    stream := finemcp.StreamFromCtx(ctx)
    if stream == nil {
        return []byte("streaming not supported"), nil
    }
    for line := range logLines(ctx) {
        if err := stream.SendText(line); err != nil {
            return nil, err
        }
    }
    return []byte(`{"done":true}`), nil
})

func StreamFromCtx

func StreamFromCtx(ctx context.Context) *ToolStream

StreamFromCtx extracts the ToolStream for the current tool call. Returns nil only for plain HTTP transport, which has no persistent server-to-client notification channel. Stdio, WebSocket, SSE, and Streamable HTTP all inject a NotificationSender and return a valid stream. Tool handlers should check for nil and fall back to returning the full result when streaming is unavailable.

func (*ToolStream) Send

func (s *ToolStream) Send(c Content) error

Send delivers a content chunk to the client. It blocks if the internal buffer is full, providing backpressure to the tool handler. Returns nil on success, ErrStreamClosed if the stream was closed, or a context error if the context was cancelled.

The sequence number is assigned by the drain goroutine at dispatch time, so ToolStream.Sequence accurately reflects only the chunks that were actually delivered (not those dropped due to close or cancellation).

Send is safe for concurrent use by multiple goroutines.

func (*ToolStream) SendText

func (s *ToolStream) SendText(text string) error

SendText is a convenience that sends a TextContent chunk.

func (*ToolStream) Sequence

func (s *ToolStream) Sequence() int64

Sequence returns the number of chunks actually dispatched to the client. This can be used by the handler to track progress or include the count in the final result. The count only includes chunks that were dequeued and sent by the drain goroutine, not chunks still buffered or dropped.

type TypedHandler

type TypedHandler[In any, Out any] func(ctx context.Context, input In) (Out, error)

TypedHandler is a tool handler with strongly typed input and output. The framework automatically deserializes JSON input into In and serializes Out back to JSON, eliminating manual json.Unmarshal/Marshal boilerplate.

Example:

func greet(_ context.Context, in GreetInput) (string, error) {
    return fmt.Sprintf("Hello, %s!", in.Name), nil
}

Directories

Path Synopsis
Package client provides a transport-agnostic MCP client SDK.
Package client provides a transport-agnostic MCP client SDK.
transport/http
Package http provides a simple HTTP request-response transport for MCP.
Package http provides a simple HTTP request-response transport for MCP.
transport/stdio
Package stdio provides a client-side stdio transport for MCP.
Package stdio provides a client-side stdio transport for MCP.
transport/streamable
Package streamable provides a client-side Streamable HTTP transport for MCP.
Package streamable provides a client-side Streamable HTTP transport for MCP.
transport/ws
Package ws provides a client-side WebSocket transport for MCP.
Package ws provides a client-side WebSocket transport for MCP.
Package clienttest provides test helpers for code that uses the finemcp client SDK.
Package clienttest provides test helpers for code that uses the finemcp client SDK.
cmd
finemcp command
Command finemcp is the unified CLI for the FineMCP SDK.
Command finemcp is the unified CLI for the FineMCP SDK.
examples
01-server/basic command
Example: Basic MCP Server
Example: Basic MCP Server
01-server/options command
Example: Server Options
Example: Server Options
02-tools/annotations command
Example: Tool Annotations
Example: Tool Annotations
02-tools/raw command
Example: Raw Tool Handler
Example: Raw Tool Handler
02-tools/session-tools command
Example: Session-Scoped Tools
Example: Session-Scoped Tools
02-tools/typed command
Example: Typed Tools
Example: Typed Tools
03-streaming command
Example: Streaming Tool Responses
Example: Streaming Tool Responses
04-resources/static command
Example: Static Resources
Example: Static Resources
04-resources/subscriptions command
Example: Resource Subscriptions
Example: Resource Subscriptions
04-resources/template command
Example: Resource Templates
Example: Resource Templates
05-prompts/basic command
Example: Prompts
Example: Prompts
05-prompts/completion command
Example: Prompt Completion
Example: Prompt Completion
06-sampling command
Example: Sampling (Server-Initiated LLM Requests)
Example: Sampling (Server-Initiated LLM Requests)
07-roots command
Example: Roots
Example: Roots
08-elicitation command
Example: Elicitation (Server-Initiated User Prompts)
Example: Elicitation (Server-Initiated User Prompts)
09-progress command
Example: Progress Reporting
Example: Progress Reporting
10-logging command
Example: Server Logging
Example: Server Logging
11-completion command
Example: Auto-Completion
Example: Auto-Completion
12-transports/http command
Example: HTTP Transport
Example: HTTP Transport
12-transports/sse command
Example: SSE (Server-Sent Events) Transport
Example: SSE (Server-Sent Events) Transport
12-transports/stdio command
Example: Stdio Transport
Example: Stdio Transport
12-transports/streamable command
Example: Streamable HTTP Transport
Example: Streamable HTTP Transport
12-transports/websocket command
Example: WebSocket Transport
Example: WebSocket Transport
13-middleware/async command
Example: Async Middleware
Example: Async Middleware
13-middleware/auditlog command
Example: Audit Log Middleware
Example: Audit Log Middleware
13-middleware/auth command
Example: Authentication Middleware
Example: Authentication Middleware
13-middleware/cache command
Example: Cache Middleware
Example: Cache Middleware
13-middleware/circuitbreaker command
Example: Circuit Breaker Middleware
Example: Circuit Breaker Middleware
13-middleware/costtracking command
Example: Cost Tracking Middleware
Example: Cost Tracking Middleware
13-middleware/logging command
Example: Logging Middleware
Example: Logging Middleware
13-middleware/multitenant command
Example: Multi-Tenant Middleware
Example: Multi-Tenant Middleware
13-middleware/otel command
Example: OpenTelemetry Middleware
Example: OpenTelemetry Middleware
13-middleware/ratelimit command
Example: Rate Limit Middleware
Example: Rate Limit Middleware
13-middleware/rbac command
Example: RBAC Middleware
Example: RBAC Middleware
13-middleware/recovery command
Example: Recovery Middleware
Example: Recovery Middleware
13-middleware/retry command
Example: Retry Middleware
Example: Retry Middleware
13-middleware/sandbox command
Example: Sandbox Middleware
Example: Sandbox Middleware
13-middleware/simulation command
Example: Simulation Middleware
Example: Simulation Middleware
13-middleware/validation command
Example: Validation Middleware
Example: Validation Middleware
14-testing
Package testing demonstrates how to use the mcptest package for in-process MCP server testing without a real network connection.
Package testing demonstrates how to use the mcptest package for in-process MCP server testing without a real network connection.
15-content-types command
Example: Content Types
Example: Content Types
16-composition command
Example: Tool Composition
Example: Tool Composition
17-embedding command
Example: Embedding MCP in an Existing HTTP Server
Example: Embedding MCP in an Existing HTTP Server
18-example-apps/notes command
Example: Notes App
Example: Notes App
18-example-apps/smartwiki command
Example: SmartWiki — Full-Featured Multi-Tenant Knowledge Base
Example: SmartWiki — Full-Featured Multi-Tenant Knowledge Base
Package mcptest provides test helpers for MCP servers built with finemcp.
Package mcptest provides test helpers for MCP servers built with finemcp.
Package middleware provides tool-level and transport-level middleware for finemcp MCP servers.
Package middleware provides tool-level and transport-level middleware for finemcp MCP servers.
Package transport provides MCP transport implementations for finemcp.
Package transport provides MCP transport implementations for finemcp.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL