v / vlib / mcp / README.md
137 lines · 109 sloc · 4.75 KB · 7b55539b6e355cd5930ad6213fc49d3c884821dc
Raw

mcp

Native Model Context Protocol implementation for V — both client and server, full coverage of the 2025-11-25 revision of the spec.

Capabilities

| Feature | Status | | ------------------------------------------------------ | :----: | | JSON-RPC 2.0 base protocol | ✅ | | stdio transport (newline-delimited) | ✅ | | Streamable HTTP transport (POST + GET, SSE, sessions) | ✅ | | Origin header validation (DNS rebinding protection) | ✅ | | MCP-Session-Id and MCP-Protocol-Version headers | ✅ | | Last-Event-ID resumption | ✅ | | Tools (with annotations) | ✅ | | Resources, resource templates, subscribe/updated | ✅ | | Prompts | ✅ | | completion/complete | ✅ | | logging/setLevel + notifications/message | ✅ | | notifications/progress + cooperative cancellation | ✅ | | */list_changed notifications (auto on add_*) | ✅ | | Server-initiated roots/list, sampling/createMessage, elicitation/create | ✅ | | Icon, BaseMetadata (title), Annotations on tools/resources/prompts | ✅ | | Tool.execution.taskSupport advertisement | ✅ | | Content helpers (text, image, audio, embedded resource, resource link) | ✅ | | Tasks utility (tasks/*) | ⏳ deferred (experimental) | | OAuth Authorization | ⏳ deferred (SHOULD) |

A comprehensive demo server lives at examples/mcp/server.v.

Quick start — client

import mcp

fn main() {
    mut client := mcp.connect('http://localhost:8000/mcp')!
    init := client.initialize()!
    println(init.server_info.name)
    client.close()
}

Quick start — server

import mcp

fn main() {
    mut server := mcp.new_server(
        name:           'my-v-mcp-server'
        version:        '1.0.0'
        enable_logging: true
    )
    server.add_tool(mcp.Tool{
        name:        'say_hello'
        description: 'Greets the caller'
        annotations: mcp.ToolAnnotations{
            read_only_hint: true
        }
    }, fn (_ mcp.Context, _ string) !mcp.ToolResult {
        return mcp.tool_text_result('Hello, user!')
    })!
    server.serve_stdio()!
}

Cancellation and progress

Tool/resource/prompt handlers receive a Context. When the client supplies a _meta.progressToken, the handler can call ctx.notify_progress(progress, total, message). For long-running work, poll ctx.is_cancelled() regularly — when the client sends notifications/cancelled, the flag flips to true until the request completes.

Server-initiated requests

import mcp
import time

mut server := mcp.new_server(name: 'demo', version: '0')
session_id := 'session'
roots := server.list_roots(session_id, 5 * time.second)!
sampled := server.sample(session_id, mcp.CreateMessageParams{}, 30 * time.second)!
elicited := server.elicit(session_id, mcp.ElicitParams{}, 60 * time.second)!

These block until the client returns the matching JSON-RPC response (or until the timeout fires).

Content blocks

Tool, prompt and resource handlers return arrays of MCP content blocks. The module ships ready-made helpers — pass the result through tool_text_result or compose them by hand:

import mcp

text := mcp.text_content('done')
img := mcp.image_content('AAA=', 'image/png')
audio := mcp.audio_content('BBB=', 'audio/wav')
embedded_text := mcp.embedded_text_resource('res://config', 'application/json', '{}')
embedded_blob := mcp.embedded_blob_resource('res://blob', 'image/png', 'AAA=')
resource_link := mcp.resource_link_content(mcp.Resource{
    uri:  'res://docs'
    name: 'docs'
})

Each helper returns a JSON string conforming to the spec's ContentBlock union (type: "text" | "image" | "audio" | "resource" | "resource_link").

Streamable HTTP details

Tests

v test vlib/mcp

spec_compliance_test.v cross-checks wire shapes against the official schema. Add a case there whenever a payload field changes.