Waypoint now supports the Model Context Protocol (MCP), allowing AI assistants to query Snapchain data directly through a standardized interface.
The Model Context Protocol (MCP) is a specification that allows AI assistants to communicate with external tools using a standardized JSON-RPC based protocol. This integration lets AI agents query real-time Snapchain data from your Waypoint instance.
Waypoint uses rmcp version 0.14.0, the official Rust SDK for the Model Context Protocol. The implementation leverages the latest macro-based API patterns and the new Streamable HTTP transport (MCP spec version 2025-03-26):
#[tool_router]: Generates tool routing logic for service implementations#[prompt_router]: Generates prompt routing logic for service implementations#[tool_handler]and#[prompt_handler]: Generate MCP ServerHandler implementationsParameters<T>: Type-safe parameter wrapper for tool inputs
For more details on the rmcp API, see the rmcp documentation.
To enable MCP integration, configure the following settings in your config.toml file or through environment variables:
[mcp]
# Enable MCP integration
enabled = true
# Bind address for the MCP server
bind_address = "0.0.0.0"
# Port for the MCP server
port = 8000Or use environment variables:
WAYPOINT_MCP__ENABLED=true
WAYPOINT_MCP__BIND_ADDRESS=0.0.0.0
WAYPOINT_MCP__PORT=8000The MCP service uses the Streamable HTTP transport, introduced in MCP spec version 2025-03-26. This replaces the previous SSE-based transport with several advantages:
- Single endpoint: All communication happens through a unified
/mcpendpoint - Dynamic streaming: Automatically adapts between simple HTTP and streaming for long-running operations
- Session management: Supports stateful sessions for maintaining context across requests
- Bidirectional communication: Servers can send notifications to clients
- Improved reliability: Better error handling and connection recovery
- WaypointMcpTools:
- Full-featured service with access to Snapchain/Farcaster data
- Accessible at
http://<host>:<port>/mcp - Provides tools for accessing Farcaster user data, casts, and verifications
- Configure with
bind_addressandportsettings
The MCP integration in Waypoint is implemented as a separate service that:
- Starts an MCP-compatible server using the Streamable HTTP protocol
- Exposes tools for querying data
- Handles AI assistant requests through the MCP protocol
- Manages sessions with configurable keep-alive (15 second default)
The MCP service is automatically started when you run Waypoint via waypoint start or Docker Compose, as long as it's enabled in the configuration.
The MCP service uses the Data Context pattern for efficient and flexible data access:
- Unified Data Access: Accesses data from both Snapchain Hub and PostgreSQL database through a single interface
- Prioritized Data Sources: Always tries to fetch fresh data from the Hub first, with database fallback
- Transport-agnostic query core:
WaypointQuerystays reusable across adapters and can run with different DB/Hub implementations - Efficient Resource Management: Shares database and Hub client connections between requests
- Type-Safe Interfaces: Uses Rust's trait system for clean abstractions
The Data Context pattern is detailed in the Architecture Documentation.
The Waypoint MCP integration provides the following tools to AI assistants:
Note: This implementation provides access to Farcaster user data, casts, reactions, links, and verifications via a comprehensive interface. It allows accessing users by FID or username and supports exploring the social graph through follow relationships.
Waypoint also exposes MCP resources for canonical read-only data views. These are JSON resources that can be fetched via resources/read with a waypoint:// URI.
Resource URIs follow RFC 3986 (URI syntax) and RFC 6570 (URI Template) standards:
- Path segments identify resource type and simple identifiers (FID, hash)
- Query parameters (
?url=...) are used for complex values like URLs
This design ensures proper URL encoding, avoids ambiguity, and follows web standards.
waypoint://users/{fid}: User profile by FIDwaypoint://users/by-username/{username}: User profile by username
waypoint://verifications/{fid}: Verified addresses for a FIDwaypoint://verifications/{fid}/{address}: Specific verification by FID and addresswaypoint://verifications/all-by-fid/{fid}: All verification messages for a FID
waypoint://casts/{fid}/{hash}: Specific cast by author FID + hashwaypoint://casts/by-fid/{fid}: Recent casts by FIDwaypoint://casts/by-mention/{fid}: Casts mentioning a FIDwaypoint://casts/by-parent/{fid}/{hash}: Replies to a parent castwaypoint://casts/by-parent-url{?url}: Replies to a parent URL (RFC 6570 query expansion)
waypoint://conversations/{fid}/{hash}: Full conversation thread for a cast (includes replies, participants, parent context, quoted casts)
waypoint://reactions/by-fid/{fid}: Reactions by FIDwaypoint://reactions/by-target-cast/{fid}/{hash}: Reactions to a target castwaypoint://reactions/by-target-url{?url}: Reactions to a target URL (RFC 6570 query expansion)
waypoint://links/by-fid/{fid}: Links by FID (defaults tofollow)waypoint://links/by-target/{fid}: Links to a target FID (defaults tofollow)waypoint://links/compact-state/{fid}: Link compact state by FID
waypoint://username-proofs/{fid}: Username proofs (fname, ens_l1, basename) for a FIDwaypoint://username-proofs/by-name/{name}: Username proof for a specific name
For resources that accept URLs (e.g., by-parent-url, by-target-url), pass the URL as a query parameter:
waypoint://casts/by-parent-url?url=https%3A%2F%2Fexample.com%2Fpost%2F123
waypoint://reactions/by-target-url?url=https%3A%2F%2Fwarpcast.com%2F~%2Fchannel%2Ftest
The URL value should be percent-encoded per RFC 3986.
List-style resources use the same default limit as tools (10), unless the tool supports explicit limits.
{
"method": "callTool",
"params": {
"name": "get_user_by_fid",
"input": {
"fid": 12345
}
}
}The response includes a JSON object with all available user data fields:
{
"fid": 12345,
"display_name": "Alex Smith",
"username": "alex",
"bio": "Building on Farcaster",
"pfp": "https://example.com/avatar.jpg",
"url": "https://example.com",
"location": "San Francisco, CA",
"twitter": "alexsmith",
"github": "asmith"
}The implementation fetches up to 20 UserData messages for the specified FID and maps each type to the appropriate field in the response. Fields not set by the user will be omitted from the response.
Retrieve verified wallet addresses for a user. This tool fetches verification messages from the Hub and provides detailed information about each verified address.
{
"method": "callTool",
"params": {
"name": "get_verifications_by_fid",
"input": {
"fid": 12345,
"limit": 10
}
}
}The response includes detailed information about each verification:
{
"fid": 12345,
"count": 2,
"verifications": [
{
"fid": 12345,
"address": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
"protocol": "ethereum",
"type": "eoa",
"timestamp": 1672531200
},
{
"fid": 12345,
"address": "0xabcdef1234567890abcdef1234567890abcdef12",
"protocol": "ethereum",
"type": "contract",
"chain_id": 1,
"timestamp": 1672617600
}
]
}The response includes:
- Protocol type (ethereum, solana)
- Verification type (eoa for personal wallets, contract for smart contracts)
- Chain ID (for contract verifications)
- Timestamp when the verification was created
Retrieve casts (posts) from a specific user.
{
"method": "callTool",
"params": {
"name": "get_casts_by_fid",
"input": {
"fid": 12345,
"limit": 10
}
}
}The response includes an array of casts with detailed information:
{
"fid": 12345,
"count": 2,
"casts": [
{
"fid": 12345,
"hash": "0x1a2b3c4d5e6f...",
"timestamp": 1672531200,
"text": "This is a sample cast with #hashtags and @mentions",
"mentions": [456, 789],
"mentions_positions": [32, 42],
"embeds": [
{
"type": "url",
"url": "https://example.com/article"
}
]
},
{
"fid": 12345,
"hash": "0xabcdef1234...",
"timestamp": 1672444800,
"text": "This is a reply to another cast",
"parent": {
"type": "cast",
"fid": 789,
"hash": "0x9876543210..."
}
}
]
}Retrieve a specific cast by its author FID and hash.
{
"method": "callTool",
"params": {
"name": "get_cast",
"input": {
"fid": 12345,
"hash": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12"
}
}
}Retrieve casts that mention a specific user.
{
"method": "callTool",
"params": {
"name": "get_casts_by_mention",
"input": {
"fid": 12345,
"limit": 10
}
}
}Retrieve replies to a specific cast.
{
"method": "callTool",
"params": {
"name": "get_casts_by_parent",
"input": {
"parent_fid": 12345,
"parent_hash": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
"limit": 10
}
}
}Retrieve casts that reply to a specific URL.
{
"method": "callTool",
"params": {
"name": "get_casts_by_parent_url",
"input": {
"parent_url": "https://example.com/article",
"limit": 10
}
}
}Retrieve complete conversation details for a cast, including participants, nested replies, parent casts, and quoted casts.
{
"method": "callTool",
"params": {
"name": "get_conversation",
"input": {
"fid": 12345,
"cast_hash": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
"recursive": true,
"max_depth": 5,
"limit": 50
}
}
}fid should be sent as a number. For backward compatibility, a numeric string is also accepted.
The response includes:
{
"root_cast": {
"fid": 12345,
"hash": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
"text": "This is the original cast that started the conversation",
"timestamp": 1672531200,
"parent": {
"type": "cast",
"fid": 9999,
"hash": "0xdeadbeef1234567890abcdef1234567890abcdef"
},
"embeds": [
{
"type": "cast",
"fid": 5678,
"hash": "0xaabbccddeeff1122334455667788990011223344"
}
]
},
"parent_casts": [
{
"fid": 9999,
"hash": "0xdeadbeef1234567890abcdef1234567890abcdef",
"text": "This is the parent cast that the root cast replies to",
"timestamp": 1672530000
},
{
"fid": 8888,
"hash": "0xaaabbbcccdddeeefffaaabbbcccdddeeefffaaab",
"text": "This is the grandparent cast in the conversation",
"timestamp": 1672529000
}
],
"quoted_casts": [
{
"fid": 5678,
"hash": "0xaabbccddeeff1122334455667788990011223344",
"text": "This is a quoted cast embedded in the original cast",
"timestamp": 1672530000
}
],
"participants": {
"count": 5,
"fids": [12345, 6789, 2468, 1357, 9876],
"user_data": {
"12345": {
"fid": 12345,
"username": "alice",
"display_name": "Alice",
"pfp": "https://example.com/alice.jpg"
},
"6789": {
"fid": 6789,
"username": "bob",
"display_name": "Bob",
"pfp": "https://example.com/bob.jpg"
}
// ... other participants
}
},
"topic": "This is the original cast...",
"summary": "Conversation started by Alice (@alice) with: \"This is the original cast...\". 8 replies in the thread.",
"conversation": {
"replies": [
{
"fid": 6789,
"hash": "0xabcdef1234567890abcdef1234567890abcdef12",
"text": "This is a reply to the original cast",
"timestamp": 1672532200,
"replies": [],
"has_more_replies": false
},
{
"fid": 2468,
"hash": "0x9876543210fedcba9876543210fedcba98765432",
"text": "Another reply with nested replies",
"timestamp": 1672533200,
"replies": [
{
"fid": 1357,
"hash": "0x0123456789abcdef0123456789abcdef01234567",
"text": "This is a nested reply",
"timestamp": 1672534200,
"quoted_casts": [
{
"fid": 9876,
"hash": "0xfedcba9876543210fedcba9876543210fedcba98",
"text": "A quoted cast within a nested reply",
"timestamp": 1672533000
}
]
}
],
"has_more_replies": false
}
],
"has_more": false
}
}Additional parameters:
recursive: When true, fetches nested replies to create a complete conversation tree (default: false)max_depth: Controls how deep to traverse the reply tree (default: 5)limit: Maximum number of replies to fetch per level (default: 10)
Key features of the conversation API:
-
Complete Thread Context:
parent_casts: Includes parent casts up to 5 levels, showing the full context thread the conversation belongs toroot_cast: The specified cast itself with all its metadataconversation: All replies to the root cast, organized in a nested tree structure when recursive mode is enabled
-
Embedded Content:
quoted_casts: Quoted/embedded casts in the root cast are fully hydrated with their content- Quotes within replies are also included, with consistent nesting throughout the conversation tree
-
Participant Information:
- All participants in the conversation are tracked, including authors of parent casts, replies, and quoted casts
- User profiles for all participants with username, display name, and profile pictures when available
- The
summaryfield includes human-readable usernames instead of just FIDs
-
Topic Extraction:
- The API generates a
topicfield by using the first words of the root cast - The
summaryfield provides a human-readable summary of the conversation with participant count
- The API generates a
-
Nested Reply Support:
- With
recursive=true, all nested replies (replies to replies) are included with proper threading - Each level tracks whether there are more replies available with the
has_more_repliesfield - Replies at each level are ordered by timestamp
- With
Retrieve casts from a user with optional timestamp filtering.
{
"method": "callTool",
"params": {
"name": "get_all_casts_by_fid",
"input": {
"fid": 12345,
"limit": 20,
"start_time": 1672531200,
"end_time": 1682531200
}
}
}Find a user's profile by their Farcaster username instead of FID.
{
"method": "callTool",
"params": {
"name": "get_user_by_username",
"input": {
"username": "alice"
}
}
}The response includes the same comprehensive profile information as get_user_by_fid, but allows searching by username instead of requiring an FID.
Find a user's FID by their Farcaster username.
{
"method": "callTool",
"params": {
"name": "get_fid_by_username",
"input": {
"username": "alice"
}
}
}Response:
{
"username": "alice",
"fid": 12345,
"found": true
}Check if a user follows another user (or any other link type relationship).
{
"method": "callTool",
"params": {
"name": "get_link",
"input": {
"fid": 12345,
"target_fid": 6789
}
}
}The link_type defaults to "follow" if not specified, making it easy to check follow relationships.
Find users that a specific user follows.
{
"method": "callTool",
"params": {
"name": "get_links_by_fid",
"input": {
"fid": 12345,
"limit": 20
}
}
}By default, this returns "follow" type links unless a different link_type is specified.
Find users that follow a specific user.
{
"method": "callTool",
"params": {
"name": "get_links_by_target",
"input": {
"target_fid": 12345,
"limit": 20
}
}
}By default, this returns "follow" type links unless a different link_type is specified.
Retrieve username proofs for a Farcaster user, including fname, ens_l1, and basename proofs.
{
"method": "callTool",
"params": {
"name": "get_username_proofs_by_fid",
"input": {
"fid": 12345
}
}
}The response includes details about each username proof:
{
"fid": 12345,
"count": 2,
"proofs": [
{
"type": "fname",
"name": "alice",
"fid": 12345,
"owner": "0x0000000000000000000000000000000000000000",
"timestamp": 1672531200
},
{
"type": "ens_l1",
"name": "vitalik.eth",
"fid": 12345,
"owner": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
"timestamp": 1672617600
}
]
}Retrieve a single username proof by name.
{
"method": "callTool",
"params": {
"name": "get_username_proof",
"input": {
"name": "vitalik.eth"
}
}
}The response includes the proof details and whether it was found:
{
"name": "vitalik.eth",
"type": "ens_l1",
"fid": 12345,
"timestamp": 1672617600,
"owner": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
"found": true
}Retrieve a specific verification for a user by FID and wallet address.
{
"method": "callTool",
"params": {
"name": "get_verification",
"input": {
"fid": 12345,
"address": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12"
}
}
}The response includes whether the verification exists and its details:
{
"fid": 12345,
"address": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
"found": true,
"verification": {
"fid": 12345,
"address": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
"protocol": "ethereum",
"type": "eoa",
"action": "add",
"timestamp": 1672531200
}
}Retrieve all verification messages for a user with optional timestamp filtering.
{
"method": "callTool",
"params": {
"name": "get_all_verification_messages_by_fid",
"input": {
"fid": 12345,
"limit": 20,
"start_time": 1672531200,
"end_time": 1682531200
}
}
}The response includes both add/remove verification messages:
{
"fid": 12345,
"count": 2,
"start_time": 1672531200,
"end_time": 1682531200,
"verifications": [
{
"fid": 12345,
"address": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
"protocol": "ethereum",
"type": "eoa",
"action": "add",
"timestamp": 1672531200
},
{
"fid": 12345,
"address": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
"protocol": "ethereum",
"action": "remove",
"timestamp": 1672617600
}
]
}The Waypoint MCP integration includes a customizable prompt for AI assistants:
{
"method": "getPrompt",
"params": {
"name": "waypoint_prompt",
"arguments": {
"fid": 12345,
"username": "vitalik.eth"
}
}
}The prompt supports two parameters:
fid(required): The Farcaster ID to focus onusername(optional): The username associated with the FID, including full ENS domains
This provides the assistant with a context-aware prompt for exploring Farcaster data about the specified user, preserving the complete username including any ".eth" domain.
AI assistants can use these tools to query Snapchain data:
User: "Find me information about Farcaster user with FID 12345"
AI: "Let me fetch information about that Farcaster user for you."
[AI uses the get_user_by_fid tool]
"Here's what I found for user with FID 12345:
- Display name: Alex Farcaster
- Username: alexfarcaster
- Bio: Building the future of decentralized social
- Profile picture: https://example.com/pfp.jpg
- URL: https://example.com
- Location: San Francisco, CA
- Twitter: @alexfarcaster
- GitHub: alexfarcaster"
The get_user_by_fid tool fetches all UserData messages for the specified FID and converts them into a structured JSON object. Each UserData message contains a specific piece of user information based on its type (e.g., display name, bio, profile picture URL, etc.), which is then mapped to the appropriate field in the response. This implementation handles the decoding of the protobuf messages and provides a clean, standardized interface for AI assistants to access user profile data.
User: "What wallets does the user with FID 12345 have verified?"
AI: "Let me check which wallet addresses this user has verified on Farcaster."
[AI uses the get_verifications_by_fid tool with the FID]
"User 12345 has verified the following wallet addresses:
- Ethereum EOA wallet: 0x1a2b3c4d5e6f... (verified on Jan 1, 2023)
- Ethereum contract wallet: 0xabcdef1234... on chain ID 1 (verified on Jan 2, 2023)
- Solana wallet: AbCdEfGhIjK... (verified on Jan 3, 2023)
"
The get_verifications_by_fid tool fetches verification messages from the Hub for the specified FID and processes them to extract the address, protocol type, verification type, and other metadata. This gives AI assistants complete information about the user's verified addresses, letting them provide rich context about the user's blockchain presence.
User: "Show me the recent posts from user with FID 12345"
AI: "Let me fetch the most recent casts from this Farcaster user."
[AI uses the get_casts_by_fid tool with the FID]
"Here are the most recent posts from user 12345:
- 'Just discovered this amazing new DeFi protocol...' (posted Jan 1, 2023)
- 'Anyone going to the ETH conference next month?' (posted Dec 30, 2022)
- 'My thoughts on the latest crypto market trends...' (posted Dec 25, 2022)
"
User: "Who has mentioned FID 12345 recently?"
AI: "Let me search for recent mentions of this Farcaster user."
[AI uses the get_casts_by_mention tool with the FID]
"Here are recent mentions of user 12345:
- FID 789: 'Enjoying the conversation with @12345 about governance models' (posted Jan 5, 2023)
- FID 456: 'Great thread by @12345 on token economics' (posted Jan 3, 2023)
- FID 123: 'Agree with @12345's take on this topic' (posted Dec 28, 2022)
"
User: "Show me all the replies to the cast with FID 12345 and hash 0x1a2b3c4d..."
AI: "Let me fetch the replies to this specific cast."
[AI uses the get_casts_by_parent tool with the parent FID and hash]
"Here are the replies to that cast:
- FID 456: 'This is a really insightful point!'
- FID 789: 'I had a similar experience with this'
- FID 101: 'Could you elaborate more on the second part?'
"
User: "Show me the entire conversation for the cast by FID 12345 with hash 0x1a2b3c4d..."
AI: "Let me fetch the complete conversation including all replies and participants."
[AI uses the get_conversation tool with the FID, hash, and recursive=true]
"Here's the conversation:
Original cast by Alice (@alice):
'This is my thought on the latest protocol upgrade...'
This is part of a thread:
- Grandparent: Charlie (@charlie): 'Announcing a new protocol upgrade coming next week'
- Parent: Dave (@dave): 'What do people think about the new changes?'
- Current: Alice (@alice): 'This is my thought on the latest protocol upgrade...'
Alice's cast quotes Eve (@eve.eth): 'Here's some useful context about the upgrade'
Participants: 5 users (Alice, Bob, Carol, Dave, Eve, Charlie)
Replies:
- Bob (@bob): 'This is a really insightful point!'
└─ Carol (@carol): 'I agree, especially regarding the implementation details'
└─ Alice (@alice): 'Thanks! I've been working on these ideas for a while'
- Dave (@dave): 'I had a similar experience with this'
└─ Eve (@eve.eth): 'Would you mind sharing more about your experience?'
└─ Dave (@dave): 'Sure, I worked on something similar last year...'
Topic summary: 'This is my thought on the latest protocol upgrade...'
8 total replies in this conversation thread
"
User: "What did FID 12345 post during the first week of January 2023?"
AI: "Let me search for posts during that specific time period."
[AI uses the get_all_casts_by_fid tool with start_time and end_time parameters]
"During the first week of January 2023, user 12345 posted:
- Jan 7: 'Wrapping up a productive week of building'
- Jan 5: 'Just pushed a major update to my project'
- Jan 3: 'Happy new year everyone! Looking forward to building in 2023'
"
User: "Can you find information about the Farcaster user @alice?"
AI: "Let me look up that username on Farcaster."
[AI uses the get_user_by_username tool with username "alice"]
"Here's what I found for @alice on Farcaster:
- FID: 12345
- Display name: Alice Builder
- Bio: Building cool things with Farcaster
- Location: New York, NY
- Twitter: @alicebuilder
- Website: https://alice.dev
"
User: "Does user @alice follow user @bob on Farcaster?"
AI: "Let me check if Alice follows Bob on Farcaster."
[AI first uses get_fid_by_username for "alice" and then for "bob"]
[Then AI uses get_link with Alice's FID as source and Bob's FID as target]
"Yes, Alice (FID 12345) follows Bob (FID 6789) on Farcaster."
User: "Who follows @alice on Farcaster?"
AI: "Let me find who follows Alice on Farcaster."
[AI uses get_fid_by_username to get Alice's FID]
[Then AI uses get_links_by_target with Alice's FID]
"Alice has 5 followers on Farcaster:
- Bob (FID 6789)
- Carol (FID 2468)
- Dave (FID 1357)
- Eve (FID 9876)
- Frank (FID 5432)
"
User: "What usernames does FID 12345 have registered?"
AI: "Let me check the username proofs for this Farcaster user."
[AI uses the get_username_proofs_by_fid tool with the FID]
"User 12345 has the following registered usernames:
- fname: alice (registered Jan 1, 2023)
- ENS: vitalik.eth (owned by 0x1a2b... registered Jan 2, 2023)
"
User: "Who owns the username vitalik.eth on Farcaster?"
AI: "Let me fetch the username proof for vitalik.eth."
[AI uses the get_username_proof tool with name "vitalik.eth"]
"The username proof for vitalik.eth is mapped to FID 12345,
and the owner address is 0x1a2b..."
User: "Is 0x1a2b... verified by FID 12345?"
AI: "Let me check that exact verification."
[AI uses the get_verification tool with fid + address]
"Yes, this address is verified for FID 12345 as an Ethereum EOA."
User: "Show all verification messages for FID 12345 in January 2023."
AI: "Let me fetch verification history for that period."
[AI uses the get_all_verification_messages_by_fid tool with start_time/end_time]
"I found 4 verification messages for January 2023:
- 3 add events
- 1 remove event
"
AI assistants can connect to Waypoint's MCP service in several ways:
Connect to the MCP service using the Streamable HTTP endpoint:
http://waypoint-host:8000/mcp
For raw HTTP clients, initialize a session first and include an Accept header that supports both JSON and event streams:
Accept: application/json, text/event-stream
Example connection using the MCP client library:
import { createClient } from "@modelcontextprotocol/client";
const client = createClient({
url: "http://waypoint-host:8000/mcp"
});
// List available tools
const toolList = await client.listTools();
console.log(toolList); // Will show tools like get_user_by_fid, get_verifications_by_fid, get_verification, get_all_verification_messages_by_fid, get_casts_by_fid, get_username_proofs_by_fid, get_username_proof
// Get user profile data
const userData = await client.callTool({
name: "get_user_by_fid",
input: { fid: 12345 }
});
console.log(userData);
// Get recent casts from a user
const casts = await client.callTool({
name: "get_casts_by_fid",
input: { fid: 12345, limit: 5 }
});
console.log(casts);When using Docker Compose, the MCP service is already configured and exposed:
- MCP Service:
http://localhost:8000/mcp
The service is enabled by default and will automatically start with Waypoint.
Developers can extend Waypoint's MCP capabilities by adding query logic in src/query/ and exposing it through MCP adapters in src/services/mcp/handlers/:
- Define new request schemas for MCP in
src/services/mcp/handlers/common.rs - Implement transport-agnostic query logic in
WaypointQuery<DB, HC>undersrc/query/*.rs - Add a delegate method in a
#[tool_router]impl block forWaypointMcpToolsinsrc/services/mcp/handlers/mod.rs - Use the
Parameters<T>wrapper for type-safe MCP parameter handling - Use the DataContext through
WaypointQueryfor data access abstraction
The do_get_user_by_fid query method demonstrates this pattern:
- It receives a Farcaster ID (FID) parameter
- Uses the
DataContextto make a gRPC request to the Hub viaget_user_data_by_fid - Processes the returned
MessagesResponseby decoding the protobuf messages - Extracts the relevant data from each
UserDataBodybased on its type - Returns typed DTOs as
QueryResult<T>(without building transport JSON in query logic) - Lets the MCP adapter serialize and return the response to clients
This layered approach promotes clean separation of concerns:
- The
McpServicestruct manages MCP server lifecycle/startup integration with the app - The
WaypointMcpToolstype handles the MCP protocol interface - The
WaypointQuerytype implements transport-agnostic business/query logic WaypointMcpToolsperforms JSON serialization at the transport boundary- The
DataContextprovides data access abstraction - The Hub/Database clients handle the actual data retrieval
Example of adding a new tool:
// 1. First, add the request structure
#[derive(Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
pub struct SearchCastsRequest {
pub query: String,
#[serde(default = "default_limit")]
pub limit: usize,
}
#[derive(Debug, serde::Serialize)]
pub struct SearchCastsResponse {
pub query: String,
pub results: Vec<CastSummary>,
}
// 2. Add the transport-agnostic implementation in WaypointQuery
impl<DB, HC> WaypointQuery<DB, HC>
where
DB: crate::core::data_context::Database + Clone + Send + Sync + 'static,
HC: crate::core::data_context::HubClient + Clone + Send + Sync + 'static,
{
// Implementation method with business logic
async fn do_search_casts(
&self,
query: &str,
limit: usize,
) -> QueryResult<SearchCastsResponse> {
info!("Query: Searching casts for query: {}", query);
// Use the Data Context to access multiple data sources
match self.data_context.search_casts(query, limit).await {
Ok(messages) => {
let results = messages.iter()
.map(Self::map_cast_summary)
.collect::<Vec<_>>();
Ok(SearchCastsResponse {
query: query.to_string(),
results,
})
},
Err(e) => Err(e.into())
}
}
}
// 3. Add the tool wrapper in WaypointMcpTools
#[tool_router]
impl WaypointMcpTools {
// Existing tools...
#[tool(description = "Search for casts matching a query")]
async fn search_casts(
&self,
Parameters(SearchCastsRequest { query, limit }): Parameters<SearchCastsRequest>,
) -> Result<CallToolResult, McpError> {
// Delegate to transport-agnostic query logic
let result = self
.query
.do_search_casts(&query, limit)
.await
.map_err(Self::map_query_error)?;
Self::call_tool_json(&result)
}
}To add a completely new data access method:
- Add a new method to the Database and/or HubClient traits in
src/core/data_context.rs - Implement the method in the appropriate provider (
src/database/providers.rsorsrc/hub/providers.rs) - Add the corresponding method to the DataContext struct
- Use the new method in your MCP tool
If you encounter issues with the MCP integration:
- Check that MCP is enabled in the configuration (
enabled = true) - Verify the bind address and port settings are correct
- Ensure the port (8000 by default) is correctly exposed in Docker or your deployment environment
- Check Waypoint logs for any MCP-related error messages
- Make sure your Farcaster Hub connection is working
- Verify that the service started successfully by checking the logs for "MCP service started" messages
- Test the connection with a simple MCP client tool
For more information on MCP, visit the Model Context Protocol specification