Model Context Protocol (MCP)
What is MCP?Copied!
The Model Context Protocol (MCP) is a standard that enables AI assistants to connect with external systems in a structured and secure way. Through MCP, a service can expose its data and operations to an assistant in the form of “tools,” which define specific actions or queries the assistant can perform. These tools give assistants the ability to do things like query user data and perform actions in users’ business applications — unlocking the potential to surface meaningful insights and automate complex, multi-step workflows.
What Can I Do with Rollout’s MCP Server?Copied!
Rollout’s MCP server enables AI assistants to query and update data from your users’ critical real estate systems. This gives users the ability to ask high-value questions like, “Which lead sources have performed best for me this month?” or “Who should I follow up with this week?” They can even have their AI assistants perform more advanced tasks, such as, “Create a task to send a text to all of my leads who I haven’t reached out to in more than six months.”
Building with Rollout’s MCP ServerCopied!
Before You BeginCopied!
The rest of this guide assumes that you have a Rollout Client Id and Client Secret as well as at least one CRM credential connected to Rollout.
Connecting to the ServerCopied!
The standard way to connect to a remote server using the Model Context Protocol is through Server-Sent Events (SSE) — a server-push technology that allows data to be streamed from the server to the client over a single, persistent HTTP connection.
Fortunately, the Model Context Protocol SDK handles this connection for you. It maintains the SSE stream and exposes the relevant operations needed to build with MCP, so you can focus on building functionality rather than infrastructure.
Authorization
Rollout’s MCP server requires each request to include a Bearer Token Authorization header containing a valid Rollout auth token. You’ll need to configure your SDK or HTTP client to set this header for every request made to the server.
Example Using the Model Context Protocol SDK
The example below demonstrates how to:
-
Connect an MCP client to Rollout’s MCP server,
-
Fetch the list of available tools
-
Provide those tools to an AI model using the Anthropic Client SDK, and
-
Call the tool on the MCP server on the model’s behalf
While this example uses Anthropic SDKs, other popular model providers, such as OpenAI, support similar tool interfaces, making it easy to adapt this pattern to different providers.
import asyncio
from mcp import ClientSession
from mcp.client.sse import sse_client
from anthropic import Anthropic
ROLLOUT_SSE_URL = "https://api.rollout.dev/mcp/sse"
ROLLOUT_AUTH_TOKEN = "<Your token here>"
ANTHROPIC_API_KEY = "<Your API Key here>"
async def send_query_with_tools (session):
"""Process a query using Claude and Rollout's tools"""
anthropic = Anthropic()
messages = [
{
"role": "user",
"content": "Which leads should I reach out to today?"
}
]
# Get the list of tools available from the MCP server
tools_response = await session.list_tools()
available_tools = [{
"name": tool.name,
"description": tool.description,
"input_schema": tool.inputSchema
} for tool in tools_response.tools]
# Send user message to the model along with provided tools
model_response = anthropic.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1000,
messages=messages,
tools=available_tools
)
for content in model_response.content:
if content.type == "tool_use":
# Make call to MCP server on the model's behalf
result = await session.call_tool(content.name, content.input)
# Provide prior conversation context and tool use result back to the model
messages.append({
"role": "assistant",
"content": [content]
})
messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": content.id,
"content": result.content
}]
})
# Get next response from the model after tool use
model_response = await anthropic.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1000,
messages=messages,
tools=available_tools
)
# Print the final response text
print(model_response.content[0].text)
async def main():
headers = {
"Authorization": f"Bearer {ROLLOUT_AUTH_TOKEN}",
}
async with sse_client(ROLLOUT_SSE_URL, headers=headers) as (read_stream, write_stream):
async with ClientSession(
read_stream,
write_stream,
message_handler=message_handler
) as session:
await send_query_with_tools(session)
if __name__ == "__main__":
asyncio.run(main())
import Anthropic from "@anthropic-ai/sdk";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
const ROLLOUT_SSE_URL = new URL("https://crm.universal.rollout.com/mcp/sse");
const ROLLOUT_AUTH_TOKEN = "<YOUR ROLLOUT AUTH TOKEN HERE>";
const ANTHROPIC_API_KEY = "<YOUR ANTHROPIC API KEY HERE>";
async function sendQueryWithTools(client) {
const anthropic = new Anthropic({
apiKey: ANTHROPIC_API_KEY,
});
const messages = [
{
role: "user",
content: "Which leads should I reach out to today?",
},
];
// Get the list of tools available from the MCP server
const toolsResponse = await client.listTools();
const availableTools = toolsResponse.tools.map((t) => ({
name: t.name,
description: t.description,
input_schema: t.inputSchema,
}));
// Send user message to the model along with provided tools
let modelResponse = await anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1000,
messages,
tools: availableTools,
});
for (const content of modelResponse.content) {
if (content.type === "tool_use") {
// Make call to MCP server on the model's behalf
const result = await client.callTool({
name: content.name,
arguments: content.input,
});
// Provide prior conversation context and tool use result back to the model
messages.push({
role: "assistant",
content: [content],
});
messages.push({
role: "user",
content: [
{
type: "tool_result",
tool_use_id: content.id,
content: result.content,
},
],
});
// Get next response from the model after tool use
modelResponse = await anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1000,
messages,
tools: availableTools,
});
}
}
// Print the final response text
console.log(modelResponse.content[0].text);
}
async function withRolloutMcpClient(token, fn) {
const client = await createRolloutMcpClient(token);
try {
await fn(client);
} finally {
client.close();
}
}
async function createRolloutMcpClient(rolloutAuthJwt) {
// Include an Authorization header on each request
const rolloutRequestInit = {
headers: { Authorization: `Bearer ${rolloutAuthJwt}` },
};
// Modify fetch to use the Rollout fetch init. MCP SDK for Typescript will only
// pass headers to `POST` request and not the initial
const rolloutFetch = (...args) => {
const [input, init] = args;
const modifiedInit = init
? { ...init, ...rolloutRequestInit }
: rolloutRequestInit;
return fetch(input, modifiedInit);
};
const transport = new SSEClientTransport(ROLLOUT_SSE_URL, {
eventSourceInit: { fetch: rolloutFetch },
// Use the Rollout request init on subsequent SSE requests
requestInit: rolloutRequestInit,
});
const client = new Client({
name: "rollout-client",
version: "0.0.1",
});
await client.connect(transport);
return client;
}
withRolloutMcpClient(ROLLOUT_AUTH_TOKEN, sendQueryWithTools);