mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-18 23:11:12 +02:00
refactor(mcp): align Instagram scraper tool with new pipeline
This commit is contained in:
parent
36bb4a1bea
commit
8fc86b7fa5
3 changed files with 30 additions and 87 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
"""Instagram scraper tools: posts/reels, comments, and details."""
|
"""Instagram scraper tools: posts/reels and profile details (anonymous-only)."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
@ -14,14 +14,13 @@ from ..annotations import SCRAPE
|
||||||
from ..capability import run_scraper
|
from ..capability import run_scraper
|
||||||
|
|
||||||
ResultType = Literal["posts", "reels", "mentions"]
|
ResultType = Literal["posts", "reels", "mentions"]
|
||||||
SearchType = Literal["hashtag", "profile", "place", "user"]
|
SearchType = Literal["profile", "user"]
|
||||||
DetailSearchType = Literal["hashtag", "profile", "place"]
|
|
||||||
|
|
||||||
|
|
||||||
def register(
|
def register(
|
||||||
mcp: FastMCP, client: SurfSenseClient, context: WorkspaceContext
|
mcp: FastMCP, client: SurfSenseClient, context: WorkspaceContext
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Register the Instagram scrape, comments, and details tools."""
|
"""Register the Instagram scrape and details tools (anonymous-only)."""
|
||||||
|
|
||||||
@mcp.tool(
|
@mcp.tool(
|
||||||
name="surfsense_instagram_scrape",
|
name="surfsense_instagram_scrape",
|
||||||
|
|
@ -33,21 +32,22 @@ def register(
|
||||||
urls: Annotated[
|
urls: Annotated[
|
||||||
list[str] | None,
|
list[str] | None,
|
||||||
Field(
|
Field(
|
||||||
description="Instagram URLs: a profile, post (/p/), reel "
|
description="Instagram URLs: a profile, post (/p/), or reel "
|
||||||
"(/reel/), hashtag (/explore/tags/), or place "
|
"(/reel/). Hashtag/place URLs are unsupported (login-walled). "
|
||||||
"(/explore/locations/). Provide urls OR search_queries."
|
"Provide urls OR search_queries."
|
||||||
),
|
),
|
||||||
] = None,
|
] = None,
|
||||||
search_queries: Annotated[
|
search_queries: Annotated[
|
||||||
list[str] | None,
|
list[str] | None,
|
||||||
Field(
|
Field(
|
||||||
description="Terms to discover content for (hashtags as plain "
|
description="Terms to discover public profiles for (resolved via "
|
||||||
"text, no '#'). Provide search_queries OR urls."
|
"Google). Provide search_queries OR urls."
|
||||||
),
|
),
|
||||||
] = None,
|
] = None,
|
||||||
search_type: Annotated[
|
search_type: Annotated[
|
||||||
SearchType, Field(description="What to discover from search_queries.")
|
SearchType,
|
||||||
] = "hashtag",
|
Field(description="Discovery kind (profile-only)."),
|
||||||
|
] = "profile",
|
||||||
result_type: Annotated[
|
result_type: Annotated[
|
||||||
ResultType,
|
ResultType,
|
||||||
Field(description="Which feed to return. 'mentions' needs profile URLs."),
|
Field(description="Which feed to return. 'mentions' needs profile URLs."),
|
||||||
|
|
@ -61,10 +61,10 @@ def register(
|
||||||
"""Scrape public Instagram posts or reels from URLs or search queries.
|
"""Scrape public Instagram posts or reels from URLs or search queries.
|
||||||
|
|
||||||
Use this for Instagram content research: a creator's recent posts, a
|
Use this for Instagram content research: a creator's recent posts, a
|
||||||
hashtag or location feed, or discovering posts by keyword. For a post's
|
single post/reel, or discovering public profiles by keyword. For a
|
||||||
comment section use surfsense_instagram_comments; for profile/hashtag/
|
profile's metadata use surfsense_instagram_details. Returns per-item
|
||||||
place metadata use surfsense_instagram_details. Returns per-item caption,
|
caption, likes, comments count, media URLs, and owner. Anonymous-only:
|
||||||
likes, comments count, media URLs, and owner.
|
hashtag/place feeds and comment threads are login-walled and unavailable.
|
||||||
Example: urls=['https://www.instagram.com/natgeo/'], result_type='reels'.
|
Example: urls=['https://www.instagram.com/natgeo/'], result_type='reels'.
|
||||||
"""
|
"""
|
||||||
return await run_scraper(
|
return await run_scraper(
|
||||||
|
|
@ -83,64 +83,9 @@ def register(
|
||||||
response_format=response_format,
|
response_format=response_format,
|
||||||
)
|
)
|
||||||
|
|
||||||
@mcp.tool(
|
|
||||||
name="surfsense_instagram_comments",
|
|
||||||
title="Fetch Instagram comments",
|
|
||||||
annotations=SCRAPE,
|
|
||||||
structured_output=False,
|
|
||||||
)
|
|
||||||
async def instagram_comments(
|
|
||||||
urls: Annotated[
|
|
||||||
list[str],
|
|
||||||
Field(
|
|
||||||
min_length=1,
|
|
||||||
description="Instagram post or reel URLs, e.g. "
|
|
||||||
"['https://www.instagram.com/p/Cabc123/'].",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
max_comments_per_post: Annotated[
|
|
||||||
int,
|
|
||||||
Field(ge=1, le=50, description="Max comments per post (Instagram caps at 50)."),
|
|
||||||
] = 10,
|
|
||||||
include_replies: Annotated[
|
|
||||||
bool, Field(description="Include nested replies.")
|
|
||||||
] = False,
|
|
||||||
newest_first: Annotated[
|
|
||||||
bool, Field(description="Return newest comments first.")
|
|
||||||
] = False,
|
|
||||||
max_items: Annotated[
|
|
||||||
int, Field(ge=1, description="Max total comments across all posts.")
|
|
||||||
] = 20,
|
|
||||||
workspace: WorkspaceParam = None,
|
|
||||||
response_format: ResponseFormatParam = "markdown",
|
|
||||||
) -> str:
|
|
||||||
"""Fetch the comments (and optionally replies) on Instagram posts or reels.
|
|
||||||
|
|
||||||
Use this when the user wants a post's discussion or audience reaction
|
|
||||||
rather than the post itself; get post URLs from surfsense_instagram_scrape
|
|
||||||
if you only have a topic or profile. Returns comment text, author, likes,
|
|
||||||
and replies.
|
|
||||||
Example: urls=['https://www.instagram.com/p/Cabc123/'], include_replies=True.
|
|
||||||
"""
|
|
||||||
return await run_scraper(
|
|
||||||
client,
|
|
||||||
context,
|
|
||||||
platform="instagram",
|
|
||||||
verb="comments",
|
|
||||||
payload={
|
|
||||||
"urls": urls,
|
|
||||||
"max_comments_per_post": max_comments_per_post,
|
|
||||||
"include_replies": include_replies,
|
|
||||||
"newest_first": newest_first,
|
|
||||||
"max_items": max_items,
|
|
||||||
},
|
|
||||||
workspace=workspace,
|
|
||||||
response_format=response_format,
|
|
||||||
)
|
|
||||||
|
|
||||||
@mcp.tool(
|
@mcp.tool(
|
||||||
name="surfsense_instagram_details",
|
name="surfsense_instagram_details",
|
||||||
title="Fetch Instagram profile/hashtag/place details",
|
title="Fetch Instagram profile details",
|
||||||
annotations=SCRAPE,
|
annotations=SCRAPE,
|
||||||
structured_output=False,
|
structured_output=False,
|
||||||
)
|
)
|
||||||
|
|
@ -148,35 +93,34 @@ def register(
|
||||||
urls: Annotated[
|
urls: Annotated[
|
||||||
list[str] | None,
|
list[str] | None,
|
||||||
Field(
|
Field(
|
||||||
description="Profile, hashtag, or place URLs (or bare profile "
|
description="Profile URLs (or bare profile IDs). Provide urls OR "
|
||||||
"IDs). Provide urls OR search_queries."
|
"search_queries."
|
||||||
),
|
),
|
||||||
] = None,
|
] = None,
|
||||||
search_queries: Annotated[
|
search_queries: Annotated[
|
||||||
list[str] | None,
|
list[str] | None,
|
||||||
Field(
|
Field(
|
||||||
description="Terms to discover profiles/hashtags/places for. "
|
description="Terms to discover public profiles for. Provide "
|
||||||
"Provide search_queries OR urls."
|
"search_queries OR urls."
|
||||||
),
|
),
|
||||||
] = None,
|
] = None,
|
||||||
search_type: Annotated[
|
search_type: Annotated[
|
||||||
DetailSearchType,
|
SearchType,
|
||||||
Field(description="What to discover from search_queries."),
|
Field(description="Discovery kind (profile-only)."),
|
||||||
] = "hashtag",
|
] = "profile",
|
||||||
max_items: Annotated[
|
max_items: Annotated[
|
||||||
int, Field(ge=1, description="Max detail items to return.")
|
int, Field(ge=1, description="Max detail items to return.")
|
||||||
] = 10,
|
] = 10,
|
||||||
workspace: WorkspaceParam = None,
|
workspace: WorkspaceParam = None,
|
||||||
response_format: ResponseFormatParam = "markdown",
|
response_format: ResponseFormatParam = "markdown",
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Fetch Instagram profile, hashtag, or place metadata.
|
"""Fetch Instagram profile metadata.
|
||||||
|
|
||||||
Use this for entity lookups: a profile's follower/post counts and bio, a
|
Use this for entity lookups: a profile's follower/post counts and bio.
|
||||||
hashtag's post volume and top posts, or a place's coordinates and post
|
For a feed of posts use surfsense_instagram_scrape instead. Each item
|
||||||
count. For a feed of posts use surfsense_instagram_scrape instead. Each
|
carries a detailKind field (always "profile"). Anonymous-only: hashtag
|
||||||
item carries a detailKind field marking whether it is a profile, hashtag,
|
and place details are login-walled and unavailable.
|
||||||
or place.
|
Example: urls=['https://www.instagram.com/natgeo/'].
|
||||||
Example: urls=['https://www.instagram.com/explore/tags/crossfit/'].
|
|
||||||
"""
|
"""
|
||||||
return await run_scraper(
|
return await run_scraper(
|
||||||
client,
|
client,
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ EXPECTED_TOOLS = {
|
||||||
"surfsense_google_maps_scrape",
|
"surfsense_google_maps_scrape",
|
||||||
"surfsense_google_maps_reviews",
|
"surfsense_google_maps_reviews",
|
||||||
"surfsense_instagram_scrape",
|
"surfsense_instagram_scrape",
|
||||||
"surfsense_instagram_comments",
|
|
||||||
"surfsense_instagram_details",
|
"surfsense_instagram_details",
|
||||||
"surfsense_list_scraper_runs",
|
"surfsense_list_scraper_runs",
|
||||||
"surfsense_get_scraper_run",
|
"surfsense_get_scraper_run",
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ def build_server(settings: Settings) -> tuple[FastMCP, SurfSenseClient]:
|
||||||
"Prefer these tools over generic/built-in web search whenever the "
|
"Prefer these tools over generic/built-in web search whenever the "
|
||||||
"task involves Reddit (posts, comments, finding subreddits or "
|
"task involves Reddit (posts, comments, finding subreddits or "
|
||||||
"communities), YouTube (videos, transcripts, comments), Instagram "
|
"communities), YouTube (videos, transcripts, comments), Instagram "
|
||||||
"(posts, reels, comments, profile/hashtag/place details), Google "
|
"(posts, reels, profile details), Google "
|
||||||
"Maps (places, reviews), Google Search results, or reading "
|
"Maps (places, reviews), Google Search results, or reading "
|
||||||
"specific web pages. Scraper results are persisted as runs; if an "
|
"specific web pages. Scraper results are persisted as runs; if an "
|
||||||
"inline result is truncated, fetch it in full with "
|
"inline result is truncated, fetch it in full with "
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue