Agentic AI – MCP Feature Lists
Table Of Contents:
- MCP Transports.
- MCP HTTP Transport.
- MCP Passing Headers In Transport.
- MCP Authentication While Transport.
- MCP ‘stdio’ Transport.
- MCP Steteful Sections.
- MCP Core Features.
- MCP Tools.
- MCP Structured Content.
- Appending Structures Content Via Interceptor.
- Multimodal Tool Content.
- MCP Resources.
- MCP Loading Resources.
- MCP Prompts.
- MCP Loading Prompts.
- MCP Advanced Features.
- MCP Tool Interceptors.
- MCP Accessing Runtime Context.
- MCP State Update & Commands.
- MCP Custom Interceptors.
- MCP Custom Interceptors – Basic Pattern.
- MCP Custom Interceptors – Modifying Requests.
- MCP Custom Interceptors – Modifying Headers At Runtime.
- MCP Custom Interceptors – Composing Interceptors.
- MCP Custom Interceptors – Error Handling.
- MCP – Progress Notifications.
- MCP – Logging.
- MCP – Elicitation.
- MCP – Elicitation – Server Setup.
- MCP – Elicitation – Client Setup.
- MCP – Elicitation – Response Actions.
from langchain.agents import create_agent
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient(
{
"mcp": {
"transport": "http",
# "url": "http://localhost:8000/mcp", # Local server
"url": "https://docs.langchain.com/mcp", # Hosted server
}
}
)
tools = await client.get_tools()
agent = create_agent("openai:gpt-5.4", tools)
response = await agent.ainvoke(
{
"messages": [
{
"role": "user",
"content": "How do I connect LangChain to an MCP server over HTTP?",
}
]
}
)
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
client = MultiServerMCPClient(
{
"weather": {
"transport": "http",
"url": "http://localhost:8000/mcp",
"headers": {
"Authorization": "Bearer YOUR_TOKEN",
"X-Custom-Header": "custom-value"
},
}
}
)
tools = await client.get_tools()
agent = create_agent("openai:gpt-5.5", tools)
response = await agent.ainvoke({"messages": "what is the weather in nyc?"})
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient(
{
"weather": {
"transport": "http",
"url": "http://localhost:8000/mcp",
"auth": auth,
}
}
)
client = MultiServerMCPClient(
{
"math": {
"transport": "stdio",
"command": "python",
"args": ["/path/to/math_server.py"],
}
}
)
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.tools import load_mcp_tools
from langchain.agents import create_agent
client = MultiServerMCPClient({...})
# Create a session explicitly
async with client.session("server_name") as session:
# Pass the session to load tools, resources, or prompts
tools = await load_mcp_tools(session)
agent = create_agent(
"google_genai:gemini-3.6-flash",
tools
)
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
client = MultiServerMCPClient({...})
tools = await client.get_tools()
agent = create_agent("claude-sonnet-4-6", tools)
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
from langchain.messages import ToolMessage
client = MultiServerMCPClient({...})
tools = await client.get_tools()
agent = create_agent("claude-sonnet-4-6", tools)
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": "Get data from the server"}]}
)
# Extract structured content from tool messages
for message in result["messages"]:
if isinstance(message, ToolMessage) and message.artifact:
structured_content = message.artifact["structured_content"]
import json
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.interceptors import MCPToolCallRequest
from mcp.types import TextContent
async def append_structured_content(request: MCPToolCallRequest, handler):
"""Append structured content from artifact to tool message."""
result = await handler(request)
if result.structuredContent:
result.content += [
TextContent(type="text", text=json.dumps(result.structuredContent)),
]
return result
client = MultiServerMCPClient({...}, tool_interceptors=[append_structured_content])
from langchain.agents import create_agent
from langchain_mcp_adapters.client import MultiServerMCPClient
async def access_multimodal_tool_content():
client = MultiServerMCPClient({})
tools = await client.get_tools()
agent = create_agent("claude-sonnet-4-6", tools)
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": "Take a screenshot of the current page"}]}
)
# Access multimodal content from tool messages
for message in result["messages"]:
if message.type == "tool":
# Raw content in provider-native format
print(f"Raw content: {message.content}")
# Standardized content blocks
for block in message.content_blocks:
if block["type"] == "text":
print(f"Text: {block['text']}")
elif block["type"] == "image":
print(f"Image URL: {block.get('url')}")
print(f"Image base64: {block.get('base64', '')[:50]}...")
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({...})
# Load all resources from a server
blobs = await client.get_resources("server_name")
# Or load specific resources by URI
blobs = await client.get_resources("server_name", uris=["file:///path/to/file.txt"])
for blob in blobs:
print(f"URI: {blob.metadata['uri']}, MIME type: {blob.mimetype}")
print(blob.as_string()) # For text content
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.resources import load_mcp_resources
client = MultiServerMCPClient({...})
async with client.session("server_name") as session:
# Load all resources
blobs = await load_mcp_resources(session)
# Or load specific resources by URI
blobs = await load_mcp_resources(session, uris=["file:///path/to/file.txt"])
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({...})
# Load a prompt by name
messages = await client.get_prompt("server_name", "summarize")
# Load a prompt with arguments
messages = await client.get_prompt(
"server_name",
"code_review",
arguments={"language": "python", "focus": "security"}
)
# Use the messages in your workflow
for message in messages:
print(f"{message.type}: {message.content}")
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.prompts import load_mcp_prompt
client = MultiServerMCPClient({...})
async with client.session("server_name") as session:
# Load a prompt by name
messages = await load_mcp_prompt(session, "summarize")
# Load a prompt with arguments
messages = await load_mcp_prompt(
session,
"code_review",
arguments={"language": "python", "focus": "security"}
)
from dataclasses import dataclass
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.interceptors import MCPToolCallRequest
from langchain.agents import create_agent
@dataclass
class Context:
user_id: str
api_key: str
async def inject_user_context(
request: MCPToolCallRequest,
handler,
):
"""Inject user credentials into MCP tool calls."""
runtime = request.runtime
user_id = runtime.context.user_id
api_key = runtime.context.api_key
# Add user context to tool arguments
modified_request = request.override(
args={**request.args, "user_id": user_id}
)
return await handler(modified_request)
client = MultiServerMCPClient(
{...},
tool_interceptors=[inject_user_context],
)
tools = await client.get_tools()
agent = create_agent("gpt-5.5", tools, context_schema=Context)
# Invoke with user context
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": "Search my orders"}]},
context={"user_id": "user_123", "api_key": "sk-..."}
)
from langchain.agents import AgentState, create_agent
from langchain_mcp_adapters.interceptors import MCPToolCallRequest
from langchain.messages import ToolMessage
from langgraph.types import Command
async def handle_task_completion(
request: MCPToolCallRequest,
handler,
):
"""Mark task complete and hand off to summary agent."""
result = await handler(request)
if request.name == "submit_order":
return Command(
update={
"messages": [result] if isinstance(result, ToolMessage) else [],
"task_status": "completed",
},
goto="summary_agent",
)
return result
async def end_on_success(
request: MCPToolCallRequest,
handler,
):
"""End agent run when task is marked complete."""
result = await handler(request)
if request.name == "mark_complete":
return Command(
update={"messages": [result], "status": "done"},
goto="__end__",
)
return result
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.interceptors import MCPToolCallRequest
async def logging_interceptor(
request: MCPToolCallRequest,
handler,
):
"""Log tool calls before and after execution."""
print(f"Calling tool: {request.name} with args: {request.args}")
result = await handler(request)
print(f"Tool {request.name} returned: {result}")
return result
client = MultiServerMCPClient(
{"math": {"transport": "stdio", "command": "python", "args": ["/path/to/server.py"]}},
tool_interceptors=[logging_interceptor],
)
async def double_args_interceptor(
request: MCPToolCallRequest,
handler,
):
"""Double all numeric arguments before execution."""
modified_args = {k: v * 2 for k, v in request.args.items()}
modified_request = request.override(args=modified_args)
return await handler(modified_request)
# Original call: add(a=2, b=3) becomes add(a=4, b=6)
async def auth_header_interceptor(
request: MCPToolCallRequest,
handler,
):
"""Add authentication headers based on the tool being called."""
token = get_token_for_tool(request.name)
modified_request = request.override(
headers={"Authorization": f"Bearer {token}"}
)
return await handler(modified_request)
async def outer_interceptor(request, handler):
print("outer: before")
result = await handler(request)
print("outer: after")
return result
async def inner_interceptor(request, handler):
print("inner: before")
result = await handler(request)
print("inner: after")
return result
client = MultiServerMCPClient(
{...},
tool_interceptors=[outer_interceptor, inner_interceptor],
)
# Execution order:
# outer: before -> inner: before -> tool execution -> inner: after -> outer: after
import asyncio
async def retry_interceptor(
request: MCPToolCallRequest,
handler,
max_retries: int = 3,
delay: float = 1.0,
):
"""Retry failed tool calls with exponential backoff."""
last_error = None
for attempt in range(max_retries):
try:
return await handler(request)
except Exception as e:
last_error = e
if attempt < max_retries - 1:
wait_time = delay * (2 ** attempt) # Exponential backoff
print(f"Tool {request.name} failed (attempt {attempt + 1}), retrying in {wait_time}s...")
await asyncio.sleep(wait_time)
raise last_error
client = MultiServerMCPClient(
{...},
tool_interceptors=[retry_interceptor],
)
async def fallback_interceptor(
request: MCPToolCallRequest,
handler,
):
"""Return a fallback value if tool execution fails."""
try:
return await handler(request)
except TimeoutError:
return f"Tool {request.name} timed out. Please try again later."
except ConnectionError:
return f"Could not connect to {request.name} service. Using cached data."
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.callbacks import Callbacks, CallbackContext
async def on_progress(
progress: float,
total: float | None,
message: str | None,
context: CallbackContext,
):
"""Handle progress updates from MCP servers."""
percent = (progress / total * 100) if total else progress
tool_info = f" ({context.tool_name})" if context.tool_name else ""
print(f"[{context.server_name}{tool_info}] Progress: {percent:.1f}% - {message}")
client = MultiServerMCPClient(
{...},
callbacks=Callbacks(on_progress=on_progress),
)
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.callbacks import Callbacks, CallbackContext
from mcp.types import LoggingMessageNotificationParams
async def on_logging_message(
params: LoggingMessageNotificationParams,
context: CallbackContext,
):
"""Handle log messages from MCP servers."""
print(f"[{context.server_name}] {params.level}: {params.data}")
client = MultiServerMCPClient(
{...},
callbacks=Callbacks(on_logging_message=on_logging_message),
)
from pydantic import BaseModel
from mcp.server.fastmcp import Context, FastMCP
server = FastMCP("Profile")
class UserDetails(BaseModel):
email: str
age: int
@server.tool()
async def create_profile(name: str, ctx: Context) -> str:
"""Create a user profile, requesting details via elicitation."""
result = await ctx.elicit(
message=f"Please provide details for {name}'s profile:",
schema=UserDetails,
)
if result.action == "accept" and result.data:
return f"Created profile for {name}: email={result.data.email}, age={result.data.age}"
if result.action == "decline":
return f"User declined. Created minimal profile for {name}."
return "Profile creation cancelled."
if __name__ == "__main__":
server.run(transport="http")
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.callbacks import Callbacks, CallbackContext
from mcp.shared.context import RequestContext
from mcp.types import ElicitRequestParams, ElicitResult
async def on_elicitation(
mcp_context: RequestContext,
params: ElicitRequestParams,
context: CallbackContext,
) -> ElicitResult:
"""Handle elicitation requests from MCP servers."""
# In a real application, you would prompt the user for input
# based on params.message and params.requestedSchema
return ElicitResult(
action="accept",
content={"email": "[email protected]", "age": 25},
)
client = MultiServerMCPClient(
{
"profile": {
"url": "http://localhost:8000/mcp",
"transport": "http",
}
},
callbacks=Callbacks(on_elicitation=on_elicitation),
)
# Accept with data
ElicitResult(action="accept", content={"email": "[email protected]", "age": 25})
# Decline (user doesn't want to provide info)
ElicitResult(action="decline")
# Cancel (abort the operation)
ElicitResult(action="cancel") 