Documentation Index Fetch the complete documentation index at: https://docs.nevermined.app/llms.txt
Use this file to discover all available pages before exploring further.
This guide explains how to integrate the Nevermined Payments Python SDK with MCP (Model Context Protocol) servers.
Overview
MCP (Model Context Protocol) enables AI applications to interact with external tools, resources, and prompts. The Nevermined SDK provides built-in MCP integration to:
Protect tools, resources, and prompts with paywalls
Handle OAuth 2.1 authentication
Manage credit consumption per operation
MCP Integration API
Access the MCP integration through payments.mcp:
from payments_py import Payments, PaymentOptions
payments = Payments.get_instance(
PaymentOptions( nvm_api_key = "nvm:your-key" , environment = "sandbox" )
)
# MCP integration is available as:
mcp = payments.mcp
Simplified API (Recommended)
The simplified API handles server setup automatically:
async def hello_handler ( args , context = None ):
"""Handle the hello tool request."""
name = args.get( "name" , "World" )
return {
"content" : [{ "type" : "text" , "text" : f "Hello, { name } !" }]
}
# Register the tool
payments.mcp.register_tool(
name = "hello_world" ,
config = {
"description" : "Says hello to someone" ,
"inputSchema" : {
"type" : "object" ,
"properties" : {
"name" : { "type" : "string" , "description" : "Name to greet" }
}
}
},
handler = hello_handler,
options = { "credits" : 1 } # Cost: 1 credit per call
)
Register a Resource
async def config_handler ( uri , variables , context = None ):
"""Handle the configuration resource request."""
return {
"contents" : [{
"uri" : str (uri),
"mimeType" : "application/json" ,
"text" : '{"version": "1.0.0", "feature_flags": {"beta": true }} '
}]
}
payments.mcp.register_resource(
uri = "data://config" ,
config = {
"name" : "Configuration" ,
"description" : "Application configuration" ,
"mimeType" : "application/json"
},
handler = config_handler,
options = { "credits" : 2 } # Cost: 2 credits per access
)
Register a Prompt
async def greeting_handler ( args , context = None ):
"""Handle the greeting prompt request."""
style = args.get( "style" , "formal" )
return {
"messages" : [{
"role" : "user" ,
"content" : {
"type" : "text" ,
"text" : f "Please greet me in a { style } way."
}
}]
}
payments.mcp.register_prompt(
name = "greeting" ,
config = {
"name" : "Greeting" ,
"description" : "Generates a greeting"
},
handler = greeting_handler,
options = { "credits" : 1 }
)
Start the Server
import asyncio
async def main ():
# Register handlers first
payments.mcp.register_tool( "hello" , { ... }, hello_handler)
# Start the MCP server
result = await payments.mcp.start({
"port" : 5001 ,
"agentId" : "your-agent-id" ,
"serverName" : "my-mcp-server" ,
"version" : "1.0.0" ,
"description" : "My MCP server with Nevermined payments"
})
print ( f "Server running at: { result[ 'info' ][ 'baseUrl' ] } " )
print ( f "Tools: { result[ 'info' ][ 'tools' ] } " )
# Server runs until stopped
# To stop: await payments.mcp.stop()
asyncio.run(main())
Advanced API
For more control, use the advanced API:
# Configure shared options
payments.mcp.configure({
"agentId" : "your-agent-id" ,
"serverName" : "my-mcp-server"
})
# Wrap a handler with paywall
async def my_handler ( args ):
return { "result" : "processed" }
protected_handler = payments.mcp.with_paywall(
handler = my_handler,
options = {
"kind" : "tool" ,
"name" : "my_tool" ,
"credits" : 1
}
)
Attach to Existing Server
from mcp.server import MCPServer
# Create your own MCP server
server = MCPServer()
# Attach payments integration
registrar = payments.mcp.attach(server)
# Register protected handlers
registrar.register_tool(
name = "hello" ,
config = { "description" : "Hello tool" },
handler = hello_handler,
options = { "credits" : 1 }
)
registrar.register_resource(
name = "config" ,
template = "data:// {path} " ,
config = { "name" : "Config" },
handler = config_handler,
options = { "credits" : 2 }
)
Complete Example
import asyncio
from payments_py import Payments, PaymentOptions
# Initialize payments
payments = Payments.get_instance(
PaymentOptions( nvm_api_key = "nvm:your-key" , environment = "sandbox" )
)
# Define handlers
async def analyze_code ( args , context = None ):
"""Analyze code for issues."""
code = args.get( "code" , "" )
language = args.get( "language" , "python" )
# Your analysis logic here
issues = analyze(code, language)
return {
"content" : [{
"type" : "text" ,
"text" : f "Found { len (issues) } issues in { language } code."
}]
}
async def get_docs ( uri , variables , context = None ):
"""Return documentation."""
topic = variables.get( "topic" , "general" )
return {
"contents" : [{
"uri" : str (uri),
"mimeType" : "text/markdown" ,
"text" : f "# Documentation for { topic } \n\n Content here..."
}]
}
async def code_review_prompt ( args , context = None ):
"""Generate code review prompt."""
return {
"messages" : [{
"role" : "user" ,
"content" : {
"type" : "text" ,
"text" : "Please review the following code for best practices..."
}
}]
}
# Register handlers
payments.mcp.register_tool(
"analyze_code" ,
{
"description" : "Analyzes code for potential issues" ,
"inputSchema" : {
"type" : "object" ,
"properties" : {
"code" : { "type" : "string" },
"language" : { "type" : "string" , "default" : "python" }
},
"required" : [ "code" ]
}
},
analyze_code,
{ "credits" : 5 } # 5 credits per analysis
)
payments.mcp.register_resource(
"docs:// {topic} " ,
{
"name" : "Documentation" ,
"description" : "Technical documentation" ,
"mimeType" : "text/markdown"
},
get_docs,
{ "credits" : 1 }
)
payments.mcp.register_prompt(
"code_review" ,
{
"name" : "Code Review" ,
"description" : "Generates a code review prompt"
},
code_review_prompt,
{ "credits" : 2 }
)
# Start server
async def main ():
result = await payments.mcp.start({
"port" : 5001 ,
"agentId" : "agent-123" ,
"serverName" : "code-assistant-mcp" ,
"version" : "1.0.0"
})
print ( f "MCP Server running at { result[ 'info' ][ 'baseUrl' ] } " )
print ( f "Tools: { result[ 'info' ][ 'tools' ] } " )
print ( f "Resources: { result[ 'info' ][ 'resources' ] } " )
print ( f "Prompts: { result[ 'info' ][ 'prompts' ] } " )
# Keep running
try :
while True :
await asyncio.sleep( 1 )
except KeyboardInterrupt :
await payments.mcp.stop()
asyncio.run(main())
Server Configuration
Option Type Required Description portintYes Server port agentIdstrYes Nevermined agent DID serverNamestrYes Human-readable name baseUrlstrNo Base URL (default: localhost) versionstrNo Server version descriptionstrNo Server description
Handler Options
Option Type Description creditsint or callableCredits to consume per call planIdstrOptional override for the plan ID (otherwise inferred from token) maxAmountintMax credits to verify during authentication (default: 1) onRedeemErrorstr"ignore" (default) or "propagate" to raise on redemption failure
After each paywall-protected call, the SDK injects a _meta field into the response following the MCP specification . This field is always present regardless of whether credit redemption succeeded or failed:
# Successful redemption
{
"content" : [{ "type" : "text" , "text" : "result" }],
"_meta" : {
"success" : True ,
"txHash" : "0xabc..." ,
"creditsRedeemed" : "5" ,
"planId" : "plan-123" ,
"subscriberAddress" : "0x123..."
}
}
# Failed redemption
{
"content" : [{ "type" : "text" , "text" : "result" }],
"_meta" : {
"success" : False ,
"creditsRedeemed" : "0" ,
"planId" : "plan-123" ,
"subscriberAddress" : "0x123..." ,
"errorReason" : "Insufficient credits"
}
}
Field Type Description successboolWhether credit redemption succeeded txHashstr or NoneBlockchain transaction hash (only on success) creditsRedeemedstrNumber of credits burned ("0" on failure) planIdstrPlan used for the operation subscriberAddressstrSubscriber’s wallet address errorReasonstrError message (only on failure)
Endpoints
The MCP server exposes:
/.well-known/oauth-authorization-server - OAuth 2.1 discovery
/.well-known/oauth-protected-resource - Resource metadata
/register - Client registration
/mcp - MCP protocol endpoint (POST/GET/DELETE)
/health - Health check
Next Steps
A2A Integration Agent-to-Agent protocol
x402 Protocol Payment protocol details