Skip to content
This repository was archived by the owner on Apr 4, 2026. It is now read-only.

Latest commit

 

History

History
1222 lines (969 loc) · 34.6 KB

File metadata and controls

1222 lines (969 loc) · 34.6 KB

Model Context Protocol (MCP) Integration Guide

Waypoint now supports the Model Context Protocol (MCP), allowing AI assistants to query Snapchain data directly through a standardized interface.

What is MCP?

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.

Implementation

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 implementations
  • Parameters<T>: Type-safe parameter wrapper for tool inputs

For more details on the rmcp API, see the rmcp documentation.

Configuration

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 = 8000

Or use environment variables:

WAYPOINT_MCP__ENABLED=true
WAYPOINT_MCP__BIND_ADDRESS=0.0.0.0
WAYPOINT_MCP__PORT=8000

Transport Protocol

The 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 /mcp endpoint
  • 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

Endpoint Configuration

  • 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_address and port settings

Architecture

The MCP integration in Waypoint is implemented as a separate service that:

  1. Starts an MCP-compatible server using the Streamable HTTP protocol
  2. Exposes tools for querying data
  3. Handles AI assistant requests through the MCP protocol
  4. 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.

Data Access

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: WaypointQuery stays 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.

Available Tools

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.

Resources

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.

URI Design (RFC 3986 / RFC 6570)

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.

Resource Templates

Users

  • waypoint://users/{fid}: User profile by FID
  • waypoint://users/by-username/{username}: User profile by username

Verifications

  • waypoint://verifications/{fid}: Verified addresses for a FID
  • waypoint://verifications/{fid}/{address}: Specific verification by FID and address
  • waypoint://verifications/all-by-fid/{fid}: All verification messages for a FID

Casts

  • waypoint://casts/{fid}/{hash}: Specific cast by author FID + hash
  • waypoint://casts/by-fid/{fid}: Recent casts by FID
  • waypoint://casts/by-mention/{fid}: Casts mentioning a FID
  • waypoint://casts/by-parent/{fid}/{hash}: Replies to a parent cast
  • waypoint://casts/by-parent-url{?url}: Replies to a parent URL (RFC 6570 query expansion)

Conversations

  • waypoint://conversations/{fid}/{hash}: Full conversation thread for a cast (includes replies, participants, parent context, quoted casts)

Reactions

  • waypoint://reactions/by-fid/{fid}: Reactions by FID
  • waypoint://reactions/by-target-cast/{fid}/{hash}: Reactions to a target cast
  • waypoint://reactions/by-target-url{?url}: Reactions to a target URL (RFC 6570 query expansion)

Links

  • waypoint://links/by-fid/{fid}: Links by FID (defaults to follow)
  • waypoint://links/by-target/{fid}: Links to a target FID (defaults to follow)
  • waypoint://links/compact-state/{fid}: Link compact state by FID

Username Proofs

  • waypoint://username-proofs/{fid}: Username proofs (fname, ens_l1, basename) for a FID
  • waypoint://username-proofs/by-name/{name}: Username proof for a specific name

URL Query Parameters

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.

User Tools

Get User by FID

{
  "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.

Get User Verifications

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

Get Casts by User

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..."
      }
    }
  ]
}

Get Specific Cast

Retrieve a specific cast by its author FID and hash.

{
  "method": "callTool",
  "params": {
    "name": "get_cast",
    "input": {
      "fid": 12345,
      "hash": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12"
    }
  }
}

Get Cast Mentions

Retrieve casts that mention a specific user.

{
  "method": "callTool",
  "params": {
    "name": "get_casts_by_mention",
    "input": {
      "fid": 12345,
      "limit": 10
    }
  }
}

Get Cast Replies

Retrieve replies to a specific cast.

{
  "method": "callTool",
  "params": {
    "name": "get_casts_by_parent",
    "input": {
      "parent_fid": 12345,
      "parent_hash": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
      "limit": 10
    }
  }
}

Get URL Replies

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
    }
  }
}

Get Conversation

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:

  1. Complete Thread Context:

    • parent_casts: Includes parent casts up to 5 levels, showing the full context thread the conversation belongs to
    • root_cast: The specified cast itself with all its metadata
    • conversation: All replies to the root cast, organized in a nested tree structure when recursive mode is enabled
  2. 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
  3. 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 summary field includes human-readable usernames instead of just FIDs
  4. Topic Extraction:

    • The API generates a topic field by using the first words of the root cast
    • The summary field provides a human-readable summary of the conversation with participant count
  5. 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_replies field
    • Replies at each level are ordered by timestamp

Get All Casts with Time Filtering

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
    }
  }
}

Get User by Username

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.

Get FID by Username

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
}

Get Link (Follow Relationship)

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.

Get Links by FID (Who a User Follows)

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.

Get Links by Target (Who Follows a User)

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.

Get Username Proofs

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
    }
  ]
}

Get Username Proof

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
}

Get Verification

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
  }
}

Get All Verification Messages by FID

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
    }
  ]
}

Using the Waypoint Prompt

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 on
  • username (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.

Example Usage

AI assistants can use these tools to query Snapchain data:

Getting User Information

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.

Getting a User's Verified Wallets

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.

Getting a User's Recent Casts

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)
    "

Finding Casts That Mention a User

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)
    "

Finding Replies to a Specific Cast

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?'
    "

Getting a Complete Conversation Thread

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
    "

Finding Casts During a Specific Time Period

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'
    "

Finding a User by Their Username

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
    "

Checking Follow Relationships

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)
    "

Getting Username Proofs

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)
    "

Getting a Username Proof by Name

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..."

Checking a Specific Verification

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."

Getting Verification History

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
    "

Connecting AI Assistants to Waypoint MCP

AI assistants can connect to Waypoint's MCP service in several ways:

HTTP Mode Connection

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);

Docker Setup

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.

Extending the MCP Integration

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/:

  1. Define new request schemas for MCP in src/services/mcp/handlers/common.rs
  2. Implement transport-agnostic query logic in WaypointQuery<DB, HC> under src/query/*.rs
  3. Add a delegate method in a #[tool_router] impl block for WaypointMcpTools in src/services/mcp/handlers/mod.rs
  4. Use the Parameters<T> wrapper for type-safe MCP parameter handling
  5. Use the DataContext through WaypointQuery for data access abstraction

The do_get_user_by_fid query method demonstrates this pattern:

  1. It receives a Farcaster ID (FID) parameter
  2. Uses the DataContext to make a gRPC request to the Hub via get_user_data_by_fid
  3. Processes the returned MessagesResponse by decoding the protobuf messages
  4. Extracts the relevant data from each UserDataBody based on its type
  5. Returns typed DTOs as QueryResult<T> (without building transport JSON in query logic)
  6. Lets the MCP adapter serialize and return the response to clients

This layered approach promotes clean separation of concerns:

  • The McpService struct manages MCP server lifecycle/startup integration with the app
  • The WaypointMcpTools type handles the MCP protocol interface
  • The WaypointQuery type implements transport-agnostic business/query logic
  • WaypointMcpTools performs JSON serialization at the transport boundary
  • The DataContext provides 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:

  1. Add a new method to the Database and/or HubClient traits in src/core/data_context.rs
  2. Implement the method in the appropriate provider (src/database/providers.rs or src/hub/providers.rs)
  3. Add the corresponding method to the DataContext struct
  4. Use the new method in your MCP tool

Troubleshooting

If you encounter issues with the MCP integration:

  1. Check that MCP is enabled in the configuration (enabled = true)
  2. Verify the bind address and port settings are correct
  3. Ensure the port (8000 by default) is correctly exposed in Docker or your deployment environment
  4. Check Waypoint logs for any MCP-related error messages
  5. Make sure your Farcaster Hub connection is working
  6. Verify that the service started successfully by checking the logs for "MCP service started" messages
  7. Test the connection with a simple MCP client tool

For more information on MCP, visit the Model Context Protocol specification